* parameter passing is now more ABI compliant

* stack frame size optimization
* optimized (64 bit) constant loading
* some code generator code cleanup

git-svn-id: trunk@1539 -
This commit is contained in:
tom_at_work 2005-10-19 23:25:21 +00:00
parent 46c9d03d82
commit 5fcb64f350
4 changed files with 169 additions and 289 deletions

View File

@ -139,6 +139,13 @@ type
{ of asmcondflags and destination addressing mode }
procedure a_jmp(list: taasmoutput; op: tasmop;
c: tasmcondflag; crval: longint; l: tasmlabel);
{ returns the lowest numbered FP register in use, and the number of used FP registers
for the current procedure }
procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
{ returns the lowest numbered GP register in use, and the number of used GP registers
for the current procedure }
procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
end;
const
@ -350,26 +357,34 @@ end;
procedure tcgppc.a_load_const_reg(list: taasmoutput; size: TCGSize; a: aint;
reg: TRegister);
var
scratchreg : TRegister;
procedure load32bitconstant(list : taasmoutput; size : TCGSize; a : longint;
reg : TRegister);
var is_half_signed : boolean;
{ loads a 32 bit constant into the given register, using an optimal instruction sequence.
This is either LIS, LI or LI+ADDIS.
Returns true if during these operations the upper 32 bits were filled with 1 bits (e.g.
sign extension was performed) }
function load32bitconstant(list : taasmoutput; size : TCGSize; a : longint;
reg : TRegister) : boolean;
var
is_half_signed : byte;
begin
(*
// ts: test optimized code using LI/ADDIS
{ if the lower 16 bits are zero, do a single LIS }
if (smallint(a) = 0) and ((a shr 16) <> 0) then begin
list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(hi(a))));
load32bitconstant := longint(a) < 0;
end else begin
is_half_signed := smallint(a) < 0;
list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
if smallint((a shr 16) + ord(is_half_signed)) <> 0 then begin
list.concat(taicpu.op_reg_reg_const(A_ADDIS, reg, reg, smallint((a shr 16) + ord(is_half_signed))));
is_half_signed := ord(smallint(lo(a)) < 0);
list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a and $ffff)));
if smallint(hi(a) + is_half_signed) <> 0 then begin
list.concat(taicpu.op_reg_reg_const(A_ADDIS, reg, reg, smallint(hi(a) + is_half_signed)));
end;
load32bitconstant := (smallint(a) < 0) or (a < 0);
end;
*)
end;
{ R0-safe version of the above (ADDIS doesn't work the same way with R0 as base), without
the return value }
procedure load32bitconstantR0(list : taasmoutput; size : TCGSize; a : longint;
reg : TRegister);
begin
// only 16 bit constant? (-2^15 <= a <= +2^15-1)
if (a >= low(smallint)) and (a <= high(smallint)) then begin
list.concat(taicpu.op_reg_const(A_LI, reg, smallint(a)));
@ -378,56 +393,52 @@ var
if ((a and $FFFF) <> 0) then begin
list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
list.concat(taicpu.op_reg_reg_const(A_ORI, reg, reg, word(a)));
end else begin
list.concat(taicpu.op_reg_const(A_LIS, reg, smallint(a shr 16)));
end;
end;
end;
var
extendssign : boolean;
{$IFDEF EXTDEBUG}
astring : string;
{$ENDIF EXTDEBUG}
begin
astring := 'a_load_const reg ' + inttostr(a) + ' ' + inttostr(tcgsize2size[size]);
{$IFDEF EXTDEBUG}
astring := 'a_load_const reg ' + inttostr(hi(a)) + ' ' + inttostr(lo(a)) + ' ' + inttostr(ord(size)) + ' ' + inttostr(tcgsize2size[size]);
list.concat(tai_comment.create(strpnew(astring)));
{$ENDIF EXTDEBUG}
if not (size in [OS_8, OS_S8, OS_16, OS_S16, OS_32, OS_S32, OS_64, OS_S64]) then
internalerror(2002090902);
// load low 32 bit (as signed number)
load32bitconstant(list, size, lo(a), reg);
// load high 32 bit if needed :( (the second expression is optimization, to be enabled and tested later!)
if (size in [OS_64, OS_S64]) {and (hi(a) <> 0)} then begin
// allocate scratch reg (=R0 because it might be called at places where register
// allocation has already happened - either procedure entry/exit, and stack check
// code generation)
// Note: I hope this restriction can be lifted at some time
//scratchreg := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
// load high 32 bit
load32bitconstant(list, size, hi(a), NR_R0);
// combine both registers
list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, NR_R0, 32, 0));
end;
(*
// for 16/32 bit unsigned constants we need to make sure that the difference from this size to
// 32 bits is cleared (since we optimize loading them as signed 16 bit parts, but 32 bit ops are
// used for them.
// e.g. for 16 bit there's a problem if the (unsigned) constant is of the form
// xx..xx xx..xx 00..00 1x..xx
// same problem as above for 32 bit: unsigned constants of the form
// xx..xx xx..xx 00..00 1x..xx
// cause troubles. Signed are ok.
// for now, just clear the upper 48/32 bits (also because full 32 bit op usage isn't done yet)
if (size in [OS_16, OS_32]) {and (lo(a) < 0)} then begin
a_load_reg_reg(list, size, size, reg, reg);
end; *)
// need to clear MSB for unsigned 64 bit int because we did not load the upper
// 32 bit at all (second expression is optimization: enable and test later!)
// e.g. constants of the form 00..00 00..00 1x..xx xx..xx
if (size in [OS_64]) and (hi(a) = 0) then begin
list.concat(taicpu.op_reg_reg_const_const(A_RLDICL, reg, reg, 0, 32));
end;
if (lo(a) = 0) and (hi(a) <> 0) then begin
{ load only upper 32 bits, and shift }
load32bitconstant(list, size, hi(a), reg);
list.concat(taicpu.op_reg_reg_const(A_SLDI, reg, reg, 32));
end else begin
{ load lower 32 bits }
extendssign := load32bitconstant(list, size, lo(a), reg);
if (extendssign) and (hi(a) = 0) then
{ if upper 32 bits are zero, but loading the lower 32 bit resulted in automatic
sign extension, clear those bits }
a_load_reg_reg(list, OS_32, OS_64, reg, reg)
else if (not
((extendssign and (longint(hi(a)) = -1)) or
((not extendssign) and (hi(a)=0)))
) then begin
{ only load the upper 32 bits, if the automatic sign extension is not okay,
that is, _not_ if
- loading the lower 32 bits resulted in -1 in the upper 32 bits, and the upper
32 bits should contain -1
- loading the lower 32 bits resulted in 0 in the upper 32 bits, and the upper
32 bits should contain 0 }
load32bitconstantR0(list, size, hi(a), NR_R0);
{ combine both registers }
list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, NR_R0, 32, 0));
end;
end;
end;
procedure tcgppc.a_load_reg_ref(list: taasmoutput; fromsize, tosize: TCGSize;
@ -794,6 +805,7 @@ var
signed: boolean;
begin
{ todo: use 32 bit compares? }
signed := cmp_op in [OC_GT, OC_LT, OC_GTE, OC_LTE];
{ in the following case, we generate more efficient code when }
{ signed is true }
@ -803,16 +815,14 @@ begin
if signed then
if (a >= low(smallint)) and (a <= high(smallint)) then
list.concat(taicpu.op_reg_reg_const(A_CMPDI, NR_CR0, reg, a))
else
begin
else begin
scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
a_load_const_reg(list, OS_64, a, scratch_register);
list.concat(taicpu.op_reg_reg_reg(A_CMPD, NR_CR0, reg, scratch_register));
end
else if (aword(a) <= $FFFF) then
list.concat(taicpu.op_reg_reg_const(A_CMPLDI, NR_CR0, reg, aword(a)))
else
begin
else begin
scratch_register := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
a_load_const_reg(list, OS_64, a, scratch_register);
list.concat(taicpu.op_reg_reg_reg(A_CMPLD, NR_CR0, reg,
@ -930,6 +940,40 @@ begin
{ this work is done in g_proc_exit }
end;
procedure tcgppc.calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
var
reg : TSuperRegister;
begin
fprcount := 0;
firstfpr := RS_F31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_F14 to RS_F31 do begin
if reg in rg[R_FPUREGISTER].used_in_proc then begin
fprcount := ord(RS_F31)-ord(reg)+1;
firstfpr := reg;
break;
end;
end;
end;
end;
procedure tcgppc.calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
var
reg : TSuperRegister;
begin
gprcount := 0;
firstgpr := RS_R31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_R14 to RS_R31 do begin
if reg in rg[R_INTREGISTER].used_in_proc then begin
gprcount := ord(RS_R31)-ord(reg)+1;
firstgpr := reg;
break;
end;
end;
end;
end;
procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
nostackframe: boolean);
{ generated the entry code of a procedure/function. Note: localsize is the }
@ -939,40 +983,6 @@ procedure tcgppc.g_proc_entry(list: taasmoutput; localsize: longint;
{ This procedure may be called before, as well as after g_return_from_proc }
{ is called. NOTE registers are not to be allocated through the register }
{ allocator here, because the register colouring has already occured !! }
procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
var
reg : TSuperRegister;
begin
fprcount := 0;
firstfpr := RS_F31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_F14 to RS_F31 do begin
if reg in rg[R_FPUREGISTER].used_in_proc then begin
fprcount := ord(RS_F31)-ord(reg)+1;
firstfpr := reg;
break;
end;
end;
end;
end;
procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
var
reg : TSuperRegister;
begin
gprcount := 0;
firstgpr := RS_R31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_R14 to RS_R31 do begin
if reg in rg[R_INTREGISTER].used_in_proc then begin
gprcount := ord(RS_R31)-ord(reg)+1;
firstgpr := reg;
break;
end;
end;
end;
end;
var
firstregfpu, firstreggpr: TSuperRegister;
href: treference;
@ -1009,7 +1019,6 @@ begin
a_reg_alloc(list, NR_R12);
list.concat(taicpu.op_reg_reg(A_MR, NR_R12, NR_STACK_POINTER_REG));
end;
// save registers, FPU first, then GPR
reference_reset_base(href, NR_STACK_POINTER_REG, -8);
if (fprcount > 0) then begin
@ -1072,45 +1081,11 @@ end;
procedure tcgppc.g_proc_exit(list: taasmoutput; parasize: longint; nostackframe:
boolean);
procedure calcFirstUsedFPR(out firstfpr : TSuperRegister; out fprcount : aint);
var
reg : TSuperRegister;
begin
fprcount := 0;
firstfpr := RS_F31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_F14 to RS_F31 do begin
if reg in rg[R_FPUREGISTER].used_in_proc then begin
fprcount := ord(RS_F31)-ord(reg)+1;
firstfpr := reg;
break;
end;
end;
end;
end;
procedure calcFirstUsedGPR(out firstgpr : TSuperRegister; out gprcount : aint);
var
reg : TSuperRegister;
begin
gprcount := 0;
firstgpr := RS_R31;
if not (po_assembler in current_procinfo.procdef.procoptions) then begin
for reg := RS_R14 to RS_R31 do begin
if reg in rg[R_INTREGISTER].used_in_proc then begin
gprcount := ord(RS_R31)-ord(reg)+1;
firstgpr := reg;
break;
end;
end;
end;
end;
{ This procedure may be called before, as well as after g_stackframe_entry }
{ is called. NOTE registers are not to be allocated through the register }
{ allocator here, because the register colouring has already occured !! }
var
regcount, firstregfpu, firstreggpr: TSuperRegister;
href: treference;
@ -1443,7 +1418,7 @@ procedure tcgppc.g_intf_wrapper(list: TAAsmoutput; procdef: tprocdef; const
procdef._class.vmtmethodoffset(procdef.extnumber));
if not ((aint(href.offset) >= low(smallint)) and
(aint(href.offset) <= high(smallint))) then begin
{$warning ts:adapt me}
{$warning ts:adapt me for offsets > 16 bit }
list.concat(taicpu.op_reg_reg_const(A_ADDIS, NR_R11, NR_R11,
smallint((href.offset shr 16) + ord(smallint(href.offset and $FFFF) <
0))));

View File

@ -19,7 +19,7 @@
****************************************************************************
}
{ This Unit contains the base types for the PowerPC
{ This Unit contains the base types for the PowerPC64
}
unit cpubase;

View File

@ -87,18 +87,14 @@ begin
cgpara.intsize := tcgsize2size[OS_INT];
cgpara.alignment := get_para_align(calloption);
paraloc := cgpara.add_location;
with paraloc^ do
begin
with paraloc^ do begin
size := OS_INT;
if (nr <= 8) then
begin
if (nr <= 8) then begin
if nr = 0 then
internalerror(200309271);
loc := LOC_REGISTER;
register := newreg(R_INTREGISTER, RS_R2 + nr, R_SUBWHOLE);
end
else
begin
end else begin
loc := LOC_REFERENCE;
paraloc^.reference.index := NR_STACK_POINTER_REG;
if (target_info.abi <> abi_powerpc_aix) then
@ -129,10 +125,7 @@ begin
classrefdef:
result := LOC_REGISTER;
recorddef:
if (target_info.abi <> abi_powerpc_aix) then
result := LOC_REFERENCE
else
result := LOC_REGISTER;
result := LOC_REGISTER;
objectdef:
if is_object(p) then
result := LOC_REFERENCE
@ -183,7 +176,6 @@ begin
result := true;
recorddef:
result :=
(target_info.abi <> abi_powerpc_aix) or
((varspez = vs_const) and
((calloption = pocall_mwpascal) or
(not (calloption in [pocall_cdecl, pocall_cppdecl]) and
@ -210,10 +202,11 @@ end;
procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg:
tsuperregister; var cur_stack_offset: aword);
begin
{ register parameter save area begins at 48(r2) }
cur_stack_offset := 48;
curintreg := RS_R3;
curfloatreg := RS_F1;
curmmreg := RS_M1;
curmmreg := RS_M2;
end;
procedure tppcparamanager.create_funcretloc_info(p: tabstractprocdef; side:
@ -230,36 +223,28 @@ begin
location_reset(p.funcretloc[side], LOC_INVALID, OS_NO);
p.funcretloc[side].size := retcgsize;
{ void has no location }
if is_void(p.rettype.def) then
begin
if is_void(p.rettype.def) then begin
p.funcretloc[side].loc := LOC_VOID;
exit;
end;
{ Return in FPU register? }
if p.rettype.def.deftype = floatdef then
begin
if p.rettype.def.deftype = floatdef then begin
p.funcretloc[side].loc := LOC_FPUREGISTER;
p.funcretloc[side].register := NR_FPU_RESULT_REG;
p.funcretloc[side].size := retcgsize;
end
else
{ Return in register? } if not ret_in_param(p.rettype.def, p.proccalloption)
then
begin
begin
p.funcretloc[side].loc := LOC_REGISTER;
p.funcretloc[side].size := retcgsize;
if side = callerside then
p.funcretloc[side].register := newreg(R_INTREGISTER,
RS_FUNCTION_RESULT_REG, cgsize2subreg(retcgsize))
else
p.funcretloc[side].register := newreg(R_INTREGISTER,
RS_FUNCTION_RETURN_REG, cgsize2subreg(retcgsize));
end;
end
else
begin
end else
{ Return in register? }
if not ret_in_param(p.rettype.def, p.proccalloption) then begin
p.funcretloc[side].loc := LOC_REGISTER;
p.funcretloc[side].size := retcgsize;
if side = callerside then
p.funcretloc[side].register := newreg(R_INTREGISTER,
RS_FUNCTION_RESULT_REG, cgsize2subreg(retcgsize))
else
p.funcretloc[side].register := newreg(R_INTREGISTER,
RS_FUNCTION_RETURN_REG, cgsize2subreg(retcgsize));
end else begin
p.funcretloc[side].loc := LOC_REFERENCE;
p.funcretloc[side].size := retcgsize;
end;
@ -282,8 +267,8 @@ end;
function tppcparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
tcallercallee; paras: tparalist;
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
aword): longint;
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
aword): longint;
var
stack_offset: longint;
paralen: aint;
@ -309,13 +294,11 @@ begin
maxfpureg := RS_F13;
for i := 0 to paras.count - 1 do
begin
for i := 0 to paras.count - 1 do begin
hp := tparavarsym(paras[i]);
paradef := hp.vartype.def;
{ Syscall for Morphos can have already a paraloc set }
if (vo_has_explicit_paraloc in hp.varoptions) then
begin
if (vo_has_explicit_paraloc in hp.varoptions) then begin
if not (vo_is_syscall_lib in hp.varoptions) then
internalerror(200412153);
continue;
@ -323,8 +306,7 @@ begin
hp.paraloc[side].reset;
{ currently only support C-style array of const }
if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
is_array_of_const(paradef) then
begin
is_array_of_const(paradef) then begin
paraloc := hp.paraloc[side].add_location;
{ hack: the paraloc must be valid, but is not actually used }
paraloc^.loc := LOC_REGISTER;
@ -336,50 +318,37 @@ begin
if (hp.varspez in [vs_var, vs_out]) or
push_addr_param(hp.varspez, paradef, p.proccalloption) or
is_open_array(paradef) or
is_array_of_const(paradef) then
begin
is_array_of_const(paradef) then begin
paradef := voidpointertype.def;
loc := LOC_REGISTER;
paracgsize := OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
end
else
begin
end else begin
if not is_special_array(paradef) then
paralen := paradef.size
else
paralen := tcgsize2size[def_cgsize(paradef)];
if (target_info.abi = abi_powerpc_aix) and
(paradef.deftype = recorddef) and
(hp.varspez in [vs_value, vs_const]) then
begin
if (paradef.deftype = recorddef) and
(hp.varspez in [vs_value, vs_const]) then begin
{ if a record has only one field and that field is }
{ non-composite (not array or record), it must be }
{ passed according to the rules of that type. }
if (trecorddef(hp.vartype.def).symtable.symindex.count = 1) and
(not trecorddef(hp.vartype.def).isunion) and
((tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) or
((target_info.system = system_powerpc_darwin) and
(tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype in [orddef, enumdef]))) then
begin
(tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) then begin
paradef :=
tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def;
loc := getparaloc(paradef);
paracgsize := def_cgsize(paradef);
end
else
begin
end else begin
loc := LOC_REGISTER;
paracgsize := int_cgsize(paralen);
end;
end
else
begin
end else begin
loc := getparaloc(paradef);
paracgsize := def_cgsize(paradef);
{ for things like formaldef }
if (paracgsize = OS_NO) then
begin
if (paracgsize = OS_NO) then begin
paracgsize := OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
end;
@ -389,20 +358,16 @@ begin
hp.paraloc[side].size := paracgsize;
hp.paraloc[side].intsize := paralen;
if (paralen = 0) then
if (paradef.deftype = recorddef) then
begin
if (paradef.deftype = recorddef) then begin
paraloc := hp.paraloc[side].add_location;
paraloc^.loc := LOC_VOID;
end
else
end else
internalerror(2005011310);
{ can become < 0 for e.g. 3-byte records }
while (paralen > 0) do
begin
while (paralen > 0) do begin
paraloc := hp.paraloc[side].add_location;
if (loc = LOC_REGISTER) and
(nextintreg <= RS_R10) then
begin
(nextintreg <= RS_R10) then begin
paraloc^.loc := loc;
{ make sure we don't lose whether or not the type is signed }
if (paradef.deftype <> orddef) then
@ -414,29 +379,36 @@ begin
paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
inc(nextintreg);
dec(paralen, tcgsize2size[paraloc^.size]);
if target_info.abi = abi_powerpc_aix then
inc(stack_offset, tcgsize2size[paraloc^.size]);
end
else if (loc = LOC_FPUREGISTER) and
(nextfloatreg <= maxfpureg) then
begin
inc(stack_offset, tcgsize2size[paraloc^.size]);
end else if (loc = LOC_FPUREGISTER) and
(nextfloatreg <= maxfpureg) then begin
paraloc^.loc := loc;
paraloc^.size := paracgsize;
paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
{ the PPC64 ABI says that the GPR index is increased for every parameter, no matter
which type it is stored in }
inc(nextintreg);
inc(nextfloatreg);
dec(paralen, tcgsize2size[paraloc^.size]);
{ if nextfpureg > maxfpureg, all intregs are already used, since there }
{ are less of those available for parameter passing in the AIX abi }
end
else { LOC_REFERENCE }
begin
inc(stack_offset, tcgsize2size[paraloc^.size]);
end else if (loc = LOC_MMREGISTER) then begin
{ Altivec not supported }
internalerror(200510192);
end else begin
{ either LOC_REFERENCE, or one of the above which must be passed on the
stack because of insufficient registers }
paraloc^.loc := LOC_REFERENCE;
paraloc^.size := int_cgsize(paralen);
if (side = callerside) then
paraloc^.reference.index := NR_STACK_POINTER_REG
else
{ during procedure entry, R12 contains the old stack pointer }
paraloc^.reference.index := NR_R12;
paraloc^.reference.offset := stack_offset;
{ TODO: change this to the next power of two (natural alignment) }
inc(stack_offset, align(paralen, 8));
paralen := 0;
end;
@ -470,9 +442,7 @@ begin
result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
curfloatreg, curmmreg, cur_stack_offset);
{ varargs routines have to reserve at least 64 bytes for the AIX abi }
{ ts: dunno??? }
if (target_info.abi = abi_powerpc_aix) and
(result < 64) then
if (result < 64) then
result := 64;
end
else
@ -497,76 +467,9 @@ begin
end;
function tppcparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
var
paraloc: pcgparalocation;
paracgsize: tcgsize;
begin
result := false;
case target_info.system of
system_powerpc_morphos:
begin
paracgsize := def_cgsize(p.vartype.def);
p.paraloc[callerside].alignment := 8;
p.paraloc[callerside].size := paracgsize;
p.paraloc[callerside].intsize := tcgsize2size[paracgsize];
paraloc := p.paraloc[callerside].add_location;
paraloc^.loc := LOC_REFERENCE;
paraloc^.size := paracgsize;
paraloc^.reference.index := newreg(R_INTREGISTER, RS_R2, R_SUBWHOLE);
{ pattern is always uppercase'd }
if s = 'D0' then
paraloc^.reference.offset := 0
else if s = 'D1' then
paraloc^.reference.offset := 8
else if s = 'D2' then
paraloc^.reference.offset := 16
else if s = 'D3' then
paraloc^.reference.offset := 24
else if s = 'D4' then
paraloc^.reference.offset := 32
else if s = 'D5' then
paraloc^.reference.offset := 40
else if s = 'D6' then
paraloc^.reference.offset := 48
else if s = 'D7' then
paraloc^.reference.offset := 56
else if s = 'A0' then
paraloc^.reference.offset := 64
else if s = 'A1' then
paraloc^.reference.offset := 72
else if s = 'A2' then
paraloc^.reference.offset := 80
else if s = 'A3' then
paraloc^.reference.offset := 88
else if s = 'A4' then
paraloc^.reference.offset := 96
else if s = 'A5' then
paraloc^.reference.offset := 104
{ 'A6' (offset 56) is used by mossyscall as libbase, so API
never passes parameters in it,
Indeed, but this allows to declare libbase either explicitly
or let the compiler insert it }
else if s = 'A6' then
paraloc^.reference.offset := 112
{ 'A7' is the stack pointer on 68k, can't be overwritten
by API calls, so it has no offset }
{ 'R12' is special, used internally to support r12base sysv
calling convention }
else if s = 'R12' then
begin
paraloc^.loc := LOC_REGISTER;
paraloc^.size := OS_ADDR;
paraloc^.register := NR_R12;
end
else
exit;
{ copy to callee side }
p.paraloc[calleeside].add_location^ := paraloc^;
end;
else
internalerror(200404182);
end;
{ not supported/required for PowerPC64-linux target }
internalerror(200404182);
result := true;
end;

View File

@ -65,11 +65,13 @@ var
locals: longint;
begin
if not (po_assembler in procdef.procoptions) then begin
{ always allocate space for 8 * 8 bytes for registers R3-R10 and stack header if
there's a stack frame }
if (maxpushedparasize < 64) then begin
maxpushedparasize := 64;
end;
{ the ABI specification says that it is required to always allocate space for 8 * 8 bytes
for registers R3-R10 and stack header if there's a stack frame, but GCC doesn't do that,
so we don't that too. Uncomment the next three lines if this is required }
// if (maxpushedparasize < 64) then begin
// maxpushedparasize := 64;
// end;
{ align the stack properly }
ofs := align(maxpushedparasize + LinkageAreaSizeELF, ELF_STACK_ALIGN);
tg.setfirsttemp(ofs);
end else begin