paramgr.pas 20 KB

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