cpupara.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Calling conventions for the SPARC64
  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. unit cpupara;
  17. {$i fpcdefs.inc}
  18. interface
  19. uses
  20. globtype,
  21. cclasses,
  22. aasmtai,aasmdata,
  23. cpubase,cpuinfo,
  24. sppara,
  25. symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase,cgutils;
  26. type
  27. tcpuparamanager=class(TSparcParaManager)
  28. procedure create_paraloc_info_intern(p : tabstractprocdef; side : tcallercallee; paras : tparalist; var curintreg : LongInt;
  29. curfloatreg : tsuperregister; var cur_stack_offset : aword);override;
  30. function push_addr_param(varspez : tvarspez; def : tdef; calloption : tproccalloption) : boolean;override;
  31. function ret_in_param(def : tdef; pd : tabstractprocdef) : boolean;override;
  32. function get_funcretloc(p : tabstractprocdef; side : tcallercallee; forcetempdef : tdef) : tcgpara;override;
  33. private
  34. function push_addr_param_intern(varspez : tvarspez; def : tdef; calloption : tproccalloption; recsizelimit : aword) : boolean;
  35. procedure create_paraloc1_info_intern(p : tabstractprocdef; side : tcallercallee; paradef : tdef; var loc : TCGPara; varspez : tvarspez; varoptions : tvaroptions; recsizelimit : aword;
  36. var curintreg : LongInt; var curfloatreg : tsuperregister; var cur_stack_offset : aword);
  37. end;
  38. implementation
  39. uses
  40. cutils,verbose,systems,
  41. defutil,
  42. cgobj;
  43. { true if a parameter is too large to copy and only the address is pushed }
  44. function tcpuparamanager.push_addr_param_intern(varspez:tvarspez;def : tdef;calloption : tproccalloption;recsizelimit : aword) : boolean;
  45. begin
  46. result:=false;
  47. { var,out,constref always require address }
  48. if varspez in [vs_var,vs_out,vs_constref] then
  49. begin
  50. result:=true;
  51. exit;
  52. end;
  53. case def.typ of
  54. arraydef:
  55. result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
  56. is_open_array(def) or
  57. is_array_of_const(def) or
  58. is_array_constructor(def);
  59. recorddef:
  60. result:=def.size>recsizelimit;
  61. variantdef:
  62. result:=false;
  63. formaldef :
  64. result:=true;
  65. objectdef :
  66. result:=(is_object(def) and (def.size>recsizelimit));
  67. stringdef :
  68. result:=(tstringdef(def).stringtype in [st_shortstring,st_longstring]);
  69. procvardef :
  70. result:=false;
  71. setdef :
  72. result:=not is_smallset(def);
  73. else
  74. ;
  75. end;
  76. end;
  77. { true if a parameter is too large to copy and only the address is pushed }
  78. function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
  79. begin
  80. result:=push_addr_param_intern(varspez,def,calloption,16);
  81. end;
  82. function tcpuparamanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean;
  83. begin
  84. if handle_common_ret_in_param(def,pd,result) then
  85. exit;
  86. case def.typ of
  87. { it is a matter of interpretation, if objects should be returned in registers according to the abi as the
  88. abi talks only about structures and unions
  89. at least for the compiler, it is a problem, if an object is returned in registers
  90. consider
  91. tobject1 = object
  92. function f : tobject1;
  93. ...
  94. contructor init;
  95. end;
  96. the constructor changes the size of tobject1, so its return location might change from register to memory, this
  97. is something the compiler could not handle currently, so we do not return objects in registers yet
  98. objectdef:
  99. begin
  100. result:=is_object(def) and (def.size>32);
  101. exit;
  102. end;}
  103. recorddef:
  104. begin
  105. result:=def.size>32;
  106. exit;
  107. end;
  108. else
  109. ;
  110. end;
  111. result:=inherited ret_in_param(def,pd);
  112. end;
  113. procedure tcpuparamanager.create_paraloc1_info_intern(
  114. p : tabstractprocdef; side: tcallercallee;paradef:tdef;var loc : TCGPara;varspez : tvarspez;varoptions : tvaroptions;recsizelimit : aword;
  115. var curintreg: LongInt; var curfloatreg: tsuperregister; var cur_stack_offset : aword);
  116. procedure nextloc(currsize : TCgSize);
  117. begin
  118. if curintreg>high(tparasupregs) then
  119. begin
  120. if (currsize<low(tcgsize2size)) or (currsize>high(tcgsize2size)) then
  121. internalerror(2017080101);
  122. { Parameters are aligned at 8 bytes }
  123. inc(cur_stack_offset,align(tcgsize2size[currsize],sizeof(pint)));
  124. end;
  125. inc(curintreg);
  126. if currsize=OS_F128 then
  127. inc(curfloatreg,4)
  128. else
  129. inc(curfloatreg,2);
  130. end;
  131. var
  132. paraloc : pcgparalocation;
  133. paracgsize : tcgsize;
  134. hparasupregs : pparasupregs;
  135. paralen : longint;
  136. begin
  137. if side=callerside then
  138. hparasupregs:=@paraoutsupregs
  139. else
  140. hparasupregs:=@parainsupregs;
  141. { currently only support C-style array of const,
  142. there should be no location assigned to the vararg array itself }
  143. if (p.proccalloption in cstylearrayofconst) and
  144. is_array_of_const(paradef) then
  145. begin
  146. paraloc:=loc.add_location;
  147. { hack: the paraloc must be valid, but is not actually used }
  148. paraloc^.loc:=LOC_REGISTER;
  149. paraloc^.register:=NR_G0;
  150. paraloc^.size:=OS_ADDR;
  151. paraloc^.def:=voidpointertype;
  152. exit;
  153. end;
  154. if push_addr_param_intern(varspez,paradef,p.proccalloption,recsizelimit) then
  155. begin
  156. paracgsize:=OS_ADDR;
  157. paradef:=cpointerdef.getreusable_no_free(paradef);
  158. end
  159. else
  160. begin
  161. paracgsize:=def_cgsize(paradef);
  162. if paradef.typ=formaldef then
  163. begin
  164. paracgsize:=OS_ADDR;
  165. paradef:=voidpointertype;
  166. end;
  167. end;
  168. loc.reset;
  169. loc.size:=paracgsize;
  170. loc.def:=paradef;
  171. if side=callerside then
  172. loc.Alignment:=std_param_align
  173. else
  174. loc.Alignment:=paradef.alignment;
  175. { sparc64 returns records up to a size of 32 in register, we cannot encode this
  176. in paracgsize, so paracgsize is OS_NO in this case }
  177. if paracgsize=OS_NO then
  178. paralen:=paradef.size
  179. else
  180. paralen:=tcgsize2size[paracgsize];
  181. loc.intsize:=paralen;
  182. while paralen>0 do
  183. begin
  184. paraloc:=loc.add_location;
  185. paraloc^.size:=paracgsize;
  186. paraloc^.def:=paradef;
  187. { ret in param? }
  188. if vo_is_funcret in varoptions then
  189. begin
  190. paraloc^.loc:=LOC_REFERENCE;
  191. paraloc^.reference.offset:=128;
  192. if side=callerside then
  193. paraloc^.reference.index:=NR_STACK_POINTER_REG
  194. else
  195. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  196. inc(paraloc^.reference.offset,STACK_BIAS);
  197. end
  198. { In case of po_delphi_nested_cc, the parent frame pointer
  199. is always passed on the stack. }
  200. else if (curintreg<=high(tparasupregs)) and
  201. (not(vo_is_parentfp in varoptions) or
  202. not(po_delphi_nested_cc in p.procoptions)) then
  203. begin
  204. if paraloc^.size in [OS_F32,OS_F64,OS_F128] then
  205. begin
  206. paraloc^.loc:=LOC_FPUREGISTER;
  207. case paraloc^.size of
  208. OS_F32:
  209. { singles are put into the uneven register }
  210. paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg+1,R_SUBFS);
  211. OS_F64:
  212. paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg,R_SUBFD);
  213. OS_F128:
  214. paraloc^.register:=newreg(R_FPUREGISTER,curfloatreg,R_SUBFQ);
  215. else
  216. Internalerror(2017072301);
  217. end;
  218. end
  219. else
  220. begin
  221. if paracgsize in [OS_NO,OS_128,OS_S128] then
  222. begin
  223. if paralen>4 then
  224. begin
  225. paraloc^.size:=OS_INT;
  226. paraloc^.def:=u64inttype;
  227. end
  228. else
  229. begin
  230. { for 3-byte records }
  231. paraloc^.size:=OS_32;
  232. paraloc^.def:=u32inttype;
  233. end;
  234. end;
  235. paraloc^.loc:=LOC_REGISTER;
  236. paraloc^.register:=newreg(R_INTREGISTER,hparasupregs^[curintreg],R_SUBWHOLE);
  237. { left align }
  238. if (target_info.endian=endian_big) and
  239. not(paraloc^.size in [OS_64,OS_S64]) and
  240. (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then
  241. begin
  242. paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size])*8;
  243. paraloc^.Size:=OS_64;
  244. end;
  245. end;
  246. nextloc(paraloc^.Size);
  247. end
  248. else
  249. begin
  250. paraloc^.loc:=LOC_REFERENCE;
  251. paraloc^.reference.offset:=target_info.first_parm_offset+cur_stack_offset;
  252. if side=callerside then
  253. paraloc^.reference.index:=NR_STACK_POINTER_REG
  254. else
  255. paraloc^.reference.index:=NR_FRAME_POINTER_REG;
  256. inc(paraloc^.reference.offset,STACK_BIAS);
  257. if (target_info.endian=endian_big) and
  258. (paralen<tcgsize2size[OS_INT]) and
  259. (paradef.typ<>recorddef) then
  260. inc(paraloc^.reference.offset,4-paralen);
  261. { Parameters are aligned to 8 byte boundaries }
  262. inc(cur_stack_offset,align(paralen,8));
  263. { a stack location covers always the remainder of a parameter }
  264. exit;
  265. end;
  266. dec(paralen,tcgsize2size[paraloc^.size]);
  267. end;
  268. end;
  269. procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
  270. var curintreg: LongInt; curfloatreg: tsuperregister; var cur_stack_offset : aword);
  271. var
  272. i : integer;
  273. begin
  274. for i:=0 to paras.count-1 do
  275. create_paraloc1_info_intern(p,side,tparavarsym(paras[i]).vardef,tparavarsym(paras[i]).paraloc[side],tparavarsym(paras[i]).varspez,
  276. tparavarsym(paras[i]).varoptions,16,curintreg,curfloatreg,cur_stack_offset);
  277. end;
  278. function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  279. var
  280. paraloc : pcgparalocation;
  281. retcgsize : tcgsize;
  282. curintreg : LongInt;
  283. curfloatreg : tsuperregister;
  284. cur_stack_offset : aword;
  285. begin
  286. if set_common_funcretloc_info(p,forcetempdef,retcgsize,result) then
  287. exit;
  288. if ret_in_param(result.def,p) then
  289. Internalerror(2017080601);
  290. if is_record(result.def) or is_object(result.def) then
  291. begin
  292. curintreg:=0;
  293. curfloatreg:=RS_F0;
  294. cur_stack_offset:=0;
  295. create_paraloc1_info_intern(p,side,result.def,result,vs_value,
  296. [],32,curintreg,curfloatreg,cur_stack_offset);
  297. { sparc64 calling conventions are difficult, so better check if everything is ok }
  298. if result.location^.loc=LOC_INVALID then
  299. Internalerror(2017080501);
  300. end
  301. else
  302. begin
  303. paraloc:=result.add_location;
  304. { Return in FPU register? }
  305. if result.def.typ=floatdef then
  306. begin
  307. paraloc^.loc:=LOC_FPUREGISTER;
  308. paraloc^.register:=NR_FPU_RESULT_REG;
  309. if retcgsize=OS_F64 then
  310. setsubreg(paraloc^.register,R_SUBFD);
  311. paraloc^.size:=retcgsize;
  312. paraloc^.def:=result.def;
  313. end
  314. else
  315. { Return in register }
  316. begin
  317. paraloc^.loc:=LOC_REGISTER;
  318. paraloc^.size:=retcgsize;
  319. paraloc^.def:=result.def;
  320. if (side=callerside) then
  321. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RESULT_REG,cgsize2subreg(R_INTREGISTER,retcgsize))
  322. else
  323. paraloc^.register:=newreg(R_INTREGISTER,RS_FUNCTION_RETURN_REG,cgsize2subreg(R_INTREGISTER,retcgsize));
  324. end;
  325. end;
  326. end;
  327. begin
  328. ParaManager:=tcpuparamanager.create;
  329. end.