mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-14 11:39:27 +02:00
* 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:
parent
acef1e22d3
commit
c2dc342c55
@ -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;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user