cpupara.pas 29 KB

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