From eb14dc7585b06d36802f5dcc258746d8f5cd57d6 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 29 Apr 2019 22:37:27 +0000 Subject: [PATCH] [ORC] Replace the LLJIT/LLLazyJIT Create methods with Builder utilities. LLJITBuilder and LLLazyJITBuilder construct LLJIT and LLLazyJIT instances respectively. Over time these will allow more configurable options to be added while remaining easy to use in the default case, which for default in-process JITing is now: auto J = ExitOnErr(LLJITBuilder.create()); llvm-svn: 359511 --- llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h | 191 ++++++++++++++++----- llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 236 ++++++++++++++------------ llvm/tools/lli/lli.cpp | 26 +-- 3 files changed, 297 insertions(+), 156 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h index b0ef20d..608ebdb 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h @@ -20,31 +20,34 @@ #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h" -#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h" #include "llvm/Support/ThreadPool.h" namespace llvm { namespace orc { +class LLJITBuilderState; +class LLLazyJITBuilderState; + /// A pre-fabricated ORC JIT stack that can serve as an alternative to MCJIT. +/// +/// Create instances using LLJITBuilder. class LLJIT { + template friend class LLJITBuilderSetters; + public: + static Expected> Create(LLJITBuilderState &S); /// Destruct this instance. If a multi-threaded instance, waits for all /// compile threads to complete. ~LLJIT(); - /// Create an LLJIT instance. - /// If NumCompileThreads is not equal to zero, creates a multi-threaded - /// LLJIT with the given number of compile threads. - static Expected> - Create(JITTargetMachineBuilder JTMB, DataLayout DL, - unsigned NumCompileThreads = 0); - /// Returns the ExecutionSession for this instance. ExecutionSession &getExecutionSession() { return *ES; } + /// Returns a reference to the DataLayout for this instance. + const DataLayout &getDataLayout() const { return DL; } + /// Returns a reference to the JITDylib representing the JIT'd main program. JITDylib &getMainJITDylib() { return Main; } @@ -103,17 +106,14 @@ public: Error runDestructors() { return DtorRunner.run(); } /// Returns a reference to the ObjLinkingLayer - RTDyldObjectLinkingLayer &getObjLinkingLayer() { return ObjLinkingLayer; } + ObjectLayer &getObjLinkingLayer() { return *ObjLinkingLayer; } protected: + static std::unique_ptr + createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES); /// Create an LLJIT instance with a single compile thread. - LLJIT(std::unique_ptr ES, std::unique_ptr TM, - DataLayout DL); - - /// Create an LLJIT instance with multiple compile threads. - LLJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, - DataLayout DL, unsigned NumCompileThreads); + LLJIT(LLJITBuilderState &S, Error &Err); std::string mangle(StringRef UnmangledName); @@ -127,8 +127,8 @@ protected: DataLayout DL; std::unique_ptr CompileThreads; - RTDyldObjectLinkingLayer ObjLinkingLayer; - IRCompileLayer CompileLayer; + std::unique_ptr ObjLinkingLayer; + std::unique_ptr CompileLayer; CtorDtorRunner CtorRunner, DtorRunner; }; @@ -136,25 +136,20 @@ protected: /// An extended version of LLJIT that supports lazy function-at-a-time /// compilation of LLVM IR. class LLLazyJIT : public LLJIT { -public: + template friend class LLJITBuilderSetters; - /// Create an LLLazyJIT instance. - /// If NumCompileThreads is not equal to zero, creates a multi-threaded - /// LLLazyJIT with the given number of compile threads. - static Expected> - Create(JITTargetMachineBuilder JTMB, DataLayout DL, - JITTargetAddress ErrorAddr, unsigned NumCompileThreads = 0); +public: /// Set an IR transform (e.g. pass manager pipeline) to run on each function /// when it is compiled. void setLazyCompileTransform(IRTransformLayer::TransformFunction Transform) { - TransformLayer.setTransform(std::move(Transform)); + TransformLayer->setTransform(std::move(Transform)); } /// Sets the partition function. void setPartitionFunction(CompileOnDemandLayer::PartitionFunction Partition) { - CODLayer.setPartitionFunction(std::move(Partition)); + CODLayer->setPartitionFunction(std::move(Partition)); } /// Add a module to be lazily compiled to JITDylib JD. @@ -168,24 +163,144 @@ public: private: // Create a single-threaded LLLazyJIT instance. - LLLazyJIT(std::unique_ptr ES, - std::unique_ptr TM, DataLayout DL, - std::unique_ptr LCTMgr, - std::function()> ISMBuilder); + LLLazyJIT(LLLazyJITBuilderState &S, Error &Err); + + std::unique_ptr LCTMgr; + std::unique_ptr TransformLayer; + std::unique_ptr CODLayer; +}; + +class LLJITBuilderState { +public: + using CreateObjectLinkingLayerFunction = + std::function(ExecutionSession &)>; + + std::unique_ptr ES; + Optional JTMB; + CreateObjectLinkingLayerFunction CreateObjectLinkingLayer; + unsigned NumCompileThreads = 0; - // Create a multi-threaded LLLazyJIT instance. - LLLazyJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, - DataLayout DL, unsigned NumCompileThreads, - std::unique_ptr LCTMgr, - std::function()> ISMBuilder); + /// Called prior to JIT class construcion to fix up defaults. + Error prepareForConstruction(); +}; + +template +class LLJITBuilderSetters { +public: + /// Set the JITTargetMachineBuilder for this instance. + /// + /// If this method is not called, JITTargetMachineBuilder::detectHost will be + /// used to construct a default target machine builder for the host platform. + SetterImpl &setJITTargetMachineBuilder(JITTargetMachineBuilder JTMB) { + impl().JTMB = std::move(JTMB); + return impl(); + } + + /// Return a reference to the JITTargetMachineBuilder. + /// + Optional &getJITTargetMachineBuilder() { + return impl().JTMB; + } + + /// Set an ObjectLinkingLayer creation function. + /// + /// If this method is not called, a default creation function will be used + /// that will construct an RTDyldObjectLinkingLayer. + SetterImpl &setCreateObjectLinkingLayer( + LLJITBuilderState::CreateObjectLinkingLayerFunction + CreateObjectLinkingLayer) { + impl().CreateObjectLinkingLayer = std::move(CreateObjectLinkingLayer); + return impl(); + } + /// Set the number of compile threads to use. + /// + /// If set to zero, compilation will be performed on the execution thread when + /// JITing in-process. If set to any other number N, a thread pool of N + /// threads will be created for compilation. + /// + /// If this method is not called, behavior will be as if it were called with + /// a zero argument. + SetterImpl &setNumCompileThreads(unsigned NumCompileThreads) { + impl().NumCompileThreads = NumCompileThreads; + return impl(); + } + + /// Create an instance of the JIT. + Expected> create() { + if (auto Err = impl().prepareForConstruction()) + return std::move(Err); + + Error Err = Error::success(); + std::unique_ptr J(new JITType(impl(), Err)); + if (Err) + return std::move(Err); + return std::move(J); + } + +protected: + SetterImpl &impl() { return static_cast(*this); } +}; + +/// Constructs LLJIT instances. +class LLJITBuilder + : public LLJITBuilderState, + public LLJITBuilderSetters {}; + +class LLLazyJITBuilderState : public LLJITBuilderState { + friend class LLLazyJIT; + +public: + using IndirectStubsManagerBuilderFunction = + std::function()>; + + Triple TT; + JITTargetAddress LazyCompileFailureAddr = 0; std::unique_ptr LCTMgr; - std::function()> ISMBuilder; + IndirectStubsManagerBuilderFunction ISMBuilder; + + Error prepareForConstruction(); +}; + +template +class LLLazyJITBuilderSetters + : public LLJITBuilderSetters { +public: + /// Set the address in the target address to call if a lazy compile fails. + /// + /// If this method is not called then the value will default to 0. + SetterImpl &setLazyCompileFailureAddr(JITTargetAddress Addr) { + this->impl().LazyCompileFailureAddr = Addr; + return this->impl(); + } + + /// Set the lazy-callthrough manager. + /// + /// If this method is not called then a default, in-process lazy callthrough + /// manager for the host platform will be used. + SetterImpl & + setLazyCallthroughManager(std::unique_ptr LCTMgr) { + this->impl().LCTMgr = std::move(LCTMgr); + return this->impl(); + } - IRTransformLayer TransformLayer; - CompileOnDemandLayer CODLayer; + /// Set the IndirectStubsManager builder function. + /// + /// If this method is not called then a default, in-process + /// IndirectStubsManager builder for the host platform will be used. + SetterImpl &setIndirectStubsManagerBuilder( + LLLazyJITBuilderState::IndirectStubsManagerBuilderFunction ISMBuilder) { + this->impl().ISMBuilder = std::move(ISMBuilder); + return this->impl(); + } }; +/// Constructs LLLazyJIT instances. +class LLLazyJITBuilder + : public LLLazyJITBuilderState, + public LLLazyJITBuilderSetters {}; + } // End namespace orc } // End namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 6202731..ae8a66f 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -8,6 +8,7 @@ #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/Mangler.h" @@ -29,27 +30,21 @@ namespace { namespace llvm { namespace orc { -LLJIT::~LLJIT() { - if (CompileThreads) - CompileThreads->wait(); -} +Error LLJITBuilderState::prepareForConstruction() { -Expected> -LLJIT::Create(JITTargetMachineBuilder JTMB, DataLayout DL, - unsigned NumCompileThreads) { - - if (NumCompileThreads == 0) { - // If NumCompileThreads == 0 then create a single-threaded LLJIT instance. - auto TM = JTMB.createTargetMachine(); - if (!TM) - return TM.takeError(); - return std::unique_ptr(new LLJIT(llvm::make_unique(), - std::move(*TM), std::move(DL))); + if (!JTMB) { + if (auto JTMBOrErr = JITTargetMachineBuilder::detectHost()) + JTMB = std::move(*JTMBOrErr); + else + return JTMBOrErr.takeError(); } - return std::unique_ptr(new LLJIT(llvm::make_unique(), - std::move(JTMB), std::move(DL), - NumCompileThreads)); + return Error::success(); +} + +LLJIT::~LLJIT() { + if (CompileThreads) + CompileThreads->wait(); } Error LLJIT::defineAbsolute(StringRef Name, JITEvaluatedSymbol Sym) { @@ -64,13 +59,13 @@ Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) { if (auto Err = applyDataLayout(*TSM.getModule())) return Err; - return CompileLayer.add(JD, std::move(TSM), ES->allocateVModule()); + return CompileLayer->add(JD, std::move(TSM), ES->allocateVModule()); } Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr Obj) { assert(Obj && "Can not add null object"); - return ObjLinkingLayer.add(JD, std::move(Obj), ES->allocateVModule()); + return ObjLinkingLayer->add(JD, std::move(Obj), ES->allocateVModule()); } Expected LLJIT::lookupLinkerMangled(JITDylib &JD, @@ -78,42 +73,70 @@ Expected LLJIT::lookupLinkerMangled(JITDylib &JD, return ES->lookup(JITDylibSearchList({{&JD, true}}), ES->intern(Name)); } -LLJIT::LLJIT(std::unique_ptr ES, - std::unique_ptr TM, DataLayout DL) - : ES(std::move(ES)), Main(this->ES->getMainJITDylib()), DL(std::move(DL)), - ObjLinkingLayer( - *this->ES, - []() { return llvm::make_unique(); }), - CompileLayer(*this->ES, ObjLinkingLayer, - TMOwningSimpleCompiler(std::move(TM))), - CtorRunner(Main), DtorRunner(Main) {} - -LLJIT::LLJIT(std::unique_ptr ES, JITTargetMachineBuilder JTMB, - DataLayout DL, unsigned NumCompileThreads) - : ES(std::move(ES)), Main(this->ES->getMainJITDylib()), DL(std::move(DL)), - ObjLinkingLayer( - *this->ES, - []() { return llvm::make_unique(); }), - CompileLayer(*this->ES, ObjLinkingLayer, - ConcurrentIRCompiler(std::move(JTMB))), - CtorRunner(Main), DtorRunner(Main) { - assert(NumCompileThreads != 0 && - "Multithreaded LLJIT instance can not be created with 0 threads"); - - // Move modules to new contexts when they're emitted so that we can compile - // them in parallel. - CompileLayer.setCloneToNewContextOnEmit(true); - - // Create a thread pool to compile on and set the execution session - // dispatcher to use the thread pool. - CompileThreads = llvm::make_unique(NumCompileThreads); - this->ES->setDispatchMaterialization( - [this](JITDylib &JD, std::unique_ptr MU) { - // FIXME: Switch to move capture once we have c++14. - auto SharedMU = std::shared_ptr(std::move(MU)); - auto Work = [SharedMU, &JD]() { SharedMU->doMaterialize(JD); }; - CompileThreads->async(std::move(Work)); - }); +std::unique_ptr +LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) { + + // If the config state provided an ObjectLinkingLayer factory then use it. + if (S.CreateObjectLinkingLayer) + return S.CreateObjectLinkingLayer(ES); + + // Otherwise default to creating an RTDyldObjectLinkingLayer that constructs + // a new SectionMemoryManager for each object. + auto GetMemMgr = []() { return llvm::make_unique(); }; + return llvm::make_unique(ES, std::move(GetMemMgr)); +} + +LLJIT::LLJIT(LLJITBuilderState &S, Error &Err) + : ES(S.ES ? std::move(S.ES) : llvm::make_unique()), + Main(this->ES->getMainJITDylib()), DL(""), CtorRunner(Main), + DtorRunner(Main) { + + ErrorAsOutParameter _(&Err); + + ObjLinkingLayer = createObjectLinkingLayer(S, *ES); + + if (S.NumCompileThreads > 0) { + + // Configure multi-threaded. + + if (auto DLOrErr = S.JTMB->getDefaultDataLayoutForTarget()) + DL = std::move(*DLOrErr); + else { + Err = DLOrErr.takeError(); + return; + } + + { + auto TmpCompileLayer = llvm::make_unique( + *ES, *ObjLinkingLayer, ConcurrentIRCompiler(std::move(*S.JTMB))); + + TmpCompileLayer->setCloneToNewContextOnEmit(true); + CompileLayer = std::move(TmpCompileLayer); + } + + CompileThreads = llvm::make_unique(S.NumCompileThreads); + ES->setDispatchMaterialization( + [this](JITDylib &JD, std::unique_ptr MU) { + // FIXME: Switch to move capture once we have c++14. + auto SharedMU = std::shared_ptr(std::move(MU)); + auto Work = [SharedMU, &JD]() { SharedMU->doMaterialize(JD); }; + CompileThreads->async(std::move(Work)); + }); + } else { + + // Configure single-threaded. + + auto TM = S.JTMB->createTargetMachine(); + if (!TM) { + Err = TM.takeError(); + return; + } + + DL = (*TM)->createDataLayout(); + + CompileLayer = llvm::make_unique( + *ES, *ObjLinkingLayer, TMOwningSimpleCompiler(std::move(*TM))); + } } std::string LLJIT::mangle(StringRef UnmangledName) { @@ -142,35 +165,11 @@ void LLJIT::recordCtorDtors(Module &M) { DtorRunner.add(getDestructors(M)); } -Expected> -LLLazyJIT::Create(JITTargetMachineBuilder JTMB, DataLayout DL, - JITTargetAddress ErrorAddr, unsigned NumCompileThreads) { - auto ES = llvm::make_unique(); - - const Triple &TT = JTMB.getTargetTriple(); - - auto LCTMgr = createLocalLazyCallThroughManager(TT, *ES, ErrorAddr); - if (!LCTMgr) - return LCTMgr.takeError(); - - auto ISMBuilder = createLocalIndirectStubsManagerBuilder(TT); - if (!ISMBuilder) - return make_error( - std::string("No indirect stubs manager builder for ") + TT.str(), - inconvertibleErrorCode()); - - if (NumCompileThreads == 0) { - auto TM = JTMB.createTargetMachine(); - if (!TM) - return TM.takeError(); - return std::unique_ptr( - new LLLazyJIT(std::move(ES), std::move(*TM), std::move(DL), - std::move(*LCTMgr), std::move(ISMBuilder))); - } - - return std::unique_ptr(new LLLazyJIT( - std::move(ES), std::move(JTMB), std::move(DL), NumCompileThreads, - std::move(*LCTMgr), std::move(ISMBuilder))); +Error LLLazyJITBuilderState::prepareForConstruction() { + if (auto Err = LLJITBuilderState::prepareForConstruction()) + return Err; + TT = JTMB->getTargetTriple(); + return Error::success(); } Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) { @@ -181,28 +180,55 @@ Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) { recordCtorDtors(*TSM.getModule()); - return CODLayer.add(JD, std::move(TSM), ES->allocateVModule()); + return CODLayer->add(JD, std::move(TSM), ES->allocateVModule()); } -LLLazyJIT::LLLazyJIT( - std::unique_ptr ES, std::unique_ptr TM, - DataLayout DL, std::unique_ptr LCTMgr, - std::function()> ISMBuilder) - : LLJIT(std::move(ES), std::move(TM), std::move(DL)), - LCTMgr(std::move(LCTMgr)), TransformLayer(*this->ES, CompileLayer), - CODLayer(*this->ES, TransformLayer, *this->LCTMgr, - std::move(ISMBuilder)) {} - -LLLazyJIT::LLLazyJIT( - std::unique_ptr ES, JITTargetMachineBuilder JTMB, - DataLayout DL, unsigned NumCompileThreads, - std::unique_ptr LCTMgr, - std::function()> ISMBuilder) - : LLJIT(std::move(ES), std::move(JTMB), std::move(DL), NumCompileThreads), - LCTMgr(std::move(LCTMgr)), TransformLayer(*this->ES, CompileLayer), - CODLayer(*this->ES, TransformLayer, *this->LCTMgr, - std::move(ISMBuilder)) { - CODLayer.setCloneToNewContextOnEmit(true); +LLLazyJIT::LLLazyJIT(LLLazyJITBuilderState &S, Error &Err) : LLJIT(S, Err) { + + // If LLJIT construction failed then bail out. + if (Err) + return; + + ErrorAsOutParameter _(&Err); + + /// Take/Create the lazy-compile callthrough manager. + if (S.LCTMgr) + LCTMgr = std::move(S.LCTMgr); + else { + if (auto LCTMgrOrErr = createLocalLazyCallThroughManager( + S.TT, *ES, S.LazyCompileFailureAddr)) + LCTMgr = std::move(*LCTMgrOrErr); + else { + Err = LCTMgrOrErr.takeError(); + return; + } + } + + // Take/Create the indirect stubs manager builder. + auto ISMBuilder = std::move(S.ISMBuilder); + + // If none was provided, try to build one. + if (!ISMBuilder) + ISMBuilder = createLocalIndirectStubsManagerBuilder(S.TT); + + // No luck. Bail out. + if (!ISMBuilder) { + Err = make_error("Could not construct " + "IndirectStubsManagerBuilder for target " + + S.TT.str(), + inconvertibleErrorCode()); + return; + } + + // Create the transform layer. + TransformLayer = llvm::make_unique(*ES, *CompileLayer); + + // Create the COD layer. + CODLayer = llvm::make_unique( + *ES, *TransformLayer, *LCTMgr, std::move(ISMBuilder)); + + if (S.NumCompileThreads > 0) + CODLayer->setCloneToNewContextOnEmit(true); } } // End namespace orc. diff --git a/llvm/tools/lli/lli.cpp b/llvm/tools/lli/lli.cpp index 66254a3..a44b743 100644 --- a/llvm/tools/lli/lli.cpp +++ b/llvm/tools/lli/lli.cpp @@ -763,14 +763,17 @@ int runOrcLazyJIT(const char *ProgName) { reportError(Err, ProgName); const auto &TT = MainModule.getModule()->getTargetTriple(); - orc::JITTargetMachineBuilder JTMB = + orc::LLLazyJITBuilder Builder; + + Builder.setJITTargetMachineBuilder( TT.empty() ? ExitOnErr(orc::JITTargetMachineBuilder::detectHost()) - : orc::JITTargetMachineBuilder(Triple(TT)); + : orc::JITTargetMachineBuilder(Triple(TT))); if (!MArch.empty()) - JTMB.getTargetTriple().setArchName(MArch); + Builder.getJITTargetMachineBuilder()->getTargetTriple().setArchName(MArch); - JTMB.setCPU(getCPUStr()) + Builder.getJITTargetMachineBuilder() + ->setCPU(getCPUStr()) .addFeatures(getFeatureList()) .setRelocationModel(RelocModel.getNumOccurrences() ? Optional(RelocModel) @@ -779,12 +782,11 @@ int runOrcLazyJIT(const char *ProgName) { ? Optional(CMModel) : None); - DataLayout DL = ExitOnErr(JTMB.getDefaultDataLayoutForTarget()); + Builder.setLazyCompileFailureAddr( + pointerToJITTargetAddress(exitOnLazyCallThroughFailure)); + Builder.setNumCompileThreads(LazyJITCompileThreads); - auto J = ExitOnErr(orc::LLLazyJIT::Create( - std::move(JTMB), DL, - pointerToJITTargetAddress(exitOnLazyCallThroughFailure), - LazyJITCompileThreads)); + auto J = ExitOnErr(Builder.create()); if (PerModuleLazy) J->setPartitionFunction(orc::CompileOnDemandLayer::compileWholeModule); @@ -801,9 +803,9 @@ int runOrcLazyJIT(const char *ProgName) { }); J->getMainJITDylib().setGenerator( ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - DL.getGlobalPrefix()))); + J->getDataLayout().getGlobalPrefix()))); - orc::MangleAndInterner Mangle(J->getExecutionSession(), DL); + orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout()); orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; ExitOnErr(CXXRuntimeOverrides.enable(J->getMainJITDylib(), Mangle)); @@ -863,8 +865,6 @@ int runOrcLazyJIT(const char *ProgName) { AltEntryThreads.push_back(std::thread([EntryPoint]() { EntryPoint(); })); } - J->getExecutionSession().dump(llvm::dbgs()); - // Run main. auto MainSym = ExitOnErr(J->lookup("main")); typedef int (*MainFnPtr)(int, const char *[]); -- 2.7.4