From 597d2b730940f42a70f9e91c8fca2aa9d7d6e079 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 13 Apr 2015 22:12:54 +0000 Subject: [PATCH] [Orc] Add an Orc layer for applying arbitrary transforms to IR, use it to add debugging output to the LLI orc-lazy JIT, and update the orc-lazy "hello.ll" test to actually test for lazy compilation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@234805 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../ExecutionEngine/Orc/IRTransformLayer.h | 101 ++++++++++++++++++ test/ExecutionEngine/OrcLazy/hello.ll | 5 +- tools/lli/OrcLazyJIT.cpp | 81 +++++++++++++- tools/lli/OrcLazyJIT.h | 16 ++- 4 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 include/llvm/ExecutionEngine/Orc/IRTransformLayer.h diff --git a/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h b/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h new file mode 100644 index 00000000000..4dabb9a4149 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h @@ -0,0 +1,101 @@ +//===----- IRTransformLayer.h - Run all IR through a functor ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Run all IR passed in through a user supplied functor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H + +#include "JITSymbol.h" + +namespace llvm { +namespace orc { + +/// @brief IR mutating layer. +/// +/// This layer accepts sets of LLVM IR Modules (via addModuleSet). It +/// immediately applies the user supplied functor to each module, then adds +/// the set of transformed modules to the layer below. +template +class IRTransformLayer { +public: + /// @brief Handle to a set of added modules. + typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + + /// @brief Construct an IRTransformLayer with the given BaseLayer + IRTransformLayer(BaseLayerT &BaseLayer, + TransformFtor Transform = TransformFtor()) + : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} + + /// @brief Apply the transform functor to each module in the module set, then + /// add the resulting set of modules to the base layer, along with the + /// memory manager and symbol resolver. + /// + /// @return A handle for the added modules. + template + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + + for (auto I = Ms.begin(), E = Ms.end(); I != E; ++I) + *I = Transform(std::move(*I)); + + return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), + std::move(Resolver)); + } + + /// @brief Remove the module set associated with the handle H. + void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(H); } + + /// @brief Search for the given named symbol. + /// @param Name The name of the symbol to search for. + /// @param ExportedSymbolsOnly If true, search only for exported symbols. + /// @return A handle for the given named symbol, if it exists. + JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { + return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); + } + + /// @brief Get the address of the given symbol in the context of the set of + /// modules represented by the handle H. This call is forwarded to the + /// base layer's implementation. + /// @param H The handle for the module set to search in. + /// @param Name The name of the symbol to search for. + /// @param ExportedSymbolsOnly If true, search only for exported symbols. + /// @return A handle for the given named symbol, if it is found in the + /// given module set. + JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); + } + + /// @brief Immediately emit and finalize the module set represented by the + /// given handle. + /// @param H Handle for module set to emit/finalize. + void emitAndFinalize(ModuleSetHandleT H) { + BaseLayer.emitAndFinalize(H); + } + + /// @brief Access the transform functor directly. + TransformFtor& getTransform() { return Transform; } + + /// @brief Access the mumate functor directly. + const TransformFtor& getTransform() const { return Transform; } + +private: + BaseLayerT &BaseLayer; + TransformFtor Transform; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H diff --git a/test/ExecutionEngine/OrcLazy/hello.ll b/test/ExecutionEngine/OrcLazy/hello.ll index dcc6da06386..247d95f0b8d 100644 --- a/test/ExecutionEngine/OrcLazy/hello.ll +++ b/test/ExecutionEngine/OrcLazy/hello.ll @@ -1,7 +1,8 @@ -; RUN: lli -jit-kind=orc-lazy %s | FileCheck %s +; RUN: lli -jit-kind=orc-lazy -orc-lazy-debug=funcs-to-stderr %s | FileCheck %s ; ; CHECK: Hello -; CHECK-NEXT: Goodbye +; CHECK: [ main$orc_body ] +; CHECK: Goodbye %class.Foo = type { i8 } diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp index 236de7c31d2..519bd72ccd4 100644 --- a/tools/lli/OrcLazyJIT.cpp +++ b/tools/lli/OrcLazyJIT.cpp @@ -9,26 +9,101 @@ #include "OrcLazyJIT.h" #include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" +#include using namespace llvm; +namespace { + + enum class DumpKind { NoDump, DumpFuncsToStdErr, DumpModsToStdErr, + DumpModsToDisk }; + + cl::opt 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::DumpFuncsToStdErr, + "funcs-to-stderr", + "Dump function names to stderr."), + 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 CCMgrT; - return [](CompileLayerT &CompileLayer, RuntimeDyld::MemoryManager &MemMgr, + return [](IRDumpLayerT &IRDumpLayer, RuntimeDyld::MemoryManager &MemMgr, LLVMContext &Context) { - return make_unique(CompileLayer, MemMgr, Context, 0, 64); + return make_unique(IRDumpLayer, MemMgr, Context, 0, 64); }; } } } +OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { + + switch (OrcDumpKind) { + case DumpKind::NoDump: + return [](std::unique_ptr M) { return std::move(M); }; + + case DumpKind::DumpFuncsToStdErr: + return [](std::unique_ptr M) { + dbgs() << "[ "; + + for (const auto &F : *M) { + if (F.isDeclaration()) + continue; + + if (F.hasName()) + dbgs() << F.getName() << " "; + else + dbgs() << " "; + } + + dbgs() << "]\n"; + return std::move(M); + }; + + case DumpKind::DumpModsToStdErr: + return [](std::unique_ptr M) { + dbgs() << "----- Module Start -----\n" << *M + << "----- Module End -----\n"; + + return std::move(M); + }; + + case DumpKind::DumpModsToDisk: + return [](std::unique_ptr 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); + }; + } +} + int llvm::runOrcLazyJIT(std::unique_ptr M, int ArgC, char* ArgV[]) { // Add the program's symbols into the JIT's search space. if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) { diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h index 8e6f400f0c5..3f89f6a5168 100644 --- a/tools/lli/OrcLazyJIT.h +++ b/tools/lli/OrcLazyJIT.h @@ -20,6 +20,7 @@ #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" @@ -33,13 +34,16 @@ public: typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; typedef orc::ObjectLinkingLayer<> ObjLayerT; typedef orc::IRCompileLayer CompileLayerT; - typedef orc::LazyEmittingLayer LazyEmitLayerT; + typedef std::function(std::unique_ptr)> + TransformFtor; + typedef orc::IRTransformLayer IRDumpLayerT; + typedef orc::LazyEmittingLayer LazyEmitLayerT; typedef orc::CompileOnDemandLayer CODLayerT; typedef CODLayerT::ModuleSetHandleT ModuleHandleT; typedef std::function< - std::unique_ptr(CompileLayerT&, + std::unique_ptr(IRDumpLayerT&, RuntimeDyld::MemoryManager&, LLVMContext&)> CallbackManagerBuilder; @@ -52,8 +56,9 @@ public: Mang(this->TM->getDataLayout()), ObjectLayer(), CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), - LazyEmitLayer(CompileLayer), - CCMgr(BuildCallbackMgr(CompileLayer, CCMgrMemMgr, Context)), + IRDumpLayer(CompileLayer, createDebugDumper()), + LazyEmitLayer(IRDumpLayer), + CCMgr(BuildCallbackMgr(IRDumpLayer, CCMgrMemMgr, Context)), CODLayer(LazyEmitLayer, *CCMgr), CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {} @@ -137,12 +142,15 @@ private: return MangledName; } + static TransformFtor createDebugDumper(); + std::unique_ptr TM; Mangler Mang; SectionMemoryManager CCMgrMemMgr; ObjLayerT ObjectLayer; CompileLayerT CompileLayer; + IRDumpLayerT IRDumpLayer; LazyEmitLayerT LazyEmitLayer; std::unique_ptr CCMgr; CODLayerT CODLayer; -- 2.34.1