paramgr.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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. aasmtai,
  28. symconst,symtype,symdef;
  29. type
  30. tvarargsinfo = (
  31. va_uses_float_reg
  32. );
  33. tvarargspara = class(tlinkedlist)
  34. varargsinfo : set of tvarargsinfo;
  35. {$ifdef x86_64}
  36. { x86_64 requires %al to contain the no. SSE regs passed }
  37. mmregsused : longint;
  38. {$endif x86_64}
  39. end;
  40. {# This class defines some methods to take care of routine
  41. parameters. It should be overriden for each new processor
  42. }
  43. tparamanager = class
  44. {# Returns true if the return value is actually a parameter
  45. pointer.
  46. }
  47. function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;virtual;
  48. function push_high_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;virtual;
  49. { Returns true if a parameter is too large to copy and only
  50. the address is pushed
  51. }
  52. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;virtual;
  53. { return the size of a push }
  54. function push_size(varspez:tvarspez;def : tdef;calloption : tproccalloption) : longint;
  55. { Returns true if a parameter needs to be copied on the stack, this
  56. is required for cdecl procedures
  57. }
  58. function copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;virtual;
  59. {# Returns a structure giving the information on
  60. the storage of the parameter (which must be
  61. an integer parameter). This is only used when calling
  62. internal routines directly, where all parameters must
  63. be 4-byte values.
  64. In case the location is a register, this register is allocated.
  65. Call freeintparaloc() after the call to free the locations again.
  66. Default implementation: don't do anything at all (in case you don't
  67. use register parameter passing)
  68. @param(list Current assembler list)
  69. @param(nr Parameter number of routine, starting from 1)
  70. }
  71. function get_para_align(calloption : tproccalloption):byte;virtual;
  72. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;virtual;
  73. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;virtual;
  74. function get_volatile_registers_flags(calloption : tproccalloption):tcpuregisterset;virtual;
  75. function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;virtual;
  76. function getintparaloc(calloption : tproccalloption; nr : longint) : tparalocation;virtual;abstract;
  77. {# allocate a parameter location created with create_paraloc_info
  78. @param(list Current assembler list)
  79. @param(loc Parameter location)
  80. }
  81. procedure allocparaloc(list: taasmoutput; const loc: tparalocation); virtual;
  82. {# free a parameter location allocated with allocparaloc
  83. @param(list Current assembler list)
  84. @param(loc Parameter location)
  85. }
  86. procedure freeparaloc(list: taasmoutput; const loc: tparalocation); virtual;
  87. { This is used to populate the location information on all parameters
  88. for the routine as seen in either the caller or the callee. It returns
  89. the size allocated on the stack
  90. }
  91. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;virtual;abstract;
  92. { This is used to populate the location information on all parameters
  93. for the routine when it is being inlined. It returns
  94. the size allocated on the stack
  95. }
  96. function create_inline_paraloc_info(p : tabstractprocdef):longint;virtual;
  97. { This is used to populate the location information on all parameters
  98. for the routine that are passed as varargs. It returns
  99. the size allocated on the stack (including the normal parameters)
  100. }
  101. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargspara):longint;virtual;abstract;
  102. { Return the location of the low and high part of a 64bit parameter }
  103. procedure splitparaloc64(const locpara:tparalocation;var loclopara,lochipara:tparalocation);virtual;
  104. procedure alloctempregs(list: taasmoutput;var locpara:tparalocation);virtual;
  105. procedure alloctempparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var locpara:tparalocation);virtual;
  106. function parseparaloc(paraitem : tparaitem;const s : string) : boolean;virtual;abstract;
  107. end;
  108. var
  109. paramanager : tparamanager;
  110. implementation
  111. uses
  112. cpuinfo,systems,
  113. cgutils,cgobj,tgobj,
  114. defutil,verbose;
  115. { true if uses a parameter as return value }
  116. function tparamanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  117. begin
  118. ret_in_param:=(def.deftype in [arraydef,recorddef]) or
  119. ((def.deftype=stringdef) and (tstringdef(def).string_typ in [st_shortstring,st_longstring])) or
  120. ((def.deftype=procvardef) and (po_methodpointer in tprocvardef(def).procoptions)) or
  121. ((def.deftype=objectdef) and is_object(def)) or
  122. (def.deftype=variantdef) or
  123. ((def.deftype=setdef) and (tsetdef(def).settype<>smallset));
  124. end;
  125. function tparamanager.push_high_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  126. begin
  127. push_high_param:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and
  128. (
  129. is_open_array(def) or
  130. is_open_string(def) or
  131. is_array_of_const(def)
  132. );
  133. end;
  134. { true if a parameter is too large to copy and only the address is pushed }
  135. function tparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  136. begin
  137. result:=false;
  138. { var,out always require address }
  139. if varspez in [vs_var,vs_out] then
  140. begin
  141. result:=true;
  142. exit;
  143. end;
  144. { Only vs_const, vs_value here }
  145. case def.deftype of
  146. variantdef,
  147. formaldef :
  148. result:=true;
  149. recorddef :
  150. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (def.size>sizeof(aint));
  151. arraydef :
  152. begin
  153. if (calloption in [pocall_cdecl,pocall_cppdecl]) then
  154. begin
  155. { array of const values are pushed on the stack }
  156. result:=not is_array_of_const(def);
  157. end
  158. else
  159. begin
  160. result:=(
  161. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  162. (def.size>sizeof(aint))
  163. ) or
  164. is_open_array(def) or
  165. is_array_of_const(def) or
  166. is_array_constructor(def);
  167. end;
  168. end;
  169. objectdef :
  170. result:=is_object(def);
  171. stringdef :
  172. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tstringdef(def).string_typ in [st_shortstring,st_longstring]);
  173. procvardef :
  174. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (po_methodpointer in tprocvardef(def).procoptions);
  175. setdef :
  176. result:=not(calloption in [pocall_cdecl,pocall_cppdecl]) and (tsetdef(def).settype<>smallset);
  177. end;
  178. end;
  179. { true if a parameter is too large to push and needs a concatcopy to get the value on the stack }
  180. function tparamanager.copy_value_on_stack(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  181. begin
  182. copy_value_on_stack:=false;
  183. { this is only for cdecl procedures with vs_const,vs_value }
  184. if not(
  185. (calloption in [pocall_cdecl,pocall_cppdecl]) and
  186. (varspez in [vs_value,vs_const])
  187. ) then
  188. exit;
  189. case def.deftype of
  190. variantdef,
  191. formaldef :
  192. copy_value_on_stack:=true;
  193. recorddef :
  194. copy_value_on_stack:=(def.size>sizeof(aint));
  195. arraydef :
  196. copy_value_on_stack:=(tarraydef(def).highrange>=tarraydef(def).lowrange) and
  197. (def.size>sizeof(aint));
  198. objectdef :
  199. copy_value_on_stack:=is_object(def);
  200. stringdef :
  201. copy_value_on_stack:=tstringdef(def).string_typ in [st_shortstring,st_longstring];
  202. procvardef :
  203. copy_value_on_stack:=(po_methodpointer in tprocvardef(def).procoptions);
  204. setdef :
  205. copy_value_on_stack:=(tsetdef(def).settype<>smallset);
  206. end;
  207. end;
  208. { return the size of a push }
  209. function tparamanager.push_size(varspez:tvarspez;def : tdef;calloption : tproccalloption) : longint;
  210. begin
  211. push_size:=-1;
  212. case varspez of
  213. vs_out,
  214. vs_var :
  215. push_size:=sizeof(aint);
  216. vs_value,
  217. vs_const :
  218. begin
  219. if push_addr_param(varspez,def,calloption) then
  220. push_size:=sizeof(aint)
  221. else
  222. begin
  223. { special array are normally pushed by addr, only for
  224. cdecl array of const it comes here and the pushsize
  225. is unknown }
  226. if is_array_of_const(def) then
  227. push_size:=0
  228. else
  229. push_size:=def.size;
  230. end;
  231. end;
  232. end;
  233. end;
  234. function tparamanager.get_para_align(calloption : tproccalloption):byte;
  235. begin
  236. result:=std_param_align;
  237. end;
  238. function tparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  239. begin
  240. result:=[];
  241. end;
  242. function tparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  243. begin
  244. result:=[];
  245. end;
  246. function tparamanager.get_volatile_registers_flags(calloption : tproccalloption):tcpuregisterset;
  247. begin
  248. result:=[];
  249. end;
  250. function tparamanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  251. begin
  252. result:=[];
  253. end;
  254. procedure tparamanager.allocparaloc(list: taasmoutput; const loc: tparalocation);
  255. begin
  256. case loc.loc of
  257. LOC_REGISTER,
  258. LOC_CREGISTER,
  259. LOC_FPUREGISTER,
  260. LOC_CFPUREGISTER,
  261. LOC_MMREGISTER,
  262. LOC_CMMREGISTER :
  263. begin
  264. { NR_NO means we don't need to allocate the parameter.
  265. This is used for inlining parameters which allocates
  266. the parameters in gen_alloc_parast (PFV) }
  267. if loc.register<>NR_NO then
  268. cg.getexplicitregister(list,loc.register);
  269. end;
  270. LOC_REFERENCE,
  271. LOC_CREFERENCE :
  272. { do nothing by default, most of the time it's the framepointer }
  273. else
  274. internalerror(200306091);
  275. end;
  276. case loc.lochigh of
  277. LOC_INVALID :
  278. ;
  279. LOC_REGISTER,
  280. LOC_CREGISTER,
  281. LOC_FPUREGISTER,
  282. LOC_CFPUREGISTER,
  283. LOC_MMREGISTER,
  284. LOC_CMMREGISTER :
  285. begin
  286. { NR_NO means we don't need to allocate the parameter.
  287. This is used for inlining parameters which allocates
  288. the parameters in gen_alloc_parast (PFV) }
  289. if loc.registerhigh<>NR_NO then
  290. cg.getexplicitregister(list,loc.registerhigh);
  291. end;
  292. else
  293. internalerror(200306092);
  294. end;
  295. end;
  296. procedure tparamanager.freeparaloc(list: taasmoutput; const loc: tparalocation);
  297. var
  298. href : treference;
  299. begin
  300. case loc.loc of
  301. LOC_REGISTER, LOC_CREGISTER:
  302. begin
  303. {$ifndef cpu64bit}
  304. if (loc.size in [OS_64,OS_S64,OS_F64]) then
  305. begin
  306. cg.ungetregister(list,loc.registerhigh);
  307. cg.ungetregister(list,loc.registerlow);
  308. end
  309. else
  310. {$endif cpu64bit}
  311. cg.ungetregister(list,loc.register);
  312. end;
  313. LOC_MMREGISTER, LOC_CMMREGISTER,
  314. LOC_FPUREGISTER, LOC_CFPUREGISTER:
  315. cg.ungetregister(list,loc.register);
  316. LOC_REFERENCE,LOC_CREFERENCE:
  317. begin
  318. {$ifdef cputargethasfixedstack}
  319. reference_reset_base(href,loc.reference.index,loc.reference.offset);
  320. tg.ungettemp(list,href);
  321. {$endif cputargethasfixedstack}
  322. end;
  323. else
  324. internalerror(200306093);
  325. end;
  326. case loc.lochigh of
  327. LOC_INVALID :
  328. ;
  329. LOC_REGISTER,
  330. LOC_CREGISTER,
  331. LOC_FPUREGISTER,
  332. LOC_CFPUREGISTER,
  333. LOC_MMREGISTER,
  334. LOC_CMMREGISTER :
  335. cg.ungetregister(list,loc.register);
  336. else
  337. internalerror(200306094);
  338. end;
  339. end;
  340. procedure tparamanager.splitparaloc64(const locpara:tparalocation;var loclopara,lochipara:tparalocation);
  341. begin
  342. lochipara:=locpara;
  343. loclopara:=locpara;
  344. case locpara.size of
  345. OS_S128 :
  346. begin
  347. lochipara.size:=OS_S64;
  348. loclopara.size:=OS_64;
  349. end;
  350. OS_128 :
  351. begin
  352. lochipara.size:=OS_64;
  353. loclopara.size:=OS_64;
  354. end;
  355. OS_S64 :
  356. begin
  357. lochipara.size:=OS_S32;
  358. loclopara.size:=OS_32;
  359. end;
  360. OS_64 :
  361. begin
  362. lochipara.size:=OS_32;
  363. loclopara.size:=OS_32;
  364. end;
  365. else
  366. internalerror(200307023);
  367. end;
  368. loclopara.lochigh:=LOC_INVALID;
  369. lochipara.lochigh:=LOC_INVALID;
  370. case locpara.loc of
  371. LOC_REGISTER,
  372. LOC_CREGISTER,
  373. LOC_FPUREGISTER,
  374. LOC_CFPUREGISTER,
  375. LOC_MMREGISTER,
  376. LOC_CMMREGISTER :
  377. begin
  378. if locpara.lochigh=LOC_INVALID then
  379. internalerror(200402061);
  380. loclopara.register:=locpara.registerlow;
  381. lochipara.register:=locpara.registerhigh;
  382. end;
  383. LOC_REFERENCE:
  384. begin
  385. if target_info.endian=endian_big then
  386. inc(loclopara.reference.offset,tcgsize2size[loclopara.size])
  387. else
  388. inc(lochipara.reference.offset,tcgsize2size[loclopara.size]);
  389. end;
  390. else
  391. internalerror(200307024);
  392. end;
  393. end;
  394. procedure tparamanager.alloctempregs(list: taasmoutput;var locpara:tparalocation);
  395. var
  396. cgsize : tcgsize;
  397. begin
  398. if locpara.lochigh<>LOC_INVALID then
  399. cgsize:=OS_INT
  400. else
  401. cgsize:=locpara.size;
  402. case locpara.loc of
  403. LOC_REGISTER:
  404. locpara.register:=cg.getintregister(list,cgsize);
  405. LOC_FPUREGISTER:
  406. locpara.register:=cg.getfpuregister(list,cgsize);
  407. LOC_MMREGISTER:
  408. locpara.register:=cg.getmmregister(list,cgsize);
  409. else
  410. internalerror(200308123);
  411. end;
  412. case locpara.lochigh of
  413. LOC_INVALID:
  414. ;
  415. LOC_REGISTER:
  416. locpara.registerhigh:=cg.getintregister(list,cgsize);
  417. LOC_FPUREGISTER:
  418. locpara.registerhigh:=cg.getfpuregister(list,cgsize);
  419. LOC_MMREGISTER:
  420. locpara.registerhigh:=cg.getmmregister(list,cgsize);
  421. else
  422. internalerror(200308124);
  423. end;
  424. end;
  425. procedure tparamanager.alloctempparaloc(list: taasmoutput;calloption : tproccalloption;paraitem : tparaitem;var locpara:tparalocation);
  426. var
  427. href : treference;
  428. l : aint;
  429. begin
  430. l:=push_size(paraitem.paratyp,paraitem.paratype.def,calloption);
  431. tg.gettemp(list,l,tt_persistent,href);
  432. locpara.loc:=LOC_REFERENCE;
  433. locpara.lochigh:=LOC_INVALID;
  434. locpara.reference.index:=href.base;
  435. locpara.reference.offset:=href.offset;
  436. end;
  437. function tparamanager.create_inline_paraloc_info(p : tabstractprocdef):longint;
  438. var
  439. hp : tparaitem;
  440. paraloc : tparalocation;
  441. parasize : longint;
  442. begin
  443. parasize:=0;
  444. hp:=tparaitem(p.para.first);
  445. while assigned(hp) do
  446. begin
  447. if push_addr_param(hp.paratyp,hp.paratype.def,p.proccalloption) then
  448. paraloc.size:=OS_ADDR
  449. else
  450. paraloc.size:=def_cgsize(hp.paratype.def);
  451. if paraloc.size=OS_NO then
  452. internalerror(200309301);
  453. { Indicate parameter is loaded in register, the register
  454. will be allocated when the allocpara is called }
  455. paraloc.loc:=LOC_REGISTER;
  456. paraloc.register:=NR_NO;
  457. (*
  458. paraloc.loc:=LOC_REFERENCE;
  459. paraloc.reference.index:=NR_FRAME_POINTER_REG;
  460. l:=push_size(hp.paratyp,hp.paratype.def,p.proccalloption);
  461. varalign:=size_2_align(l);
  462. paraloc.reference.offset:=parasize+target_info.first_parm_offset;
  463. varalign:=used_align(varalign,p.paraalign,p.paraalign);
  464. parasize:=align(parasize+l,varalign);
  465. *)
  466. hp.paraloc[callerside]:=paraloc;
  467. hp.paraloc[calleeside]:=paraloc;
  468. hp:=tparaitem(hp.next);
  469. end;
  470. { We need to return the size allocated }
  471. result:=parasize;
  472. end;
  473. initialization
  474. ;
  475. finalization
  476. paramanager.free;
  477. end.
  478. {
  479. $Log$
  480. Revision 1.76 2004-06-20 08:55:30 florian
  481. * logs truncated
  482. Revision 1.75 2004/06/16 20:07:09 florian
  483. * dwarf branch merged
  484. Revision 1.74 2004/04/18 15:22:24 florian
  485. + location support for arguments, currently PowerPC/MorphOS only
  486. Revision 1.73.2.5 2004/05/03 20:18:52 peter
  487. * fixes for tprintf
  488. Revision 1.73.2.4 2004/05/02 20:20:59 florian
  489. * started to fix callee side result value handling
  490. Revision 1.73.2.3 2004/05/02 12:45:32 peter
  491. * enabled cpuhasfixedstack for x86-64 again
  492. * fixed size of temp allocation for parameters
  493. }