cpupara.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. PowerPC64 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,
  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):
  29. tcpuregisterset; override;
  30. function get_volatile_registers_fpu(calloption: tproccalloption):
  31. tcpuregisterset; override;
  32. function push_addr_param(varspez: tvarspez; def: tdef; calloption:
  33. tproccalloption): boolean; override;
  34. procedure getintparaloc(calloption: tproccalloption; nr: longint; var
  35. cgpara: TCGPara); override;
  36. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):
  37. longint; override;
  38. function create_varargs_paraloc_info(p: tabstractprocdef; varargspara:
  39. tvarargsparalist): longint; override;
  40. procedure create_funcretloc_info(p: tabstractprocdef; side: tcallercallee);
  41. private
  42. procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister;
  43. var cur_stack_offset: aword);
  44. function create_paraloc_info_intern(p: tabstractprocdef; side:
  45. tcallercallee; paras: tparalist;
  46. var curintreg, curfloatreg, curmmreg: tsuperregister; var
  47. cur_stack_offset: aword): longint;
  48. function parseparaloc(p: tparavarsym; const s: string): boolean; override;
  49. end;
  50. implementation
  51. uses
  52. verbose, systems,
  53. defutil,
  54. cgutils;
  55. function tppcparamanager.get_volatile_registers_int(calloption:
  56. tproccalloption): tcpuregisterset;
  57. begin
  58. result := [RS_R3..RS_R12];
  59. end;
  60. function tppcparamanager.get_volatile_registers_fpu(calloption:
  61. tproccalloption): tcpuregisterset;
  62. begin
  63. result := [RS_F0..RS_F13];
  64. end;
  65. procedure tppcparamanager.getintparaloc(calloption: tproccalloption; nr:
  66. longint; var cgpara: TCGPara);
  67. var
  68. paraloc: pcgparalocation;
  69. begin
  70. cgpara.reset;
  71. cgpara.size := OS_INT;
  72. cgpara.intsize := tcgsize2size[OS_INT];
  73. cgpara.alignment := get_para_align(calloption);
  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(aint) * (nr - 8)
  91. else
  92. reference.offset := sizeof(aint) * (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.deftype 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. recorddef:
  115. if (target_info.abi <> abi_powerpc_aix) then
  116. result := LOC_REFERENCE
  117. else
  118. result := LOC_REGISTER;
  119. objectdef:
  120. if is_object(p) then
  121. result := LOC_REFERENCE
  122. else
  123. result := LOC_REGISTER;
  124. stringdef:
  125. if is_shortstring(p) or is_longstring(p) then
  126. result := LOC_REFERENCE
  127. else
  128. result := LOC_REGISTER;
  129. procvardef:
  130. if (po_methodpointer in tprocvardef(p).procoptions) then
  131. result := LOC_REFERENCE
  132. else
  133. result := LOC_REGISTER;
  134. filedef:
  135. result := LOC_REGISTER;
  136. arraydef:
  137. result := LOC_REFERENCE;
  138. setdef:
  139. if is_smallset(p) then
  140. result := LOC_REGISTER
  141. else
  142. result := LOC_REFERENCE;
  143. variantdef:
  144. result := LOC_REFERENCE;
  145. { avoid problems with errornous definitions }
  146. errordef:
  147. result := LOC_REGISTER;
  148. else
  149. internalerror(2002071001);
  150. end;
  151. end;
  152. function tppcparamanager.push_addr_param(varspez: tvarspez; def: tdef;
  153. 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.deftype of
  163. variantdef,
  164. formaldef:
  165. result := true;
  166. recorddef:
  167. result :=
  168. (target_info.abi <> abi_powerpc_aix) or
  169. ((varspez = vs_const) and
  170. ((calloption = pocall_mwpascal) or
  171. (not (calloption in [pocall_cdecl, pocall_cppdecl]) and
  172. (def.size > 8)
  173. )
  174. )
  175. );
  176. arraydef:
  177. result := (tarraydef(def).highrange >= tarraydef(def).lowrange) or
  178. is_open_array(def) or
  179. is_array_of_const(def) or
  180. is_array_constructor(def);
  181. objectdef:
  182. result := is_object(def);
  183. setdef:
  184. result := (tsetdef(def).settype <> smallset);
  185. stringdef:
  186. result := tstringdef(def).string_typ in [st_shortstring, st_longstring];
  187. procvardef:
  188. result := po_methodpointer in tprocvardef(def).procoptions;
  189. end;
  190. end;
  191. procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg:
  192. tsuperregister; var cur_stack_offset: aword);
  193. begin
  194. cur_stack_offset := 48;
  195. curintreg := RS_R3;
  196. curfloatreg := RS_F1;
  197. curmmreg := RS_M1;
  198. end;
  199. procedure tppcparamanager.create_funcretloc_info(p: tabstractprocdef; side:
  200. tcallercallee);
  201. var
  202. retcgsize: tcgsize;
  203. begin
  204. { Constructors return self instead of a boolean }
  205. if (p.proctypeoption = potype_constructor) then
  206. retcgsize := OS_ADDR
  207. else
  208. retcgsize := def_cgsize(p.rettype.def);
  209. location_reset(p.funcretloc[side], LOC_INVALID, OS_NO);
  210. p.funcretloc[side].size := retcgsize;
  211. { void has no location }
  212. if is_void(p.rettype.def) then
  213. begin
  214. p.funcretloc[side].loc := LOC_VOID;
  215. exit;
  216. end;
  217. { Return in FPU register? }
  218. if p.rettype.def.deftype = floatdef then
  219. begin
  220. p.funcretloc[side].loc := LOC_FPUREGISTER;
  221. p.funcretloc[side].register := NR_FPU_RESULT_REG;
  222. p.funcretloc[side].size := retcgsize;
  223. end
  224. else
  225. { Return in register? } if not ret_in_param(p.rettype.def, p.proccalloption)
  226. then
  227. begin
  228. begin
  229. p.funcretloc[side].loc := LOC_REGISTER;
  230. p.funcretloc[side].size := retcgsize;
  231. if side = callerside then
  232. p.funcretloc[side].register := newreg(R_INTREGISTER,
  233. RS_FUNCTION_RESULT_REG, cgsize2subreg(retcgsize))
  234. else
  235. p.funcretloc[side].register := newreg(R_INTREGISTER,
  236. RS_FUNCTION_RETURN_REG, cgsize2subreg(retcgsize));
  237. end;
  238. end
  239. else
  240. begin
  241. p.funcretloc[side].loc := LOC_REFERENCE;
  242. p.funcretloc[side].size := retcgsize;
  243. end;
  244. end;
  245. function tppcparamanager.create_paraloc_info(p: tabstractprocdef; side:
  246. tcallercallee): longint;
  247. var
  248. cur_stack_offset: aword;
  249. curintreg, curfloatreg, curmmreg: tsuperregister;
  250. begin
  251. init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
  252. result := create_paraloc_info_intern(p, side, p.paras, curintreg, curfloatreg,
  253. curmmreg, cur_stack_offset);
  254. create_funcretloc_info(p, side);
  255. end;
  256. function tppcparamanager.create_paraloc_info_intern(p: tabstractprocdef; side:
  257. tcallercallee; paras: tparalist;
  258. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset:
  259. aword): longint;
  260. var
  261. stack_offset: longint;
  262. paralen: aint;
  263. nextintreg, nextfloatreg, nextmmreg, maxfpureg: tsuperregister;
  264. paradef: tdef;
  265. paraloc: pcgparalocation;
  266. i: integer;
  267. hp: tparavarsym;
  268. loc: tcgloc;
  269. paracgsize: tcgsize;
  270. begin
  271. {$IFDEF extdebug}
  272. if po_explicitparaloc in p.procoptions then
  273. internalerror(200411141);
  274. {$ENDIF extdebug}
  275. result := 0;
  276. nextintreg := curintreg;
  277. nextfloatreg := curfloatreg;
  278. nextmmreg := curmmreg;
  279. stack_offset := cur_stack_offset;
  280. maxfpureg := RS_F13;
  281. for i := 0 to paras.count - 1 do
  282. begin
  283. hp := tparavarsym(paras[i]);
  284. paradef := hp.vartype.def;
  285. { Syscall for Morphos can have already a paraloc set }
  286. if (vo_has_explicit_paraloc in hp.varoptions) then
  287. begin
  288. if not (vo_is_syscall_lib in hp.varoptions) then
  289. internalerror(200412153);
  290. continue;
  291. end;
  292. hp.paraloc[side].reset;
  293. { currently only support C-style array of const }
  294. if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) and
  295. is_array_of_const(paradef) then
  296. begin
  297. paraloc := hp.paraloc[side].add_location;
  298. { hack: the paraloc must be valid, but is not actually used }
  299. paraloc^.loc := LOC_REGISTER;
  300. paraloc^.register := NR_R0;
  301. paraloc^.size := OS_ADDR;
  302. break;
  303. end;
  304. if (hp.varspez in [vs_var, vs_out]) or
  305. push_addr_param(hp.varspez, paradef, p.proccalloption) or
  306. is_open_array(paradef) or
  307. is_array_of_const(paradef) then
  308. begin
  309. paradef := voidpointertype.def;
  310. loc := LOC_REGISTER;
  311. paracgsize := OS_ADDR;
  312. paralen := tcgsize2size[OS_ADDR];
  313. end
  314. else
  315. begin
  316. if not is_special_array(paradef) then
  317. paralen := paradef.size
  318. else
  319. paralen := tcgsize2size[def_cgsize(paradef)];
  320. if (target_info.abi = abi_powerpc_aix) and
  321. (paradef.deftype = recorddef) and
  322. (hp.varspez in [vs_value, vs_const]) then
  323. begin
  324. { if a record has only one field and that field is }
  325. { non-composite (not array or record), it must be }
  326. { passed according to the rules of that type. }
  327. if (trecorddef(hp.vartype.def).symtable.symindex.count = 1) and
  328. (not trecorddef(hp.vartype.def).isunion) and
  329. ((tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype = floatdef) or
  330. ((target_info.system = system_powerpc_darwin) and
  331. (tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def.deftype in [orddef, enumdef]))) then
  332. begin
  333. paradef :=
  334. tabstractvarsym(trecorddef(hp.vartype.def).symtable.symindex.search(1)).vartype.def;
  335. loc := getparaloc(paradef);
  336. paracgsize := def_cgsize(paradef);
  337. end
  338. else
  339. begin
  340. loc := LOC_REGISTER;
  341. paracgsize := int_cgsize(paralen);
  342. end;
  343. end
  344. else
  345. begin
  346. loc := getparaloc(paradef);
  347. paracgsize := def_cgsize(paradef);
  348. { for things like formaldef }
  349. if (paracgsize = OS_NO) then
  350. begin
  351. paracgsize := OS_ADDR;
  352. paralen := tcgsize2size[OS_ADDR];
  353. end;
  354. end
  355. end;
  356. hp.paraloc[side].alignment := std_param_align;
  357. hp.paraloc[side].size := paracgsize;
  358. hp.paraloc[side].intsize := paralen;
  359. if (paralen = 0) then
  360. if (paradef.deftype = recorddef) then
  361. begin
  362. paraloc := hp.paraloc[side].add_location;
  363. paraloc^.loc := LOC_VOID;
  364. end
  365. else
  366. internalerror(2005011310);
  367. { can become < 0 for e.g. 3-byte records }
  368. while (paralen > 0) do
  369. begin
  370. paraloc := hp.paraloc[side].add_location;
  371. if (loc = LOC_REGISTER) and
  372. (nextintreg <= RS_R10) then
  373. begin
  374. paraloc^.loc := loc;
  375. { make sure we don't lose whether or not the type is signed }
  376. if (paradef.deftype <> orddef) then
  377. paracgsize := int_cgsize(paralen);
  378. if (paracgsize in [OS_NO]) then
  379. paraloc^.size := OS_INT
  380. else
  381. paraloc^.size := paracgsize;
  382. paraloc^.register := newreg(R_INTREGISTER, nextintreg, R_SUBNONE);
  383. inc(nextintreg);
  384. dec(paralen, tcgsize2size[paraloc^.size]);
  385. if target_info.abi = abi_powerpc_aix then
  386. inc(stack_offset, tcgsize2size[paraloc^.size]);
  387. end
  388. else if (loc = LOC_FPUREGISTER) and
  389. (nextfloatreg <= maxfpureg) then
  390. begin
  391. paraloc^.loc := loc;
  392. paraloc^.size := paracgsize;
  393. paraloc^.register := newreg(R_FPUREGISTER, nextfloatreg, R_SUBWHOLE);
  394. inc(nextfloatreg);
  395. dec(paralen, tcgsize2size[paraloc^.size]);
  396. { if nextfpureg > maxfpureg, all intregs are already used, since there }
  397. { are less of those available for parameter passing in the AIX abi }
  398. end
  399. else { LOC_REFERENCE }
  400. begin
  401. paraloc^.loc := LOC_REFERENCE;
  402. paraloc^.size := int_cgsize(paralen);
  403. if (side = callerside) then
  404. paraloc^.reference.index := NR_STACK_POINTER_REG
  405. else
  406. paraloc^.reference.index := NR_R12;
  407. paraloc^.reference.offset := stack_offset;
  408. inc(stack_offset, align(paralen, 8));
  409. paralen := 0;
  410. end;
  411. end;
  412. end;
  413. curintreg := nextintreg;
  414. curfloatreg := nextfloatreg;
  415. curmmreg := nextmmreg;
  416. cur_stack_offset := stack_offset;
  417. result := stack_offset;
  418. end;
  419. function tppcparamanager.create_varargs_paraloc_info(p: tabstractprocdef;
  420. varargspara: tvarargsparalist): longint;
  421. var
  422. cur_stack_offset: aword;
  423. parasize, l: longint;
  424. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  425. i: integer;
  426. hp: tparavarsym;
  427. paraloc: pcgparalocation;
  428. begin
  429. init_values(curintreg, curfloatreg, curmmreg, cur_stack_offset);
  430. firstfloatreg := curfloatreg;
  431. result := create_paraloc_info_intern(p, callerside, p.paras, curintreg,
  432. curfloatreg, curmmreg, cur_stack_offset);
  433. if (p.proccalloption in [pocall_cdecl, pocall_cppdecl]) then
  434. { just continue loading the parameters in the registers }
  435. begin
  436. result := create_paraloc_info_intern(p, callerside, varargspara, curintreg,
  437. curfloatreg, curmmreg, cur_stack_offset);
  438. { varargs routines have to reserve at least 64 bytes for the AIX abi }
  439. { ts: dunno??? }
  440. if (target_info.abi = abi_powerpc_aix) and
  441. (result < 64) then
  442. result := 64;
  443. end
  444. else
  445. begin
  446. parasize := cur_stack_offset;
  447. for i := 0 to varargspara.count - 1 do
  448. begin
  449. hp := tparavarsym(varargspara[i]);
  450. hp.paraloc[callerside].alignment := 8;
  451. paraloc := hp.paraloc[callerside].add_location;
  452. paraloc^.loc := LOC_REFERENCE;
  453. paraloc^.size := def_cgsize(hp.vartype.def);
  454. paraloc^.reference.index := NR_STACK_POINTER_REG;
  455. l := push_size(hp.varspez, hp.vartype.def, p.proccalloption);
  456. paraloc^.reference.offset := parasize;
  457. parasize := parasize + l;
  458. end;
  459. result := parasize;
  460. end;
  461. if curfloatreg <> firstfloatreg then
  462. include(varargspara.varargsinfo, va_uses_float_reg);
  463. end;
  464. function tppcparamanager.parseparaloc(p: tparavarsym; const s: string): boolean;
  465. var
  466. paraloc: pcgparalocation;
  467. paracgsize: tcgsize;
  468. begin
  469. result := false;
  470. case target_info.system of
  471. system_powerpc_morphos:
  472. begin
  473. paracgsize := def_cgsize(p.vartype.def);
  474. p.paraloc[callerside].alignment := 8;
  475. p.paraloc[callerside].size := paracgsize;
  476. p.paraloc[callerside].intsize := tcgsize2size[paracgsize];
  477. paraloc := p.paraloc[callerside].add_location;
  478. paraloc^.loc := LOC_REFERENCE;
  479. paraloc^.size := paracgsize;
  480. paraloc^.reference.index := newreg(R_INTREGISTER, RS_R2, R_SUBWHOLE);
  481. { pattern is always uppercase'd }
  482. if s = 'D0' then
  483. paraloc^.reference.offset := 0
  484. else if s = 'D1' then
  485. paraloc^.reference.offset := 8
  486. else if s = 'D2' then
  487. paraloc^.reference.offset := 16
  488. else if s = 'D3' then
  489. paraloc^.reference.offset := 24
  490. else if s = 'D4' then
  491. paraloc^.reference.offset := 32
  492. else if s = 'D5' then
  493. paraloc^.reference.offset := 40
  494. else if s = 'D6' then
  495. paraloc^.reference.offset := 48
  496. else if s = 'D7' then
  497. paraloc^.reference.offset := 56
  498. else if s = 'A0' then
  499. paraloc^.reference.offset := 64
  500. else if s = 'A1' then
  501. paraloc^.reference.offset := 72
  502. else if s = 'A2' then
  503. paraloc^.reference.offset := 80
  504. else if s = 'A3' then
  505. paraloc^.reference.offset := 88
  506. else if s = 'A4' then
  507. paraloc^.reference.offset := 96
  508. else if s = 'A5' then
  509. paraloc^.reference.offset := 104
  510. { 'A6' (offset 56) is used by mossyscall as libbase, so API
  511. never passes parameters in it,
  512. Indeed, but this allows to declare libbase either explicitly
  513. or let the compiler insert it }
  514. else if s = 'A6' then
  515. paraloc^.reference.offset := 112
  516. { 'A7' is the stack pointer on 68k, can't be overwritten
  517. by API calls, so it has no offset }
  518. { 'R12' is special, used internally to support r12base sysv
  519. calling convention }
  520. else if s = 'R12' then
  521. begin
  522. paraloc^.loc := LOC_REGISTER;
  523. paraloc^.size := OS_ADDR;
  524. paraloc^.register := NR_R12;
  525. end
  526. else
  527. exit;
  528. { copy to callee side }
  529. p.paraloc[calleeside].add_location^ := paraloc^;
  530. end;
  531. else
  532. internalerror(200404182);
  533. end;
  534. result := true;
  535. end;
  536. begin
  537. paramanager := tppcparamanager.create;
  538. end.