Index: include/llvm/Linker/Linker.h =================================================================== --- include/llvm/Linker/Linker.h +++ include/llvm/Linker/Linker.h @@ -67,8 +67,8 @@ DenseMap *ValIDToTempMDMap); }; -/// Create a new module with exported local functions renamed and promoted -/// for ThinLTO. +/// Perform in-place global value handling on the given Module for +/// exported local functions renamed and promoted for ThinLTO. std::unique_ptr renameModuleForThinLTO(std::unique_ptr M, const FunctionInfoIndex *Index); Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -65,9 +65,6 @@ return Flags & Linker::InternalizeLinkedSymbols; } - /// Check if we should promote the given local value to global scope. - bool doPromoteLocalToGlobal(const GlobalValue *SGV); - bool shouldLinkFromSource(bool &LinkFromSrc, const GlobalValue &Dest, const GlobalValue &Src); @@ -97,11 +94,11 @@ Module &DstM = Mover.getModule(); // If the source has no name it can't link. If it has local linkage, // there is no name match-up going on. - if (!SrcGV->hasName() || GlobalValue::isLocalLinkage(getLinkage(SrcGV))) + if (!SrcGV->hasName() || GlobalValue::isLocalLinkage(SrcGV->getLinkage())) return nullptr; // Otherwise see if we have a match in the destination module's symtab. - GlobalValue *DGV = DstM.getNamedValue(getName(SrcGV)); + GlobalValue *DGV = DstM.getNamedValue(SrcGV->getName()); if (!DGV) return nullptr; @@ -116,6 +113,63 @@ bool linkIfNeeded(GlobalValue &GV); + /// Helper method to check if we are importing from the current source + /// module. + bool isPerformingImport() const { return FunctionsToImport != nullptr; } + + /// If we are importing from the source module, checks if we should + /// import SGV as a definition, otherwise import as a declaration. + bool doImportAsDefinition(const GlobalValue *SGV); + +public: + ModuleLinker(IRMover &Mover, Module &SrcM, unsigned Flags, + const FunctionInfoIndex *Index = nullptr, + DenseSet *FunctionsToImport = nullptr, + DenseMap *ValIDToTempMDMap = nullptr) + : Mover(Mover), SrcM(SrcM), Flags(Flags), ImportIndex(Index), + FunctionsToImport(FunctionsToImport), ValIDToTempMDMap(ValIDToTempMDMap) { + assert((ImportIndex || !FunctionsToImport) && + "Expect a FunctionInfoIndex when importing"); + // If we have a FunctionInfoIndex but no function to import, + // then this is the primary module being compiled in a ThinLTO + // backend compilation, and we need to see if it has functions that + // may be exported to another backend compilation. + if (ImportIndex && !FunctionsToImport) + HasExportedFunctions = ImportIndex->hasExportedFunctions(SrcM); + assert((ValIDToTempMDMap || !FunctionsToImport) && + "Function importing must provide a ValIDToTempMDMap"); + } + + bool run(); +}; + +/// Class to handle necessary GlobalValue changes required by ThinLTO including +/// linkage changes and any necessary renaming. +class ThinLTOGlobalProcessing { + /// The Module which we are exporting or importing functions from. + Module &M; + + /// Function index passed in for function importing/exporting handling. + const FunctionInfoIndex *ImportIndex; + + /// Functions to import from this module, all other functions will be + /// imported as declarations instead of definitions. + DenseSet *FunctionsToImport; + + /// Set to true if the given FunctionInfoIndex contains any functions + /// from this source module, in which case we must conservatively assume + /// that any of its functions may be imported into another module + /// as part of a different backend compilation process. + bool HasExportedFunctions = false; + + /// Populated during ThinLTO global processing with locals promoted + /// to global scope in an exporting module, which now need to be linked + /// in if calling from the ModuleLinker. + SetVector NewExportedValues; + + /// Check if we should promote the given local value to global scope. + bool doPromoteLocalToGlobal(const GlobalValue *SGV); + /// Helper methods to check if we are importing from or potentially /// exporting from the current source module. bool isPerformingImport() const { return FunctionsToImport != nullptr; } @@ -130,6 +184,11 @@ /// a local that is being promoted to global scope. std::string getName(const GlobalValue *SGV); + /// Get the new linkage for SGV that should be used in the linked destination + /// module. Specifically, for ThinLTO importing or exporting it may need + /// to be adjusted. + GlobalValue::LinkageTypes getLinkage(const GlobalValue *SGV); + /// Process globals so that they can be used in ThinLTO. This includes /// promoting local variables so that they can be reference externally by /// thin lto imported globals and converting strong external globals to @@ -137,38 +196,31 @@ void processGlobalsForThinLTO(); void processGlobalForThinLTO(GlobalValue &GV); - /// Get the new linkage for SGV that should be used in the linked destination - /// module. Specifically, for ThinLTO importing or exporting it may need - /// to be adjusted. - GlobalValue::LinkageTypes getLinkage(const GlobalValue *SGV); - public: - ModuleLinker(IRMover &Mover, Module &SrcM, unsigned Flags, - const FunctionInfoIndex *Index = nullptr, - DenseSet *FunctionsToImport = nullptr, - DenseMap *ValIDToTempMDMap = nullptr) - : Mover(Mover), SrcM(SrcM), Flags(Flags), ImportIndex(Index), - FunctionsToImport(FunctionsToImport), - ValIDToTempMDMap(ValIDToTempMDMap) { - assert((ImportIndex || !FunctionsToImport) && - "Expect a FunctionInfoIndex when importing"); + ThinLTOGlobalProcessing( + Module &M, const FunctionInfoIndex *Index, + DenseSet *FunctionsToImport = nullptr) + : M(M), ImportIndex(Index), FunctionsToImport(FunctionsToImport) { // If we have a FunctionInfoIndex but no function to import, // then this is the primary module being compiled in a ThinLTO // backend compilation, and we need to see if it has functions that // may be exported to another backend compilation. - if (ImportIndex && !FunctionsToImport) - HasExportedFunctions = ImportIndex->hasExportedFunctions(SrcM); - assert((ValIDToTempMDMap || !FunctionsToImport) && - "Function importing must provide a ValIDToTempMDMap"); + if (!FunctionsToImport) + HasExportedFunctions = ImportIndex->hasExportedFunctions(M); } bool run(); + + /// Access the promoted globals that are now exported and need to be linked. + SetVector &getNewExportedValues() { return NewExportedValues; } }; } -bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) { - if (!isPerformingImport()) - return false; +/// Checks if we should import SGV as a definition, otherwise import as a +/// declaration. +static bool +doImportAsDefinitionImpl(const GlobalValue *SGV, + DenseSet *FunctionsToImport) { auto *GA = dyn_cast(SGV); if (GA) { if (GA->hasWeakAnyLinkage()) @@ -176,7 +228,7 @@ const GlobalObject *GO = GA->getBaseObject(); if (!GO->hasLinkOnceODRLinkage()) return false; - return doImportAsDefinition(GO); + return doImportAsDefinitionImpl(GO, FunctionsToImport); } // Always import GlobalVariable definitions, except for the special // case of WeakAny which are imported as ExternalWeak declarations @@ -196,7 +248,19 @@ return false; } -bool ModuleLinker::doPromoteLocalToGlobal(const GlobalValue *SGV) { +bool ThinLTOGlobalProcessing::doImportAsDefinition(const GlobalValue *SGV) { + if (!isPerformingImport()) + return false; + return doImportAsDefinitionImpl(SGV, FunctionsToImport); +} + +bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) { + if (!isPerformingImport()) + return false; + return doImportAsDefinitionImpl(SGV, FunctionsToImport); +} + +bool ThinLTOGlobalProcessing::doPromoteLocalToGlobal(const GlobalValue *SGV) { assert(SGV->hasLocalLinkage()); // Both the imported references and the original local variable must // be promoted. @@ -220,7 +284,7 @@ return true; } -std::string ModuleLinker::getName(const GlobalValue *SGV) { +std::string ThinLTOGlobalProcessing::getName(const GlobalValue *SGV) { // For locals that must be promoted to global scope, ensure that // the promoted name uniquely identifies the copy in the original module, // using the ID assigned during combined index creation. When importing, @@ -234,7 +298,8 @@ return SGV->getName(); } -GlobalValue::LinkageTypes ModuleLinker::getLinkage(const GlobalValue *SGV) { +GlobalValue::LinkageTypes +ThinLTOGlobalProcessing::getLinkage(const GlobalValue *SGV) { // Any local variable that is referenced by an exported function needs // to be promoted to global scope. Since we don't currently know which // functions reference which local variables/functions, we must treat @@ -298,8 +363,7 @@ // since it would cause global constructors/destructors to be // executed multiple times. This should have already been handled // by linkIfNeeded, and we will assert in shouldLinkFromSource - // if we try to import, so we simply return AppendingLinkage here - // as this helper is called more widely in getLinkedToGlobal. + // if we try to import, so we simply return AppendingLinkage. return GlobalValue::AppendingLinkage; case GlobalValue::InternalLinkage: @@ -652,7 +716,7 @@ } } -void ModuleLinker::processGlobalForThinLTO(GlobalValue &GV) { +void ThinLTOGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) { if (GV.hasLocalLinkage() && (doPromoteLocalToGlobal(&GV) || isPerformingImport())) { GV.setName(getName(&GV)); @@ -660,21 +724,26 @@ if (!GV.hasLocalLinkage()) GV.setVisibility(GlobalValue::HiddenVisibility); if (isModuleExporting()) - ValuesToLink.insert(&GV); + NewExportedValues.insert(&GV); return; } GV.setLinkage(getLinkage(&GV)); } -void ModuleLinker::processGlobalsForThinLTO() { - for (GlobalVariable &GV : SrcM.globals()) +void ThinLTOGlobalProcessing::processGlobalsForThinLTO() { + for (GlobalVariable &GV : M.globals()) processGlobalForThinLTO(GV); - for (Function &SF : SrcM) + for (Function &SF : M) processGlobalForThinLTO(SF); - for (GlobalAlias &GA : SrcM.aliases()) + for (GlobalAlias &GA : M.aliases()) processGlobalForThinLTO(GA); } +bool ThinLTOGlobalProcessing::run() { + processGlobalsForThinLTO(); + return false; +} + bool ModuleLinker::run() { for (const auto &SMEC : SrcM.getComdatSymbolTable()) { const Comdat &C = SMEC.getValue(); @@ -713,7 +782,14 @@ if (linkIfNeeded(GA)) return true; - processGlobalsForThinLTO(); + if (ImportIndex) { + ThinLTOGlobalProcessing ThinLTOProcessing(SrcM, ImportIndex, + FunctionsToImport); + if (ThinLTOProcessing.run()) + return true; + for (auto *GV : ThinLTOProcessing.getNewExportedValues()) + ValuesToLink.insert(GV); + } for (unsigned I = 0; I < ValuesToLink.size(); ++I) { GlobalValue *GV = ValuesToLink[I]; @@ -789,12 +865,10 @@ std::unique_ptr llvm::renameModuleForThinLTO(std::unique_ptr M, const FunctionInfoIndex *Index) { - std::unique_ptr RenamedModule( - new llvm::Module(M->getModuleIdentifier(), M->getContext())); - Linker L(*RenamedModule.get()); - if (L.linkInModule(std::move(M), llvm::Linker::Flags::None, Index)) + ThinLTOGlobalProcessing ThinLTOProcessing(*M, Index); + if (ThinLTOProcessing.run()) return nullptr; - return RenamedModule; + return M; } //===----------------------------------------------------------------------===//