Explorar o código

* 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 %!s(int64=4) %!d(string=hai) anos
pai
achega
c2dc342c55
Modificáronse 2 ficheiros con 93 adicións e 15 borrados
  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 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
       var
         usedef: tdef;
         usedef: tdef;
         varloc: tai_varloc;
         varloc: tai_varloc;
@@ -674,6 +702,11 @@ implementation
 {$endif cpu64bitalu and not cpuhighleveltarget}
 {$endif cpu64bitalu and not cpuhighleveltarget}
           varloc:=tai_varloc.create(sym,sym.initialloc.register);
           varloc:=tai_varloc.create(sym,sym.initialloc.register);
         list.concat(varloc);
         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;
       end;
 
 
 
 

+ 60 - 15
compiler/rgobj.pas

@@ -93,9 +93,10 @@ unit rgobj;
       end;
       end;
 
 
       Treginfoflag=(
       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;
       Treginfoflagset=set of Treginfoflag;
 
 
@@ -189,6 +190,8 @@ unit rgobj;
         procedure add_edge(u,v:Tsuperregister);
         procedure add_edge(u,v:Tsuperregister);
         { translates a single given imaginary register to it's real register }
         { translates a single given imaginary register to it's real register }
         procedure translate_register(var reg : tregister);
         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
       protected
         maxreginfo,
         maxreginfo,
         maxreginfoinc,
         maxreginfoinc,
@@ -293,6 +296,7 @@ unit rgobj;
         function get_live_start(reg : tsuperregister) : tai;
         function get_live_start(reg : tsuperregister) : tai;
         procedure set_live_end(reg : tsuperregister;t : tai);
         procedure set_live_end(reg : tsuperregister;t : tai);
         function get_live_end(reg : tsuperregister) : tai;
         function get_live_end(reg : tsuperregister) : tai;
+        procedure alloc_spillinfo(max_reg: Tsuperregister);
 {$ifdef DEBUG_SPILLCOALESCE}
 {$ifdef DEBUG_SPILLCOALESCE}
         procedure write_spill_stats;
         procedure write_spill_stats;
 {$endif DEBUG_SPILLCOALESCE}
 {$endif DEBUG_SPILLCOALESCE}
@@ -637,10 +641,18 @@ unit rgobj;
           i8086 where indexed memory access instructions allow only
           i8086 where indexed memory access instructions allow only
           few registers as arguments and additionally the calling convention
           few registers as arguments and additionally the calling convention
           provides no general purpose volatile registers.
           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
         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
         if spillednodes.length<>0 then
           begin
           begin
             spill_registers(list,headertai);
             spill_registers(list,headertai);
@@ -859,6 +871,19 @@ unit rgobj;
       end;
       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);
     procedure trgobj.add_reg_instruction(instr:Tai;r:tregister;aweight:longint);
       var
       var
         supreg : tsuperregister;
         supreg : tsuperregister;
@@ -2106,7 +2131,20 @@ unit rgobj;
       end;
       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;
       function get_reg_name_full(r: tregister): string;
         var
         var
@@ -2332,13 +2370,7 @@ unit rgobj;
         writeln('trgobj.spill_registers: Spilling ',spillednodes.length,' nodes');
         writeln('trgobj.spill_registers: Spilling ',spillednodes.length,' nodes');
 {$endif DEBUG_SPILLCOALESCE}
 {$endif DEBUG_SPILLCOALESCE}
         { after each round of spilling, more registers could be used due to allocations for spilling }
         { 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 }
         { Allocate temps and insert in front of the list }
         templist:=TAsmList.create;
         templist:=TAsmList.create;
         { Safe: this procedure is only called if there are spilled nodes. }
         { 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 all interferences of the spilled register. }
               clear_interferences(t);
               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
               { 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
                 interfere but are connected by a move instruction
@@ -2427,6 +2461,17 @@ unit rgobj;
                         supreg:=getsupreg(reg);
                         supreg:=getsupreg(reg);
                         if supregset_in(regs_to_spill_set,supreg) then
                         if supregset_in(regs_to_spill_set,supreg) then
                           begin
                           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);
                             q:=Tai(p.next);
                             list.remove(p);
                             list.remove(p);
                             p.free;
                             p.free;
@@ -2466,7 +2511,7 @@ unit rgobj;
         {Safe: this procedure is only called if there are spilled nodes.}
         {Safe: this procedure is only called if there are spilled nodes.}
         with spillednodes do
         with spillednodes do
           for i:=0 to length-1 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);
         freemem(spill_temps);
       end;
       end;