cpupara.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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;
  27. type
  28. tcpuparamanager = class(tparamanager)
  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 push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  33. function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override;
  34. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;override;
  35. function create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;override;
  36. function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  37. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  38. private
  39. curintreg,
  40. curmmreg: tsuperregister;
  41. curstackoffset: aword;
  42. procedure init_para_alloc_values;
  43. procedure alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  44. procedure create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  45. end;
  46. implementation
  47. uses
  48. verbose,systems,cutils,
  49. rgobj,
  50. defutil,symsym,symtable;
  51. const
  52. RS_FIRST_INT_PARAM_SUPREG = RS_X0;
  53. RS_LAST_INT_PARAM_SUPREG = RS_X7;
  54. { Q0/D0/S0/H0/B0 all have the same superregister number }
  55. RS_FIRST_MM_PARAM_SUPREG = RS_D0;
  56. RS_LAST_MM_PARAM_SUPREG = RS_D7;
  57. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  58. begin
  59. result:=VOLATILE_INTREGISTERS
  60. end;
  61. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  62. begin
  63. result:=[];
  64. end;
  65. function tcpuparamanager.get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset;
  66. begin
  67. result:=VOLATILE_MMREGISTERS;
  68. end;
  69. function is_hfa_internal(p: tdef; var basedef: tdef; var elecount: longint): boolean;
  70. var
  71. i: longint;
  72. sym: tsym;
  73. tmpelecount: longint;
  74. begin
  75. result:=false;
  76. case p.typ of
  77. arraydef:
  78. begin
  79. if is_special_array(p) then
  80. exit;
  81. case tarraydef(p).elementdef.typ of
  82. floatdef:
  83. begin
  84. { an array of empty records has no influence }
  85. if tarraydef(p).elementdef.size=0 then
  86. begin
  87. result:=true;
  88. exit
  89. end;
  90. tmpelecount:=0;
  91. if not is_hfa_internal(tarraydef(p).elementdef,basedef,tmpelecount) then
  92. exit;
  93. { tmpelecount now contains the number of hfa elements in a
  94. single array element (e.g. 2 if it's an array of a record
  95. containing two singles) -> multiply by number of elements
  96. in the array }
  97. inc(elecount,tarraydef(p).elecount*tmpelecount);
  98. if elecount>4 then
  99. exit;
  100. end;
  101. else
  102. result:=is_hfa_internal(tarraydef(p).elementdef,basedef,elecount);
  103. end;
  104. end;
  105. floatdef:
  106. begin
  107. if not assigned(basedef) then
  108. basedef:=p
  109. else if basedef<>p then
  110. exit;
  111. inc(elecount);
  112. result:=true;
  113. end;
  114. recorddef:
  115. begin
  116. for i:=0 to tabstractrecorddef(p).symtable.symlist.count-1 do
  117. begin
  118. sym:=tsym(tabstractrecorddef(p).symtable.symlist[i]);
  119. if sym.typ<>fieldvarsym then
  120. continue;
  121. if not is_hfa_internal(tfieldvarsym(sym).vardef,basedef,elecount) then
  122. exit
  123. end;
  124. result:=true;
  125. end;
  126. else
  127. exit
  128. end;
  129. end;
  130. { Returns whether a def is a "homogeneous float array" at the machine level.
  131. This means that in the memory layout, the def only consists of maximally
  132. 4 floating point values that appear consecutively in memory }
  133. function is_hfa(p: tdef; out basedef: tdef) : boolean;
  134. var
  135. elecount: longint;
  136. begin
  137. result:=false;
  138. basedef:=nil;
  139. elecount:=0;
  140. result:=is_hfa_internal(p,basedef,elecount);
  141. result:=
  142. result and
  143. (elecount>0) and
  144. (elecount<=4) and
  145. (p.size=basedef.size*elecount)
  146. end;
  147. function getparaloc(calloption: tproccalloption; p: tdef): tcgloc;
  148. var
  149. hfabasedef: tdef;
  150. begin
  151. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  152. if push_addr_param for the def is true
  153. }
  154. case p.typ of
  155. orddef:
  156. getparaloc:=LOC_REGISTER;
  157. floatdef:
  158. getparaloc:=LOC_MMREGISTER;
  159. enumdef:
  160. getparaloc:=LOC_REGISTER;
  161. pointerdef:
  162. getparaloc:=LOC_REGISTER;
  163. formaldef:
  164. getparaloc:=LOC_REGISTER;
  165. classrefdef:
  166. getparaloc:=LOC_REGISTER;
  167. recorddef:
  168. if not is_hfa(p,hfabasedef) then
  169. getparaloc:=LOC_REGISTER
  170. else
  171. getparaloc:=LOC_MMREGISTER;
  172. objectdef:
  173. getparaloc:=LOC_REGISTER;
  174. stringdef:
  175. if is_shortstring(p) or is_longstring(p) then
  176. getparaloc:=LOC_REFERENCE
  177. else
  178. getparaloc:=LOC_REGISTER;
  179. procvardef:
  180. getparaloc:=LOC_REGISTER;
  181. filedef:
  182. getparaloc:=LOC_REGISTER;
  183. arraydef:
  184. if not is_hfa(p,hfabasedef) then
  185. getparaloc:=LOC_REGISTER
  186. else
  187. getparaloc:=LOC_MMREGISTER;
  188. setdef:
  189. getparaloc:=LOC_REGISTER;
  190. variantdef:
  191. getparaloc:=LOC_REGISTER;
  192. { avoid problems with errornous definitions }
  193. errordef:
  194. getparaloc:=LOC_REGISTER;
  195. else
  196. internalerror(2002071001);
  197. end;
  198. end;
  199. function tcpuparamanager.push_addr_param(varspez: tvarspez; def :tdef; calloption: tproccalloption): boolean;
  200. var
  201. hfabasedef: tdef;
  202. begin
  203. result:=false;
  204. if varspez in [vs_var,vs_out,vs_constref] then
  205. begin
  206. result:=true;
  207. exit;
  208. end;
  209. case def.typ of
  210. objectdef:
  211. result:=is_object(def);
  212. recorddef:
  213. { ABI: any composite > 16 bytes that not a hfa/hva
  214. Special case: MWPascal, which passes all const parameters by
  215. reference for compatibility reasons
  216. }
  217. result:=
  218. ((varspez=vs_const) and
  219. (calloption=pocall_mwpascal)) or
  220. (not is_hfa(def,hfabasedef) and
  221. (def.size>16));
  222. variantdef,
  223. formaldef:
  224. result:=true;
  225. { arrays are composites and hence treated the same as records by the
  226. ABI (watch out for C, where an array is a pointer)
  227. Also: all other platforms pass const arrays by reference. Do the
  228. same here, because there is too much hacky code out there that
  229. relies on this ("array[0..0] of x" passed as const parameter and
  230. then indexed beyond its bounds) }
  231. arraydef:
  232. result:=
  233. (calloption in cdecl_pocalls) or
  234. is_open_array(def) or
  235. is_array_of_const(def) or
  236. is_array_constructor(def) or
  237. ((tarraydef(def).highrange>=tarraydef(def).lowrange) and
  238. ((varspez=vs_const) or
  239. (not is_hfa(def,hfabasedef) and
  240. (def.size>16))));
  241. setdef :
  242. result:=def.size>16;
  243. stringdef :
  244. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  245. end;
  246. end;
  247. function tcpuparamanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean;
  248. begin
  249. if handle_common_ret_in_param(def,pd,result) then
  250. exit;
  251. { ABI: if the parameter would be passed in registers, it is returned
  252. in those registers; otherwise, it's returned by reference }
  253. result:=push_addr_param(vs_value,def,pd.proccalloption);
  254. end;
  255. procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
  256. var
  257. hp: tparavarsym;
  258. i: longint;
  259. begin
  260. for i:=0 to paras.count-1 do
  261. begin
  262. hp:=tparavarsym(paras[i]);
  263. { hidden function result parameter is passed in X8 (doesn't have to
  264. be valid on return) according to the ABI
  265. -- don't follow the ABI for managed types, because
  266. a) they are passed in registers as parameters, so we should also
  267. return them in a register to be ABI-compliant (which we can't
  268. because the entire compiler is built around the idea that
  269. they are returned by reference, for ref-counting performance
  270. and Delphi-compatibility reasons)
  271. b) there are hacks in the system unit that expect that you can
  272. call
  273. function f: com_interface;
  274. as
  275. procedure p(out o: obj);
  276. That can only work in case we do not use x8 to return them
  277. from the function, but the regular first parameter register.
  278. As the ABI says this behaviour is ok for C++ classes with a
  279. non-trivial copy constructor or destructor, it seems reasonable
  280. for us to do this for managed types as well.}
  281. if (vo_is_funcret in hp.varoptions) and
  282. not is_managed_type(hp.vardef) then
  283. begin
  284. hp.paraloc[side].reset;
  285. hp.paraloc[side].size:=OS_ADDR;
  286. hp.paraloc[side].alignment:=voidpointertype.alignment;
  287. hp.paraloc[side].intsize:=voidpointertype.size;
  288. hp.paraloc[side].def:=cpointerdef.getreusable(hp.vardef);
  289. with hp.paraloc[side].add_location^ do
  290. begin
  291. size:=OS_ADDR;
  292. def:=hp.paraloc[side].def;
  293. loc:=LOC_REGISTER;
  294. register:=NR_X8;
  295. end
  296. end
  297. else
  298. alloc_para(hp.paraloc[side],p,hp.varspez,side,hp.vardef,isvariadic,
  299. (vo_is_parentfp in hp.varoptions) and
  300. (po_delphi_nested_cc in p.procoptions));
  301. end;
  302. end;
  303. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  304. var
  305. retcgsize: tcgsize;
  306. begin
  307. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  308. exit;
  309. { in this case, it must be returned in registers as if it were passed
  310. as the first parameter }
  311. init_para_alloc_values;
  312. alloc_para(result,p,vs_value,side,result.def,false,false);
  313. { sanity check (LOC_VOID for empty records) }
  314. if not assigned(result.location) or
  315. not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then
  316. internalerror(2014113001);
  317. end;
  318. function tcpuparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  319. begin
  320. { we always set up a stack frame -> we can always access the parameters
  321. this way }
  322. result:=
  323. (cgpara.location^.loc=LOC_REFERENCE) and
  324. not assigned(cgpara.location^.next);
  325. end;
  326. procedure tcpuparamanager.init_para_alloc_values;
  327. begin
  328. curintreg:=RS_FIRST_INT_PARAM_SUPREG;
  329. curmmreg:=RS_FIRST_MM_PARAM_SUPREG;
  330. curstackoffset:=0;
  331. end;
  332. procedure tcpuparamanager.alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
  333. var
  334. hfabasedef, locdef: tdef;
  335. paraloc: pcgparalocation;
  336. paralen, stackslotlen: asizeint;
  337. loc: tcgloc;
  338. paracgsize, locsize: tcgsize;
  339. firstparaloc: boolean;
  340. begin
  341. result.reset;
  342. { currently only support C-style array of const,
  343. there should be no location assigned to the vararg array itself }
  344. if (p.proccalloption in cstylearrayofconst) and
  345. is_array_of_const(paradef) then
  346. begin
  347. paraloc:=result.add_location;
  348. { hack: the paraloc must be valid, but is not actually used }
  349. paraloc^.loc:=LOC_REGISTER;
  350. paraloc^.register:=NR_X0;
  351. paraloc^.size:=OS_ADDR;
  352. exit;
  353. end;
  354. if push_addr_param(varspez,paradef,p.proccalloption) then
  355. begin
  356. paradef:=cpointerdef.getreusable(paradef);
  357. loc:=LOC_REGISTER;
  358. paracgsize:=OS_ADDR;
  359. paralen:=tcgsize2size[OS_ADDR];
  360. end
  361. else
  362. begin
  363. if not is_special_array(paradef) then
  364. paralen:=paradef.size
  365. else
  366. paralen:=tcgsize2size[def_cgsize(paradef)];
  367. loc:=getparaloc(p.proccalloption,paradef);
  368. if (paradef.typ in [objectdef,arraydef,recorddef]) and
  369. not is_special_array(paradef) and
  370. (varspez in [vs_value,vs_const]) then
  371. paracgsize:=int_cgsize(paralen)
  372. else
  373. begin
  374. paracgsize:=def_cgsize(paradef);
  375. { for things like formaldef }
  376. if paracgsize=OS_NO then
  377. begin
  378. paracgsize:=OS_ADDR;
  379. paralen:=tcgsize2size[OS_ADDR];
  380. paradef:=voidpointertype;
  381. end;
  382. end
  383. end;
  384. { get hfa basedef if applicable }
  385. if not is_hfa(paradef,hfabasedef) then
  386. hfabasedef:=nil;
  387. result.size:=paracgsize;
  388. result.alignment:=std_param_align;
  389. result.intsize:=paralen;
  390. result.def:=paradef;
  391. { empty record: skipped (explicitly defined by Apple ABI, undefined
  392. by general ABI; libffi also skips them in all cases) }
  393. if not is_special_array(paradef) and
  394. (paradef.size=0) then
  395. begin
  396. paraloc:=result.add_location;
  397. paraloc^.loc:=LOC_VOID;
  398. paraloc^.def:=paradef;
  399. paraloc^.size:=OS_NO;
  400. exit;
  401. end;
  402. { sufficient registers left? }
  403. case loc of
  404. LOC_REGISTER:
  405. begin
  406. { In case of po_delphi_nested_cc, the parent frame pointer
  407. is always passed on the stack. }
  408. if isdelphinestedcc then
  409. loc:=LOC_REFERENCE
  410. else if curintreg+((paralen-1) shr 3)>RS_LAST_INT_PARAM_SUPREG then
  411. begin
  412. { not enough integer registers left -> no more register
  413. parameters, copy all to stack
  414. }
  415. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  416. loc:=LOC_REFERENCE;
  417. end;
  418. end;
  419. LOC_MMREGISTER:
  420. begin;
  421. { every hfa element must be passed in a separate register }
  422. if (assigned(hfabasedef) and
  423. (curmmreg+(paralen div hfabasedef.size)>RS_LAST_MM_PARAM_SUPREG)) or
  424. (curmmreg+((paralen-1) shr 3)>RS_LAST_MM_PARAM_SUPREG) then
  425. begin
  426. { not enough mm registers left -> no more register
  427. parameters, copy all to stack
  428. }
  429. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  430. loc:=LOC_REFERENCE;
  431. end;
  432. end;
  433. end;
  434. { allocate registers/stack locations }
  435. firstparaloc:=true;
  436. repeat
  437. paraloc:=result.add_location;
  438. { set paraloc size/def }
  439. if assigned(hfabasedef) then
  440. begin
  441. locsize:=def_cgsize(hfabasedef);
  442. locdef:=hfabasedef;
  443. end
  444. { make sure we don't lose whether or not the type is signed }
  445. else if (loc=LOC_REGISTER) and
  446. (paradef.typ<>orddef) then
  447. begin
  448. locsize:=int_cgsize(paralen);
  449. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  450. end
  451. else
  452. begin
  453. locsize:=paracgsize;
  454. locdef:=paradef;
  455. end;
  456. if locsize in [OS_NO,OS_128,OS_S128] then
  457. begin
  458. if paralen>4 then
  459. begin
  460. paraloc^.size:=OS_INT;
  461. paraloc^.def:=u64inttype;
  462. end
  463. else
  464. begin
  465. { for 3-byte records }
  466. paraloc^.size:=OS_32;
  467. paraloc^.def:=u32inttype;
  468. end;
  469. end
  470. else
  471. begin
  472. paraloc^.size:=locsize;
  473. paraloc^.def:=locdef;
  474. end;
  475. { paraloc loc }
  476. paraloc^.loc:=loc;
  477. { assign register/stack address }
  478. case loc of
  479. LOC_REGISTER:
  480. begin
  481. paraloc^.register:=newreg(R_INTREGISTER,curintreg,cgsize2subreg(R_INTREGISTER,paraloc^.size));
  482. inc(curintreg);
  483. dec(paralen,tcgsize2size[paraloc^.size]);
  484. { "The general ABI specifies that it is the callee's
  485. responsibility to sign or zero-extend arguments having fewer
  486. than 32 bits, and that unused bits in a register are
  487. unspecified. In iOS, however, the caller must perform such
  488. extensions, up to 32 bits." }
  489. if (target_info.abi=abi_aarch64_darwin) and
  490. (side=callerside) and
  491. is_ordinal(paradef) and
  492. (paradef.size<4) then
  493. paraloc^.size:=OS_32;
  494. { in case it's a composite, "The argument is passed as though
  495. it had been loaded into the registers from a double-word-
  496. aligned address with an appropriate sequence of LDR
  497. instructions loading consecutive registers from memory" ->
  498. in case of big endian, values in not completely filled
  499. registers must be shifted to the top bits }
  500. if (target_info.endian=endian_big) and
  501. not(paraloc^.size in [OS_64,OS_S64]) and
  502. (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then
  503. paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size]);
  504. end;
  505. LOC_MMREGISTER:
  506. begin
  507. paraloc^.register:=newreg(R_MMREGISTER,curmmreg,cgsize2subreg(R_MMREGISTER,paraloc^.size));
  508. inc(curmmreg);
  509. dec(paralen,tcgsize2size[paraloc^.size]);
  510. end;
  511. LOC_REFERENCE:
  512. begin
  513. paraloc^.size:=paracgsize;
  514. paraloc^.loc:=LOC_REFERENCE;
  515. { the current stack offset may not be properly aligned in
  516. case we're on Darwin have allocated a non-variadic argument
  517. < 8 bytes previously }
  518. if target_info.abi=abi_aarch64_darwin then
  519. curstackoffset:=align(curstackoffset,paraloc^.def.alignment);
  520. { on Darwin, non-variadic arguments take up their actual size
  521. on the stack; on other platforms, they take up a multiple of
  522. 8 bytes }
  523. if (target_info.abi=abi_aarch64_darwin) and
  524. not isvariadic then
  525. stackslotlen:=paralen
  526. else
  527. stackslotlen:=align(paralen,8);
  528. { from the ABI: if arguments occupy partial stack space, they
  529. have to occupy the lowest significant bits of a register
  530. containing that value which is then stored to memory ->
  531. in case of big endian, skip the alignment bytes (if any) }
  532. if target_info.endian=endian_little then
  533. paraloc^.reference.offset:=curstackoffset
  534. else
  535. paraloc^.reference.offset:=curstackoffset+stackslotlen-paralen;
  536. if side=callerside then
  537. paraloc^.reference.index:=NR_STACK_POINTER_REG
  538. else
  539. begin
  540. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  541. inc(paraloc^.reference.offset,16);
  542. end;
  543. inc(curstackoffset,stackslotlen);
  544. paralen:=0
  545. end;
  546. else
  547. internalerror(2002071002);
  548. end;
  549. firstparaloc:=false;
  550. { <=0 for sign/zero-extended locations }
  551. until paralen<=0;
  552. end;
  553. function tcpuparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;
  554. begin
  555. init_para_alloc_values;
  556. create_paraloc_info_intern(p,side,p.paras,false);
  557. result:=curstackoffset;
  558. create_funcretloc_info(p,side);
  559. end;
  560. function tcpuparamanager.create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;
  561. begin
  562. init_para_alloc_values;
  563. { non-variadic parameters }
  564. create_paraloc_info_intern(p,callerside,p.paras,false);
  565. if p.proccalloption in cstylearrayofconst then
  566. begin
  567. { on Darwin, we cannot use any registers for variadic parameters }
  568. if target_info.abi=abi_aarch64_darwin then
  569. begin
  570. curintreg:=succ(RS_LAST_INT_PARAM_SUPREG);
  571. curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG);
  572. end;
  573. { continue loading the parameters }
  574. create_paraloc_info_intern(p,callerside,varargspara,true);
  575. result:=curstackoffset;
  576. end
  577. else
  578. internalerror(200410231);
  579. end;
  580. begin
  581. paramanager:=tcpuparamanager.create;
  582. end.