paramgr.pas 19 KB

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