paramgr.pas 15 KB

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