2
0

llvmpara.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. {
  2. Copyright (c) 2013 by Jonas Maebe
  3. Includes the llvm parameter manager
  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 llvmpara;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,aasmdata,
  22. symconst,symtype,symdef,symsym,
  23. parabase,cgbase,
  24. cpupara;
  25. type
  26. { LLVM stands for "low level code generator", and regarding parameter
  27. handling it is indeed very low level. We are responsible for decomposing
  28. aggregate parameters into multiple simple parameters in case they have
  29. to be passed in special registers (such as floating point or SSE), and
  30. also for indicating whether e.g. 8 bit parameters need to be sign or
  31. zero exntended. This corresponds to pretty much what we do when creating
  32. parameter locations, so we reuse the original parameter manager and then
  33. process its output.
  34. The future will tell whether we can do this without
  35. architecture-specific code, or whether we will have to integrate parts
  36. into the various tcpuparamanager classes }
  37. tllvmparamanager = class(tcpuparamanager)
  38. function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
  39. procedure getcgtempparaloc(list: TAsmList; pd: tabstractprocdef; nr: longint; var cgpara: tcgpara); override;
  40. function param_use_paraloc(const cgpara: tcgpara): boolean; override;
  41. procedure createtempparaloc(list: TAsmList; calloption: tproccalloption; parasym: tparavarsym; can_use_final_stack_loc: boolean; var cgpara: TCGPara); override;
  42. function create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint; override;
  43. function create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist): longint; override;
  44. function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara; override;
  45. function has_strict_proc_signature: boolean; override;
  46. private
  47. procedure create_paraloc_info_internllvm(p: tabstractprocdef; side: tcallercallee);
  48. procedure set_llvm_paraloc_name(p: tabstractprocdef; hp: tparavarsym; var para: tcgpara);
  49. procedure add_llvm_callee_paraloc_names(p: tabstractprocdef);
  50. procedure reducetosingleregparaloc(paraloc: PCGParaLocation; def: tdef; reg: tregister);
  51. procedure reduceparalocs(p: tabstractprocdef; side: tcallercallee; paras: tparalist);
  52. end;
  53. implementation
  54. uses
  55. verbose,
  56. aasmbase,
  57. llvmsym,
  58. paramgr,defutil,llvmdef,
  59. cgutils,tgobj,hlcgobj;
  60. { tllvmparamanager }
  61. function tllvmparamanager.push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
  62. begin
  63. if def<>llvm_metadatatype then
  64. begin
  65. result:=inherited;
  66. exit;
  67. end;
  68. result:=false;
  69. end;
  70. procedure tllvmparamanager.getcgtempparaloc(list: TAsmList; pd: tabstractprocdef; nr: longint; var cgpara: tcgpara);
  71. begin
  72. if (nr<1) or (nr>pd.paras.count) then
  73. InternalError(2015040402);
  74. pd.init_paraloc_info(callerside);
  75. createtempparaloc(list,pd.proccalloption,tparavarsym(pd.paras[nr-1]),true,cgpara);
  76. end;
  77. function tllvmparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
  78. begin
  79. { we can use the paraloc on the callee side if the SSA property is
  80. guaranteed, i.e., if it is a constant location (and if it's not been
  81. split up into multiple locations for ABI reasons). We can't deduce that
  82. from the paraloc though, we need the parasym for that. Potential
  83. future optimisation, although llvm will probably optimise away the
  84. temps we create anyway }
  85. result:=false;
  86. end;
  87. procedure tllvmparamanager.reducetosingleregparaloc(paraloc: PCGParaLocation; def: tdef; reg: tregister);
  88. var
  89. nextloc: pcgparalocation;
  90. begin
  91. paraloc^.def:=def;
  92. paraloc^.size:=def_cgsize(def);
  93. paraloc^.register:=reg;
  94. paraloc^.shiftval:=0;
  95. { remove all other paralocs }
  96. while assigned(paraloc^.next) do
  97. begin
  98. nextloc:=paraloc^.next;
  99. paraloc^.next:=nextloc^.next;
  100. dispose(nextloc);
  101. end;
  102. end;
  103. procedure tllvmparamanager.reduceparalocs(p: tabstractprocdef; side: tcallercallee; paras: tparalist);
  104. var
  105. paranr: longint;
  106. hp: tparavarsym;
  107. paraloc: PCGParaLocation;
  108. begin
  109. for paranr:=0 to paras.count-1 do
  110. begin
  111. hp:=tparavarsym(paras[paranr]);
  112. paraloc:=hp.paraloc[side].location;
  113. if assigned(paraloc) then
  114. begin
  115. if assigned(paraloc^.next) and
  116. (hp.paraloc[side].def.typ in [orddef,enumdef,floatdef]) then
  117. begin
  118. if not(paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER]) then
  119. internalerror(2019011902);
  120. reducetosingleregparaloc(paraloc,hp.paraloc[side].def,paraloc^.register);
  121. end
  122. else if paraloc^.def=llvm_metadatatype then
  123. begin
  124. paraloc^.Loc:=LOC_REGISTER;
  125. // will be overwritten with a "register" whose superregister is an index in the LLVM metadata table
  126. paraloc^.register:=NR_INVALID;
  127. end;
  128. end;
  129. end;
  130. end;
  131. procedure tllvmparamanager.createtempparaloc(list: TAsmList; calloption: tproccalloption; parasym: tparavarsym; can_use_final_stack_loc: boolean; var cgpara: TCGPara);
  132. var
  133. paraloc: pcgparalocation;
  134. paralocdef: tdef;
  135. begin
  136. inherited;
  137. paraloc:=cgpara.location;
  138. { No need to set paraloc^.llvmloc.*, these are not used/needed for temp
  139. paralocs }
  140. while assigned(paraloc) do
  141. begin
  142. if (vo_is_funcret in parasym.varoptions) and
  143. { sret attribute is only valid for the first parameter; sometimes
  144. FPC will place other parameters first (e.g. self), and then
  145. we can't use it; we use other attributes in that case to
  146. approximate the optimisations that LLVM can do for sret }
  147. (tabstractprocdef(parasym.owner.defowner).paras[0] = parasym)
  148. {$ifdef aarch64}
  149. { see AArch64's tcpuparamanager.create_paraloc_info_intern() }
  150. and not is_managed_type(parasym.vardef)
  151. {$endif aarch64}
  152. then
  153. paraloc^.retvalloc:=true;
  154. { ordinal parameters must be passed as a single paraloc }
  155. if (cgpara.def.typ in [orddef,enumdef,floatdef]) and
  156. assigned(paraloc^.next) then
  157. begin
  158. paraloc^.loc:=LOC_REGISTER;
  159. reducetosingleregparaloc(paraloc,cgpara.def,hlcg.getintregister(list,cgpara.def));
  160. end;
  161. { varargs parameters do not have a parasym.owner, but they're always
  162. by value }
  163. if (assigned(parasym.owner) and
  164. paramanager.push_addr_param(parasym.varspez,parasym.vardef,tabstractprocdef(parasym.owner.defowner).proccalloption)) or
  165. not llvmbyvalparaloc(paraloc) then
  166. begin
  167. case paraloc^.loc of
  168. LOC_REFERENCE:
  169. begin
  170. case hlcg.def2regtyp(paraloc^.def) of
  171. R_INTREGISTER,
  172. R_ADDRESSREGISTER:
  173. paraloc^.loc:=LOC_REGISTER;
  174. R_FPUREGISTER:
  175. paraloc^.loc:=LOC_FPUREGISTER;
  176. R_MMREGISTER:
  177. paraloc^.Loc:=LOC_MMREGISTER;
  178. else
  179. internalerror(2013012308);
  180. end;
  181. paraloc^.register:=hlcg.getregisterfordef(list,paraloc^.def);
  182. paraloc^.llvmvalueloc:=true;
  183. { paraloc^.reference overlaid this field, so zero it now
  184. that we turned it into a register location }
  185. paraloc^.shiftval:=0;
  186. end;
  187. LOC_REGISTER,
  188. LOC_FPUREGISTER,
  189. LOC_MMREGISTER:
  190. begin
  191. paraloc^.llvmvalueloc:=true;
  192. end;
  193. LOC_VOID:
  194. begin
  195. { for empty records, ensure these don't get a byval
  196. attribute }
  197. paraloc^.llvmvalueloc:=true;
  198. end;
  199. else
  200. internalerror(2014012302);
  201. end;
  202. end
  203. else
  204. begin
  205. { turn this paraloc into the "byval" parameter: at the llvm level,
  206. a pointer to the value that it should place on the stack (or
  207. passed in registers, in some cases) }
  208. paraloc^.llvmvalueloc:=false;
  209. paraloc^.loc:=LOC_REGISTER;
  210. paralocdef:=cpointerdef.getreusable_no_free(paraloc^.def);
  211. reducetosingleregparaloc(paraloc,paralocdef,hlcg.getaddressregister(list,paralocdef));
  212. end;
  213. paraloc^.llvmloc.loc:=paraloc^.loc;
  214. paraloc^.llvmloc.reg:=paraloc^.register;
  215. paraloc:=paraloc^.next;
  216. end;
  217. end;
  218. function tllvmparamanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee): longint;
  219. begin
  220. result:=inherited;
  221. create_paraloc_info_internllvm(p,side);
  222. end;
  223. function tllvmparamanager.create_varargs_paraloc_info(p: tabstractprocdef; side: tcallercallee; varargspara: tvarargsparalist): longint;
  224. begin
  225. result:=inherited;
  226. create_paraloc_info_internllvm(p,side);
  227. if assigned(varargspara) then
  228. reduceparalocs(p,side,varargspara);
  229. end;
  230. function tllvmparamanager.get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
  231. var
  232. paraloc: pcgparalocation;
  233. begin
  234. result:=inherited;
  235. paraloc:=result.location;
  236. repeat
  237. paraloc^.llvmvalueloc:=true;
  238. paraloc:=paraloc^.next;
  239. until not assigned(paraloc);
  240. paraloc:=result.location;
  241. if assigned(paraloc^.next) and
  242. (result.def.typ in [orddef,enumdef,floatdef]) and
  243. ((side=callerside) or
  244. not(po_assembler in p.procoptions)) then
  245. begin
  246. if not(paraloc^.loc in [LOC_REGISTER,LOC_FPUREGISTER,LOC_MMREGISTER]) then
  247. internalerror(2019011901);
  248. reducetosingleregparaloc(paraloc,result.def,paraloc^.register);
  249. end;
  250. end;
  251. function tllvmparamanager.has_strict_proc_signature: boolean;
  252. begin
  253. result:=true;
  254. end;
  255. procedure tllvmparamanager.create_paraloc_info_internllvm(p: tabstractprocdef; side: tcallercallee);
  256. begin
  257. { on the calleeside, llvm declares the parameters similar to Pascal or C
  258. (a list of parameters and their types), but they correspond more
  259. closely to parameter locations than to parameters -> add names to the
  260. locations }
  261. if (side=calleeside) and
  262. not(po_assembler in p.procoptions) then
  263. begin
  264. add_llvm_callee_paraloc_names(p);
  265. reduceparalocs(p,side,p.paras);
  266. end
  267. else if side=callerside then
  268. begin
  269. reduceparalocs(p,side,p.paras);
  270. end;
  271. end;
  272. { hp non-nil: parasym to check
  273. hp nil: function result
  274. }
  275. procedure tllvmparamanager.set_llvm_paraloc_name(p: tabstractprocdef; hp: tparavarsym; var para: tcgpara);
  276. var
  277. paraloc: PCGParaLocation;
  278. paralocnr: longint;
  279. begin
  280. paraloc:=hp.paraloc[calleeside].location;
  281. paralocnr:=0;
  282. repeat
  283. paraloc^.llvmloc.loc:=LOC_REFERENCE;
  284. paraloc^.llvmloc.sym:=current_asmdata.DefineAsmSymbol(llvmparaname(hp,paralocnr),AB_TEMP,AT_DATA,paraloc^.def);
  285. { byval: a pointer to a type that should actually be passed by
  286. value (e.g. a record that should be passed on the stack) }
  287. paraloc^.llvmvalueloc:=
  288. paramanager.push_addr_param(hp.varspez,hp.vardef,p.proccalloption) or
  289. not llvmbyvalparaloc(paraloc);
  290. paraloc:=paraloc^.next;
  291. inc(paralocnr);
  292. until not assigned(paraloc);
  293. end;
  294. procedure tllvmparamanager.add_llvm_callee_paraloc_names(p: tabstractprocdef);
  295. var
  296. paranr: longint;
  297. hp: tparavarsym;
  298. begin
  299. for paranr:=0 to p.paras.count-1 do
  300. begin
  301. hp:=tparavarsym(p.paras[paranr]);
  302. set_llvm_paraloc_name(p,hp,hp.paraloc[calleeside]);
  303. end;
  304. end;
  305. begin
  306. if not assigned(paramanager) then
  307. begin
  308. writeln('Internalerror 2018052006');
  309. halt(1);
  310. end;
  311. { replace the native parameter manager. Maybe this has to be moved to a
  312. procedure like the creations of the code generators, but possibly not since
  313. we still call the original paramanager }
  314. paramanager.free;
  315. paramanager:=tllvmparamanager.create;
  316. end.