cpupara.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Generates the argument location information for 680x0
  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. cpubase,
  23. aasmdata,
  24. symconst,symtype,symdef,symsym,
  25. parabase,paramgr,cgbase,cgutils;
  26. type
  27. { Returns the location for the nr-st 32 Bit int parameter
  28. if every parameter before is an 32 Bit int parameter as well
  29. and if the calling conventions for the helper routines of the
  30. rtl are used.
  31. }
  32. tcpuparamanager = class(tparamanager)
  33. function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
  34. function param_use_paraloc(const cgpara:tcgpara):boolean;override;
  35. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  36. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  37. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  38. procedure createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);override;
  39. function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
  40. function parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;override;
  41. function get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;override;
  42. function get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;override;
  43. function get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;override;
  44. private
  45. function parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  46. function create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  47. var cur_stack_offset: aword):longint;
  48. function create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  49. var cur_stack_offset: aword):longint;
  50. end;
  51. implementation
  52. uses
  53. verbose,
  54. globals,
  55. systems,
  56. cpuinfo,
  57. defutil,
  58. cutils,
  59. hlcgobj;
  60. const
  61. intparasupregs : array[0..1] of tsuperregister = (RS_D0,RS_D1);
  62. addrparasupregs : array[0..1] of tsuperregister = (RS_A0,RS_A1);
  63. floatparasupregs : array[0..1] of tsuperregister = (RS_FP0,RS_FP1);
  64. function tcpuparamanager.get_volatile_registers_int(calloption:tproccalloption):tcpuregisterset;
  65. begin
  66. { d0 and d1 are considered volatile }
  67. Result:=VOLATILE_INTREGISTERS;
  68. end;
  69. function tcpuparamanager.get_volatile_registers_address(calloption:tproccalloption):tcpuregisterset;
  70. begin
  71. { a0 and a1 are considered volatile }
  72. Result:=VOLATILE_ADDRESSREGISTERS;
  73. end;
  74. function tcpuparamanager.get_volatile_registers_fpu(calloption:tproccalloption):tcpuregisterset;
  75. begin
  76. { fp0 and fp1 are considered volatile }
  77. Result:=VOLATILE_FPUREGISTERS;
  78. end;
  79. function tcpuparamanager.param_use_paraloc(const cgpara:tcgpara):boolean;
  80. var
  81. paraloc : pcgparalocation;
  82. begin
  83. if not assigned(cgpara.location) then
  84. internalerror(200410102);
  85. result:=true;
  86. { All locations are LOC_REFERENCE }
  87. paraloc:=cgpara.location;
  88. while assigned(paraloc) do
  89. begin
  90. if (paraloc^.loc<>LOC_REFERENCE) then
  91. begin
  92. result:=false;
  93. exit;
  94. end;
  95. paraloc:=paraloc^.next;
  96. end;
  97. end;
  98. { TODO: copied from ppc cg, needs work}
  99. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  100. begin
  101. result:=false;
  102. { var,out,constref always require address }
  103. if varspez in [vs_var,vs_out,vs_constref] then
  104. begin
  105. result:=true;
  106. exit;
  107. end;
  108. case def.typ of
  109. variantdef,
  110. formaldef :
  111. result:=true;
  112. recorddef:
  113. result:=false;
  114. arraydef:
  115. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  116. is_open_array(def) or
  117. is_array_of_const(def) or
  118. is_array_constructor(def);
  119. objectdef :
  120. result:=is_object(def);
  121. setdef :
  122. result:=not is_smallset(def);
  123. stringdef :
  124. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  125. procvardef :
  126. { Handling of methods must match that of records }
  127. result:=false;
  128. end;
  129. end;
  130. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  131. begin
  132. if handle_common_ret_in_param(def,pd,result) then
  133. exit;
  134. case def.typ of
  135. recorddef:
  136. if def.size in [1,2,4] then
  137. begin
  138. result:=false;
  139. exit;
  140. end;
  141. end;
  142. result:=inherited ret_in_param(def,pd);
  143. end;
  144. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  145. var
  146. paraloc : pcgparalocation;
  147. retcgsize : tcgsize;
  148. begin
  149. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  150. exit;
  151. { always use the whole 32 bit register when returning values }
  152. if (side=calleeside) and
  153. (result.intsize>0) and
  154. (result.intsize<sizeof(aint)) then
  155. begin
  156. result.def:=sinttype;
  157. result.intsize:=sizeof(aint);
  158. retcgsize:=OS_SINT;
  159. result.size:=retcgsize;
  160. end;
  161. paraloc:=result.add_location;
  162. { Return in FPU register? }
  163. if not (cs_fp_emulation in current_settings.moduleswitches) and
  164. not (current_settings.fputype=fpu_soft) and (result.def.typ=floatdef) then
  165. begin
  166. paraloc^.loc:=LOC_FPUREGISTER;
  167. paraloc^.register:=NR_FPU_RESULT_REG;
  168. paraloc^.size:=retcgsize;
  169. paraloc^.def:=result.def;
  170. end
  171. else
  172. { Return in register }
  173. begin
  174. if retcgsize in [OS_64,OS_S64] then
  175. begin
  176. { low 32bits }
  177. paraloc^.loc:=LOC_REGISTER;
  178. paraloc^.size:=OS_32;
  179. paraloc^.def:=u32inttype;
  180. if side=callerside then
  181. paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG
  182. else
  183. paraloc^.register:=NR_FUNCTION_RETURN64_LOW_REG;
  184. { high 32bits }
  185. paraloc:=result.add_location;
  186. paraloc^.loc:=LOC_REGISTER;
  187. paraloc^.size:=OS_32;
  188. paraloc^.def:=u32inttype;
  189. if side=calleeside then
  190. paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG
  191. else
  192. paraloc^.register:=NR_FUNCTION_RETURN64_HIGH_REG;
  193. end
  194. else
  195. begin
  196. paraloc^.loc:=LOC_REGISTER;
  197. paraloc^.size:=retcgsize;
  198. paraloc^.def:=result.def;
  199. if side=callerside then
  200. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  201. else
  202. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  203. end;
  204. end;
  205. end;
  206. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  207. var
  208. cur_stack_offset: aword;
  209. begin
  210. cur_stack_offset:=0;
  211. case p.proccalloption of
  212. pocall_register :
  213. result:=create_register_paraloc_info(p,side,p.paras,cur_stack_offset);
  214. else
  215. result:=create_stdcall_paraloc_info(p,side,p.paras,cur_stack_offset);
  216. end;
  217. create_funcretloc_info(p,side);
  218. end;
  219. function tcpuparamanager.create_stdcall_paraloc_info(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
  220. var cur_stack_offset: aword):longint;
  221. var
  222. paraloc : pcgparalocation;
  223. hp : tparavarsym;
  224. paracgsize : tcgsize;
  225. paralen : aint;
  226. paradef : tdef;
  227. i : longint;
  228. firstparaloc : boolean;
  229. begin
  230. result:=0;
  231. for i:=0 to paras.count-1 do
  232. begin
  233. hp:=tparavarsym(paras[i]);
  234. paradef:=hp.vardef;
  235. { syscall for AmigaOS can have already a paraloc set }
  236. if (vo_has_explicit_paraloc in hp.varoptions) then
  237. begin
  238. if not(vo_is_syscall_lib in hp.varoptions) then
  239. internalerror(200506051);
  240. continue;
  241. end;
  242. hp.paraloc[side].reset;
  243. { currently only support C-style array of const }
  244. if (p.proccalloption in cstylearrayofconst) and
  245. is_array_of_const(paradef) then
  246. begin
  247. paraloc:=hp.paraloc[side].add_location;
  248. { hack: the paraloc must be valid, but is not actually used }
  249. paraloc^.loc:=LOC_REGISTER;
  250. paraloc^.register:=NR_D0;
  251. paraloc^.size:=OS_ADDR;
  252. paraloc^.def:=voidpointertype;
  253. break;
  254. end;
  255. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  256. begin
  257. paradef:=cpointerdef.getreusable_no_free(paradef);
  258. paracgsize := OS_ADDR;
  259. paralen := tcgsize2size[OS_ADDR];
  260. end
  261. else
  262. begin
  263. if not is_special_array(paradef) then
  264. paralen:=paradef.size
  265. else
  266. paralen:=tcgsize2size[def_cgsize(paradef)];
  267. paracgsize:=def_cgsize(paradef);
  268. { for things like formaldef }
  269. if (paracgsize=OS_NO) and (paradef.typ<>recorddef) then
  270. begin
  271. paracgsize:=OS_ADDR;
  272. paralen := tcgsize2size[OS_ADDR];
  273. end;
  274. end;
  275. hp.paraloc[side].alignment:=target_info.stackalign; //std_param_align;
  276. hp.paraloc[side].size:=paracgsize;
  277. hp.paraloc[side].intsize:=paralen;
  278. hp.paraloc[side].def:=paradef;
  279. if (paralen = 0) then
  280. if (paradef.typ = recorddef) then
  281. begin
  282. paraloc:=hp.paraloc[side].add_location;
  283. paraloc^.loc := LOC_VOID;
  284. end
  285. else
  286. internalerror(200506052);
  287. firstparaloc:=true;
  288. { can become < 0 for e.g. 3-byte records }
  289. while (paralen > 0) do
  290. begin
  291. paraloc:=hp.paraloc[side].add_location;
  292. paraloc^.loc:=LOC_REFERENCE;
  293. paraloc^.def:=get_paraloc_def(paradef,paralen,firstparaloc);
  294. if (not (cs_fp_emulation in current_settings.moduleswitches)) and
  295. (paradef.typ=floatdef) then
  296. paraloc^.size:=int_float_cgsize(paralen)
  297. else
  298. paraloc^.size:=int_cgsize(paralen);
  299. paraloc^.reference.offset:=cur_stack_offset;
  300. if (side = callerside) then
  301. paraloc^.reference.index:=NR_STACK_POINTER_REG
  302. else
  303. begin
  304. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  305. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  306. { M68K is a big-endian target }
  307. if (paralen<target_info.stackalign{tcgsize2size[OS_INT]}) then
  308. inc(paraloc^.reference.offset,target_info.stackalign-paralen);
  309. end;
  310. inc(cur_stack_offset,align(paralen,target_info.stackalign));
  311. paralen := 0;
  312. firstparaloc:=false;
  313. end;
  314. end;
  315. result:=cur_stack_offset;
  316. end;
  317. function tcpuparamanager.create_register_paraloc_info(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  318. var cur_stack_offset: aword): longint;
  319. var
  320. hp : tparavarsym;
  321. paradef : tdef;
  322. paraloc : pcgparalocation;
  323. paracgsize : tcgsize;
  324. i : integer;
  325. l,
  326. paralen,
  327. parareg: longint;
  328. addrparareg: longint;
  329. floatparareg: longint;
  330. varalign : longint;
  331. paraalign : shortint;
  332. pass : byte;
  333. firstparaloc,
  334. pushaddr : boolean;
  335. rt: tregistertype;
  336. begin
  337. result:=0;
  338. parareg:=0;
  339. addrparareg:=0;
  340. floatparareg:=0;
  341. if paras.count=0 then
  342. exit;
  343. paraalign:=get_para_align(p.proccalloption);
  344. { clean up here so we can later detect properly if a parameter has been
  345. assigned or not
  346. }
  347. for i:=0 to paras.count-1 do
  348. tparavarsym(paras[i]).paraloc[side].reset;
  349. { Register parameters are assigned from left to right,
  350. stack parameters from right to left so assign first the
  351. register parameters in a first pass, in the second
  352. pass all unhandled parameters are done }
  353. for pass:=1 to 2 do
  354. begin
  355. if pass=1 then
  356. i:=0
  357. else
  358. i:=paras.count-1;
  359. while true do
  360. begin
  361. hp:=tparavarsym(paras[i]);
  362. paradef:=hp.vardef;
  363. if not(assigned(hp.paraloc[side].location)) then
  364. begin
  365. pushaddr:=push_addr_param(hp.varspez,hp.vardef,p.proccalloption);
  366. if pushaddr then
  367. begin
  368. paralen:=sizeof(aint);
  369. paracgsize:=OS_ADDR;
  370. paradef:=cpointerdef.getreusable_no_free(paradef);
  371. end
  372. else
  373. begin
  374. paralen:=push_size(hp.varspez,hp.vardef,p.proccalloption);
  375. paracgsize:=def_cgsize(hp.vardef);
  376. end;
  377. hp.paraloc[side].size:=paracgsize;
  378. hp.paraloc[side].intsize:=paralen;
  379. hp.paraloc[side].Alignment:=paraalign;
  380. hp.paraloc[side].def:=paradef;
  381. {
  382. In case of po_delphi_nested_cc, the parent frame pointer
  383. is also always passed on the stack.
  384. }
  385. rt:=chlcgobj.def2regtyp(paradef);
  386. if (rt=R_FPUREGISTER) and
  387. (floatparareg<=high(floatparasupregs)) and
  388. (not pushaddr) then
  389. begin
  390. if pass=1 then
  391. begin
  392. paraloc:=hp.paraloc[side].add_location;
  393. paraloc^.size:=paracgsize;
  394. paraloc^.def:=paradef;
  395. paraloc^.loc:=LOC_FPUREGISTER;
  396. paraloc^.register:=newreg(R_FPUREGISTER,floatparasupregs[floatparareg],R_SUBWHOLE);
  397. inc(floatparareg);
  398. end;
  399. end
  400. else
  401. if (((rt=R_INTREGISTER) and (parareg<=high(intparasupregs))) or
  402. ((rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)))) and
  403. (paralen<=sizeof(aint)) and
  404. (not(hp.vardef.typ in [floatdef,recorddef,arraydef]) or
  405. pushaddr or
  406. is_dynamic_array(hp.vardef)) and
  407. (not(vo_is_parentfp in hp.varoptions) or
  408. not(po_delphi_nested_cc in p.procoptions)) then
  409. begin
  410. if pass=1 then
  411. begin
  412. paraloc:=hp.paraloc[side].add_location;
  413. paraloc^.size:=paracgsize;
  414. paraloc^.def:=paradef;
  415. paraloc^.loc:=LOC_REGISTER;
  416. if (rt=R_ADDRESSREGISTER) and (addrparareg<=high(addrparasupregs)) then
  417. begin
  418. paraloc^.register:=newreg(R_ADDRESSREGISTER,addrparasupregs[addrparareg],R_SUBWHOLE);
  419. inc(addrparareg);
  420. end
  421. else
  422. if (rt=R_INTREGISTER) and (parareg<=high(intparasupregs)) then
  423. begin
  424. paraloc^.register:=newreg(R_INTREGISTER,intparasupregs[parareg],cgsize2subreg(R_INTREGISTER,paracgsize));
  425. inc(parareg);
  426. end
  427. else
  428. internalerror(2016051801);
  429. end;
  430. end
  431. else
  432. if pass=2 then
  433. begin
  434. { Copy to stack? }
  435. if (use_fixed_stack) or
  436. (paracgsize=OS_NO) then
  437. begin
  438. paraloc:=hp.paraloc[side].add_location;
  439. paraloc^.loc:=LOC_REFERENCE;
  440. paraloc^.size:=paracgsize;
  441. paraloc^.def:=paradef;
  442. if side=callerside then
  443. paraloc^.reference.index:=NR_STACK_POINTER_REG
  444. else
  445. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  446. varalign:=used_align(size_2_align(paralen),paraalign,paraalign);
  447. paraloc^.reference.offset:=cur_stack_offset;
  448. if side=calleeside then
  449. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  450. cur_stack_offset:=align(cur_stack_offset+paralen,varalign);
  451. end
  452. else
  453. begin
  454. if paralen=0 then
  455. internalerror(200501163);
  456. firstparaloc:=true;
  457. while (paralen>0) do
  458. begin
  459. paraloc:=hp.paraloc[side].add_location;
  460. paraloc^.loc:=LOC_REFERENCE;
  461. { Extended and double need a single location }
  462. if (paracgsize in [OS_F64,OS_F32]) then
  463. begin
  464. paraloc^.size:=paracgsize;
  465. paraloc^.def:=paradef;
  466. l:=paralen;
  467. end
  468. else
  469. begin
  470. { We can allocate at maximum 32 bits per location }
  471. if paralen>sizeof(aint) then
  472. begin
  473. l:=sizeof(aint);
  474. paraloc^.def:=uinttype;
  475. end
  476. else
  477. begin
  478. l:=paralen;
  479. paraloc^.def:=get_paraloc_def(paradef,l,firstparaloc);
  480. end;
  481. paraloc^.size:=int_cgsize(l);
  482. end;
  483. if side=callerside then
  484. paraloc^.reference.index:=NR_STACK_POINTER_REG
  485. else
  486. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  487. varalign:=used_align(size_2_align(l),paraalign,paraalign);
  488. paraloc^.reference.offset:=cur_stack_offset;
  489. { M68K is a big-endian target }
  490. if (paralen<tcgsize2size[OS_INT]) then
  491. inc(paraloc^.reference.offset,4-paralen);
  492. if side=calleeside then
  493. inc(paraloc^.reference.offset,target_info.first_parm_offset);
  494. cur_stack_offset:=align(cur_stack_offset+l,varalign);
  495. dec(paralen,l);
  496. firstparaloc:=false;
  497. end;
  498. end;
  499. end;
  500. end;
  501. case pass of
  502. 1:
  503. begin
  504. if i=paras.count-1 then
  505. break;
  506. inc(i);
  507. end;
  508. 2:
  509. begin
  510. if i=0 then
  511. break;
  512. dec(i);
  513. end;
  514. end;
  515. end;
  516. end;
  517. result:=cur_stack_offset;
  518. end;
  519. function tcpuparamanager.parse_loc_string_to_register(var locreg: tregister; const s : string): boolean;
  520. begin
  521. locreg:=std_regnum_search(lower(s));
  522. result:=(locreg <> NR_NO) and (locreg <> NR_SP);
  523. end;
  524. function tcpuparamanager.parsefuncretloc(p : tabstractprocdef; const s : string) : boolean;
  525. begin
  526. case target_info.system of
  527. system_m68k_amiga:
  528. result:=parse_loc_string_to_register(p.exp_funcretloc, s);
  529. else
  530. internalerror(2005121801);
  531. end;
  532. end;
  533. procedure tcpuparamanager.createtempparaloc(list: TAsmList;calloption : tproccalloption;parasym : tparavarsym;can_use_final_stack_loc : boolean;var cgpara:TCGPara);
  534. begin
  535. { Never a need for temps when value is pushed (calls inside parameters
  536. will simply allocate even more stack space for their parameters) }
  537. if not(use_fixed_stack) then
  538. can_use_final_stack_loc:=true;
  539. inherited createtempparaloc(list,calloption,parasym,can_use_final_stack_loc,cgpara);
  540. end;
  541. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;
  542. var
  543. cur_stack_offset: aword;
  544. begin
  545. cur_stack_offset:=0;
  546. result:=create_stdcall_paraloc_info(p,callerside,p.paras,cur_stack_offset);
  547. if (p.proccalloption in cstylearrayofconst) then
  548. { just continue loading the parameters in the registers }
  549. result:=create_stdcall_paraloc_info(p,callerside,varargspara,cur_stack_offset)
  550. else
  551. internalerror(200410231);
  552. end;
  553. begin
  554. paramanager:=tcpuparamanager.create;
  555. end.