|  | //===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" | 
|  | #include "llvm/Bitcode/BitcodeReader.h" | 
|  | #include "llvm/Bitcode/BitcodeWriter.h" | 
|  | #include "llvm/IR/Mangler.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Transforms/Utils/Cloning.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::orc; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | template <typename MaterializerFtor> | 
|  | class LambdaValueMaterializer final : public ValueMaterializer { | 
|  | public: | 
|  | LambdaValueMaterializer(MaterializerFtor M) : M(std::move(M)) {} | 
|  |  | 
|  | Value *materialize(Value *V) final { return M(V); } | 
|  |  | 
|  | private: | 
|  | MaterializerFtor M; | 
|  | }; | 
|  |  | 
|  | template <typename MaterializerFtor> | 
|  | LambdaValueMaterializer<MaterializerFtor> | 
|  | createLambdaValueMaterializer(MaterializerFtor M) { | 
|  | return LambdaValueMaterializer<MaterializerFtor>(std::move(M)); | 
|  | } | 
|  | } // namespace | 
|  |  | 
|  | static void extractAliases(MaterializationResponsibility &R, Module &M, | 
|  | MangleAndInterner &Mangle) { | 
|  | SymbolAliasMap Aliases; | 
|  |  | 
|  | std::vector<GlobalAlias *> ModAliases; | 
|  | for (auto &A : M.aliases()) | 
|  | ModAliases.push_back(&A); | 
|  |  | 
|  | for (auto *A : ModAliases) { | 
|  | Constant *Aliasee = A->getAliasee(); | 
|  | assert(A->hasName() && "Anonymous alias?"); | 
|  | assert(Aliasee->hasName() && "Anonymous aliasee"); | 
|  | std::string AliasName = A->getName(); | 
|  |  | 
|  | Aliases[Mangle(AliasName)] = SymbolAliasMapEntry( | 
|  | {Mangle(Aliasee->getName()), JITSymbolFlags::fromGlobalValue(*A)}); | 
|  |  | 
|  | if (isa<Function>(Aliasee)) { | 
|  | auto *F = cloneFunctionDecl(M, *cast<Function>(Aliasee)); | 
|  | A->replaceAllUsesWith(F); | 
|  | A->eraseFromParent(); | 
|  | F->setName(AliasName); | 
|  | } else if (isa<GlobalValue>(Aliasee)) { | 
|  | auto *G = cloneGlobalVariableDecl(M, *cast<GlobalVariable>(Aliasee)); | 
|  | A->replaceAllUsesWith(G); | 
|  | A->eraseFromParent(); | 
|  | G->setName(AliasName); | 
|  | } | 
|  | } | 
|  |  | 
|  | R.replace(symbolAliases(std::move(Aliases))); | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<Module> | 
|  | extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix, | 
|  | function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) { | 
|  | SmallVector<char, 1> ClonedModuleBuffer; | 
|  |  | 
|  | { | 
|  | std::set<GlobalValue *> ClonedDefsInSrc; | 
|  | ValueToValueMapTy VMap; | 
|  | auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) { | 
|  | if (ShouldCloneDefinition(GV)) { | 
|  | ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV)); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | }); | 
|  |  | 
|  | for (auto *GV : ClonedDefsInSrc) { | 
|  | // Delete the definition and bump the linkage in the source module. | 
|  | if (isa<Function>(GV)) { | 
|  | auto &F = *cast<Function>(GV); | 
|  | F.deleteBody(); | 
|  | F.setPersonalityFn(nullptr); | 
|  | } else if (isa<GlobalVariable>(GV)) { | 
|  | cast<GlobalVariable>(GV)->setInitializer(nullptr); | 
|  | } else | 
|  | llvm_unreachable("Unsupported global type"); | 
|  |  | 
|  | GV->setLinkage(GlobalValue::ExternalLinkage); | 
|  | } | 
|  |  | 
|  | BitcodeWriter BCWriter(ClonedModuleBuffer); | 
|  |  | 
|  | BCWriter.writeModule(*Tmp); | 
|  | BCWriter.writeSymtab(); | 
|  | BCWriter.writeStrtab(); | 
|  | } | 
|  |  | 
|  | MemoryBufferRef ClonedModuleBufferRef( | 
|  | StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()), | 
|  | "cloned module buffer"); | 
|  |  | 
|  | auto ClonedModule = | 
|  | cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext)); | 
|  | ClonedModule->setModuleIdentifier((M.getName() + Suffix).str()); | 
|  | return ClonedModule; | 
|  | } | 
|  |  | 
|  | static std::unique_ptr<Module> extractGlobals(Module &M, | 
|  | LLVMContext &NewContext) { | 
|  | return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) { | 
|  | return isa<GlobalVariable>(GV); | 
|  | }); | 
|  | } | 
|  |  | 
|  | namespace llvm { | 
|  | namespace orc { | 
|  |  | 
|  | class ExtractingIRMaterializationUnit : public IRMaterializationUnit { | 
|  | public: | 
|  | ExtractingIRMaterializationUnit(ExecutionSession &ES, | 
|  | CompileOnDemandLayer2 &Parent, | 
|  | std::unique_ptr<Module> M) | 
|  | : IRMaterializationUnit(ES, std::move(M)), Parent(Parent) {} | 
|  |  | 
|  | ExtractingIRMaterializationUnit(std::unique_ptr<Module> M, | 
|  | SymbolFlagsMap SymbolFlags, | 
|  | SymbolNameToDefinitionMap SymbolToDefinition, | 
|  | CompileOnDemandLayer2 &Parent) | 
|  | : IRMaterializationUnit(std::move(M), std::move(SymbolFlags), | 
|  | std::move(SymbolToDefinition)), | 
|  | Parent(Parent) {} | 
|  |  | 
|  | private: | 
|  | void materialize(MaterializationResponsibility R) override { | 
|  | // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the | 
|  | //        extracted module key, extracted module, and source module key | 
|  | //        together. This could be used, for example, to provide a specific | 
|  | //        memory manager instance to the linking layer. | 
|  |  | 
|  | auto RequestedSymbols = R.getRequestedSymbols(); | 
|  |  | 
|  | // Extract the requested functions into a new module. | 
|  | std::unique_ptr<Module> ExtractedFunctionsModule; | 
|  | if (!RequestedSymbols.empty()) { | 
|  | std::string Suffix; | 
|  | std::set<const GlobalValue *> FunctionsToClone; | 
|  | for (auto &Name : RequestedSymbols) { | 
|  | auto I = SymbolToDefinition.find(Name); | 
|  | assert(I != SymbolToDefinition.end() && I->second != nullptr && | 
|  | "Should have a non-null definition"); | 
|  | FunctionsToClone.insert(I->second); | 
|  | Suffix += "."; | 
|  | Suffix += *Name; | 
|  | } | 
|  |  | 
|  | std::lock_guard<std::mutex> Lock(SourceModuleMutex); | 
|  | ExtractedFunctionsModule = | 
|  | extractAndClone(*M, Parent.GetAvailableContext(), Suffix, | 
|  | [&](const GlobalValue *GV) -> bool { | 
|  | return FunctionsToClone.count(GV); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Build a new ExtractingIRMaterializationUnit to delegate the unrequested | 
|  | // symbols to. | 
|  | SymbolFlagsMap DelegatedSymbolFlags; | 
|  | IRMaterializationUnit::SymbolNameToDefinitionMap | 
|  | DelegatedSymbolToDefinition; | 
|  | for (auto &KV : SymbolToDefinition) { | 
|  | if (RequestedSymbols.count(KV.first)) | 
|  | continue; | 
|  | DelegatedSymbolFlags[KV.first] = | 
|  | JITSymbolFlags::fromGlobalValue(*KV.second); | 
|  | DelegatedSymbolToDefinition[KV.first] = KV.second; | 
|  | } | 
|  |  | 
|  | if (!DelegatedSymbolFlags.empty()) { | 
|  | assert(DelegatedSymbolFlags.size() == | 
|  | DelegatedSymbolToDefinition.size() && | 
|  | "SymbolFlags and SymbolToDefinition should have the same number " | 
|  | "of entries"); | 
|  | R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>( | 
|  | std::move(M), std::move(DelegatedSymbolFlags), | 
|  | std::move(DelegatedSymbolToDefinition), Parent)); | 
|  | } | 
|  |  | 
|  | if (ExtractedFunctionsModule) | 
|  | Parent.emitExtractedFunctionsModule(std::move(R), | 
|  | std::move(ExtractedFunctionsModule)); | 
|  | } | 
|  |  | 
|  | void discard(const VSO &V, SymbolStringPtr Name) override { | 
|  | // All original symbols were materialized by the CODLayer and should be | 
|  | // final. The function bodies provided by M should never be overridden. | 
|  | llvm_unreachable("Discard should never be called on an " | 
|  | "ExtractingIRMaterializationUnit"); | 
|  | } | 
|  |  | 
|  | mutable std::mutex SourceModuleMutex; | 
|  | CompileOnDemandLayer2 &Parent; | 
|  | }; | 
|  |  | 
|  | CompileOnDemandLayer2::CompileOnDemandLayer2( | 
|  | ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr, | 
|  | IndirectStubsManagerBuilder BuildIndirectStubsManager, | 
|  | GetAvailableContextFunction GetAvailableContext) | 
|  | : IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr), | 
|  | BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)), | 
|  | GetAvailableContext(std::move(GetAvailableContext)) {} | 
|  |  | 
|  | Error CompileOnDemandLayer2::add(VSO &V, VModuleKey K, | 
|  | std::unique_ptr<Module> M) { | 
|  | return IRLayer::add(V, K, std::move(M)); | 
|  | } | 
|  |  | 
|  | void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K, | 
|  | std::unique_ptr<Module> M) { | 
|  | auto &ES = getExecutionSession(); | 
|  | assert(M && "M should not be null"); | 
|  |  | 
|  | for (auto &GV : M->global_values()) | 
|  | if (GV.hasWeakLinkage()) | 
|  | GV.setLinkage(GlobalValue::ExternalLinkage); | 
|  |  | 
|  | MangleAndInterner Mangle(ES, M->getDataLayout()); | 
|  |  | 
|  | extractAliases(R, *M, Mangle); | 
|  |  | 
|  | auto GlobalsModule = extractGlobals(*M, GetAvailableContext()); | 
|  |  | 
|  | // Delete the bodies of any available externally functions, rename the | 
|  | // rest, and build the compile callbacks. | 
|  | std::map<SymbolStringPtr, std::pair<JITTargetAddress, JITSymbolFlags>> | 
|  | StubCallbacksAndLinkages; | 
|  | auto &TargetVSO = R.getTargetVSO(); | 
|  |  | 
|  | for (auto &F : M->functions()) { | 
|  | if (F.isDeclaration()) | 
|  | continue; | 
|  |  | 
|  | if (F.hasAvailableExternallyLinkage()) { | 
|  | F.deleteBody(); | 
|  | F.setPersonalityFn(nullptr); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | assert(F.hasName() && "Function should have a name"); | 
|  | std::string StubUnmangledName = F.getName(); | 
|  | F.setName(F.getName() + "$body"); | 
|  | auto StubDecl = cloneFunctionDecl(*M, F); | 
|  | StubDecl->setName(StubUnmangledName); | 
|  | StubDecl->setPersonalityFn(nullptr); | 
|  | StubDecl->setLinkage(GlobalValue::ExternalLinkage); | 
|  | F.replaceAllUsesWith(StubDecl); | 
|  |  | 
|  | auto StubName = Mangle(StubUnmangledName); | 
|  | auto BodyName = Mangle(F.getName()); | 
|  | if (auto CallbackAddr = CCMgr.getCompileCallback( | 
|  | [BodyName, &TargetVSO, &ES]() -> JITTargetAddress { | 
|  | if (auto Sym = lookup({&TargetVSO}, BodyName)) | 
|  | return Sym->getAddress(); | 
|  | else { | 
|  | ES.reportError(Sym.takeError()); | 
|  | return 0; | 
|  | } | 
|  | })) { | 
|  | auto Flags = JITSymbolFlags::fromGlobalValue(F); | 
|  | Flags &= ~JITSymbolFlags::Weak; | 
|  | StubCallbacksAndLinkages[std::move(StubName)] = | 
|  | std::make_pair(*CallbackAddr, Flags); | 
|  | } else { | 
|  | ES.reportError(CallbackAddr.takeError()); | 
|  | R.failMaterialization(); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Build the stub inits map. | 
|  | IndirectStubsManager::StubInitsMap StubInits; | 
|  | for (auto &KV : StubCallbacksAndLinkages) | 
|  | StubInits[*KV.first] = KV.second; | 
|  |  | 
|  | // Build the function-body-extracting materialization unit. | 
|  | if (auto Err = R.getTargetVSO().define( | 
|  | llvm::make_unique<ExtractingIRMaterializationUnit>(ES, *this, | 
|  | std::move(M)))) { | 
|  | ES.reportError(std::move(Err)); | 
|  | R.failMaterialization(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Build the stubs. | 
|  | // FIXME: Remove function bodies materialization unit if stub creation fails. | 
|  | auto &StubsMgr = getStubsManager(TargetVSO); | 
|  | if (auto Err = StubsMgr.createStubs(StubInits)) { | 
|  | ES.reportError(std::move(Err)); | 
|  | R.failMaterialization(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Resolve and finalize stubs. | 
|  | SymbolMap ResolvedStubs; | 
|  | for (auto &KV : StubCallbacksAndLinkages) { | 
|  | if (auto Sym = StubsMgr.findStub(*KV.first, false)) | 
|  | ResolvedStubs[KV.first] = Sym; | 
|  | else | 
|  | llvm_unreachable("Stub went missing"); | 
|  | } | 
|  |  | 
|  | R.resolve(ResolvedStubs); | 
|  |  | 
|  | BaseLayer.emit(std::move(R), std::move(K), std::move(GlobalsModule)); | 
|  | } | 
|  |  | 
|  | IndirectStubsManager &CompileOnDemandLayer2::getStubsManager(const VSO &V) { | 
|  | std::lock_guard<std::mutex> Lock(CODLayerMutex); | 
|  | StubManagersMap::iterator I = StubsMgrs.find(&V); | 
|  | if (I == StubsMgrs.end()) | 
|  | I = StubsMgrs.insert(std::make_pair(&V, BuildIndirectStubsManager())).first; | 
|  | return *I->second; | 
|  | } | 
|  |  | 
|  | void CompileOnDemandLayer2::emitExtractedFunctionsModule( | 
|  | MaterializationResponsibility R, std::unique_ptr<Module> M) { | 
|  | auto K = getExecutionSession().allocateVModule(); | 
|  | BaseLayer.emit(std::move(R), std::move(K), std::move(M)); | 
|  | } | 
|  |  | 
|  | } // end namespace orc | 
|  | } // end namespace llvm |