cpupara.pas 27 KB

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