cpupara.pas 30 KB

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