From 3462426b1d74924f7c785660b8c6cc6d971c03c3 Mon Sep 17 00:00:00 2001 From: tom_at_work Date: Wed, 4 Jan 2006 23:27:40 +0000 Subject: [PATCH] * stack frame optimizations git-svn-id: trunk@2172 - --- compiler/ncgutil.pas | 10 +++++--- compiler/powerpc64/cgcpu.pas | 44 +++++++++++++++++++++++++++++----- compiler/powerpc64/cpubase.pas | 4 ++++ compiler/powerpc64/cpupara.pas | 7 ++++-- compiler/powerpc64/cpupi.pas | 11 +++++++-- 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/compiler/ncgutil.pas b/compiler/ncgutil.pas index c08fb12a3d..11f082e521 100644 --- a/compiler/ncgutil.pas +++ b/compiler/ncgutil.pas @@ -136,6 +136,9 @@ implementation {$ifdef powerpc} , cpupi {$endif} +{$ifdef powerpc64} + , cpupi +{$endif} ; @@ -1346,10 +1349,10 @@ implementation case paraloc.loc of LOC_REGISTER : begin - {$IFDEF CPUPOWERPC64} + {$IFDEF POWERPC64} if (paraloc.shiftval <> 0) then cg.a_op_const_reg_reg(list, OP_SHL, OS_INT, paraloc.shiftval, paraloc.register, paraloc.register); - {$ENDIF CPUPOWERPC64} + {$ENDIF POWERPC64} cg.a_load_reg_ref(list,paraloc.size,paraloc.size,paraloc.register,ref); end; LOC_MMREGISTER : @@ -1576,7 +1579,8 @@ implementation {$ifdef powerpc64} { unget the register that contains the stack pointer before the procedure entry, } { which is used to access the parameters in their original callee-side location } - cg.a_reg_dealloc(list, NR_OLD_STACK_POINTER_REG); + if (tppcprocinfo(current_procinfo).needs_frame_pointer) then + cg.a_reg_dealloc(list, NR_OLD_STACK_POINTER_REG); {$endif powerpc64} end; diff --git a/compiler/powerpc64/cgcpu.pas b/compiler/powerpc64/cgcpu.pas index 61b9fbddd1..f6cac15c90 100644 --- a/compiler/powerpc64/cgcpu.pas +++ b/compiler/powerpc64/cgcpu.pas @@ -129,6 +129,8 @@ type { the sum of part of the original reference } function fixref(list: taasmoutput; var ref: treference; const size : TCgsize): boolean; + function load_got_symbol(list : taasmoutput; symbol : string) : tregister; + { returns whether a reference can be used immediately in a powerpc } { instruction } function issimpleref(const ref: treference): boolean; @@ -1304,7 +1306,8 @@ begin { determine whether we need to save the link register } needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and (pi_do_call in current_procinfo.flags)) or - ((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0))); + ((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0))) or + ([cs_lineinfo, cs_debuginfo] * aktmoduleswitches <> []); a_reg_alloc(list, NR_STACK_POINTER_REG); a_reg_alloc(list, NR_R0); @@ -1316,7 +1319,7 @@ begin save_standard_registers; { save old stack frame pointer } - if (localsize > 0) then begin + if (tppcprocinfo(current_procinfo).needs_frame_pointer) then begin a_reg_alloc(list, NR_OLD_STACK_POINTER_REG); list.concat(taicpu.op_reg_reg(A_MR, NR_OLD_STACK_POINTER_REG, NR_STACK_POINTER_REG)); end; @@ -1441,7 +1444,8 @@ begin { determine whether we need to restore the link register } needslinkreg := ((not (po_assembler in current_procinfo.procdef.procoptions)) and (pi_do_call in current_procinfo.flags)) or - ((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0))); + ((cs_littlesize in aktglobalswitches) and ((fprcount > 0) or (gprcount > 0))) or + ([cs_lineinfo, cs_debuginfo] * aktmoduleswitches <> []); { calculate stack frame } localsize := tppcprocinfo(current_procinfo).calc_stackframe_size( @@ -1819,13 +1823,41 @@ begin (ref.offset = 0))); end; +function tcgppc.load_got_symbol(list: taasmoutput; symbol : string) : tregister; +var + l: tasmsymbol; + ref: treference; +begin + l:=objectlibrary.getasmsymbol(symbol+'$got'); + if not(assigned(l)) then begin + l:=objectlibrary.newasmsymbol(symbol+'$got',AB_COMMON,AT_DATA); + asmlist[al_picdata].concat(tai_symbol.create(l,0)); + asmlist[al_picdata].concat(tai_const.create_indirect_sym(objectlibrary.newasmsymbol(symbol,AB_EXTERNAL,AT_DATA))); + asmlist[al_picdata].concat(tai_const.create_32bit(0)); + end; + reference_reset_symbol(ref,l,0); + ref.base := NR_R2; + result := cg.rg[R_INTREGISTER].getregister(list, R_SUBWHOLE); + cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,result); +end; + function tcgppc.fixref(list: taasmoutput; var ref: treference; const size : TCgsize): boolean; var - tmpreg: tregister; - needsAlign : boolean; + tmpreg: tregister; + name : string; begin result := false; - needsAlign := size in [OS_S32, OS_64, OS_S64]; + if (cs_create_pic in aktmoduleswitches) and (assigned(ref.symbol)) and (ref.symbol.defbind = AB_EXTERNAL) then begin + if (length(name) > 100) then internalerror(123456); + tmpreg := load_got_symbol(list, ref.symbol.name); + if (ref.base = NR_NO) then + ref.base := tmpreg + else if (ref.index = NR_NO) then + ref.index := tmpreg + else + list.concat(taicpu.op_reg_reg_reg(A_ADD,ref.base,ref.base,tmpreg)); + ref.symbol := nil; + end; if (ref.base = NR_NO) then begin ref.base := ref.index; diff --git a/compiler/powerpc64/cpubase.pas b/compiler/powerpc64/cpubase.pas index 0fe3932355..0f0ad34b2c 100644 --- a/compiler/powerpc64/cpubase.pas +++ b/compiler/powerpc64/cpubase.pas @@ -370,6 +370,10 @@ const ELF_STACK_ALIGN = 16; + { the size of the "red zone" which must not be changed by asynchronous calls + in the stack frame and can be used for storing temps } + RED_ZONE_SIZE = 288; + {***************************************************************************** Helpers *****************************************************************************} diff --git a/compiler/powerpc64/cpupara.pas b/compiler/powerpc64/cpupara.pas index 4c4ec8583b..2ce3d168b9 100644 --- a/compiler/powerpc64/cpupara.pas +++ b/compiler/powerpc64/cpupara.pas @@ -62,7 +62,8 @@ implementation uses verbose, systems, defutil, - cgutils; + cgutils, + procinfo, cpupi; function tppcparamanager.get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; @@ -417,9 +418,11 @@ begin paraloc^.size := int_cgsize(paralen); if (side = callerside) then paraloc^.reference.index := NR_STACK_POINTER_REG - else + else begin { during procedure entry, NR_OLD_STACK_POINTER_REG contains the old stack pointer } paraloc^.reference.index := NR_OLD_STACK_POINTER_REG; + tppcprocinfo(current_procinfo).needs_frame_pointer := true; + end; paraloc^.reference.offset := stack_offset; { align temp contents to next register size } diff --git a/compiler/powerpc64/cpupi.pas b/compiler/powerpc64/cpupi.pas index f733950e09..5161bd312e 100644 --- a/compiler/powerpc64/cpupi.pas +++ b/compiler/powerpc64/cpupi.pas @@ -40,6 +40,8 @@ type procedure allocate_push_parasize(size: longint); override; function calc_stackframe_size: longint; override; function calc_stackframe_size(numgpr, numfpr : longint): longint; + + needs_frame_pointer : boolean; end; implementation @@ -57,6 +59,7 @@ constructor tppcprocinfo.create(aparent: tprocinfo); begin inherited create(aparent); maxpushedparasize := 0; + needs_frame_pointer := false; end; procedure tppcprocinfo.set_first_temp_offset; @@ -100,8 +103,12 @@ begin { more or less copied from cgcpu.pas/g_stackframe_entry } if not (po_assembler in procdef.procoptions) then begin // no VMX support - result := align(align(numgpr * tcgsize2size[OS_INT] + - numfpr * tcgsize2size[OS_FLOAT], ELF_STACK_ALIGN) + tg.lasttemp, ELF_STACK_ALIGN); + result := align(numgpr * tcgsize2size[OS_INT] + + numfpr * tcgsize2size[OS_FLOAT], ELF_STACK_ALIGN); + + if not ((not (pi_do_call in flags)) and (tg.lasttemp = tg.firsttemp) and + (result <= RED_ZONE_SIZE)) then + result := align(result + tg.lasttemp, ELF_STACK_ALIGN); end else result := align(tg.lasttemp, ELF_STACK_ALIGN); end;