cpupara.pas 30 KB

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