mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 09:59:08 +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 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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,9 +93,10 @@ unit rgobj;
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
Treginfoflag=(
|
Treginfoflag=(
|
||||||
ri_coalesced, { the register is coalesced with other register }
|
ri_coalesced, { the register is coalesced with other register }
|
||||||
ri_selected, { the register is put to selectstack }
|
ri_selected, { the register is put to selectstack }
|
||||||
ri_spill_read { the register contains a value loaded from a spilled register }
|
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
|
with reginfo[i] do
|
||||||
spillednodes.add(i);
|
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
|
alloc_spillinfo(maxreg);
|
||||||
begin
|
|
||||||
j:=Length(spillinfo);
|
|
||||||
SetLength(spillinfo,maxreg);
|
|
||||||
fillchar(spillinfo[j],sizeof(spillinfo[0])*(Length(spillinfo)-j),0);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ 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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user