cpupara.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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;
  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. procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  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,
  45. cgutils,
  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. var
  221. retcgsize : tcgsize;
  222. begin
  223. { Constructors return self instead of a boolean }
  224. if (p.proctypeoption=potype_constructor) then
  225. retcgsize:=OS_ADDR
  226. else
  227. retcgsize:=def_cgsize(p.returndef);
  228. location_reset(p.funcretloc[side],LOC_INVALID,OS_NO);
  229. p.funcretloc[side].size:=retcgsize;
  230. { void has no location }
  231. if is_void(p.returndef) then
  232. begin
  233. p.funcretloc[side].loc:=LOC_VOID;
  234. exit;
  235. end;
  236. { Return is passed as var parameter }
  237. if ret_in_param(p.returndef,p.proccalloption) then
  238. begin
  239. p.funcretloc[side].loc:=LOC_REFERENCE;
  240. p.funcretloc[side].size:=retcgsize;
  241. exit;
  242. end;
  243. { Return in FPU register? }
  244. if p.returndef.typ=floatdef then
  245. begin
  246. p.funcretloc[side].loc:=LOC_FPUREGISTER;
  247. p.funcretloc[side].register:=NR_FPU_RESULT_REG;
  248. p.funcretloc[side].size:=retcgsize;
  249. end
  250. else
  251. { Return in register }
  252. begin
  253. {$ifndef cpu64bitaddr}
  254. if retcgsize in [OS_64,OS_S64] then
  255. begin
  256. { low 32bits }
  257. p.funcretloc[side].loc:=LOC_REGISTER;
  258. if side=callerside then
  259. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RESULT64_HIGH_REG
  260. else
  261. p.funcretloc[side].register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
  262. { high 32bits }
  263. if side=callerside then
  264. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RESULT64_LOW_REG
  265. else
  266. p.funcretloc[side].register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
  267. end
  268. else
  269. {$endif cpu64bitaddr}
  270. begin
  271. p.funcretloc[side].loc:=LOC_REGISTER;
  272. p.funcretloc[side].size:=retcgsize;
  273. if side=callerside then
  274. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  275. else
  276. p.funcretloc[side].register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  277. end;
  278. end;
  279. end;
  280. function tppcparamanager.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 tppcparamanager.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. paradef : tdef;
  296. paraloc : pcgparalocation;
  297. i : integer;
  298. hp : tparavarsym;
  299. loc : tcgloc;
  300. paracgsize: tcgsize;
  301. begin
  302. {$ifdef extdebug}
  303. if po_explicitparaloc in p.procoptions then
  304. internalerror(200411141);
  305. {$endif extdebug}
  306. result:=0;
  307. nextintreg := curintreg;
  308. nextfloatreg := curfloatreg;
  309. nextmmreg := curmmreg;
  310. stack_offset := cur_stack_offset;
  311. case target_info.abi of
  312. abi_powerpc_aix:
  313. maxfpureg := RS_F13;
  314. abi_powerpc_sysv:
  315. maxfpureg := RS_F8;
  316. else internalerror(2004070912);
  317. end;
  318. for i:=0 to paras.count-1 do
  319. begin
  320. hp:=tparavarsym(paras[i]);
  321. paradef := hp.vardef;
  322. { Syscall for Morphos can have already a paraloc set }
  323. if (vo_has_explicit_paraloc in hp.varoptions) then
  324. begin
  325. if not(vo_is_syscall_lib in hp.varoptions) then
  326. internalerror(200412153);
  327. continue;
  328. end;
  329. hp.paraloc[side].reset;
  330. { currently only support C-style array of const }
  331. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_mwpascal]) and
  332. is_array_of_const(paradef) then
  333. begin
  334. paraloc:=hp.paraloc[side].add_location;
  335. { hack: the paraloc must be valid, but is not actually used }
  336. paraloc^.loc := LOC_REGISTER;
  337. paraloc^.register := NR_R0;
  338. paraloc^.size := OS_ADDR;
  339. break;
  340. end;
  341. if (hp.varspez in [vs_var,vs_out]) or
  342. push_addr_param(hp.varspez,paradef,p.proccalloption) or
  343. is_open_array(paradef) or
  344. is_array_of_const(paradef) then
  345. begin
  346. paradef:=voidpointertype;
  347. loc:=LOC_REGISTER;
  348. paracgsize := OS_ADDR;
  349. paralen := tcgsize2size[OS_ADDR];
  350. end
  351. else
  352. begin
  353. if not is_special_array(paradef) then
  354. paralen := paradef.size
  355. else
  356. paralen := tcgsize2size[def_cgsize(paradef)];
  357. loc := getparaloc(paradef);
  358. if (target_info.abi = abi_powerpc_aix) and
  359. (paradef.typ = recorddef) and
  360. (hp.varspez in [vs_value,vs_const]) then
  361. begin
  362. { if a record has only one field and that field is }
  363. { non-composite (not array or record), it must be }
  364. { passed according to the rules of that type. }
  365. if (trecorddef(hp.vardef).symtable.SymList.count = 1) and
  366. (not trecorddef(hp.vardef).isunion) and
  367. ((tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef.typ = floatdef) or
  368. ((target_info.system = system_powerpc_darwin) and
  369. (tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef.typ in [orddef,enumdef]))) then
  370. begin
  371. paradef :=
  372. tabstractvarsym(trecorddef(hp.vardef).symtable.SymList[0]).vardef;
  373. paracgsize:=def_cgsize(paradef);
  374. end
  375. else
  376. begin
  377. paracgsize := int_cgsize(paralen);
  378. end;
  379. end
  380. else
  381. begin
  382. paracgsize:=def_cgsize(paradef);
  383. { for things like formaldef }
  384. if (paracgsize=OS_NO) then
  385. begin
  386. paracgsize:=OS_ADDR;
  387. paralen := tcgsize2size[OS_ADDR];
  388. end;
  389. end
  390. end;
  391. if varargsparas and
  392. (target_info.abi = abi_powerpc_aix) and
  393. (paradef.typ = floatdef) then
  394. begin
  395. loc := LOC_REGISTER;
  396. if paracgsize = OS_F64 then
  397. paracgsize := OS_64
  398. else
  399. paracgsize := OS_32;
  400. end;
  401. hp.paraloc[side].alignment:=std_param_align;
  402. hp.paraloc[side].size:=paracgsize;
  403. hp.paraloc[side].intsize:=paralen;
  404. if (target_info.abi = abi_powerpc_aix) and
  405. (paradef.typ in [recorddef,arraydef]) then
  406. hp.paraloc[side].composite:=true;
  407. {$ifndef cpu64bitaddr}
  408. if (target_info.abi=abi_powerpc_sysv) and
  409. is_64bit(paradef) and
  410. odd(nextintreg-RS_R3) then
  411. inc(nextintreg);
  412. {$endif not cpu64bitaddr}
  413. if (paralen = 0) then
  414. if (paradef.typ = recorddef) then
  415. begin
  416. paraloc:=hp.paraloc[side].add_location;
  417. paraloc^.loc := LOC_VOID;
  418. end
  419. else
  420. internalerror(2005011310);
  421. { can become < 0 for e.g. 3-byte records }
  422. while (paralen > 0) do
  423. begin
  424. paraloc:=hp.paraloc[side].add_location;
  425. if (loc = LOC_REGISTER) and
  426. (nextintreg <= RS_R10) then
  427. begin
  428. paraloc^.loc := loc;
  429. { make sure we don't lose whether or not the type is signed }
  430. if (paradef.typ <> orddef) then
  431. paracgsize := int_cgsize(paralen);
  432. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  433. paraloc^.size := OS_INT
  434. else
  435. paraloc^.size := paracgsize;
  436. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  437. inc(nextintreg);
  438. dec(paralen,tcgsize2size[paraloc^.size]);
  439. if target_info.abi=abi_powerpc_aix then
  440. inc(stack_offset,align(tcgsize2size[paraloc^.size],4));
  441. end
  442. else if (loc = LOC_FPUREGISTER) and
  443. (nextfloatreg <= maxfpureg) then
  444. begin
  445. paraloc^.loc:=loc;
  446. paraloc^.size := paracgsize;
  447. paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  448. inc(nextfloatreg);
  449. dec(paralen,tcgsize2size[paraloc^.size]);
  450. { if nextfpureg > maxfpureg, all intregs are already used, since there }
  451. { are less of those available for parameter passing in the AIX abi }
  452. if target_info.abi=abi_powerpc_aix then
  453. {$ifndef cpu64bitaddr}
  454. if (paracgsize = OS_F32) then
  455. begin
  456. inc(stack_offset,4);
  457. if (nextintreg < RS_R11) then
  458. inc(nextintreg);
  459. end
  460. else
  461. begin
  462. inc(stack_offset,8);
  463. if (nextintreg < RS_R10) then
  464. inc(nextintreg,2)
  465. else
  466. nextintreg := RS_R11;
  467. end;
  468. {$else not cpu64bitaddr}
  469. begin
  470. inc(stack_offset,tcgsize2size[paracgsize]);
  471. if (nextintreg < RS_R11) then
  472. inc(nextintreg);
  473. end;
  474. {$endif not cpu64bitaddr}
  475. end
  476. else { LOC_REFERENCE }
  477. begin
  478. paraloc^.loc:=LOC_REFERENCE;
  479. case loc of
  480. LOC_FPUREGISTER:
  481. paraloc^.size:=int_float_cgsize(paralen);
  482. LOC_REGISTER,
  483. LOC_REFERENCE:
  484. paraloc^.size:=int_cgsize(paralen);
  485. else
  486. internalerror(2006011101);
  487. end;
  488. if (side = callerside) then
  489. paraloc^.reference.index:=NR_STACK_POINTER_REG
  490. else
  491. begin
  492. paraloc^.reference.index:=NR_R12;
  493. tppcprocinfo(current_procinfo).needs_frame_pointer := true;
  494. end;
  495. if (target_info.abi = abi_powerpc_aix) and
  496. (hp.paraloc[side].intsize < 3) then
  497. paraloc^.reference.offset:=stack_offset+(4-paralen)
  498. else
  499. paraloc^.reference.offset:=stack_offset;
  500. inc(stack_offset,align(paralen,4));
  501. while (paralen > 0) and
  502. (nextintreg < RS_R11) do
  503. begin
  504. inc(nextintreg);
  505. dec(paralen,sizeof(pint));
  506. end;
  507. paralen := 0;
  508. end;
  509. end;
  510. end;
  511. curintreg:=nextintreg;
  512. curfloatreg:=nextfloatreg;
  513. curmmreg:=nextmmreg;
  514. cur_stack_offset:=stack_offset;
  515. result:=stack_offset;
  516. end;
  517. function tppcparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  518. var
  519. cur_stack_offset: aword;
  520. parasize, l: longint;
  521. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  522. i : integer;
  523. hp: tparavarsym;
  524. paraloc: pcgparalocation;
  525. begin
  526. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  527. firstfloatreg:=curfloatreg;
  528. result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset, false);
  529. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_mwpascal]) then
  530. { just continue loading the parameters in the registers }
  531. begin
  532. result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,true);
  533. { varargs routines have to reserve at least 32 bytes for the AIX abi }
  534. if (target_info.abi = abi_powerpc_aix) and
  535. (result < 32) then
  536. result := 32;
  537. end
  538. else
  539. begin
  540. parasize:=cur_stack_offset;
  541. for i:=0 to varargspara.count-1 do
  542. begin
  543. hp:=tparavarsym(varargspara[i]);
  544. hp.paraloc[callerside].alignment:=4;
  545. paraloc:=hp.paraloc[callerside].add_location;
  546. paraloc^.loc:=LOC_REFERENCE;
  547. paraloc^.size:=def_cgsize(hp.vardef);
  548. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  549. l:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  550. paraloc^.reference.offset:=parasize;
  551. parasize:=parasize+l;
  552. end;
  553. result:=parasize;
  554. end;
  555. if curfloatreg<>firstfloatreg then
  556. include(varargspara.varargsinfo,va_uses_float_reg);
  557. end;
  558. function tppcparamanager.parseparaloc(p : tparavarsym;const s : string) : boolean;
  559. var
  560. paraloc : pcgparalocation;
  561. paracgsize : tcgsize;
  562. begin
  563. result:=false;
  564. case target_info.system of
  565. system_powerpc_morphos:
  566. begin
  567. paracgsize:=def_cgsize(p.vardef);
  568. p.paraloc[callerside].alignment:=4;
  569. p.paraloc[callerside].size:=paracgsize;
  570. p.paraloc[callerside].intsize:=tcgsize2size[paracgsize];
  571. paraloc:=p.paraloc[callerside].add_location;
  572. paraloc^.loc:=LOC_REFERENCE;
  573. paraloc^.size:=paracgsize;
  574. paraloc^.reference.index:=newreg(R_INTREGISTER,RS_R2,R_SUBWHOLE);
  575. { pattern is always uppercase'd }
  576. if s='D0' then
  577. paraloc^.reference.offset:=0
  578. else if s='D1' then
  579. paraloc^.reference.offset:=4
  580. else if s='D2' then
  581. paraloc^.reference.offset:=8
  582. else if s='D3' then
  583. paraloc^.reference.offset:=12
  584. else if s='D4' then
  585. paraloc^.reference.offset:=16
  586. else if s='D5' then
  587. paraloc^.reference.offset:=20
  588. else if s='D6' then
  589. paraloc^.reference.offset:=24
  590. else if s='D7' then
  591. paraloc^.reference.offset:=28
  592. else if s='A0' then
  593. paraloc^.reference.offset:=32
  594. else if s='A1' then
  595. paraloc^.reference.offset:=36
  596. else if s='A2' then
  597. paraloc^.reference.offset:=40
  598. else if s='A3' then
  599. paraloc^.reference.offset:=44
  600. else if s='A4' then
  601. paraloc^.reference.offset:=48
  602. else if s='A5' then
  603. paraloc^.reference.offset:=52
  604. { 'A6' (offset 56) is used by mossyscall as libbase, so API
  605. never passes parameters in it,
  606. Indeed, but this allows to declare libbase either explicitly
  607. or let the compiler insert it }
  608. else if s='A6' then
  609. paraloc^.reference.offset:=56
  610. { 'A7' is the stack pointer on 68k, can't be overwritten
  611. by API calls, so it has no offset }
  612. { 'R12' is special, used internally to support r12base sysv
  613. calling convention }
  614. else if s='R12' then
  615. begin
  616. paraloc^.loc:=LOC_REGISTER;
  617. paraloc^.size:=OS_ADDR;
  618. paraloc^.register:=NR_R12;
  619. end
  620. else
  621. exit;
  622. { copy to callee side }
  623. p.paraloc[calleeside].add_location^:=paraloc^;
  624. end;
  625. else
  626. internalerror(200404182);
  627. end;
  628. result:=true;
  629. end;
  630. {
  631. breaks e.g. tests/test/cg/tpara1
  632. procedure tppcparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;var cgpara:TCGPara);
  633. var
  634. paraloc : pcgparalocation;
  635. begin
  636. paraloc:=parasym.paraloc[callerside].location;
  637. { No need for temps when value is pushed }
  638. if assigned(paraloc) and
  639. (paraloc^.loc=LOC_REFERENCE) and
  640. (paraloc^.reference.index=NR_STACK_POINTER_REG) then
  641. duplicateparaloc(list,calloption,parasym,cgpara)
  642. else
  643. inherited createtempparaloc(list,calloption,parasym,cgpara);
  644. end;
  645. }
  646. begin
  647. paramanager:=tppcparamanager.create;
  648. end.