fpc/compiler/powerpc64/cpupara.pas
2021-11-17 22:19:57 +01:00

837 lines
28 KiB
ObjectPascal

{
Copyright (c) 2002 by Florian Klaempfl
PowerPC64 specific calling conventions
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit cpupara;
{$I fpcdefs.inc}
interface
uses
globtype,
aasmtai,aasmdata,
cpubase,
symconst, symtype, symdef, symsym,
paramgr, parabase, cgbase, cgutils;
type
tcpuparamanager = class(tparamanager)
function get_volatile_registers_int(calloption: tproccalloption):
tcpuregisterset; override;
function get_volatile_registers_fpu(calloption: tproccalloption):
tcpuregisterset; override;
function get_saved_registers_int(calloption: tproccalloption):
tcpuregisterarray; override;
function push_addr_param(varspez: tvarspez; def: tdef; calloption:
tproccalloption): boolean; override;
function ret_in_param(def: tdef; pd: tabstractprocdef): boolean; override;
procedure getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara); override;
function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
function create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist): longint; override;
function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
private
procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister;
var cur_stack_offset: aword);
function create_paraloc_info_intern(p: tabstractprocdef; side:
tcallercallee; paras: tparalist;
var curintreg, curfloatreg, curmmreg: tsuperregister; var
cur_stack_offset: aword; isVararg : boolean): longint;
function parseparaloc(p: tparavarsym; const s: string): boolean; override;
procedure create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
end;
implementation
uses
verbose, systems,
defutil,symtable,symcpu,
procinfo, cpupi;
function tcpuparamanager.get_volatile_registers_int(calloption:
tproccalloption): tcpuregisterset;
begin
result := [RS_R0,RS_R3..RS_R12];
if (target_info.system = system_powerpc64_darwin) then
include(result,RS_R2);
end;
function tcpuparamanager.get_volatile_registers_fpu(calloption:
tproccalloption): tcpuregisterset;
begin
result := [RS_F0..RS_F13];
end;
function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption):
tcpuregisterarray;
const
saved_regs: tcpuregisterarray = (
RS_R14, RS_R15, RS_R16, RS_R17, RS_R18, RS_R19,
RS_R20, RS_R21, RS_R22, RS_R23, RS_R24, RS_R25,
RS_R26, RS_R27, RS_R28, RS_R29, RS_R30, RS_R31
);
begin
result:=saved_regs;
end;
procedure tcpuparamanager.getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr: longint; var cgpara: tcgpara);
var
paraloc: pcgparalocation;
psym: tparavarsym;
pdef: tdef;
begin
psym:=tparavarsym(pd.paras[nr-1]);
pdef:=psym.vardef;
if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
pdef:=cpointerdef.getreusable_no_free(pdef);
cgpara.reset;
cgpara.size := def_cgsize(pdef);
cgpara.intsize := tcgsize2size[cgpara.size];
cgpara.alignment := get_para_align(pd.proccalloption);
cgpara.def:=pdef;
paraloc := cgpara.add_location;
with paraloc^ do begin
size := def_cgsize(pdef);
def := pdef;
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
loc := LOC_REFERENCE;
paraloc^.reference.index := NR_STACK_POINTER_REG;
reference.offset := sizeof(aint) * (nr - 8);
end;
end;
end;
function getparaloc(p: tdef): tcgloc;
begin
{ Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
if push_addr_param for the def is true
}
case p.typ of
orddef:
result := LOC_REGISTER;
floatdef:
result := LOC_FPUREGISTER;
enumdef:
result := LOC_REGISTER;
pointerdef:
result := LOC_REGISTER;
formaldef:
result := LOC_REGISTER;
classrefdef:
result := LOC_REGISTER;
procvardef,
recorddef:
result := LOC_REGISTER;
objectdef:
if is_object(p) then
result := LOC_REFERENCE
else
result := LOC_REGISTER;
stringdef:
if is_shortstring(p) or is_longstring(p) then
result := LOC_REFERENCE
else
result := LOC_REGISTER;
filedef:
result := LOC_REGISTER;
arraydef:
if is_dynamic_array(p) then
getparaloc:=LOC_REGISTER
else
result := LOC_REFERENCE;
setdef:
if is_smallset(p) then
result := LOC_REGISTER
else
result := LOC_REFERENCE;
variantdef:
result := LOC_REFERENCE;
{ avoid problems with errornous definitions }
errordef:
result := LOC_REGISTER;
else
internalerror(2002071001);
end;
end;
function tcpuparamanager.push_addr_param(varspez: tvarspez; def: tdef;
calloption: tproccalloption): boolean;
begin
result := false;
{ var,out,constref always require address }
if varspez in [vs_var, vs_out, vs_constref] then
begin
result := true;
exit;
end;
case def.typ of
variantdef,
formaldef:
result := true;
procvardef,
recorddef:
result :=
(varspez = vs_const) and
(
(
(not (calloption in cdecl_pocalls) and
(def.size > 8))
) or
(calloption = pocall_mwpascal)
);
arraydef:
result := (tarraydef(def).highrange >= tarraydef(def).lowrange) or
is_open_array(def) or
is_array_of_const(def) or
is_array_constructor(def);
objectdef:
result := is_object(def);
setdef:
result := not is_smallset(def);
stringdef:
result := tstringdef(def).stringtype in [st_shortstring, st_longstring];
else
;
end;
end;
function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
var
tmpdef: tdef;
begin
if handle_common_ret_in_param(def,pd,result) then
exit;
{ general rule: passed in registers -> returned in registers }
result:=push_addr_param(vs_value,def,pd.proccalloption);
case target_info.abi of
{ elfv2: non-homogeneous aggregate larger than 2 doublewords or a
homogeneous aggregate with more than eight registers are returned by
reference }
abi_powerpc_elfv2:
begin
if not result then
begin
if (def.typ=recorddef) then
begin
if tcpurecorddef(def).has_single_type_elfv2(tmpdef) then
begin
if def.size>8*tmpdef.size then
result:=true
end
else if def.size>2*sizeof(aint) then
result:=true;
end
else if (def.typ=arraydef) then
begin
if tcpuarraydef(def).has_single_type_elfv2(tmpdef) then
begin
if def.size>8*tmpdef.size then
result:=true
end
else if def.size>2*sizeof(aint) then
result:=true;
end;
end;
end;
{ sysv/aix: any non-scalar/non-floating point is returned by reference }
abi_powerpc_sysv,
abi_powerpc_aix:
begin
case def.typ of
procvardef:
result:=def.size>8;
recorddef:
result:=true;
else
;
end;
end;
{ Darwin: if completely passed in registers -> returned by registers;
i.e., if part is passed via memory because there are not enough
registers, return via memory }
abi_powerpc_darwin:
begin
case def.typ of
recorddef:
begin
{ todo: fix once the Darwin/ppc64 abi is fully implemented, as it
requires individual fields to be passed in individual registers,
so a record with 9 bytes may need to be passed via memory }
if def.size>8*sizeof(aint) then
result:=true;
end;
else
;
end;
end;
else
internalerror(2019051030);
end;
end;
procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg:
tsuperregister; var cur_stack_offset: aword);
begin
case target_info.abi of
abi_powerpc_elfv2:
cur_stack_offset := 32;
else
cur_stack_offset := 48;
end;
curintreg := RS_R3;
curfloatreg := RS_F1;
curmmreg := RS_M2;
end;
function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side:
tcallercallee; forcetempdef: tdef): tcgpara;
var
paraloc: pcgparalocation;
retcgsize: tcgsize;
nextfloatreg, nextintreg, nextmmreg: tsuperregister;
stack_offset: aword;
begin
if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
exit;
{ on Darwin and with ELFv2, results are returned the same way as they are
passed }
if target_info.abi in [abi_powerpc_elfv2,abi_powerpc_darwin] then
begin
init_values(nextintreg,nextfloatreg,nextmmreg,stack_offset);
create_paraloc_for_def(result,vs_value,result.def,nextfloatreg,nextintreg,stack_offset,false,false,side,p);
end
else
begin
{ for AIX and ELFv1, the situation is simpler: always just one register }
paraloc:=result.add_location;
{ Return in FPU register? }
if result.def.typ=floatdef then
begin
paraloc^.loc:=LOC_FPUREGISTER;
paraloc^.register:=NR_FPU_RESULT_REG;
paraloc^.size:=retcgsize;
paraloc^.def:=result.def;
end
else
{ Return in register }
begin
paraloc^.loc:=LOC_REGISTER;
if side=callerside then
paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
else
paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
paraloc^.size:=retcgsize;
paraloc^.def:=result.def;
end;
end;
end;
function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side:
tcallercallee): longint;
var
cur_stack_offset: aword;
curintreg, curfloatreg, curmmreg : tsuperregister;
begin
init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
result := create_paraloc_info_intern(p, side, p.paras, curintreg, curfloatreg,
curmmreg, cur_stack_offset, false);
create_funcretloc_info(p, side);
end;
function tcpuparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
tcallercallee; paras: tparalist;
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
aword; isVararg : boolean): longint;
var
nextintreg, nextfloatreg, nextmmreg : tsuperregister;
i: integer;
hp: tparavarsym;
paraloc: pcgparalocation;
delphi_nestedfp: boolean;
begin
{$IFDEF extdebug}
if po_explicitparaloc in p.procoptions then
internalerror(200411141);
{$ENDIF extdebug}
result := 0;
nextintreg := curintreg;
nextfloatreg := curfloatreg;
nextmmreg := curmmreg;
for i := 0 to paras.count - 1 do begin
hp := tparavarsym(paras[i]);
{ Syscall for Morphos can have already a paraloc set; not supported on ppc64 }
if (vo_has_explicit_paraloc in hp.varoptions) then begin
internalerror(200412153);
end;
{ currently only support C-style array of const }
if (p.proccalloption in cstylearrayofconst) and
is_array_of_const(hp.vardef) then begin
paraloc := hp.paraloc[side].add_location;
{ hack: the paraloc must be valid, but is not actually used }
paraloc^.loc := LOC_REGISTER;
paraloc^.register := NR_R0;
paraloc^.size := OS_ADDR;
paraloc^.def := voidpointertype;
break;
end;
delphi_nestedfp:=(vo_is_parentfp in hp.varoptions) and (po_delphi_nested_cc in p.procoptions);
create_paraloc_for_def(hp.paraloc[side], hp.varspez, hp.vardef,
nextfloatreg, nextintreg, cur_stack_offset, isVararg, delphi_nestedfp, side, p);
end;
curintreg := nextintreg;
curfloatreg := nextfloatreg;
curmmreg := nextmmreg;
result := cur_stack_offset;
end;
procedure tcpuparamanager.create_paraloc_for_def(var para: TCGPara; varspez: tvarspez; paradef: tdef; var nextfloatreg, nextintreg: tsuperregister; var stack_offset: aword; const isVararg, forceintmem: boolean; const side: tcallercallee; const p: tabstractprocdef);
var
paracgsize: tcgsize;
loc: tcgloc;
paraloc: pcgparalocation;
{ def to use for all paralocs if <> nil }
alllocdef,
{ def to use for the current paraloc }
locdef,
tmpdef: tdef;
paralen: aint;
parashift: byte;
tailpadding,
firstparaloc,
paraaligned: boolean;
begin
alllocdef:=nil;
locdef:=nil;
parashift := 0;
para.reset;
{ should the tail be shifted into the most significant bits? }
tailpadding:=false;
{ have we ensured that the next parameter location will be aligned to the
next 8 byte boundary? }
paraaligned:=false;
if push_addr_param(varspez, paradef, p.proccalloption) then begin
paradef := cpointerdef.getreusable_no_free(paradef);
loc := LOC_REGISTER;
paracgsize := OS_ADDR;
paralen := tcgsize2size[OS_ADDR];
end else begin
if not is_special_array(paradef) then
paralen := paradef.size
else
paralen := tcgsize2size[def_cgsize(paradef)];
{ default rules:
* integer parameters sign/zero-extended to 64 bit
* floating point register used -> skip equivalent GP register
* floating point parameters passed as is (32/64 bit)
* floating point parameters to variable arguments -> in int registers
* aggregates passed in consecutive integer registers
* all *aggregate* data in integer registers exactly mirrors the data
in memory -> on big endian it's left aligned (passed in most
significant part of the 64 bit word if it's < 64 bit), on little
endian it's right aligned (least significant part of the 64 bit
word)
special rules:
implemented
|
| * AIX/ELFv1/SysV ppc64 ABI (big endian only):
x a) single precision floats are stored in the second word of a 64 bit
location when passed on the stack
x b) aggregate with 1 floating point element passed like a floating
point parameter of the same size
x c) aggregates smaller than 64 bit are aligned in least significant bits
of a single 64bit location (incl. register) (AIX exception: it puts
them in the most significant bits)
* ELFv2 ppc64 ABI:
x a) so-called "homogeneous" aggregates, i.e. struct, arrays, or unions
that (recursively) contain only elements of the same floating-
point or vector type, are passed as if those elements were passed as
separate arguments. This is done for up to 8 such elements.
x b) other than a), it's the same as the AIX ppc64 ABI
* Darwin ppc64 ABI:
- as in the general case, aggregates in registers mirror their place in
memory, so if e.g. a struct starts with a 32 bit integer, it's
placed in the upper 32 bits of a the corresponding register. A plain
32 bit integer para is however passed in the lower 32 bits, since it
is promoted to a 64 bit int first (see below)
x a) aggregates with sizes 1, 2 and 4 bytes are padded with 0s on the left
(-> aligned in least significant bits of 64 bit word on big endian) to
a multiple of *4 bytes* (when passed by memory, don't occupy 8 bytes)
x b) other aggregates are padded with 0s on the right (-> aligned in most
signifcant bits of 64 bit word of integer register) to a multiple of
*4 bytes*
x c) all floating pointer parameters (not in aggregates) are promoted to
double (doesn't seem to be correct: 8 bytes are reserved in the
stack frame, but the compiler still stores a single in it (in the
lower 4 bytes -- like with SysV a) )
x d) all integer parameters (not in aggregates) are promoted to 64 bit
(x) e) aggregates (incl. arrays) of exactly 16 bytes passed in two integer
registers
f) floats in *structures without unions* are processed per rule c)
(similar for vector fields)
g) other fields in *structures without unions* are processed
recursively according to e) / f) if they are aggragates, and h)
otherwise (i.e, without promotion!)
(x) h) everything else (structures with unions and size<>16, arrays with
size<>16, ...) is passed "normally" in integer registers
}
{ ELFv2 a) }
if (target_info.abi=abi_powerpc_elfv2) and
(((paradef.typ=recorddef) and
tcpurecorddef(paradef).has_single_type_elfv2(tmpdef)) or
((paradef.typ=arraydef) and
tcpuarraydef(paradef).has_single_type_elfv2(tmpdef))) and
(tmpdef.typ=floatdef { or vectordef }) and
(paradef.size<=(8*tmpdef.size)) then
begin
alllocdef:=tmpdef;
loc:=getparaloc(alllocdef);
paracgsize:=def_cgsize(paradef);
end
{ AIX/ELFv1 b) }
else if (target_info.abi in [abi_powerpc_aix,abi_powerpc_sysv]) and
(paradef.typ=recorddef) and
tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(tmpdef) and
(tmpdef.typ=floatdef) then
begin
paradef:=tmpdef;
loc:=getparaloc(paradef);
paracgsize:=def_cgsize(paradef)
end
else if (((paradef.typ=arraydef) and not
is_special_array(paradef)) or
(paradef.typ=recorddef)) then
begin
{ should handle Darwin f/g/h) now, but can't model that yet }
{ general rule: aggregate data is aligned in the most significant bits
except for ELFv1 c) and Darwin a) }
if (target_info.endian=endian_big) and
((target_info.abi in [abi_powerpc_aix,abi_powerpc_elfv2]) or
((target_info.abi=abi_powerpc_sysv) and
(paralen>8)) or
((target_info.abi=abi_powerpc_darwin) and
not(paralen in [1,2,4]))) then
tailpadding:=true
{ if we don't add tailpadding on the caller side, the callee will have
to shift the value in the register before it can store it to memory }
else if (target_info.endian=endian_big) and
(paralen in [3,5,6,7]) then
parashift:=(8-paralen)*8;
{ general fallback rule: pass aggregate types in integer registers
without special adjustments (incl. Darwin h) }
loc:=LOC_REGISTER;
paracgsize:=int_cgsize(paralen);
end
else
begin
loc:=getparaloc(paradef);
paracgsize:=def_cgsize(paradef);
{ for things like formaldef }
if (paracgsize=OS_NO) then
begin
paracgsize:=OS_ADDR;
paralen:=tcgsize2size[OS_ADDR];
end;
end
end;
{ patch FPU values into integer registers if we are processing varargs }
if (isVararg) and (paradef.typ = floatdef) then begin
loc := LOC_REGISTER;
if paracgsize = OS_F64 then
paracgsize := OS_64
else
paracgsize := OS_32;
end;
{ AIX/SysV a), Darwin c) -> skip 4 bytes in the stack frame }
if (target_info.endian=endian_big) and
(paradef.typ=floatdef) and
(tfloatdef(paradef).floattype=s32real) and
(nextfloatreg>RS_F13) then
begin
inc(stack_offset,4);
paraaligned:=true;
end;
{ Darwin d) }
if (target_info.abi=abi_powerpc_darwin) and
(paradef.typ in [orddef,enumdef]) and
(paralen<8) and
{ we don't have to sign/zero extend the lower 8/16/32 bit on the callee
side since it's done on the caller side; however, if the value is
passed via memory, we do have to modify the stack offset since this
is big endian and otherwise we'll load/store the wrong bytes) }
((side=callerside) or
forceintmem or
(nextintreg>RS_R10)) then
begin
if side=callerside then
begin
paralen:=8;
paradef:=s64inttype;
paracgsize:=OS_S64;
end
else
begin
inc(stack_offset,8-paralen);
paraaligned:=true;
end;
end;
para.alignment := std_param_align;
para.size := paracgsize;
para.intsize := paralen;
para.def := paradef;
if (paralen = 0) then
if (paradef.typ = recorddef) then begin
paraloc := para.add_location;
paraloc^.loc := LOC_VOID;
end else
internalerror(2005011310);
if not assigned(alllocdef) then
locdef:=paradef
else
begin
locdef:=alllocdef;
paracgsize:=def_cgsize(locdef);
end;
firstparaloc:=true;
{ can become < 0 for e.g. 3-byte records }
while (paralen > 0) do begin
paraloc := para.add_location;
{ ELF64v2 a: overflow homogeneous float storage into integer registers
if possible (only possible in case of single precision floats, because
there are more fprs than gprs for parameter passing) }
if assigned(alllocdef) and
(loc=LOC_FPUREGISTER) and
(((nextfloatreg=RS_F13) and
(tcgsize2size[paracgsize]=4) and
(paralen>4)) or
(nextfloatreg>RS_F13)) then
begin
loc:=LOC_REGISTER;
paracgsize:=OS_64;
locdef:=u64inttype;
end;
{ In case of po_delphi_nested_cc, the parent frame pointer
is always passed on the stack. }
if (loc = LOC_REGISTER) and
(nextintreg <= RS_R10) and
not forceintmem then begin
paraloc^.loc := loc;
paraloc^.shiftval := parashift;
{ make sure we don't lose whether or not the type is signed }
if (paracgsize <> OS_NO) and
(paradef.typ <> orddef) and
not assigned(alllocdef) then
begin
paracgsize := int_cgsize(paralen);
locdef:=get_paraloc_def(paradef, paralen, firstparaloc);
end;
{ Partial aggregate data may have to be left-aligned. If so, add tail
padding }
if tailpadding and
(paralen < sizeof(aint)) then
begin
paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
paraloc^.size := OS_INT;
paraloc^.def := u64inttype;
end
else if (paracgsize in [OS_NO, OS_128, OS_S128]) then
begin
if (paralen>4) or
(parashift<>0) then
begin
paraloc^.size := OS_INT;
paraloc^.def := osuinttype;
end
else
begin
{ for 3-byte records aligned in the lower bits of register }
paraloc^.size := OS_32;
paraloc^.def := u32inttype;
end;
end
else
begin
paraloc^.size := paracgsize;
paraloc^.def := locdef;
end;
paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
inc(nextintreg);
dec(paralen, tcgsize2size[paraloc^.size]);
inc(stack_offset, sizeof(pint));
end else if (loc = LOC_FPUREGISTER) and
(nextfloatreg <= RS_F13) then begin
paraloc^.loc := loc;
paraloc^.size := paracgsize;
paraloc^.def := locdef;
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
-- exception: ELFv2 abi when passing aggregate parts in FPRs, because those are
a direct mirror of the memory layout of the aggregate }
if not assigned(alllocdef) then
begin
inc(nextintreg);
inc(stack_offset, tcgsize2size[OS_FLOAT]);
end
else
begin
if (tcgsize2size[paracgsize]=8) or
odd(ord(nextfloatreg)-ord(RS_F1)) then
inc(nextintreg);
inc(stack_offset, tcgsize2size[paracgsize]);
end;
inc(nextfloatreg);
dec(paralen, 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;
case loc of
LOC_FPUREGISTER:
begin
if assigned(alllocdef) then
paraloc^.size:=def_cgsize(alllocdef)
else
paraloc^.size:=int_float_cgsize(paralen);
case paraloc^.size of
OS_F32: paraloc^.def:=s32floattype;
OS_F64: paraloc^.def:=s64floattype;
else
internalerror(2013060122);
end;
end;
LOC_REGISTER,
LOC_REFERENCE:
begin
paraloc^.size:=int_cgsize(paralen);
paraloc^.def:=get_paraloc_def(paradef, paralen, firstparaloc);
end;
else
internalerror(2006011101);
end;
if (side = callerside) then
paraloc^.reference.index := NR_STACK_POINTER_REG
else begin
{ during procedure entry, NR_OLD_STACK_POINTER_REG contains the old stack pointer }
paraloc^.reference.index := NR_OLD_STACK_POINTER_REG;
{ create_paraloc_info_intern might be also called when being outside of
code generation so current_procinfo might be not set }
if assigned(current_procinfo) then
tcpuprocinfo(current_procinfo).needs_frame_pointer := true;
end;
paraloc^.reference.offset := stack_offset;
{ align temp contents to next register size }
if not paraaligned then
inc(stack_offset, align(paralen, 8))
else
inc(stack_offset, paralen);
paralen := 0;
end;
firstparaloc:=false;
end;
end;
function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee;
varargspara: tvarargsparalist): longint;
var
cur_stack_offset: aword;
parasize, l: longint;
curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
i: integer;
hp: tparavarsym;
paraloc: pcgparalocation;
begin
init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
firstfloatreg := curfloatreg;
result := create_paraloc_info_intern(p, side, p.paras, curintreg,
curfloatreg, curmmreg, cur_stack_offset, false);
if (p.proccalloption in cstylearrayofconst) then
begin
{ just continue loading the parameters in the registers }
if assigned(varargspara) then
begin
if side=callerside then
result := create_paraloc_info_intern(p, side, varargspara, curintreg,
curfloatreg, curmmreg, cur_stack_offset, true)
else
internalerror(2019021920);
end;
{ varargs routines have to reserve at least 64 bytes for the PPC64 ABI }
if (result < 64) then
result := 64;
end
else
internalerror(2019021911);
if curfloatreg <> firstfloatreg then
include(varargspara.varargsinfo, va_uses_float_reg);
create_funcretloc_info(p, side);
end;
function tcpuparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
begin
{ not supported/required for PowerPC64-linux target }
internalerror(200404182);
result := true;
end;
begin
paramanager := tcpuparamanager.create;
end.