cpupara.pas 18 KB

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