cpupara.pas 29 KB

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