cpupara.pas 17 KB

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