paramgr.pas 20 KB

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