* 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 -
This commit is contained in:
yury 2020-09-05 18:20:18 +00:00
parent acef1e22d3
commit c2dc342c55
2 changed files with 93 additions and 15 deletions

View File

@ -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;

View File

@ -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;