Skip to content

Commit

Permalink
[ThinLTO] Refactor ODR resolution and internalization (NFC)
Browse files Browse the repository at this point in the history
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@270698 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
teresajohnson committed May 25, 2016
1 parent d380dee commit 32d095c
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 174 deletions.
24 changes: 24 additions & 0 deletions include/llvm/LTO/LTO.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define LLVM_LTO_LTO_H

#include "llvm/ADT/StringMap.h"
#include "llvm/IR/ModuleSummaryIndex.h"

namespace llvm {

Expand Down Expand Up @@ -47,6 +48,29 @@ class ModuleLoader {
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
10 changes: 10 additions & 0 deletions include/llvm/Transforms/IPO/FunctionImport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
100 changes: 100 additions & 0 deletions lib/LTO/LTO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
174 changes: 0 additions & 174 deletions lib/LTO/ThinLTOCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 32d095c

Please sign in to comment.