cpupara.pas 29 KB

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