cpupara.pas 26 KB

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