cpupara.pas 28 KB

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