From 655b4d9f2028a6ae30f7fa843418914a1d70cd77 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Wed, 25 May 2016 14:03:11 +0000 Subject: [PATCH] [ThinLTO] Refactor ODR resolution and internalization (NFC) Move the now index-based ODR resolution and internalization routines out of ThinLTOCodeGenerator.cpp and into either LTO.cpp (index-based analysis) or FunctionImport.cpp (index-driven optimizations). This is to enable usage by other linkers. llvm-svn: 270698 --- include/llvm/LTO/LTO.h | 24 +++ include/llvm/Transforms/IPO/FunctionImport.h | 10 ++ lib/LTO/LTO.cpp | 100 +++++++++++ lib/LTO/ThinLTOCodeGenerator.cpp | 174 ------------------- lib/Transforms/IPO/FunctionImport.cpp | 77 ++++++++ 5 files changed, 211 insertions(+), 174 deletions(-) diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index 34c20f2074d..6048502705e 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -17,6 +17,7 @@ #define LLVM_LTO_LTO_H #include "llvm/ADT/StringMap.h" +#include "llvm/IR/ModuleSummaryIndex.h" namespace llvm { @@ -47,6 +48,29 @@ public: return loadModuleFromBuffer(ModuleMap[Identifier], Context, /*Lazy*/ true); } }; + + +/// Resolve Weak and LinkOnce values in the \p Index. Linkage changes recorded +/// in the index and the ThinLTO backends must apply the changes to the Module +/// via thinLTOResolveWeakForLinkerModule. +/// +/// This is done for correctness (if value exported, ensure we always +/// emit a copy), and compile-time optimization (allow drop of duplicates). +void thinLTOResolveWeakForLinkerInIndex( + ModuleSummaryIndex &Index, + std::function + isPrevailing, + std::function isExported, + std::function + recordNewLinkage); + +/// Update the linkages in the given \p Index to mark exported values +/// as external and non-exported values as internal. The ThinLTO backends +/// must apply the changes to the Module via thinLTOInternalizeModule. +void thinLTOInternalizeAndPromoteInIndex( + ModuleSummaryIndex &Index, + std::function isExported); + } #endif diff --git a/include/llvm/Transforms/IPO/FunctionImport.h b/include/llvm/Transforms/IPO/FunctionImport.h index 276185c9082..91273e13416 100644 --- a/include/llvm/Transforms/IPO/FunctionImport.h +++ b/include/llvm/Transforms/IPO/FunctionImport.h @@ -107,6 +107,16 @@ void gatherImportedSummariesForModule( std::error_code EmitImportsFiles(StringRef ModulePath, StringRef OutputFilename, const StringMap &ImportLists); + +/// Resolve WeakForLinker values in \p TheModule based on the information +/// recorded in the summaries during global summary-based analysis. +void thinLTOResolveWeakForLinkerModule(Module &TheModule, + const GVSummaryMapTy &DefinedGlobals); + +/// Internalize \p TheModule based on the information recorded in the summaries +/// during global summary-based analysis. +void thinLTOInternalizeModule(Module &TheModule, + const GVSummaryMapTy &DefinedGlobals); } #endif // LLVM_FUNCTIONIMPORT_H diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 5f89e5c95a7..fa875c29e29 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -39,4 +39,104 @@ std::unique_ptr loadModuleFromBuffer(const MemoryBufferRef &Buffer, } return std::move(ModuleOrErr.get()); } + +static void thinLTOResolveWeakForLinkerGUID( + GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, + DenseSet &GlobalInvolvedWithAlias, + std::function + isPrevailing, + std::function isExported, + std::function + recordNewLinkage) { + auto HasMultipleCopies = GVSummaryList.size() > 1; + + for (auto &S : GVSummaryList) { + if (GlobalInvolvedWithAlias.count(S.get())) + continue; + GlobalValue::LinkageTypes OriginalLinkage = S->linkage(); + if (!GlobalValue::isWeakForLinker(OriginalLinkage)) + continue; + // We need to emit only one of these, the first module will keep it, + // but turned into a weak, while the others will drop it when possible. + if (!HasMultipleCopies) { + // Exported Linkonce needs to be promoted to not be discarded. + // FIXME: This should handle LinkOnceAny as well, but that should be a + // follow-on to the NFC restructuring: + // if (GlobalValue::isLinkOnceLinkage(OriginalLinkage) && + // isExported(S->modulePath(), GUID)) + // S->setLinkage(GlobalValue::getWeakLinkage( + // GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); + if (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) && + isExported(S->modulePath(), GUID)) + S->setLinkage(GlobalValue::WeakODRLinkage); + } else if (isPrevailing(GUID, S.get())) { + // FIXME: This should handle LinkOnceAny as well, but that should be a + // follow-on to the NFC restructuring: + // if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) + // S->setLinkage(GlobalValue::getWeakLinkage( + // GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); + if (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage)) + S->setLinkage(GlobalValue::WeakODRLinkage); + } + // Alias can't be turned into available_externally. + else if (!isa(S.get()) && + (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) || + GlobalValue::isWeakODRLinkage(OriginalLinkage))) + S->setLinkage(GlobalValue::AvailableExternallyLinkage); + if (S->linkage() != OriginalLinkage) + recordNewLinkage(S->modulePath(), GUID, S->linkage()); + } +} + +// Resolve Weak and LinkOnce values in the \p Index. +// +// We'd like to drop these functions if they are no longer referenced in the +// current module. However there is a chance that another module is still +// referencing them because of the import. We make sure we always emit at least +// one copy. +void thinLTOResolveWeakForLinkerInIndex( + ModuleSummaryIndex &Index, + std::function + isPrevailing, + std::function isExported, + std::function + recordNewLinkage) { + if (Index.modulePaths().size() == 1) + // Nothing to do if we don't have multiple modules + return; + + // We won't optimize the globals that are referenced by an alias for now + // Ideally we should turn the alias into a global and duplicate the definition + // when needed. + DenseSet GlobalInvolvedWithAlias; + for (auto &I : Index) + for (auto &S : I.second) + if (auto AS = dyn_cast(S.get())) + GlobalInvolvedWithAlias.insert(&AS->getAliasee()); + + for (auto &I : Index) + thinLTOResolveWeakForLinkerGUID(I.second, I.first, GlobalInvolvedWithAlias, + isPrevailing, isExported, recordNewLinkage); +} + +static void thinLTOInternalizeAndPromoteGUID( + GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, + std::function isExported) { + for (auto &S : GVSummaryList) { + if (isExported(S->modulePath(), GUID)) { + if (GlobalValue::isLocalLinkage(S->linkage())) + S->setLinkage(GlobalValue::ExternalLinkage); + } else if (!GlobalValue::isLocalLinkage(S->linkage())) + S->setLinkage(GlobalValue::InternalLinkage); + } +} + +// Update the linkages in the given \p Index to mark exported values +// as external and non-exported values as internal. +void thinLTOInternalizeAndPromoteInIndex( + ModuleSummaryIndex &Index, + std::function isExported) { + for (auto &I : Index) + thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); +} } diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index 5c74d72c25a..8baab57a796 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -128,112 +128,6 @@ static void computePrevailingCopies( } } -static void thinLTOResolveWeakForLinkerGUID( - GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, - DenseSet &GlobalInvolvedWithAlias, - std::function - isPrevailing, - std::function isExported, - std::function - recordNewLinkage) { - auto HasMultipleCopies = GVSummaryList.size() > 1; - - for (auto &S : GVSummaryList) { - if (GlobalInvolvedWithAlias.count(S.get())) - continue; - GlobalValue::LinkageTypes OriginalLinkage = S->linkage(); - if (!GlobalValue::isWeakForLinker(OriginalLinkage)) - continue; - // We need to emit only one of these, the first module will keep it, - // but turned into a weak, while the others will drop it when possible. - if (!HasMultipleCopies) { - // Exported Linkonce needs to be promoted to not be discarded. - // FIXME: This should handle LinkOnceAny as well, but that should be a - // follow-on to the NFC restructuring: - // if (GlobalValue::isLinkOnceLinkage(OriginalLinkage) && - // isExported(S->modulePath(), GUID)) - // S->setLinkage(GlobalValue::getWeakLinkage( - // GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); - if (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) && - isExported(S->modulePath(), GUID)) - S->setLinkage(GlobalValue::WeakODRLinkage); - } else if (isPrevailing(GUID, S.get())) { - // FIXME: This should handle LinkOnceAny as well, but that should be a - // follow-on to the NFC restructuring: - // if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) - // S->setLinkage(GlobalValue::getWeakLinkage( - // GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); - if (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage)) - S->setLinkage(GlobalValue::WeakODRLinkage); - } - // Alias can't be turned into available_externally. - else if (!isa(S.get()) && - (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) || - GlobalValue::isWeakODRLinkage(OriginalLinkage))) - S->setLinkage(GlobalValue::AvailableExternallyLinkage); - if (S->linkage() != OriginalLinkage) - recordNewLinkage(S->modulePath(), GUID, S->linkage()); - } -} - -// Resolve Weak and LinkOnce values in the \p Index. -// -// We'd like to drop these functions if they are no longer referenced in the -// current module. However there is a chance that another module is still -// referencing them because of the import. We make sure we always emit at least -// one copy. -void thinLTOResolveWeakForLinkerInIndex( - ModuleSummaryIndex &Index, - std::function - isPrevailing, - std::function isExported, - std::function - recordNewLinkage) { - if (Index.modulePaths().size() == 1) - // Nothing to do if we don't have multiple modules - return; - - // We won't optimize the globals that are referenced by an alias for now - // Ideally we should turn the alias into a global and duplicate the definition - // when needed. - DenseSet GlobalInvolvedWithAlias; - for (auto &I : Index) - for (auto &S : I.second) - if (auto AS = dyn_cast(S.get())) - GlobalInvolvedWithAlias.insert(&AS->getAliasee()); - - for (auto &I : Index) - thinLTOResolveWeakForLinkerGUID(I.second, I.first, GlobalInvolvedWithAlias, - isPrevailing, isExported, recordNewLinkage); -} - -/// Fixup WeakForLinker linkages in \p TheModule based on summary analysis. -void thinLTOResolveWeakForLinkerModule(Module &TheModule, - const GVSummaryMapTy &DefinedGlobals) { - auto updateLinkage = [&](GlobalValue &GV) { - if (!GlobalValue::isWeakForLinker(GV.getLinkage())) - return; - // See if the global summary analysis computed a new resolved linkage. - const auto &GS = DefinedGlobals.find(GV.getGUID()); - if (GS == DefinedGlobals.end()) - return; - auto NewLinkage = GS->second->linkage(); - if (NewLinkage == GV.getLinkage()) - return; - DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from " - << GV.getLinkage() << " to " << NewLinkage << "\n"); - GV.setLinkage(NewLinkage); - }; - - // Process functions and global now - for (auto &GV : TheModule) - updateLinkage(GV); - for (auto &GV : TheModule.globals()) - updateLinkage(GV); - for (auto &GV : TheModule.aliases()) - updateLinkage(GV); -} - static StringMap generateModuleMap(const std::vector &Modules) { StringMap ModuleMap; @@ -284,74 +178,6 @@ static void optimizeModule(Module &TheModule, TargetMachine &TM) { PM.run(TheModule); } -static void thinLTOInternalizeAndPromoteGUID( - GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, - std::function isExported) { - for (auto &S : GVSummaryList) { - if (isExported(S->modulePath(), GUID)) { - if (GlobalValue::isLocalLinkage(S->linkage())) - S->setLinkage(GlobalValue::ExternalLinkage); - } else if (!GlobalValue::isLocalLinkage(S->linkage())) - S->setLinkage(GlobalValue::InternalLinkage); - } -} - -// Update the linkages in the given \p Index to mark exported values -// as external and non-exported values as internal. -void thinLTOInternalizeAndPromoteInIndex( - ModuleSummaryIndex &Index, - std::function isExported) { - for (auto &I : Index) - thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); -} - -// Run internalization on \p TheModule based on symmary analysis. -void thinLTOInternalizeModule(Module &TheModule, - const GVSummaryMapTy &DefinedGlobals) { - // Parse inline ASM and collect the list of symbols that are not defined in - // the current module. - StringSet<> AsmUndefinedRefs; - object::IRObjectFile::CollectAsmUndefinedRefs( - Triple(TheModule.getTargetTriple()), TheModule.getModuleInlineAsm(), - [&AsmUndefinedRefs](StringRef Name, object::BasicSymbolRef::Flags Flags) { - if (Flags & object::BasicSymbolRef::SF_Undefined) - AsmUndefinedRefs.insert(Name); - }); - - // Declare a callback for the internalize pass that will ask for every - // candidate GlobalValue if it can be internalized or not. - auto MustPreserveGV = [&](const GlobalValue &GV) -> bool { - // Can't be internalized if referenced in inline asm. - if (AsmUndefinedRefs.count(GV.getName())) - return true; - - // Lookup the linkage recorded in the summaries during global analysis. - const auto &GS = DefinedGlobals.find(GV.getGUID()); - GlobalValue::LinkageTypes Linkage; - if (GS == DefinedGlobals.end()) { - // Must have been promoted (possibly conservatively). Find original - // name so that we can access the correct summary and see if it can - // be internalized again. - // FIXME: Eventually we should control promotion instead of promoting - // and internalizing again. - StringRef OrigName = - ModuleSummaryIndex::getOriginalNameBeforePromote(GV.getName()); - std::string OrigId = GlobalValue::getGlobalIdentifier( - OrigName, GlobalValue::InternalLinkage, - TheModule.getSourceFileName()); - const auto &GS = DefinedGlobals.find(GlobalValue::getGUID(OrigId)); - assert(GS != DefinedGlobals.end()); - Linkage = GS->second->linkage(); - } else - Linkage = GS->second->linkage(); - return !GlobalValue::isLocalLinkage(Linkage); - }; - - // FIXME: See if we can just internalize directly here via linkage changes - // based on the index, rather than invoking internalizeModule. - llvm::internalizeModule(TheModule, MustPreserveGV); -} - // Convert the PreservedSymbols map from "Name" based to "GUID" based. static DenseSet computeGUIDPreservedSymbols(const StringSet<> &PreservedSymbols, diff --git a/lib/Transforms/IPO/FunctionImport.cpp b/lib/Transforms/IPO/FunctionImport.cpp index a089f3c16e3..3e4cbf520fc 100644 --- a/lib/Transforms/IPO/FunctionImport.cpp +++ b/lib/Transforms/IPO/FunctionImport.cpp @@ -16,16 +16,19 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ModuleSummaryIndexObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #define DEBUG_TYPE "function-import" @@ -460,6 +463,80 @@ std::error_code llvm::EmitImportsFiles( return std::error_code(); } +/// Fixup WeakForLinker linkages in \p TheModule based on summary analysis. +void llvm::thinLTOResolveWeakForLinkerModule( + Module &TheModule, const GVSummaryMapTy &DefinedGlobals) { + auto updateLinkage = [&](GlobalValue &GV) { + if (!GlobalValue::isWeakForLinker(GV.getLinkage())) + return; + // See if the global summary analysis computed a new resolved linkage. + const auto &GS = DefinedGlobals.find(GV.getGUID()); + if (GS == DefinedGlobals.end()) + return; + auto NewLinkage = GS->second->linkage(); + if (NewLinkage == GV.getLinkage()) + return; + DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from " + << GV.getLinkage() << " to " << NewLinkage << "\n"); + GV.setLinkage(NewLinkage); + }; + + // Process functions and global now + for (auto &GV : TheModule) + updateLinkage(GV); + for (auto &GV : TheModule.globals()) + updateLinkage(GV); + for (auto &GV : TheModule.aliases()) + updateLinkage(GV); +} + +/// Run internalization on \p TheModule based on symmary analysis. +void llvm::thinLTOInternalizeModule(Module &TheModule, + const GVSummaryMapTy &DefinedGlobals) { + // Parse inline ASM and collect the list of symbols that are not defined in + // the current module. + StringSet<> AsmUndefinedRefs; + object::IRObjectFile::CollectAsmUndefinedRefs( + Triple(TheModule.getTargetTriple()), TheModule.getModuleInlineAsm(), + [&AsmUndefinedRefs](StringRef Name, object::BasicSymbolRef::Flags Flags) { + if (Flags & object::BasicSymbolRef::SF_Undefined) + AsmUndefinedRefs.insert(Name); + }); + + // Declare a callback for the internalize pass that will ask for every + // candidate GlobalValue if it can be internalized or not. + auto MustPreserveGV = [&](const GlobalValue &GV) -> bool { + // Can't be internalized if referenced in inline asm. + if (AsmUndefinedRefs.count(GV.getName())) + return true; + + // Lookup the linkage recorded in the summaries during global analysis. + const auto &GS = DefinedGlobals.find(GV.getGUID()); + GlobalValue::LinkageTypes Linkage; + if (GS == DefinedGlobals.end()) { + // Must have been promoted (possibly conservatively). Find original + // name so that we can access the correct summary and see if it can + // be internalized again. + // FIXME: Eventually we should control promotion instead of promoting + // and internalizing again. + StringRef OrigName = + ModuleSummaryIndex::getOriginalNameBeforePromote(GV.getName()); + std::string OrigId = GlobalValue::getGlobalIdentifier( + OrigName, GlobalValue::InternalLinkage, + TheModule.getSourceFileName()); + const auto &GS = DefinedGlobals.find(GlobalValue::getGUID(OrigId)); + assert(GS != DefinedGlobals.end()); + Linkage = GS->second->linkage(); + } else + Linkage = GS->second->linkage(); + return !GlobalValue::isLocalLinkage(Linkage); + }; + + // FIXME: See if we can just internalize directly here via linkage changes + // based on the index, rather than invoking internalizeModule. + llvm::internalizeModule(TheModule, MustPreserveGV); +} + // Automatically import functions in Module \p DestModule based on the summaries // index. //