paramgr.pas 21 KB

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