diff options
Diffstat (limited to 'tools/lli')
-rw-r--r-- | tools/lli/OrcLazyJIT.cpp | 124 | ||||
-rw-r--r-- | tools/lli/OrcLazyJIT.h | 98 | ||||
-rw-r--r-- | tools/lli/RemoteMemoryManager.h | 2 | ||||
-rw-r--r-- | tools/lli/RemoteTargetExternal.h | 2 | ||||
-rw-r--r-- | tools/lli/lli.cpp | 2 |
5 files changed, 197 insertions, 31 deletions
diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp index 4a8d3b9..ff8baf0 100644 --- a/tools/lli/OrcLazyJIT.cpp +++ b/tools/lli/OrcLazyJIT.cpp @@ -9,34 +9,130 @@ #include "OrcLazyJIT.h" #include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DynamicLibrary.h" +#include <system_error> using namespace llvm; -std::unique_ptr<OrcLazyJIT::CompileCallbackMgr> -OrcLazyJIT::createCallbackMgr(Triple T, LLVMContext &Context) { +namespace { + + enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdErr, + DumpModsToDisk }; + + cl::opt<DumpKind> OrcDumpKind("orc-lazy-debug", + cl::desc("Debug dumping for the orc-lazy JIT."), + cl::init(DumpKind::NoDump), + cl::values( + clEnumValN(DumpKind::NoDump, "no-dump", + "Don't dump anything."), + clEnumValN(DumpKind::DumpFuncsToStdOut, + "funcs-to-stdout", + "Dump function names to stdout."), + clEnumValN(DumpKind::DumpModsToStdErr, + "mods-to-stderr", + "Dump modules to stderr."), + clEnumValN(DumpKind::DumpModsToDisk, + "mods-to-disk", + "Dump modules to the current " + "working directory. (WARNING: " + "will overwrite existing files)."), + clEnumValEnd)); +} + +OrcLazyJIT::CallbackManagerBuilder +OrcLazyJIT::createCallbackManagerBuilder(Triple T) { switch (T.getArch()) { - default: - // Flag error. - Error = true; - return nullptr; + default: return nullptr; case Triple::x86_64: { - typedef orc::JITCompileCallbackManager<CompileLayerT, + typedef orc::JITCompileCallbackManager<IRDumpLayerT, orc::OrcX86_64> CCMgrT; - return make_unique<CCMgrT>(CompileLayer, Context, 0, 64); + return [](IRDumpLayerT &IRDumpLayer, RuntimeDyld::MemoryManager &MemMgr, + LLVMContext &Context) { + return llvm::make_unique<CCMgrT>(IRDumpLayer, MemMgr, Context, 0, + 64); + }; } } } +OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { + + switch (OrcDumpKind) { + case DumpKind::NoDump: + return [](std::unique_ptr<Module> M) { return std::move(M); }; + + case DumpKind::DumpFuncsToStdOut: + return [](std::unique_ptr<Module> M) { + printf("[ "); + + for (const auto &F : *M) { + if (F.isDeclaration()) + continue; + + if (F.hasName()) { + std::string Name(F.getName()); + printf("%s ", Name.c_str()); + } else + printf("<anon> "); + } + + printf("]\n"); + return std::move(M); + }; + + case DumpKind::DumpModsToStdErr: + return [](std::unique_ptr<Module> M) { + dbgs() << "----- Module Start -----\n" << *M + << "----- Module End -----\n"; + + return std::move(M); + }; + + case DumpKind::DumpModsToDisk: + return [](std::unique_ptr<Module> M) { + std::error_code EC; + raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC, + sys::fs::F_Text); + if (EC) { + errs() << "Couldn't open " << M->getModuleIdentifier() + << " for dumping.\nError:" << EC.message() << "\n"; + exit(1); + } + Out << *M; + return std::move(M); + }; + } + llvm_unreachable("Unknown DumpKind"); +} + int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { - OrcLazyJIT J(std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget()), - getGlobalContext()); + // Add the program's symbols into the JIT's search space. + if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { + errs() << "Error loading program symbols.\n"; + return 1; + } + + // Grab a target machine and try to build a factory function for the + // target-specific Orc callback manager. + auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget()); + auto &Context = getGlobalContext(); + auto CallbackMgrBuilder = + OrcLazyJIT::createCallbackManagerBuilder(Triple(TM->getTargetTriple())); - if (!J.Ok()) { - errs() << "Could not construct JIT.\n"; + // If we couldn't build the factory function then there must not be a callback + // manager for this target. Bail out. + if (!CallbackMgrBuilder) { + errs() << "No callback manager available for target '" + << TM->getTargetTriple() << "'.\n"; return 1; } + // Everything looks good. Build the JIT. + OrcLazyJIT J(std::move(TM), Context, CallbackMgrBuilder); + + // Add the module, look up main and run it. auto MainHandle = J.addModule(std::move(M)); auto MainSym = J.findSymbolIn(MainHandle, "main"); @@ -46,8 +142,6 @@ int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { } typedef int (*MainFnPtr)(int, char*[]); - auto Main = reinterpret_cast<MainFnPtr>( - static_cast<uintptr_t>(MainSym.getAddress())); - + auto Main = OrcLazyJIT::fromTargetAddress<MainFnPtr>(MainSym.getAddress()); return Main(ArgC, ArgV); } diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h index 76e1ac6..2b2db6e 100644 --- a/tools/lli/OrcLazyJIT.h +++ b/tools/lli/OrcLazyJIT.h @@ -18,9 +18,12 @@ #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" #include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/IR/LLVMContext.h" namespace llvm { @@ -31,30 +34,96 @@ public: typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; typedef orc::ObjectLinkingLayer<> ObjLayerT; typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT; - typedef orc::LazyEmittingLayer<CompileLayerT> LazyEmitLayerT; + typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)> + TransformFtor; + typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT; + typedef orc::LazyEmittingLayer<IRDumpLayerT> LazyEmitLayerT; typedef orc::CompileOnDemandLayer<LazyEmitLayerT, CompileCallbackMgr> CODLayerT; typedef CODLayerT::ModuleSetHandleT ModuleHandleT; - OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context) - : Error(false), TM(std::move(TM)), + typedef std::function< + std::unique_ptr<CompileCallbackMgr>(IRDumpLayerT&, + RuntimeDyld::MemoryManager&, + LLVMContext&)> + CallbackManagerBuilder; + + static CallbackManagerBuilder createCallbackManagerBuilder(Triple T); + + OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context, + CallbackManagerBuilder &BuildCallbackMgr) + : TM(std::move(TM)), Mang(this->TM->getDataLayout()), - ObjectLayer([](){ return llvm::make_unique<SectionMemoryManager>(); }), + ObjectLayer(), CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), - LazyEmitLayer(CompileLayer), - CCMgr(createCallbackMgr(Triple(this->TM->getTargetTriple()), Context)), - CODLayer(LazyEmitLayer, *CCMgr) { } + IRDumpLayer(CompileLayer, createDebugDumper()), + LazyEmitLayer(IRDumpLayer), + CCMgr(BuildCallbackMgr(IRDumpLayer, CCMgrMemMgr, Context)), + CODLayer(LazyEmitLayer, *CCMgr), + CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {} + + ~OrcLazyJIT() { + // Run any destructors registered with __cxa_atexit. + CXXRuntimeOverrides.runDestructors(); + // Run any IR destructors. + for (auto &DtorRunner : IRStaticDestructorRunners) + DtorRunner.runViaLayer(CODLayer); + } - bool Ok() const { return !Error; } + template <typename PtrTy> + static PtrTy fromTargetAddress(orc::TargetAddress Addr) { + return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr)); + } ModuleHandleT addModule(std::unique_ptr<Module> M) { // Attach a data-layout if one isn't already present. if (M->getDataLayout().isDefault()) M->setDataLayout(*TM->getDataLayout()); + // Record the static constructors and destructors. We have to do this before + // we hand over ownership of the module to the JIT. + std::vector<std::string> CtorNames, DtorNames; + for (auto Ctor : orc::getConstructors(*M)) + CtorNames.push_back(mangle(Ctor.Func->getName())); + for (auto Dtor : orc::getDestructors(*M)) + DtorNames.push_back(mangle(Dtor.Func->getName())); + + // Symbol resolution order: + // 1) Search the JIT symbols. + // 2) Check for C++ runtime overrides. + // 3) Search the host process (LLI)'s symbol table. + auto Resolver = + orc::createLambdaResolver( + [this](const std::string &Name) { + + if (auto Sym = CODLayer.findSymbol(Name, true)) + return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); + + if (auto Sym = CXXRuntimeOverrides.searchOverrides(Name)) + return Sym; + + if (auto Addr = RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported); + + return RuntimeDyld::SymbolInfo(nullptr); + }, + [](const std::string &Name) { return RuntimeDyld::SymbolInfo(nullptr); } + ); + + // Add the module to the JIT. std::vector<std::unique_ptr<Module>> S; S.push_back(std::move(M)); - return CODLayer.addModuleSet(std::move(S)); + auto H = CODLayer.addModuleSet(std::move(S), nullptr, std::move(Resolver)); + + // Run the static constructors, and save the static destructor runner for + // execution when the JIT is torn down. + orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames), H); + CtorRunner.runViaLayer(CODLayer); + + IRStaticDestructorRunners.push_back( + orc::CtorDtorRunner<CODLayerT>(std::move(DtorNames), H)); + + return H; } orc::JITSymbol findSymbol(const std::string &Name) { @@ -67,9 +136,6 @@ public: private: - std::unique_ptr<CompileCallbackMgr> - createCallbackMgr(Triple T, LLVMContext &Context); - std::string mangle(const std::string &Name) { std::string MangledName; { @@ -79,15 +145,21 @@ private: return MangledName; } - bool Error; + static TransformFtor createDebugDumper(); + std::unique_ptr<TargetMachine> TM; Mangler Mang; + SectionMemoryManager CCMgrMemMgr; ObjLayerT ObjectLayer; CompileLayerT CompileLayer; + IRDumpLayerT IRDumpLayer; LazyEmitLayerT LazyEmitLayer; std::unique_ptr<CompileCallbackMgr> CCMgr; CODLayerT CODLayer; + + orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; + std::vector<orc::CtorDtorRunner<CODLayerT>> IRStaticDestructorRunners; }; int runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]); diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h index 895bcda..5733fa5 100644 --- a/tools/lli/RemoteMemoryManager.h +++ b/tools/lli/RemoteMemoryManager.h @@ -64,7 +64,7 @@ private: public: RemoteMemoryManager() : Target(nullptr) {} - virtual ~RemoteMemoryManager(); + ~RemoteMemoryManager() override; uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h index bb621f5..afe8570 100644 --- a/tools/lli/RemoteTargetExternal.h +++ b/tools/lli/RemoteTargetExternal.h @@ -106,7 +106,7 @@ public: void stop() override; RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {} - virtual ~RemoteTargetExternal() {} + ~RemoteTargetExternal() override {} private: std::string ChildName; diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 47ce2c0..c1e3522 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -271,7 +271,7 @@ public: this->CacheDir[this->CacheDir.size() - 1] != '/') this->CacheDir += '/'; } - virtual ~LLIObjectCache() {} + ~LLIObjectCache() override {} void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override { const std::string ModuleID = M->getModuleIdentifier(); |