(NFC) Track global summary liveness in GVFlags.

Replace GVFlags::LiveRoot with GVFlags::Live and use that instead of
all the DeadSymbols sets. This is refactoring in order to make
liveness information available in the RegularLTO pipeline.

llvm-svn: 304466
This commit is contained in:
Evgeniy Stepanov 2017-06-01 20:30:06 +00:00
parent a5dbbc6ead
commit 56584bbf16
8 changed files with 114 additions and 103 deletions

View File

@ -134,16 +134,18 @@ public:
/// be renamed or references something that can't be renamed).
unsigned NotEligibleToImport : 1;
/// Indicate that the global value must be considered a live root for
/// index-based liveness analysis. Used for special LLVM values such as
/// llvm.global_ctors that the linker does not know about.
unsigned LiveRoot : 1;
/// In per-module summary, indicate that the global value must be considered
/// a live root for index-based liveness analysis. Used for special LLVM
/// values such as llvm.global_ctors that the linker does not know about.
///
/// In combined summary, indicate that the global value is live.
unsigned Live : 1;
/// Convenience Constructors
explicit GVFlags(GlobalValue::LinkageTypes Linkage,
bool NotEligibleToImport, bool LiveRoot)
bool NotEligibleToImport, bool Live)
: Linkage(Linkage), NotEligibleToImport(NotEligibleToImport),
LiveRoot(LiveRoot) {}
Live(Live) {}
};
private:
@ -172,6 +174,8 @@ private:
/// are listed in the derived FunctionSummary object.
std::vector<ValueInfo> RefEdgeList;
bool isLive() const { return Flags.Live; }
protected:
GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs)
: Kind(K), Flags(Flags), RefEdgeList(std::move(Refs)) {}
@ -213,19 +217,17 @@ public:
/// Return true if this global value can't be imported.
bool notEligibleToImport() const { return Flags.NotEligibleToImport; }
/// Return true if this global value must be considered a root for live
/// value analysis on the index.
bool liveRoot() const { return Flags.LiveRoot; }
/// Flag that this global value must be considered a root for live
/// value analysis on the index.
void setLiveRoot() { Flags.LiveRoot = true; }
void setLive(bool Live) { Flags.Live = Live; }
/// Flag that this global value cannot be imported.
void setNotEligibleToImport() { Flags.NotEligibleToImport = true; }
/// Return the list of values referenced by this global value definition.
ArrayRef<ValueInfo> refs() const { return RefEdgeList; }
friend class ModuleSummaryIndex;
friend void computeDeadSymbols(class ModuleSummaryIndex &,
const DenseSet<GlobalValue::GUID> &);
};
/// \brief Alias summary information.
@ -535,6 +537,11 @@ private:
/// GUIDs, it will be mapped to 0.
std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;
/// Indicates that summary-based GlobalValue GC has run, and values with
/// GVFlags::Live==false are really dead. Otherwise, all values must be
/// considered live.
bool WithGlobalValueDeadStripping = false;
// YAML I/O support.
friend yaml::MappingTraits<ModuleSummaryIndex>;
@ -550,6 +557,17 @@ public:
const_gvsummary_iterator end() const { return GlobalValueMap.end(); }
size_t size() const { return GlobalValueMap.size(); }
bool withGlobalValueDeadStripping() const {
return WithGlobalValueDeadStripping;
}
void setWithGlobalValueDeadStripping() {
WithGlobalValueDeadStripping = true;
}
bool isGlobalValueLive(const GlobalValueSummary *GVS) const {
return !WithGlobalValueDeadStripping || GVS->isLive();
}
/// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo().
ValueInfo getValueInfo(GlobalValue::GUID GUID) const {
auto I = GlobalValueMap.find(GUID);

View File

@ -81,15 +81,11 @@ public:
/// \p ExportLists contains for each Module the set of globals (GUID) that will
/// be imported by another module, or referenced by such a function. I.e. this
/// is the set of globals that need to be promoted/renamed appropriately.
///
/// \p DeadSymbols (optional) contains a list of GUID that are deemed "dead" and
/// will be ignored for the purpose of importing.
void ComputeCrossModuleImport(
const ModuleSummaryIndex &Index,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
StringMap<FunctionImporter::ExportSetTy> &ExportLists,
const DenseSet<GlobalValue::GUID> *DeadSymbols = nullptr);
StringMap<FunctionImporter::ExportSetTy> &ExportLists);
/// Compute all the imports for the given module using the Index.
///
@ -102,9 +98,9 @@ void ComputeCrossModuleImportForModule(
/// Compute all the symbols that are "dead": i.e these that can't be reached
/// in the graph from any of the given symbols listed in
/// \p GUIDPreservedSymbols.
DenseSet<GlobalValue::GUID>
computeDeadSymbols(const ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
void computeDeadSymbols(
ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
/// Compute the set of summaries needed for a ThinLTO backend compilation of
/// \p ModulePath.

View File

@ -275,7 +275,7 @@ computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
// FIXME: refactor this to use the same code that inliner is using.
F.isVarArg();
GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport,
/* LiveRoot = */ false);
/* Live = */ false);
auto FuncSummary = llvm::make_unique<FunctionSummary>(
Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(),
TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
@ -295,7 +295,7 @@ computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
findRefEdges(Index, &V, RefEdges, Visited);
bool NonRenamableLocal = isNonRenamableLocal(V);
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
/* LiveRoot = */ false);
/* Live = */ false);
auto GVarSummary =
llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector());
if (NonRenamableLocal)
@ -308,7 +308,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
DenseSet<GlobalValue::GUID> &CantBePromoted) {
bool NonRenamableLocal = isNonRenamableLocal(A);
GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal,
/* LiveRoot = */ false);
/* Live = */ false);
auto AS = llvm::make_unique<AliasSummary>(Flags, ArrayRef<ValueInfo>{});
auto *Aliasee = A.getBaseObject();
auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee);
@ -323,7 +323,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name)))
for (auto &Summary : VI.getSummaryList())
Summary->setLiveRoot();
Summary->setLive(true);
}
ModuleSummaryIndex llvm::buildModuleSummaryIndex(
@ -423,8 +423,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
return;
assert(GV->isDeclaration() && "Def in module asm already has definition");
GlobalValueSummary::GVFlags GVFlags(GlobalValue::InternalLinkage,
/* NotEligibleToImport */ true,
/* LiveRoot */ true);
/* NotEligibleToImport = */ true,
/* Live = */ true);
CantBePromoted.insert(GlobalValue::getGUID(Name));
// Create the appropriate summary type.
if (isa<Function>(GV)) {

View File

@ -865,11 +865,11 @@ static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags,
auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits
RawFlags = RawFlags >> 4;
bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3;
// The LiveRoot flag wasn't introduced until version 3. For dead stripping
// The Live flag wasn't introduced until version 3. For dead stripping
// to work correctly on earlier versions, we must conservatively treat all
// values as live.
bool LiveRoot = (RawFlags & 0x2) || Version < 3;
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot);
bool Live = (RawFlags & 0x2) || Version < 3;
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live);
}
static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {

View File

@ -864,7 +864,7 @@ static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) {
uint64_t RawFlags = 0;
RawFlags |= Flags.NotEligibleToImport; // bool
RawFlags |= (Flags.LiveRoot << 1);
RawFlags |= (Flags.Live << 1);
// Linkage don't need to be remapped at that time for the summary. Any future
// change to the getEncodedLinkage() function will need to be taken into
// account here as well.

View File

@ -930,6 +930,17 @@ ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
};
}
static bool IsLiveByGUID(const ModuleSummaryIndex &Index,
GlobalValue::GUID GUID) {
auto VI = Index.getValueInfo(GUID);
if (!VI)
return false;
for (auto &I : VI.getSummaryList())
if (Index.isGlobalValueLive(I.get()))
return true;
return false;
}
Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
bool HasRegularLTO) {
if (ThinLTO.ModuleMap.empty())
@ -973,11 +984,10 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
GlobalValue::dropLLVMManglingEscape(Res.second.IRName)));
}
auto DeadSymbols =
computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
ImportLists, ExportLists, &DeadSymbols);
ImportLists, ExportLists);
std::set<GlobalValue::GUID> ExportedGUIDs;
for (auto &Res : GlobalResolutions) {
@ -992,7 +1002,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
auto GUID = GlobalValue::getGUID(
GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
// Mark exported unless index-based analysis determined it to be dead.
if (!DeadSymbols.count(GUID))
if (IsLiveByGUID(ThinLTO.CombinedIndex, GUID))
ExportedGUIDs.insert(GUID);
}

View File

@ -628,13 +628,13 @@ void ThinLTOCodeGenerator::promote(Module &TheModule,
PreservedSymbols, Triple(TheModule.getTargetTriple()));
// Compute "dead" symbols, we don't want to import/export these!
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
computeDeadSymbols(Index, GUIDPreservedSymbols);
// Generate import/export list
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
ExportLists, &DeadSymbols);
ExportLists);
// Resolve LinkOnce/Weak symbols.
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
@ -673,13 +673,13 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
PreservedSymbols, Triple(TheModule.getTargetTriple()));
// Compute "dead" symbols, we don't want to import/export these!
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
computeDeadSymbols(Index, GUIDPreservedSymbols);
// Generate import/export list
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
ExportLists, &DeadSymbols);
ExportLists);
auto &ImportList = ImportLists[TheModule.getModuleIdentifier()];
crossImportIntoModule(TheModule, Index, ModuleMap, ImportList);
@ -750,13 +750,13 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule,
Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
// Compute "dead" symbols, we don't want to import/export these!
auto DeadSymbols = computeDeadSymbols(Index, GUIDPreservedSymbols);
computeDeadSymbols(Index, GUIDPreservedSymbols);
// Generate import/export list
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
ExportLists, &DeadSymbols);
ExportLists);
auto &ExportList = ExportLists[ModuleIdentifier];
// Be friendly and don't nuke totally the module when the client didn't
@ -902,14 +902,14 @@ void ThinLTOCodeGenerator::run() {
computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple);
// Compute "dead" symbols, we don't want to import/export these!
auto DeadSymbols = computeDeadSymbols(*Index, GUIDPreservedSymbols);
computeDeadSymbols(*Index, GUIDPreservedSymbols);
// Collect the import/export lists for all modules from the call-graph in the
// combined index.
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists,
ExportLists, &DeadSymbols);
ExportLists);
// We use a std::map here to be able to have a defined ordering when
// producing a hash for the cache entry.

