cpupara.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. {
  2. $Id$
  3. Copyright (c) 2002 by Florian Klaempfl
  4. PowerPC specific calling conventions
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. { PowerPC specific calling conventions are handled by this unit
  19. }
  20. unit cpupara;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. globtype,
  25. cclasses,
  26. aasmtai,
  27. cpubase,cpuinfo,
  28. symconst,symbase,symtype,symdef,paramgr,cgbase;
  29. type
  30. tppcparamanager = class(tparamanager)
  31. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  32. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  33. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  34. function getintparaloc(calloption : tproccalloption; nr : longint) : tparalocation;override;
  35. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  36. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;override;
  37. private
  38. procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
  39. function create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; firstpara: tparaitem;
  40. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
  41. function parseparaloc(p : tparaitem;const s : string) : boolean;override;
  42. end;
  43. implementation
  44. uses
  45. verbose,systems,
  46. procinfo,
  47. rgobj,
  48. defutil,symsym,cpupi;
  49. function tppcparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  50. begin
  51. result := [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. result := [RS_F0..RS_F13];
  58. abi_powerpc_sysv:
  59. {$warning: the 64bit sysv abi also uses RS_F0..RS_F13 like the aix abi above }
  60. result := [RS_F0..RS_F8];
  61. else
  62. internalerror(2003091401);
  63. end;
  64. end;
  65. function tppcparamanager.getintparaloc(calloption : tproccalloption; nr : longint) : tparalocation;
  66. begin
  67. fillchar(result,sizeof(tparalocation),0);
  68. result.lochigh:=LOC_INVALID;
  69. if nr<1 then
  70. internalerror(2002070801)
  71. else if nr<=8 then
  72. begin
  73. result.loc:=LOC_REGISTER;
  74. result.register:=newreg(R_INTREGISTER,RS_R2+nr,R_SUBWHOLE);
  75. end
  76. else
  77. begin
  78. result.loc:=LOC_REFERENCE;
  79. result.reference.index:=NR_STACK_POINTER_REG;
  80. result.reference.offset:=(nr-8)*4;
  81. end;
  82. result.size := OS_INT;
  83. end;
  84. function getparaloc(p : tdef) : tcgloc;
  85. begin
  86. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  87. if push_addr_param for the def is true
  88. }
  89. case p.deftype of
  90. orddef:
  91. getparaloc:=LOC_REGISTER;
  92. floatdef:
  93. getparaloc:=LOC_FPUREGISTER;
  94. enumdef:
  95. getparaloc:=LOC_REGISTER;
  96. pointerdef:
  97. getparaloc:=LOC_REGISTER;
  98. formaldef:
  99. getparaloc:=LOC_REGISTER;
  100. classrefdef:
  101. getparaloc:=LOC_REGISTER;
  102. recorddef:
  103. getparaloc:=LOC_REFERENCE;
  104. objectdef:
  105. if is_object(p) then
  106. getparaloc:=LOC_REFERENCE
  107. else
  108. getparaloc:=LOC_REGISTER;
  109. stringdef:
  110. if is_shortstring(p) or is_longstring(p) then
  111. getparaloc:=LOC_REFERENCE
  112. else
  113. getparaloc:=LOC_REGISTER;
  114. procvardef:
  115. if (po_methodpointer in tprocvardef(p).procoptions) then
  116. getparaloc:=LOC_REFERENCE
  117. else
  118. getparaloc:=LOC_REGISTER;
  119. filedef:
  120. getparaloc:=LOC_REGISTER;
  121. arraydef:
  122. getparaloc:=LOC_REFERENCE;
  123. setdef:
  124. if is_smallset(p) then
  125. getparaloc:=LOC_REGISTER
  126. else
  127. getparaloc:=LOC_REFERENCE;
  128. variantdef:
  129. getparaloc:=LOC_REFERENCE;
  130. { avoid problems with errornous definitions }
  131. errordef:
  132. getparaloc:=LOC_REGISTER;
  133. else
  134. internalerror(2002071001);
  135. end;
  136. end;
  137. function tppcparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  138. begin
  139. { var,out always require address }
  140. if varspez in [vs_var,vs_out] then
  141. begin
  142. result:=true;
  143. exit;
  144. end;
  145. case def.deftype of
  146. recorddef:
  147. result:=true;
  148. arraydef:
  149. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  150. is_open_array(def) or
  151. is_array_of_const(def) or
  152. is_array_constructor(def);
  153. setdef :
  154. result:=(tsetdef(def).settype<>smallset);
  155. stringdef :
  156. result:=tstringdef(def).string_typ in [st_shortstring,st_longstring];
  157. procvardef :
  158. result:=po_methodpointer in tprocvardef(def).procoptions;
  159. else
  160. result:=inherited push_addr_param(varspez,def,calloption);
  161. end;
  162. end;
  163. procedure tppcparamanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword);
  164. begin
  165. case target_info.abi of
  166. abi_powerpc_aix:
  167. cur_stack_offset:=24;
  168. abi_powerpc_sysv:
  169. cur_stack_offset:=8;
  170. else
  171. internalerror(2003051901);
  172. end;
  173. curintreg:=RS_R3;
  174. curfloatreg:=RS_F1;
  175. curmmreg:=RS_M1;
  176. end;
  177. function tppcparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  178. var
  179. paraloc : tparalocation;
  180. cur_stack_offset: aword;
  181. curintreg, curfloatreg, curmmreg: tsuperregister;
  182. begin
  183. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  184. result := create_paraloc_info_intern(p,side,tparaitem(p.para.first),curintreg,curfloatreg,curmmreg,cur_stack_offset);
  185. { Function return }
  186. fillchar(paraloc,sizeof(tparalocation),0);
  187. paraloc.alignment:= std_param_align;
  188. paraloc.size:=def_cgsize(p.rettype.def);
  189. paraloc.lochigh:=LOC_INVALID;
  190. { Return in FPU register? }
  191. if p.rettype.def.deftype=floatdef then
  192. begin
  193. paraloc.loc:=LOC_FPUREGISTER;
  194. paraloc.register:=NR_FPU_RESULT_REG;
  195. end
  196. else
  197. { Return in register? }
  198. if not ret_in_param(p.rettype.def,p.proccalloption) then
  199. begin
  200. paraloc.loc:=LOC_REGISTER;
  201. {$ifndef cpu64bit}
  202. if paraloc.size in [OS_64,OS_S64] then
  203. begin
  204. paraloc.register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
  205. paraloc.register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
  206. paraloc.lochigh:=LOC_REGISTER;
  207. end
  208. else
  209. {$endif cpu64bit}
  210. paraloc.register:=NR_FUNCTION_RETURN_REG;
  211. end
  212. else
  213. begin
  214. paraloc.loc:=LOC_REFERENCE;
  215. end;
  216. p.funcret_paraloc[side]:=paraloc;
  217. end;
  218. function tppcparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; firstpara: tparaitem;
  219. var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword):longint;
  220. var
  221. stack_offset: aword;
  222. nextintreg,nextfloatreg,nextmmreg : tsuperregister;
  223. paradef : tdef;
  224. paraloc : tparalocation;
  225. hp : tparaitem;
  226. loc : tcgloc;
  227. is_64bit: boolean;
  228. procedure assignintreg;
  229. begin
  230. if nextintreg<=ord(NR_R10) then
  231. begin
  232. paraloc.loc:=LOC_REGISTER;
  233. paraloc.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  234. inc(nextintreg);
  235. if target_info.abi=abi_powerpc_aix then
  236. inc(stack_offset,4);
  237. end
  238. else
  239. begin
  240. paraloc.loc:=LOC_REFERENCE;
  241. paraloc.reference.index:=NR_STACK_POINTER_REG;
  242. paraloc.reference.offset:=stack_offset;
  243. inc(stack_offset,4);
  244. end;
  245. end;
  246. begin
  247. result:=0;
  248. nextintreg := curintreg;
  249. nextfloatreg := curfloatreg;
  250. nextmmreg := curmmreg;
  251. stack_offset := cur_stack_offset;
  252. hp:=firstpara;
  253. while assigned(hp) do
  254. begin
  255. { currently only support C-style array of const }
  256. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) and
  257. is_array_of_const(hp.paratype.def) then
  258. begin
  259. { hack: the paraloc must be valid, but is not actually used }
  260. hp.paraloc[side].loc := LOC_REGISTER;
  261. hp.paraloc[side].lochigh := LOC_INVALID;
  262. hp.paraloc[side].register := NR_R0;
  263. hp.paraloc[side].size := OS_ADDR;
  264. break;
  265. end;
  266. if (hp.paratyp in [vs_var,vs_out]) then
  267. begin
  268. paradef := voidpointertype.def;
  269. loc := LOC_REGISTER;
  270. end
  271. else
  272. begin
  273. paradef := hp.paratype.def;
  274. loc:=getparaloc(paradef);
  275. end;
  276. { make sure all alignment bytes are 0 as well }
  277. fillchar(paraloc,sizeof(paraloc),0);
  278. paraloc.alignment:= std_param_align;
  279. paraloc.lochigh:=LOC_INVALID;
  280. case loc of
  281. LOC_REGISTER:
  282. begin
  283. paraloc.size := def_cgsize(paradef);
  284. { for things like formaldef }
  285. if paraloc.size = OS_NO then
  286. paraloc.size := OS_ADDR;
  287. is_64bit := paraloc.size in [OS_64,OS_S64];
  288. if nextintreg<=(RS_R10-ord(is_64bit)) then
  289. begin
  290. paraloc.loc:=LOC_REGISTER;
  291. if is_64bit then
  292. begin
  293. if odd(nextintreg-RS_R3) and (target_info.abi=abi_powerpc_sysv) Then
  294. inc(nextintreg);
  295. paraloc.registerhigh:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  296. paraloc.lochigh:=LOC_REGISTER;
  297. inc(nextintreg);
  298. if target_info.abi=abi_powerpc_aix then
  299. inc(stack_offset,4);
  300. end;
  301. paraloc.registerlow:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  302. inc(nextintreg);
  303. if target_info.abi=abi_powerpc_aix then
  304. inc(stack_offset,4);
  305. end
  306. else
  307. begin
  308. nextintreg:=RS_R11;
  309. paraloc.loc:=LOC_REFERENCE;
  310. paraloc.reference.index:=NR_STACK_POINTER_REG;
  311. paraloc.reference.offset:=stack_offset;
  312. if not is_64bit then
  313. inc(stack_offset,4)
  314. else
  315. inc(stack_offset,8);
  316. end;
  317. end;
  318. LOC_FPUREGISTER:
  319. begin
  320. paraloc.size:=def_cgsize(paradef);
  321. if nextfloatreg<=RS_F10 then
  322. begin
  323. paraloc.loc:=LOC_FPUREGISTER;
  324. paraloc.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE);
  325. inc(nextfloatreg);
  326. if target_info.abi=abi_powerpc_aix then
  327. inc(stack_offset,8);
  328. end
  329. else
  330. begin
  331. {!!!!!!!}
  332. paraloc.size:=def_cgsize(paradef);
  333. internalerror(2002071004);
  334. end;
  335. end;
  336. LOC_REFERENCE:
  337. begin
  338. paraloc.size:=OS_ADDR;
  339. if push_addr_param(hp.paratyp,paradef,p.proccalloption) or
  340. is_open_array(paradef) or
  341. is_array_of_const(paradef) then
  342. assignintreg
  343. else
  344. begin
  345. paraloc.loc:=LOC_REFERENCE;
  346. paraloc.reference.index:=NR_STACK_POINTER_REG;
  347. paraloc.reference.offset:=stack_offset;
  348. inc(stack_offset,hp.paratype.def.size);
  349. end;
  350. end;
  351. else
  352. internalerror(2002071002);
  353. end;
  354. {
  355. this is filled in in ncgutil
  356. if side = calleeside then
  357. begin
  358. if (paraloc.loc = LOC_REFERENCE) then
  359. begin
  360. if (current_procinfo.procdef <> p) then
  361. internalerror(2003112201);
  362. inc(paraloc.reference.offset,current_procinfo.calc_stackframe_size);
  363. end;
  364. end;
  365. }
  366. hp.paraloc[side]:=paraloc;
  367. hp:=tparaitem(hp.next);
  368. end;
  369. curintreg:=nextintreg;
  370. curfloatreg:=nextfloatreg;
  371. curmmreg:=nextmmreg;
  372. cur_stack_offset:=stack_offset;
  373. result:=cur_stack_offset;
  374. end;
  375. function tppcparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;
  376. var
  377. cur_stack_offset: aword;
  378. parasize, l: longint;
  379. curintreg, firstfloatreg, curfloatreg, curmmreg: tsuperregister;
  380. hp: tparaitem;
  381. paraloc: tparalocation;
  382. begin
  383. init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset);
  384. firstfloatreg:=curfloatreg;
  385. result := create_paraloc_info_intern(p,callerside,tparaitem(p.para.first),curintreg,curfloatreg,curmmreg,cur_stack_offset);
  386. if (p.proccalloption in [pocall_cdecl,pocall_cppdecl]) then
  387. { just continue loading the parameters in the registers }
  388. result := create_paraloc_info_intern(p,callerside,tparaitem(varargspara.first),curintreg,curfloatreg,curmmreg,cur_stack_offset)
  389. else
  390. begin
  391. hp := tparaitem(varargspara.first);
  392. parasize := cur_stack_offset;
  393. while assigned(hp) do
  394. begin
  395. paraloc.size:=def_cgsize(hp.paratype.def);
  396. paraloc.lochigh:=LOC_INVALID;
  397. paraloc.loc:=LOC_REFERENCE;
  398. paraloc.alignment:=4;
  399. paraloc.reference.index:=NR_STACK_POINTER_REG;
  400. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  401. paraloc.reference.offset:=parasize;
  402. parasize:=parasize+l;
  403. hp.paraloc[callerside]:=paraloc;
  404. hp:=tparaitem(hp.next);
  405. end;
  406. result := parasize;
  407. end;
  408. if curfloatreg<>firstfloatreg then
  409. include(varargspara.varargsinfo,va_uses_float_reg);
  410. end;
  411. function tppcparamanager.parseparaloc(p : tparaitem;const s : string) : boolean;
  412. begin
  413. result:=false;
  414. case target_info.system of
  415. system_powerpc_morphos:
  416. begin
  417. p.paraloc[callerside].loc:=LOC_REFERENCE;
  418. p.paraloc[callerside].lochigh:=LOC_INVALID;
  419. p.paraloc[callerside].size:=def_cgsize(p.paratype.def);
  420. p.paraloc[callerside].alignment:=4;
  421. p.paraloc[callerside].reference.index:=NR_R2;
  422. { pattern is always uppercase'd }
  423. if s='D0' then
  424. p.paraloc[callerside].reference.offset:=0
  425. else if s='D1' then
  426. p.paraloc[callerside].reference.offset:=4
  427. else if s='D2' then
  428. p.paraloc[callerside].reference.offset:=8
  429. else if s='D3' then
  430. p.paraloc[callerside].reference.offset:=12
  431. else if s='D4' then
  432. p.paraloc[callerside].reference.offset:=16
  433. else if s='D5' then
  434. p.paraloc[callerside].reference.offset:=20
  435. else if s='D6' then
  436. p.paraloc[callerside].reference.offset:=24
  437. else if s='D7' then
  438. p.paraloc[callerside].reference.offset:=28
  439. else if s='A0' then
  440. p.paraloc[callerside].reference.offset:=32
  441. else if s='A1' then
  442. p.paraloc[callerside].reference.offset:=36
  443. else if s='A2' then
  444. p.paraloc[callerside].reference.offset:=40
  445. else if s='A3' then
  446. p.paraloc[callerside].reference.offset:=44
  447. else if s='A4' then
  448. p.paraloc[callerside].reference.offset:=48
  449. else if s='A5' then
  450. p.paraloc[callerside].reference.offset:=52
  451. { 'A6' (offset 56) is used by mossyscall as libbase, so API
  452. never passes parameters in it,
  453. Indeed, but this allows to declare libbase either explicitly
  454. or let the compiler insert it }
  455. else if s='A6' then
  456. p.paraloc[callerside].reference.offset:=56
  457. { 'A7' is the stack pointer on 68k, can't be overwritten
  458. by API calls, so it has no offset }
  459. else
  460. exit;
  461. p.paraloc[calleeside]:=p.paraloc[callerside];
  462. end;
  463. else
  464. internalerror(200404182);
  465. end;
  466. result:=true;
  467. end;
  468. begin
  469. paramanager:=tppcparamanager.create;
  470. end.
  471. {
  472. $Log$
  473. Revision 1.63 2004-06-20 08:55:32 florian
  474. * logs truncated
  475. Revision 1.62 2004/05/01 22:05:02 florian
  476. + added lib support for Amiga/MorphOS syscalls
  477. Revision 1.61 2004/04/18 23:19:48 karoly
  478. * added correct offsets for PowerPC/MorphOS location support
  479. Revision 1.60 2004/04/18 15:22:24 florian
  480. + location support for arguments, currently PowerPC/MorphOS only
  481. Revision 1.59 2004/02/19 17:07:42 florian
  482. * fixed arg. area calculation
  483. Revision 1.58 2004/02/11 23:18:59 florian
  484. * fixed to compile the rtl again
  485. }