cpupara.pas 14 KB

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