cpupara.pas 21 KB

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