nllvmbas.pas 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. {
  2. Copyright (c) 2015 by Jonas Maebe
  3. This unit implements llvm support for some basic nodes
  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 nllvmbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,cclasses,
  22. aasmbase,aasmtai,aasmdata,
  23. nbas,ncgbas,
  24. symsym;
  25. type
  26. tllvmasmnode = class(tcgasmnode)
  27. protected
  28. { map a tasmsymbol to an index in fsymboldata }
  29. fsymbollookup: THashSet;
  30. { the LLVM symbolic inline assembly operands to which the ones in the
  31. source code are mapped }
  32. fsymboldata: tfplist;
  33. function getllvmasmopindexforsym(sym: tabstractnormalvarsym): longint;
  34. function getllvmasmparasym(sym: tabstractnormalvarsym): tasmsymbol;
  35. procedure ResolveRef(const filepos: tfileposinfo; var op: toper); override;
  36. public
  37. constructor create(p : TAsmList); override;
  38. destructor destroy; override;
  39. procedure pass_generate_code; override;
  40. end;
  41. tllvmtempinfoaccessor = class(ttempinfoaccessor)
  42. protected
  43. class procedure settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags); override;
  44. end;
  45. tllvmtempcreatenode = class(tcgtempcreatenode)
  46. procedure pass_generate_code;override;
  47. end;
  48. implementation
  49. uses
  50. verbose,cutils,
  51. cgbase,cgutils,paramgr,
  52. symconst,symdef,procinfo,
  53. node,
  54. cpubase,llvmbase,aasmllvm
  55. ;
  56. {*****************************************************************************
  57. TLLVMASMNODE
  58. *****************************************************************************}
  59. function tllvmasmnode.getllvmasmopindexforsym(sym: tabstractnormalvarsym): longint;
  60. var
  61. key: record
  62. sym: pointer;
  63. end;
  64. res: PHashSetItem;
  65. callpara: pllvmcallpara;
  66. begin
  67. key.sym:=sym;
  68. res:=fsymbollookup.FindOrAdd(@key,sizeof(key));
  69. if not assigned(res^.Data) then
  70. begin
  71. new(callpara);
  72. callpara^.def:=cpointerdef.getreusable(sym.vardef);
  73. if (sym.typ=paravarsym) and
  74. paramanager.push_addr_param(sym.varspez,sym.vardef,current_procinfo.procdef.proccalloption) then
  75. callpara^.def:=cpointerdef.getreusable(callpara^.def);
  76. callpara^.sret:=false;
  77. callpara^.byval:=false;
  78. callpara^.valueext:=lve_none;
  79. callpara^.loc:=LOC_REGISTER;
  80. { address must be a temp register }
  81. if (sym.localloc.loc<>LOC_REFERENCE) or
  82. (sym.localloc.reference.base=NR_NO) or
  83. (sym.localloc.reference.index<>NR_NO) or
  84. (sym.localloc.reference.offset<>0) or
  85. assigned(sym.localloc.reference.symbol) then
  86. internalerror(2016111001);
  87. callpara^.reg:=sym.localloc.reference.base;
  88. fsymboldata.add(callpara);
  89. ptruint(res^.Data):=fsymboldata.count-1;
  90. end;
  91. result:=longint(ptruint(res^.Data));
  92. end;
  93. function tllvmasmnode.getllvmasmparasym(sym: tabstractnormalvarsym): tasmsymbol;
  94. begin
  95. result:=current_asmdata.RefAsmSymbol('$'+tostr(getllvmasmopindexforsym(sym)),AT_DATA,false);
  96. end;
  97. procedure tllvmasmnode.ResolveRef(const filepos: tfileposinfo; var op: toper);
  98. var
  99. sym: tabstractnormalvarsym;
  100. ref: treference;
  101. sofs: pint;
  102. indexreg : tregister;
  103. getoffset: boolean;
  104. {$ifdef x86}
  105. scale : byte;
  106. {$endif x86}
  107. begin
  108. { pure assembler routines are handled by the regular code generator }
  109. if po_assembler in current_procinfo.procdef.procoptions then
  110. begin
  111. inherited;
  112. exit;
  113. end;
  114. { translate all symbolic references to "parameters" of the llvm
  115. assembler statements }
  116. case op.typ of
  117. top_local:
  118. begin
  119. sofs:=op.localoper^.localsymofs;
  120. indexreg:=op.localoper^.localindexreg;
  121. {$ifdef x86}
  122. scale:=op.localoper^.localscale;
  123. {$endif x86}
  124. getoffset:=op.localoper^.localgetoffset;
  125. sym:=tabstractnormalvarsym(op.localoper^.localsym);
  126. dispose(op.localoper);
  127. case sym.localloc.loc of
  128. LOC_REFERENCE:
  129. begin
  130. if getoffset then
  131. begin
  132. { todo: print proper error. You cannot get the offset
  133. of a local variable since it may be in a register
  134. outside the assembler block with llvm }
  135. internalerror(2016102001);
  136. end
  137. else
  138. begin
  139. op.typ:=top_ref;
  140. new(op.ref);
  141. reference_reset_symbol(op.ref^,getllvmasmparasym(sym),sofs,
  142. newalignment(sym.localloc.reference.alignment,sofs));
  143. op.ref^.index:=indexreg;
  144. {$ifdef x86}
  145. op.ref^.scalefactor:=scale;
  146. {$endif x86}
  147. end;
  148. end
  149. else
  150. { all locals accessed from assembler are forced into memory
  151. by FPC }
  152. internalerror(2016101506);
  153. end;
  154. end;
  155. end;
  156. end;
  157. constructor tllvmasmnode.create(p: TAsmList);
  158. begin
  159. inherited;
  160. end;
  161. destructor tllvmasmnode.destroy;
  162. begin
  163. { normally already freed in pass_generate_code, but in case an error
  164. occurred that may not have happened }
  165. fsymboldata.free;
  166. fsymbollookup.free;
  167. inherited;
  168. end;
  169. procedure tllvmasmnode.pass_generate_code;
  170. var
  171. oldasmlist: tasmlist;
  172. asmai: tai;
  173. begin
  174. oldasmlist:=nil;
  175. if not(po_assembler in current_procinfo.procdef.procoptions) and
  176. not(nf_get_asm_position in flags) then
  177. begin
  178. { store the assembler code in a separate list, so we can make it
  179. the argument of an asmblock instruction }
  180. oldasmlist:=current_asmdata.CurrAsmList;
  181. current_asmdata.CurrAsmList:=tasmlist.create;
  182. { record relation between parameters and replaced local assembler
  183. operands }
  184. fsymboldata:=tfplist.create;
  185. fsymbollookup:=THashSet.Create(8,True,False);
  186. end;
  187. inherited;
  188. if not(po_assembler in current_procinfo.procdef.procoptions) and
  189. not(nf_get_asm_position in flags) then
  190. begin
  191. asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
  192. fsymboldata:=nil;
  193. fsymbollookup.free;
  194. fsymbollookup:=nil;
  195. oldasmlist.concat(asmai);
  196. current_asmdata.CurrAsmList:=oldasmlist;
  197. end;
  198. end;
  199. {*****************************************************************************
  200. TLLVMTEMPINFOACCESSOR
  201. *****************************************************************************}
  202. class procedure tllvmtempinfoaccessor.settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags);
  203. begin
  204. { it is not possible to typecast between e.g. an integer and a record
  205. in a register, which is a problem if such a typecast is performed on
  206. an lvalue (since we then have to store it first to a temp in memory,
  207. which means we no longer have an lvalue).
  208. Disable regvars altogether since LLVM will put the values in registers
  209. anyway if possible/useful. }
  210. inherited settempinfoflags(tempinfo,flags-[ti_may_be_in_reg]);
  211. end;
  212. {*****************************************************************************
  213. TTEMPCREATENODE
  214. *****************************************************************************}
  215. procedure tllvmtempcreatenode.pass_generate_code;
  216. begin
  217. inherited;
  218. { if a temp is in a register and we never assign anything to it (e.g.
  219. because it's the register for an inlined function result that never
  220. gets assigned a value), then llvm will be confused the first time
  221. we try to read from it (since it's never been defined) -> always
  222. immediately assign undef to such registers }
  223. if tempinfo^.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_FPUREGISTER,
  224. LOC_CFPUREGISTER,LOC_MMREGISTER,LOC_CMMREGISTER] then
  225. current_asmdata.CurrAsmList.concat(
  226. taillvm.op_reg_size_undef(la_bitcast,tempinfo^.location.register,tempinfo^.typedef)
  227. );
  228. end;
  229. begin
  230. casmnode:=tllvmasmnode;
  231. ctempinfoaccessor:=tllvmtempinfoaccessor;
  232. ctempcreatenode:=tllvmtempcreatenode;
  233. end.