cpupara.pas 27 KB

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