cpupara.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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 in [pocall_stdcall,pocall_safecall]) 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<=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. procedure ti386paramanager.create_funcretloc_info(p : tabstractprocdef; side: tcallercallee);
  281. begin
  282. p.funcretloc[side]:=get_funcretloc(p,side,p.returndef);
  283. end;
  284. function ti386paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; def: tdef): TCGPara;
  285. var
  286. retcgsize : tcgsize;
  287. paraloc : pcgparalocation;
  288. sym: tfieldvarsym;
  289. begin
  290. result.init;
  291. result.alignment:=get_para_align(p.proccalloption);
  292. { void has no location }
  293. if is_void(def) then
  294. begin
  295. paraloc:=result.add_location;
  296. result.size:=OS_NO;
  297. result.intsize:=0;
  298. paraloc^.size:=OS_NO;
  299. paraloc^.loc:=LOC_VOID;
  300. exit;
  301. end;
  302. { on darwin/i386, if a record has only one field and that field is a
  303. single or double, it has to be returned like a single/double }
  304. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  305. ((def.typ=recorddef) or
  306. is_object(def)) and
  307. tabstractrecordsymtable(tabstractrecorddef(def).symtable).has_single_field(sym) and
  308. (sym.vardef.typ=floatdef) and
  309. (tfloatdef(sym.vardef).floattype in [s32real,s64real]) then
  310. def:=sym.vardef;
  311. { Constructors return self instead of a boolean }
  312. if (p.proctypeoption=potype_constructor) then
  313. begin
  314. retcgsize:=OS_ADDR;
  315. result.intsize:=sizeof(pint);
  316. end
  317. else
  318. begin
  319. retcgsize:=def_cgsize(def);
  320. { darwin/x86 requires that results < sizeof(aint) are sign/ }
  321. { zero extended to sizeof(aint) }
  322. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  323. (side=calleeside) and
  324. (result.intsize>0) and
  325. (result.intsize<sizeof(aint)) then
  326. begin
  327. result.intsize:=sizeof(aint);
  328. retcgsize:=OS_SINT;
  329. end
  330. else
  331. result.intsize:=def.size;
  332. end;
  333. result.size:=retcgsize;
  334. { Return is passed as var parameter }
  335. if ret_in_param(def,p.proccalloption) then
  336. begin
  337. paraloc:=result.add_location;
  338. paraloc^.loc:=LOC_REFERENCE;
  339. paraloc^.size:=retcgsize;
  340. exit;
  341. end;
  342. { Return in FPU register? }
  343. if def.typ=floatdef then
  344. begin
  345. paraloc:=result.add_location;
  346. paraloc^.loc:=LOC_FPUREGISTER;
  347. paraloc^.register:=NR_FPU_RESULT_REG;
  348. paraloc^.size:=retcgsize;
  349. end
  350. else
  351. { Return in register }
  352. begin
  353. paraloc:=result.add_location;
  354. paraloc^.loc:=LOC_REGISTER;
  355. if retcgsize in [OS_64,OS_S64] then
  356. begin
  357. { low 32bits }
  358. if side=callerside then
  359. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  360. else
  361. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  362. paraloc^.size:=OS_32;
  363. { high 32bits }
  364. paraloc:=result.add_location;
  365. paraloc^.loc:=LOC_REGISTER;
  366. if side=callerside then
  367. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  368. else
  369. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  370. paraloc^.size:=OS_32;
  371. end
  372. else
  373. begin
  374. paraloc^.size:=retcgsize;
  375. if side=callerside then
  376. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  377. else
  378. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  379. end;
  380. end;
  381. end;
  382. procedure ti386paramanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;var parasize:longint);
  383. var
  384. i : integer;
  385. hp : tparavarsym;
  386. paraloc : pcgparalocation;
  387. l,
  388. paralen,
  389. varalign : longint;
  390. paraalign : shortint;
  391. pushaddr : boolean;
  392. paracgsize : tcgsize;
  393. begin
  394. paraalign:=get_para_align(p.proccalloption);
  395. { we push Flags and CS as long
  396. to cope with the IRETD
  397. and we save 6 register + 4 selectors }
  398. if po_interrupt in p.procoptions then
  399. inc(parasize,8+6*4+4*2);
  400. { Offset is calculated like:
  401. sub esp,12
  402. mov [esp+8],para3
  403. mov [esp+4],para2
  404. mov [esp],para1
  405. call function
  406. That means for pushes the para with the
  407. highest offset (see para3) needs to be pushed first
  408. }
  409. if p.proccalloption in pushleftright_pocalls then
  410. i:=paras.count-1
  411. else
  412. i:=0;
  413. while ((p.proccalloption in pushleftright_pocalls) and (i>=0)) or
  414. (not(p.proccalloption in pushleftright_pocalls) and (i<=paras.count-1)) do
  415. begin
  416. hp:=tparavarsym(paras[i]);
  417. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  418. if pushaddr then
  419. begin
  420. paralen:=sizeof(aint);
  421. paracgsize:=OS_ADDR;
  422. end
  423. else
  424. begin
  425. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  426. { darwin/x86 requires that parameters < sizeof(aint) are sign/ }
  427. { zero extended to sizeof(aint) }
  428. if (target_info.system in [system_i386_darwin,system_i386_iphonesim]) and
  429. (side = callerside) and
  430. (paralen > 0) and
  431. (paralen < sizeof(aint)) then
  432. begin
  433. paralen := sizeof(aint);
  434. paracgsize:=OS_SINT;
  435. end
  436. else
  437. paracgsize:=def_cgsize(hp.vardef);
  438. end;
  439. hp.paraloc[side].reset;
  440. hp.paraloc[side].size:=paracgsize;
  441. hp.paraloc[side].intsize:=paralen;
  442. hp.paraloc[side].Alignment:=paraalign;
  443. { Copy to stack? }
  444. if (paracgsize=OS_NO) or
  445. (use_fixed_stack) then
  446. begin
  447. paraloc:=hp.paraloc[side].add_location;
  448. paraloc^.loc:=LOC_REFERENCE;
  449. paraloc^.size:=paracgsize;
  450. if side=callerside then
  451. paraloc^.reference.index:=NR_STACK_POINTER_REG
  452. else
  453. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  454. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  455. { don't let push_size return 16, because then we can }
  456. { read past the end of the heap since the value is only }
  457. { 10 bytes long (JM) }
  458. if (paracgsize = OS_F80) and
  459. (target_info.system in [system_i386_darwin,system_i386_iphonesim]) then
  460. paralen:=16;
  461. paraloc^.reference.offset:=parasize;
  462. if side=calleeside then
  463. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  464. parasize:=align(parasize+paralen,varalign);
  465. end
  466. else
  467. begin
  468. if paralen=0 then
  469. internalerror(200501163);
  470. while (paralen>0) do
  471. begin
  472. paraloc:=hp.paraloc[side].add_location;
  473. paraloc^.loc:=LOC_REFERENCE;
  474. { single and double need a single location }
  475. if (paracgsize in [OS_F64,OS_F32]) then
  476. begin
  477. paraloc^.size:=paracgsize;
  478. l:=paralen;
  479. end
  480. else
  481. begin
  482. { We can allocate at maximum 32 bits per location }
  483. if paralen>sizeof(aint) then
  484. l:=sizeof(aint)
  485. else
  486. l:=paralen;
  487. paraloc^.size:=int_cgsize(l);
  488. end;
  489. if (side=callerside) or
  490. (po_nostackframe in p.procoptions) then
  491. paraloc^.reference.index:=NR_STACK_POINTER_REG
  492. else
  493. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  494. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  495. paraloc^.reference.offset:=parasize;
  496. if side=calleeside then
  497. if not(po_nostackframe in p.procoptions) then
  498. inc(paraloc^.reference.offset,target_info.first_parm_offset)
  499. else
  500. { return addres }
  501. inc(paraloc^.reference.offset,4);
  502. parasize:=align(parasize+l,varalign);
  503. dec(paralen,l);
  504. end;
  505. end;
  506. if p.proccalloption in pushleftright_pocalls then
  507. dec(i)
  508. else
  509. inc(i);
  510. end;
  511. end;
  512. procedure ti386paramanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  513. var parareg,parasize:longint);
  514. var
  515. hp : tparavarsym;
  516. paraloc : pcgparalocation;
  517. paracgsize : tcgsize;
  518. i : integer;
  519. l,
  520. paralen,
  521. varalign : longint;
  522. pushaddr : boolean;
  523. paraalign : shortint;
  524. pass : byte;
  525. begin
  526. if paras.count=0 then
  527. exit;
  528. paraalign:=get_para_align(p.proccalloption);
  529. { clean up here so we can later detect properly if a parameter has been
  530. assigned or not
  531. }
  532. for i:=0 to paras.count-1 do
  533. tparavarsym(paras[i]).paraloc[side].reset;
  534. { Register parameters are assigned from left to right,
  535. stack parameters from right to left so assign first the
  536. register parameters in a first pass, in the second
  537. pass all unhandled parameters are done }
  538. for pass:=1 to 2 do
  539. begin
  540. if pass=1 then
  541. i:=0
  542. else
  543. i:=paras.count-1;
  544. while true do
  545. begin
  546. hp:=tparavarsym(paras[i]);
  547. if not(assigned(hp.paraloc[side].location)) then
  548. begin
  549. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  550. if pushaddr then
  551. begin
  552. paralen:=sizeof(aint);
  553. paracgsize:=OS_ADDR;
  554. end
  555. else
  556. begin
  557. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  558. paracgsize:=def_cgsize(hp.vardef);
  559. end;
  560. hp.paraloc[side].size:=paracgsize;
  561. hp.paraloc[side].intsize:=paralen;
  562. hp.paraloc[side].Alignment:=paraalign;
  563. {
  564. EAX
  565. EDX
  566. ECX
  567. Stack
  568. Stack
  569. 64bit values,floats,arrays and records are always
  570. on the stack.
  571. In case of po_delphi_nested_cc, the parent frame pointer
  572. is also always passed on the stack.
  573. }
  574. if (parareg<=high(parasupregs)) and
  575. (paralen<=sizeof(aint)) and
  576. (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
  577. pushaddr) and
  578. (not(vo_is_parentfp in hp.varoptions) or
  579. not(po_delphi_nested_cc in p.procoptions)) then
  580. begin
  581. if pass=1 then
  582. begin
  583. paraloc:=hp.paraloc[side].add_location;
  584. paraloc^.size:=paracgsize;
  585. paraloc^.loc:=LOC_REGISTER;
  586. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  587. inc(parareg);
  588. end;
  589. end
  590. else
  591. if pass=2 then
  592. begin
  593. { Copy to stack? }
  594. if (use_fixed_stack) or
  595. (paracgsize=OS_NO) then
  596. begin
  597. paraloc:=hp.paraloc[side].add_location;
  598. paraloc^.loc:=LOC_REFERENCE;
  599. paraloc^.size:=paracgsize;
  600. if side=callerside then
  601. paraloc^.reference.index:=NR_STACK_POINTER_REG
  602. else
  603. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  604. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  605. paraloc^.reference.offset:=parasize;
  606. if side=calleeside then
  607. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  608. parasize:=align(parasize+paralen,varalign);
  609. end
  610. else
  611. begin
  612. if paralen=0 then
  613. internalerror(200501163);
  614. while (paralen>0) do
  615. begin
  616. paraloc:=hp.paraloc[side].add_location;
  617. paraloc^.loc:=LOC_REFERENCE;
  618. { Extended and double need a single location }
  619. if (paracgsize in [OS_F64,OS_F32]) then
  620. begin
  621. paraloc^.size:=paracgsize;
  622. l:=paralen;
  623. end
  624. else
  625. begin
  626. { We can allocate at maximum 32 bits per location }
  627. if paralen>sizeof(aint) then
  628. l:=sizeof(aint)
  629. else
  630. l:=paralen;
  631. paraloc^.size:=int_cgsize(l);
  632. end;
  633. if side=callerside then
  634. paraloc^.reference.index:=NR_STACK_POINTER_REG
  635. else
  636. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  637. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  638. paraloc^.reference.offset:=parasize;
  639. if side=calleeside then
  640. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  641. parasize:=align(parasize+l,varalign);
  642. dec(paralen,l);
  643. end;
  644. end;
  645. end;
  646. end;
  647. case pass of
  648. 1:
  649. begin
  650. if i=paras.count-1 then
  651. break;
  652. inc(i);
  653. end;
  654. 2:
  655. begin
  656. if i=0 then
  657. break;
  658. dec(i);
  659. end;
  660. end;
  661. end;
  662. end;
  663. end;
  664. function ti386paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  665. var
  666. parasize,
  667. parareg : longint;
  668. begin
  669. parasize:=0;
  670. parareg:=0;
  671. case p.proccalloption of
  672. pocall_register :
  673. create_register_paraloc_info(p,side,p.paras,parareg,parasize);
  674. pocall_internproc :
  675. begin
  676. { Use default calling }
  677. {$warnings off}
  678. if (pocall_default=pocall_register) then
  679. create_register_paraloc_info(p,side,p.paras,parareg,parasize)
  680. else
  681. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  682. {$warnings on}
  683. end;
  684. else
  685. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  686. end;
  687. create_funcretloc_info(p,side);
  688. result:=parasize;
  689. end;
  690. function ti386paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  691. var
  692. parasize : longint;
  693. begin
  694. parasize:=0;
  695. { calculate the registers for the normal parameters }
  696. create_stdcall_paraloc_info(p,callerside,p.paras,parasize);
  697. { append the varargs }
  698. create_stdcall_paraloc_info(p,callerside,varargspara,parasize);
  699. result:=parasize;
  700. end;
  701. procedure ti386paramanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  702. begin
  703. { Never a need for temps when value is pushed (calls inside parameters
  704. will simply allocate even more stack space for their parameters) }
  705. if not(use_fixed_stack) then
  706. can_use_final_stack_loc:=true;
  707. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  708. end;
  709. begin
  710. paramanager:=ti386paramanager.create;
  711. end.