View File

@ -292,8 +292,7 @@ static void computeImportForFunction(
static void ComputeImportForModule(
const GVSummaryMapTy &DefinedGVSummaries, const ModuleSummaryIndex &Index,
FunctionImporter::ImportMapTy &ImportList,
StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr,
const DenseSet<GlobalValue::GUID> *DeadSymbols = nullptr) {
StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) {
// Worklist contains the list of function imported in this module, for which
// we will analyse the callees and may import further down the callgraph.
SmallVector<EdgeInfo, 128> Worklist;
@ -301,7 +300,7 @@ static void ComputeImportForModule(
// Populate the worklist with the import for the functions in the current
// module
for (auto &GVSummary : DefinedGVSummaries) {
if (DeadSymbols && DeadSymbols->count(GVSummary.first)) {
if (!Index.isGlobalValueLive(GVSummary.second)) {
DEBUG(dbgs() << "Ignores Dead GUID: " << GVSummary.first << "\n");
continue;
}
@ -344,15 +343,14 @@ void llvm::ComputeCrossModuleImport(
const ModuleSummaryIndex &Index,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
StringMap<FunctionImporter::ExportSetTy> &ExportLists,
const DenseSet<GlobalValue::GUID> *DeadSymbols) {
StringMap<FunctionImporter::ExportSetTy> &ExportLists) {
// For each module that has function defined, compute the import/export lists.
for (auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) {
auto &ImportList = ImportLists[DefinedGVSummaries.first()];
DEBUG(dbgs() << "Computing import for Module '"
<< DefinedGVSummaries.first() << "'\n");
ComputeImportForModule(DefinedGVSummaries.second, Index, ImportList,
&ExportLists, DeadSymbols);
&ExportLists);
}
// When computing imports we added all GUIDs referenced by anything
@ -414,82 +412,71 @@ void llvm::ComputeCrossModuleImportForModule(
#endif
}
DenseSet<GlobalValue::GUID> llvm::computeDeadSymbols(
const ModuleSummaryIndex &Index,
void llvm::computeDeadSymbols(
ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
assert(!Index.withGlobalValueDeadStripping());
if (!ComputeDead)
return DenseSet<GlobalValue::GUID>();
return;
if (GUIDPreservedSymbols.empty())
// Don't do anything when nothing is live, this is friendly with tests.
return DenseSet<GlobalValue::GUID>();
DenseSet<ValueInfo> LiveSymbols;
return;
unsigned LiveSymbols = 0;
SmallVector<ValueInfo, 128> Worklist;
Worklist.reserve(GUIDPreservedSymbols.size() * 2);
for (auto GUID : GUIDPreservedSymbols) {
ValueInfo VI = Index.getValueInfo(GUID);
if (!VI)
continue;
DEBUG(dbgs() << "Live root: " << VI.getGUID() << "\n");
LiveSymbols.insert(VI);
Worklist.push_back(VI);
for (auto &S : VI.getSummaryList())
S->setLive(true);
}
// Add values flagged in the index as live roots to the worklist.
for (const auto &Entry : Index) {
bool IsLiveRoot = llvm::any_of(
Entry.second.SummaryList,
[&](const std::unique_ptr<llvm::GlobalValueSummary> &Summary) {
return Summary->liveRoot();
});
if (!IsLiveRoot)
continue;
DEBUG(dbgs() << "Live root (summary): " << Entry.first << "\n");
Worklist.push_back(ValueInfo(&Entry));
}
for (const auto &Entry : Index)
for (auto &S : Entry.second.SummaryList)
if (S->isLive()) {
DEBUG(dbgs() << "Live root: " << Entry.first << "\n");
Worklist.push_back(ValueInfo(&Entry));
++LiveSymbols;
break;
}
// Make value live and add it to the worklist if it was not live before.
// FIXME: we should only make the prevailing copy live here
auto visit = [&](ValueInfo VI) {
for (auto &S : VI.getSummaryList())
if (S->isLive())
return;
for (auto &S : VI.getSummaryList())
S->setLive(true);
++LiveSymbols;
Worklist.push_back(VI);
};
while (!Worklist.empty()) {
auto VI = Worklist.pop_back_val();
// FIXME: we should only make the prevailing copy live here
for (auto &Summary : VI.getSummaryList()) {
for (auto Ref : Summary->refs()) {
if (LiveSymbols.insert(Ref).second) {
DEBUG(dbgs() << "Marking live (ref): " << Ref.getGUID() << "\n");
Worklist.push_back(Ref);
}
}
if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
for (auto Call : FS->calls()) {
if (LiveSymbols.insert(Call.first).second) {
DEBUG(dbgs() << "Marking live (call): " << Call.first.getGUID()
<< "\n");
Worklist.push_back(Call.first);
}
}
}
for (auto Ref : Summary->refs())
visit(Ref);
if (auto *FS = dyn_cast<FunctionSummary>(Summary.get()))
for (auto Call : FS->calls())
visit(Call.first);
if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
auto AliaseeGUID = AS->getAliasee().getOriginalName();
ValueInfo AliaseeVI = Index.getValueInfo(AliaseeGUID);
if (AliaseeVI && LiveSymbols.insert(AliaseeVI).second) {
DEBUG(dbgs() << "Marking live (alias): " << AliaseeGUID << "\n");
Worklist.push_back(AliaseeVI);
}
if (AliaseeVI)
visit(AliaseeVI);
}
}
}
DenseSet<GlobalValue::GUID> DeadSymbols;
DeadSymbols.reserve(
std::min(Index.size(), Index.size() - LiveSymbols.size()));
for (auto &Entry : Index) {
if (!LiveSymbols.count(ValueInfo(&Entry))) {
DEBUG(dbgs() << "Marking dead: " << Entry.first << "\n");
DeadSymbols.insert(Entry.first);
}
}
DEBUG(dbgs() << LiveSymbols.size() << " symbols Live, and "
<< DeadSymbols.size() << " symbols Dead \n");
NumDeadSymbols += DeadSymbols.size();
NumLiveSymbols += LiveSymbols.size();
return DeadSymbols;
Index.setWithGlobalValueDeadStripping();
unsigned DeadSymbols = Index.size() - LiveSymbols;
DEBUG(dbgs() << LiveSymbols << " symbols Live, and " << DeadSymbols
<< " symbols Dead \n");
NumDeadSymbols += DeadSymbols;
NumLiveSymbols += LiveSymbols;
}
/// Compute the set of summaries needed for a ThinLTO backend compilation of