From 89c9cdf6c47c6cc32741ff1c5537d11fa0df5bbb Mon Sep 17 00:00:00 2001 From: sergei Date: Tue, 25 Jun 2013 08:15:17 +0000 Subject: [PATCH] + 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 - --- compiler/mips/cgcpu.pas | 42 ++++++++++++++++++++++----------------- compiler/mips/cpupara.pas | 38 ++++++++++++++++++++++++++--------- compiler/mips/cpupi.pas | 13 +----------- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/compiler/mips/cgcpu.pas b/compiler/mips/cgcpu.pas index 32aa358af3..c7e9280337 100644 --- a/compiler/mips/cgcpu.pas +++ b/compiler/mips/cgcpu.pas @@ -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; diff --git a/compiler/mips/cpupara.pas b/compiler/mips/cpupara.pas index 82f65a8772..a5db3253cc 100644 --- a/compiler/mips/cpupara.pas +++ b/compiler/mips/cpupara.pas @@ -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