diff --git a/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 8f4e844032c0..242d2420162f 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -47,9 +47,8 @@ private: class LambdaMaterializer final : public ValueMaterializer { public: LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} - Value* materializeValueFor(Value *V) final { - return M(V); - } + Value *materializeDeclFor(Value *V) final { return M(V); } + private: MaterializerFtor M; }; diff --git a/llvm/include/llvm/Transforms/Utils/ValueMapper.h b/llvm/include/llvm/Transforms/Utils/ValueMapper.h index 17ce4f4ab73d..5687bd21e998 100644 --- a/llvm/include/llvm/Transforms/Utils/ValueMapper.h +++ b/llvm/include/llvm/Transforms/Utils/ValueMapper.h @@ -46,10 +46,15 @@ namespace llvm { ValueMaterializer &operator=(const ValueMaterializer&) = default; public: - /// materializeValueFor - The client should implement this method if they - /// want to generate a mapped Value on demand. For example, if linking - /// lazily. - virtual Value *materializeValueFor(Value *V) = 0; + /// The client should implement this method if they want to generate a + /// mapped Value on demand. For example, if linking lazily. + virtual Value *materializeDeclFor(Value *V) = 0; + + /// If the data being mapped is recursive, the above function can map + /// just the declaration and this is called to compute the initializer. + /// It is called after the mapping is recorded, so it doesn't need to worry + /// about recursion. + virtual void materializeInitFor(GlobalValue *New, GlobalValue *Old); }; /// RemapFlags - These are flags that the value mapping APIs allow. diff --git a/llvm/lib/Linker/LinkModules.cpp b/llvm/lib/Linker/LinkModules.cpp index bd445dd367f4..afb39a1ae6df 100644 --- a/llvm/lib/Linker/LinkModules.cpp +++ b/llvm/lib/Linker/LinkModules.cpp @@ -366,19 +366,13 @@ class ModuleLinker; /// speeds up linking for modules with many/ lazily linked functions of which /// few get used. class ValueMaterializerTy final : public ValueMaterializer { - TypeMapTy &TypeMap; - Module *DstM; - std::vector &LazilyLinkGlobalValues; ModuleLinker *ModLinker; public: - ValueMaterializerTy(TypeMapTy &TypeMap, Module *DstM, - std::vector &LazilyLinkGlobalValues, - ModuleLinker *ModLinker) - : ValueMaterializer(), TypeMap(TypeMap), DstM(DstM), - LazilyLinkGlobalValues(LazilyLinkGlobalValues), ModLinker(ModLinker) {} + ValueMaterializerTy(ModuleLinker *ModLinker) : ModLinker(ModLinker) {} - Value *materializeValueFor(Value *V) override; + Value *materializeDeclFor(Value *V) override; + void materializeInitFor(GlobalValue *New, GlobalValue *Old) override; }; class LinkDiagnosticInfo : public DiagnosticInfo { @@ -418,9 +412,6 @@ class ModuleLinker { // Set of items not to link in from source. SmallPtrSet DoNotLinkFromSource; - // Vector of GlobalValues to lazily link in. - std::vector LazilyLinkGlobalValues; - DiagnosticHandlerFunction DiagnosticHandler; /// For symbol clashes, prefer those from Src. @@ -450,8 +441,7 @@ public: DiagnosticHandlerFunction DiagnosticHandler, unsigned Flags, const FunctionInfoIndex *Index = nullptr, Function *FuncToImport = nullptr) - : DstM(dstM), SrcM(srcM), TypeMap(Set), - ValMaterializer(TypeMap, DstM, LazilyLinkGlobalValues, this), + : DstM(dstM), SrcM(srcM), TypeMap(Set), ValMaterializer(this), DiagnosticHandler(DiagnosticHandler), Flags(Flags), ImportIndex(Index), ImportFunction(FuncToImport), HasExportedFunctions(false), DoneLinkingBodies(false) { @@ -466,7 +456,10 @@ public: } bool run(); + Value *materializeDeclFor(Value *V); + void materializeInitFor(GlobalValue *New, GlobalValue *Old); +private: bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; } bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; } bool shouldInternalizeLinkedSymbols() { @@ -484,7 +477,6 @@ public: /// Check if all global value body linking is complete. bool doneLinkingBodies() { return DoneLinkingBodies; } -private: bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest, const GlobalValue &Src); @@ -901,7 +893,11 @@ GlobalValue *ModuleLinker::copyGlobalValueProto(TypeMapTy &TypeMap, return NewGV; } -Value *ValueMaterializerTy::materializeValueFor(Value *V) { +Value *ValueMaterializerTy::materializeDeclFor(Value *V) { + return ModLinker->materializeDeclFor(V); +} + +Value *ModuleLinker::materializeDeclFor(Value *V) { auto *SGV = dyn_cast(V); if (!SGV) return nullptr; @@ -909,10 +905,10 @@ Value *ValueMaterializerTy::materializeValueFor(Value *V) { // If we are done linking global value bodies (i.e. we are performing // metadata linking), don't link in the global value due to this // reference, simply map it to null. - if (ModLinker->doneLinkingBodies()) + if (doneLinkingBodies()) return nullptr; - GlobalValue *DGV = ModLinker->copyGlobalValueProto(TypeMap, SGV); + GlobalValue *DGV = copyGlobalValueProto(TypeMap, SGV); if (Comdat *SC = SGV->getComdat()) { if (auto *DGO = dyn_cast(DGV)) { @@ -921,10 +917,27 @@ Value *ValueMaterializerTy::materializeValueFor(Value *V) { } } - LazilyLinkGlobalValues.push_back(SGV); return DGV; } +void ValueMaterializerTy::materializeInitFor(GlobalValue *New, + GlobalValue *Old) { + return ModLinker->materializeInitFor(New, Old); +} + +void ModuleLinker::materializeInitFor(GlobalValue *New, GlobalValue *Old) { + if (isPerformingImport() && !doImportAsDefinition(Old)) + return; + + // Skip declarations that ValueMaterializer may have created in + // case we link in only some of SrcM. + if (shouldLinkOnlyNeeded() && Old->isDeclaration()) + return; + + assert(!Old->isDeclaration() && "users should not pass down decls"); + linkGlobalValueBody(*Old); +} + bool ModuleLinker::getComdatLeader(Module *M, StringRef ComdatName, const GlobalVariable *&GVar) { const GlobalValue *GVal = M->getNamedValue(ComdatName); @@ -1602,10 +1615,10 @@ bool ModuleLinker::linkGlobalValueBody(GlobalValue &Src) { // are linked in. Otherwise, linkonce and other lazy linked GVs will // not be materialized if they aren't referenced. for (auto *SGV : ComdatMembers[SC]) { - if (ValueMap[SGV]) + auto *DGV = cast_or_null(ValueMap[SGV]); + if (DGV && !DGV->isDeclaration()) continue; - Value *NewV = ValMaterializer.materializeValueFor(SGV); - ValueMap[SGV] = NewV; + MapValue(SGV, ValueMap, RF_MoveDistinctMDs, &TypeMap, &ValMaterializer); } } if (shouldInternalizeLinkedSymbols()) @@ -1939,23 +1952,6 @@ bool ModuleLinker::run() { linkGlobalValueBody(Src); } - // Process vector of lazily linked in functions. - while (!LazilyLinkGlobalValues.empty()) { - GlobalValue *SGV = LazilyLinkGlobalValues.back(); - LazilyLinkGlobalValues.pop_back(); - if (isPerformingImport() && !doImportAsDefinition(SGV)) - continue; - - // Skip declarations that ValueMaterializer may have created in - // case we link in only some of SrcM. - if (shouldLinkOnlyNeeded() && SGV->isDeclaration()) - continue; - - assert(!SGV->isDeclaration() && "users should not pass down decls"); - if (linkGlobalValueBody(*SGV)) - return true; - } - // Note that we are done linking global value bodies. This prevents // metadata linking from creating new references. DoneLinkingBodies = true; diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp index c8d13385b1d4..0a63c1d5153c 100644 --- a/llvm/lib/Transforms/Utils/ValueMapper.cpp +++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp @@ -25,6 +25,8 @@ using namespace llvm; // Out of line method to get vtable etc for class. void ValueMapTypeRemapper::anchor() {} void ValueMaterializer::anchor() {} +void ValueMaterializer::materializeInitFor(GlobalValue *New, GlobalValue *Old) { +} Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM, RemapFlags Flags, ValueMapTypeRemapper *TypeMapper, @@ -36,8 +38,14 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM, RemapFlags Flags, // If we have a materializer and it can materialize a value, use that. if (Materializer) { - if (Value *NewV = Materializer->materializeValueFor(const_cast(V))) - return VM[V] = NewV; + if (Value *NewV = + Materializer->materializeDeclFor(const_cast(V))) { + VM[V] = NewV; + if (auto *GV = dyn_cast(V)) + Materializer->materializeInitFor(cast(NewV), + const_cast(GV)); + return NewV; + } } // Global values do not need to be seeded into the VM if they diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index e563376ca9ab..b8318be27ce0 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -554,11 +554,11 @@ class LocalValueMaterializer final : public ValueMaterializer { public: LocalValueMaterializer(DenseSet &Dropped) : Dropped(Dropped) {} - Value *materializeValueFor(Value *V) override; + Value *materializeDeclFor(Value *V) override; }; } -Value *LocalValueMaterializer::materializeValueFor(Value *V) { +Value *LocalValueMaterializer::materializeDeclFor(Value *V) { auto *GO = dyn_cast(V); if (!GO) return nullptr;