cpupara.pas 17 KB

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