cpupara.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. {$warning HACK: framepointer reg shall be a normal parameter}
  230. if p.parast.symtablelevel>normal_function_level then
  231. inc(parasize,POINTER_SIZE);
  232. { we push Flags and CS as long
  233. to cope with the IRETD
  234. and we save 6 register + 4 selectors }
  235. if po_interrupt in p.procoptions then
  236. inc(parasize,8+6*4+4*2);
  237. { Assign fields }
  238. hp:=tparaitem(p.para.first);
  239. while assigned(hp) do
  240. begin
  241. if hp.paratyp in [vs_var,vs_out] then
  242. paraloc.size:=OS_ADDR
  243. else
  244. paraloc.size:=def_cgsize(hp.paratype.def);
  245. paraloc.loc:=LOC_REFERENCE;
  246. if assigned(current_procinfo) then
  247. paraloc.reference.index:=current_procinfo.framepointer
  248. else
  249. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  250. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  251. varalign:=size_2_align(l);
  252. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  253. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  254. parasize:=align(parasize+l,varalign);
  255. if (side=callerside) then
  256. begin
  257. paraloc.reference.index:=NR_STACK_POINTER_REG;
  258. dec(paraloc.reference.offset,POINTER_SIZE);
  259. end;
  260. hp.paraloc[side]:=paraloc;
  261. hp:=tparaitem(hp.next);
  262. end;
  263. { We need to return the size allocated }
  264. result:=parasize;
  265. end;
  266. function ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  267. var
  268. hp : tparaitem;
  269. paraloc : tparalocation;
  270. subreg : tsubregister;
  271. is_64bit : boolean;
  272. l,parareg,
  273. varalign,
  274. parasize : longint;
  275. begin
  276. parareg:=0;
  277. parasize:=0;
  278. {$warning HACK: framepointer reg shall be a normal parameter}
  279. if p.parast.symtablelevel>normal_function_level then
  280. inc(parareg);
  281. hp:=tparaitem(p.para.first);
  282. while assigned(hp) do
  283. begin
  284. if push_addr_param(hp.paratyp,hp.paratype.def,p.proccalloption) then
  285. paraloc.size:=OS_ADDR
  286. else
  287. paraloc.size:=def_cgsize(hp.paratype.def);
  288. is_64bit:=(paraloc.size in [OS_64,OS_S64,OS_F64]);
  289. {
  290. EAX
  291. EDX
  292. ECX
  293. Stack
  294. Stack
  295. 64bit values,floats,arrays and records are always
  296. on the stack.
  297. }
  298. if (parareg<=high(parasupregs)) and
  299. not(
  300. is_64bit or
  301. (hp.paratype.def.deftype in [floatdef,recorddef,arraydef])
  302. ) then
  303. begin
  304. paraloc.loc:=LOC_REGISTER;
  305. if (paraloc.size=OS_NO) or is_64bit then
  306. subreg:=R_SUBWHOLE
  307. else
  308. subreg:=cgsize2subreg(paraloc.size);
  309. paraloc.register:=newreg(R_INTREGISTER,parasupregs[parareg],subreg);
  310. inc(parareg);
  311. end
  312. else
  313. begin
  314. paraloc.loc:=LOC_REFERENCE;
  315. if assigned(current_procinfo) then
  316. paraloc.reference.index:=current_procinfo.framepointer
  317. else
  318. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  319. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  320. varalign:=size_2_align(l);
  321. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  322. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  323. parasize:=align(parasize+l,varalign);
  324. end;
  325. if (side=callerside) and
  326. (paraloc.loc=LOC_REFERENCE) then
  327. begin
  328. paraloc.reference.index:=NR_STACK_POINTER_REG;
  329. dec(paraloc.reference.offset,POINTER_SIZE);
  330. end;
  331. hp.paraloc[side]:=paraloc;
  332. hp:=tparaitem(hp.next);
  333. end;
  334. { We need to return the size allocated }
  335. result:=parasize;
  336. end;
  337. procedure ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee);
  338. var
  339. l : longint;
  340. begin
  341. if (p.proccalloption=pocall_register) or
  342. ((pocall_default=pocall_register) and
  343. (p.proccalloption in [pocall_compilerproc,pocall_internproc])) then
  344. l:=create_register_paraloc_info(p,side)
  345. else
  346. l:=create_stdcall_paraloc_info(p,side);
  347. create_funcret_paraloc_info(p,side);
  348. { Store the size of the parameters on the stack }
  349. if (side=calleeside) then
  350. current_procinfo.para_stack_size:=l;
  351. end;
  352. begin
  353. paramanager:=ti386paramanager.create;
  354. end.
  355. {
  356. $Log$
  357. Revision 1.32 2003-09-28 13:35:24 peter
  358. * register calling updates
  359. Revision 1.31 2003/09/25 21:30:11 peter
  360. * parameter fixes
  361. Revision 1.30 2003/09/23 17:56:06 peter
  362. * locals and paras are allocated in the code generation
  363. * tvarsym.localloc contains the location of para/local when
  364. generating code for the current procedure
  365. Revision 1.29 2003/09/16 16:17:01 peter
  366. * varspez in calls to push_addr_param
  367. Revision 1.28 2003/09/10 08:31:47 marco
  368. * Patch from Peter for paraloc
  369. Revision 1.27 2003/09/09 21:03:17 peter
  370. * basics for x86 register calling
  371. Revision 1.26 2003/09/09 15:55:05 peter
  372. * winapi doesn't like pushing 8 byte record
  373. Revision 1.25 2003/09/08 18:28:51 peter
  374. * fix compilerproc for default=oldfpccall
  375. Revision 1.24 2003/09/07 22:09:35 peter
  376. * preparations for different default calling conventions
  377. * various RA fixes
  378. Revision 1.23 2003/09/03 15:55:01 peter
  379. * NEWRA branch merged
  380. Revision 1.22.2.2 2003/08/28 18:35:08 peter
  381. * tregister changed to cardinal
  382. Revision 1.22.2.1 2003/08/27 19:55:54 peter
  383. * first tregister patch
  384. Revision 1.22 2003/08/11 21:18:20 peter
  385. * start of sparc support for newra
  386. Revision 1.21 2003/07/05 20:11:41 jonas
  387. * create_paraloc_info() is now called separately for the caller and
  388. callee info
  389. * fixed ppc cycle
  390. Revision 1.20 2003/07/02 22:18:04 peter
  391. * paraloc splitted in callerparaloc,calleeparaloc
  392. * sparc calling convention updates
  393. Revision 1.19 2003/06/17 16:34:19 peter
  394. * freeintparaloc added
  395. Revision 1.18 2003/06/07 18:57:04 jonas
  396. + added freeintparaloc
  397. * ppc get/freeintparaloc now check whether the parameter regs are
  398. properly allocated/deallocated (and get an extra list para)
  399. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  400. * fixed lot of missing pi_do_call's
  401. Revision 1.17 2003/06/06 14:41:22 peter
  402. * needs cpuinfo
  403. Revision 1.16 2003/06/06 07:36:06 michael
  404. + Forgot a line in patch from peter
  405. Revision 1.15 2003/06/06 07:35:14 michael
  406. + Patch to Patch from peter
  407. Revision 1.14 2003/06/06 07:34:11 michael
  408. + Patch from peter
  409. Revision 1.13 2003/06/05 20:58:05 peter
  410. * updated
  411. Revision 1.12 2003/05/30 23:57:08 peter
  412. * more sparc cleanup
  413. * accumulator removed, splitted in function_return_reg (called) and
  414. function_result_reg (caller)
  415. Revision 1.11 2003/05/13 15:16:13 peter
  416. * removed ret_in_acc, it's the reverse of ret_in_param
  417. * fixed ret_in_param for win32 cdecl array
  418. Revision 1.10 2003/04/22 23:50:23 peter
  419. * firstpass uses expectloc
  420. * checks if there are differences between the expectloc and
  421. location.loc from secondpass in EXTDEBUG
  422. Revision 1.9 2003/04/22 14:33:38 peter
  423. * removed some notes/hints
  424. Revision 1.8 2003/01/08 18:43:57 daniel
  425. * Tregister changed into a record
  426. Revision 1.7 2002/12/24 15:56:50 peter
  427. * stackpointer_alloc added for adjusting ESP. Win32 needs
  428. this for the pageprotection
  429. Revision 1.6 2002/12/17 22:19:33 peter
  430. * fixed pushing of records>8 bytes with stdcall
  431. * simplified hightree loading
  432. Revision 1.5 2002/11/18 17:32:00 peter
  433. * pass proccalloption to ret_in_xxx and push_xxx functions
  434. Revision 1.4 2002/11/15 01:58:56 peter
  435. * merged changes from 1.0.7 up to 04-11
  436. - -V option for generating bug report tracing
  437. - more tracing for option parsing
  438. - errors for cdecl and high()
  439. - win32 import stabs
  440. - win32 records<=8 are returned in eax:edx (turned off by default)
  441. - heaptrc update
  442. - more info for temp management in .s file with EXTDEBUG
  443. Revision 1.3 2002/08/09 07:33:04 florian
  444. * a couple of interface related fixes
  445. Revision 1.2 2002/07/11 14:41:32 florian
  446. * start of the new generic parameter handling
  447. Revision 1.1 2002/07/07 09:52:33 florian
  448. * powerpc target fixed, very simple units can be compiled
  449. * some basic stuff for better callparanode handling, far from being finished
  450. }