cpupara.pas 26 KB

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