paramgr.pas 21 KB

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