paramgr.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. {
  2. $Id$
  3. Copyright (c) 2002 by Florian Klaempfl
  4. Generic calling convention handling
  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 by
  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. {# Parameter passing manager. Used to manage how
  19. parameters are passed to routines.
  20. }
  21. unit paramgr;
  22. {$i fpcdefs.inc}
  23. interface
  24. uses
  25. cpubase,
  26. globtype,
  27. symtype,symdef;
  28. type
  29. {# This class defines some methods to take care of routine
  30. parameters. It should be overriden for each new processor
  31. }
  32. tparamanager = class
  33. {# Returns true if the return value can be put in accumulator }
  34. function ret_in_acc(def : tdef;calloption : tproccalloption) : boolean;virtual;
  35. {# Returns true if the return value is put in a register
  36. Either a floating point register, or a general purpose
  37. register.
  38. }
  39. function ret_in_reg(def : tdef;calloption : tproccalloption) : boolean;virtual;
  40. {# Returns true if the return value is actually a parameter
  41. pointer.
  42. }
  43. function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;virtual;
  44. function push_high_param(def : tdef;calloption : tproccalloption) : boolean;virtual;
  45. { Returns true if a parameter is too large to copy and only
  46. the address is pushed
  47. }
  48. function push_addr_param(def : tdef;calloption : tproccalloption) : boolean;virtual;
  49. { Returns true if a parameter needs to be copied on the stack, this
  50. is required for cdecl procedures
  51. }
  52. function copy_value_on_stack(def : tdef;calloption : tproccalloption) : boolean;
  53. { Returns a structure giving the information on
  54. the storage of the parameter (which must be
  55. an integer parameter)
  56. @param(nr Parameter number of routine, starting from 1)
  57. }
  58. function getintparaloc(nr : longint) : tparalocation;virtual;abstract;
  59. procedure create_param_loc_info(p : tabstractprocdef);virtual;abstract;
  60. {
  61. Returns the location where the invisible parameter for structured
  62. function results will be passed.
  63. }
  64. function getfuncretparaloc(p : tabstractprocdef) : tparalocation;virtual;
  65. {
  66. Returns the location where the invisible parameter for nested
  67. subroutines is passed.
  68. }
  69. function getframepointerloc(p : tabstractprocdef) : tparalocation;virtual;
  70. { Returns the self pointer location for the given tabstractprocdef,
  71. when the stack frame is already created. This is used by the code
  72. generating the wrappers for implemented interfaces.
  73. }
  74. function getselflocation(p : tabstractprocdef) : tparalocation;virtual;abstract;
  75. {
  76. Returns the location of the result if the result is in
  77. a register, the register(s) return depend on the type of
  78. the result.
  79. @param(def The definition of the result type of the function)
  80. }
  81. function getfuncresultloc(def : tdef;calloption:tproccalloption): tparalocation; virtual;
  82. end;
  83. procedure setparalocs(p : tprocdef);
  84. function getfuncretusedregisters(def : tdef;calloption:tproccalloption): tregisterset;
  85. var
  86. paralocdummy : tparalocation;
  87. paramanager : tparamanager;
  88. implementation
  89. uses
  90. cpuinfo,globals,systems,
  91. symconst,symbase,symsym,
  92. rgobj,
  93. defutil,cgbase,cginfo,verbose;
  94. { true if the return value is in accumulator (EAX for i386), D0 for 68k }
  95. function tparamanager.ret_in_acc(def : tdef;calloption : tproccalloption) : boolean;
  96. begin
  97. ret_in_acc:=(def.deftype in [orddef,pointerdef,enumdef,classrefdef]) or
  98. ((def.deftype=stringdef) and (tstringdef(def).string_typ in [st_ansistring,st_widestring])) or
  99. ((def.deftype=procvardef) and not(po_methodpointer in tprocvardef(def).procoptions)) or
  100. ((def.deftype=objectdef) and not is_object(def)) or
  101. ((def.deftype=setdef) and (tsetdef(def).settype=smallset));
  102. end;
  103. function tparamanager.ret_in_reg(def : tdef;calloption : tproccalloption) : boolean;
  104. begin
  105. ret_in_reg:=ret_in_acc(def,calloption) or (def.deftype=floatdef);
  106. end;
  107. { true if uses a parameter as return value }
  108. function tparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  109. begin
  110. ret_in_param:=(def.deftype in [arraydef,recorddef]) or
  111. ((def.deftype=stringdef) and (tstringdef(def).string_typ in [st_shortstring,st_longstring])) or
  112. ((def.deftype=procvardef) and (po_methodpointer in tprocvardef(def).procoptions)) or
  113. ((def.deftype=objectdef) and is_object(def)) or
  114. (def.deftype=variantdef) or
  115. ((def.deftype=setdef) and (tsetdef(def).settype<>smallset));
  116. end;
  117. function tparamanager.push_high_param(def : tdef;calloption : tproccalloption) : boolean;
  118. begin
  119. push_high_param:=is_open_array(def) or
  120. is_open_string(def) or
  121. is_array_of_const(def);
  122. end;
  123. { true if a parameter is too large to copy and only the address is pushed }
  124. function tparamanager.push_addr_param(def : tdef;calloption : tproccalloption) : boolean;
  125. begin
  126. push_addr_param:=false;
  127. if never_copy_const_param then
  128. push_addr_param:=true
  129. else
  130. begin
  131. case def.deftype of
  132. variantdef,
  133. formaldef :
  134. push_addr_param:=true;
  135. recorddef :
  136. push_addr_param:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (def.size>pointer_size);
  137. arraydef :
  138. push_addr_param:=(
  139. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  140. (
  141. not(target_info.system=system_i386_win32) or
  142. ((def.size>pointer_size) and
  143. not(calloption in [pocall_cdecl,pocall_cppdecl]))
  144. )
  145. ) or
  146. is_open_array(def) or
  147. is_array_of_const(def) or
  148. is_array_constructor(def);
  149. objectdef :
  150. push_addr_param:=is_object(def);
  151. stringdef :
  152. push_addr_param:=tstringdef(def).string_typ in [st_shortstring,st_longstring];
  153. procvardef :
  154. push_addr_param:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (po_methodpointer in tprocvardef(def).procoptions);
  155. setdef :
  156. push_addr_param:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tsetdef(def).settype<>smallset);
  157. end;
  158. end;
  159. end;
  160. { true if a parameter is too large to copy and only the address is pushed }
  161. function tparamanager.copy_value_on_stack(def : tdef;calloption : tproccalloption) : boolean;
  162. begin
  163. copy_value_on_stack:=false;
  164. { this is only for cdecl procedures }
  165. if not(calloption in [pocall_cdecl,pocall_cppdecl]) then
  166. exit;
  167. case def.deftype of
  168. variantdef,
  169. formaldef :
  170. copy_value_on_stack:=true;
  171. recorddef :
  172. copy_value_on_stack:=(def.size>pointer_size);
  173. arraydef :
  174. copy_value_on_stack:=(
  175. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  176. (
  177. not(target_info.system=system_i386_win32) or
  178. (def.size>pointer_size)
  179. )
  180. ) or
  181. is_open_array(def) or
  182. is_array_of_const(def) or
  183. is_array_constructor(def);
  184. objectdef :
  185. copy_value_on_stack:=is_object(def);
  186. stringdef :
  187. copy_value_on_stack:=tstringdef(def).string_typ in [st_shortstring,st_longstring];
  188. procvardef :
  189. copy_value_on_stack:=(po_methodpointer in tprocvardef(def).procoptions);
  190. setdef :
  191. copy_value_on_stack:=(tsetdef(def).settype<>smallset);
  192. end;
  193. end;
  194. function tparamanager.getfuncretparaloc(p : tabstractprocdef) : tparalocation;
  195. begin
  196. result.loc:=LOC_REFERENCE;
  197. result.size:=OS_ADDR;
  198. result.sp_fixup:=pointer_size;
  199. result.reference.index:=stack_pointer_reg;
  200. result.reference.offset:=0;
  201. end;
  202. function tparamanager.getframepointerloc(p : tabstractprocdef) : tparalocation;
  203. begin
  204. result.loc:=LOC_REFERENCE;
  205. result.size:=OS_ADDR;
  206. result.sp_fixup:=pointer_size;
  207. result.reference.index:=stack_pointer_reg;
  208. result.reference.offset:=0;
  209. end;
  210. function tparamanager.getfuncresultloc(def : tdef;calloption:tproccalloption): tparalocation;
  211. begin
  212. fillchar(result,sizeof(tparalocation),0);
  213. if is_void(def) then exit;
  214. result.size := def_cgsize(def);
  215. case def.deftype of
  216. orddef,
  217. enumdef :
  218. begin
  219. result.loc := LOC_REGISTER;
  220. {$ifndef cpu64bit}
  221. if result.size in [OS_64,OS_S64] then
  222. begin
  223. result.register64.reghi:=accumulatorhigh;
  224. result.register64.reglo:=accumulator;
  225. end
  226. else
  227. {$endif cpu64bit}
  228. result.register:=accumulator;
  229. end;
  230. floatdef :
  231. begin
  232. result.loc := LOC_FPUREGISTER;
  233. if cs_fp_emulation in aktmoduleswitches then
  234. result.register := accumulator
  235. else
  236. result.register := FPU_RESULT_REG;
  237. end;
  238. else
  239. begin
  240. if ret_in_reg(def,calloption) then
  241. begin
  242. result.loc := LOC_REGISTER;
  243. result.register := accumulator;
  244. end
  245. else
  246. begin
  247. result.loc := LOC_REFERENCE;
  248. internalerror(2002081602);
  249. (*
  250. {$ifdef EXTDEBUG}
  251. { it is impossible to have the
  252. return value with an index register
  253. and a symbol!
  254. }
  255. if (ref.index <> R_NO) or (assigned(ref.symbol)) then
  256. internalerror(2002081602);
  257. {$endif}
  258. result.reference.index := ref.base;
  259. result.reference.offset := ref.offset;
  260. *)
  261. end;
  262. end;
  263. end;
  264. end;
  265. function getfuncretusedregisters(def : tdef;calloption:tproccalloption): tregisterset;
  266. var
  267. paramloc : tparalocation;
  268. regset : tregisterset;
  269. begin
  270. regset:=[];
  271. getfuncretusedregisters:=[];
  272. { if nothing is returned in registers,
  273. its useless to continue on in this
  274. routine
  275. }
  276. if not paramanager.ret_in_reg(def,calloption) then
  277. exit;
  278. paramloc := paramanager.getfuncresultloc(def,calloption);
  279. case paramloc.loc of
  280. LOC_FPUREGISTER,
  281. LOC_CFPUREGISTER,
  282. LOC_MMREGISTER,
  283. LOC_CMMREGISTER,
  284. LOC_REGISTER,LOC_CREGISTER :
  285. begin
  286. regset := regset + [paramloc.register];
  287. if ((paramloc.size in [OS_S64,OS_64]) and
  288. (sizeof(aword) < 8))
  289. then
  290. begin
  291. regset := regset + [paramloc.registerhigh];
  292. end;
  293. end;
  294. else
  295. internalerror(20020816);
  296. end;
  297. getfuncretusedregisters:=regset;
  298. end;
  299. procedure setparalocs(p : tprocdef);
  300. var
  301. hp : tparaitem;
  302. begin
  303. hp:=tparaitem(p.para.first);
  304. while assigned(hp) do
  305. begin
  306. if (hp.paraloc.loc in [LOC_REGISTER,LOC_FPUREGISTER,
  307. LOC_MMREGISTER]) and
  308. (
  309. (vo_regable in tvarsym(hp.parasym).varoptions) or
  310. (vo_fpuregable in tvarsym(hp.parasym).varoptions) or
  311. paramanager.push_addr_param(hp.paratype.def,p.proccalloption) or
  312. (hp.paratyp in [vs_var,vs_out])
  313. ) then
  314. begin
  315. case hp.paraloc.loc of
  316. LOC_REGISTER:
  317. hp.paraloc.loc := LOC_CREGISTER;
  318. LOC_FPUREGISTER:
  319. hp.paraloc.loc := LOC_CFPUREGISTER;
  320. {$ifdef SUPPORT_MMX}
  321. LOC_MMREGISTER:
  322. hp.paraloc.loc := LOC_CMMREGISTER;
  323. {$endif}
  324. end;
  325. tvarsym(hp.parasym).paraitem:=hp;
  326. end;
  327. hp:=tparaitem(hp.next);
  328. end;
  329. end;
  330. initialization
  331. ;
  332. finalization
  333. paramanager.free;
  334. end.
  335. {
  336. $Log$
  337. Revision 1.25 2002-11-27 02:33:19 peter
  338. * copy_value_on_stack method added for cdecl record passing
  339. Revision 1.24 2002/11/25 17:43:21 peter
  340. * splitted defbase in defutil,symutil,defcmp
  341. * merged isconvertable and is_equal into compare_defs(_ext)
  342. * made operator search faster by walking the list only once
  343. Revision 1.23 2002/11/18 17:31:58 peter
  344. * pass proccalloption to ret_in_xxx and push_xxx functions
  345. Revision 1.22 2002/11/16 18:00:04 peter
  346. * only push small arrays on the stack for win32
  347. Revision 1.21 2002/10/05 12:43:25 carl
  348. * fixes for Delphi 6 compilation
  349. (warning : Some features do not work under Delphi)
  350. Revision 1.20 2002/09/30 07:07:25 florian
  351. * fixes to common code to get the alpha compiler compiled applied
  352. Revision 1.19 2002/09/30 07:00:47 florian
  353. * fixes to common code to get the alpha compiler compiled applied
  354. Revision 1.18 2002/09/09 09:10:51 florian
  355. + added generic tparamanager.getframepointerloc
  356. Revision 1.17 2002/09/07 19:40:39 florian
  357. * tvarsym.paraitem is set now
  358. Revision 1.16 2002/09/01 21:04:48 florian
  359. * several powerpc related stuff fixed
  360. Revision 1.15 2002/08/25 19:25:19 peter
  361. * sym.insert_in_data removed
  362. * symtable.insertvardata/insertconstdata added
  363. * removed insert_in_data call from symtable.insert, it needs to be
  364. called separatly. This allows to deref the address calculation
  365. * procedures now calculate the parast addresses after the procedure
  366. directives are parsed. This fixes the cdecl parast problem
  367. * push_addr_param has an extra argument that specifies if cdecl is used
  368. or not
  369. Revision 1.14 2002/08/17 22:09:47 florian
  370. * result type handling in tcgcal.pass_2 overhauled
  371. * better tnode.dowrite
  372. * some ppc stuff fixed
  373. Revision 1.13 2002/08/17 09:23:38 florian
  374. * first part of procinfo rewrite
  375. Revision 1.12 2002/08/16 14:24:58 carl
  376. * issameref() to test if two references are the same (then emit no opcodes)
  377. + ret_in_reg to replace ret_in_acc
  378. (fix some register allocation bugs at the same time)
  379. + save_std_register now has an extra parameter which is the
  380. usedinproc registers
  381. Revision 1.11 2002/08/12 15:08:40 carl
  382. + stab register indexes for powerpc (moved from gdb to cpubase)
  383. + tprocessor enumeration moved to cpuinfo
  384. + linker in target_info is now a class
  385. * many many updates for m68k (will soon start to compile)
  386. - removed some ifdef or correct them for correct cpu
  387. Revision 1.10 2002/08/10 17:15:20 jonas
  388. * register parameters are now LOC_CREGISTER instead of LOC_REGISTER
  389. Revision 1.9 2002/08/09 07:33:02 florian
  390. * a couple of interface related fixes
  391. Revision 1.8 2002/08/06 20:55:21 florian
  392. * first part of ppc calling conventions fix
  393. Revision 1.7 2002/08/05 18:27:48 carl
  394. + more more more documentation
  395. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  396. Revision 1.6 2002/07/30 20:50:43 florian
  397. * the code generator knows now if parameters are in registers
  398. Revision 1.5 2002/07/26 21:15:39 florian
  399. * rewrote the system handling
  400. Revision 1.4 2002/07/20 11:57:55 florian
  401. * types.pas renamed to defbase.pas because D6 contains a types
  402. unit so this would conflicts if D6 programms are compiled
  403. + Willamette/SSE2 instructions to assembler added
  404. Revision 1.3 2002/07/13 19:38:43 florian
  405. * some more generic calling stuff fixed
  406. Revision 1.2 2002/07/13 07:17:15 jonas
  407. * fixed memory leak reported by Sergey Korshunoff
  408. Revision 1.1 2002/07/11 14:41:28 florian
  409. * start of the new generic parameter handling
  410. }