ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
71using namespace etiss;
72
73using namespace llvm;
74using namespace clang;
75using namespace llvm::orc;
76
79
80class 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)))
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
174LLVMJIT::LLVMJIT() : JIT("LLVMJIT")
175{
176
177 // init environment once
180 {
181 // LLVMInitializeNativeTarget();
182 InitializeNativeTarget();
183 InitializeNativeTargetAsmPrinter();
184 InitializeNativeTargetAsmParser();
186 }
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
200void *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
286void *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}
294void 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
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::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::Expected< llvm::JITEvaluatedSymbol > lookup(llvm::StringRef Name)
Definition LLVMJIT.cpp:117
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::LLVMContext & getContext()
Definition LLVMJIT.cpp:110
llvm::orc::JITDylib & MainJITDylib
Definition LLVMJIT.cpp:171
const llvm::DataLayout & getDataLayout() const
Definition LLVMJIT.cpp:109
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
static llvm::Expected< std::unique_ptr< OrcJit > > Create()
Definition LLVMJIT.cpp:96
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