From c2dc342c556e5fd9a6db27b7de8f12e193b0fbb0 Mon Sep 17 00:00:00 2001 From: yury Date: Sat, 5 Sep 2020 18:20:18 +0000 Subject: [PATCH] * 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 - --- compiler/ncgutil.pas | 33 +++++++++++++++++++ compiler/rgobj.pas | 75 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas index bab9f65218..3969742a45 100644 --- a/compiler/ncgutil.pas +++ b/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; diff --git a/compiler/rgobj.pas b/compiler/rgobj.pas index de8d30cb3c..25dcad7740 100644 --- a/compiler/rgobj.pas +++ b/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)=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)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;