Ver código fonte

+ ttai_typedconstbuilder.start_internal_data_builder() and
ttai_typedconstbuilder.finish_internal_data_builder() to generate data
will only be referenced by the typed const that we are currently
generating. Takes care of creating an appropriate label/section for
this data, avoiding needless global symbols and sections.

git-svn-id: branches/hlcgllvm@30339 -

Jonas Maebe 10 anos atrás
pai
commit
158116392c
1 arquivos alterados com 144 adições e 0 exclusões
  1. 144 0
      compiler/aasmcnst.pas

+ 144 - 0
compiler/aasmcnst.pas

@@ -185,6 +185,32 @@ type
      { array of caggregateinformation instances }
      faggregateinformation: tfpobjectlist;
 
+    { Support for generating data that is only referenced from the typed
+      constant data that we are currently generated. Such data can all be put
+      in the same dead-strippable unit, as it's either all included or none of
+      it is included. This data can be spread over multiple kinds of sections
+      though (e.g. rodata and rodata_no_rel), so per section keep track whether
+      we already started a dead-strippable unit and if so, what the section
+      name was (so that on platforms that perform the dead stripping based on
+      sections, we put all data for one typed constant into a single section
+      with the same name) }
+    protected type
+     tinternal_data_section_info = record
+       secname: TSymStr;
+       sectype: TAsmSectiontype;
+     end;
+    protected var
+     { all internally generated data must be stored in the same list, as it must
+       be consecutive (if it's spread over multiple lists, we don't know in
+       which order they'll be concatenated) -> keep track of this list }
+     finternal_data_asmlist: tasmlist;
+     { kind of the last section we started in the finternal_data_asmlist, to
+       avoid creating unnecessary section statements }
+     finternal_data_current_section: TAsmSectiontype;
+     { info about in which kinds of sections we have already emitted internal
+       data, and what their names were }
+     finternal_data_section_info: array of tinternal_data_section_info;
+
      { ensure that finalize_asmlist is called only once }
      fasmlist_finalized: boolean;
 
@@ -203,12 +229,27 @@ type
        location }
      procedure pad_next_field(nextfielddef: tdef);
 
+     { returns the index in finternal_data_section_info of the info for the
+       section of type typ. Returns -1 if there is no such info yet }
+     function get_internal_data_section_index(typ: TAsmSectiontype): longint;
+
      { easy access to the top level aggregate information instance }
      property curagginfo: taggregateinformation read getcurragginfo;
     public
      constructor create(const options: ttcasmlistoptions); virtual;
      destructor destroy; override;
 
+    public
+     { returns a builder for generating data that is only referrenced by the
+       typed constant date we are currently generating (e.g. string data for a
+       pchar constant). Also returns the label that will be placed at the start
+       of that data. list is the tasmlist to which the data will be }
+     procedure start_internal_data_builder(list: tasmlist; sectype: TAsmSectiontype; out tcb: ttai_typedconstbuilder; out l: tasmlabel);
+     { finish a previously started internal data builder, including
+       concatenating all generated data to the provided list and freeing the
+       builder }
+     procedure finish_internal_data_builder(var tcb: ttai_typedconstbuilder; l: tasmlabel; def: tdef; alignment: longint);
+
      { add a simple constant data element (p) to the typed constant.
        def is the type of the added value }
      procedure emit_tai(p: tai; def: tdef); virtual;
@@ -649,6 +690,15 @@ implementation
      end;
 
 
+   function ttai_typedconstbuilder.get_internal_data_section_index(typ: TAsmSectiontype): longint;
+     begin
+       for result:=low(finternal_data_section_info) to high(finternal_data_section_info) do
+         if finternal_data_section_info[result].sectype=typ then
+           exit;
+       result:=-1;
+     end;
+
+
    function ttai_typedconstbuilder.aggregate_kind(def: tdef): ttypedconstkind;
      begin
        if (def.typ in [recorddef,filedef,variantdef]) or
@@ -771,6 +821,7 @@ implementation
        foptions:=options;
        { queue is empty }
        fqueue_offset:=low(fqueue_offset);
+       finternal_data_current_section:=sec_none;
      end;
 
 
@@ -785,6 +836,99 @@ implementation
      end;
 
 
+   procedure ttai_typedconstbuilder.start_internal_data_builder(list: tasmlist; sectype: TAsmSectiontype; out tcb: ttai_typedconstbuilder; out l: tasmlabel);
+     var
+       options: ttcasmlistoptions;
+       foundsec: longint;
+     begin
+       options:=[tcalo_is_lab];
+       { Add a section header if the previous one was different. We'll use the
+         same section name in case multiple items are added to the same kind of
+         section (rodata, rodata_no_rel, ...), so that everything will still
+         end up in the same section even if there are multiple section headers }
+       if finternal_data_current_section<>sectype then
+         include(options,tcalo_new_section);
+       finternal_data_current_section:=sectype;
+       l:=nil;
+       { did we already create a section of this type for the internal data of
+         this builder? }
+       foundsec:=get_internal_data_section_index(sectype);
+       if foundsec=-1 then
+         begin
+           { we only need to start a dead-strippable section of data at the
+             start of the first subsection of this kind for this block.
+
+             exception: if dead stripping happens based on objects/libraries,
+             then we only have to create a new object file for the first
+             internal data section of any kind (all the rest will simply be put
+             in the same object file) }
+           if create_smartlink then
+             begin
+               if not create_smartlink_library or
+                  (length(finternal_data_section_info)=0) then
+                 include(options,tcalo_make_dead_strippable);
+               { on Darwin, dead code/data stripping happens based on non-
+                 temporary labels (any label that doesn't start with "L" -- it
+                 doesn't have to be global) -> add a non-temporary lobel at the
+                 start of every kind of subsection created in this builder }
+               if target_info.system in systems_darwin then
+                 current_asmdata.getstaticdatalabel(l)
+             end;
+           foundsec:=length(finternal_data_section_info);
+           setlength(finternal_data_section_info,foundsec+1);
+           finternal_data_section_info[foundsec].sectype:=sectype;
+         end;
+       if not assigned(finternal_data_asmlist) and
+          (cs_create_smart in current_settings.moduleswitches) then
+         begin
+           { on Darwin, dead code/data stripping happens based on non-temporary
+             labels (any label that doesn't start with "L" -- it doesn't have
+             to be global) }
+           if target_info.system in systems_darwin then
+             current_asmdata.getstaticdatalabel(l)
+           else if create_smartlink_library then
+             current_asmdata.getglobaldatalabel(l);
+           { the internal data list should only be assigned by this routine,
+             the first time that an internal data block is started }
+           if not assigned(list) or
+              assigned(finternal_data_asmlist) then
+             internalerror(2015032101);
+           finternal_data_asmlist:=list;
+         end
+       { all internal data for this tcb must go to the same list (otherwise all
+         data we want to add to the dead-strippable block is not guaranteed to
+         be sequential and e.g. in the same object file in case of library-based
+         dead stripping) }
+       else if (assigned(finternal_data_asmlist) and
+           (list<>finternal_data_asmlist)) or
+           not assigned(list) then
+         internalerror(2015032101);
+       finternal_data_asmlist:=list;
+       if not assigned(l) then
+         if create_smartlink_library then
+           { all labels need to be global in case they're in another object }
+           current_asmdata.getglobaldatalabel(l)
+         else
+           { no special requirement for the label -> just get a local one }
+           current_asmdata.getlocaldatalabel(l);
+       { first section of this kind -> set name }
+       if finternal_data_section_info[foundsec].secname='' then
+         finternal_data_section_info[foundsec].secname:=l.Name;
+       tcb:=ttai_typedconstbuilderclass(classtype).create(options);
+     end;
+
+
+   procedure ttai_typedconstbuilder.finish_internal_data_builder(var tcb: ttai_typedconstbuilder; l: tasmlabel; def: tdef; alignment: longint);
+     begin
+       finternal_data_asmlist.concatList(tcb.get_final_asmlist(l,def,
+         finternal_data_current_section,
+         finternal_data_section_info[get_internal_data_section_index(finternal_data_current_section)].secname,
+         alignment));
+       tcb.free;
+       tcb:=nil;
+     end;
+
+
    procedure ttai_typedconstbuilder.emit_tai(p: tai; def: tdef);
      var
        kind: ttypedconstkind;