paramgr.pas 21 KB

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