cpupara.pas 32 KB

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