cpupara.pas 31 KB

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