cpupara.pas 31 KB

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