cpupara.pas 14 KB

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