nllvmbas.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. { these have to be transformed from ^nr into into $nr; we use ^ because
  96. we also have to double all other occurrences of '$' in the assembly
  97. code, and we can't differentiate between these and other '$'s in
  98. agllvm }
  99. result:=current_asmdata.RefAsmSymbol('^'+tostr(getllvmasmopindexforsym(sym)),AT_DATA,false);
  100. end;
  101. procedure tllvmasmnode.ResolveRef(const filepos: tfileposinfo; var op: toper);
  102. var
  103. sym: tabstractnormalvarsym;
  104. ref: treference;
  105. sofs: pint;
  106. indexreg : tregister;
  107. getoffset: boolean;
  108. {$ifdef x86}
  109. scale : byte;
  110. {$endif x86}
  111. begin
  112. { pure assembler routines are handled by the regular code generator }
  113. if po_assembler in current_procinfo.procdef.procoptions then
  114. begin
  115. inherited;
  116. exit;
  117. end;
  118. { translate all symbolic references to "parameters" of the llvm
  119. assembler statements }
  120. case op.typ of
  121. top_local:
  122. begin
  123. sofs:=op.localoper^.localsymofs;
  124. indexreg:=op.localoper^.localindexreg;
  125. {$ifdef x86}
  126. scale:=op.localoper^.localscale;
  127. {$endif x86}
  128. getoffset:=op.localoper^.localgetoffset;
  129. sym:=tabstractnormalvarsym(op.localoper^.localsym);
  130. dispose(op.localoper);
  131. case sym.localloc.loc of
  132. LOC_REFERENCE:
  133. begin
  134. if getoffset then
  135. begin
  136. { todo: print proper error. You cannot get the offset
  137. of a local variable since it may be in a register
  138. outside the assembler block with llvm }
  139. internalerror(2016102001);
  140. end
  141. else
  142. begin
  143. op.typ:=top_ref;
  144. new(op.ref);
  145. reference_reset_symbol(op.ref^,getllvmasmparasym(sym),sofs,
  146. newalignment(sym.localloc.reference.alignment,sofs),[]);
  147. op.ref^.index:=indexreg;
  148. {$ifdef x86}
  149. op.ref^.scalefactor:=scale;
  150. {$endif x86}
  151. end;
  152. end
  153. else
  154. { all locals accessed from assembler are forced into memory
  155. by FPC }
  156. internalerror(2016101506);
  157. end;
  158. end;
  159. end;
  160. end;
  161. constructor tllvmasmnode.create(p: TAsmList);
  162. begin
  163. inherited;
  164. end;
  165. destructor tllvmasmnode.destroy;
  166. begin
  167. { normally already freed in pass_generate_code, but in case an error
  168. occurred that may not have happened }
  169. fsymboldata.free;
  170. fsymbollookup.free;
  171. inherited;
  172. end;
  173. procedure tllvmasmnode.pass_generate_code;
  174. var
  175. oldasmlist: tasmlist;
  176. asmai: tai;
  177. begin
  178. oldasmlist:=nil;
  179. if not(po_assembler in current_procinfo.procdef.procoptions) and
  180. not(nf_get_asm_position in flags) then
  181. begin
  182. { store the assembler code in a separate list, so we can make it
  183. the argument of an asmblock instruction }
  184. oldasmlist:=current_asmdata.CurrAsmList;
  185. current_asmdata.CurrAsmList:=tasmlist.create;
  186. { record relation between parameters and replaced local assembler
  187. operands }
  188. fsymboldata:=tfplist.create;
  189. fsymbollookup:=THashSet.Create(8,True,False);
  190. end;
  191. inherited;
  192. if not(po_assembler in current_procinfo.procdef.procoptions) and
  193. not(nf_get_asm_position in flags) then
  194. begin
  195. asmai:=taillvm.asm_paras(current_asmdata.CurrAsmList,fsymboldata);
  196. fsymboldata:=nil;
  197. fsymbollookup.free;
  198. fsymbollookup:=nil;
  199. oldasmlist.concat(asmai);
  200. current_asmdata.CurrAsmList:=oldasmlist;
  201. end;
  202. end;
  203. {*****************************************************************************
  204. TLLVMTEMPINFOACCESSOR
  205. *****************************************************************************}
  206. class procedure tllvmtempinfoaccessor.settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags);
  207. begin
  208. { it is not possible to typecast between e.g. an integer and a record
  209. in a register, which is a problem if such a typecast is performed on
  210. an lvalue (since we then have to store it first to a temp in memory,
  211. which means we no longer have an lvalue).
  212. Disable regvars altogether since LLVM will put the values in registers
  213. anyway if possible/useful. }
  214. inherited settempinfoflags(tempinfo,flags-[ti_may_be_in_reg]);
  215. end;
  216. {*****************************************************************************
  217. TTEMPCREATENODE
  218. *****************************************************************************}
  219. procedure tllvmtempcreatenode.pass_generate_code;
  220. begin
  221. inherited;
  222. { if a temp is in a register and we never assign anything to it (e.g.
  223. because it's the register for an inlined function result that never
  224. gets assigned a value), then llvm will be confused the first time
  225. we try to read from it (since it's never been defined) -> always
  226. immediately assign undef to such registers }
  227. if tempinfo^.location.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_FPUREGISTER,
  228. LOC_CFPUREGISTER,LOC_MMREGISTER,LOC_CMMREGISTER] then
  229. current_asmdata.CurrAsmList.concat(
  230. taillvm.op_reg_size_undef(la_bitcast,tempinfo^.location.register,tempinfo^.typedef)
  231. );
  232. end;
  233. begin
  234. casmnode:=tllvmasmnode;
  235. ctempinfoaccessor:=tllvmtempinfoaccessor;
  236. ctempcreatenode:=tllvmtempcreatenode;
  237. end.