diff --git a/compiler/aarch64/cpupara.pas b/compiler/aarch64/cpupara.pas index 4cca8c0d7f..3b6bb66ea4 100644 --- a/compiler/aarch64/cpupara.pas +++ b/compiler/aarch64/cpupara.pas @@ -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;