paramgr.pas 15 KB

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