cpupara.pas 17 KB

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