+ MIPS: implemented parameter location reusing, eliminating second copy of (potentially large) records passed by value. When parameter is passed both in registers and stack, let it have a single LOC_REFERENCE location on callee side, and store relevant registers on stack (into 16-byte area reserved by ABI) early in prologue.

git-svn-id: trunk@24970 -
This commit is contained in:
sergei 2013-06-25 08:15:17 +00:00
parent 466eb4c684
commit 89c9cdf6c4
3 changed files with 54 additions and 39 deletions

View File

@ -1157,6 +1157,20 @@ end;
{ *********** entry/exit code and address loading ************ }
procedure FixupOffsets(p:TObject;arg:pointer);
var
sym: tabstractnormalvarsym absolute p;
begin
if (tsym(p).typ=paravarsym) and
(sym.localloc.loc=LOC_REFERENCE) and
(sym.localloc.reference.base=NR_FRAME_POINTER_REG) then
begin
sym.localloc.reference.base:=NR_STACK_POINTER_REG;
Inc(sym.localloc.reference.offset,PLongint(arg)^);
end;
end;
procedure TCGMIPS.g_proc_entry(list: tasmlist; localsize: longint; nostackframe: boolean);
var
lastintoffset,lastfpuoffset,
@ -1283,28 +1297,20 @@ begin
list.concat(Taicpu.op_none(A_P_SET_NOMACRO));
end;
with TMIPSProcInfo(current_procinfo) do
begin
href.offset:=0;
//if current_procinfo.framepointer<>NR_STACK_POINTER_REG then
href.base:=NR_FRAME_POINTER_REG;
href.base:=NR_STACK_POINTER_REG;
for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
if (register_used[i]) then
begin
reg:=parasupregs[i];
if register_offset[i]=-1 then
comment(V_warning,'Register parameter has offset -1 in TCGMIPS.g_proc_entry');
for i:=0 to MIPS_MAX_REGISTERS_USED_IN_CALL-1 do
if TMIPSProcInfo(current_procinfo).register_used[i] then
begin
reg:=parasupregs[i];
href.offset:=i*sizeof(aint)+LocalSize;
list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
end;
//if current_procinfo.framepointer=NR_STACK_POINTER_REG then
// href.offset:=register_offset[i]+Localsize
//else
href.offset:=register_offset[i];
list.concat(taicpu.op_reg_ref(A_SW, newreg(R_INTREGISTER,reg,R_SUBWHOLE), href));
end;
end;
list.concatList(helplist);
helplist.Free;
if current_procinfo.has_nestedprocs then
current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@LocalSize);
end;

View File

@ -31,8 +31,6 @@ interface
symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase,cgutils;
const
MIPS_MAX_OFFSET = 20;
{ The value below is OK for O32 and N32 calling conventions }
MIPS_MAX_REGISTERS_USED_IN_CALL = 6;
@ -63,9 +61,6 @@ interface
type
tparasupregs = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of tsuperregister;
tparasupregsused = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of boolean;
tparasupregsize = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of tcgsize;
tparasuprename = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of shortstring;
tparasupregsoffset = array[0..MIPS_MAX_REGISTERS_USED_IN_CALL-1] of longint;
const
@ -79,6 +74,7 @@ interface
function create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override;
function create_varargs_paraloc_info(p : TAbstractProcDef; varargspara:tvarargsparalist):longint;override;
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
function param_use_paraloc(const cgpara: tcgpara): boolean; override;
private
intparareg,
intparasize : longint;
@ -119,6 +115,16 @@ implementation
end;
function TMIPSParaManager.param_use_paraloc(const cgpara: tcgpara): boolean;
var
paraloc: pcgparalocation;
begin
paraloc:=cgpara.location;
if not assigned(paraloc) then
internalerror(200410102);
result:=(paraloc^.loc=LOC_REFERENCE) and (paraloc^.next=nil);
end;
{ true if a parameter is too large to copy and only the address is pushed }
function TMIPSParaManager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
@ -231,7 +237,7 @@ implementation
procedure TMIPSParaManager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist);
var
paraloc : pcgparalocation;
i : integer;
i,j : integer;
hp : tparavarsym;
paracgsize : tcgsize;
paralen : longint;
@ -242,6 +248,7 @@ implementation
alignment : longint;
tmp : longint;
firstparaloc : boolean;
reg_and_stack: boolean;
begin
fpparareg := 0;
for i:=0 to paras.count-1 do
@ -340,6 +347,9 @@ implementation
can_use_float := false;
firstparaloc:=true;
{ Is parameter split between stack and registers? }
reg_and_stack:=(side=calleeside) and
(paralen+intparasize>16) and (intparasize<16);
while paralen>0 do
begin
paraloc:=hp.paraloc[side].add_location;
@ -368,11 +378,14 @@ implementation
paraloc^.register:=newreg(R_INTREGISTER,parasupregs[0],R_SUBWHOLE);
inc(intparasize,align(tcgsize2size[paraloc^.size],sizeof(aint)));
end
{ In case of po_delphi_nested_cc, the parent frame pointer
is always passed on the stack. }
{ "In case of po_delphi_nested_cc, the parent frame pointer
is always passed on the stack". On other targets it is
used to provide caller-side stack cleanup and prevent stackframe
optimization. For MIPS this does not matter. }
else if (intparareg<mips_nb_used_registers) and
(not reg_and_stack) {and
(not(vo_is_parentfp in hp.varoptions) or
not(po_delphi_nested_cc in p.procoptions)) then
not(po_delphi_nested_cc in p.procoptions))} then
begin
if (can_use_float) then
begin
@ -418,6 +431,13 @@ implementation
end
else
begin
if reg_and_stack then
begin
for j:=intparareg to mips_nb_used_registers-1 do
tmipsprocinfo(current_procinfo).register_used[j]:=true;
{ all registers used now }
intparareg:=mips_nb_used_registers;
end;
paraloc^.loc:=LOC_REFERENCE;
paraloc^.size:=int_cgsize(paralen);
paraloc^.def:=get_paraloc_def(locdef,paralen,firstparaloc);

View File

@ -41,9 +41,6 @@ interface
intregssave,
floatregssave : byte;
register_used : tparasupregsused;
register_size : tparasupregsize;
register_name : tparasuprename;
register_offset : tparasupregsoffset;
computed_local_size : longint;
save_gp_ref: treference;
//intparareg,
@ -66,20 +63,12 @@ implementation
tgobj,paramgr,symconst;
constructor TMIPSProcInfo.create(aparent: tprocinfo);
var
i : longint;
begin
inherited create(aparent);
{ if (cs_generate_stackframes in current_settings.localswitches) or
not (cs_opt_stackframe in current_settings.optimizerswitches) then }
include(flags,pi_needs_stackframe);
for i:=low(tparasupregs) to high(tparasupregs) do
begin
register_used[i]:=false;
register_size[i]:=OS_NO;
register_name[i]:='invalid';
register_offset[i]:=-1;
end;
floatregssave:=12; { f20-f31 }
intregssave:=10; { r16-r23,r30,r31 }
computed_local_size:=-1;