ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
LLVMJIT.cpp
Go to the documentation of this file.
1 /*
2 
3  @copyright
4 
5  <pre>
6 
7  Copyright 2018 Infineon Technologies AG
8 
9  This file is part of ETISS tool, see <https://github.com/tum-ei-eda/etiss>.
10 
11  The initial version of this software has been created with the funding support by the German Federal
12  Ministry of Education and Research (BMBF) in the project EffektiV under grant 01IS13022.
13 
14  Redistribution and use in source and binary forms, with or without modification, are permitted
15  provided that the following conditions are met:
16 
17  1. Redistributions of source code must retain the above copyright notice, this list of conditions and
18  the following disclaimer.
19 
20  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
21  and the following disclaimer in the documentation and/or other materials provided with the distribution.
22 
23  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
24  or promote products derived from this software without specific prior written permission.
25 
26  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
27  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
28  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
29  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  POSSIBILITY OF SUCH DAMAGE.
34 
35  </pre>
36 
37  @author Chair of Electronic Design Automation, TUM
38 
39  @version 0.1
40 
41 */
42 
43 #include "LLVMJIT.h"
44 #include "etiss/ETISS.h"
45 
46 #include "llvm/ADT/StringRef.h"
47 #include "llvm/ExecutionEngine/JITSymbol.h"
48 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
49 #include "llvm/ExecutionEngine/Orc/Core.h"
50 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
51 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
52 #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
53 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
54 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
55 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
56 #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
57 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
58 #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
59 #include "llvm/IR/DataLayout.h"
60 #include "llvm/IR/LLVMContext.h"
61 #include "llvm/IR/LegacyPassManager.h"
62 #include "llvm/Transforms/InstCombine/InstCombine.h"
63 #include "llvm/Transforms/Scalar.h"
64 #include "llvm/Transforms/Scalar/GVN.h"
65 #include "clang/Basic/FileManager.h"
66 #include "llvm/ExecutionEngine/ExecutionEngine.h"
67 
68 #include <vector>
69 #include <iostream>
70 
71 using namespace etiss;
72 
73 using namespace llvm;
74 using namespace clang;
75 using namespace llvm::orc;
76 
79 
80 class OrcJit
81 {
82  public:
83  OrcJit(llvm::orc::JITTargetMachineBuilder JTMB, llvm::DataLayout DL)
84  : ObjectLayer(ES, []() { return std::make_unique<llvm::SectionMemoryManager>(); })
85  , CompileLayer(ES, ObjectLayer, std::make_unique<llvm::orc::ConcurrentIRCompiler>(std::move(JTMB)))
86  , OptimizeLayer(ES, CompileLayer, optimizeModule)
87  , DL(std::move(DL))
88  , Mangle(ES, this->DL)
89  , Ctx(std::make_unique<llvm::LLVMContext>())
90  , MainJITDylib(ES.createBareJITDylib("<main>"))
91  {
92  MainJITDylib.addGenerator(
93  llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(DL.getGlobalPrefix())));
94  }
95 
96  static llvm::Expected<std::unique_ptr<OrcJit>> Create()
97  {
98  auto JTMB = llvm::orc::JITTargetMachineBuilder::detectHost();
99  if (!JTMB)
100  return JTMB.takeError();
101 
102  auto DL = JTMB->getDefaultDataLayoutForTarget();
103  if (!DL)
104  return DL.takeError();
105 
106  return std::make_unique<OrcJit>(std::move(*JTMB), std::move(*DL));
107  }
108 
109  const llvm::DataLayout &getDataLayout() const { return DL; }
110  llvm::LLVMContext &getContext() { return *Ctx.getContext(); }
111 
112  void addModule(std::unique_ptr<llvm::Module> M)
113  {
114  llvm::cantFail(OptimizeLayer.add(MainJITDylib, llvm::orc::ThreadSafeModule(std::move(M), Ctx)));
115  }
116 
117  llvm::Expected<llvm::JITEvaluatedSymbol> lookup(llvm::StringRef Name)
118  {
119  return ES.lookup({ &MainJITDylib }, Mangle(Name.str()));
120  }
121 
122  bool loadLib(const std::string &libName, const std::set<std::string> &libPaths)
123  {
124  for (const auto &libPath : libPaths)
125  {
126  SmallString<128> fullPath;
127  sys::path::append(fullPath, libPath, "lib" + libName + ".so");
128  if (sys::fs::exists(fullPath))
129  {
130  MainJITDylib.addGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::Load(fullPath.c_str(), DL.getGlobalPrefix())));
131  return true;
132  }
133  }
134 
135  return false;
136  }
137 
138  static llvm::orc::ThreadSafeModule optimizeModule(llvm::orc::ThreadSafeModule TSM,
139  const llvm::orc::MaterializationResponsibility &R)
140  {
141  auto lock = TSM.getContext();
142  auto M = TSM.getModuleUnlocked();
143 
144  // Create a function pass manager.
145  auto FPM = std::make_unique<llvm::legacy::FunctionPassManager>(M);
146 
147  // Add some optimizations.
148  FPM->add(llvm::createInstructionCombiningPass());
149  FPM->add(llvm::createReassociatePass());
150  FPM->add(llvm::createGVNPass());
151  FPM->add(llvm::createCFGSimplificationPass());
152  FPM->doInitialization();
153 
154  // Run the optimizations over all functions in the module being added to
155  // the JIT.
156  for (auto &F : *M)
157  FPM->run(F);
158 
159  return TSM;
160  }
161 
162  private:
163  llvm::orc::ExecutionSession ES;
164  llvm::orc::RTDyldObjectLinkingLayer ObjectLayer;
165  llvm::orc::IRCompileLayer CompileLayer;
166  llvm::orc::IRTransformLayer OptimizeLayer;
167 
168  llvm::DataLayout DL;
169  llvm::orc::MangleAndInterner Mangle;
170  llvm::orc::ThreadSafeContext Ctx;
171  llvm::orc::JITDylib &MainJITDylib;
172 };
173 
174 LLVMJIT::LLVMJIT() : JIT("LLVMJIT")
175 {
176 
177  // init environment once
180  {
181  // LLVMInitializeNativeTarget();
182  InitializeNativeTarget();
183  InitializeNativeTargetAsmPrinter();
184  InitializeNativeTargetAsmParser();
186  }
187  etiss_jit_llvm_init_mu_.unlock();
188 
189  auto orcJit = OrcJit::Create();
190  if (!orcJit)
191  throw std::runtime_error("fail");
192  orcJit_ = (*orcJit).release();
193 }
194 
196 {
197  delete orcJit_;
198 }
199 
200 void *LLVMJIT::translate(std::string code, std::set<std::string> headerpaths, std::set<std::string> librarypaths,
201  std::set<std::string> libraries, std::string &error, bool debug)
202 {
203  clang::CompilerInstance CI;
204 
205  DiagnosticOptions *diagOpts = new DiagnosticOptions();
206  TextDiagnosticPrinter *diagPrinter = new TextDiagnosticPrinter(llvm::outs(), diagOpts);
207 
208  CI.createDiagnostics(diagPrinter);
209  auto pto = std::make_shared<clang::TargetOptions>();
210  pto->Triple = llvm::sys::getDefaultTargetTriple();
211  TargetInfo *pti = TargetInfo::CreateTargetInfo(CI.getDiagnostics(), pto);
212  CI.setTarget(pti);
213  CI.createFileManager();
214  CI.createSourceManager(CI.getFileManager());
215  CI.createPreprocessor(clang::TranslationUnitKind::TU_Module);
216 
217  // compilation task
218  std::vector<std::string> args;
219  if (debug)
220  {
221  args.push_back("-g");
222  args.push_back("-O0");
223  }
224  else
225  {
226  args.push_back("-O3");
227  }
228  args.push_back("-std=c99");
229  args.push_back("-isystem" + etiss::jitFiles() + "/clang_stdlib");
230  args.push_back("-isystem/usr/include");
231  for (const auto &headerPath : headerpaths)
232  {
233  args.push_back("-isystem" + headerPath);
234  }
235  args.push_back("/etiss_llvm_clang_memory_mapped_file.c");
236  args.push_back("-isystem/usr/include/x86_64-linux-gnu");
237 
238  for (const auto &lib : libraries)
239  {
240  if (loadedLibs_.count(lib) == 0)
241  {
242  if (!orcJit_->loadLib(lib, librarypaths))
243  {
244  error = "could not load library";
245  return 0;
246  }
247  loadedLibs_.insert(lib);
248  }
249  }
250 
251  // configure compiler call
252  std::vector<const char *> argsCStr;
253  for (const auto &arg : args)
254  {
255  argsCStr.push_back(arg.c_str());
256  }
257  if (!CompilerInvocation::CreateFromArgs(CI.getInvocation(), argsCStr, CI.getDiagnostics()))
258  {
259  error = "error on parsing args";
260  return 0;
261  }
262 
263  // input file is mapped to memory area containing the code
264  auto buffer = MemoryBuffer::getMemBufferCopy(code, "/etiss_llvm_clang_memory_mapped_file.c");
265  CI.getSourceManager().overrideFileContents(
266  CI.getFileManager().getVirtualFile("/etiss_llvm_clang_memory_mapped_file.c", buffer->getBufferSize(), 0),
267  buffer.get(), true);
268 
269  // compiler should only output llvm module
270 
271  EmitLLVMOnlyAction action(&orcJit_->getContext());
272 
273  // compile
274  if (!CI.ExecuteAction(action))
275  {
276  error = "failed to execute translation action ";
277  return 0;
278  }
279 
280  // load module with orcjit
281  orcJit_->addModule(action.takeModule());
282 
283  return (void *)1;
284 }
285 
286 void *LLVMJIT::getFunction(void *handle, std::string name, std::string &error)
287 {
288 
289  auto func = orcJit_->lookup(name);
290  if (!func)
291  throw std::runtime_error("fail");
292  return (void *)(*func).getAddress();
293 }
294 void LLVMJIT::free(void *handle) {}
Header file of the ETISS library.
bool etiss_jit_llvm_init_done_
Definition: LLVMJIT.cpp:78
std::mutex etiss_jit_llvm_init_mu_
Definition: LLVMJIT.cpp:77
llvm::orc::RTDyldObjectLinkingLayer ObjectLayer
Definition: LLVMJIT.cpp:164
static llvm::Expected< std::unique_ptr< OrcJit > > Create()
Definition: LLVMJIT.cpp:96
llvm::orc::IRCompileLayer CompileLayer
Definition: LLVMJIT.cpp:165
OrcJit(llvm::orc::JITTargetMachineBuilder JTMB, llvm::DataLayout DL)
Definition: LLVMJIT.cpp:83
llvm::orc::ThreadSafeContext Ctx
Definition: LLVMJIT.cpp:170
llvm::LLVMContext & getContext()
Definition: LLVMJIT.cpp:110
llvm::orc::IRTransformLayer OptimizeLayer
Definition: LLVMJIT.cpp:166
void addModule(std::unique_ptr< llvm::Module > M)
Definition: LLVMJIT.cpp:112
llvm::DataLayout DL
Definition: LLVMJIT.cpp:168
llvm::orc::ExecutionSession ES
Definition: LLVMJIT.cpp:163
bool loadLib(const std::string &libName, const std::set< std::string > &libPaths)
Definition: LLVMJIT.cpp:122
llvm::Expected< llvm::JITEvaluatedSymbol > lookup(llvm::StringRef Name)
Definition: LLVMJIT.cpp:117
const llvm::DataLayout & getDataLayout() const
Definition: LLVMJIT.cpp:109
llvm::orc::JITDylib & MainJITDylib
Definition: LLVMJIT.cpp:171
llvm::orc::MangleAndInterner Mangle
Definition: LLVMJIT.cpp:169
static llvm::orc::ThreadSafeModule optimizeModule(llvm::orc::ThreadSafeModule TSM, const llvm::orc::MaterializationResponsibility &R)
Definition: LLVMJIT.cpp:138
compiler interface for just in time compilation of generated C code
Definition: JIT.h:67
virtual ~LLVMJIT()
Definition: LLVMJIT.cpp:195
virtual void * getFunction(void *handle, std::string name, std::string &error)
returns a function pointer to a compiled function from the handle returned by etiss::JIT::translate
Definition: LLVMJIT.cpp:286
OrcJit * orcJit_
Definition: LLVMJIT.h:115
std::unordered_set< std::string > loadedLibs_
Definition: LLVMJIT.h:116
virtual void free(void *handle)
clean up handled returned by etiss::JIT::translate
Definition: LLVMJIT.cpp:294
virtual void * translate(std::string code, std::set< std::string > headerpaths, std::set< std::string > librarypaths, std::set< std::string > libraries, std::string &error, bool debug=false)
translate C code to executable code and return a handle/pointer that identifies the compilation resul...
Definition: LLVMJIT.cpp:200
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: Benchmark.h:53
std::string jitFiles()
Get ETISS JIT files path.
Definition: Misc.cpp:592