Jelajahi Sumber

* Use the initial location of stack parameters as a spilling location if spilling is needed. This leads to the following optimizations:
- no spill temp is allocated;
- no load of a stack parameter to a spill temp;
- if a stack parameter is used only once do not preload it to a register. The parameter can be accessed directly in the stack if the target CPU supports this.

git-svn-id: trunk@46776 -

yury 4 tahun lalu
induk
melakukan
c2dc342c55
2 mengubah file dengan 93 tambahan dan 15 penghapusan
  1. 33 0
      compiler/ncgutil.pas
  2. 60 15
      compiler/rgobj.pas

+ 33 - 0
compiler/ncgutil.pas

@@ -588,6 +588,34 @@ implementation
 
 
     procedure gen_alloc_regvar(list:TAsmList;sym: tabstractnormalvarsym; allocreg: boolean);
+
+      procedure set_para_regvar_initial_location;
+        var
+          paraloc: PCGParalocation;
+          loc: tlocation;
+          regtype: tregistertype;
+          reg: tregister;
+          size: tcgint;
+        begin
+          tparavarsym(sym).paraloc[calleeside].get_location(loc);
+          size:=tparavarsym(sym).paraloc[calleeside].IntSize;
+          paraloc:=tparavarsym(sym).paraloc[calleeside].Location;
+          reg:=sym.initialloc.register;
+          regtype:=getregtype(reg);
+          repeat
+            loc.reference.offset:=paraloc^.reference.offset;
+            cg.rg[regtype].set_reg_initial_location(reg,loc.reference);
+            dec(size,tcgsize2size[paraloc^.Size]);
+{$if defined(cpu8bitalu) or defined(cpu16bitalu)}
+            if cg.has_next_reg[getsupreg(reg)] then
+              reg:=cg.GetNextReg(reg)
+            else
+{$endif}
+              reg:=sym.initialloc.registerhi;
+            paraloc:=paraloc^.Next;
+          until size=0;
+        end;
+
       var
         usedef: tdef;
         varloc: tai_varloc;
@@ -674,6 +702,11 @@ implementation
 {$endif cpu64bitalu and not cpuhighleveltarget}
           varloc:=tai_varloc.create(sym,sym.initialloc.register);
         list.concat(varloc);
+        { Notify the register allocator about memory location of
+          the register which holds a value of a stack parameter }
+        if (sym.typ=paravarsym) and
+          (tparavarsym(sym).paraloc[calleeside].Location^.Loc=LOC_REFERENCE) then
+          set_para_regvar_initial_location;
       end;
 
 

+ 60 - 15
compiler/rgobj.pas

@@ -93,9 +93,10 @@ unit rgobj;
       end;
 
       Treginfoflag=(
-        ri_coalesced,   { the register is coalesced with other register }
-        ri_selected,    { the register is put to selectstack }
-        ri_spill_read   { the register contains a value loaded from a spilled register }
+        ri_coalesced,       { the register is coalesced with other register }
+        ri_selected,        { the register is put to selectstack }
+        ri_spill_read,      { the register contains a value loaded from a spilled register }
+        ri_has_initial_loc  { the register has the initial memory location (e.g. a parameter in the stack) }
       );
       Treginfoflagset=set of Treginfoflag;
 
@@ -189,6 +190,8 @@ unit rgobj;
         procedure add_edge(u,v:Tsuperregister);
         { translates a single given imaginary register to it's real register }
         procedure translate_register(var reg : tregister);
+        { sets the initial memory location of the register }
+        procedure set_reg_initial_location(reg: tregister; const ref: treference);
       protected
         maxreginfo,
         maxreginfoinc,
@@ -293,6 +296,7 @@ unit rgobj;
         function get_live_start(reg : tsuperregister) : tai;
         procedure set_live_end(reg : tsuperregister;t : tai);
         function get_live_end(reg : tsuperregister) : tai;
+        procedure alloc_spillinfo(max_reg: Tsuperregister);
 {$ifdef DEBUG_SPILLCOALESCE}
         procedure write_spill_stats;
 {$endif DEBUG_SPILLCOALESCE}
@@ -637,10 +641,18 @@ unit rgobj;
           i8086 where indexed memory access instructions allow only
           few registers as arguments and additionally the calling convention
           provides no general purpose volatile registers.
+          
+          Also spill registers which have the initial memory location
+          and are used only once. This allows to access the memory location
+          directly, without preloading it to a register.
         }
         for i:=first_imaginary to maxreg-1 do
