cpupara.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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 getcgtempparaloc(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. 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.asm_result_var(def:tdef;pd:tabstractprocdef):boolean;
  97. begin
  98. if not(po_assembler in pd.procoptions) then
  99. internalerror(2018021502);
  100. result:=ret_in_param(def,pd);
  101. end;
  102. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  103. begin
  104. result:=false;
  105. { var,out,constref always require address }
  106. if varspez in [vs_var,vs_out,vs_constref] then
  107. begin
  108. result:=true;
  109. exit;
  110. end;
  111. { Only vs_const, vs_value here }
  112. case def.typ of
  113. variantdef :
  114. begin
  115. { variants are small enough to be passed by value except if
  116. required by the windows api
  117. variants are somethings very delphi/windows specific so do it like
  118. windows/delphi (FK)
  119. }
  120. if ((target_info.system=system_i386_win32) and
  121. (calloption in [pocall_stdcall,pocall_safecall]) and
  122. (varspez=vs_const)) or
  123. (calloption=pocall_register) then
  124. result:=true
  125. else
  126. result:=false;
  127. end;
  128. formaldef :
  129. result:=true;
  130. recorddef :
  131. begin
  132. { Delphi stdcall passes records on the stack for call by value }
  133. if (target_info.system=system_i386_win32) and
  134. (calloption=pocall_stdcall) and
  135. (varspez=vs_value) then
  136. result:=false
  137. else
  138. result:=
  139. (not(calloption in (cdecl_pocalls)) and
  140. (def.size>sizeof(aint)));
  141. end;
  142. arraydef :
  143. begin
  144. { array of const values are pushed on the stack as
  145. well as dyn. arrays }
  146. if (calloption in cdecl_pocalls) then
  147. result:=not(is_array_of_const(def) or
  148. is_dynamic_array(def))
  149. else
  150. begin
  151. result:=(
  152. (tarraydef(def).highrange>=tarraydef(def).lowrange) and
  153. (def.size>sizeof(aint))
  154. ) or
  155. is_open_array(def) or
  156. is_array_of_const(def) or
  157. is_array_constructor(def);
  158. end;
  159. end;
  160. objectdef :
  161. result:=is_object(def);
  162. stringdef :
  163. result:= (tstringdef(def).stringtype in [st_shortstring,st_longstring]);
  164. procvardef :
  165. result:=not(calloption in cdecl_pocalls) and not tprocvardef(def).is_addressonly;
  166. setdef :
  167. result:=not(calloption in cdecl_pocalls) and (not is_smallset(def));
  168. else
  169. ;
  170. end;
  171. end;
  172. function tcpuparamanager.get_para_align(calloption : tproccalloption):byte;
  173. begin
  174. result:=std_param_align;
  175. end;
  176. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  177. begin
  178. case calloption of
  179. pocall_internproc :
  180. result:=[];
  181. pocall_register,
  182. pocall_cdecl:
  183. result:=[RS_AX,RS_DX,RS_CX,RS_BX];
  184. pocall_safecall,
  185. pocall_stdcall,
  186. pocall_cppdecl,
  187. pocall_pascal :
  188. result:=[RS_AX,RS_DX,RS_CX,RS_SI,RS_DI,RS_BX];
  189. else
  190. internalerror(200309071);
  191. end;
  192. end;
  193. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  194. begin
  195. result:=[0..first_fpu_imreg-1];
  196. end;
  197. function tcpuparamanager.get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;
  198. begin
  199. result:=[0..first_mm_imreg-1];
  200. end;
  201. function tcpuparamanager.get_saved_registers_int(calloption : tproccalloption):tcpuregisterarray;
  202. const
  203. saveregs_cdecl: {$ifndef VER3_0}tcpuregisterarray{$else}array [0..2] of tsuperregister{$endif} = (RS_BP,RS_SI,RS_DI);
  204. saveregs_pascal: {$ifndef VER3_0}tcpuregisterarray{$else}array [0..0] of tsuperregister{$endif} = (RS_BP);
  205. begin
  206. case calloption of
  207. pocall_register,
  208. pocall_cdecl:
  209. result:=saveregs_cdecl;
  210. pocall_internproc,
  211. pocall_safecall,
  212. pocall_stdcall,
  213. pocall_cppdecl,
  214. pocall_pascal :
  215. result:=saveregs_pascal;
  216. else
  217. internalerror(2018042301);
  218. end;
  219. end;
  220. procedure tcpuparamanager.getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  221. var
  222. paraloc : pcgparalocation;
  223. psym: tparavarsym;
  224. pdef : tdef;
  225. begin
  226. psym:=tparavarsym(pd.paras[nr-1]);
  227. pdef:=psym.vardef;
  228. if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
  229. pdef:=cpointerdef.getreusable_no_free(pdef);
  230. cgpara.reset;
  231. cgpara.size:=def_cgsize(pdef);
  232. cgpara.intsize:=tcgsize2size[cgpara.size];
  233. cgpara.alignment:=get_para_align(pd.proccalloption);
  234. cgpara.def:=pdef;
  235. paraloc:=cgpara.add_location;
  236. with paraloc^ do
  237. begin
  238. size:=def_cgsize(pdef);
  239. def:=pdef;
  240. if pd.proccalloption=pocall_register then
  241. begin
  242. if (nr<=length(parasupregs)) then
  243. begin
  244. if nr=0 then
  245. internalerror(200309271);
  246. loc:=LOC_REGISTER;
  247. register:=newreg(R_INTREGISTER,parasupregs[nr-1],R_SUBWHOLE);
  248. end
  249. else
  250. begin
  251. loc:=LOC_REFERENCE;
  252. reference.index:=NR_STACK_POINTER_REG;
  253. { the previous parameters didn't take up room in memory }
  254. reference.offset:=sizeof(aint)*(nr-length(parasupregs)-1)
  255. end;
  256. end
  257. else
  258. begin
  259. loc:=LOC_REFERENCE;
  260. reference.index:=NR_STACK_POINTER_REG;
  261. reference.offset:=sizeof(aint)*nr;
  262. end;
  263. end;
  264. end;
  265. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): TCGPara;
  266. var
  267. retcgsize : tcgsize;
  268. paraloc : pcgparalocation;
  269. usedef: tdef;
  270. handled: boolean;
  271. begin
  272. if not assigned(forcetempdef) then
  273. usedef:=p.returndef
  274. else
  275. usedef:=forcetempdef;
  276. handled:=set_common_funcretloc_info(p,usedef,retcgsize,result);
  277. { normally forcetempdef is passed straight through to
  278. set_common_funcretloc_info and that one will correctly determine whether
  279. the location is a temporary one, but that doesn't work here because we
  280. sometimes have to change the type }
  281. result.temporary:=assigned(forcetempdef);
  282. if handled then
  283. exit;
  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 tcpuparamanager.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. pushleftright: boolean;
  379. begin
  380. paraalign:=get_para_align(p.proccalloption);
  381. { interrupt routines need parameter fixup }
  382. if po_interrupt in p.procoptions then
  383. if is_proc_far(p) then
  384. dec(parasize,6)
  385. else
  386. dec(parasize,4);
  387. { Offset is calculated like:
  388. sub esp,12
  389. mov [esp+8],para3
  390. mov [esp+4],para2
  391. mov [esp],para1
  392. call function
  393. That means for pushes the para with the
  394. highest offset (see para3) needs to be pushed first
  395. }
  396. pushleftright:=(p.proccalloption in pushleftright_pocalls) or (po_interrupt in p.procoptions);
  397. if pushleftright then
  398. i:=paras.count-1
  399. else
  400. i:=0;
  401. while (pushleftright and (i>=0)) or
  402. (not(pushleftright) and (i<=paras.count-1)) do
  403. begin
  404. hp:=tparavarsym(paras[i]);
  405. paradef:=hp.vardef;
  406. pushaddr:=push_addr_param(hp.varspez,paradef,p.proccalloption);
  407. if pushaddr then
  408. begin
  409. paralen:=voidpointertype.size;
  410. paracgsize:=int_cgsize(voidpointertype.size);
  411. paradef:=cpointerdef.getreusable_no_free(paradef);
  412. end
  413. else
  414. begin
  415. paralen:=push_size(hp.varspez,paradef,p.proccalloption);
  416. paracgsize:=def_cgsize(paradef);
  417. end;
  418. hp.paraloc[side].reset;
  419. hp.paraloc[side].size:=paracgsize;
  420. hp.paraloc[side].intsize:=paralen;
  421. hp.paraloc[side].def:=paradef;
  422. hp.paraloc[side].Alignment:=paraalign;
  423. { Copy to stack? }
  424. if (paracgsize=OS_NO) or
  425. (use_fixed_stack) then
  426. begin
  427. paraloc:=hp.paraloc[side].add_location;
  428. paraloc^.loc:=LOC_REFERENCE;
  429. paraloc^.size:=paracgsize;
  430. paraloc^.def:=paradef;
  431. if side=callerside then
  432. paraloc^.reference.index:=NR_STACK_POINTER_REG
  433. else
  434. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  435. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  436. paraloc^.reference.offset:=parasize;
  437. if side=calleeside then
  438. begin
  439. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  440. if is_proc_far(p) then
  441. inc(paraloc^.reference.offset,2);
  442. end;
  443. parasize:=align(parasize+paralen,varalign);
  444. end
  445. else
  446. begin
  447. if paralen=0 then
  448. internalerror(2005011604);
  449. firstparaloc:=true;
  450. while (paralen>0) do
  451. begin
  452. paraloc:=hp.paraloc[side].add_location;
  453. paraloc^.loc:=LOC_REFERENCE;
  454. { single and double need a single location }
  455. if (paracgsize in [OS_F64,OS_F32]) then
  456. begin
  457. paraloc^.size:=paracgsize;
  458. paraloc^.def:=paradef;
  459. l:=paralen;
  460. end
  461. else
  462. begin
  463. { We can allocate at maximum 16 bits per location }
  464. if paralen>=sizeof(aint) then
  465. begin
  466. l:=sizeof(aint);
  467. paraloc^.def:=uinttype;
  468. end
  469. else
  470. begin
  471. l:=paralen;
  472. paraloc^.def:=get_paraloc_def(paradef,l,firstparaloc);
  473. end;
  474. paraloc^.size:=int_cgsize(l);
  475. end;
  476. if (side=callerside) or
  477. (po_nostackframe in p.procoptions) then
  478. paraloc^.reference.index:=NR_STACK_POINTER_REG
  479. else
  480. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  481. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  482. paraloc^.reference.offset:=parasize;
  483. if side=calleeside then
  484. begin
  485. if not(po_nostackframe in p.procoptions) then
  486. inc(paraloc^.reference.offset,target_info.first_parm_offset)
  487. else
  488. { return addres }
  489. inc(paraloc^.reference.offset,2);
  490. if is_proc_far(p) then
  491. inc(paraloc^.reference.offset,2);
  492. end;
  493. parasize:=align(parasize+l,varalign);
  494. dec(paralen,l);
  495. firstparaloc:=false;
  496. end;
  497. end;
  498. if pushleftright then
  499. dec(i)
  500. else
  501. inc(i);
  502. end;
  503. end;
  504. procedure tcpuparamanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  505. var parareg,parasize:longint);
  506. var
  507. hp : tparavarsym;
  508. paradef : tdef;
  509. paraloc : pcgparalocation;
  510. paracgsize : tcgsize;
  511. i : integer;
  512. l,
  513. paralen,
  514. varalign : longint;
  515. pushaddr : boolean;
  516. paraalign : shortint;
  517. pass : byte;
  518. firstparaloc : boolean;
  519. begin
  520. if paras.count=0 then
  521. exit;
  522. paraalign:=get_para_align(p.proccalloption);
  523. { clean up here so we can later detect properly if a parameter has been
  524. assigned or not
  525. }
  526. for i:=0 to paras.count-1 do
  527. tparavarsym(paras[i]).paraloc[side].reset;
  528. { Register parameters are assigned from left to right,
  529. stack parameters from right to left so assign first the
  530. register parameters in a first pass, in the second
  531. pass all unhandled parameters are done }
  532. for pass:=1 to 2 do
  533. begin
  534. if pass=1 then
  535. i:=0
  536. else
  537. i:=paras.count-1;
  538. while true do
  539. begin
  540. hp:=tparavarsym(paras[i]);
  541. paradef:=hp.vardef;
  542. if not(assigned(hp.paraloc[side].location)) then
  543. begin
  544. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  545. if pushaddr then
  546. begin
  547. paralen:=voidpointertype.size;
  548. paracgsize:=int_cgsize(voidpointertype.size);
  549. paradef:=cpointerdef.getreusable_no_free(paradef);
  550. end
  551. else
  552. begin
  553. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  554. paracgsize:=def_cgsize(hp.vardef);
  555. end;
  556. hp.paraloc[side].size:=paracgsize;
  557. hp.paraloc[side].intsize:=paralen;
  558. hp.paraloc[side].Alignment:=paraalign;
  559. hp.paraloc[side].def:=paradef;
  560. {
  561. AX
  562. DX
  563. BX
  564. Stack
  565. Stack
  566. 32/64bit values,far pointers,floats,arrays and records are
  567. always on the stack. The only exception is that Longints
  568. (but not far pointers) can be passed in DX:AX if these
  569. registers are unallocated.
  570. In case of po_delphi_nested_cc, the parent frame pointer
  571. is also always passed on the stack.
  572. }
  573. if (parareg=low(parasupregs)) and
  574. (paralen=4) and
  575. (hp.vardef.typ=orddef) then
  576. begin
  577. if pass=1 then
  578. begin
  579. paraloc:=hp.paraloc[side].add_location;
  580. paraloc^.size:=OS_16;
  581. paraloc^.def:=paradef;
  582. paraloc^.loc:=LOC_REGISTER;
  583. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],R_SUBW);
  584. inc(parareg);
  585. paraloc:=hp.paraloc[side].add_location;
  586. paraloc^.size:=OS_16;
  587. paraloc^.def:=paradef;
  588. paraloc^.loc:=LOC_REGISTER;
  589. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],R_SUBW);
  590. inc(parareg);
  591. end;
  592. end
  593. else if (parareg<=high(parasupregs)) and
  594. (paralen<=sizeof(aint)) and
  595. (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
  596. pushaddr or
  597. is_dynamic_array(hp.vardef)) and
  598. (not(vo_is_parentfp in hp.varoptions) or
  599. not(po_delphi_nested_cc in p.procoptions)) then
  600. begin
  601. if pass=1 then
  602. begin
  603. paraloc:=hp.paraloc[side].add_location;
  604. paraloc^.size:=paracgsize;
  605. paraloc^.def:=paradef;
  606. paraloc^.loc:=LOC_REGISTER;
  607. paraloc^.register:=newreg(R_INTREGISTER,parasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  608. inc(parareg);
  609. end;
  610. end
  611. else
  612. if pass=2 then
  613. begin
  614. { Copy to stack? }
  615. if (use_fixed_stack) or
  616. (paracgsize=OS_NO) then
  617. begin
  618. paraloc:=hp.paraloc[side].add_location;
  619. paraloc^.loc:=LOC_REFERENCE;
  620. paraloc^.size:=paracgsize;
  621. paraloc^.def:=paradef;
  622. if side=callerside then
  623. paraloc^.reference.index:=NR_STACK_POINTER_REG
  624. else
  625. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  626. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  627. paraloc^.reference.offset:=parasize;
  628. if side=calleeside then
  629. begin
  630. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  631. if is_proc_far(p) then
  632. inc(paraloc^.reference.offset,2);
  633. end;
  634. parasize:=align(parasize+paralen,varalign);
  635. end
  636. else
  637. begin
  638. if paralen=0 then
  639. internalerror(2005011605);
  640. firstparaloc:=true;
  641. while (paralen>0) do
  642. begin
  643. paraloc:=hp.paraloc[side].add_location;
  644. paraloc^.loc:=LOC_REFERENCE;
  645. { Extended and double need a single location }
  646. if (paracgsize in [OS_F64,OS_F32]) then
  647. begin
  648. paraloc^.size:=paracgsize;
  649. paraloc^.def:=paradef;
  650. l:=paralen;
  651. end
  652. else
  653. begin
  654. { We can allocate at maximum 16 bits per location }
  655. if paralen>=sizeof(aint) then
  656. begin
  657. l:=sizeof(aint);
  658. paraloc^.def:=uinttype;
  659. end
  660. else
  661. begin
  662. l:=paralen;
  663. paraloc^.def:=get_paraloc_def(paradef,l,firstparaloc);
  664. end;
  665. paraloc^.size:=int_cgsize(l);
  666. end;
  667. if side=callerside then
  668. paraloc^.reference.index:=NR_STACK_POINTER_REG
  669. else
  670. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  671. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  672. paraloc^.reference.offset:=parasize;
  673. if side=calleeside then
  674. begin
  675. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  676. if is_proc_far(p) then
  677. inc(paraloc^.reference.offset,2);
  678. end;
  679. parasize:=align(parasize+l,varalign);
  680. dec(paralen,l);
  681. firstparaloc:=false;
  682. end;
  683. end;
  684. end;
  685. end;
  686. case pass of
  687. 1:
  688. begin
  689. if i=paras.count-1 then
  690. break;
  691. inc(i);
  692. end;
  693. 2:
  694. begin
  695. if i=0 then
  696. break;
  697. dec(i);
  698. end;
  699. end;
  700. end;
  701. end;
  702. end;
  703. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  704. var
  705. parasize,
  706. parareg : longint;
  707. begin
  708. parasize:=0;
  709. parareg:=0;
  710. case p.proccalloption of
  711. pocall_register :
  712. create_register_paraloc_info(p,side,p.paras,parareg,parasize);
  713. pocall_internproc :
  714. begin
  715. { Use default calling }
  716. {$warnings off}
  717. if (pocall_default=pocall_register) then
  718. create_register_paraloc_info(p,side,p.paras,parareg,parasize)
  719. else
  720. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  721. {$warnings on}
  722. end;
  723. else
  724. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  725. end;
  726. create_funcretloc_info(p,side);
  727. result:=parasize;
  728. end;
  729. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  730. var
  731. parasize : longint;
  732. begin
  733. parasize:=0;
  734. { calculate the registers for the normal parameters }
  735. create_stdcall_paraloc_info(p,side,p.paras,parasize);
  736. { append the varargs }
  737. if assigned(varargspara) then
  738. begin
  739. if side=callerside then
  740. create_stdcall_paraloc_info(p,side,varargspara,parasize)
  741. else
  742. internalerror(2019021925);
  743. end;
  744. create_funcretloc_info(p,side);
  745. result:=parasize;
  746. end;
  747. procedure tcpuparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  748. begin
  749. { Never a need for temps when value is pushed (calls inside parameters
  750. will simply allocate even more stack space for their parameters) }
  751. if not(use_fixed_stack) then
  752. can_use_final_stack_loc:=true;
  753. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  754. end;
  755. begin
  756. paramanager:=tcpuparamanager.create;
  757. end.