diff options
Diffstat (limited to 'contrib/llvm/tools/lli')
-rw-r--r-- | contrib/llvm/tools/lli/OrcLazyJIT.cpp | 153 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/OrcLazyJIT.h | 165 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteMemoryManager.cpp | 1 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteMemoryManager.h | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/RemoteTargetExternal.h | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/lli/lli.cpp | 82 |
6 files changed, 362 insertions, 43 deletions
diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.cpp b/contrib/llvm/tools/lli/OrcLazyJIT.cpp new file mode 100644 index 0000000..ae276e6 --- /dev/null +++ b/contrib/llvm/tools/lli/OrcLazyJIT.cpp @@ -0,0 +1,153 @@ +//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OrcLazyJIT.h" +#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DynamicLibrary.h" +#include <cstdio> +#include <system_error> + +using namespace llvm; + +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: return nullptr; + + case Triple::x86_64: { + typedef orc::JITCompileCallbackManager<IRDumpLayerT, + orc::OrcX86_64> CCMgrT; + 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 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 M; + }; + + case DumpKind::DumpModsToStdErr: + return [](std::unique_ptr<Module> M) { + dbgs() << "----- Module Start -----\n" << *M + << "----- Module End -----\n"; + + return 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 M; + }; + } + llvm_unreachable("Unknown DumpKind"); +} + +// Defined in lli.cpp. +CodeGenOpt::Level getOptLevel(); + +int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { + // 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. + EngineBuilder EB; + EB.setOptLevel(getOptLevel()); + auto TM = std::unique_ptr<TargetMachine>(EB.selectTarget()); + auto &Context = getGlobalContext(); + auto CallbackMgrBuilder = + OrcLazyJIT::createCallbackManagerBuilder(Triple(TM->getTargetTriple())); + + // 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().str() << "'.\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"); + + if (!MainSym) { + errs() << "Could not find main function.\n"; + return 1; + } + + typedef int (*MainFnPtr)(int, char*[]); + auto Main = OrcLazyJIT::fromTargetAddress<MainFnPtr>(MainSym.getAddress()); + return Main(ArgC, ArgV); +} diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.h b/contrib/llvm/tools/lli/OrcLazyJIT.h new file mode 100644 index 0000000..9257225 --- /dev/null +++ b/contrib/llvm/tools/lli/OrcLazyJIT.h @@ -0,0 +1,165 @@ +//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple Orc-based JIT. Uses the compile-on-demand layer to break up and +// lazily compile modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H +#define LLVM_TOOLS_LLI_ORCLAZYJIT_H + +#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/ObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/IR/LLVMContext.h" + +namespace llvm { + +class OrcLazyJIT { +public: + + typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; + typedef orc::ObjectLinkingLayer<> ObjLayerT; + typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT; + typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)> + TransformFtor; + typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT; + typedef orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr> CODLayerT; + typedef CODLayerT::ModuleSetHandleT ModuleHandleT; + + 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(), + CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), + IRDumpLayer(CompileLayer, createDebugDumper()), + CCMgr(BuildCallbackMgr(IRDumpLayer, CCMgrMemMgr, Context)), + CODLayer(IRDumpLayer, *CCMgr, false), + 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); + } + + 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. + std::shared_ptr<RuntimeDyld::SymbolResolver> 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)); + 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.emplace_back(std::move(DtorNames), H); + + return H; + } + + orc::JITSymbol findSymbol(const std::string &Name) { + return CODLayer.findSymbol(mangle(Name), true); + } + + orc::JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { + return CODLayer.findSymbolIn(H, mangle(Name), true); + } + +private: + + std::string mangle(const std::string &Name) { + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mang.getNameWithPrefix(MangledNameStream, Name); + } + return MangledName; + } + + static TransformFtor createDebugDumper(); + + std::unique_ptr<TargetMachine> TM; + Mangler Mang; + SectionMemoryManager CCMgrMemMgr; + + ObjLayerT ObjectLayer; + CompileLayerT CompileLayer; + IRDumpLayerT IRDumpLayer; + 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[]); + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/lli/RemoteMemoryManager.cpp b/contrib/llvm/tools/lli/RemoteMemoryManager.cpp index 47da8fb..0a16210 100644 --- a/contrib/llvm/tools/lli/RemoteMemoryManager.cpp +++ b/contrib/llvm/tools/lli/RemoteMemoryManager.cpp @@ -16,6 +16,7 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/contrib/llvm/tools/lli/RemoteMemoryManager.h b/contrib/llvm/tools/lli/RemoteMemoryManager.h index 895bcda..5733fa5 100644 --- a/contrib/llvm/tools/lli/RemoteMemoryManager.h +++ b/contrib/llvm/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/contrib/llvm/tools/lli/RemoteTargetExternal.h b/contrib/llvm/tools/lli/RemoteTargetExternal.h index bb621f5..afe8570 100644 --- a/contrib/llvm/tools/lli/RemoteTargetExternal.h +++ b/contrib/llvm/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/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp index 730911b..057841f 100644 --- a/contrib/llvm/tools/lli/lli.cpp +++ b/contrib/llvm/tools/lli/lli.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" +#include "OrcLazyJIT.h" #include "RemoteMemoryManager.h" #include "RemoteTarget.h" #include "RemoteTargetExternal.h" @@ -25,6 +26,7 @@ #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/OrcMCJITReplacement.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" @@ -41,6 +43,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" @@ -64,6 +67,9 @@ using namespace llvm; #define DEBUG_TYPE "lli" namespace { + + enum class JITKind { MCJIT, OrcMCJITReplacement, OrcLazy }; + cl::opt<std::string> InputFile(cl::desc("<input bitcode>"), cl::Positional, cl::init("-")); @@ -74,6 +80,20 @@ namespace { cl::desc("Force interpretation: disable JIT"), cl::init(false)); + cl::opt<JITKind> UseJITKind("jit-kind", + cl::desc("Choose underlying JIT kind."), + cl::init(JITKind::MCJIT), + cl::values( + clEnumValN(JITKind::MCJIT, "mcjit", + "MCJIT"), + clEnumValN(JITKind::OrcMCJITReplacement, + "orc-mcjit", + "Orc-based MCJIT replacement"), + clEnumValN(JITKind::OrcLazy, + "orc-lazy", + "Orc-based lazy JIT."), + clEnumValEnd)); + // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying // memory manager with IPC to execute using this functionality. @@ -215,23 +235,6 @@ namespace { clEnumValN(FloatABI::Hard, "hard", "Hard float ABI (uses FP registers)"), clEnumValEnd)); - cl::opt<bool> -// In debug builds, make this default to true. -#ifdef NDEBUG -#define EMIT_DEBUG false -#else -#define EMIT_DEBUG true -#endif - EmitJitDebugInfo("jit-emit-debug", - cl::desc("Emit debug information to debugger"), - cl::init(EMIT_DEBUG)); -#undef EMIT_DEBUG - - static cl::opt<bool> - EmitJitDebugInfoToDisk("jit-emit-debug-to-disk", - cl::Hidden, - cl::desc("Emit debug info objfiles to disk"), - cl::init(false)); } //===----------------------------------------------------------------------===// @@ -251,7 +254,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(); @@ -362,6 +365,19 @@ static void addCygMingExtraModule(ExecutionEngine *EE, EE->addModule(std::move(M)); } +CodeGenOpt::Level getOptLevel() { + switch (OptLevel) { + default: + errs() << "lli: Invalid optimization level.\n"; + exit(1); + case '0': return CodeGenOpt::None; + case '1': return CodeGenOpt::Less; + case ' ': + case '2': return CodeGenOpt::Default; + case '3': return CodeGenOpt::Aggressive; + } + llvm_unreachable("Unrecognized opt level."); +} //===----------------------------------------------------------------------===// // main Driver function @@ -395,6 +411,9 @@ int main(int argc, char **argv, char * const *envp) { return 1; } + if (UseJITKind == JITKind::OrcLazy) + return runOrcLazyJIT(std::move(Owner), argc, argv); + if (EnableCacheManager) { std::string CacheName("file:"); CacheName.append(InputFile); @@ -421,6 +440,7 @@ int main(int argc, char **argv, char * const *envp) { builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter : EngineKind::JIT); + builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement); // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) @@ -444,31 +464,11 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } - CodeGenOpt::Level OLvl = CodeGenOpt::Default; - switch (OptLevel) { - default: - errs() << argv[0] << ": invalid optimization level.\n"; - return 1; - case ' ': break; - case '0': OLvl = CodeGenOpt::None; break; - case '1': OLvl = CodeGenOpt::Less; break; - case '2': OLvl = CodeGenOpt::Default; break; - case '3': OLvl = CodeGenOpt::Aggressive; break; - } - builder.setOptLevel(OLvl); + builder.setOptLevel(getOptLevel()); TargetOptions Options; - Options.UseSoftFloat = GenerateSoftFloatCalls; if (FloatABIForCalls != FloatABI::Default) Options.FloatABIType = FloatABIForCalls; - if (GenerateSoftFloatCalls) - FloatABIForCalls = FloatABI::Soft; - - // Remote target execution doesn't handle EH or debug registration. - if (!RemoteMCJIT) { - Options.JITEmitDebugInfo = EmitJitDebugInfo; - Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk; - } builder.setTargetOptions(Options); @@ -556,7 +556,7 @@ int main(int argc, char **argv, char * const *envp) { // If the user specifically requested an argv[0] to pass into the program, // do it now. if (!FakeArgv0.empty()) { - InputFile = FakeArgv0; + InputFile = static_cast<std::string>(FakeArgv0); } else { // Otherwise, if there is a .bc suffix on the executable strip it off, it // might confuse the program. @@ -588,7 +588,7 @@ int main(int argc, char **argv, char * const *envp) { // function later on to make an explicit call, so get the function now. Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), Type::getInt32Ty(Context), - NULL); + nullptr); // Run static constructors. if (!ForceInterpreter) { |