cpupara.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. {
  2. Copyright (c) 2002 by Florian Klaempfl
  3. Xtensa specific calling conventions
  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,
  23. cpubase,
  24. symconst,symtype,symdef,symsym,
  25. paramgr,parabase,cgbase,cgutils;
  26. type
  27. tcpuparamanager = class(tparamanager)
  28. function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
  29. function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
  30. function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
  31. procedure getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
  32. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  33. function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
  34. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  35. private
  36. { the max. register depends on the used call instruction }
  37. maxintreg : TSuperRegister;
  38. procedure init_values(side: tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
  39. function create_paraloc_info_intern(p : tabstractprocdef; side : tcallercallee;
  40. paras : tparalist; var curintreg : tsuperregister;
  41. var cur_stack_offset : aword; varargsparas : boolean) : longint;
  42. end;
  43. implementation
  44. uses
  45. cpuinfo,globals,
  46. verbose,systems,
  47. defutil,symtable,
  48. procinfo,cpupi;
  49. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  50. begin
  51. { we have actually to check what calling instruction is used, but we do not handle this,
  52. instead CALL(X)8 is used always }
  53. if target_info.abi=abi_xtensa_windowed then
  54. result:=[RS_A8..RS_A15]
  55. else
  56. result:=[RS_A0..RS_A7];
  57. end;
  58. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  59. begin
  60. result:=[RS_F0..RS_F15];
  61. end;
  62. procedure tcpuparamanager.getcgtempparaloc(list: TAsmList; pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
  63. var
  64. paraloc : pcgparalocation;
  65. psym : tparavarsym;
  66. pdef : tdef;
  67. begin
  68. psym:=tparavarsym(pd.paras[nr-1]);
  69. pdef:=psym.vardef;
  70. if push_addr_param(psym.varspez,pdef,pd.proccalloption) then
  71. pdef:=cpointerdef.getreusable_no_free(pdef);
  72. cgpara.reset;
  73. cgpara.size:=def_cgsize(pdef);
  74. cgpara.intsize:=tcgsize2size[cgpara.size];
  75. cgpara.alignment:=get_para_align(pd.proccalloption);
  76. cgpara.def:=pdef;
  77. paraloc:=cgpara.add_location;
  78. with paraloc^ do
  79. begin
  80. size:=def_cgsize(pdef);
  81. def:=pdef;
  82. if (nr<=8) then
  83. begin
  84. if nr=0 then
  85. internalerror(200309271);
  86. loc:=LOC_REGISTER;
  87. register:=newreg(R_INTREGISTER,RS_A2+nr,R_SUBWHOLE);
  88. end
  89. else
  90. begin
  91. loc:=LOC_REFERENCE;
  92. paraloc^.reference.index:=NR_STACK_POINTER_REG;
  93. reference.offset:=sizeof(pint)*(nr);
  94. end;
  95. end;
  96. end;
  97. function getparaloc(p : tdef) : tcgloc;
  98. begin
  99. { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER
  100. if push_addr_param for the def is true
  101. }
  102. case p.typ of
  103. orddef:
  104. result:=LOC_REGISTER;
  105. floatdef:
  106. if (cs_fp_emulation in current_settings.moduleswitches) or
  107. (current_settings.fputype in [fpu_soft]) then
  108. result := LOC_REGISTER
  109. else
  110. result := LOC_FPUREGISTER;
  111. enumdef:
  112. result:=LOC_REGISTER;
  113. pointerdef:
  114. result:=LOC_REGISTER;
  115. formaldef:
  116. result:=LOC_REGISTER;
  117. classrefdef:
  118. result:=LOC_REGISTER;
  119. procvardef:
  120. if (p.size = sizeof(pint)) then
  121. result:=LOC_REGISTER
  122. else
  123. result:=LOC_REFERENCE;
  124. recorddef:
  125. if (p.size > 4) then
  126. result:=LOC_REFERENCE
  127. else
  128. result:=LOC_REGISTER;
  129. objectdef:
  130. if is_object(p) then
  131. result:=LOC_REFERENCE
  132. else
  133. result:=LOC_REGISTER;
  134. stringdef:
  135. if is_shortstring(p) or is_longstring(p) then
  136. result:=LOC_REFERENCE
  137. else
  138. result:=LOC_REGISTER;
  139. filedef:
  140. result:=LOC_REGISTER;
  141. arraydef:
  142. if is_dynamic_array(p) then
  143. getparaloc:=LOC_REGISTER
  144. else
  145. result:=LOC_REFERENCE;
  146. setdef:
  147. if is_smallset(p) then
  148. result:=LOC_REGISTER
  149. else
  150. result:=LOC_REFERENCE;
  151. variantdef:
  152. result:=LOC_REFERENCE;
  153. { avoid problems with errornous definitions }
  154. errordef:
  155. result:=LOC_REGISTER;
  156. else
  157. internalerror(2002071001);
  158. end;
  159. end;
  160. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  161. begin
  162. result:=false;
  163. { var,out,constref always require address }
  164. if varspez in [vs_var,vs_out,vs_constref] then
  165. begin
  166. result:=true;
  167. exit;
  168. end;
  169. case def.typ of
  170. variantdef,
  171. formaldef :
  172. result:=true;
  173. { regular procvars must be passed by value, because you cannot pass
  174. the address of a local stack location when calling e.g.
  175. pthread_create with the address of a function (first of all it
  176. expects the address of the function to execute and not the address
  177. of a memory location containing that address, and secondly if you
  178. first store the address on the stack and then pass the address of
  179. this stack location, then this stack location may no longer be
  180. valid when the newly started thread accesses it.
  181. However, for "procedure of object" we must use the same calling
  182. convention as for "8 byte record" due to the need for
  183. interchangeability with the TMethod record type.
  184. }
  185. procvardef :
  186. result:=
  187. (def.size <> sizeof(pint));
  188. recorddef :
  189. result := (def.size > 8) or (varspez = vs_const);
  190. arraydef:
  191. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  192. is_open_array(def) or
  193. is_array_of_const(def) or
  194. is_array_constructor(def);
  195. objectdef :
  196. result:=is_object(def);
  197. setdef :
  198. result:=not is_smallset(def);
  199. stringdef :
  200. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  201. else
  202. ;
  203. end;
  204. end;
  205. procedure tcpuparamanager.init_values(side : tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
  206. begin
  207. cur_stack_offset:=0;
  208. case target_info.abi of
  209. abi_xtensa_windowed:
  210. begin
  211. if side=calleeside then
  212. begin
  213. curintreg:=RS_A2;
  214. maxintreg:=RS_A7;
  215. end
  216. else
  217. begin
  218. { we use CALL(X)8 only so far }
  219. curintreg:=RS_A10;
  220. maxintreg:=RS_A15;
  221. end;
  222. end;
  223. abi_xtensa_call0:
  224. begin
  225. curintreg:=RS_A2;
  226. maxintreg:=RS_A7;
  227. end;
  228. else
  229. Internalerror(2020031404);
  230. end;
  231. end;
  232. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  233. var
  234. paraloc : pcgparalocation;
  235. retcgsize : tcgsize;
  236. begin
  237. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  238. exit;
  239. paraloc:=result.add_location;
  240. { Return in FPU register? }
  241. if (result.def.typ=floatdef) and
  242. (not ((cs_fp_emulation in current_settings.moduleswitches) or
  243. (current_settings.fputype in [fpu_soft]))) then
  244. begin
  245. paraloc^.loc:=LOC_FPUREGISTER;
  246. paraloc^.register:=NR_FPU_RESULT_REG;
  247. paraloc^.size:=retcgsize;
  248. paraloc^.def:=result.def;
  249. end
  250. else
  251. { Return in register }
  252. begin
  253. if retcgsize in [OS_64,OS_S64] then
  254. begin
  255. { low 32bits }
  256. paraloc^.loc:=LOC_REGISTER;
  257. if side=callerside then
  258. paraloc^.register:=NR_A3
  259. else
  260. paraloc^.register:=NR_A3;
  261. paraloc^.size:=OS_32;
  262. paraloc^.def:=u32inttype;
  263. { high 32bits }
  264. paraloc:=result.add_location;
  265. paraloc^.loc:=LOC_REGISTER;
  266. if side=callerside then
  267. paraloc^.register:=NR_A2
  268. else
  269. paraloc^.register:=NR_A2;
  270. paraloc^.size:=OS_32;
  271. paraloc^.def:=u32inttype;
  272. end
  273. else
  274. begin
  275. paraloc^.loc:=LOC_REGISTER;
  276. if side=callerside then
  277. case target_info.abi of
  278. abi_xtensa_call0:
  279. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  280. abi_xtensa_windowed:
  281. { only call8 used/supported so far }
  282. paraloc^.register:=newreg(R_INTREGISTER,RS_A10,cgsize2subreg(R_INTREGISTER,retcgsize));
  283. else
  284. Internalerror(2020031502);
  285. end
  286. else
  287. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  288. paraloc^.size:=retcgsize;
  289. paraloc^.def:=result.def;
  290. end;
  291. end;
  292. end;
  293. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  294. var
  295. cur_stack_offset: aword;
  296. curintreg: tsuperregister;
  297. begin
  298. init_values(side,curintreg,cur_stack_offset);
  299. result := create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset,false);
  300. create_funcretloc_info(p,side);
  301. end;
  302. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
  303. var curintreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
  304. var
  305. stack_offset: longint;
  306. paralen: aint;
  307. nextintreg : tsuperregister;
  308. locdef,
  309. fdef,
  310. paradef : tdef;
  311. paraloc : pcgparalocation;
  312. i : integer;
  313. hp : tparavarsym;
  314. loc : tcgloc;
  315. paracgsize: tcgsize;
  316. firstparaloc: boolean;
  317. begin
  318. {$ifdef extdebug}
  319. if po_explicitparaloc in p.procoptions then
  320. internalerror(200411141);
  321. {$endif extdebug}
  322. result:=0;
  323. nextintreg := curintreg;
  324. stack_offset := cur_stack_offset;
  325. for i:=0 to paras.count-1 do
  326. begin
  327. hp:=tparavarsym(paras[i]);
  328. paradef := hp.vardef;
  329. hp.paraloc[side].reset;
  330. { currently only support C-style array of const }
  331. if (p.proccalloption in cstylearrayofconst) and
  332. is_array_of_const(paradef) then
  333. begin
  334. paraloc:=hp.paraloc[side].add_location;
  335. { hack: the paraloc must be valid, but is not actually used }
  336. paraloc^.loc := LOC_REGISTER;
  337. paraloc^.register := NR_A2;
  338. paraloc^.size := OS_ADDR;
  339. paraloc^.def:=voidpointertype;
  340. break;
  341. end;
  342. if push_addr_param(hp.varspez,paradef,p.proccalloption) then
  343. begin
  344. paradef:=cpointerdef.getreusable_no_free(paradef);
  345. loc:=LOC_REGISTER;
  346. paracgsize := OS_ADDR;
  347. paralen := tcgsize2size[OS_ADDR];
  348. end
  349. else
  350. begin
  351. if not is_special_array(paradef) then
  352. paralen := paradef.size
  353. else
  354. paralen := tcgsize2size[def_cgsize(paradef)];
  355. paracgsize:=def_cgsize(paradef);
  356. { for things like formaldef }
  357. if (paracgsize=OS_NO) then
  358. begin
  359. paracgsize:=OS_ADDR;
  360. paralen := tcgsize2size[OS_ADDR];
  361. end;
  362. end;
  363. loc := getparaloc(paradef);
  364. hp.paraloc[side].alignment:=std_param_align;
  365. hp.paraloc[side].size:=paracgsize;
  366. hp.paraloc[side].intsize:=paralen;
  367. hp.paraloc[side].def:=paradef;
  368. if (is_64bit(paradef)) and
  369. odd(nextintreg-RS_A2) then
  370. inc(nextintreg);
  371. if (paralen = 0) then
  372. if (paradef.typ = recorddef) then
  373. begin
  374. paraloc:=hp.paraloc[side].add_location;
  375. paraloc^.loc := LOC_VOID;
  376. end
  377. else
  378. internalerror(2020031407);
  379. locdef:=paradef;
  380. firstparaloc:=true;
  381. { can become < 0 for e.g. 3-byte records }
  382. while (paralen > 0) do
  383. begin
  384. paraloc:=hp.paraloc[side].add_location;
  385. { In case of po_delphi_nested_cc, the parent frame pointer
  386. is always passed on the stack. }
  387. if (loc = LOC_REGISTER) and
  388. (nextintreg <= maxintreg) and
  389. (not(vo_is_parentfp in hp.varoptions) or
  390. not(po_delphi_nested_cc in p.procoptions)) then
  391. begin
  392. paraloc^.loc := loc;
  393. { make sure we don't lose whether or not the type is signed }
  394. if (paradef.typ<>orddef) then
  395. begin
  396. paracgsize:=int_cgsize(paralen);
  397. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  398. end;
  399. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  400. begin
  401. paraloc^.size:=OS_INT;
  402. paraloc^.def:=u32inttype;
  403. end
  404. else
  405. begin
  406. paraloc^.size:=paracgsize;
  407. paraloc^.def:=locdef;
  408. end;
  409. { aix requires that record data stored in parameter
  410. registers is left-aligned }
  411. if (target_info.system in systems_aix) and
  412. (paradef.typ = recorddef) and
  413. (paralen < sizeof(aint)) then
  414. begin
  415. paraloc^.shiftval := (sizeof(aint)-paralen)*(-8);
  416. paraloc^.size := OS_INT;
  417. paraloc^.def := u32inttype;
  418. end;
  419. paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBNONE);
  420. inc(nextintreg);
  421. dec(paralen,tcgsize2size[paraloc^.size]);
  422. end
  423. else if (loc = LOC_FPUREGISTER) and
  424. (nextintreg <= maxintreg) then
  425. begin
  426. paraloc^.loc:=loc;
  427. paraloc^.size := paracgsize;
  428. paraloc^.def := paradef;
  429. paraloc^.register:=newreg(R_FPUREGISTER,nextintreg,R_SUBWHOLE);
  430. inc(nextintreg);
  431. dec(paralen,tcgsize2size[paraloc^.size]);
  432. end
  433. else { LOC_REFERENCE }
  434. begin
  435. paraloc^.loc:=LOC_REFERENCE;
  436. case loc of
  437. LOC_FPUREGISTER:
  438. begin
  439. paraloc^.size:=int_float_cgsize(paralen);
  440. case paraloc^.size of
  441. OS_F32: paraloc^.def:=s32floattype;
  442. OS_F64: paraloc^.def:=s64floattype;
  443. else
  444. internalerror(2020031406);
  445. end;
  446. end;
  447. LOC_REGISTER,
  448. LOC_REFERENCE:
  449. begin
  450. paraloc^.size:=int_cgsize(paralen);
  451. if paraloc^.size<>OS_NO then
  452. paraloc^.def:=cgsize_orddef(paraloc^.size)
  453. else
  454. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  455. end;
  456. else
  457. internalerror(2020031405);
  458. end;
  459. if (side = callerside) then
  460. paraloc^.reference.index:=NR_STACK_POINTER_REG
  461. else
  462. begin
  463. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  464. { create_paraloc_info_intern might be also called when being outside of
  465. code generation so current_procinfo might be not set }
  466. if assigned(current_procinfo) then
  467. txtensaprocinfo(current_procinfo).needs_frame_pointer := true;
  468. end;
  469. paraloc^.reference.offset:=stack_offset;
  470. inc(stack_offset,align(paralen,4));
  471. while (paralen > 0) and
  472. (nextintreg < maxintreg) do
  473. begin
  474. inc(nextintreg);
  475. dec(paralen,sizeof(pint));
  476. end;
  477. paralen := 0;
  478. end;
  479. firstparaloc:=false;
  480. end;
  481. end;
  482. curintreg:=nextintreg;
  483. cur_stack_offset:=stack_offset;
  484. result:=stack_offset;
  485. end;
  486. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  487. var
  488. cur_stack_offset: aword;
  489. parasize, l: longint;
  490. curintreg, firstfloatreg: tsuperregister;
  491. i : integer;
  492. hp: tparavarsym;
  493. paraloc: pcgparalocation;
  494. begin
  495. init_values(side,curintreg,cur_stack_offset);
  496. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset, false);
  497. if (p.proccalloption in cstylearrayofconst) then
  498. { just continue loading the parameters in the registers }
  499. begin
  500. if assigned(varargspara) then
  501. begin
  502. if side=callerside then
  503. result:=create_paraloc_info_intern(p,side,varargspara,curintreg,cur_stack_offset,true)
  504. else
  505. internalerror(2020030704);
  506. end;
  507. end
  508. else
  509. internalerror(2020030703);
  510. create_funcretloc_info(p,side);
  511. end;
  512. begin
  513. paramanager:=tcpuparamanager.create;
  514. end.