cpupara.pas 28 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;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; def: tdef): TCGPara;override;
  44. private
  45. procedure create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  46. procedure create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  47. procedure create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parareg,parasize:longint);
  48. end;
  49. implementation
  50. uses
  51. cutils,
  52. systems,verbose,
  53. symtable,
  54. defutil;
  55. const
  56. parasupregs : array[0..2] of tsuperregister = (RS_EAX,RS_EDX,RS_ECX);
  57. {****************************************************************************
  58. TI386PARAMANAGER
  59. ****************************************************************************}
  60. function ti386paramanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  61. var
  62. paraloc : pcgparalocation;
  63. begin
  64. if not assigned(cgpara.location) then
  65. internalerror(200410102);
  66. result:=true;
  67. { All locations are LOC_REFERENCE }
  68. paraloc:=cgpara.location;
  69. while assigned(paraloc) do
  70. begin
  71. if (paraloc^.loc<>LOC_REFERENCE) then
  72. begin
  73. result:=false;
  74. exit;
  75. end;
  76. paraloc:=paraloc^.next;
  77. end;
  78. end;
  79. function ti386paramanager.ret_in_param(def : tdef;calloption : tproccalloption) : boolean;
  80. var
  81. size: longint;
  82. begin
  83. if (tf_safecall_exceptions in target_info.flags) and
  84. (calloption=pocall_safecall) then
  85. begin
  86. result:=true;
  87. exit;
  88. end;
  89. case target_info.system of
  90. system_i386_win32 :
  91. begin
  92. case def.typ of
  93. recorddef :
  94. begin
  95. { Win32 GCC returns small records in the FUNCTION_RETURN_REG.
  96. For stdcall we follow delphi instead of GCC }
  97. if (calloption in [pocall_cdecl,pocall_cppdecl]) and
  98. (def.size>0) and
  99. (def.size<=8) then
  100. begin
  101. result:=false;
  102. exit;
  103. end;
  104. end;
  105. end;
  106. end;
  107. system_i386_darwin,
  108. system_i386_iphonesim :
  109. begin
  110. case def.typ of
  111. recorddef :
  112. begin
  113. size := def.size;
  114. if (size > 0) and
  115. (size <= 8) and
  116. { only if size is a power of 2 }
  117. ((size and (size-1)) = 0) then
  118. begin
  119. result := false;
  120. exit;
  121. end;
  122. end;
  123. procvardef:
  124. begin
  125. result:=false;
  126. exit;
  127. end;
  128. end;
  129. end;
  130. end;
  131. result:=inherited ret_in_param(def,calloption);
  132. end;
  133. function ti386paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  134. begin
  135. result:=false;
  136. { var,out,constref always require address }
  137. if varspez in [vs_var,vs_out,vs_constref] then
  138. begin
  139. result:=true;
  140. exit;
  141. end;
  142. { Only vs_const, vs_value here }
  143. case def.typ of
  144. variantdef :
  145. begin
  146. { variants are small enough to be passed by value except if
  147. required by the windows api
  148. variants are somethings very delphi/windows specific so do it like
  149. windows/delphi (FK)
  150. }
  151. if ((target_info.system=system_i386_win32) and
  152. (calloption=pocall_stdcall) and
  153. (varspez=vs_const)) or
  154. (calloption=pocall_register) then
  155. result:=true
  156. else
  157. result:=false;
  158. end;
  159. formaldef :
  160. result:=true;
  161. recorddef :
  162. begin
  163. { Delphi stdcall passes records on the stack for call by value }
  164. if (target_info.system=system_i386_win32) and
  165. (calloption=pocall_stdcall) and
  166. (varspez=vs_value) then
  167. result:=false
  168. else
  169. result:=
  170. (not(calloption in (cdecl_pocalls+[pocall_mwpascal])) and
  171. (def.size>sizeof(aint))) or
  172. (((calloption = pocall_mwpascal) or (target_info.system=system_i386_wince)) and
  173. (varspez=vs_const));
  174. end;
  175. arraydef :
  176. begin
  177. { array of const values are pushed on the stack as
  178. well as dyn. arrays }
  179. if (calloption in cdecl_pocalls) then
  180. result:=not(is_array_of_const(def) or
  181. is_dynamic_array(def))
  182. else
  183. begin
  184. result:=(
  185. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  186. (def.size>sizeof(aint))
  187. ) or
  188. is_open_array(def) or
  189. is_array_of_const(def) or
  190. is_array_constructor(def);
  191. end;
  192. end;
  193. objectdef :
  194. result:=is_object(def);
  195. stringdef :
  196. result:= (tstringdef(def).stringtype in [st_shortstring,st_longstring]);
  197. procvardef :
  198. result:=not(calloption in cdecl_pocalls) and not tprocvardef(def).is_addressonly;
  199. setdef :
  200. result:=not(calloption in cdecl_pocalls) and (not is_smallset(def));
  201. end;
  202. end;
  203. function ti386paramanager.get_para_align(calloption : tproccalloption):byte;
  204. begin
  205. if calloption=pocall_oldfpccall then
  206. begin
  207. if target_info.system in [system_i386_go32v2,system_i386_watcom] then
  208. result:=2
  209. else
  210. result:=4;
  211. end
  212. else
  213. result:=std_param_align;
  214. end;
  215. function ti386paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  216. begin
  217. case calloption of
  218. pocall_internproc :
  219. result:=[];
  220. pocall_register,
  221. pocall_safecall,
  222. pocall_stdcall,
  223. pocall_cdecl,
  224. pocall_cppdecl,
  225. pocall_mwpascal :
  226. result:=[RS_EAX,RS_EDX,RS_ECX];
  227. pocall_far16,
  228. pocall_pascal,
  229. pocall_oldfpccall :
  230. result:=[RS_EAX,RS_EDX,RS_ECX,RS_ESI,RS_EDI,RS_EBX];
  231. else
  232. internalerror(200309071);
  233. end;
  234. end;
  235. function ti386paramanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  236. begin
  237. result:=[0..first_fpu_imreg-1];
  238. end;
  239. function ti386paramanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  240. begin
  241. result:=[0..first_mm_imreg-1];
  242. end;
  243. procedure ti386paramanager.getintparaloc(calloption : tproccalloption; nr : longint;var cgpara:TCGPara);
  244. var
  245. paraloc : pcgparalocation;
  246. begin
  247. cgpara.reset;
  248. cgpara.size:=OS_ADDR;
  249. cgpara.intsize:=sizeof(pint);
  250. cgpara.alignment:=get_para_align(calloption);
  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<=high(parasupregs)+1) 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. reference.offset:=sizeof(aint)*nr;
  269. end;
  270. end
  271. else
  272. begin
  273. loc:=LOC_REFERENCE;
  274. reference.index:=NR_STACK_POINTER_REG;
  275. reference.offset:=sizeof(aint)*nr;
  276. end;
  277. end;
  278. end;
  279. procedure ti386paramanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  280. begin
  281. p.funcretloc[side]:=get_funcretloc(p,side,p.returndef);
  282. end;
  283. function ti386paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): TCGPara;
  284. var
  285. retcgsize : tcgsize;
  286. paraloc : pcgparalocation;
  287. sym: tfieldvarsym;
  288. begin
  289. result.init;
  290. result.alignment:=get_para_align(p.proccalloption);
  291. { void has no location }
  292. if is_void(def) then
  293. begin
  294. paraloc:=result.add_location;
  295. result.size:=OS_NO;
  296. result.intsize:=0;
  297. paraloc^.size:=OS_NO;
  298. paraloc^.loc:=LOC_VOID;
  299. exit;
  300. end;
  301. { on darwin/i386, if a record has only one field and that field is a
  302. single or double, it has to be returned like a single/double }
  303. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  304. ((def.typ=recorddef) or
  305. is_object(def)) and
  306. tabstractrecordsymtable(tabstractrecorddef(def).symtable).has_single_field(sym) and
  307. (sym.vardef.typ=floatdef) and
  308. (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then
  309. def:=sym.vardef;
  310. { Constructors return self instead of a boolean }
  311. if (p.proctypeoption=potype_constructor) then
  312. begin
  313. retcgsize:=OS_ADDR;
  314. result.intsize:=sizeof(pint);
  315. end
  316. else
  317. begin
  318. retcgsize:=def_cgsize(def);
  319. result.intsize:=def.size;
  320. end;
  321. result.size:=retcgsize;
  322. { Return is passed as var parameter }
  323. if ret_in_param(def,p.proccalloption) then
  324. begin
  325. paraloc:=result.add_location;
  326. paraloc^.loc:=LOC_REFERENCE;
  327. paraloc^.size:=retcgsize;
  328. exit;
  329. end;
  330. { Return in FPU register? }
  331. if def.typ=floatdef then
  332. begin
  333. paraloc:=result.add_location;
  334. paraloc^.loc:=LOC_FPUREGISTER;
  335. paraloc^.register:=NR_FPU_RESULT_REG;
  336. paraloc^.size:=retcgsize;
  337. end
  338. else
  339. { Return in register }
  340. begin
  341. paraloc:=result.add_location;
  342. paraloc^.loc:=LOC_REGISTER;
  343. if retcgsize in [OS_64,OS_S64] then
  344. begin
  345. { low 32bits }
  346. if side=callerside then
  347. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  348. else
  349. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  350. paraloc^.size:=OS_32;
  351. { high 32bits }
  352. paraloc:=result.add_location;
  353. paraloc^.loc:=LOC_REGISTER;
  354. if side=callerside then
  355. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  356. else
  357. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  358. paraloc^.size:=OS_32;
  359. end
  360. else
  361. begin
  362. paraloc^.size:=retcgsize;
  363. if side=callerside then
  364. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  365. else
  366. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  367. end;
  368. end;
  369. end;
  370. procedure ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  371. var
  372. i : integer;
  373. hp : tparavarsym;
  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. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  406. if pushaddr then
  407. begin
  408. paralen:=sizeof(aint);
  409. paracgsize:=OS_ADDR;
  410. end
  411. else
  412. begin
  413. paralen:=push_size(hp.varspez,hp.vardef,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_INT;
  423. end
  424. else
  425. paracgsize:=def_cgsize(hp.vardef);
  426. end;
  427. hp.paraloc[side].reset;
  428. hp.paraloc[side].size:=paracgsize;
  429. hp.paraloc[side].intsize:=paralen;
  430. hp.paraloc[side].Alignment:=paraalign;
  431. { Copy to stack? }
  432. if (paracgsize=OS_NO) or
  433. (use_fixed_stack) then
  434. begin
  435. paraloc:=hp.paraloc[side].add_location;
  436. paraloc^.loc:=LOC_REFERENCE;
  437. paraloc^.size:=paracgsize;
  438. if side=callerside then
  439. paraloc^.reference.index:=NR_STACK_POINTER_REG
  440. else
  441. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  442. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  443. { don't let push_size return 16, because then we can }
  444. { read past the end of the heap since the value is only }
  445. { 10 bytes long (JM) }
  446. if (paracgsize = OS_F80) and
  447. (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  448. paralen:=16;
  449. paraloc^.reference.offset:=parasize;
  450. if side=calleeside then
  451. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  452. parasize:=align(parasize+paralen,varalign);
  453. end
  454. else
  455. begin
  456. if paralen=0 then
  457. internalerror(200501163);
  458. while (paralen>0) do
  459. begin
  460. paraloc:=hp.paraloc[side].add_location;
  461. paraloc^.loc:=LOC_REFERENCE;
  462. { single and double need a single location }
  463. if (paracgsize in [OS_F64,OS_F32]) then
  464. begin
  465. paraloc^.size:=paracgsize;
  466. l:=paralen;
  467. end
  468. else
  469. begin
  470. { We can allocate at maximum 32 bits per location }
  471. if paralen>sizeof(aint) then
  472. l:=sizeof(aint)
  473. else
  474. l:=paralen;
  475. paraloc^.size:=int_cgsize(l);
  476. end;
  477. if (side=callerside) or
  478. (po_nostackframe in p.procoptions) then
  479. paraloc^.reference.index:=NR_STACK_POINTER_REG
  480. else
  481. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  482. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  483. paraloc^.reference.offset:=parasize;
  484. if side=calleeside then
  485. if not(po_nostackframe in p.procoptions) then
  486. inc(paraloc^.reference.offset,target_info.first_parm_offset)
  487. else
  488. { return addres }
  489. inc(paraloc^.reference.offset,4);
  490. parasize:=align(parasize+l,varalign);
  491. dec(paralen,l);
  492. end;
  493. end;
  494. if p.proccalloption in pushleftright_pocalls then
  495. dec(i)
  496. else
  497. inc(i);
  498. end;
  499. end;
  500. procedure ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  501. var parareg,parasize:longint);
  502. var
  503. hp : tparavarsym;
  504. paraloc : pcgparalocation;
  505. paracgsize : tcgsize;
  506. i : integer;
  507. l,
  508. paralen,
  509. varalign : longint;
  510. pushaddr : boolean;
  511. paraalign : shortint;
  512. pass : byte;
  513. begin
  514. if paras.count=0 then
  515. exit;
  516. paraalign:=get_para_align(p.proccalloption);
  517. { clean up here so we can later detect properly if a parameter has been
  518. assigned or not
  519. }
  520. for i:=0 to paras.count-1 do
  521. tparavarsym(paras[i]).paraloc[side].reset;
  522. { Register parameters are assigned from left to right,
  523. stack parameters from right to left so assign first the
  524. register parameters in a first pass, in the second
  525. pass all unhandled parameters are done }
  526. for pass:=1 to 2 do
  527. begin
  528. if pass=1 then
  529. i:=0
  530. else
  531. i:=paras.count-1;
  532. while true do
  533. begin
  534. hp:=tparavarsym(paras[i]);
  535. if not(assigned(hp.paraloc[side].location)) then
  536. begin
  537. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  538. if pushaddr then
  539. begin
  540. paralen:=sizeof(aint);
  541. paracgsize:=OS_ADDR;
  542. end
  543. else
  544. begin
  545. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  546. paracgsize:=def_cgsize(hp.vardef);
  547. end;
  548. hp.paraloc[side].size:=paracgsize;
  549. hp.paraloc[side].intsize:=paralen;
  550. hp.paraloc[side].Alignment:=paraalign;
  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.