mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-07 05:08:06 +02:00
+ 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:
parent
466eb4c684
commit
89c9cdf6c4
@ -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;
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user