diff options
Diffstat (limited to 'include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h')
| -rw-r--r-- | include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h | 367 |
1 files changed, 247 insertions, 120 deletions
diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 9694b80d19289..7dab5d1bc67f0 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -22,6 +22,7 @@ #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Transforms/Utils/Cloning.h" #include <list> +#include <memory> #include <set> #include "llvm/Support/Debug.h" @@ -36,56 +37,89 @@ namespace orc { /// added to the layer below. When a stub is called it triggers the extraction /// of the function body from the original module. The extracted body is then /// compiled and executed. -template <typename BaseLayerT, typename CompileCallbackMgrT, - typename PartitioningFtor = - std::function<std::set<Function*>(Function&)>> +template <typename BaseLayerT, + typename CompileCallbackMgrT = JITCompileCallbackManager, + typename IndirectStubsMgrT = IndirectStubsManager> class CompileOnDemandLayer { private: - // Utility class for MapValue. Only materializes declarations for global - // variables. - class GlobalDeclMaterializer : public ValueMaterializer { + template <typename MaterializerFtor> + class LambdaMaterializer final : public ValueMaterializer { public: - typedef std::set<const Function*> StubSet; + LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} + Value *materializeDeclFor(Value *V) final { return M(V); } - GlobalDeclMaterializer(Module &Dst, const StubSet *StubsToClone = nullptr) - : Dst(Dst), StubsToClone(StubsToClone) {} - - Value* materializeValueFor(Value *V) final { - if (auto *GV = dyn_cast<GlobalVariable>(V)) - return cloneGlobalVariableDecl(Dst, *GV); - else if (auto *F = dyn_cast<Function>(V)) { - auto *ClonedF = cloneFunctionDecl(Dst, *F); - if (StubsToClone && StubsToClone->count(F)) { - GlobalVariable *FnBodyPtr = - createImplPointer(*ClonedF->getType(), *ClonedF->getParent(), - ClonedF->getName() + "$orc_addr", nullptr); - makeStub(*ClonedF, *FnBodyPtr); - ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); - ClonedF->addFnAttr(Attribute::AlwaysInline); - } - return ClonedF; - } - // Else. - return nullptr; - } private: - Module &Dst; - const StubSet *StubsToClone; + MaterializerFtor M; }; + template <typename MaterializerFtor> + LambdaMaterializer<MaterializerFtor> + createLambdaMaterializer(MaterializerFtor M) { + return LambdaMaterializer<MaterializerFtor>(std::move(M)); + } + typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; + class ModuleOwner { + public: + ModuleOwner() = default; + ModuleOwner(const ModuleOwner&) = delete; + ModuleOwner& operator=(const ModuleOwner&) = delete; + virtual ~ModuleOwner() { } + virtual Module& getModule() const = 0; + }; + + template <typename ModulePtrT> + class ModuleOwnerImpl : public ModuleOwner { + public: + ModuleOwnerImpl(ModulePtrT ModulePtr) : ModulePtr(std::move(ModulePtr)) {} + Module& getModule() const override { return *ModulePtr; } + private: + ModulePtrT ModulePtr; + }; + + template <typename ModulePtrT> + std::unique_ptr<ModuleOwner> wrapOwnership(ModulePtrT ModulePtr) { + return llvm::make_unique<ModuleOwnerImpl<ModulePtrT>>(std::move(ModulePtr)); + } + struct LogicalModuleResources { - std::shared_ptr<Module> SourceModule; + std::unique_ptr<ModuleOwner> SourceModuleOwner; std::set<const Function*> StubsToClone; + std::unique_ptr<IndirectStubsMgrT> StubsMgr; + + LogicalModuleResources() = default; + + // Explicit move constructor to make MSVC happy. + LogicalModuleResources(LogicalModuleResources &&Other) + : SourceModuleOwner(std::move(Other.SourceModuleOwner)), + StubsToClone(std::move(Other.StubsToClone)), + StubsMgr(std::move(Other.StubsMgr)) {} + + // Explicit move assignment to make MSVC happy. + LogicalModuleResources& operator=(LogicalModuleResources &&Other) { + SourceModuleOwner = std::move(Other.SourceModuleOwner); + StubsToClone = std::move(Other.StubsToClone); + StubsMgr = std::move(Other.StubsMgr); + } + + JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { + if (Name.endswith("$stub_ptr") && !ExportedSymbolsOnly) { + assert(!ExportedSymbolsOnly && "Stubs are never exported"); + return StubsMgr->findPointer(Name.drop_back(9)); + } + return StubsMgr->findStub(Name, ExportedSymbolsOnly); + } + }; + + struct LogicalDylibResources { typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)> SymbolResolverFtor; SymbolResolverFtor ExternalSymbolResolver; - PartitioningFtor Partitioner; }; typedef LogicalDylib<BaseLayerT, LogicalModuleResources, @@ -95,13 +129,25 @@ private: typedef std::list<CODLogicalDylib> LogicalDylibList; public: + /// @brief Handle to a set of loaded modules. typedef typename LogicalDylibList::iterator ModuleSetHandleT; + /// @brief Module partitioning functor. + typedef std::function<std::set<Function*>(Function&)> PartitioningFtor; + + /// @brief Builder for IndirectStubsManagers. + typedef std::function<std::unique_ptr<IndirectStubsMgrT>()> + IndirectStubsManagerBuilderT; + /// @brief Construct a compile-on-demand layer instance. - CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr, - bool CloneStubsIntoPartitions) - : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr), + CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition, + CompileCallbackMgrT &CallbackMgr, + IndirectStubsManagerBuilderT CreateIndirectStubsManager, + bool CloneStubsIntoPartitions = true) + : BaseLayer(BaseLayer), Partition(Partition), + CompileCallbackMgr(CallbackMgr), + CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} /// @brief Add a module to the compile-on-demand layer. @@ -122,17 +168,9 @@ public: return Resolver->findSymbol(Name); }; - LDResources.Partitioner = - [](Function &F) { - std::set<Function*> Partition; - Partition.insert(&F); - return Partition; - }; - // Process each of the modules in this module set. for (auto &M : Ms) - addLogicalModule(LogicalDylibs.back(), - std::shared_ptr<Module>(std::move(M))); + addLogicalModule(LogicalDylibs.back(), std::move(M)); return std::prev(LogicalDylibs.end()); } @@ -150,6 +188,10 @@ public: /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it exists. JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { + for (auto LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end(); + LDI != LDE; ++LDI) + if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly)) + return Symbol; return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); } @@ -162,85 +204,138 @@ public: private: - void addLogicalModule(CODLogicalDylib &LD, std::shared_ptr<Module> SrcM) { + template <typename ModulePtrT> + void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) { // Bump the linkage and rename any anonymous/privote members in SrcM to // ensure that everything will resolve properly after we partition SrcM. - makeAllSymbolsExternallyAccessible(*SrcM); + makeAllSymbolsExternallyAccessible(*SrcMPtr); // Create a logical module handle for SrcM within the logical dylib. auto LMH = LD.createLogicalModule(); auto &LMResources = LD.getLogicalModuleResources(LMH); - LMResources.SourceModule = SrcM; - // Create the GVs-and-stubs module. - auto GVsAndStubsM = llvm::make_unique<Module>( - (SrcM->getName() + ".globals_and_stubs").str(), - SrcM->getContext()); - GVsAndStubsM->setDataLayout(SrcM->getDataLayout()); - ValueToValueMapTy VMap; + LMResources.SourceModuleOwner = wrapOwnership(std::move(SrcMPtr)); - // Process module and create stubs. - // We create the stubs before copying the global variables as we know the - // stubs won't refer to any globals (they only refer to their implementation - // pointer) so there's no ordering/value-mapping issues. - for (auto &F : *SrcM) { + Module &SrcM = LMResources.SourceModuleOwner->getModule(); - // Skip declarations. - if (F.isDeclaration()) - continue; + // Create the GlobalValues module. + const DataLayout &DL = SrcM.getDataLayout(); + auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(), + SrcM.getContext()); + GVsM->setDataLayout(DL); - // Record all functions defined by this module. - if (CloneStubsIntoPartitions) - LMResources.StubsToClone.insert(&F); + // Create function stubs. + ValueToValueMapTy VMap; + { + typename IndirectStubsMgrT::StubInitsMap StubInits; + for (auto &F : SrcM) { + // Skip declarations. + if (F.isDeclaration()) + continue; - // For each definition: create a callback, a stub, and a function body - // pointer. Initialize the function body pointer to point at the callback, - // and set the callback to compile the function body. - auto CCInfo = CompileCallbackMgr.getCompileCallback(SrcM->getContext()); - Function *StubF = cloneFunctionDecl(*GVsAndStubsM, F, &VMap); - GlobalVariable *FnBodyPtr = - createImplPointer(*StubF->getType(), *StubF->getParent(), - StubF->getName() + "$orc_addr", - createIRTypedAddress(*StubF->getFunctionType(), - CCInfo.getAddress())); - makeStub(*StubF, *FnBodyPtr); - CCInfo.setCompileAction( - [this, &LD, LMH, &F]() { + // Record all functions defined by this module. + if (CloneStubsIntoPartitions) + LMResources.StubsToClone.insert(&F); + + // Create a callback, associate it with the stub for the function, + // and set the compile action to compile the partition containing the + // function. + auto CCInfo = CompileCallbackMgr.getCompileCallback(); + StubInits[mangle(F.getName(), DL)] = + std::make_pair(CCInfo.getAddress(), + JITSymbolBase::flagsFromGlobalValue(F)); + CCInfo.setCompileAction([this, &LD, LMH, &F]() { return this->extractAndCompile(LD, LMH, F); }); + } + + LMResources.StubsMgr = CreateIndirectStubsManager(); + auto EC = LMResources.StubsMgr->createStubs(StubInits); + (void)EC; + // FIXME: This should be propagated back to the user. Stub creation may + // fail for remote JITs. + assert(!EC && "Error generating stubs"); } - // Now clone the global variable declarations. - GlobalDeclMaterializer GDMat(*GVsAndStubsM); - for (auto &GV : SrcM->globals()) - if (!GV.isDeclaration()) - cloneGlobalVariableDecl(*GVsAndStubsM, GV, &VMap); + // Clone global variable decls. + for (auto &GV : SrcM.globals()) + if (!GV.isDeclaration() && !VMap.count(&GV)) + cloneGlobalVariableDecl(*GVsM, GV, &VMap); + + // And the aliases. + for (auto &A : SrcM.aliases()) + if (!VMap.count(&A)) + cloneGlobalAliasDecl(*GVsM, A, VMap); + + // Now we need to clone the GV and alias initializers. + + // Initializers may refer to functions declared (but not defined) in this + // module. Build a materializer to clone decls on demand. + auto Materializer = createLambdaMaterializer( + [this, &GVsM, &LMResources](Value *V) -> Value* { + if (auto *F = dyn_cast<Function>(V)) { + // Decls in the original module just get cloned. + if (F->isDeclaration()) + return cloneFunctionDecl(*GVsM, *F); + + // Definitions in the original module (which we have emitted stubs + // for at this point) get turned into a constant alias to the stub + // instead. + const DataLayout &DL = GVsM->getDataLayout(); + std::string FName = mangle(F->getName(), DL); + auto StubSym = LMResources.StubsMgr->findStub(FName, false); + unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType()); + ConstantInt *StubAddr = + ConstantInt::get(GVsM->getContext(), + APInt(PtrBitWidth, StubSym.getAddress())); + Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr, + StubAddr, F->getType()); + return GlobalAlias::create(F->getFunctionType(), + F->getType()->getAddressSpace(), + F->getLinkage(), F->getName(), + Init, GVsM.get()); + } + // else.... + return nullptr; + }); - // Then clone the initializers. - for (auto &GV : SrcM->globals()) + // Clone the global variable initializers. + for (auto &GV : SrcM.globals()) if (!GV.isDeclaration()) - moveGlobalVariableInitializer(GV, VMap, &GDMat); + moveGlobalVariableInitializer(GV, VMap, &Materializer); - // Build a resolver for the stubs module and add it to the base layer. - auto GVsAndStubsResolver = createLambdaResolver( - [&LD](const std::string &Name) { + // Clone the global alias initializers. + for (auto &A : SrcM.aliases()) { + auto *NewA = cast<GlobalAlias>(VMap[&A]); + assert(NewA && "Alias not cloned?"); + Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr, + &Materializer); + NewA->setAliasee(cast<Constant>(Init)); + } + + // Build a resolver for the globals module and add it to the base layer. + auto GVsResolver = createLambdaResolver( + [&LD, LMH](const std::string &Name) { + auto &LMResources = LD.getLogicalModuleResources(LMH); + if (auto Sym = LMResources.StubsMgr->findStub(Name, false)) + return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); return LD.getDylibResources().ExternalSymbolResolver(Name); }, [](const std::string &Name) { return RuntimeDyld::SymbolInfo(nullptr); }); - std::vector<std::unique_ptr<Module>> GVsAndStubsMSet; - GVsAndStubsMSet.push_back(std::move(GVsAndStubsM)); - auto GVsAndStubsH = - BaseLayer.addModuleSet(std::move(GVsAndStubsMSet), + std::vector<std::unique_ptr<Module>> GVsMSet; + GVsMSet.push_back(std::move(GVsM)); + auto GVsH = + BaseLayer.addModuleSet(std::move(GVsMSet), llvm::make_unique<SectionMemoryManager>(), - std::move(GVsAndStubsResolver)); - LD.addToLogicalModule(LMH, GVsAndStubsH); + std::move(GVsResolver)); + LD.addToLogicalModule(LMH, GVsH); } - static std::string Mangle(StringRef Name, const DataLayout &DL) { + static std::string mangle(StringRef Name, const DataLayout &DL) { std::string MangledName; { raw_string_ostream MangledNameStream(MangledName); @@ -252,42 +347,35 @@ private: TargetAddress extractAndCompile(CODLogicalDylib &LD, LogicalModuleHandle LMH, Function &F) { - Module &SrcM = *LD.getLogicalModuleResources(LMH).SourceModule; + auto &LMResources = LD.getLogicalModuleResources(LMH); + Module &SrcM = LMResources.SourceModuleOwner->getModule(); // If F is a declaration we must already have compiled it. if (F.isDeclaration()) return 0; // Grab the name of the function being called here. - std::string CalledFnName = Mangle(F.getName(), SrcM.getDataLayout()); + std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout()); - auto Partition = LD.getDylibResources().Partitioner(F); - auto PartitionH = emitPartition(LD, LMH, Partition); + auto Part = Partition(F); + auto PartH = emitPartition(LD, LMH, Part); TargetAddress CalledAddr = 0; - for (auto *SubF : Partition) { - std::string FName = SubF->getName(); - auto FnBodySym = - BaseLayer.findSymbolIn(PartitionH, Mangle(FName, SrcM.getDataLayout()), - false); - auto FnPtrSym = - BaseLayer.findSymbolIn(*LD.moduleHandlesBegin(LMH), - Mangle(FName + "$orc_addr", - SrcM.getDataLayout()), - false); + for (auto *SubF : Part) { + std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout()); + auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false); assert(FnBodySym && "Couldn't find function body."); - assert(FnPtrSym && "Couldn't find function body pointer."); TargetAddress FnBodyAddr = FnBodySym.getAddress(); - void *FnPtrAddr = reinterpret_cast<void*>( - static_cast<uintptr_t>(FnPtrSym.getAddress())); // If this is the function we're calling record the address so we can // return it from this function. if (SubF == &F) CalledAddr = FnBodyAddr; - memcpy(FnPtrAddr, &FnBodyAddr, sizeof(uintptr_t)); + // Update the function body pointer for the stub. + if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr)) + return 0; } return CalledAddr; @@ -296,13 +384,13 @@ private: template <typename PartitionT> BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD, LogicalModuleHandle LMH, - const PartitionT &Partition) { + const PartitionT &Part) { auto &LMResources = LD.getLogicalModuleResources(LMH); - Module &SrcM = *LMResources.SourceModule; + Module &SrcM = LMResources.SourceModuleOwner->getModule(); // Create the module. std::string NewName = SrcM.getName(); - for (auto *F : Partition) { + for (auto *F : Part) { NewName += "."; NewName += F->getName(); } @@ -310,15 +398,51 @@ private: auto M = llvm::make_unique<Module>(NewName, SrcM.getContext()); M->setDataLayout(SrcM.getDataLayout()); ValueToValueMapTy VMap; - GlobalDeclMaterializer GDM(*M, &LMResources.StubsToClone); + + auto Materializer = createLambdaMaterializer([this, &LMResources, &M, + &VMap](Value *V) -> Value * { + if (auto *GV = dyn_cast<GlobalVariable>(V)) + return cloneGlobalVariableDecl(*M, *GV); + + if (auto *F = dyn_cast<Function>(V)) { + // Check whether we want to clone an available_externally definition. + if (!LMResources.StubsToClone.count(F)) + return cloneFunctionDecl(*M, *F); + + // Ok - we want an inlinable stub. For that to work we need a decl + // for the stub pointer. + auto *StubPtr = createImplPointer(*F->getType(), *M, + F->getName() + "$stub_ptr", nullptr); + auto *ClonedF = cloneFunctionDecl(*M, *F); + makeStub(*ClonedF, *StubPtr); + ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); + ClonedF->addFnAttr(Attribute::AlwaysInline); + return ClonedF; + } + + if (auto *A = dyn_cast<GlobalAlias>(V)) { + auto *Ty = A->getValueType(); + if (Ty->isFunctionTy()) + return Function::Create(cast<FunctionType>(Ty), + GlobalValue::ExternalLinkage, A->getName(), + M.get()); + + return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, + nullptr, A->getName(), nullptr, + GlobalValue::NotThreadLocal, + A->getType()->getAddressSpace()); + } + + return nullptr; + }); // Create decls in the new module. - for (auto *F : Partition) + for (auto *F : Part) cloneFunctionDecl(*M, *F, &VMap); // Move the function bodies. - for (auto *F : Partition) - moveFunctionBody(*F, VMap, &GDM); + for (auto *F : Part) + moveFunctionBody(*F, VMap, &Materializer); // Create memory manager and symbol resolver. auto MemMgr = llvm::make_unique<SectionMemoryManager>(); @@ -342,7 +466,10 @@ private: } BaseLayerT &BaseLayer; + PartitioningFtor Partition; CompileCallbackMgrT &CompileCallbackMgr; + IndirectStubsManagerBuilderT CreateIndirectStubsManager; + LogicalDylibList LogicalDylibs; bool CloneStubsIntoPartitions; }; |
