[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
This commit is contained in:
Teresa Johnson 2016-05-25 14:03:11 +00:00
parent 34bf60ca68
commit 655b4d9f20
5 changed files with 211 additions and 174 deletions

View File

@ -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<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
std::function<bool(StringRef, GlobalValue::GUID)> isExported,
std::function<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)>
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<bool(StringRef, GlobalValue::GUID)> isExported);
}
#endif

View File

@ -107,6 +107,16 @@ void gatherImportedSummariesForModule(
std::error_code
EmitImportsFiles(StringRef ModulePath, StringRef OutputFilename,
const StringMap<FunctionImporter::ImportMapTy> &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

View File

@ -39,4 +39,104 @@ std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer,
}
return std::move(ModuleOrErr.get());
}
static void thinLTOResolveWeakForLinkerGUID(
GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID,
DenseSet<GlobalValueSummary *> &GlobalInvolvedWithAlias,
std::function<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
std::function<bool(StringRef, GlobalValue::GUID)> isExported,
std::function<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)>
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<AliasSummary>(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<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
std::function<bool(StringRef, GlobalValue::GUID)> isExported,
std::function<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)>
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<GlobalValueSummary *> GlobalInvolvedWithAlias;
for (auto &I : Index)
for (auto &S : I.second)
if (auto AS = dyn_cast<AliasSummary>(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<bool(StringRef, GlobalValue::GUID)> 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<bool(StringRef, GlobalValue::GUID)> isExported) {
for (auto &I : Index)
thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported);
}
}

View File

@ -128,112 +128,6 @@ static void computePrevailingCopies(
}
}
static void thinLTOResolveWeakForLinkerGUID(
GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID,
DenseSet<GlobalValueSummary *> &GlobalInvolvedWithAlias,
std::function<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
std::function<bool(StringRef, GlobalValue::GUID)> isExported,
std::function<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)>
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<AliasSummary>(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<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
std::function<bool(StringRef, GlobalValue::GUID)> isExported,
std::function<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)>
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<GlobalValueSummary *> GlobalInvolvedWithAlias;
for (auto &I : Index)
for (auto &S : I.second)
if (auto AS = dyn_cast<AliasSummary>(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<MemoryBufferRef>
generateModuleMap(const std::vector<MemoryBufferRef> &Modules) {
StringMap<MemoryBufferRef> 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<bool(StringRef, GlobalValue::GUID)> 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<bool(StringRef, GlobalValue::GUID)> 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<GlobalValue::GUID>
computeGUIDPreservedSymbols(const StringSet<> &PreservedSymbols,

View File

@ -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.
//