cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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 getcgtempparaloc(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 : tcpuregisterarray = (
  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.getcgtempparaloc(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. else
  227. ;
  228. end;
  229. end;
  230. procedure tcpuparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
  231. begin
  232. case target_info.abi of
  233. abi_powerpc_aix,
  234. abi_powerpc_darwin:
  235. cur_stack_offset:=24;
  236. abi_powerpc_sysv:
  237. cur_stack_offset:=8;
  238. else
  239. internalerror(2003051901);
  240. end;
  241. curintreg:=RS_R3;
  242. curfloatreg:=RS_F1;
  243. curmmreg:=RS_M1;
  244. end;
  245. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  246. var
  247. paraloc : pcgparalocation;
  248. retcgsize : tcgsize;
  249. begin
  250. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  251. exit;
  252. paraloc:=result.add_location;
  253. { Return in FPU register? }
  254. if result.def.typ=floatdef then
  255. begin
  256. paraloc^.loc:=LOC_FPUREGISTER;
  257. paraloc^.register:=NR_FPU_RESULT_REG;
  258. paraloc^.size:=retcgsize;
  259. paraloc^.def:=result.def;
  260. end
  261. else
  262. { Return in register }
  263. begin
  264. if retcgsize in [OS_64,OS_S64] then
  265. begin
  266. { low 32bits }
  267. paraloc^.loc:=LOC_REGISTER;
  268. if side=callerside then
  269. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  270. else
  271. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  272. paraloc^.size:=OS_32;
  273. paraloc^.def:=u32inttype;
  274. { high 32bits }
  275. paraloc:=result.add_location;
  276. paraloc^.loc:=LOC_REGISTER;
  277. if side=callerside then
  278. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  279. else
  280. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  281. paraloc^.size:=OS_32;
  282. paraloc^.def:=u32inttype;
  283. end
  284. else
  285. begin
  286. paraloc^.loc:=LOC_REGISTER;
  287. if side=callerside then
  288. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  289. else
  290. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  291. paraloc^.size:=retcgsize;
  292. paraloc^.def:=result.def;
  293. end;
  294. end;
  295. end;
  296. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  297. var
  298. cur_stack_offset: aword;
  299. curintreg, curfloatreg, curmmreg: tsuperregister;
  300. begin
  301. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  302. result := create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,false);
  303. create_funcretloc_info(p,side);
  304. end;
  305. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
  306. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
  307. var
  308. stack_offset: longint;
  309. paralen: aint;
  310. nextintreg,nextfloatreg,nextmmreg, maxfpureg : tsuperregister;
  311. locdef,
  312. fdef,
  313. paradef : tdef;
  314. paraloc : pcgparalocation;
  315. i : integer;
  316. hp : tparavarsym;
  317. loc : tcgloc;
  318. paracgsize: tcgsize;
  319. firstparaloc: boolean;
  320. begin
  321. {$ifdef extdebug}
  322. if po_explicitparaloc in p.procoptions then
  323. internalerror(200411141);
  324. {$endif extdebug}
  325. result:=0;
  326. nextintreg := curintreg;
  327. nextfloatreg := curfloatreg;
  328. nextmmreg := curmmreg;
  329. stack_offset := cur_stack_offset;
  330. case target_info.abi of
  331. abi_powerpc_aix,
  332. abi_powerpc_darwin:
  333. maxfpureg := RS_F13;
  334. abi_powerpc_sysv:
  335. maxfpureg := RS_F8;
  336. else internalerror(2004070912);
  337. end;
  338. for i:=0 to paras.count-1 do
  339. begin
  340. hp:=tparavarsym(paras[i]);
  341. paradef := hp.vardef;
  342. { Syscall for Morphos can have already a paraloc set }
  343. if (vo_has_explicit_paraloc in hp.varoptions) then
  344. continue;
  345. hp.paraloc[side].reset;
  346. { currently only support C-style array of const }
  347. if (p.proccalloption in cstylearrayofconst) and
  348. is_array_of_const(paradef) then
  349. begin
  350. paraloc:=hp.paraloc[side].add_location;
  351. { hack: the paraloc must be valid, but is not actually used }
  352. paraloc^.loc := LOC_REGISTER;
  353. paraloc^.register := NR_R0;
  354. paraloc^.size := OS_ADDR;
  355. paraloc^.def:=voidpointertype;
  356. break;
  357. end;
  358. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  359. begin
  360. paradef:=cpointerdef.getreusable_no_free(paradef);
  361. loc:=LOC_REGISTER;
  362. paracgsize := OS_ADDR;
  363. paralen := tcgsize2size[OS_ADDR];
  364. end
  365. else
  366. begin
  367. if not is_special_array(paradef) then
  368. paralen := paradef.size
  369. else
  370. paralen := tcgsize2size[def_cgsize(paradef)];
  371. if (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  372. (paradef.typ = recorddef) and
  373. (hp.varspez in [vs_value,vs_const]) then
  374. begin
  375. { if a record has only one field and that field is }
  376. { non-composite (not array or record), it must be }
  377. { passed according to the rules of that type. }
  378. if tabstractrecordsymtable(tabstractrecorddef(paradef).symtable).has_single_field(fdef) and
  379. ((fdef.typ=floatdef) or
  380. ((target_info.system=system_powerpc_darwin) and
  381. (fdef.typ in [orddef,enumdef]))) then
  382. begin
  383. paradef:=fdef;
  384. paracgsize:=def_cgsize(paradef);
  385. end
  386. else
  387. begin
  388. paracgsize := int_cgsize(paralen);
  389. end;
  390. end
  391. else
  392. begin
  393. paracgsize:=def_cgsize(paradef);
  394. { for things like formaldef }
  395. if (paracgsize=OS_NO) then
  396. begin
  397. paracgsize:=OS_ADDR;
  398. paralen := tcgsize2size[OS_ADDR];
  399. end;
  400. end
  401. end;
  402. loc := getparaloc(paradef);
  403. if varargsparas and
  404. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  405. (paradef.typ = floatdef) then
  406. begin
  407. loc := LOC_REGISTER;
  408. if paracgsize=OS_F64 then
  409. begin
  410. paracgsize:=OS_64;
  411. paradef:=u64inttype;
  412. end
  413. else
  414. begin
  415. paracgsize:=OS_32;
  416. paradef:=u32inttype;
  417. end;
  418. end;
  419. hp.paraloc[side].alignment:=std_param_align;
  420. hp.paraloc[side].size:=paracgsize;
  421. hp.paraloc[side].intsize:=paralen;
  422. hp.paraloc[side].def:=paradef;
  423. {$ifndef cpu64bitaddr}
  424. if (target_info.abi=abi_powerpc_sysv) and
  425. is_64bit(paradef) and
  426. odd(nextintreg-RS_R3) then
  427. inc(nextintreg);
  428. {$endif not cpu64bitaddr}
  429. if (paralen = 0) then
  430. if (paradef.typ = recorddef) then
  431. begin
  432. paraloc:=hp.paraloc[side].add_location;
  433. paraloc^.loc := LOC_VOID;
  434. end
  435. else
  436. internalerror(2005011310);
  437. locdef:=paradef;
  438. firstparaloc:=true;
  439. { can become < 0 for e.g. 3-byte records }
  440. while (paralen > 0) do
  441. begin
  442. paraloc:=hp.paraloc[side].add_location;
  443. { In case of po_delphi_nested_cc, the parent frame pointer
  444. is always passed on the stack. }
  445. if (loc = LOC_REGISTER) and
  446. (nextintreg <= RS_R10) and
  447. (not(vo_is_parentfp in hp.varoptions) or
  448. not(po_delphi_nested_cc in p.procoptions)) then
  449. begin
  450. paraloc^.loc := loc;
  451. { make sure we don't lose whether or not the type is signed }
  452. if (paradef.typ<>orddef) then
  453. begin
  454. paracgsize:=int_cgsize(paralen);
  455. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  456. end;
  457. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  458. begin
  459. paraloc^.size:=OS_INT;
  460. paraloc^.def:=u32inttype;
  461. end
  462. else
  463. begin
  464. paraloc^.size:=paracgsize;
  465. paraloc^.def:=locdef;
  466. end;
  467. { aix requires that record data stored in parameter
  468. registers is left-aligned }
  469. if (target_info.system in systems_aix) and
  470. (paradef.typ = recorddef) and
  471. (paralen < sizeof(aint)) then
  472. begin
  473. paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
  474. paraloc^.size := OS_INT;
  475. paraloc^.def := u32inttype;
  476. end;
  477. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  478. inc(nextintreg);
  479. dec(paralen,tcgsize2size[paraloc^.size]);
  480. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  481. inc(stack_offset,align(tcgsize2size[paraloc^.size],4));
  482. end
  483. else if (loc = LOC_FPUREGISTER) and
  484. (nextfloatreg <= maxfpureg) then
  485. begin
  486. paraloc^.loc:=loc;
  487. paraloc^.size := paracgsize;
  488. paraloc^.def := paradef;
  489. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  490. inc(nextfloatreg);
  491. dec(paralen,tcgsize2size[paraloc^.size]);
  492. { if nextfpureg > maxfpureg, all intregs are already used, since there }
  493. { are less of those available for parameter passing in the AIX abi }
  494. if target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin] then
  495. {$ifndef cpu64bitaddr}
  496. if (paracgsize = OS_F32) then
  497. begin
  498. inc(stack_offset,4);
  499. if (nextintreg < RS_R11) then
  500. inc(nextintreg);
  501. end
  502. else
  503. begin
  504. inc(stack_offset,8);
  505. if (nextintreg < RS_R10) then
  506. inc(nextintreg,2)
  507. else
  508. nextintreg := RS_R11;
  509. end;
  510. {$else not cpu64bitaddr}
  511. begin
  512. inc(stack_offset,tcgsize2size[paracgsize]);
  513. if (nextintreg < RS_R11) then
  514. inc(nextintreg);
  515. end;
  516. {$endif not cpu64bitaddr}
  517. end
  518. else { LOC_REFERENCE }
  519. begin
  520. paraloc^.loc:=LOC_REFERENCE;
  521. case loc of
  522. LOC_FPUREGISTER:
  523. begin
  524. paraloc^.size:=int_float_cgsize(paralen);
  525. case paraloc^.size of
  526. OS_F32: paraloc^.def:=s32floattype;
  527. OS_F64: paraloc^.def:=s64floattype;
  528. else
  529. internalerror(2013060124);
  530. end;
  531. end;
  532. LOC_REGISTER,
  533. LOC_REFERENCE:
  534. begin
  535. paraloc^.size:=int_cgsize(paralen);
  536. if paraloc^.size<>OS_NO then
  537. paraloc^.def:=cgsize_orddef(paraloc^.size)
  538. else
  539. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  540. end;
  541. else
  542. internalerror(2006011101);
  543. end;
  544. if (side = callerside) then
  545. paraloc^.reference.index:=NR_STACK_POINTER_REG
  546. else
  547. begin
  548. paraloc^.reference.index:=NR_R12;
  549. { create_paraloc_info_intern might be also called when being outside of
  550. code generation so current_procinfo might be not set }
  551. if assigned(current_procinfo) then
  552. tcpuprocinfo(current_procinfo).needs_frame_pointer := true;
  553. end;
  554. if not((target_info.system in systems_aix) and
  555. (paradef.typ=recorddef)) and
  556. (target_info.abi in [abi_powerpc_aix,abi_powerpc_darwin]) and
  557. (hp.paraloc[side].intsize < 3) then
  558. paraloc^.reference.offset:=stack_offset+(4-paralen)
  559. else
  560. paraloc^.reference.offset:=stack_offset;
  561. inc(stack_offset,align(paralen,4));
  562. while (paralen > 0) and
  563. (nextintreg < RS_R11) do
  564. begin
  565. inc(nextintreg);
  566. dec(paralen,sizeof(pint));
  567. end;
  568. paralen := 0;
  569. end;
  570. firstparaloc:=false;
  571. end;
  572. end;
  573. curintreg:=nextintreg;
  574. curfloatreg:=nextfloatreg;
  575. curmmreg:=nextmmreg;
  576. cur_stack_offset:=stack_offset;
  577. result:=stack_offset;
  578. end;
  579. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  580. var
  581. cur_stack_offset: aword;
  582. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  583. begin
  584. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  585. firstfloatreg:=curfloatreg;
  586. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
  587. if (p.proccalloption in cstylearrayofconst) then
  588. { just continue loading the parameters in the registers }
  589. begin
  590. if assigned(varargspara) then
  591. begin
  592. if side=callerside then
  593. result:=create_paraloc_info_intern(p,side,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true)
  594. else
  595. internalerror(2019021921);
  596. end;
  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. internalerror(2019021710);
  604. if curfloatreg<>firstfloatreg then
  605. include(varargspara.varargsinfo,va_uses_float_reg);
  606. create_funcretloc_info(p,side);
  607. end;
  608. function tcpuparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  609. var
  610. paraloc : pcgparalocation;
  611. paracgsize : tcgsize;
  612. offset_lo: aint;
  613. offset_hi: aint;
  614. function parse68kregname(idx: longint): longint;
  615. begin
  616. result:=-1;
  617. if (lowercase(s[idx]) = 'd') and (s[idx+1] in ['0'..'7']) then
  618. result:=(ord(s[idx+1]) - ord('0')) * sizeof(pint)
  619. else if (lowercase(s[idx]) = 'a') and (s[idx+1] in ['0'..'6']) then
  620. result:=(ord(s[idx+1]) - ord('0') + 8) * sizeof(pint);
  621. end;
  622. begin
  623. result:=false;
  624. offset_hi:=-1;
  625. offset_lo:=-1;
  626. case target_info.system of
  627. system_powerpc_morphos:
  628. begin
  629. paracgsize:=def_cgsize(p.vardef);
  630. p.paraloc[callerside].alignment:=4;
  631. p.paraloc[callerside].size:=paracgsize;
  632. p.paraloc[callerside].intsize:=tcgsize2size[paracgsize];
  633. paraloc:=p.paraloc[callerside].add_location;
  634. { The OS side should be zero extended and the entire "virtual"
  635. 68k register should be overwritten. This is what the C ppcinline
  636. macros do as well, by casting all arguments to ULONG. A call
  637. which breaks w/o this is for example exec/RawPutChar (KB) }
  638. paraloc^.size:=OS_ADDR;
  639. paraloc^.def:=p.vardef;
  640. { convert virtual 68k reg patterns into offsets }
  641. case length(s) of
  642. 2: begin
  643. { single register }
  644. offset_lo:=parse68kregname(1);
  645. if offset_lo<0 then
  646. message(parser_e_illegal_explicit_paraloc);
  647. if tcgsize2size[paracgsize]>4 then
  648. message(parser_e_location_size_too_small);
  649. paraloc^.loc:=LOC_REFERENCE;
  650. paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
  651. paraloc^.reference.offset:=offset_lo;
  652. end;
  653. 5: begin
  654. { 64bit register pair, used by AmiSSL 68k for example }
  655. offset_hi:=parse68kregname(1);
  656. offset_lo:=parse68kregname(4);
  657. if (not (s[3] in [':','-'])) or
  658. (offset_lo<0) or (offset_hi<0) then
  659. message(parser_e_illegal_explicit_paraloc);
  660. if offset_lo>=(8*sizeof(pint)) then
  661. message(parser_e_location_regpair_only_data);
  662. if (offset_lo-offset_hi)<>4 then
  663. message(parser_e_location_regpair_only_consecutive);
  664. if tcgsize2size[paracgsize]<=4 then
  665. message(parser_e_location_size_too_large);
  666. if tcgsize2size[paracgsize]>8 then
  667. message(parser_e_location_size_too_small);
  668. paraloc^.loc:=LOC_REFERENCE;
  669. paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
  670. paraloc^.reference.offset:=offset_hi;
  671. paraloc^.size:=OS_64;
  672. end;
  673. else
  674. begin
  675. { 'R12' is special, used internally to support regbase and nobase
  676. calling convention }
  677. if lowercase(s)='r12' then
  678. begin
  679. paraloc^.loc:=LOC_REGISTER;
  680. paraloc^.register:=NR_R12;
  681. end
  682. else
  683. exit; { error, cannot parse }
  684. end;
  685. end;
  686. { copy to callee side }
  687. p.paraloc[calleeside].add_location^:=paraloc^;
  688. end;
  689. else
  690. internalerror(200404182);
  691. end;
  692. result:=true;
  693. end;
  694. begin
  695. paramanager:=tcpuparamanager.create;
  696. end.