mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-21 20:29:32 +02:00
* implemented parameter passing and function result locations
git-svn-id: trunk@29862 -
This commit is contained in:
parent
edef6b2a0a
commit
2214966f26
@ -34,18 +34,23 @@ unit cpupara;
|
||||
|
||||
type
|
||||
taarch64paramanager = class(tparamanager)
|
||||
function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
|
||||
function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
|
||||
function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
|
||||
function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
|
||||
function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
|
||||
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 get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
|
||||
function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
|
||||
function get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset; override;
|
||||
function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
|
||||
function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override;
|
||||
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;
|
||||
private
|
||||
procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
|
||||
function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
|
||||
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
|
||||
curintreg,
|
||||
curmmreg: tsuperregister;
|
||||
curstackoffset: aword;
|
||||
|
||||
procedure init_para_alloc_values;
|
||||
procedure alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
|
||||
|
||||
procedure create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -55,6 +60,13 @@ unit cpupara;
|
||||
rgobj,
|
||||
defutil,symsym,symtable;
|
||||
|
||||
const
|
||||
RS_FIRST_INT_PARAM_SUPREG = RS_X0;
|
||||
RS_LAST_INT_PARAM_SUPREG = RS_X7;
|
||||
{ Q0/D0/S0/H0/B0 all have the same superregister number }
|
||||
RS_FIRST_MM_PARAM_SUPREG = RS_D0;
|
||||
RS_LAST_MM_PARAM_SUPREG = RS_D7;
|
||||
|
||||
|
||||
function taarch64paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
|
||||
begin
|
||||
@ -265,7 +277,7 @@ unit cpupara;
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
|
||||
function taarch64paramanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
|
||||
begin
|
||||
if handle_common_ret_in_param(def,pd,result) then
|
||||
exit;
|
||||
@ -275,428 +287,329 @@ unit cpupara;
|
||||
end;
|
||||
|
||||
|
||||
procedure taarch64paramanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
|
||||
begin
|
||||
curintreg:=RS_R0;
|
||||
curfloatreg:=RS_F0;
|
||||
curmmreg:=RS_D0;
|
||||
cur_stack_offset:=0;
|
||||
sparesinglereg := NR_NO;
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
|
||||
var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint;
|
||||
|
||||
procedure taarch64paramanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
|
||||
var
|
||||
nextintreg,nextfloatreg,nextmmreg : tsuperregister;
|
||||
paradef : tdef;
|
||||
paraloc : pcgparalocation;
|
||||
stack_offset : aword;
|
||||
hp : tparavarsym;
|
||||
loc : tcgloc;
|
||||
paracgsize : tcgsize;
|
||||
paralen : longint;
|
||||
i : integer;
|
||||
firstparaloc: boolean;
|
||||
|
||||
procedure assignintreg;
|
||||
begin
|
||||
{ In case of po_delphi_nested_cc, the parent frame pointer
|
||||
is always passed on the stack. }
|
||||
if (nextintreg<=RS_R3) and
|
||||
(not(vo_is_parentfp in hp.varoptions) or
|
||||
not(po_delphi_nested_cc in p.procoptions)) then
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
|
||||
inc(nextintreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,4);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
hp: tparavarsym;
|
||||
i: longint;
|
||||
begin
|
||||
result:=0;
|
||||
nextintreg:=curintreg;
|
||||
nextfloatreg:=curfloatreg;
|
||||
nextmmreg:=curmmreg;
|
||||
stack_offset:=cur_stack_offset;
|
||||
|
||||
for i:=0 to paras.count-1 do
|
||||
begin
|
||||
hp:=tparavarsym(paras[i]);
|
||||
paradef:=hp.vardef;
|
||||
|
||||
hp.paraloc[side].reset;
|
||||
|
||||
{ currently only support C-style array of const,
|
||||
there should be no location assigned to the vararg array itself }
|
||||
if (p.proccalloption in cstylearrayofconst) and
|
||||
is_array_of_const(paradef) then
|
||||
{ hidden function result parameter is passed in X8 (doesn't have to
|
||||
be valid on return) }
|
||||
if vo_is_funcret in hp.varoptions 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;
|
||||
break;
|
||||
end;
|
||||
|
||||
if push_addr_param(hp.varspez,paradef,p.proccalloption) then
|
||||
begin
|
||||
paradef:=getpointerdef(paradef);
|
||||
loc:=LOC_REGISTER;
|
||||
paracgsize := OS_ADDR;
|
||||
paralen := tcgsize2size[OS_ADDR];
|
||||
hp.paraloc[side].reset;
|
||||
hp.paraloc[side].size:=OS_ADDR;
|
||||
hp.paraloc[side].alignment:=voidpointertype.alignment;
|
||||
hp.paraloc[side].intsize:=voidpointertype.size;
|
||||
hp.paraloc[side].def:=getpointerdef(hp.vardef);
|
||||
with hp.paraloc[side].add_location^ do
|
||||
begin
|
||||
size:=OS_ADDR;
|
||||
def:=hp.paraloc[side].def;
|
||||
loc:=LOC_REGISTER;
|
||||
register:=NR_X8;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
if not is_special_array(paradef) then
|
||||
paralen := paradef.size
|
||||
else
|
||||
paralen := tcgsize2size[def_cgsize(paradef)];
|
||||
loc := getparaloc(p.proccalloption,paradef,isvariadic);
|
||||
if (paradef.typ in [objectdef,arraydef,recorddef]) and
|
||||
not is_special_array(paradef) and
|
||||
(hp.varspez in [vs_value,vs_const]) then
|
||||
paracgsize := int_cgsize(paralen)
|
||||
else
|
||||
begin
|
||||
paracgsize:=def_cgsize(paradef);
|
||||
{ for things like formaldef }
|
||||
if (paracgsize=OS_NO) then
|
||||
begin
|
||||
paracgsize:=OS_ADDR;
|
||||
paralen:=tcgsize2size[OS_ADDR];
|
||||
paradef:=voidpointertype;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
|
||||
hp.paraloc[side].size:=paracgsize;
|
||||
hp.paraloc[side].Alignment:=std_param_align;
|
||||
hp.paraloc[side].intsize:=paralen;
|
||||
hp.paraloc[side].def:=paradef;
|
||||
firstparaloc:=true;
|
||||
|
||||
{$ifdef EXTDEBUG}
|
||||
if paralen=0 then
|
||||
internalerror(200410311);
|
||||
{$endif EXTDEBUG}
|
||||
while paralen>0 do
|
||||
begin
|
||||
paraloc:=hp.paraloc[side].add_location;
|
||||
|
||||
if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then
|
||||
case paracgsize of
|
||||
OS_F32:
|
||||
paraloc^.size:=OS_32;
|
||||
OS_F64:
|
||||
paraloc^.size:=OS_32;
|
||||
else
|
||||
internalerror(2005082901);
|
||||
end
|
||||
else if (paracgsize in [OS_NO,OS_64,OS_S64]) then
|
||||
paraloc^.size := OS_32
|
||||
else
|
||||
paraloc^.size:=paracgsize;
|
||||
case loc of
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
{ align registers for eabi }
|
||||
if (target_info.abi in [abi_eabi,abi_eabihf]) and
|
||||
firstparaloc and
|
||||
(paradef.alignment=8) then
|
||||
begin
|
||||
if (nextintreg in [RS_R1,RS_R3]) then
|
||||
inc(nextintreg)
|
||||
else if nextintreg>RS_R3 then
|
||||
stack_offset:=align(stack_offset,8);
|
||||
end;
|
||||
{ this is not abi compliant
|
||||
why? (FK) }
|
||||
if nextintreg<=RS_R3 then
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE);
|
||||
inc(nextintreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ LOC_REFERENCE always contains everything that's left }
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.size:=int_cgsize(paralen);
|
||||
if (side=callerside) then
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,align(paralen,4));
|
||||
paralen:=0;
|
||||
end;
|
||||
end;
|
||||
LOC_FPUREGISTER:
|
||||
begin
|
||||
if nextfloatreg<=RS_F3 then
|
||||
begin
|
||||
paraloc^.loc:=LOC_FPUREGISTER;
|
||||
paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
|
||||
inc(nextfloatreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
case paraloc^.size of
|
||||
OS_F32:
|
||||
inc(stack_offset,4);
|
||||
OS_F64:
|
||||
inc(stack_offset,8);
|
||||
OS_F80:
|
||||
inc(stack_offset,10);
|
||||
OS_F128:
|
||||
inc(stack_offset,16);
|
||||
else
|
||||
internalerror(200403201);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
LOC_MMREGISTER:
|
||||
begin
|
||||
if (nextmmreg<=RS_D7) or
|
||||
((paraloc^.size = OS_F32) and
|
||||
(sparesinglereg<>NR_NO)) then
|
||||
begin
|
||||
paraloc^.loc:=LOC_MMREGISTER;
|
||||
case paraloc^.size of
|
||||
OS_F32:
|
||||
if sparesinglereg = NR_NO then
|
||||
begin
|
||||
paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS);
|
||||
sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS);
|
||||
inc(nextmmreg);
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.register:=sparesinglereg;
|
||||
sparesinglereg := NR_NO;
|
||||
end;
|
||||
OS_F64:
|
||||
begin
|
||||
paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD);
|
||||
inc(nextmmreg);
|
||||
end;
|
||||
else
|
||||
internalerror(2012031601);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ once a floating point parameters has been placed
|
||||
on the stack we must not pass any more in vfp regs
|
||||
even if there is a single precision register still
|
||||
free}
|
||||
sparesinglereg := NR_NO;
|
||||
{ LOC_REFERENCE always contains everything that's left }
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.size:=int_cgsize(paralen);
|
||||
if (side=callerside) then
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,align(paralen,4));
|
||||
paralen:=0;
|
||||
end;
|
||||
end;
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
if push_addr_param(hp.varspez,paradef,p.proccalloption) then
|
||||
begin
|
||||
paraloc^.size:=OS_ADDR;
|
||||
assignintreg
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ align stack for eabi }
|
||||
if (target_info.abi in [abi_eabi,abi_eabihf]) and
|
||||
firstparaloc and
|
||||
(paradef.alignment=8) then
|
||||
stack_offset:=align(stack_offset,8);
|
||||
|
||||
paraloc^.size:=paracgsize;
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG;
|
||||
paraloc^.reference.offset:=stack_offset;
|
||||
inc(stack_offset,align(paralen,4));
|
||||
paralen:=0
|
||||
end;
|
||||
end;
|
||||
else
|
||||
internalerror(2002071002);
|
||||
end;
|
||||
if side=calleeside then
|
||||
begin
|
||||
if paraloc^.loc=LOC_REFERENCE then
|
||||
begin
|
||||
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
||||
{ on non-Darwin, the framepointer contains the value
|
||||
of the stack pointer on entry. On Darwin, the
|
||||
framepointer points to the previously saved
|
||||
framepointer (which is followed only by the saved
|
||||
return address -> framepointer + 4 = stack pointer
|
||||
on entry }
|
||||
if not(target_info.system in systems_darwin) then
|
||||
inc(paraloc^.reference.offset,4)
|
||||
else
|
||||
inc(paraloc^.reference.offset,8);
|
||||
end;
|
||||
end;
|
||||
dec(paralen,tcgsize2size[paraloc^.size]);
|
||||
firstparaloc:=false
|
||||
end;
|
||||
alloc_para(hp.paraloc[side],p,hp.varspez,side,hp.vardef,isvariadic,
|
||||
(vo_is_parentfp in hp.varoptions) and
|
||||
(po_delphi_nested_cc in p.procoptions));
|
||||
end;
|
||||
curintreg:=nextintreg;
|
||||
curfloatreg:=nextfloatreg;
|
||||
curmmreg:=nextmmreg;
|
||||
cur_stack_offset:=stack_offset;
|
||||
result:=cur_stack_offset;
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
|
||||
var
|
||||
paraloc : pcgparalocation;
|
||||
retcgsize : tcgsize;
|
||||
retcgsize: tcgsize;
|
||||
begin
|
||||
if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
|
||||
exit;
|
||||
|
||||
paraloc:=result.add_location;
|
||||
{ Return in FPU register? }
|
||||
if result.def.typ=floatdef then
|
||||
begin
|
||||
if target_info.abi = abi_eabihf then
|
||||
begin
|
||||
paraloc^.loc:=LOC_MMREGISTER;
|
||||
case retcgsize of
|
||||
OS_64,
|
||||
OS_F64:
|
||||
begin
|
||||
paraloc^.register:=NR_MM_RESULT_REG;
|
||||
end;
|
||||
OS_32,
|
||||
OS_F32:
|
||||
begin
|
||||
paraloc^.register:=NR_S0;
|
||||
end;
|
||||
else
|
||||
internalerror(2012032501);
|
||||
end;
|
||||
paraloc^.size:=retcgsize;
|
||||
end
|
||||
else if (p.proccalloption in [pocall_softfloat]) or
|
||||
(cs_fp_emulation in current_settings.moduleswitches) or
|
||||
(current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16,fpu_fpv4_s16]) then
|
||||
begin
|
||||
case retcgsize of
|
||||
OS_64,
|
||||
OS_F64:
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
if target_info.endian = endian_big then
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
|
||||
else
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
|
||||
paraloc^.size:=OS_32;
|
||||
paraloc:=result.add_location;
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
if target_info.endian = endian_big then
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
|
||||
else
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
|
||||
paraloc^.size:=OS_32;
|
||||
end;
|
||||
OS_32,
|
||||
OS_F32:
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=NR_FUNCTION_RETURN_REG;
|
||||
paraloc^.size:=OS_32;
|
||||
end;
|
||||
else
|
||||
internalerror(2005082603);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_FPUREGISTER;
|
||||
paraloc^.register:=NR_FPU_RESULT_REG;
|
||||
paraloc^.size:=retcgsize;
|
||||
end;
|
||||
end
|
||||
{ Return in register }
|
||||
else
|
||||
begin
|
||||
if retcgsize in [OS_64,OS_S64] then
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
if target_info.endian = endian_big then
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
|
||||
else
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG;
|
||||
paraloc^.size:=OS_32;
|
||||
paraloc:=result.add_location;
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
if target_info.endian = endian_big then
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
|
||||
else
|
||||
paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG;
|
||||
paraloc^.size:=OS_32;
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=NR_FUNCTION_RETURN_REG;
|
||||
if (result.intsize<>3) then
|
||||
paraloc^.size:=retcgsize
|
||||
else
|
||||
paraloc^.size:=OS_32;
|
||||
end;
|
||||
end;
|
||||
{ in this case, it must be returned in registers as if it were passed
|
||||
as the first parameter }
|
||||
init_para_alloc_values;
|
||||
alloc_para(result,p,vs_value,side,result.def,false,false);
|
||||
{ sanity check (LOC_VOID for empty records) }
|
||||
if not assigned(result.location) or
|
||||
not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then
|
||||
internalerror(2014113001);
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
|
||||
var
|
||||
cur_stack_offset: aword;
|
||||
curintreg, curfloatreg, curmmreg: tsuperregister;
|
||||
sparesinglereg:tregister;
|
||||
procedure taarch64paramanager.init_para_alloc_values;
|
||||
begin
|
||||
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
|
||||
curintreg:=RS_FIRST_INT_PARAM_SUPREG;
|
||||
curmmreg:=RS_FIRST_MM_PARAM_SUPREG;
|
||||
curstackoffset:=0;
|
||||
end;
|
||||
|
||||
result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
|
||||
|
||||
procedure taarch64paramanager.alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
|
||||
var
|
||||
hfabasedef, locdef: tdef;
|
||||
paraloc: pcgparalocation;
|
||||
paralen, stackslotlen: asizeint;
|
||||
loc: tcgloc;
|
||||
paracgsize, locsize: tcgsize;
|
||||
firstparaloc: boolean;
|
||||
begin
|
||||
result.reset;
|
||||
|
||||
{ currently only support C-style array of const,
|
||||
there should be no location assigned to the vararg array itself }
|
||||
if (p.proccalloption in cstylearrayofconst) and
|
||||
is_array_of_const(paradef) then
|
||||
begin
|
||||
paraloc:=result.add_location;
|
||||
{ hack: the paraloc must be valid, but is not actually used }
|
||||
paraloc^.loc:=LOC_REGISTER;
|
||||
paraloc^.register:=NR_X0;
|
||||
paraloc^.size:=OS_ADDR;
|
||||
exit;
|
||||
end;
|
||||
|
||||
if push_addr_param(varspez,paradef,p.proccalloption) then
|
||||
begin
|
||||
paradef:=getpointerdef(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)];
|
||||
loc:=getparaloc(p.proccalloption,paradef);
|
||||
if (paradef.typ in [objectdef,arraydef,recorddef]) and
|
||||
not is_special_array(paradef) and
|
||||
(varspez in [vs_value,vs_const]) then
|
||||
paracgsize:=int_cgsize(paralen)
|
||||
else
|
||||
begin
|
||||
paracgsize:=def_cgsize(paradef);
|
||||
{ for things like formaldef }
|
||||
if paracgsize=OS_NO then
|
||||
begin
|
||||
paracgsize:=OS_ADDR;
|
||||
paralen:=tcgsize2size[OS_ADDR];
|
||||
paradef:=voidpointertype;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
|
||||
{ get hfa basedef if applicable }
|
||||
if not is_hfa(paradef,hfabasedef) then
|
||||
hfabasedef:=nil;
|
||||
|
||||
result.size:=paracgsize;
|
||||
result.alignment:=std_param_align;
|
||||
result.intsize:=paralen;
|
||||
result.def:=paradef;
|
||||
|
||||
{ empty record: skipped (explicitly defined by Apple ABI, undefined
|
||||
by general ABI; libffi also skips them in all cases) }
|
||||
if not is_special_array(paradef) and
|
||||
(paradef.size=0) then
|
||||
begin
|
||||
paraloc:=result.add_location;
|
||||
paraloc^.loc:=LOC_VOID;
|
||||
paraloc^.def:=paradef;
|
||||
paraloc^.size:=OS_NO;
|
||||
exit;
|
||||
end;
|
||||
|
||||
{ sufficient registers left? }
|
||||
case loc of
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
{ In case of po_delphi_nested_cc, the parent frame pointer
|
||||
is always passed on the stack. }
|
||||
if isdelphinestedcc then
|
||||
loc:=LOC_REFERENCE
|
||||
else if curintreg+((paralen-1) shr 3)>RS_LAST_INT_PARAM_SUPREG then
|
||||
begin
|
||||
{ not enough integer registers left -> no more register
|
||||
parameters, copy all to stack
|
||||
}
|
||||
curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
|
||||
loc:=LOC_REFERENCE;
|
||||
end;
|
||||
end;
|
||||
LOC_MMREGISTER:
|
||||
begin;
|
||||
{ every hfa element must be passed in a separate register }
|
||||
if (assigned(hfabasedef) and
|
||||
(curmmreg+(paralen div hfabasedef.size)>RS_LAST_MM_PARAM_SUPREG)) or
|
||||
(curmmreg+((paralen-1) shr 3)>RS_LAST_MM_PARAM_SUPREG) then
|
||||
begin
|
||||
{ not enough mm registers left -> no more register
|
||||
parameters, copy all to stack
|
||||
}
|
||||
curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
|
||||
loc:=LOC_REFERENCE;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ allocate registers/stack locations }
|
||||
firstparaloc:=true;
|
||||
repeat
|
||||
paraloc:=result.add_location;
|
||||
|
||||
{ set paraloc size/def }
|
||||
if assigned(hfabasedef) then
|
||||
begin
|
||||
locsize:=def_cgsize(hfabasedef);
|
||||
locdef:=hfabasedef;
|
||||
end
|
||||
{ make sure we don't lose whether or not the type is signed }
|
||||
else if (loc=LOC_REGISTER) and
|
||||
(paradef.typ<>orddef) then
|
||||
begin
|
||||
locsize:=int_cgsize(paralen);
|
||||
locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
|
||||
end
|
||||
else
|
||||
begin
|
||||
locsize:=paracgsize;
|
||||
locdef:=paradef;
|
||||
end;
|
||||
if locsize in [OS_NO,OS_128,OS_S128] then
|
||||
begin
|
||||
if paralen>4 then
|
||||
begin
|
||||
paraloc^.size:=OS_INT;
|
||||
paraloc^.def:=u64inttype;
|
||||
end
|
||||
else
|
||||
begin
|
||||
{ for 3-byte records }
|
||||
paraloc^.size:=OS_32;
|
||||
paraloc^.def:=u32inttype;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
paraloc^.size:=locsize;
|
||||
paraloc^.def:=locdef;
|
||||
end;
|
||||
|
||||
{ paraloc loc }
|
||||
paraloc^.loc:=loc;
|
||||
|
||||
{ assign register/stack address }
|
||||
case loc of
|
||||
LOC_REGISTER:
|
||||
begin
|
||||
paraloc^.register:=newreg(R_INTREGISTER,curintreg,cgsize2subreg(R_INTREGISTER,paraloc^.size));
|
||||
inc(curintreg);
|
||||
dec(paralen,tcgsize2size[paraloc^.size]);
|
||||
|
||||
{ "The general ABI specifies that it is the callee's
|
||||
responsibility to sign or zero-extend arguments having fewer
|
||||
than 32 bits, and that unused bits in a register are
|
||||
unspecified. In iOS, however, the caller must perform such
|
||||
extensions, up to 32 bits." }
|
||||
if (target_info.abi=abi_aarch64_darwin) and
|
||||
(side=callerside) and
|
||||
is_ordinal(paradef) and
|
||||
(paradef.size<4) then
|
||||
paraloc^.size:=OS_32;
|
||||
|
||||
{ in case it's a composite, "The argument is passed as though
|
||||
it had been loaded into the registers from a double-word-
|
||||
aligned address with an appropriate sequence of LDR
|
||||
instructions loading consecutive registers from memory" ->
|
||||
in case of big endian, values in not completely filled
|
||||
registers must be shifted to the top bits }
|
||||
if (target_info.endian=endian_big) and
|
||||
not(paraloc^.size in [OS_64,OS_S64]) and
|
||||
(paradef.typ in [setdef,recorddef,arraydef,objectdef]) then
|
||||
paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size]);
|
||||
end;
|
||||
LOC_MMREGISTER:
|
||||
begin
|
||||
paraloc^.register:=newreg(R_MMREGISTER,curmmreg,cgsize2subreg(R_MMREGISTER,paraloc^.size));
|
||||
inc(curmmreg);
|
||||
dec(paralen,tcgsize2size[paraloc^.size]);
|
||||
end;
|
||||
LOC_REFERENCE:
|
||||
begin
|
||||
paraloc^.size:=paracgsize;
|
||||
paraloc^.loc:=LOC_REFERENCE;
|
||||
if side=callerside then
|
||||
paraloc^.reference.index:=NR_STACK_POINTER_REG
|
||||
else
|
||||
paraloc^.reference.index:=NR_FRAME_POINTER_REG;
|
||||
|
||||
{ the current stack offset may not be properly aligned in
|
||||
case we're on Darwin have allocated a non-variadic argument
|
||||
< 8 bytes previously }
|
||||
if target_info.abi=abi_aarch64_darwin then
|
||||
curstackoffset:=align(curstackoffset,paraloc^.def.alignment);
|
||||
|
||||
{ on Darwin, non-variadic arguments take up their actual size
|
||||
on the stack; on other platforms, they take up a multiple of
|
||||
8 bytes }
|
||||
if (target_info.abi=abi_aarch64_darwin) and
|
||||
not isvariadic then
|
||||
stackslotlen:=paralen
|
||||
else
|
||||
stackslotlen:=align(paralen,8);
|
||||
|
||||
{ from the ABI: if arguments occupy partial stack space, they
|
||||
have to occupy the lowest significant bits of a register
|
||||
containing that value which is then stored to memory ->
|
||||
in case of big endian, skip the alignment bytes (if any) }
|
||||
if target_info.endian=endian_little then
|
||||
paraloc^.reference.offset:=curstackoffset
|
||||
else
|
||||
paraloc^.reference.offset:=curstackoffset+stackslotlen-paralen;
|
||||
inc(curstackoffset,stackslotlen);
|
||||
paralen:=0
|
||||
end;
|
||||
else
|
||||
internalerror(2002071002);
|
||||
end;
|
||||
firstparaloc:=false;
|
||||
{ <=0 for sign/zero-extended locations }
|
||||
until paralen<=0;
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;
|
||||
begin
|
||||
init_para_alloc_values;
|
||||
|
||||
create_paraloc_info_intern(p,side,p.paras,false);
|
||||
result:=curstackoffset;
|
||||
|
||||
create_funcretloc_info(p,side);
|
||||
end;
|
||||
|
||||
|
||||
function taarch64paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
|
||||
var
|
||||
cur_stack_offset: aword;
|
||||
curintreg, curfloatreg, curmmreg: tsuperregister;
|
||||
sparesinglereg:tregister;
|
||||
function taarch64paramanager.create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;
|
||||
begin
|
||||
init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
|
||||
init_para_alloc_values;
|
||||
|
||||
result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true);
|
||||
if (p.proccalloption in cstylearrayofconst) then
|
||||
{ just continue loading the parameters in the registers }
|
||||
result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true)
|
||||
{ non-variadic parameters }
|
||||
create_paraloc_info_intern(p,callerside,p.paras,false);
|
||||
if p.proccalloption in cstylearrayofconst then
|
||||
begin
|
||||
{ on Darwin, we cannot use any registers for variadic parameters }
|
||||
if target_info.abi=abi_aarch64_darwin then
|
||||
begin
|
||||
curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
|
||||
curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
|
||||
end;
|
||||
{ continue loading the parameters }
|
||||
create_paraloc_info_intern(p,callerside,varargspara,true);
|
||||
result:=curstackoffset;
|
||||
end
|
||||
else
|
||||
internalerror(200410231);
|
||||
end;
|
||||
|
Loading…
Reference in New Issue
Block a user