cpupara.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. {
  2. $Id$
  3. Copyright (c) 2002 by Florian Klaempfl
  4. Generates the argument location information for i386
  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. { Generates the argument location information for i386.
  19. }
  20. unit cpupara;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. aasmtai,
  25. cpubase,
  26. globtype,
  27. cginfo,
  28. symconst,symtype,symdef,paramgr;
  29. type
  30. { Returns the location for the nr-st 32 Bit int parameter
  31. if every parameter before is an 32 Bit int parameter as well
  32. and if the calling conventions for the helper routines of the
  33. rtl are used.
  34. }
  35. ti386paramanager = class(tparamanager)
  36. function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;override;
  37. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  38. function get_volatile_registers_int(calloption : tproccalloption):tsuperregisterset;override;
  39. function get_volatile_registers_fpu(calloption : tproccalloption):tsuperregisterset;override;
  40. function getintparaloc(calloption : tproccalloption; nr : longint) : tparalocation;override;
  41. procedure create_paraloc_info(p : tabstractprocdef; side: tcallercallee);override;
  42. private
  43. procedure create_funcret_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  44. function create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  45. function create_inline_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  46. function create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  47. end;
  48. implementation
  49. uses
  50. cutils,
  51. systems,globals,verbose,
  52. symsym,
  53. cpuinfo,
  54. cgbase;
  55. const
  56. parasupregs : array[0..2] of tsuperregister = (RS_EAX,RS_EDX,RS_ECX);
  57. {****************************************************************************
  58. TI386PARAMANAGER
  59. ****************************************************************************}
  60. function ti386paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  61. begin
  62. case target_info.system of
  63. system_i386_win32 :
  64. begin
  65. case def.deftype of
  66. recorddef :
  67. begin
  68. { Win32 GCC returns small records in the FUNCTION_RETURN_REG.
  69. For stdcall we follow delphi instead of GCC }
  70. if (calloption in [pocall_cdecl,pocall_cppdecl]) and
  71. (def.size<=8) then
  72. begin
  73. result:=false;
  74. exit;
  75. end;
  76. end;
  77. end;
  78. end;
  79. end;
  80. result:=inherited ret_in_param(def,calloption);
  81. end;
  82. function ti386paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  83. begin
  84. case target_info.system of
  85. system_i386_win32 :
  86. begin
  87. case def.deftype of
  88. recorddef :
  89. begin
  90. { Win32 passes small records on the stack for call by
  91. value }
  92. if (calloption in [pocall_stdcall,pocall_cdecl,pocall_cppdecl]) and
  93. (varspez=vs_value) and
  94. (def.size<=8) then
  95. begin
  96. result:=false;
  97. exit;
  98. end;
  99. end;
  100. arraydef :
  101. begin
  102. { Win32 passes arrays on the stack for call by
  103. value }
  104. if (calloption in [pocall_stdcall,pocall_cdecl,pocall_cppdecl]) and
  105. (varspez=vs_value) and
  106. (tarraydef(def).highrange>=tarraydef(def).lowrange) then
  107. begin
  108. result:=true;
  109. exit;
  110. end;
  111. end;
  112. end;
  113. end;
  114. end;
  115. if calloption=pocall_register then
  116. begin
  117. case def.deftype of
  118. floatdef :
  119. begin
  120. result:=true;
  121. exit;
  122. end;
  123. end;
  124. end;
  125. result:=inherited push_addr_param(varspez,def,calloption);
  126. end;
  127. function ti386paramanager.get_volatile_registers_int(calloption : tproccalloption):tsuperregisterset;
  128. begin
  129. case calloption of
  130. pocall_internproc :
  131. result:=[];
  132. pocall_compilerproc :
  133. begin
  134. if pocall_default=pocall_oldfpccall then
  135. result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX]
  136. else
  137. result:=[RS_EAX,RS_EDX,RS_ECX];
  138. end;
  139. pocall_inline,
  140. pocall_register,
  141. pocall_safecall,
  142. pocall_stdcall,
  143. pocall_cdecl,
  144. pocall_cppdecl :
  145. result:=[RS_EAX,RS_EDX,RS_ECX];
  146. pocall_far16,
  147. pocall_pascal,
  148. pocall_oldfpccall :
  149. result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX];
  150. else
  151. internalerror(200309071);
  152. end;
  153. end;
  154. function ti386paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tsuperregisterset;
  155. begin
  156. result:=[first_fpu_supreg..last_fpu_supreg];;
  157. end;
  158. function ti386paramanager.getintparaloc(calloption : tproccalloption; nr : longint) : tparalocation;
  159. begin
  160. fillchar(result,sizeof(tparalocation),0);
  161. result.size:=OS_INT;
  162. if calloption=pocall_register then
  163. begin
  164. if (nr<=high(parasupregs)+1) then
  165. begin
  166. if nr=0 then
  167. internalerror(200309271);
  168. result.loc:=LOC_REGISTER;
  169. result.register:=newreg(R_INTREGISTER,parasupregs[nr-1],R_SUBWHOLE);
  170. end
  171. else
  172. begin
  173. result.loc:=LOC_REFERENCE;
  174. result.reference.index:=NR_EBP;
  175. result.reference.offset:=4*nr;
  176. end;
  177. end
  178. else
  179. begin
  180. result.loc:=LOC_REFERENCE;
  181. result.reference.index:=NR_EBP;
  182. result.reference.offset:=4*nr;
  183. end;
  184. end;
  185. procedure ti386paramanager.create_funcret_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  186. var
  187. paraloc : tparalocation;
  188. begin
  189. { Function return }
  190. fillchar(paraloc,sizeof(tparalocation),0);
  191. paraloc.size:=def_cgsize(p.rettype.def);
  192. { Return in FPU register? }
  193. if p.rettype.def.deftype=floatdef then
  194. begin
  195. paraloc.loc:=LOC_FPUREGISTER;
  196. paraloc.register:=NR_FPU_RESULT_REG;
  197. end
  198. else
  199. { Return in register? }
  200. if not ret_in_param(p.rettype.def,p.proccalloption) then
  201. begin
  202. paraloc.loc:=LOC_REGISTER;
  203. {$ifndef cpu64bit}
  204. if paraloc.size in [OS_64,OS_S64] then
  205. begin
  206. paraloc.register64.reglo:=NR_FUNCTION_RETURN64_LOW_REG;
  207. paraloc.register64.reghi:=NR_FUNCTION_RETURN64_HIGH_REG;
  208. end
  209. else
  210. {$endif cpu64bit}
  211. begin
  212. paraloc.register:=NR_FUNCTION_RETURN_REG;
  213. end;
  214. end
  215. else
  216. begin
  217. paraloc.loc:=LOC_REFERENCE;
  218. end;
  219. p.funcret_paraloc[side]:=paraloc;
  220. end;
  221. function ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  222. var
  223. hp : tparaitem;
  224. paraloc : tparalocation;
  225. l,
  226. varalign,
  227. parasize : longint;
  228. begin
  229. parasize:=0;
  230. { we push Flags and CS as long
  231. to cope with the IRETD
  232. and we save 6 register + 4 selectors }
  233. if po_interrupt in p.procoptions then
  234. inc(parasize,8+6*4+4*2);
  235. { Assign fields }
  236. hp:=tparaitem(p.para.first);
  237. while assigned(hp) do
  238. begin
  239. if hp.paratyp in [vs_var,vs_out] then
  240. paraloc.size:=OS_ADDR
  241. else
  242. paraloc.size:=def_cgsize(hp.paratype.def);
  243. paraloc.loc:=LOC_REFERENCE;
  244. if assigned(current_procinfo) then
  245. paraloc.reference.index:=current_procinfo.framepointer
  246. else
  247. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  248. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  249. varalign:=size_2_align(l);
  250. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  251. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  252. parasize:=align(parasize+l,varalign);
  253. if (side=callerside) then
  254. begin
  255. paraloc.reference.index:=NR_STACK_POINTER_REG;
  256. dec(paraloc.reference.offset,POINTER_SIZE);
  257. end;
  258. hp.paraloc[side]:=paraloc;
  259. hp:=tparaitem(hp.next);
  260. end;
  261. { We need to return the size allocated }
  262. result:=parasize;
  263. end;
  264. function ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  265. var
  266. hp : tparaitem;
  267. paraloc : tparalocation;
  268. subreg : tsubregister;
  269. is_64bit : boolean;
  270. l,parareg,
  271. varalign,
  272. parasize : longint;
  273. begin
  274. parareg:=0;
  275. parasize:=0;
  276. hp:=tparaitem(p.para.first);
  277. while assigned(hp) do
  278. begin
  279. if push_addr_param(hp.paratyp,hp.paratype.def,p.proccalloption) then
  280. paraloc.size:=OS_ADDR
  281. else
  282. paraloc.size:=def_cgsize(hp.paratype.def);
  283. is_64bit:=(paraloc.size in [OS_64,OS_S64,OS_F64]);
  284. {
  285. EAX
  286. EDX
  287. ECX
  288. Stack
  289. Stack
  290. 64bit values,floats,arrays and records are always
  291. on the stack.
  292. }
  293. if (parareg<=high(parasupregs)) and
  294. not(
  295. is_64bit or
  296. (hp.paratype.def.deftype in [floatdef,recorddef,arraydef])
  297. ) then
  298. begin
  299. paraloc.loc:=LOC_REGISTER;
  300. if (paraloc.size=OS_NO) or is_64bit then
  301. subreg:=R_SUBWHOLE
  302. else
  303. subreg:=cgsize2subreg(paraloc.size);
  304. paraloc.register:=newreg(R_INTREGISTER,parasupregs[parareg],subreg);
  305. inc(parareg);
  306. end
  307. else
  308. begin
  309. paraloc.loc:=LOC_REFERENCE;
  310. if assigned(current_procinfo) then
  311. paraloc.reference.index:=current_procinfo.framepointer
  312. else
  313. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  314. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  315. varalign:=size_2_align(l);
  316. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  317. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  318. parasize:=align(parasize+l,varalign);
  319. end;
  320. if (side=callerside) and
  321. (paraloc.loc=LOC_REFERENCE) then
  322. begin
  323. paraloc.reference.index:=NR_STACK_POINTER_REG;
  324. dec(paraloc.reference.offset,POINTER_SIZE);
  325. end;
  326. hp.paraloc[side]:=paraloc;
  327. hp:=tparaitem(hp.next);
  328. end;
  329. { We need to return the size allocated }
  330. result:=parasize;
  331. end;
  332. function ti386paramanager.create_inline_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  333. var
  334. hp : tparaitem;
  335. paraloc : tparalocation;
  336. l,
  337. varalign,
  338. parasize : longint;
  339. begin
  340. parasize:=0;
  341. hp:=tparaitem(p.para.first);
  342. while assigned(hp) do
  343. begin
  344. if push_addr_param(hp.paratyp,hp.paratype.def,p.proccalloption) then
  345. paraloc.size:=OS_ADDR
  346. else
  347. paraloc.size:=def_cgsize(hp.paratype.def);
  348. if paraloc.size=OS_NO then
  349. internalerror(200309301);
  350. { Indicate parameter is loaded in register, the register
  351. will be allocated when the allocpara is called }
  352. paraloc.loc:=LOC_REGISTER;
  353. paraloc.register:=NR_NO;
  354. (*
  355. paraloc.loc:=LOC_REFERENCE;
  356. if assigned(current_procinfo) then
  357. paraloc.reference.index:=current_procinfo.framepointer
  358. else
  359. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  360. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  361. varalign:=size_2_align(l);
  362. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  363. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  364. parasize:=align(parasize+l,varalign);
  365. *)
  366. hp.paraloc[side]:=paraloc;
  367. hp:=tparaitem(hp.next);
  368. end;
  369. { We need to return the size allocated }
  370. result:=parasize;
  371. end;
  372. procedure ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  373. var
  374. l : longint;
  375. begin
  376. case p.proccalloption of
  377. pocall_register :
  378. l:=create_register_paraloc_info(p,side);
  379. pocall_inline :
  380. begin
  381. if inlining_procedure then
  382. l:=create_inline_paraloc_info(p,side)
  383. else
  384. begin
  385. { Use default calling }
  386. if (pocall_default=pocall_register) then
  387. l:=create_register_paraloc_info(p,side)
  388. else
  389. l:=create_stdcall_paraloc_info(p,side);
  390. end;
  391. end;
  392. pocall_compilerproc,
  393. pocall_internproc :
  394. begin
  395. { Use default calling }
  396. if (pocall_default=pocall_register) then
  397. l:=create_register_paraloc_info(p,side)
  398. else
  399. l:=create_stdcall_paraloc_info(p,side);
  400. end;
  401. else
  402. l:=create_stdcall_paraloc_info(p,side);
  403. end;
  404. create_funcret_paraloc_info(p,side);
  405. { Store the size of the parameters on the stack }
  406. if (side=calleeside) then
  407. current_procinfo.para_stack_size:=l;
  408. end;
  409. begin
  410. paramanager:=ti386paramanager.create;
  411. end.
  412. {
  413. $Log$
  414. Revision 1.34 2003-09-30 21:02:37 peter
  415. * updates for inlining
  416. Revision 1.33 2003/09/28 17:55:04 peter
  417. * parent framepointer changed to hidden parameter
  418. * tloadparentfpnode added
  419. Revision 1.32 2003/09/28 13:35:24 peter
  420. * register calling updates
  421. Revision 1.31 2003/09/25 21:30:11 peter
  422. * parameter fixes
  423. Revision 1.30 2003/09/23 17:56:06 peter
  424. * locals and paras are allocated in the code generation
  425. * tvarsym.localloc contains the location of para/local when
  426. generating code for the current procedure
  427. Revision 1.29 2003/09/16 16:17:01 peter
  428. * varspez in calls to push_addr_param
  429. Revision 1.28 2003/09/10 08:31:47 marco
  430. * Patch from Peter for paraloc
  431. Revision 1.27 2003/09/09 21:03:17 peter
  432. * basics for x86 register calling
  433. Revision 1.26 2003/09/09 15:55:05 peter
  434. * winapi doesn't like pushing 8 byte record
  435. Revision 1.25 2003/09/08 18:28:51 peter
  436. * fix compilerproc for default=oldfpccall
  437. Revision 1.24 2003/09/07 22:09:35 peter
  438. * preparations for different default calling conventions
  439. * various RA fixes
  440. Revision 1.23 2003/09/03 15:55:01 peter
  441. * NEWRA branch merged
  442. Revision 1.22.2.2 2003/08/28 18:35:08 peter
  443. * tregister changed to cardinal
  444. Revision 1.22.2.1 2003/08/27 19:55:54 peter
  445. * first tregister patch
  446. Revision 1.22 2003/08/11 21:18:20 peter
  447. * start of sparc support for newra
  448. Revision 1.21 2003/07/05 20:11:41 jonas
  449. * create_paraloc_info() is now called separately for the caller and
  450. callee info
  451. * fixed ppc cycle
  452. Revision 1.20 2003/07/02 22:18:04 peter
  453. * paraloc splitted in callerparaloc,calleeparaloc
  454. * sparc calling convention updates
  455. Revision 1.19 2003/06/17 16:34:19 peter
  456. * freeintparaloc added
  457. Revision 1.18 2003/06/07 18:57:04 jonas
  458. + added freeintparaloc
  459. * ppc get/freeintparaloc now check whether the parameter regs are
  460. properly allocated/deallocated (and get an extra list para)
  461. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  462. * fixed lot of missing pi_do_call's
  463. Revision 1.17 2003/06/06 14:41:22 peter
  464. * needs cpuinfo
  465. Revision 1.16 2003/06/06 07:36:06 michael
  466. + Forgot a line in patch from peter
  467. Revision 1.15 2003/06/06 07:35:14 michael
  468. + Patch to Patch from peter
  469. Revision 1.14 2003/06/06 07:34:11 michael
  470. + Patch from peter
  471. Revision 1.13 2003/06/05 20:58:05 peter
  472. * updated
  473. Revision 1.12 2003/05/30 23:57:08 peter
  474. * more sparc cleanup
  475. * accumulator removed, splitted in function_return_reg (called) and
  476. function_result_reg (caller)
  477. Revision 1.11 2003/05/13 15:16:13 peter
  478. * removed ret_in_acc, it's the reverse of ret_in_param
  479. * fixed ret_in_param for win32 cdecl array
  480. Revision 1.10 2003/04/22 23:50:23 peter
  481. * firstpass uses expectloc
  482. * checks if there are differences between the expectloc and
  483. location.loc from secondpass in EXTDEBUG
  484. Revision 1.9 2003/04/22 14:33:38 peter
  485. * removed some notes/hints
  486. Revision 1.8 2003/01/08 18:43:57 daniel
  487. * Tregister changed into a record
  488. Revision 1.7 2002/12/24 15:56:50 peter
  489. * stackpointer_alloc added for adjusting ESP. Win32 needs
  490. this for the pageprotection
  491. Revision 1.6 2002/12/17 22:19:33 peter
  492. * fixed pushing of records>8 bytes with stdcall
  493. * simplified hightree loading
  494. Revision 1.5 2002/11/18 17:32:00 peter
  495. * pass proccalloption to ret_in_xxx and push_xxx functions
  496. Revision 1.4 2002/11/15 01:58:56 peter
  497. * merged changes from 1.0.7 up to 04-11
  498. - -V option for generating bug report tracing
  499. - more tracing for option parsing
  500. - errors for cdecl and high()
  501. - win32 import stabs
  502. - win32 records<=8 are returned in eax:edx (turned off by default)
  503. - heaptrc update
  504. - more info for temp management in .s file with EXTDEBUG
  505. Revision 1.3 2002/08/09 07:33:04 florian
  506. * a couple of interface related fixes
  507. Revision 1.2 2002/07/11 14:41:32 florian
  508. * start of the new generic parameter handling
  509. Revision 1.1 2002/07/07 09:52:33 florian
  510. * powerpc target fixed, very simple units can be compiled
  511. * some basic stuff for better callparanode handling, far from being finished
  512. }