cpupara.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. {
  2. Copyright (c) 2013-2014 by Jonas Maebe, Florian Klaempfl and others
  3. AArch64 specific calling conventions
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. { AArch64 specific calling conventions are handled by this unit
  18. }
  19. unit cpupara;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. globtype,globals,
  24. aasmtai,aasmdata,
  25. cpuinfo,cpubase,cgbase,cgutils,
  26. symconst,symbase,symtype,symdef,parabase,paramgr,armpara;
  27. type
  28. tcpuparamanager = class(tarmgenparamanager)
  29. function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
  30. function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
  31. function get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset; override;
  32. function get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray; override;
  33. function get_saved_registers_mm(calloption: tproccalloption): tcpuregisterarray; override;
  34. function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  35. function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override;
  36. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;override;
  37. function create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist):longint;override;
  38. function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  39. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  40. private
  41. curintreg,
  42. curmmreg: tsuperregister;
  43. curstackoffset: aword;
  44. procedure init_para_alloc_values;
  45. procedure alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  46. function getparaloc(calloption: tproccalloption; p: tdef): tcgloc;
  47. procedure create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  48. end;
  49. implementation
  50. uses
  51. verbose,systems,cutils,
  52. rgobj,
  53. defutil,symsym,symtable;
  54. const
  55. RS_FIRST_INT_PARAM_SUPREG = RS_X0;
  56. RS_LAST_INT_PARAM_SUPREG = RS_X7;
  57. { Q0/D0/S0/H0/B0 all have the same superregister number }
  58. RS_FIRST_MM_PARAM_SUPREG = RS_D0;
  59. RS_LAST_MM_PARAM_SUPREG = RS_D7;
  60. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  61. begin
  62. result:=VOLATILE_INTREGISTERS
  63. end;
  64. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  65. begin
  66. result:=[];
  67. end;
  68. function tcpuparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  69. begin
  70. result:=VOLATILE_MMREGISTERS;
  71. end;
  72. function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;
  73. const
  74. saved_regs : tcpuregisterarray =
  75. (RS_X19,RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27,RS_X28);
  76. begin
  77. result:=saved_regs;
  78. end;
  79. function tcpuparamanager.get_saved_registers_mm(calloption: tproccalloption): tcpuregisterarray;
  80. const
  81. saved_mm_regs : tcpuregisterarray =
  82. (RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15);
  83. begin
  84. result:=saved_mm_regs;
  85. end;
  86. function tcpuparamanager.getparaloc(calloption: tproccalloption; p: tdef): tcgloc;
  87. var
  88. hfabasedef: tdef;
  89. begin
  90. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  91. if push_addr_param for the def is true
  92. }
  93. case p.typ of
  94. orddef:
  95. getparaloc:=LOC_REGISTER;
  96. floatdef:
  97. getparaloc:=LOC_MMREGISTER;
  98. enumdef:
  99. getparaloc:=LOC_REGISTER;
  100. pointerdef:
  101. getparaloc:=LOC_REGISTER;
  102. formaldef:
  103. getparaloc:=LOC_REGISTER;
  104. classrefdef:
  105. getparaloc:=LOC_REGISTER;
  106. recorddef:
  107. if not is_hfa(p,hfabasedef) then
  108. getparaloc:=LOC_REGISTER
  109. else
  110. getparaloc:=LOC_MMREGISTER;
  111. objectdef:
  112. getparaloc:=LOC_REGISTER;
  113. stringdef:
  114. if is_shortstring(p) or is_longstring(p) then
  115. getparaloc:=LOC_REFERENCE
  116. else
  117. getparaloc:=LOC_REGISTER;
  118. procvardef:
  119. getparaloc:=LOC_REGISTER;
  120. filedef:
  121. getparaloc:=LOC_REGISTER;
  122. arraydef:
  123. if not is_hfa(p,hfabasedef) then
  124. getparaloc:=LOC_REGISTER
  125. else
  126. getparaloc:=LOC_MMREGISTER;
  127. setdef:
  128. getparaloc:=LOC_REGISTER;
  129. variantdef:
  130. getparaloc:=LOC_REGISTER;
  131. { avoid problems with errornous definitions }
  132. errordef:
  133. getparaloc:=LOC_REGISTER;
  134. else
  135. internalerror(2002071001);
  136. end;
  137. end;
  138. function tcpuparamanager.push_addr_param(varspez: tvarspez; def :tdef; calloption: tproccalloption): boolean;
  139. var
  140. hfabasedef: tdef;
  141. begin
  142. result:=false;
  143. if varspez in [vs_var,vs_out,vs_constref] then
  144. begin
  145. result:=true;
  146. exit;
  147. end;
  148. case def.typ of
  149. objectdef:
  150. result:=is_object(def);
  151. recorddef:
  152. { ABI: any composite > 16 bytes that not a hfa/hva
  153. Special case: MWPascal, which passes all const parameters by
  154. reference for compatibility reasons
  155. Special case 2: on Windows we need to pass all const records by
  156. reference due to the Windows unit (ab)using const to pass
  157. pointer parameters }
  158. result:=
  159. ((varspez=vs_const) and
  160. (
  161. (calloption=pocall_mwpascal) or
  162. (target_info.system=system_aarch64_win64)
  163. )) or
  164. (not is_hfa(def,hfabasedef) and
  165. (def.size>16));
  166. variantdef,
  167. formaldef:
  168. result:=true;
  169. { arrays are composites and hence treated the same as records by the
  170. ABI (watch out for C, where an array is a pointer)
  171. Also: all other platforms pass const arrays by reference. Do the
  172. same here, because there is too much hacky code out there that
  173. relies on this ("array[0..0] of x" passed as const parameter and
  174. then indexed beyond its bounds) }
  175. arraydef:
  176. result:=
  177. ((calloption in cdecl_pocalls) and
  178. not is_dynamic_array(def)) or
  179. is_open_array(def) or
  180. is_array_of_const(def) or
  181. is_array_constructor(def) or
  182. ((tarraydef(def).highrange>=tarraydef(def).lowrange) and
  183. ((varspez=vs_const) or
  184. (not is_hfa(def,hfabasedef) and
  185. (def.size>16))));
  186. setdef :
  187. result:=def.size>16;
  188. stringdef :
  189. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  190. else
  191. ;
  192. end;
  193. end;
  194. function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
  195. begin
  196. if handle_common_ret_in_param(def,pd,result) then
  197. exit;
  198. { ABI: if the parameter would be passed in registers, it is returned
  199. in those registers; otherwise, it's returned by reference }
  200. result:=push_addr_param(vs_value,def,pd.proccalloption);
  201. end;
  202. procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  203. var
  204. hp: tparavarsym;
  205. i: longint;
  206. begin
  207. for i:=0 to paras.count-1 do
  208. begin
  209. hp:=tparavarsym(paras[i]);
  210. { hidden function result parameter is passed in X8 (doesn't have to
  211. be valid on return) according to the ABI
  212. -- don't follow the ABI for managed types, because
  213. a) they are passed in registers as parameters, so we should also
  214. return them in a register to be ABI-compliant (which we can't
  215. because the entire compiler is built around the idea that
  216. they are returned by reference, for ref-counting performance
  217. and Delphi-compatibility reasons)
  218. b) there are hacks in the system unit that expect that you can
  219. call
  220. function f: com_interface;
  221. as
  222. procedure p(out o: obj);
  223. That can only work in case we do not use x8 to return them
  224. from the function, but the regular first parameter register.
  225. As the ABI says this behaviour is ok for C++ classes with a
  226. non-trivial copy constructor or destructor, it seems reasonable
  227. for us to do this for managed types as well.}
  228. if (vo_is_funcret in hp.varoptions) and
  229. not is_managed_type(hp.vardef) then
  230. begin
  231. hp.paraloc[side].reset;
  232. hp.paraloc[side].size:=OS_ADDR;
  233. hp.paraloc[side].alignment:=voidpointertype.alignment;
  234. hp.paraloc[side].intsize:=voidpointertype.size;
  235. hp.paraloc[side].def:=cpointerdef.getreusable_no_free(hp.vardef);
  236. with hp.paraloc[side].add_location^ do
  237. begin
  238. size:=OS_ADDR;
  239. def:=hp.paraloc[side].def;
  240. loc:=LOC_REGISTER;
  241. register:=NR_XR;
  242. end
  243. end
  244. else
  245. alloc_para(hp.paraloc[side],p,hp.varspez,side,hp.vardef,isvariadic,
  246. (vo_is_parentfp in hp.varoptions) and
  247. (po_delphi_nested_cc in p.procoptions));
  248. end;
  249. end;
  250. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  251. var
  252. retcgsize: tcgsize;
  253. otherside: tcallercallee;
  254. begin
  255. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  256. exit;
  257. { in this case, it must be returned in registers as if it were passed
  258. as the first parameter }
  259. init_para_alloc_values;
  260. { if we're on the callee side, filling the result location is actually the "callerside"
  261. as far passing it as a parameter value is concerned }
  262. if side=callerside then
  263. otherside:=calleeside
  264. else
  265. otherside:=callerside;
  266. alloc_para(result,p,vs_value,otherside,result.def,false,false);
  267. { sanity check (LOC_VOID for empty records) }
  268. if not assigned(result.location) or
  269. not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then
  270. internalerror(2014113001);
  271. {$ifndef llvm}
  272. {
  273. According to ARM64 ABI: "If the size of the argument is less than 8 bytes then
  274. the size of the argument is set to 8 bytes. The effect is as if the argument
  275. was copied to the least significant bits of a 64-bit register and the remaining
  276. bits filled with unspecified values."
  277. Therefore at caller side force the ordinal result to be always 64-bit, so it
  278. will be stripped to the required size and uneeded bits are discarded.
  279. According to Jonas iOS doesn't zero extend results in the callee either
  280. }
  281. if (side=callerside) and (result.location^.loc = LOC_REGISTER) and
  282. (result.def.size<8) and is_ordinal(result.def) then
  283. begin
  284. result.location^.size:=OS_64;
  285. result.location^.def:=u64inttype;
  286. end;
  287. {$endif}
  288. end;
  289. function tcpuparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  290. begin
  291. { we always set up a stack frame -> we can always access the parameters
  292. this way }
  293. result:=
  294. (cgpara.location^.loc=LOC_REFERENCE) and
  295. not assigned(cgpara.location^.next);
  296. end;
  297. procedure tcpuparamanager.init_para_alloc_values;
  298. begin
  299. curintreg:=RS_FIRST_INT_PARAM_SUPREG;
  300. curmmreg:=RS_FIRST_MM_PARAM_SUPREG;
  301. curstackoffset:=0;
  302. end;
  303. procedure tcpuparamanager.alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  304. var
  305. hfabasedef, locdef: tdef;
  306. paraloc: pcgparalocation;
  307. paralen, stackslotlen: asizeint;
  308. loc: tcgloc;
  309. paracgsize, locsize: tcgsize;
  310. firstparaloc: boolean;
  311. begin
  312. result.init;
  313. { currently only support C-style array of const,
  314. there should be no location assigned to the vararg array itself }
  315. if (p.proccalloption in cstylearrayofconst) and
  316. is_array_of_const(paradef) then
  317. begin
  318. result.size:=OS_NO;
  319. result.def:=paradef;
  320. result.alignment:=std_param_align;
  321. result.intsize:=0;
  322. paraloc:=result.add_location;
  323. { hack: the paraloc must be valid, but is not actually used }
  324. paraloc^.loc:=LOC_REGISTER;
  325. paraloc^.register:=NR_X0;
  326. paraloc^.size:=OS_ADDR;
  327. paraloc^.def:=paradef;
  328. exit;
  329. end;
  330. if push_addr_param(varspez,paradef,p.proccalloption) then
  331. begin
  332. paradef:=cpointerdef.getreusable_no_free(paradef);
  333. loc:=LOC_REGISTER;
  334. paracgsize:=OS_ADDR;
  335. paralen:=tcgsize2size[OS_ADDR];
  336. end
  337. else
  338. begin
  339. if not is_special_array(paradef) then
  340. paralen:=paradef.size
  341. else
  342. paralen:=tcgsize2size[def_cgsize(paradef)];
  343. loc:=getparaloc(p.proccalloption,paradef);
  344. if (paradef.typ in [objectdef,arraydef,recorddef,setdef]) and
  345. not is_special_array(paradef) and
  346. (varspez in [vs_value,vs_const]) then
  347. paracgsize:=int_cgsize(paralen)
  348. else
  349. begin
  350. paracgsize:=def_cgsize(paradef);
  351. { for things like formaldef }
  352. if paracgsize=OS_NO then
  353. begin
  354. paracgsize:=OS_ADDR;
  355. paralen:=tcgsize2size[OS_ADDR];
  356. paradef:=voidpointertype;
  357. end;
  358. end
  359. end;
  360. { get hfa basedef if applicable }
  361. if not is_hfa(paradef,hfabasedef) then
  362. hfabasedef:=nil;
  363. result.size:=paracgsize;
  364. result.alignment:=std_param_align;
  365. result.intsize:=paralen;
  366. result.def:=paradef;
  367. { empty record: skipped (explicitly defined by Apple ABI, undefined
  368. by general ABI; libffi also skips them in all cases) }
  369. if not is_special_array(paradef) and
  370. (paradef.size=0) then
  371. begin
  372. paraloc:=result.add_location;
  373. paraloc^.loc:=LOC_VOID;
  374. paraloc^.def:=paradef;
  375. paraloc^.size:=OS_NO;
  376. exit;
  377. end;
  378. { sufficient registers left? }
  379. case loc of
  380. LOC_REGISTER:
  381. begin
  382. { In case of po_delphi_nested_cc, the parent frame pointer
  383. is always passed on the stack. }
  384. if isdelphinestedcc then
  385. loc:=LOC_REFERENCE
  386. else if curintreg+((paralen-1) shr 3)>RS_LAST_INT_PARAM_SUPREG then
  387. begin
  388. { not enough integer registers left -> no more register
  389. parameters, copy all to stack
  390. }
  391. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  392. loc:=LOC_REFERENCE;
  393. end;
  394. end;
  395. LOC_MMREGISTER:
  396. begin;
  397. { every hfa element must be passed in a separate register }
  398. if (assigned(hfabasedef) and
  399. (curmmreg+((paralen-1) div hfabasedef.size)>RS_LAST_MM_PARAM_SUPREG)) or
  400. (curmmreg+((paralen-1) shr 3)>RS_LAST_MM_PARAM_SUPREG) then
  401. begin
  402. { not enough mm registers left -> no more register
  403. parameters, copy all to stack
  404. }
  405. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  406. loc:=LOC_REFERENCE;
  407. end;
  408. end;
  409. else
  410. ;
  411. end;
  412. { allocate registers/stack locations }
  413. firstparaloc:=true;
  414. repeat
  415. paraloc:=result.add_location;
  416. { set paraloc size/def }
  417. if assigned(hfabasedef) then
  418. begin
  419. locsize:=def_cgsize(hfabasedef);
  420. locdef:=hfabasedef;
  421. end
  422. { make sure we don't lose whether or not the type is signed }
  423. else if (loc=LOC_REGISTER) and
  424. (paradef.typ<>orddef) then
  425. begin
  426. locsize:=int_cgsize(paralen);
  427. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  428. end
  429. else
  430. begin
  431. locsize:=paracgsize;
  432. locdef:=paradef;
  433. end;
  434. if locsize in [OS_NO,OS_128,OS_S128] then
  435. begin
  436. if paralen>4 then
  437. begin
  438. paraloc^.size:=OS_INT;
  439. paraloc^.def:=u64inttype;
  440. end
  441. else
  442. begin
  443. { for 3-byte records }
  444. paraloc^.size:=OS_32;
  445. paraloc^.def:=u32inttype;
  446. end;
  447. end
  448. else
  449. begin
  450. paraloc^.size:=locsize;
  451. paraloc^.def:=locdef;
  452. {$ifdef llvm}
  453. if not is_ordinal(paradef) then
  454. begin
  455. case locsize of
  456. OS_8,OS_16,OS_32:
  457. begin
  458. paraloc^.size:=OS_64;
  459. paraloc^.def:=u64inttype;
  460. end;
  461. OS_S8,OS_S16,OS_S32:
  462. begin
  463. paraloc^.size:=OS_S64;
  464. paraloc^.def:=s64inttype;
  465. end;
  466. OS_F32:
  467. begin
  468. paraloc^.size:=OS_F32;
  469. paraloc^.def:=s32floattype;
  470. end;
  471. OS_F64:
  472. begin
  473. paraloc^.size:=OS_F64;
  474. paraloc^.def:=s64floattype;
  475. end;
  476. else
  477. begin
  478. if is_record(locdef) or
  479. is_set(locdef) or
  480. ((locdef.typ=arraydef) and
  481. not is_special_array(locdef)) then
  482. begin
  483. paraloc^.size:=OS_64;
  484. paraloc^.def:=u64inttype;
  485. end
  486. end;
  487. end;
  488. end;
  489. {$endif llvm}
  490. end;
  491. { paraloc loc }
  492. paraloc^.loc:=loc;
  493. { assign register/stack address }
  494. case loc of
  495. LOC_REGISTER:
  496. begin
  497. paraloc^.register:=newreg(R_INTREGISTER,curintreg,cgsize2subreg(R_INTREGISTER,paraloc^.size));
  498. inc(curintreg);
  499. dec(paralen,tcgsize2size[paraloc^.size]);
  500. { "The general ABI specifies that it is the callee's
  501. responsibility to sign or zero-extend arguments having fewer
  502. than 32 bits, and that unused bits in a register are
  503. unspecified. In iOS, however, the caller must perform such
  504. extensions, up to 32 bits."
  505. Zero extend an argument at caller side for iOS and
  506. ignore the argument's unspecified high bits at callee side for
  507. all other platforms. }
  508. if (paradef.size<4) and is_ordinal(paradef) then
  509. begin
  510. if target_info.abi=abi_aarch64_darwin then
  511. begin
  512. if side=callerside then
  513. begin
  514. paraloc^.size:=OS_32;
  515. paraloc^.def:=u32inttype;
  516. end;
  517. end
  518. {$ifndef llvm}
  519. else
  520. begin
  521. if side=calleeside then
  522. begin
  523. paraloc^.size:=OS_32;
  524. paraloc^.def:=u32inttype;
  525. end;
  526. end;
  527. {$endif llvm}
  528. end;
  529. { in case it's a composite, "The argument is passed as though
  530. it had been loaded into the registers from a double-word-
  531. aligned address with an appropriate sequence of LDR
  532. instructions loading consecutive registers from memory" ->
  533. in case of big endian, values in not completely filled
  534. registers must be shifted to the top bits }
  535. if (target_info.endian=endian_big) and
  536. not(paraloc^.size in [OS_64,OS_S64]) and
  537. (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then
  538. paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size])*8;
  539. end;
  540. LOC_MMREGISTER:
  541. begin
  542. paraloc^.register:=newreg(R_MMREGISTER,curmmreg,cgsize2subreg(R_MMREGISTER,paraloc^.size));
  543. inc(curmmreg);
  544. dec(paralen,tcgsize2size[paraloc^.size]);
  545. end;
  546. LOC_REFERENCE:
  547. begin
  548. paraloc^.size:=paracgsize;
  549. paraloc^.loc:=LOC_REFERENCE;
  550. if assigned(hfabasedef) then
  551. paraloc^.def:=carraydef.getreusable_no_free(hfabasedef,paralen div hfabasedef.size)
  552. else
  553. paraloc^.def:=paradef;
  554. { the current stack offset may not be properly aligned in
  555. case we're on Darwin and have allocated a non-variadic argument
  556. < 8 bytes previously }
  557. if target_info.abi=abi_aarch64_darwin then
  558. begin
  559. curstackoffset:=align(curstackoffset,paraloc^.def.alignment);
  560. if firstparaloc then
  561. result.alignment:=newalignment(result.alignment,curstackoffset);
  562. end;
  563. { on Darwin, non-variadic arguments take up their actual size
  564. on the stack; on other platforms, they take up a multiple of
  565. 8 bytes }
  566. if (target_info.abi=abi_aarch64_darwin) and
  567. not isvariadic then
  568. stackslotlen:=paralen
  569. else
  570. stackslotlen:=align(paralen,8);
  571. { from the ABI: if arguments occupy partial stack space, they
  572. have to occupy the lowest significant bits of a register
  573. containing that value which is then stored to memory ->
  574. in case of big endian, skip the alignment bytes (if any) }
  575. if target_info.endian=endian_little then
  576. paraloc^.reference.offset:=curstackoffset
  577. else
  578. paraloc^.reference.offset:=curstackoffset+stackslotlen-paralen;
  579. if side=callerside then
  580. paraloc^.reference.index:=NR_STACK_POINTER_REG
  581. else
  582. begin
  583. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  584. inc(paraloc^.reference.offset,16);
  585. end;
  586. inc(curstackoffset,stackslotlen);
  587. paralen:=0
  588. end;
  589. else
  590. internalerror(2002071002);
  591. end;
  592. firstparaloc:=false;
  593. { <=0 for sign/zero-extended locations }
  594. until paralen<=0;
  595. end;
  596. function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;
  597. begin
  598. init_para_alloc_values;
  599. create_paraloc_info_intern(p,side,p.paras,false);
  600. result:=curstackoffset;
  601. create_funcretloc_info(p,side);
  602. end;
  603. function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist):longint;
  604. begin
  605. init_para_alloc_values;
  606. { non-variadic parameters }
  607. create_paraloc_info_intern(p,side,p.paras,false);
  608. if p.proccalloption in cstylearrayofconst then
  609. begin
  610. { on Darwin, we cannot use any registers for variadic parameters }
  611. if target_info.abi=abi_aarch64_darwin then
  612. begin
  613. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  614. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  615. end;
  616. { continue loading the parameters }
  617. if assigned(varargspara) then
  618. begin
  619. if side=callerside then
  620. create_paraloc_info_intern(p,side,varargspara,true)
  621. else
  622. internalerror(2019021916);
  623. end;
  624. result:=curstackoffset;
  625. end
  626. else
  627. internalerror(2004102303);
  628. create_funcretloc_info(p,side);
  629. end;
  630. begin
  631. paramanager:=tcpuparamanager.create;
  632. end.