cpupara.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. {
  2. $Id$
  3. Copyright (c) 2002 by Florian Klaempfl
  4. Generates the argument location information for x86-64 target
  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 bymethodpointer
  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. unit cpupara;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. cpubase,cgbase,
  24. symconst,symbase,symtype,symdef,
  25. aasmtai,
  26. parabase,paramgr;
  27. type
  28. tx86_64paramanager = class(tparamanager)
  29. private
  30. procedure create_funcret_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  31. procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;firstpara:tparaitem;
  32. var intparareg,mmparareg,parasize:longint);
  33. public
  34. procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);override;
  35. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  36. function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
  37. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  38. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  39. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;override;
  40. end;
  41. implementation
  42. uses
  43. cutils,verbose,
  44. systems,
  45. defutil;
  46. const
  47. paraintsupregs : array[0..5] of tsuperregister = (RS_RDI,RS_RSI,RS_RDX,RS_RCX,RS_R8,RS_R9);
  48. parammsupregs : array[0..7] of tsuperregister = (RS_XMM0,RS_XMM1,RS_XMM2,RS_XMM3,RS_XMM4,RS_XMM5,RS_XMM6,RS_XMM7);
  49. procedure getvalueparaloc(p : tdef;var loc1,loc2:tcgloc);
  50. begin
  51. loc1:=LOC_INVALID;
  52. loc2:=LOC_INVALID;
  53. case p.deftype of
  54. orddef:
  55. begin
  56. loc1:=LOC_REGISTER;
  57. {$warning TODO 128bit also needs lochigh}
  58. end;
  59. floatdef:
  60. begin
  61. case tfloatdef(p).typ of
  62. s80real:
  63. loc1:=LOC_REFERENCE;
  64. s32real,
  65. s64real :
  66. loc1:=LOC_MMREGISTER;
  67. s64currency,
  68. s64comp :
  69. loc1:=LOC_REGISTER;
  70. s128real:
  71. begin
  72. loc1:=LOC_MMREGISTER;
  73. loc2:=LOC_MMREGISTER;
  74. {$warning TODO float 128bit needs SSEUP lochigh}
  75. end;
  76. end;
  77. end;
  78. recorddef:
  79. begin
  80. if p.size<=16 then
  81. begin
  82. {$warning TODO location depends on the fields}
  83. loc1:=LOC_REFERENCE;
  84. end
  85. else
  86. loc1:=LOC_REFERENCE;
  87. end;
  88. objectdef:
  89. begin
  90. if is_object(p) then
  91. loc1:=LOC_REFERENCE
  92. else
  93. loc1:=LOC_REGISTER;
  94. end;
  95. arraydef:
  96. loc1:=LOC_REFERENCE;
  97. variantdef:
  98. loc1:=LOC_REFERENCE;
  99. stringdef:
  100. if is_shortstring(p) or is_longstring(p) then
  101. loc1:=LOC_REFERENCE
  102. else
  103. loc1:=LOC_REGISTER;
  104. setdef:
  105. if is_smallset(p) then
  106. loc1:=LOC_REGISTER
  107. else
  108. loc1:=LOC_REFERENCE;
  109. procvardef:
  110. begin
  111. { This is a record < 16 bytes }
  112. if (po_methodpointer in tprocvardef(p).procoptions) then
  113. begin
  114. loc1:=LOC_REGISTER;
  115. loc2:=LOC_REGISTER;
  116. end
  117. else
  118. loc1:=LOC_REGISTER;
  119. end;
  120. else
  121. begin
  122. { default for pointers,enums,etc }
  123. loc1:=LOC_REGISTER;
  124. end;
  125. end;
  126. end;
  127. function tx86_64paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  128. begin
  129. result:=[RS_RAX,RS_RCX,RS_RDX,RS_RSI,RS_RDI,RS_R8,RS_R9,RS_R10,RS_R11];
  130. end;
  131. function tx86_64paramanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  132. begin
  133. result:=[RS_XMM0..RS_XMM15];
  134. end;
  135. function tx86_64paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  136. begin
  137. result:=[RS_ST0..RS_ST7];
  138. end;
  139. procedure tx86_64paramanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
  140. var
  141. paraloc : pcgparalocation;
  142. begin
  143. cgpara.reset;
  144. cgpara.size:=OS_INT;
  145. cgpara.alignment:=get_para_align(calloption);
  146. paraloc:=cgpara.add_location;
  147. with paraloc^ do
  148. begin
  149. size:=OS_INT;
  150. if nr<1 then
  151. internalerror(200304303)
  152. else if nr<=high(paraintsupregs)+1 then
  153. begin
  154. loc:=LOC_REGISTER;
  155. register:=newreg(R_INTREGISTER,paraintsupregs[nr-1],R_SUBWHOLE);
  156. end
  157. else
  158. begin
  159. loc:=LOC_REFERENCE;
  160. reference.index:=NR_STACK_POINTER_REG;
  161. reference.offset:=(nr-6)*sizeof(aint);
  162. end;
  163. end;
  164. end;
  165. procedure tx86_64paramanager.create_funcret_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  166. var
  167. paraloc : pcgparalocation;
  168. retcgsize : tcgsize;
  169. begin
  170. { Constructors return self instead of a boolean }
  171. if (p.proctypeoption=potype_constructor) then
  172. retcgsize:=OS_ADDR
  173. else
  174. retcgsize:=def_cgsize(p.rettype.def);
  175. p.funcret_paraloc[side].reset;
  176. p.funcret_paraloc[side].Alignment:=std_param_align;
  177. p.funcret_paraloc[side].size:=retcgsize;
  178. { void has no location }
  179. if is_void(p.rettype.def) then
  180. exit;
  181. paraloc:=p.funcret_paraloc[side].add_location;
  182. { Return in FPU register? }
  183. if p.rettype.def.deftype=floatdef then
  184. begin
  185. case tfloatdef(p.rettype.def).typ of
  186. s32real,s64real:
  187. begin
  188. paraloc^.loc:=LOC_MMREGISTER;
  189. paraloc^.register:=NR_MM_RESULT_REG;
  190. end;
  191. s64currency,
  192. s64comp,
  193. s80real:
  194. begin
  195. paraloc^.loc:=LOC_FPUREGISTER;
  196. paraloc^.register:=NR_FPU_RESULT_REG;
  197. end;
  198. else
  199. internalerror(200405034);
  200. end;
  201. paraloc^.size:=retcgsize;
  202. end
  203. else
  204. { Return in register? }
  205. if not ret_in_param(p.rettype.def,p.proccalloption) then
  206. begin
  207. paraloc^.loc:=LOC_REGISTER;
  208. paraloc^.size:=retcgsize;
  209. if side=callerside then
  210. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(retcgsize))
  211. else
  212. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(retcgsize));
  213. end
  214. else
  215. begin
  216. paraloc^.loc:=LOC_REFERENCE;
  217. paraloc^.size:=retcgsize;
  218. end;
  219. end;
  220. procedure tx86_64paramanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;firstpara:tparaitem;
  221. var intparareg,mmparareg,parasize:longint);
  222. var
  223. hp : tparaitem;
  224. paraloc,
  225. paraloc2 : pcgparalocation;
  226. subreg : tsubregister;
  227. pushaddr : boolean;
  228. paracgsize : tcgsize;
  229. loc1,loc2 : tcgloc;
  230. l,
  231. varalign,
  232. paraalign : longint;
  233. begin
  234. paraalign:=get_para_align(p.proccalloption);
  235. { Register parameters are assigned from left to right }
  236. hp:=firstpara;
  237. while assigned(hp) do
  238. begin
  239. pushaddr:=push_addr_param(hp.paratyp,hp.paratype.def,p.proccalloption);
  240. if pushaddr then
  241. begin
  242. loc1:=LOC_REGISTER;
  243. loc2:=LOC_INVALID;
  244. paracgsize:=OS_ADDR;
  245. end
  246. else
  247. begin
  248. getvalueparaloc(hp.paratype.def,loc1,loc2);
  249. paracgsize:=def_cgsize(hp.paratype.def);
  250. if paracgsize=OS_C64 then
  251. paracgsize:=OS_64;
  252. end;
  253. hp.paraloc[side].reset;
  254. hp.paraloc[side].size:=paracgsize;
  255. hp.paraloc[side].Alignment:=paraalign;
  256. { First location }
  257. paraloc:=hp.paraloc[side].add_location;
  258. paraloc^.size:=paracgsize;
  259. if (loc1=LOC_REGISTER) and
  260. (intparareg<=high(paraintsupregs)) then
  261. begin
  262. if (paracgsize=OS_NO) or (loc2<>LOC_INVALID) then
  263. begin
  264. paraloc^.size:=OS_INT;
  265. subreg:=R_SUBWHOLE;
  266. end
  267. else
  268. begin
  269. paraloc^.size:=paracgsize;
  270. subreg:=cgsize2subreg(paracgsize);
  271. end;
  272. paraloc^.loc:=LOC_REGISTER;
  273. paraloc^.register:=newreg(R_INTREGISTER,paraintsupregs[intparareg],subreg);
  274. inc(intparareg);
  275. end
  276. else if (loc1=LOC_MMREGISTER) and
  277. (mmparareg<=high(parammsupregs)) then
  278. begin
  279. paraloc^.loc:=LOC_MMREGISTER;
  280. paraloc^.register:=newreg(R_MMREGISTER,parammsupregs[mmparareg],R_SUBNONE);
  281. if paracgsize=OS_F128 then
  282. paraloc^.size:=OS_F64
  283. else
  284. paraloc^.size:=paracgsize;
  285. inc(mmparareg);
  286. end
  287. else
  288. begin
  289. paraloc^.loc:=LOC_REFERENCE;
  290. if side=callerside then
  291. paraloc^.reference.index:=NR_STACK_POINTER_REG
  292. else
  293. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  294. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  295. varalign:=size_2_align(l);
  296. paraloc^.reference.offset:=parasize;
  297. varalign:=used_align(varalign,paraalign,paraalign);
  298. parasize:=align(parasize+l,varalign);
  299. end;
  300. { Second location }
  301. if (loc2<>LOC_INVALID) then
  302. begin
  303. if (loc2=LOC_REGISTER) and
  304. (intparareg<=high(paraintsupregs)) then
  305. begin
  306. paraloc2:=hp.paraloc[side].add_location;
  307. paraloc2^.loc:=LOC_REGISTER;
  308. paraloc2^.register:=newreg(R_INTREGISTER,paraintsupregs[intparareg],R_SUBWHOLE);
  309. paraloc2^.size:=OS_INT;
  310. inc(intparareg);
  311. end
  312. else
  313. if (loc2=LOC_MMREGISTER) and
  314. (mmparareg<=high(parammsupregs)) then
  315. begin
  316. paraloc2:=hp.paraloc[side].add_location;
  317. paraloc2^.loc:=LOC_REGISTER;
  318. paraloc2^.register:=newreg(R_MMREGISTER,parammsupregs[mmparareg],R_SUBNONE);
  319. if paracgsize=OS_F128 then
  320. paraloc2^.size:=OS_F64
  321. else
  322. paraloc2^.size:=paracgsize;
  323. inc(mmparareg);
  324. end
  325. else
  326. begin
  327. { Release when location low has already registers
  328. assigned }
  329. if paraloc^.loc=LOC_REGISTER then
  330. dec(intparareg);
  331. if paraloc^.loc=LOC_MMREGISTER then
  332. dec(mmparareg);
  333. { Overwrite with LOC_REFERENCE }
  334. paraloc^.loc:=LOC_REFERENCE;
  335. if side=callerside then
  336. paraloc^.reference.index:=NR_STACK_POINTER_REG
  337. else
  338. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  339. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  340. varalign:=size_2_align(l);
  341. paraloc^.reference.offset:=parasize;
  342. varalign:=used_align(varalign,paraalign,paraalign);
  343. parasize:=align(parasize+l,varalign);
  344. end;
  345. end;
  346. hp:=tparaitem(hp.next);
  347. end;
  348. { Register parameters are assigned from left-to-right, but the
  349. offsets on the stack are right-to-left. There is no need
  350. to reverse the offset, only adapt the calleeside with the
  351. start offset of the first param on the stack }
  352. if side=calleeside then
  353. begin
  354. hp:=tparaitem(p.para.first);
  355. while assigned(hp) do
  356. begin
  357. with hp.paraloc[side].location^ do
  358. if (loc=LOC_REFERENCE) then
  359. inc(reference.offset,target_info.first_parm_offset);
  360. hp:=tparaitem(hp.next);
  361. end;
  362. end;
  363. end;
  364. function tx86_64paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;
  365. var
  366. intparareg,mmparareg,
  367. parasize : longint;
  368. begin
  369. intparareg:=0;
  370. mmparareg:=0;
  371. parasize:=0;
  372. { calculate the registers for the normal parameters }
  373. create_paraloc_info_intern(p,callerside,tparaitem(p.para.first),intparareg,mmparareg,parasize);
  374. { append the varargs }
  375. create_paraloc_info_intern(p,callerside,tparaitem(varargspara.first),intparareg,mmparareg,parasize);
  376. { store used no. of SSE registers, that needs to be passed in %AL }
  377. varargspara.mmregsused:=mmparareg;
  378. result:=parasize;
  379. end;
  380. function tx86_64paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  381. var
  382. intparareg,mmparareg,
  383. parasize : longint;
  384. begin
  385. intparareg:=0;
  386. mmparareg:=0;
  387. parasize:=0;
  388. create_paraloc_info_intern(p,side,tparaitem(p.para.first),intparareg,mmparareg,parasize);
  389. { Create Function result paraloc }
  390. create_funcret_paraloc_info(p,side);
  391. { We need to return the size allocated on the stack }
  392. result:=parasize;
  393. end;
  394. begin
  395. paramanager:=tx86_64paramanager.create;
  396. end.
  397. {
  398. $Log$
  399. Revision 1.10 2004-09-21 17:25:13 peter
  400. * paraloc branch merged
  401. Revision 1.9.4.1 2004/08/31 20:43:06 peter
  402. * paraloc patch
  403. Revision 1.9 2004/06/20 08:55:32 florian
  404. * logs truncated
  405. Revision 1.8 2004/06/16 20:07:11 florian
  406. * dwarf branch merged
  407. Revision 1.7.2.7 2004/05/03 20:18:52 peter
  408. * fixes for tprintf
  409. Revision 1.7.2.6 2004/05/02 21:37:35 florian
  410. * setting of func. ret. for i386 fixed
  411. Revision 1.7.2.5 2004/05/02 20:56:55 florian
  412. * more fixes to handle_return_value update
  413. Revision 1.7.2.4 2004/05/02 19:08:01 florian
  414. * rewrote tcgcallnode.handle_return_value
  415. }