cpupara.pas 18 KB

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