cpupara.pas 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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; 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. begin
  343. if not(vo_is_syscall_lib in hp.varoptions) then
  344. internalerror(200412153);
  345. continue;
  346. end;
  347. hp.paraloc[side].reset;
  348. { currently only support C-style array of const }
  349. if (p.proccalloption in cstylearrayofconst) and
  350. is_array_of_const(paradef) then
  351. begin
  352. paraloc:=hp.paraloc[side].add_location;
  353. { hack: the paraloc must be valid, but is not actually used }
  354. paraloc^.loc := LOC_REGISTER;
  355. paraloc^.register := NR_R0;
  356. paraloc^.size := OS_ADDR;
  357. paraloc^.def:=voidpointertype;
  358. break;
  359. end;
  360. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  361. begin
  362. paradef:=cpointerdef.getreusable_no_free(paradef);
  363. loc:=LOC_REGISTER;
  364. paracgsize := OS_ADDR;
  365. paralen := tcgsize2size[OS_ADDR];
  366. end
  367. else
  368. begin
  369. if not is_special_array(paradef) then
  370. paralen := paradef.size
  371. else
  372. paralen := tcgsize2size[def_cgsize(paradef)];
  373. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  374. (paradef.typ = recorddef) and
  375. (hp.varspez in [vs_value,vs_const]) then
  376. begin
  377. { if a record has only one field and that field is }
  378. { non-composite (not array or record), it must be }
  379. { passed according to the rules of that type. }
  380. if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and
  381. ((fdef.typ=floatdef) or
  382. ((target_info.system=system_powerpc_darwin) and
  383. (fdef.typ in [orddef,enumdef]))) then
  384. begin
  385. paradef:=fdef;
  386. paracgsize:=def_cgsize(paradef);
  387. end
  388. else
  389. begin
  390. paracgsize := int_cgsize(paralen);
  391. end;
  392. end
  393. else
  394. begin
  395. paracgsize:=def_cgsize(paradef);
  396. { for things like formaldef }
  397. if (paracgsize=OS_NO) then
  398. begin
  399. paracgsize:=OS_ADDR;
  400. paralen := tcgsize2size[OS_ADDR];
  401. end;
  402. end
  403. end;
  404. loc := getparaloc(paradef);
  405. if varargsparas and
  406. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  407. (paradef.typ = floatdef) then
  408. begin
  409. loc := LOC_REGISTER;
  410. if paracgsize=OS_F64 then
  411. begin
  412. paracgsize:=OS_64;
  413. paradef:=u64inttype;
  414. end
  415. else
  416. begin
  417. paracgsize:=OS_32;
  418. paradef:=u32inttype;
  419. end;
  420. end;
  421. hp.paraloc[side].alignment:=std_param_align;
  422. hp.paraloc[side].size:=paracgsize;
  423. hp.paraloc[side].intsize:=paralen;
  424. hp.paraloc[side].def:=paradef;
  425. {$ifndef cpu64bitaddr}
  426. if (target_info.abi=abi_powerpc_sysv) and
  427. is_64bit(paradef) and
  428. odd(nextintreg-RS_R3) then
  429. inc(nextintreg);
  430. {$endif not cpu64bitaddr}
  431. if (paralen = 0) then
  432. if (paradef.typ = recorddef) then
  433. begin
  434. paraloc:=hp.paraloc[side].add_location;
  435. paraloc^.loc := LOC_VOID;
  436. end
  437. else
  438. internalerror(2005011310);
  439. locdef:=paradef;
  440. firstparaloc:=true;
  441. { can become < 0 for e.g. 3-byte records }
  442. while (paralen > 0) do
  443. begin
  444. paraloc:=hp.paraloc[side].add_location;
  445. { In case of po_delphi_nested_cc, the parent frame pointer
  446. is always passed on the stack. }
  447. if (loc = LOC_REGISTER) and
  448. (nextintreg <= RS_R10) and
  449. (not(vo_is_parentfp in hp.varoptions) or
  450. not(po_delphi_nested_cc in p.procoptions)) then
  451. begin
  452. paraloc^.loc := loc;
  453. { make sure we don't lose whether or not the type is signed }
  454. if (paradef.typ<>orddef) then
  455. begin
  456. paracgsize:=int_cgsize(paralen);
  457. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  458. end;
  459. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  460. begin
  461. paraloc^.size:=OS_INT;
  462. paraloc^.def:=u32inttype;
  463. end
  464. else
  465. begin
  466. paraloc^.size:=paracgsize;
  467. paraloc^.def:=locdef;
  468. end;
  469. { aix requires that record data stored in parameter
  470. registers is left-aligned }
  471. if (target_info.system in systems_aix) and
  472. (paradef.typ = recorddef) and
  473. (paralen < sizeof(aint)) then
  474. begin
  475. paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
  476. paraloc^.size := OS_INT;
  477. paraloc^.def := u32inttype;
  478. end;
  479. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  480. inc(nextintreg);
  481. dec(paralen,tcgsize2size[paraloc^.size]);
  482. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  483. inc(stack_offset,align(tcgsize2size[paraloc^.size],4));
  484. end
  485. else if (loc = LOC_FPUREGISTER) and
  486. (nextfloatreg <= maxfpureg) then
  487. begin
  488. paraloc^.loc:=loc;
  489. paraloc^.size := paracgsize;
  490. paraloc^.def := paradef;
  491. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  492. inc(nextfloatreg);
  493. dec(paralen,tcgsize2size[paraloc^.size]);
  494. { if nextfpureg > maxfpureg, all intregs are already used, since there }
  495. { are less of those available for parameter passing in the AIX abi }
  496. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  497. {$ifndef cpu64bitaddr}
  498. if (paracgsize = OS_F32) then
  499. begin
  500. inc(stack_offset,4);
  501. if (nextintreg < RS_R11) then
  502. inc(nextintreg);
  503. end
  504. else
  505. begin
  506. inc(stack_offset,8);
  507. if (nextintreg < RS_R10) then
  508. inc(nextintreg,2)
  509. else
  510. nextintreg := RS_R11;
  511. end;
  512. {$else not cpu64bitaddr}
  513. begin
  514. inc(stack_offset,tcgsize2size[paracgsize]);
  515. if (nextintreg < RS_R11) then
  516. inc(nextintreg);
  517. end;
  518. {$endif not cpu64bitaddr}
  519. end
  520. else { LOC_REFERENCE }
  521. begin
  522. paraloc^.loc:=LOC_REFERENCE;
  523. case loc of
  524. LOC_FPUREGISTER:
  525. begin
  526. paraloc^.size:=int_float_cgsize(paralen);
  527. case paraloc^.size of
  528. OS_F32: paraloc^.def:=s32floattype;
  529. OS_F64: paraloc^.def:=s64floattype;
  530. else
  531. internalerror(2013060124);
  532. end;
  533. end;
  534. LOC_REGISTER,
  535. LOC_REFERENCE:
  536. begin
  537. paraloc^.size:=int_cgsize(paralen);
  538. if paraloc^.size<>OS_NO then
  539. paraloc^.def:=cgsize_orddef(paraloc^.size)
  540. else
  541. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  542. end;
  543. else
  544. internalerror(2006011101);
  545. end;
  546. if (side = callerside) then
  547. paraloc^.reference.index:=NR_STACK_POINTER_REG
  548. else
  549. begin
  550. paraloc^.reference.index:=NR_R12;
  551. { create_paraloc_info_intern might be also called when being outside of
  552. code generation so current_procinfo might be not set }
  553. if assigned(current_procinfo) then
  554. tcpuprocinfo(current_procinfo).needs_frame_pointer := true;
  555. end;
  556. if not((target_info.system in systems_aix) and
  557. (paradef.typ=recorddef)) and
  558. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  559. (hp.paraloc[side].intsize < 3) then
  560. paraloc^.reference.offset:=stack_offset+(4-paralen)
  561. else
  562. paraloc^.reference.offset:=stack_offset;
  563. inc(stack_offset,align(paralen,4));
  564. while (paralen > 0) and
  565. (nextintreg < RS_R11) do
  566. begin
  567. inc(nextintreg);
  568. dec(paralen,sizeof(pint));
  569. end;
  570. paralen := 0;
  571. end;
  572. firstparaloc:=false;
  573. end;
  574. end;
  575. curintreg:=nextintreg;
  576. curfloatreg:=nextfloatreg;
  577. curmmreg:=nextmmreg;
  578. cur_stack_offset:=stack_offset;
  579. result:=stack_offset;
  580. end;
  581. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  582. var
  583. cur_stack_offset: aword;
  584. parasize, l: longint;
  585. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  586. i : integer;
  587. hp: tparavarsym;
  588. paraloc: pcgparalocation;
  589. begin
  590. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  591. firstfloatreg:=curfloatreg;
  592. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
  593. if (p.proccalloption in cstylearrayofconst) then
  594. { just continue loading the parameters in the registers }
  595. begin
  596. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true);
  597. { varargs routines have to reserve at least 32 bytes for the AIX abi }
  598. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  599. (result < 32) then
  600. result := 32;
  601. end
  602. else
  603. begin
  604. parasize:=cur_stack_offset;
  605. for i:=0 to varargspara.count-1 do
  606. begin
  607. hp:=tparavarsym(varargspara[i]);
  608. hp.paraloc[callerside].alignment:=4;
  609. paraloc:=hp.paraloc[callerside].add_location;
  610. paraloc^.loc:=LOC_REFERENCE;
  611. paraloc^.size:=def_cgsize(hp.vardef);
  612. paraloc^.def:=hp.vardef;
  613. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  614. l:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  615. paraloc^.reference.offset:=parasize;
  616. parasize:=parasize+l;
  617. end;
  618. result:=parasize;
  619. end;
  620. if curfloatreg<>firstfloatreg then
  621. include(varargspara.varargsinfo,va_uses_float_reg);
  622. end;
  623. function tcpuparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  624. var
  625. paraloc : pcgparalocation;
  626. paracgsize : tcgsize;
  627. offset : aint;
  628. begin
  629. result:=false;
  630. offset:=-1;
  631. case target_info.system of
  632. system_powerpc_morphos:
  633. begin
  634. paracgsize:=def_cgsize(p.vardef);
  635. p.paraloc[callerside].alignment:=4;
  636. p.paraloc[callerside].size:=paracgsize;
  637. p.paraloc[callerside].intsize:=tcgsize2size[paracgsize];
  638. paraloc:=p.paraloc[callerside].add_location;
  639. { The OS side should be zero extended and the entire "virtual"
  640. 68k register should be overwritten. This is what the C ppcinline
  641. macros do as well, by casting all arguments to ULONG. A call
  642. which breaks w/o this is for example exec/RawPutChar (KB) }
  643. paraloc^.size:=OS_ADDR;
  644. paraloc^.def:=p.vardef;
  645. { convert d0-d7/a0-a6 virtual 68k reg patterns into offsets }
  646. if length(s) = 2 then
  647. begin
  648. if (lowercase(s[1]) = 'd') and (s[2] in ['0'..'7']) then
  649. offset:=(ord(s[2]) - ord('0')) * sizeof(pint)
  650. else if (lowercase(s[1]) = 'a') and (s[2] in ['0'..'6']) then
  651. offset:=(ord(s[2]) - ord('0') + 8) * sizeof(pint);
  652. if offset < 0 then
  653. exit;
  654. paraloc^.loc:=LOC_REFERENCE;
  655. paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
  656. paraloc^.reference.offset:=offset;
  657. end
  658. { 'R12' is special, used internally to support regbase and nobase
  659. calling convention }
  660. else if lowercase(s)='r12' then
  661. begin
  662. paraloc^.loc:=LOC_REGISTER;
  663. paraloc^.register:=NR_R12;
  664. end
  665. else
  666. exit;
  667. { copy to callee side }
  668. p.paraloc[calleeside].add_location^:=paraloc^;
  669. end;
  670. else
  671. internalerror(200404182);
  672. end;
  673. result:=true;
  674. end;
  675. begin
  676. paramanager:=tcpuparamanager.create;
  677. end.