cpupara.pas 31 KB

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