cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Generates the argument location information for i386
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cpupara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. aasmtai,aasmdata,cpubase,cgbase,cgutils,
  23. symconst,symtype,symsym,symdef,
  24. parabase,paramgr;
  25. type
  26. ti386paramanager = class(tparamanager)
  27. function param_use_paraloc(const cgpara:tcgpara):boolean;override;
  28. function ret_in_param(def : tdef;calloption : tproccalloption) : boolean;override;
  29. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  30. function get_para_align(calloption : tproccalloption):byte;override;
  31. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  32. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  33. function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
  34. { Returns the location for the nr-st 32 Bit int parameter
  35. if every parameter before is an 32 Bit int parameter as well
  36. and if the calling conventions for the helper routines of the
  37. rtl are used.
  38. }
  39. procedure getintparaloc(calloption : tproccalloption; nr : longint; def : tdef; var cgpara : tcgpara);override;
  40. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  41. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  42. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
  43. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara;override;
  44. private
  45. procedure create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  46. procedure create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parareg,parasize:longint);
  47. end;
  48. implementation
  49. uses
  50. cutils,
  51. systems,verbose,
  52. symtable,
  53. defutil;
  54. const
  55. parasupregs : array[0..2] of tsuperregister = (RS_EAX,RS_EDX,RS_ECX);
  56. {****************************************************************************
  57. TI386PARAMANAGER
  58. ****************************************************************************}
  59. function ti386paramanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  60. var
  61. paraloc : pcgparalocation;
  62. begin
  63. if not assigned(cgpara.location) then
  64. internalerror(200410102);
  65. result:=true;
  66. { All locations are LOC_REFERENCE }
  67. paraloc:=cgpara.location;
  68. while assigned(paraloc) do
  69. begin
  70. if (paraloc^.loc<>LOC_REFERENCE) then
  71. begin
  72. result:=false;
  73. exit;
  74. end;
  75. paraloc:=paraloc^.next;
  76. end;
  77. end;
  78. function ti386paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  79. var
  80. size: longint;
  81. begin
  82. if (tf_safecall_exceptions in target_info.flags) and
  83. (calloption=pocall_safecall) then
  84. begin
  85. result:=true;
  86. exit;
  87. end;
  88. case target_info.system of
  89. system_i386_win32 :
  90. begin
  91. case def.typ of
  92. recorddef :
  93. begin
  94. { Win32 GCC returns small records in the FUNCTION_RETURN_REG.
  95. For stdcall we follow delphi instead of GCC }
  96. if (calloption in [pocall_cdecl,pocall_cppdecl]) and
  97. (def.size>0) and
  98. (def.size<=8) then
  99. begin
  100. result:=false;
  101. exit;
  102. end;
  103. end;
  104. end;
  105. end;
  106. system_i386_darwin,
  107. system_i386_iphonesim :
  108. begin
  109. case def.typ of
  110. recorddef :
  111. begin
  112. size := def.size;
  113. if (size > 0) and
  114. (size <= 8) and
  115. { only if size is a power of 2 }
  116. ((size and (size-1)) = 0) then
  117. begin
  118. result := false;
  119. exit;
  120. end;
  121. end;
  122. procvardef:
  123. begin
  124. result:=false;
  125. exit;
  126. end;
  127. end;
  128. end;
  129. end;
  130. result:=inherited ret_in_param(def,calloption);
  131. end;
  132. function ti386paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  133. begin
  134. result:=false;
  135. { var,out,constref always require address }
  136. if varspez in [vs_var,vs_out,vs_constref] then
  137. begin
  138. result:=true;
  139. exit;
  140. end;
  141. { Only vs_const, vs_value here }
  142. case def.typ of
  143. variantdef :
  144. begin
  145. { variants are small enough to be passed by value except if
  146. required by the windows api
  147. variants are somethings very delphi/windows specific so do it like
  148. windows/delphi (FK)
  149. }
  150. if ((target_info.system=system_i386_win32) and
  151. (calloption in [pocall_stdcall,pocall_safecall]) and
  152. (varspez=vs_const)) or
  153. (calloption=pocall_register) then
  154. result:=true
  155. else
  156. result:=false;
  157. end;
  158. formaldef :
  159. result:=true;
  160. recorddef :
  161. begin
  162. { Delphi stdcall passes records on the stack for call by value }
  163. if (target_info.system=system_i386_win32) and
  164. (calloption=pocall_stdcall) and
  165. (varspez=vs_value) then
  166. result:=false
  167. else
  168. result:=
  169. (not(calloption in (cdecl_pocalls+[pocall_mwpascal])) and
  170. (def.size>sizeof(aint))) or
  171. (((calloption = pocall_mwpascal) or (target_info.system=system_i386_wince)) and
  172. (varspez=vs_const));
  173. end;
  174. arraydef :
  175. begin
  176. { array of const values are pushed on the stack as
  177. well as dyn. arrays }
  178. if (calloption in cdecl_pocalls) then
  179. result:=not(is_array_of_const(def) or
  180. is_dynamic_array(def))
  181. else
  182. begin
  183. result:=(
  184. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  185. (def.size>sizeof(aint))
  186. ) or
  187. is_open_array(def) or
  188. is_array_of_const(def) or
  189. is_array_constructor(def);
  190. end;
  191. end;
  192. objectdef :
  193. result:=is_object(def);
  194. stringdef :
  195. result:= (tstringdef(def).stringtype in [st_shortstring,st_longstring]);
  196. procvardef :
  197. result:=not(calloption in cdecl_pocalls) and not tprocvardef(def).is_addressonly;
  198. setdef :
  199. result:=not(calloption in cdecl_pocalls) and (not is_smallset(def));
  200. end;
  201. end;
  202. function ti386paramanager.get_para_align(calloption : tproccalloption):byte;
  203. begin
  204. if calloption=pocall_oldfpccall then
  205. begin
  206. if target_info.system in [system_i386_go32v2,system_i386_watcom] then
  207. result:=2
  208. else
  209. result:=4;
  210. end
  211. else
  212. result:=std_param_align;
  213. end;
  214. function ti386paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  215. begin
  216. case calloption of
  217. pocall_internproc :
  218. result:=[];
  219. pocall_register,
  220. pocall_safecall,
  221. pocall_stdcall,
  222. pocall_cdecl,
  223. pocall_cppdecl,
  224. pocall_mwpascal :
  225. result:=[RS_EAX,RS_EDX,RS_ECX];
  226. pocall_far16,
  227. pocall_pascal,
  228. pocall_oldfpccall :
  229. result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX];
  230. else
  231. internalerror(200309071);
  232. end;
  233. end;
  234. function ti386paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  235. begin
  236. result:=[0..first_fpu_imreg-1];
  237. end;
  238. function ti386paramanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  239. begin
  240. result:=[0..first_mm_imreg-1];
  241. end;
  242. procedure ti386paramanager.getintparaloc(calloption : tproccalloption; nr : longint; def : tdef; var cgpara : tcgpara);
  243. var
  244. paraloc : pcgparalocation;
  245. begin
  246. cgpara.reset;
  247. cgpara.size:=def_cgsize(def);
  248. cgpara.intsize:=tcgsize2size[cgpara.size];
  249. cgpara.alignment:=get_para_align(calloption);
  250. cgpara.def:=def;
  251. paraloc:=cgpara.add_location;
  252. with paraloc^ do
  253. begin
  254. size:=OS_INT;
  255. if calloption=pocall_register then
  256. begin
  257. if (nr<=length(parasupregs)) then
  258. begin
  259. if nr=0 then
  260. internalerror(200309271);
  261. loc:=LOC_REGISTER;
  262. register:=newreg(R_INTREGISTER,parasupregs[nr-1],R_SUBWHOLE);
  263. end
  264. else
  265. begin
  266. loc:=LOC_REFERENCE;
  267. reference.index:=NR_STACK_POINTER_REG;
  268. { the previous parameters didn't take up room in memory }
  269. reference.offset:=sizeof(aint)*(nr-length(parasupregs)-1)
  270. end;
  271. end
  272. else
  273. begin
  274. loc:=LOC_REFERENCE;
  275. reference.index:=NR_STACK_POINTER_REG;
  276. reference.offset:=sizeof(aint)*nr;
  277. end;
  278. end;
  279. end;
  280. function ti386paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara;
  281. var
  282. retcgsize : tcgsize;
  283. paraloc : pcgparalocation;
  284. sym: tfieldvarsym;
  285. usedef: tdef;
  286. handled: boolean;
  287. begin
  288. if not assigned(forcetempdef) then
  289. usedef:=p.returndef
  290. else
  291. usedef:=forcetempdef;
  292. { on darwin/i386, if a record has only one field and that field is a
  293. single or double, it has to be returned like a single/double }
  294. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  295. ((usedef.typ=recorddef) or
  296. is_object(usedef)) and
  297. tabstractrecordsymtable(tabstractrecorddef(usedef).symtable).has_single_field(sym) and
  298. (sym.vardef.typ=floatdef) and
  299. (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then
  300. usedef:=sym.vardef;
  301. handled:=set_common_funcretloc_info(p,usedef,retcgsize,result);
  302. { normally forcetempdef is passed straight through to
  303. set_common_funcretloc_info and that one will correctly determine whether
  304. the location is a temporary one, but that doesn't work here because we
  305. sometimes have to change the type }
  306. result.temporary:=assigned(forcetempdef);
  307. if handled then
  308. exit;
  309. { darwin/x86 requires that results < sizeof(aint) are sign/zero
  310. extended to sizeof(aint) }
  311. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  312. (side=calleeside) and
  313. (result.intsize>0) and
  314. (result.intsize<sizeof(aint)) then
  315. begin
  316. result.def:=sinttype;
  317. result.intsize:=sizeof(aint);
  318. retcgsize:=OS_SINT;
  319. result.size:=retcgsize;
  320. end;
  321. { Return in FPU register? }
  322. if result.def.typ=floatdef then
  323. begin
  324. paraloc:=result.add_location;
  325. paraloc^.loc:=LOC_FPUREGISTER;
  326. paraloc^.register:=NR_FPU_RESULT_REG;
  327. paraloc^.size:=retcgsize;
  328. end
  329. else
  330. { Return in register }
  331. begin
  332. paraloc:=result.add_location;
  333. paraloc^.loc:=LOC_REGISTER;
  334. if retcgsize in [OS_64,OS_S64] then
  335. begin
  336. { low 32bits }
  337. if side=callerside then
  338. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  339. else
  340. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  341. paraloc^.size:=OS_32;
  342. { high 32bits }
  343. paraloc:=result.add_location;
  344. paraloc^.loc:=LOC_REGISTER;
  345. if side=callerside then
  346. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  347. else
  348. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  349. paraloc^.size:=OS_32;
  350. end
  351. else
  352. begin
  353. paraloc^.size:=retcgsize;
  354. if side=callerside then
  355. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  356. else
  357. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  358. end;
  359. end;
  360. end;
  361. procedure ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  362. var
  363. i : integer;
  364. hp : tparavarsym;
  365. paradef : tdef;
  366. paraloc : pcgparalocation;
  367. l,
  368. paralen,
  369. varalign : longint;
  370. paraalign : shortint;
  371. pushaddr : boolean;
  372. paracgsize : tcgsize;
  373. begin
  374. paraalign:=get_para_align(p.proccalloption);
  375. { we push Flags and CS as long
  376. to cope with the IRETD
  377. and we save 6 register + 4 selectors }
  378. if po_interrupt in p.procoptions then
  379. inc(parasize,8+6*4+4*2);
  380. { Offset is calculated like:
  381. sub esp,12
  382. mov [esp+8],para3
  383. mov [esp+4],para2
  384. mov [esp],para1
  385. call function
  386. That means for pushes the para with the
  387. highest offset (see para3) needs to be pushed first
  388. }
  389. if p.proccalloption in pushleftright_pocalls then
  390. i:=paras.count-1
  391. else
  392. i:=0;
  393. while ((p.proccalloption in pushleftright_pocalls) and (i>=0)) or
  394. (not(p.proccalloption in pushleftright_pocalls) and (i<=paras.count-1)) do
  395. begin
  396. hp:=tparavarsym(paras[i]);
  397. paradef:=hp.vardef;
  398. pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption);
  399. if pushaddr then
  400. begin
  401. paralen:=sizeof(aint);
  402. paracgsize:=OS_ADDR;
  403. paradef:=getpointerdef(paradef);
  404. end
  405. else
  406. begin
  407. paralen:=push_size(hp.varspez,paradef,p.proccalloption);
  408. { darwin/x86 requires that parameters < sizeof(aint) are sign/ }
  409. { zero extended to sizeof(aint) }
  410. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  411. (side = callerside) and
  412. (paralen > 0) and
  413. (paralen < sizeof(aint)) then
  414. begin
  415. paralen:=sizeof(aint);
  416. paracgsize:=OS_SINT;
  417. paradef:=sinttype;
  418. end
  419. else
  420. paracgsize:=def_cgsize(paradef);
  421. end;
  422. hp.paraloc[side].reset;
  423. hp.paraloc[side].size:=paracgsize;
  424. hp.paraloc[side].intsize:=paralen;
  425. hp.paraloc[side].def:=paradef;
  426. hp.paraloc[side].Alignment:=paraalign;
  427. { Copy to stack? }
  428. if (paracgsize=OS_NO) or
  429. (use_fixed_stack) then
  430. begin
  431. paraloc:=hp.paraloc[side].add_location;
  432. paraloc^.loc:=LOC_REFERENCE;
  433. paraloc^.size:=paracgsize;
  434. if side=callerside then
  435. paraloc^.reference.index:=NR_STACK_POINTER_REG
  436. else
  437. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  438. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  439. { don't let push_size return 16, because then we can }
  440. { read past the end of the heap since the value is only }
  441. { 10 bytes long (JM) }
  442. if (paracgsize = OS_F80) and
  443. (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  444. paralen:=16;
  445. paraloc^.reference.offset:=parasize;
  446. if side=calleeside then
  447. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  448. parasize:=align(parasize+paralen,varalign);
  449. end
  450. else
  451. begin
  452. if paralen=0 then
  453. internalerror(200501163);
  454. while (paralen>0) do
  455. begin
  456. paraloc:=hp.paraloc[side].add_location;
  457. paraloc^.loc:=LOC_REFERENCE;
  458. { single and double need a single location }
  459. if (paracgsize in [OS_F64,OS_F32]) then
  460. begin
  461. paraloc^.size:=paracgsize;
  462. l:=paralen;
  463. end
  464. else
  465. begin
  466. { We can allocate at maximum 32 bits per location }
  467. if paralen>sizeof(aint) then
  468. l:=sizeof(aint)
  469. else
  470. l:=paralen;
  471. paraloc^.size:=int_cgsize(l);
  472. end;
  473. if (side=callerside) or
  474. (po_nostackframe in p.procoptions) then
  475. paraloc^.reference.index:=NR_STACK_POINTER_REG
  476. else
  477. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  478. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  479. paraloc^.reference.offset:=parasize;
  480. if side=calleeside then
  481. if not(po_nostackframe in p.procoptions) then
  482. inc(paraloc^.reference.offset,target_info.first_parm_offset)
  483. else
  484. { return addres }
  485. inc(paraloc^.reference.offset,4);
  486. parasize:=align(parasize+l,varalign);
  487. dec(paralen,l);
  488. end;
  489. end;
  490. if p.proccalloption in pushleftright_pocalls then
  491. dec(i)
  492. else
  493. inc(i);
  494. end;
  495. end;
  496. procedure ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  497. var parareg,parasize:longint);
  498. var
  499. hp : tparavarsym;
  500. paradef : tdef;
  501. paraloc : pcgparalocation;
  502. paracgsize : tcgsize;
  503. i : integer;
  504. l,
  505. paralen,
  506. varalign : longint;
  507. pushaddr : boolean;
  508. paraalign : shortint;
  509. pass : byte;
  510. begin
  511. if paras.count=0 then
  512. exit;
  513. paraalign:=get_para_align(p.proccalloption);
  514. { clean up here so we can later detect properly if a parameter has been
  515. assigned or not
  516. }
  517. for i:=0 to paras.count-1 do
  518. tparavarsym(paras[i]).paraloc[side].reset;
  519. { Register parameters are assigned from left to right,
  520. stack parameters from right to left so assign first the
  521. register parameters in a first pass, in the second
  522. pass all unhandled parameters are done }
  523. for pass:=1 to 2 do
  524. begin
  525. if pass=1 then
  526. i:=0
  527. else
  528. i:=paras.count-1;
  529. while true do
  530. begin
  531. hp:=tparavarsym(paras[i]);
  532. paradef:=hp.vardef;
  533. if not(assigned(hp.paraloc[side].location)) then
  534. begin
  535. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  536. if pushaddr then
  537. begin
  538. paralen:=sizeof(aint);
  539. paracgsize:=OS_ADDR;
  540. paradef:=getpointerdef(paradef);
  541. end
  542. else
  543. begin
  544. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  545. paracgsize:=def_cgsize(hp.vardef);
  546. end;
  547. hp.paraloc[side].size:=paracgsize;
  548. hp.paraloc[side].intsize:=paralen;
  549. hp.paraloc[side].Alignment:=paraalign;
  550. hp.paraloc[side].def:=paradef;
  551. {
  552. EAX
  553. EDX
  554. ECX
  555. Stack
  556. Stack
  557. 64bit values,floats,arrays and records are always
  558. on the stack.
  559. In case of po_delphi_nested_cc, the parent frame pointer
  560. is also always passed on the stack.
  561. }
  562. if (parareg<=high(parasupregs)) and
  563. (paralen<=sizeof(aint)) and
  564. (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
  565. pushaddr) and
  566. (not(vo_is_parentfp in hp.varoptions) or
  567. not(po_delphi_nested_cc in p.procoptions)) then
  568. begin
  569. if pass=1 then
  570. begin
  571. paraloc:=hp.paraloc[side].add_location;
  572. paraloc^.size:=paracgsize;
  573. paraloc^.loc:=LOC_REGISTER;
  574. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  575. inc(parareg);
  576. end;
  577. end
  578. else
  579. if pass=2 then
  580. begin
  581. { Copy to stack? }
  582. if (use_fixed_stack) or
  583. (paracgsize=OS_NO) then
  584. begin
  585. paraloc:=hp.paraloc[side].add_location;
  586. paraloc^.loc:=LOC_REFERENCE;
  587. paraloc^.size:=paracgsize;
  588. if side=callerside then
  589. paraloc^.reference.index:=NR_STACK_POINTER_REG
  590. else
  591. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  592. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  593. paraloc^.reference.offset:=parasize;
  594. if side=calleeside then
  595. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  596. parasize:=align(parasize+paralen,varalign);
  597. end
  598. else
  599. begin
  600. if paralen=0 then
  601. internalerror(200501163);
  602. while (paralen>0) do
  603. begin
  604. paraloc:=hp.paraloc[side].add_location;
  605. paraloc^.loc:=LOC_REFERENCE;
  606. { Extended and double need a single location }
  607. if (paracgsize in [OS_F64,OS_F32]) then
  608. begin
  609. paraloc^.size:=paracgsize;
  610. l:=paralen;
  611. end
  612. else
  613. begin
  614. { We can allocate at maximum 32 bits per location }
  615. if paralen>sizeof(aint) then
  616. l:=sizeof(aint)
  617. else
  618. l:=paralen;
  619. paraloc^.size:=int_cgsize(l);
  620. end;
  621. if side=callerside then
  622. paraloc^.reference.index:=NR_STACK_POINTER_REG
  623. else
  624. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  625. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  626. paraloc^.reference.offset:=parasize;
  627. if side=calleeside then
  628. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  629. parasize:=align(parasize+l,varalign);
  630. dec(paralen,l);
  631. end;
  632. end;
  633. end;
  634. end;
  635. case pass of
  636. 1:
  637. begin
  638. if i=paras.count-1 then
  639. break;
  640. inc(i);
  641. end;
  642. 2:
  643. begin
  644. if i=0 then
  645. break;
  646. dec(i);
  647. end;
  648. end;
  649. end;
  650. end;
  651. end;
  652. function ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  653. var
  654. parasize,
  655. parareg : longint;
  656. begin
  657. parasize:=0;
  658. parareg:=0;
  659. case p.proccalloption of
  660. pocall_register :
  661. create_register_paraloc_info(p,side,p.paras,parareg,parasize);
  662. pocall_internproc :
  663. begin
  664. { Use default calling }
  665. {$warnings off}
  666. if (pocall_default=pocall_register) then
  667. create_register_paraloc_info(p,side,p.paras,parareg,parasize)
  668. else
  669. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  670. {$warnings on}
  671. end;
  672. else
  673. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  674. end;
  675. create_funcretloc_info(p,side);
  676. result:=parasize;
  677. end;
  678. function ti386paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  679. var
  680. parasize : longint;
  681. begin
  682. parasize:=0;
  683. { calculate the registers for the normal parameters }
  684. create_stdcall_paraloc_info(p,callerside,p.paras,parasize);
  685. { append the varargs }
  686. create_stdcall_paraloc_info(p,callerside,varargspara,parasize);
  687. result:=parasize;
  688. end;
  689. procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  690. begin
  691. { Never a need for temps when value is pushed (calls inside parameters
  692. will simply allocate even more stack space for their parameters) }
  693. if not(use_fixed_stack) then
  694. can_use_final_stack_loc:=true;
  695. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  696. end;
  697. begin
  698. paramanager:=ti386paramanager.create;
  699. end.