cpupara.pas 17 KB

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