cpupara.pas 32 KB

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