llvmpara.pas 13 KB

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