cpupara.pas 20 KB

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