llvmpara.pas 11 KB

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