cpupara.pas 20 KB

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