summaryrefslogtreecommitdiff
path: root/compiler/powerpc64
diff options
context:
space:
mode:
authortom_at_work <tom_at_work@3ad0048d-3df7-0310-abae-a5850022a9f2>2006-01-04 23:27:40 +0000
committertom_at_work <tom_at_work@3ad0048d-3df7-0310-abae-a5850022a9f2>2006-01-04 23:27:40 +0000
commit4ee5645d9921c2b0e3b41da74e092d12bd15fedc (patch)
tree10a439b0cbcb94f061c4ebe15faa70d91eb89f14 /compiler/powerpc64
parent5b17ea9a50a4ae692b18f6963fdd8326720d62b9 (diff)
downloadfpc-4ee5645d9921c2b0e3b41da74e092d12bd15fedc.tar.gz
* stack frame optimizations
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@2172 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler/powerpc64')
-rw-r--r--compiler/powerpc64/cgcpu.pas44
-rw-r--r--compiler/powerpc64/cpubase.pas4
-rw-r--r--compiler/powerpc64/cpupara.pas7
-rw-r--r--compiler/powerpc64/cpupi.pas11
4 files changed, 56 insertions, 10 deletions
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;