aboutsummaryrefslogtreecommitdiff
path: root/lib/IR/ModuleSummaryIndex.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/IR/ModuleSummaryIndex.cpp
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Diffstat (limited to 'lib/IR/ModuleSummaryIndex.cpp')
-rw-r--r--lib/IR/ModuleSummaryIndex.cpp192
1 files changed, 108 insertions, 84 deletions
diff --git a/lib/IR/ModuleSummaryIndex.cpp b/lib/IR/ModuleSummaryIndex.cpp
index 46b88cd31779..9f347d8da01d 100644
--- a/lib/IR/ModuleSummaryIndex.cpp
+++ b/lib/IR/ModuleSummaryIndex.cpp
@@ -1,9 +1,8 @@
//===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -24,9 +23,12 @@ using namespace llvm;
STATISTIC(ReadOnlyLiveGVars,
"Number of live global variables marked read only");
+STATISTIC(WriteOnlyLiveGVars,
+ "Number of live global variables marked write only");
FunctionSummary FunctionSummary::ExternalNode =
FunctionSummary::makeDummyFunctionSummary({});
+
bool ValueInfo::isDSOLocal() const {
// Need to check all summaries are local in case of hash collisions.
return getSummaryList().size() &&
@@ -36,15 +38,27 @@ bool ValueInfo::isDSOLocal() const {
});
}
-// Gets the number of immutable refs in RefEdgeList
-unsigned FunctionSummary::immutableRefCount() const {
- // Here we take advantage of having all readonly references
+bool ValueInfo::canAutoHide() const {
+ // Can only auto hide if all copies are eligible to auto hide.
+ return getSummaryList().size() &&
+ llvm::all_of(getSummaryList(),
+ [](const std::unique_ptr<GlobalValueSummary> &Summary) {
+ return Summary->canAutoHide();
+ });
+}
+
+// Gets the number of readonly and writeonly refs in RefEdgeList
+std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const {
+ // Here we take advantage of having all readonly and writeonly references
// located in the end of the RefEdgeList.
auto Refs = refs();
- unsigned ImmutableRefCnt = 0;
- for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I)
- ImmutableRefCnt++;
- return ImmutableRefCnt;
+ unsigned RORefCnt = 0, WORefCnt = 0;
+ int I;
+ for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I)
+ WORefCnt++;
+ for (; I >= 0 && Refs[I].isReadOnly(); --I)
+ RORefCnt++;
+ return {RORefCnt, WORefCnt};
}
// Collect for the given module the list of function it defines
@@ -66,17 +80,6 @@ void ModuleSummaryIndex::collectDefinedFunctionsForModule(
}
}
-// Collect for each module the list of function it defines (GUID -> Summary).
-void ModuleSummaryIndex::collectDefinedGVSummariesPerModule(
- StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const {
- for (auto &GlobalList : *this) {
- auto GUID = GlobalList.first;
- for (auto &Summary : GlobalList.second.SummaryList) {
- ModuleToDefinedGVSummaries[Summary->modulePath()][GUID] = Summary.get();
- }
- }
-}
-
GlobalValueSummary *
ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
bool PerModuleIndex) const {
@@ -101,48 +104,56 @@ bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
return false;
}
-static void propagateConstantsToRefs(GlobalValueSummary *S) {
- // If reference is not readonly then referenced summary is not
- // readonly either. Note that:
+static void propagateAttributesToRefs(GlobalValueSummary *S) {
+ // If reference is not readonly or writeonly then referenced summary is not
+ // read/writeonly either. Note that:
// - All references from GlobalVarSummary are conservatively considered as
- // not readonly. Tracking them properly requires more complex analysis
- // then we have now.
+ // not readonly or writeonly. Tracking them properly requires more complex
+ // analysis then we have now.
//
// - AliasSummary objects have no refs at all so this function is a no-op
// for them.
for (auto &VI : S->refs()) {
- if (VI.isReadOnly()) {
- // We only mark refs as readonly when computing function summaries on
- // analysis phase.
- assert(isa<FunctionSummary>(S));
- continue;
- }
+ assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S));
for (auto &Ref : VI.getSummaryList())
- // If references to alias is not readonly then aliasee is not readonly
- if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject()))
- GVS->setReadOnly(false);
+ // If references to alias is not read/writeonly then aliasee
+ // is not read/writeonly
+ if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) {
+ if (!VI.isReadOnly())
+ GVS->setReadOnly(false);
+ if (!VI.isWriteOnly())
+ GVS->setWriteOnly(false);
+ }
}
}
-// Do the constant propagation in combined index.
-// The goal of constant propagation is internalization of readonly
-// variables. To determine which variables are readonly and which
-// are not we take following steps:
-// - During analysis we speculatively assign readonly attribute to
-// all variables which can be internalized. When computing function
-// summary we also assign readonly attribute to a reference if
-// function doesn't modify referenced variable.
+// Do the access attribute propagation in combined index.
+// The goal of attribute propagation is internalization of readonly (RO)
+// or writeonly (WO) variables. To determine which variables are RO or WO
+// and which are not we take following steps:
+// - During analysis we speculatively assign readonly and writeonly
+// attribute to all variables which can be internalized. When computing
+// function summary we also assign readonly or writeonly attribute to a
+// reference if function doesn't modify referenced variable (readonly)
+// or doesn't read it (writeonly).
+//
+// - After computing dead symbols in combined index we do the attribute
+// propagation. During this step we:
+// a. clear RO and WO attributes from variables which are preserved or
+// can't be imported
+// b. clear RO and WO attributes from variables referenced by any global
+// variable initializer
+// c. clear RO attribute from variable referenced by a function when
+// reference is not readonly
+// d. clear WO attribute from variable referenced by a function when
+// reference is not writeonly
//
-// - After computing dead symbols in combined index we do the constant
-// propagation. During this step we clear readonly attribute from
-// all variables which:
-// a. are preserved or can't be imported
-// b. referenced by any global variable initializer
-// c. referenced by a function and reference is not readonly
+// Because of (c, d) we don't internalize variables read by function A
+// and modified by function B.
//
// Internalization itself happens in the backend after import is finished
-// See internalizeImmutableGVs.
-void ModuleSummaryIndex::propagateConstants(
+// See internalizeGVsAfterImport.
+void ModuleSummaryIndex::propagateAttributes(
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
for (auto &P : *this)
for (auto &S : P.second.SummaryList) {
@@ -150,29 +161,36 @@ void ModuleSummaryIndex::propagateConstants(
// We don't examine references from dead objects
continue;
- // Global variable can't be marked read only if it is not eligible
- // to import since we need to ensure that all external references
- // get a local (imported) copy. It also can't be marked read only
- // if it or any alias (since alias points to the same memory) are
- // preserved or notEligibleToImport, since either of those means
- // there could be writes that are not visible (because preserved
- // means it could have external to DSO writes, and notEligibleToImport
- // means it could have writes via inline assembly leading it to be
- // in the @llvm.*used).
+ // Global variable can't be marked read/writeonly if it is not eligible
+ // to import since we need to ensure that all external references get
+ // a local (imported) copy. It also can't be marked read/writeonly if
+ // it or any alias (since alias points to the same memory) are preserved
+ // or notEligibleToImport, since either of those means there could be
+ // writes (or reads in case of writeonly) that are not visible (because
+ // preserved means it could have external to DSO writes or reads, and
+ // notEligibleToImport means it could have writes or reads via inline
+ // assembly leading it to be in the @llvm.*used).
if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
// Here we intentionally pass S.get() not GVS, because S could be
// an alias.
- if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first))
+ if (!canImportGlobalVar(S.get()) ||
+ GUIDPreservedSymbols.count(P.first)) {
GVS->setReadOnly(false);
- propagateConstantsToRefs(S.get());
+ GVS->setWriteOnly(false);
+ }
+ propagateAttributesToRefs(S.get());
}
if (llvm::AreStatisticsEnabled())
for (auto &P : *this)
if (P.second.SummaryList.size())
if (auto *GVS = dyn_cast<GlobalVarSummary>(
P.second.SummaryList[0]->getBaseObject()))
- if (isGlobalValueLive(GVS) && GVS->isReadOnly())
- ReadOnlyLiveGVars++;
+ if (isGlobalValueLive(GVS)) {
+ if (GVS->maybeReadOnly())
+ ReadOnlyLiveGVars++;
+ if (GVS->maybeWriteOnly())
+ WriteOnlyLiveGVars++;
+ }
}
// TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
@@ -335,14 +353,21 @@ static void defineExternalNode(raw_ostream &OS, const char *Pfx,
static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
- return GVS->isReadOnly();
+ return GVS->maybeReadOnly();
+ return false;
+}
+
+static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
+ if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
+ return GVS->maybeWriteOnly();
return false;
}
void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
std::vector<Edge> CrossModuleEdges;
DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
- StringMap<GVSummaryMapTy> ModuleToDefinedGVS;
+ using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>;
+ std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS;
collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
// Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
@@ -359,12 +384,14 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
// 0 - alias
// 1 - reference
// 2 - constant reference
- // Other value: (hotness - 3).
- TypeOrHotness += 3;
+ // 3 - writeonly reference
+ // Other value: (hotness - 4).
+ TypeOrHotness += 4;
static const char *EdgeAttrs[] = {
" [style=dotted]; // alias",
" [style=dashed]; // ref",
" [style=dashed,color=forestgreen]; // const-ref",
+ " [style=dashed,color=violetred]; // writeOnly-ref",
" // call (hotness : Unknown)",
" [color=blue]; // call (hotness : Cold)",
" // call (hotness : None)",
@@ -379,12 +406,12 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
OS << "digraph Summary {\n";
for (auto &ModIt : ModuleToDefinedGVS) {
- auto ModId = getModuleId(ModIt.first());
- OS << " // Module: " << ModIt.first() << "\n";
+ auto ModId = getModuleId(ModIt.first);
+ OS << " // Module: " << ModIt.first << "\n";
OS << " subgraph cluster_" << std::to_string(ModId) << " {\n";
OS << " style = filled;\n";
OS << " color = lightgrey;\n";
- OS << " label = \"" << sys::path::filename(ModIt.first()) << "\";\n";
+ OS << " label = \"" << sys::path::filename(ModIt.first) << "\";\n";
OS << " node [style=filled,fillcolor=lightblue];\n";
auto &GVSMap = ModIt.second;
@@ -409,7 +436,13 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
A.add("shape", "Mrecord", "variable");
if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
A.addComment("immutable");
+ if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
+ A.addComment("writeOnly");
}
+ if (Flags.DSOLocal)
+ A.addComment("dsoLocal");
+ if (Flags.CanAutoHide)
+ A.addComment("canAutoHide");
auto VI = getValueInfo(SummaryIt.first);
A.add("label", getNodeLabel(VI, SummaryIt.second));
@@ -426,20 +459,11 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
for (auto &SummaryIt : GVSMap) {
auto *GVS = SummaryIt.second;
for (auto &R : GVS->refs())
- Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2);
+ Draw(SummaryIt.first, R.getGUID(),
+ R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3));
if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
- GlobalValue::GUID AliaseeId;
- if (AS->hasAliaseeGUID())
- AliaseeId = AS->getAliaseeGUID();
- else {
- auto AliaseeOrigId = AS->getAliasee().getOriginalName();
- AliaseeId = getGUIDFromOriginalID(AliaseeOrigId);
- if (!AliaseeId)
- AliaseeId = AliaseeOrigId;
- }
-
- Draw(SummaryIt.first, AliaseeId, -3);
+ Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
continue;
}