-          if reginfo[i].real_reg_interferences>=usable_registers_cnt then
-            spillednodes.add(i);
+          with reginfo[i] do
+            if (real_reg_interferences>=usable_registers_cnt) or
+               { also spill registers which have the initial memory location
+                 and are used only once }
+               ((ri_has_initial_loc in flags) and (weight<=200)) then
+              spillednodes.add(i);
         if spillednodes.length<>0 then
           begin
             spill_registers(list,headertai);
@@ -859,6 +871,19 @@ unit rgobj;
       end;
 
 
+    procedure trgobj.alloc_spillinfo(max_reg: Tsuperregister);
+      var
+        j: longint;
+      begin
+        if Length(spillinfo)<max_reg then
+          begin
+            j:=Length(spillinfo);
+            SetLength(spillinfo,max_reg);
+            fillchar(spillinfo[j],sizeof(spillinfo[0])*(Length(spillinfo)-j),0);
+          end;
+      end;
+
+
     procedure trgobj.add_reg_instruction(instr:Tai;r:tregister;aweight:longint);
       var
         supreg : tsuperregister;
@@ -2106,7 +2131,20 @@ unit rgobj;
       end;
 
 
-    procedure Trgobj.translate_registers(list:TAsmList);
+    procedure trgobj.set_reg_initial_location(reg: tregister; const ref: treference);
+      var
+        supreg: TSuperRegister;
+      begin
+        supreg:=getsupreg(reg);
+        if supreg>=maxreg then
+          internalerror(2020090501);
+        alloc_spillinfo(supreg+1);
+        spillinfo[supreg].spilllocation:=ref;
+        include(reginfo[supreg].flags,ri_has_initial_loc);
+      end;
+
+
+    procedure trgobj.translate_registers(list: TAsmList);
 
       function get_reg_name_full(r: tregister): string;
         var
@@ -2332,13 +2370,7 @@ unit rgobj;
         writeln('trgobj.spill_registers: Spilling ',spillednodes.length,' nodes');
 {$endif DEBUG_SPILLCOALESCE}
         { after each round of spilling, more registers could be used due to allocations for spilling }
-        if Length(spillinfo)<maxreg then
-          begin
-            j:=Length(spillinfo);
-            SetLength(spillinfo,maxreg);
-            fillchar(spillinfo[j],sizeof(spillinfo[0])*(Length(spillinfo)-j),0);
-          end;
-
+        alloc_spillinfo(maxreg);
         { Allocate temps and insert in front of the list }
         templist:=TAsmList.create;
         { Safe: this procedure is only called if there are spilled nodes. }
@@ -2363,7 +2395,9 @@ unit rgobj;
               { Clear all interferences of the spilled register. }
               clear_interferences(t);
 
-              getnewspillloc:=true;
+              getnewspillloc:=not (ri_has_initial_loc in reginfo[t].flags);
+              if not getnewspillloc then
+                spill_temps^[t]:=spillinfo[t].spilllocation;
 
               { check if we can "coalesce" spilled nodes. To do so, it is required that they do not
                 interfere but are connected by a move instruction
@@ -2427,6 +2461,17 @@ unit rgobj;
                         supreg:=getsupreg(reg);
                         if supregset_in(regs_to_spill_set,supreg) then
                           begin
+                            { Remove loading of the register from its initial memory location
+                              (e.g. load of a stack parameter to the register). }
+                            if (ratype=ra_alloc) and
+                               (ri_has_initial_loc in reginfo[supreg].flags) and
+                               (instr<>nil) then
+                              begin
+                                list.remove(instr);
+                                FreeAndNil(instr);
+                                dec(reginfo[supreg].weight,100);
+                              end;
+                            { Remove the regalloc }
                             q:=Tai(p.next);
                             list.remove(p);
                             p.free;
@@ -2466,7 +2511,7 @@ unit rgobj;
         {Safe: this procedure is only called if there are spilled nodes.}
         with spillednodes do
           for i:=0 to length-1 do
-            tg.ungettemp(list,spill_temps^[buf^[i]]);
+            tg.ungetiftemp(list,spill_temps^[buf^[i]]);
         freemem(spill_temps);
       end;