cpupara.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  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. function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
  32. function create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
  33. function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
  34. function ret_in_param(def: tdef; pd: tabstractprocdef): boolean;override;
  35. private
  36. { the max. register depends on the used call instruction }
  37. maxintreg : TSuperRegister;
  38. procedure init_values(p: tabstractprocdef; 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. function create_paraloc1_info_intern(p: tabstractprocdef; side: tcallercallee; paradef: tdef; var loc: TCGPara; varspez: tvarspez; varoptions: tvaroptions;
  43. var curintreg: tsuperregister; var cur_stack_offset: aword; varargsparas, funcret: boolean): longint;
  44. end;
  45. implementation
  46. uses
  47. cpuinfo,globals,
  48. verbose,systems,
  49. defutil,
  50. symtable,symcpu,
  51. procinfo,cpupi;
  52. function tcpuparamanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
  53. begin
  54. { we have actually to check what calling instruction is used, but we do not handle this,
  55. instead CALL(X)8 is used always }
  56. if target_info.abi=abi_xtensa_windowed then
  57. result:=[RS_A8..RS_A15]
  58. else
  59. result:=[RS_A0..RS_A11];
  60. end;
  61. function tcpuparamanager.get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;
  62. begin
  63. result:=[RS_F0..RS_F15];
  64. end;
  65. function getparaloc(p : tdef) : tcgloc;
  66. begin
  67. case p.typ of
  68. orddef,
  69. floatdef,
  70. enumdef,
  71. pointerdef,
  72. formaldef,
  73. classrefdef,
  74. procvardef,
  75. recorddef,
  76. objectdef,
  77. stringdef,
  78. filedef,
  79. arraydef,
  80. setdef,
  81. variantdef,
  82. { avoid problems with errornous definitions }
  83. errordef:
  84. result:=LOC_REGISTER;
  85. else
  86. internalerror(2020082501);
  87. end;
  88. end;
  89. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  90. begin
  91. result:=false;
  92. { var,out,constref always require address }
  93. if varspez in [vs_var,vs_out,vs_constref] then
  94. begin
  95. result:=true;
  96. exit;
  97. end;
  98. case def.typ of
  99. formaldef :
  100. result:=true;
  101. recorddef :
  102. result:=(varspez = vs_const);
  103. arraydef:
  104. result:=true;
  105. objectdef :
  106. result:=is_object(def) and (varspez = vs_const);
  107. variantdef,
  108. setdef :
  109. result:=(varspez = vs_const);
  110. stringdef :
  111. result:=tstringdef(def).stringtype in [st_shortstring,st_longstring];
  112. else
  113. ;
  114. end;
  115. end;
  116. procedure tcpuparamanager.init_values(p : tabstractprocdef; side : tcallercallee; var curintreg: tsuperregister; var cur_stack_offset: aword);
  117. begin
  118. cur_stack_offset:=0;
  119. case target_info.abi of
  120. abi_xtensa_windowed:
  121. begin
  122. if side=calleeside then
  123. begin
  124. curintreg:=RS_A2;
  125. maxintreg:=RS_A7;
  126. if current_procinfo.framepointer=NR_STACK_POINTER_REG then
  127. cur_stack_offset:=(p as tcpuprocdef).total_stackframe_size;
  128. end
  129. else
  130. begin
  131. { we use CALL(X)8 only so far }
  132. curintreg:=RS_A10;
  133. maxintreg:=RS_A15;
  134. end;
  135. end;
  136. abi_xtensa_call0:
  137. begin
  138. curintreg:=RS_A2;
  139. maxintreg:=RS_A7;
  140. end;
  141. else
  142. Internalerror(2020031404);
  143. end;
  144. end;
  145. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  146. var
  147. paraloc : pcgparalocation;
  148. retcgsize : tcgsize;
  149. cur_stack_offset: aword;
  150. curintreg: tsuperregister;
  151. begin
  152. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  153. exit;
  154. paraloc:=result.add_location;
  155. if retcgsize in [OS_64,OS_S64,OS_F64] then
  156. begin
  157. { low 32bits }
  158. paraloc^.loc:=LOC_REGISTER;
  159. paraloc^.size:=OS_32;
  160. paraloc^.def:=u32inttype;
  161. if side=callerside then
  162. case target_info.abi of
  163. abi_xtensa_call0:
  164. paraloc^.register:=NR_A2;
  165. abi_xtensa_windowed:
  166. { only call8 used/supported so far }
  167. paraloc^.register:=newreg(R_INTREGISTER,RS_A10,cgsize2subreg(R_INTREGISTER,retcgsize));
  168. else
  169. Internalerror(2020032201);
  170. end
  171. else
  172. paraloc^.register:=NR_A2;
  173. { high 32bits }
  174. paraloc:=result.add_location;
  175. paraloc^.loc:=LOC_REGISTER;
  176. paraloc^.size:=OS_32;
  177. paraloc^.def:=u32inttype;
  178. if side=callerside then
  179. case target_info.abi of
  180. abi_xtensa_call0:
  181. paraloc^.register:=NR_A3;
  182. abi_xtensa_windowed:
  183. { only call8 used/supported so far }
  184. paraloc^.register:=newreg(R_INTREGISTER,RS_A11,cgsize2subreg(R_INTREGISTER,retcgsize));
  185. else
  186. Internalerror(2020032202);
  187. end
  188. else
  189. paraloc^.register:=NR_A3;
  190. end
  191. else if (result.def.size>4) and (result.def.size<=16) then
  192. begin
  193. init_values(p,side,curintreg,cur_stack_offset);
  194. create_paraloc1_info_intern(p,side,result.def,result,vs_value,[],curintreg,cur_stack_offset,false,true);
  195. { check if everything is ok }
  196. if result.location^.loc=LOC_INVALID then
  197. Internalerror(2020082901);
  198. end
  199. else
  200. begin
  201. paraloc^.loc:=LOC_REGISTER;
  202. if side=callerside then
  203. case target_info.abi of
  204. abi_xtensa_call0:
  205. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  206. abi_xtensa_windowed:
  207. { only call8 used/supported so far }
  208. paraloc^.register:=newreg(R_INTREGISTER,RS_A10,cgsize2subreg(R_INTREGISTER,retcgsize));
  209. else
  210. Internalerror(2020031502);
  211. end
  212. else
  213. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  214. paraloc^.size:=OS_32;
  215. paraloc^.def:=result.def;
  216. end;
  217. end;
  218. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  219. var
  220. i: longint;
  221. sym: tsym;
  222. basedef: tdef;
  223. begin
  224. if handle_common_ret_in_param(def,pd,result) then
  225. exit;
  226. case def.typ of
  227. arraydef,
  228. objectdef,
  229. stringdef,
  230. setdef,
  231. recorddef:
  232. result:=def.size>16;
  233. floatdef,
  234. variantdef,
  235. procvardef:
  236. result:=false
  237. else
  238. result:=inherited ret_in_param(def,pd);
  239. end;
  240. end;
  241. function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
  242. var
  243. cur_stack_offset: aword;
  244. curintreg: tsuperregister;
  245. begin
  246. init_values(p,side,curintreg,cur_stack_offset);
  247. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset,false);
  248. if result<cur_stack_offset then
  249. Internalerror(2020083001);
  250. create_funcretloc_info(p,side);
  251. end;
  252. function tcpuparamanager.create_paraloc1_info_intern(p : tabstractprocdef; side: tcallercallee; paradef:tdef;var loc : TCGPara;varspez : tvarspez;varoptions : tvaroptions;
  253. var curintreg: tsuperregister; var cur_stack_offset: aword; varargsparas, funcret: boolean):longint;
  254. var
  255. paralen: aint;
  256. locdef,
  257. fdef : tdef;
  258. paraloc : pcgparalocation;
  259. paracgsize: tcgsize;
  260. firstparaloc: boolean;
  261. locpara: TCGLoc;
  262. begin
  263. {$ifdef extdebug}
  264. if po_explicitparaloc in p.procoptions then
  265. internalerror(200411141);
  266. {$endif extdebug}
  267. loc.reset;
  268. { currently only support C-style array of const }
  269. if (p.proccalloption in cstylearrayofconst) and
  270. is_array_of_const(paradef) then
  271. begin
  272. paraloc:=loc.add_location;
  273. { hack: the paraloc must be valid, but is not actually used }
  274. paraloc^.loc := LOC_REGISTER;
  275. paraloc^.register := NR_A2;
  276. paraloc^.size := OS_ADDR;
  277. paraloc^.def:=voidpointertype;
  278. result:=cur_stack_offset;
  279. exit;
  280. end;
  281. if not is_special_array(paradef) then
  282. paralen:=paradef.size
  283. else
  284. paralen:=tcgsize2size[def_cgsize(paradef)];
  285. if (not(funcret) and push_addr_param(varspez,paradef,p.proccalloption)) or
  286. (funcret and (paralen>24)) then
  287. begin
  288. paradef:=cpointerdef.getreusable_no_free(paradef);
  289. locpara:=LOC_REGISTER;
  290. paracgsize:=OS_ADDR;
  291. paralen:=tcgsize2size[OS_ADDR];
  292. end
  293. else
  294. begin
  295. if (paradef.typ in [objectdef,arraydef,recorddef,setdef,stringdef]) and
  296. not is_special_array(paradef) and
  297. (varspez in [vs_value,vs_const]) then
  298. paracgsize:=int_cgsize(paralen)
  299. else
  300. begin
  301. paracgsize:=def_cgsize(paradef);
  302. if paracgsize=OS_NO then
  303. begin
  304. paracgsize:=OS_ADDR;
  305. paralen:=tcgsize2size[OS_ADDR];
  306. paradef:=voidpointertype;
  307. end;
  308. end;
  309. end;
  310. locpara:=getparaloc(paradef);
  311. if (maxintreg-curintreg+1)*4<paralen then
  312. begin
  313. locpara:=LOC_REFERENCE;
  314. curintreg:=maxintreg+1;
  315. end;
  316. loc.alignment:=std_param_align;
  317. loc.size:=paracgsize;
  318. loc.intsize:=paralen;
  319. loc.def:=paradef;
  320. if (locpara=LOC_REGISTER) and (paradef.alignment>4) and
  321. odd(curintreg-RS_A2) then
  322. inc(curintreg);
  323. if (paralen = 0) then
  324. if (paradef.typ = recorddef) then
  325. begin
  326. paraloc:=loc.add_location;
  327. paraloc^.loc := LOC_VOID;
  328. end
  329. else
  330. internalerror(2020031407);
  331. locdef:=paradef;
  332. firstparaloc:=true;
  333. { can become < 0 for e.g. 3-byte records }
  334. while paralen>0 do
  335. begin
  336. paraloc:=loc.add_location;
  337. { In case of po_delphi_nested_cc, the parent frame pointer
  338. is always passed on the stack. }
  339. if (locpara=LOC_REGISTER) and
  340. (curintreg<=maxintreg) and
  341. (not(vo_is_parentfp in varoptions) or
  342. not(po_delphi_nested_cc in p.procoptions)) then
  343. begin
  344. paraloc^.loc:=locpara;
  345. { make sure we don't lose whether or not the type is signed }
  346. if (paradef.typ<>orddef) then
  347. begin
  348. paracgsize:=int_cgsize(paralen);
  349. locdef:=get_paraloc_def(paradef,paralen,firstparaloc);
  350. end;
  351. if (paracgsize in [OS_NO,OS_64,OS_S64,OS_128,OS_S128]) then
  352. begin
  353. paraloc^.size:=OS_INT;
  354. paraloc^.def:=u32inttype;
  355. end
  356. else
  357. begin
  358. paraloc^.size:=paracgsize;
  359. paraloc^.def:=locdef;
  360. end;
  361. paraloc^.register:=newreg(R_INTREGISTER,curintreg,R_SUBNONE);
  362. inc(curintreg);
  363. dec(paralen,tcgsize2size[paraloc^.size]);
  364. end
  365. else { LOC_REFERENCE }
  366. begin
  367. paraloc^.loc:=LOC_REFERENCE;
  368. case locpara of
  369. LOC_REGISTER,
  370. LOC_REFERENCE:
  371. begin
  372. paraloc^.size:=int_cgsize(paralen);
  373. if paraloc^.size<>OS_NO then
  374. paraloc^.def:=cgsize_orddef(paraloc^.size)
  375. else
  376. paraloc^.def:=carraydef.getreusable_no_free(u8inttype,paralen);
  377. end;
  378. else
  379. internalerror(2020031405);
  380. end;
  381. if side = callerside then
  382. paraloc^.reference.index:=NR_STACK_POINTER_REG
  383. else
  384. paraloc^.reference.index:=current_procinfo.framepointer;
  385. cur_stack_offset:=align(cur_stack_offset,paradef.alignment);
  386. paraloc^.reference.offset:=cur_stack_offset;
  387. inc(cur_stack_offset,align(paralen,4));
  388. while (paralen > 0) and
  389. (curintreg < maxintreg) do
  390. begin
  391. inc(curintreg);
  392. dec(paralen,sizeof(pint));
  393. end;
  394. paralen := 0;
  395. end;
  396. firstparaloc:=false;
  397. end;
  398. result:=cur_stack_offset;
  399. end;
  400. function tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras:tparalist;
  401. var curintreg: tsuperregister; var cur_stack_offset: aword; varargsparas: boolean):longint;
  402. var
  403. i : integer;
  404. begin
  405. result:=0;
  406. for i:=0 to paras.count-1 do
  407. result:=create_paraloc1_info_intern(p,side,tparavarsym(paras[i]).vardef,tparavarsym(paras[i]).paraloc[side],tparavarsym(paras[i]).varspez,
  408. tparavarsym(paras[i]).varoptions,curintreg,cur_stack_offset,false,false);
  409. end;
  410. function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
  411. var
  412. cur_stack_offset: aword;
  413. parasize, l: longint;
  414. curintreg: tsuperregister;
  415. i : integer;
  416. hp: tparavarsym;
  417. paraloc: pcgparalocation;
  418. begin
  419. init_values(p,side,curintreg,cur_stack_offset);
  420. result:=create_paraloc_info_intern(p,side,p.paras,curintreg,cur_stack_offset, false);
  421. if (p.proccalloption in cstylearrayofconst) then
  422. { just continue loading the parameters in the registers }
  423. begin
  424. if assigned(varargspara) then
  425. begin
  426. if side=callerside then
  427. result:=create_paraloc_info_intern(p,side,varargspara,curintreg,cur_stack_offset,true)
  428. else
  429. internalerror(2020030704);
  430. end;
  431. end
  432. else
  433. internalerror(2020030703);
  434. create_funcretloc_info(p,side);
  435. end;
  436. begin
  437. paramanager:=tcpuparamanager.create;
  438. end.