paramgr.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  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. cclasses,globtype,
  26. cpubase,cgbase,
  27. parabase,
  28. aasmtai,
  29. symconst,symtype,symdef;
  30. type
  31. {# This class defines some methods to take care of routine
  32. parameters. It should be overriden for each new processor
  33. }
  34. tparamanager = class
  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(varspez:tvarspez;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(varspez:tvarspez;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(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;virtual;
  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. In case the location is a register, this register is allocated.
  56. Call freeintparaloc() after the call to free the locations again.
  57. Default implementation: don't do anything at all (in case you don't
  58. use register parameter passing)
  59. @param(list Current assembler list)
  60. @param(nr Parameter number of routine, starting from 1)
  61. }
  62. function get_para_align(calloption : tproccalloption):byte;virtual;
  63. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;virtual;
  64. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;virtual;
  65. function get_volatile_registers_flags(calloption : tproccalloption):tcpuregisterset;virtual;
  66. function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;virtual;
  67. procedure getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);virtual;abstract;
  68. {# allocate a parameter location created with create_paraloc_info
  69. @param(list Current assembler list)
  70. @param(loc Parameter location)
  71. }
  72. procedure allocparaloc(list: taasmoutput; const cgpara: TCGPara); virtual;
  73. {# free a parameter location allocated with alloccgpara
  74. @param(list Current assembler list)
  75. @param(loc Parameter location)
  76. }
  77. procedure freeparaloc(list: taasmoutput; const cgpara: TCGPara); virtual;
  78. { This is used to populate the location information on all parameters
  79. for the routine as seen in either the caller or the callee. It returns
  80. the size allocated on the stack
  81. }
  82. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;virtual;abstract;
  83. { This is used to populate the location information on all parameters
  84. for the routine when it is being inlined. It returns
  85. the size allocated on the stack
  86. }
  87. function create_inline_paraloc_info(p : tabstractprocdef):longint;virtual;
  88. { This is used to populate the location information on all parameters
  89. for the routine that are passed as varargs. It returns
  90. the size allocated on the stack (including the normal parameters)
  91. }
  92. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;virtual;abstract;
  93. procedure createtempparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var cgpara:TCGPara);virtual;
  94. procedure duplicateparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var cgpara:TCGPara);
  95. function parseparaloc(paraitem : tparaitem;const s : string) : boolean;virtual;abstract;
  96. end;
  97. var
  98. paramanager : tparamanager;
  99. implementation
  100. uses
  101. systems,
  102. cgobj,tgobj,
  103. defutil,verbose;
  104. { true if uses a parameter as return value }
  105. function tparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  106. begin
  107. ret_in_param:=(def.deftype in [arraydef,recorddef]) or
  108. ((def.deftype=stringdef) and (tstringdef(def).string_typ in [st_shortstring,st_longstring])) or
  109. ((def.deftype=procvardef) and (po_methodpointer in tprocvardef(def).procoptions)) or
  110. ((def.deftype=objectdef) and is_object(def)) or
  111. (def.deftype=variantdef) or
  112. ((def.deftype=setdef) and (tsetdef(def).settype<>smallset));
  113. end;
  114. function tparamanager.push_high_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  115. begin
  116. push_high_param:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and
  117. (
  118. is_open_array(def) or
  119. is_open_string(def) or
  120. is_array_of_const(def)
  121. );
  122. end;
  123. { true if a parameter is too large to copy and only the address is pushed }
  124. function tparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  125. begin
  126. result:=false;
  127. { var,out always require address }
  128. if varspez in [vs_var,vs_out] then
  129. begin
  130. result:=true;
  131. exit;
  132. end;
  133. { Only vs_const, vs_value here }
  134. case def.deftype of
  135. variantdef,
  136. formaldef :
  137. result:=true;
  138. recorddef :
  139. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (def.size>sizeof(aint));
  140. arraydef :
  141. begin
  142. if (calloption in [pocall_cdecl,pocall_cppdecl]) then
  143. begin
  144. { array of const values are pushed on the stack }
  145. result:=not is_array_of_const(def);
  146. end
  147. else
  148. begin
  149. result:=(
  150. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  151. (def.size>sizeof(aint))
  152. ) or
  153. is_open_array(def) or
  154. is_array_of_const(def) or
  155. is_array_constructor(def);
  156. end;
  157. end;
  158. objectdef :
  159. result:=is_object(def);
  160. stringdef :
  161. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tstringdef(def).string_typ in [st_shortstring,st_longstring]);
  162. procvardef :
  163. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (po_methodpointer in tprocvardef(def).procoptions);
  164. setdef :
  165. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tsetdef(def).settype<>smallset);
  166. end;
  167. end;
  168. { true if a parameter is too large to push and needs a concatcopy to get the value on the stack }
  169. function tparamanager.copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  170. begin
  171. copy_value_on_stack:=false;
  172. { this is only for cdecl procedures with vs_const,vs_value }
  173. if not(
  174. (calloption in [pocall_cdecl,pocall_cppdecl]) and
  175. (varspez in [vs_value,vs_const])
  176. ) 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>sizeof(aint));
  184. arraydef :
  185. copy_value_on_stack:=(tarraydef(def).highrange>=tarraydef(def).lowrange) and
  186. (def.size>sizeof(aint));
  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:=sizeof(aint);
  205. vs_value,
  206. vs_const :
  207. begin
  208. if push_addr_param(varspez,def,calloption) then
  209. push_size:=sizeof(aint)
  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.get_para_align(calloption : tproccalloption):byte;
  224. begin
  225. result:=std_param_align;
  226. end;
  227. function tparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  228. begin
  229. result:=[];
  230. end;
  231. function tparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  232. begin
  233. result:=[];
  234. end;
  235. function tparamanager.get_volatile_registers_flags(calloption : tproccalloption):tcpuregisterset;
  236. begin
  237. result:=[];
  238. end;
  239. function tparamanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  240. begin
  241. result:=[];
  242. end;
  243. procedure tparamanager.allocparaloc(list: taasmoutput; const cgpara: TCGPara);
  244. var
  245. paraloc : pcgparalocation;
  246. begin
  247. paraloc:=cgpara.location;
  248. while assigned(paraloc) do
  249. begin
  250. case paraloc^.loc of
  251. LOC_REGISTER,
  252. LOC_CREGISTER:
  253. begin
  254. if getsupreg(paraloc^.register)<first_int_imreg then
  255. cg.getcpuregister(list,paraloc^.register);
  256. end;
  257. LOC_FPUREGISTER,
  258. LOC_CFPUREGISTER:
  259. begin
  260. if getsupreg(paraloc^.register)<first_fpu_imreg then
  261. cg.getcpuregister(list,paraloc^.register);
  262. end;
  263. LOC_MMREGISTER,
  264. LOC_CMMREGISTER :
  265. begin
  266. if getsupreg(paraloc^.register)<first_mm_imreg then
  267. cg.getcpuregister(list,paraloc^.register);
  268. end;
  269. end;
  270. paraloc:=paraloc^.next;
  271. end;
  272. end;
  273. procedure tparamanager.freeparaloc(list: taasmoutput; const cgpara: TCGPara);
  274. var
  275. paraloc : Pcgparalocation;
  276. {$ifdef cputargethasfixedstack}
  277. href : treference;
  278. {$endif cputargethasfixedstack}
  279. begin
  280. paraloc:=cgpara.location;
  281. while assigned(paraloc) do
  282. begin
  283. case paraloc^.loc of
  284. LOC_REGISTER,
  285. LOC_CREGISTER:
  286. begin
  287. if getsupreg(paraloc^.register)<first_int_imreg then
  288. cg.ungetcpuregister(list,paraloc^.register);
  289. end;
  290. LOC_FPUREGISTER,
  291. LOC_CFPUREGISTER:
  292. begin
  293. if getsupreg(paraloc^.register)<first_fpu_imreg then
  294. cg.ungetcpuregister(list,paraloc^.register);
  295. end;
  296. LOC_MMREGISTER,
  297. LOC_CMMREGISTER :
  298. begin
  299. if getsupreg(paraloc^.register)<first_mm_imreg then
  300. cg.ungetcpuregister(list,paraloc^.register);
  301. end;
  302. LOC_REFERENCE,
  303. LOC_CREFERENCE :
  304. begin
  305. {$ifdef cputargethasfixedstack}
  306. { don't use reference_reset_base, because that will depend on cgobj }
  307. fillchar(href,sizeof(href),0);
  308. href.base:=paraloc^.reference.index;
  309. href.offset:=paraloc^.reference.offset;
  310. tg.ungettemp(list,href);
  311. {$endif cputargethasfixedstack}
  312. end;
  313. end;
  314. paraloc:=paraloc^.next;
  315. end;
  316. end;
  317. procedure tparamanager.createtempparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var cgpara:TCGPara);
  318. var
  319. href : treference;
  320. len : aint;
  321. paraloc,
  322. newparaloc : pcgparalocation;
  323. begin
  324. cgpara.reset;
  325. cgpara.size:=paraitem.paraloc[callerside].size;
  326. cgpara.alignment:=paraitem.paraloc[callerside].alignment;
  327. paraloc:=paraitem.paraloc[callerside].location;
  328. while assigned(paraloc) do
  329. begin
  330. if paraloc^.size=OS_NO then
  331. len:=push_size(paraitem.paratyp,paraitem.paratype.def,calloption)
  332. else
  333. len:=tcgsize2size[paraloc^.size];
  334. newparaloc:=cgpara.add_location;
  335. newparaloc^.size:=paraloc^.size;
  336. {$warning maybe release this optimization for all targets?}
  337. {$ifdef sparc}
  338. { Does it fit a register? }
  339. if len<=sizeof(aint) then
  340. newparaloc^.loc:=LOC_REGISTER
  341. else
  342. {$endif sparc}
  343. newparaloc^.loc:=paraloc^.loc;
  344. case newparaloc^.loc of
  345. LOC_REGISTER :
  346. newparaloc^.register:=cg.getintregister(list,paraloc^.size);
  347. LOC_FPUREGISTER :
  348. newparaloc^.register:=cg.getfpuregister(list,paraloc^.size);
  349. LOC_MMREGISTER :
  350. newparaloc^.register:=cg.getmmregister(list,paraloc^.size);
  351. LOC_REFERENCE :
  352. begin
  353. tg.gettemp(list,len,tt_persistent,href);
  354. newparaloc^.reference.index:=href.base;
  355. newparaloc^.reference.offset:=href.offset;
  356. end;
  357. end;
  358. paraloc:=paraloc^.next;
  359. end;
  360. end;
  361. procedure tparamanager.duplicateparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var cgpara:TCGPara);
  362. var
  363. paraloc,
  364. newparaloc : pcgparalocation;
  365. begin
  366. cgpara.reset;
  367. cgpara.size:=paraitem.paraloc[callerside].size;
  368. cgpara.alignment:=paraitem.paraloc[callerside].alignment;
  369. paraloc:=paraitem.paraloc[callerside].location;
  370. while assigned(paraloc) do
  371. begin
  372. newparaloc:=cgpara.add_location;
  373. move(paraloc^,newparaloc^,sizeof(newparaloc^));
  374. newparaloc^.next:=nil;
  375. paraloc:=paraloc^.next;
  376. end;
  377. end;
  378. function tparamanager.create_inline_paraloc_info(p : tabstractprocdef):longint;
  379. begin
  380. { We need to return the size allocated }
  381. create_paraloc_info(p,callerside);
  382. result:=create_paraloc_info(p,calleeside);
  383. end;
  384. initialization
  385. ;
  386. finalization
  387. paramanager.free;
  388. end.
  389. {
  390. $Log$
  391. Revision 1.79 2004-09-25 14:23:54 peter
  392. * ungetregister is now only used for cpuregisters, renamed to
  393. ungetcpuregister
  394. * renamed (get|unget)explicitregister(s) to ..cpuregister
  395. * removed location-release/reference_release
  396. Revision 1.78 2004/09/21 17:25:12 peter
  397. * paraloc branch merged
  398. Revision 1.77.4.1 2004/08/31 20:43:06 peter
  399. * paraloc patch
  400. Revision 1.77 2004/07/09 23:41:04 jonas
  401. * support register parameters for inlined procedures + some inline
  402. cleanups
  403. Revision 1.76 2004/06/20 08:55:30 florian
  404. * logs truncated
  405. Revision 1.75 2004/06/16 20:07:09 florian
  406. * dwarf branch merged
  407. Revision 1.74 2004/04/18 15:22:24 florian
  408. + location support for arguments, currently PowerPC/MorphOS only
  409. Revision 1.73.2.5 2004/05/03 20:18:52 peter
  410. * fixes for tprintf
  411. Revision 1.73.2.4 2004/05/02 20:20:59 florian
  412. * started to fix callee side result value handling
  413. Revision 1.73.2.3 2004/05/02 12:45:32 peter
  414. * enabled cpuhasfixedstack for x86-64 again
  415. * fixed size of temp allocation for parameters
  416. }