summaryrefslogtreecommitdiffstats
path: root/llvm/lib/IR/ModuleSummaryIndex.cpp
diff options
context:
space:
mode:
authorEugene Leviant <eleviant@accesssoftek.com>2019-07-05 12:00:10 +0000
committerEugene Leviant <eleviant@accesssoftek.com>2019-07-05 12:00:10 +0000
commit820cc01d1e65f7be7c3c27bcdcb6b8c13f4ec2e6 (patch)
tree8580e927d93c7185dd262f864c9bdeef7d450cae /llvm/lib/IR/ModuleSummaryIndex.cpp
parent1a517a4630ae4d9e24e991a3e6a3bf58c5dabf6d (diff)
downloadbcm5719-llvm-820cc01d1e65f7be7c3c27bcdcb6b8c13f4ec2e6.tar.gz
bcm5719-llvm-820cc01d1e65f7be7c3c27bcdcb6b8c13f4ec2e6.zip
[ThinLTO] Attempt to recommit r365040 after caching fix
It's possible that some function can load and store the same variable using the same constant expression: store %Derived* @foo, %Derived** bitcast (%Base** @bar to %Derived**) %42 = load %Derived*, %Derived** bitcast (%Base** @bar to %Derived**) The bitcast expression was mistakenly cached while processing loads, and never examined later when processing store. This caused @bar to be mistakenly treated as read-only variable. See load-store-caching.ll. llvm-svn: 365188
Diffstat (limited to 'llvm/lib/IR/ModuleSummaryIndex.cpp')
-rw-r--r--llvm/lib/IR/ModuleSummaryIndex.cpp141
1 files changed, 86 insertions, 55 deletions
diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp
index 18b7ac09388..9f347d8da01 100644
--- a/llvm/lib/IR/ModuleSummaryIndex.cpp
+++ b/llvm/lib/IR/ModuleSummaryIndex.cpp
@@ -23,6 +23,8 @@ 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({});
@@ -45,15 +47,18 @@ bool ValueInfo::canAutoHide() const {
});
}
-// Gets the number of immutable refs in RefEdgeList
-unsigned FunctionSummary::immutableRefCount() const {
- // Here we take advantage of having all readonly references
+// 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
@@ -99,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) {
@@ -148,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)
@@ -333,7 +353,13 @@ 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;
}
@@ -358,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)",
@@ -408,6 +436,8 @@ 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");
@@ -429,10 +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)) {
- Draw(SummaryIt.first, AS->getAliaseeGUID(), -3);
+ Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
continue;
}
OpenPOWER on IntegriCloud