paramgr.pas 20 KB

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