|
@@ -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];
|
|
|
- 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
|
|
|
+ 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
|
|
|
- paracgsize:=def_cgsize(paradef);
|
|
|
- { for things like formaldef }
|
|
|
- if (paracgsize=OS_NO) then
|
|
|
- begin
|
|
|
- paracgsize:=OS_ADDR;
|
|
|
- paralen:=tcgsize2size[OS_ADDR];
|
|
|
- paradef:=voidpointertype;
|
|
|
- end;
|
|
|
+ size:=OS_ADDR;
|
|
|
+ def:=hp.paraloc[side].def;
|
|
|
+ loc:=LOC_REGISTER;
|
|
|
+ register:=NR_X8;
|
|
|
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;
|
|
|
+ end
|
|
|
+ else
|
|
|
+ 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
|
|
|
+ { 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;
|
|
|
+
|
|
|
+
|
|
|
+ procedure taarch64paramanager.init_para_alloc_values;
|
|
|
+ begin
|
|
|
+ curintreg:=RS_FIRST_INT_PARAM_SUPREG;
|
|
|
+ curmmreg:=RS_FIRST_MM_PARAM_SUPREG;
|
|
|
+ curstackoffset:=0;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ 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
|
|
|
- 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;
|
|
|
+ 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
|
|
|
- { 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
|
|
|
+ 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
|
|
|
- paraloc^.loc:=LOC_REGISTER;
|
|
|
- paraloc^.register:=NR_FUNCTION_RETURN_REG;
|
|
|
- if (result.intsize<>3) then
|
|
|
- paraloc^.size:=retcgsize
|
|
|
- else
|
|
|
- paraloc^.size:=OS_32;
|
|
|
- end;
|
|
|
+ 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;
|
|
|
- var
|
|
|
- cur_stack_offset: aword;
|
|
|
- curintreg, curfloatreg, curmmreg: tsuperregister;
|
|
|
- sparesinglereg:tregister;
|
|
|
+ function taarch64paramanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;
|
|
|
begin
|
|
|
- init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
|
|
|
+ init_para_alloc_values;
|
|
|
|
|
|
- result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false);
|
|
|
+ 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;
|