cpupara.pas 29 KB

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