cpupara.pas 29 KB

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