cpupara.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. PowerPC 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. unit cpupara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmtai,aasmdata,
  23. cpubase,
  24. symconst,symtype,symdef,symsym,
  25. paramgr,parabase,cgbase,cgutils;
  26. type
  27. tcpuparamanager = class(tparamanager)
  28. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  29. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  30. function get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;override;
  31. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  32. procedure getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
  33. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  34. function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
  35. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  36. private
  37. procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
  38. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
  39. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
  40. function parseparaloc(p : tparavarsym;const s : string) : boolean;override;
  41. end;
  42. implementation
  43. uses
  44. verbose,systems,
  45. defutil,symtable,
  46. procinfo,cpupi;
  47. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  48. begin
  49. if (target_info.system = system_powerpc_darwin) then
  50. result := [RS_R0,RS_R2..RS_R12]
  51. else
  52. result := [RS_R0,RS_R3..RS_R12];
  53. end;
  54. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  55. begin
  56. case target_info.abi of
  57. abi_powerpc_aix,
  58. abi_powerpc_darwin,
  59. abi_powerpc_sysv:
  60. result := [RS_F0..RS_F13];
  61. else
  62. internalerror(2003091401);
  63. end;
  64. end;
  65. function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;
  66. const
  67. saved_regs : array[0..18] of tsuperregister = (
  68. RS_R13,RS_R14,RS_R15,RS_R16,RS_R17,RS_R18,RS_R19,
  69. RS_R20,RS_R21,RS_R22,RS_R23,RS_R24,RS_R25,RS_R26,RS_R27,RS_R28,RS_R29,
  70. RS_R30,RS_R31
  71. );
  72. begin
  73. result:=saved_regs;
  74. end;
  75. procedure tcpuparamanager.getintparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  76. var
  77. paraloc : pcgparalocation;
  78. psym : tparavarsym;
  79. pdef : tdef;
  80. begin
  81. psym:=tparavarsym(pd.paras[nr-1]);
  82. pdef:=psym.vardef;
  83. if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
  84. pdef:=cpointerdef.getreusable_no_free(pdef);
  85. cgpara.reset;
  86. cgpara.size:=def_cgsize(pdef);
  87. cgpara.intsize:=tcgsize2size[cgpara.size];
  88. cgpara.alignment:=get_para_align(pd.proccalloption);
  89. cgpara.def:=pdef;
  90. paraloc:=cgpara.add_location;
  91. with paraloc^ do
  92. begin
  93. size:=def_cgsize(pdef);
  94. def:=pdef;
  95. if (nr<=8) then
  96. begin
  97. if nr=0 then
  98. internalerror(200309271);
  99. loc:=LOC_REGISTER;
  100. register:=newreg(R_INTREGISTER,RS_R2+nr,R_SUBWHOLE);
  101. end
  102. else
  103. begin
  104. loc:=LOC_REFERENCE;
  105. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  106. if not(target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) then
  107. reference.offset:=sizeof(pint)*(nr-8)
  108. else
  109. reference.offset:=sizeof(pint)*(nr);
  110. end;
  111. end;
  112. end;
  113. function getparaloc(p : tdef) : tcgloc;
  114. begin
  115. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  116. if push_addr_param for the def is true
  117. }
  118. case p.typ of
  119. orddef:
  120. result:=LOC_REGISTER;
  121. floatdef:
  122. result:=LOC_FPUREGISTER;
  123. enumdef:
  124. result:=LOC_REGISTER;
  125. pointerdef:
  126. result:=LOC_REGISTER;
  127. formaldef:
  128. result:=LOC_REGISTER;
  129. classrefdef:
  130. result:=LOC_REGISTER;
  131. procvardef:
  132. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) or
  133. (p.size = sizeof(pint)) then
  134. result:=LOC_REGISTER
  135. else
  136. result:=LOC_REFERENCE;
  137. recorddef:
  138. if not(target_info.system in systems_aix) and
  139. (not(target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) or
  140. ((p.size >= 3) and
  141. ((p.size mod 4) <> 0))) then
  142. result:=LOC_REFERENCE
  143. else
  144. result:=LOC_REGISTER;
  145. objectdef:
  146. if is_object(p) then
  147. result:=LOC_REFERENCE
  148. else
  149. result:=LOC_REGISTER;
  150. stringdef:
  151. if is_shortstring(p) or is_longstring(p) then
  152. result:=LOC_REFERENCE
  153. else
  154. result:=LOC_REGISTER;
  155. filedef:
  156. result:=LOC_REGISTER;
  157. arraydef:
  158. if is_dynamic_array(p) then
  159. getparaloc:=LOC_REGISTER
  160. else
  161. result:=LOC_REFERENCE;
  162. setdef:
  163. if is_smallset(p) then
  164. result:=LOC_REGISTER
  165. else
  166. result:=LOC_REFERENCE;
  167. variantdef:
  168. result:=LOC_REFERENCE;
  169. { avoid problems with errornous definitions }
  170. errordef:
  171. result:=LOC_REGISTER;
  172. else
  173. internalerror(2002071001);
  174. end;
  175. end;
  176. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  177. begin
  178. result:=false;
  179. { var,out,constref always require address }
  180. if varspez in [vs_var,vs_out,vs_constref] then
  181. begin
  182. result:=true;
  183. exit;
  184. end;
  185. case def.typ of
  186. variantdef,
  187. formaldef :
  188. result:=true;
  189. { regular procvars must be passed by value, because you cannot pass
  190. the address of a local stack location when calling e.g.
  191. pthread_create with the address of a function (first of all it
  192. expects the address of the function to execute and not the address
  193. of a memory location containing that address, and secondly if you
  194. first store the address on the stack and then pass the address of
  195. this stack location, then this stack location may no longer be
  196. valid when the newly started thread accesses it.
  197. However, for "procedure of object" we must use the same calling
  198. convention as for "8 byte record" due to the need for
  199. interchangeability with the TMethod record type.
  200. }
  201. procvardef :
  202. result:=
  203. not(target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  204. (def.size <> sizeof(pint));
  205. recorddef :
  206. result :=
  207. not(target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) or
  208. ((varspez = vs_const) and
  209. ((calloption = pocall_mwpascal) or
  210. (not (calloption in cdecl_pocalls) and
  211. (def.size > 8)
  212. )
  213. )
  214. );
  215. arraydef:
  216. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  217. is_open_array(def) or
  218. is_array_of_const(def) or
  219. is_array_constructor(def);
  220. objectdef :
  221. result:=is_object(def);
  222. setdef :
  223. result:=not is_smallset(def);
  224. stringdef :
  225. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  226. end;
  227. end;
  228. procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
  229. begin
  230. case target_info.abi of
  231. abi_powerpc_aix,
  232. abi_powerpc_darwin:
  233. cur_stack_offset:=24;
  234. abi_powerpc_sysv:
  235. cur_stack_offset:=8;
  236. else
  237. internalerror(2003051901);
  238. end;
  239. curintreg:=RS_R3;
  240. curfloatreg:=RS_F1;
  241. curmmreg:=RS_M1;
  242. end;
  243. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  244. var
  245. paraloc : pcgparalocation;
  246. retcgsize : tcgsize;
  247. begin
  248. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  249. exit;
  250. paraloc:=result.add_location;
  251. { Return in FPU register? }
  252. if result.def.typ=floatdef then
  253. begin
  254. paraloc^.loc:=LOC_FPUREGISTER;
  255. paraloc^.register:=NR_FPU_RESULT_REG;
  256. paraloc^.size:=retcgsize;
  257. paraloc^.def:=result.def;
  258. end
  259. else
  260. { Return in register }
  261. begin
  262. if retcgsize in [OS_64,OS_S64] then
  263. begin
  264. { low 32bits }
  265. paraloc^.loc:=LOC_REGISTER;
  266. if side=callerside then
  267. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  268. else
  269. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  270. paraloc^.size:=OS_32;
  271. paraloc^.def:=u32inttype;
  272. { high 32bits }
  273. paraloc:=result.add_location;
  274. paraloc^.loc:=LOC_REGISTER;
  275. if side=callerside then
  276. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  277. else
  278. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  279. paraloc^.size:=OS_32;
  280. paraloc^.def:=u32inttype;
  281. end
  282. else
  283. begin
  284. paraloc^.loc:=LOC_REGISTER;
  285. if side=callerside then
  286. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  287. else
  288. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  289. paraloc^.size:=retcgsize;
  290. paraloc^.def:=result.def;
  291. end;
  292. end;
  293. end;
  294. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  295. var
  296. cur_stack_offset: aword;
  297. curintreg, curfloatreg, curmmreg: tsuperregister;
  298. begin
  299. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  300. result := create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,false);
  301. create_funcretloc_info(p,side);
  302. end;
  303. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
  304. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
  305. var
  306. stack_offset: longint;
  307. paralen: aint;
  308. nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
  309. locdef,
  310. fdef,
  311. paradef : tdef;
  312. paraloc : pcgparalocation;
  313. i : integer;
  314. hp : tparavarsym;
  315. loc : tcgloc;
  316. paracgsize: tcgsize;
  317. firstparaloc: boolean;
  318. begin
  319. {$ifdef extdebug}
  320. if po_explicitparaloc in p.procoptions then
  321. internalerror(200411141);
  322. {$endif extdebug}
  323. result:=0;
  324. nextintreg := curintreg;
  325. nextfloatreg := curfloatreg;
  326. nextmmreg := curmmreg;
  327. stack_offset := cur_stack_offset;
  328. case target_info.abi of
  329. abi_powerpc_aix,
  330. abi_powerpc_darwin:
  331. maxfpureg := RS_F13;
  332. abi_powerpc_sysv:
  333. maxfpureg := RS_F8;
  334. else internalerror(2004070912);
  335. end;
  336. for i:=0 to paras.count-1 do
  337. begin
  338. hp:=tparavarsym(paras[i]);
  339. paradef := hp.vardef;
  340. { Syscall for Morphos can have already a paraloc set }
  341. if (vo_has_explicit_paraloc in hp.varoptions) then
  342. continue;
  343. hp.paraloc[side].reset;
  344. { currently only support C-style array of const }
  345. if (p.proccalloption in cstylearrayofconst) and
  346. is_array_of_const(paradef) then
  347. begin
  348. paraloc:=hp.paraloc[side].add_location;
  349. { hack: the paraloc must be valid, but is not actually used }
  350. paraloc^.loc := LOC_REGISTER;
  351. paraloc^.register := NR_R0;
  352. paraloc^.size := OS_ADDR;
  353. paraloc^.def:=voidpointertype;
  354. break;
  355. end;
  356. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  357. begin
  358. paradef:=cpointerdef.getreusable_no_free(paradef);
  359. loc:=LOC_REGISTER;
  360. paracgsize := OS_ADDR;
  361. paralen := tcgsize2size[OS_ADDR];
  362. end
  363. else
  364. begin
  365. if not is_special_array(paradef) then
  366. paralen := paradef.size
  367. else
  368. paralen := tcgsize2size[def_cgsize(paradef)];
  369. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  370. (paradef.typ = recorddef) and
  371. (hp.varspez in [vs_value,vs_const]) then
  372. begin
  373. { if a record has only one field and that field is }
  374. { non-composite (not array or record), it must be }
  375. { passed according to the rules of that type. }
  376. if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and
  377. ((fdef.typ=floatdef) or
  378. ((target_info.system=system_powerpc_darwin) and
  379. (fdef.typ in [orddef,enumdef]))) then
  380. begin
  381. paradef:=fdef;
  382. paracgsize:=def_cgsize(paradef);
  383. end
  384. else
  385. begin
  386. paracgsize := int_cgsize(paralen);
  387. end;
  388. end
  389. else
  390. begin
  391. paracgsize:=def_cgsize(paradef);
  392. { for things like formaldef }
  393. if (paracgsize=OS_NO) then
  394. begin
  395. paracgsize:=OS_ADDR;
  396. paralen := tcgsize2size[OS_ADDR];
  397. end;
  398. end
  399. end;
  400. loc := getparaloc(paradef);
  401. if varargsparas and
  402. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  403. (paradef.typ = floatdef) then
  404. begin
  405. loc := LOC_REGISTER;
  406. if paracgsize=OS_F64 then
  407. begin
  408. paracgsize:=OS_64;
  409. paradef:=u64inttype;
  410. end
  411. else
  412. begin
  413. paracgsize:=OS_32;
  414. paradef:=u32inttype;
  415. end;
  416. end;
  417. hp.paraloc[side].alignment:=std_param_align;
  418. hp.paraloc[side].size:=paracgsize;
  419. hp.paraloc[side].intsize:=paralen;
  420. hp.paraloc[side].def:=paradef;
  421. {$ifndef cpu64bitaddr}
  422. if (target_info.abi=abi_powerpc_sysv) and
  423. is_64bit(paradef) and
  424. odd(nextintreg-RS_R3) then
  425. inc(nextintreg);
  426. {$endif not cpu64bitaddr}
  427. if (paralen = 0) then
  428. if (paradef.typ = recorddef) then
  429. begin
  430. paraloc:=hp.paraloc[side].add_location;
  431. paraloc^.loc := LOC_VOID;
  432. end
  433. else
  434. internalerror(2005011310);
  435. locdef:=paradef;
  436. firstparaloc:=true;
  437. { can become < 0 for e.g. 3-byte records }
  438. while (paralen > 0) do
  439. begin
  440. paraloc:=hp.paraloc[side].add_location;
  441. { In case of po_delphi_nested_cc, the parent frame pointer
  442. is always passed on the stack. }
  443. if (loc = LOC_REGISTER) and
  444. (nextintreg <= RS_R10) and
  445. (not(vo_is_parentfp in hp.varoptions) or
  446. not(po_delphi_nested_cc in p.procoptions)) then
  447. begin
  448. paraloc^.loc := loc;
  449. { make sure we don't lose whether or not the type is signed }
  450. if (paradef.typ<>orddef) then
  451. begin
  452. paracgsize:=int_cgsize(paralen);
  453. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  454. end;
  455. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  456. begin
  457. paraloc^.size:=OS_INT;
  458. paraloc^.def:=u32inttype;
  459. end
  460. else
  461. begin
  462. paraloc^.size:=paracgsize;
  463. paraloc^.def:=locdef;
  464. end;
  465. { aix requires that record data stored in parameter
  466. registers is left-aligned }
  467. if (target_info.system in systems_aix) and
  468. (paradef.typ = recorddef) and
  469. (paralen < sizeof(aint)) then
  470. begin
  471. paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
  472. paraloc^.size := OS_INT;
  473. paraloc^.def := u32inttype;
  474. end;
  475. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  476. inc(nextintreg);
  477. dec(paralen,tcgsize2size[paraloc^.size]);
  478. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  479. inc(stack_offset,align(tcgsize2size[paraloc^.size],4));
  480. end
  481. else if (loc = LOC_FPUREGISTER) and
  482. (nextfloatreg <= maxfpureg) then
  483. begin
  484. paraloc^.loc:=loc;
  485. paraloc^.size := paracgsize;
  486. paraloc^.def := paradef;
  487. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  488. inc(nextfloatreg);
  489. dec(paralen,tcgsize2size[paraloc^.size]);
  490. { if nextfpureg > maxfpureg, all intregs are already used, since there }
  491. { are less of those available for parameter passing in the AIX abi }
  492. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  493. {$ifndef cpu64bitaddr}
  494. if (paracgsize = OS_F32) then
  495. begin
  496. inc(stack_offset,4);
  497. if (nextintreg < RS_R11) then
  498. inc(nextintreg);
  499. end
  500. else
  501. begin
  502. inc(stack_offset,8);
  503. if (nextintreg < RS_R10) then
  504. inc(nextintreg,2)
  505. else
  506. nextintreg := RS_R11;
  507. end;
  508. {$else not cpu64bitaddr}
  509. begin
  510. inc(stack_offset,tcgsize2size[paracgsize]);
  511. if (nextintreg < RS_R11) then
  512. inc(nextintreg);
  513. end;
  514. {$endif not cpu64bitaddr}
  515. end
  516. else { LOC_REFERENCE }
  517. begin
  518. paraloc^.loc:=LOC_REFERENCE;
  519. case loc of
  520. LOC_FPUREGISTER:
  521. begin
  522. paraloc^.size:=int_float_cgsize(paralen);
  523. case paraloc^.size of
  524. OS_F32: paraloc^.def:=s32floattype;
  525. OS_F64: paraloc^.def:=s64floattype;
  526. else
  527. internalerror(2013060124);
  528. end;
  529. end;
  530. LOC_REGISTER,
  531. LOC_REFERENCE:
  532. begin
  533. paraloc^.size:=int_cgsize(paralen);
  534. if paraloc^.size<>OS_NO then
  535. paraloc^.def:=cgsize_orddef(paraloc^.size)
  536. else
  537. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  538. end;
  539. else
  540. internalerror(2006011101);
  541. end;
  542. if (side = callerside) then
  543. paraloc^.reference.index:=NR_STACK_POINTER_REG
  544. else
  545. begin
  546. paraloc^.reference.index:=NR_R12;
  547. { create_paraloc_info_intern might be also called when being outside of
  548. code generation so current_procinfo might be not set }
  549. if assigned(current_procinfo) then
  550. tcpuprocinfo(current_procinfo).needs_frame_pointer := true;
  551. end;
  552. if not((target_info.system in systems_aix) and
  553. (paradef.typ=recorddef)) and
  554. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  555. (hp.paraloc[side].intsize < 3) then
  556. paraloc^.reference.offset:=stack_offset+(4-paralen)
  557. else
  558. paraloc^.reference.offset:=stack_offset;
  559. inc(stack_offset,align(paralen,4));
  560. while (paralen > 0) and
  561. (nextintreg < RS_R11) do
  562. begin
  563. inc(nextintreg);
  564. dec(paralen,sizeof(pint));
  565. end;
  566. paralen := 0;
  567. end;
  568. firstparaloc:=false;
  569. end;
  570. end;
  571. curintreg:=nextintreg;
  572. curfloatreg:=nextfloatreg;
  573. curmmreg:=nextmmreg;
  574. cur_stack_offset:=stack_offset;
  575. result:=stack_offset;
  576. end;
  577. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  578. var
  579. cur_stack_offset: aword;
  580. parasize, l: longint;
  581. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  582. i : integer;
  583. hp: tparavarsym;
  584. paraloc: pcgparalocation;
  585. begin
  586. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  587. firstfloatreg:=curfloatreg;
  588. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
  589. if (p.proccalloption in cstylearrayofconst) then
  590. { just continue loading the parameters in the registers }
  591. begin
  592. if assigned(varargspara) then
  593. begin
  594. if side=callerside then
  595. result:=create_paraloc_info_intern(p,side,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true)
  596. else
  597. internalerror(2019021921);
  598. end;
  599. { varargs routines have to reserve at least 32 bytes for the AIX abi }
  600. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  601. (result < 32) then
  602. result := 32;
  603. end
  604. else
  605. internalerror(2019021710);
  606. if curfloatreg<>firstfloatreg then
  607. include(varargspara.varargsinfo,va_uses_float_reg);
  608. create_funcretloc_info(p,side);
  609. end;
  610. function tcpuparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  611. var
  612. paraloc : pcgparalocation;
  613. paracgsize : tcgsize;
  614. offset : aint;
  615. begin
  616. result:=false;
  617. offset:=-1;
  618. case target_info.system of
  619. system_powerpc_morphos:
  620. begin
  621. paracgsize:=def_cgsize(p.vardef);
  622. p.paraloc[callerside].alignment:=4;
  623. p.paraloc[callerside].size:=paracgsize;
  624. p.paraloc[callerside].intsize:=tcgsize2size[paracgsize];
  625. paraloc:=p.paraloc[callerside].add_location;
  626. { The OS side should be zero extended and the entire "virtual"
  627. 68k register should be overwritten. This is what the C ppcinline
  628. macros do as well, by casting all arguments to ULONG. A call
  629. which breaks w/o this is for example exec/RawPutChar (KB) }
  630. paraloc^.size:=OS_ADDR;
  631. paraloc^.def:=p.vardef;
  632. { convert d0-d7/a0-a6 virtual 68k reg patterns into offsets }
  633. if length(s) = 2 then
  634. begin
  635. if (lowercase(s[1]) = 'd') and (s[2] in ['0'..'7']) then
  636. offset:=(ord(s[2]) - ord('0')) * sizeof(pint)
  637. else if (lowercase(s[1]) = 'a') and (s[2] in ['0'..'6']) then
  638. offset:=(ord(s[2]) - ord('0') + 8) * sizeof(pint);
  639. if offset < 0 then
  640. exit;
  641. paraloc^.loc:=LOC_REFERENCE;
  642. paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
  643. paraloc^.reference.offset:=offset;
  644. end
  645. { 'R12' is special, used internally to support regbase and nobase
  646. calling convention }
  647. else if lowercase(s)='r12' then
  648. begin
  649. paraloc^.loc:=LOC_REGISTER;
  650. paraloc^.register:=NR_R12;
  651. end
  652. else
  653. exit;
  654. { copy to callee side }
  655. p.paraloc[calleeside].add_location^:=paraloc^;
  656. end;
  657. else
  658. internalerror(200404182);
  659. end;
  660. result:=true;
  661. end;
  662. begin
  663. paramanager:=tcpuparamanager.create;
  664. end.