cpupara.pas 19 KB

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