aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/BasicAliasAnalysis.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r--llvm/lib/Analysis/BasicAliasAnalysis.cpp69
1 files changed, 49 insertions, 20 deletions
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 6eac30f..72db289 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -555,17 +555,17 @@ struct BasicAAResult::DecomposedGEP {
APInt Offset;
// Scaled variable (non-constant) indices.
SmallVector<VariableGEPIndex, 4> VarIndices;
- // Are all operations inbounds GEPs or non-indexing operations?
- // (std::nullopt iff expression doesn't involve any geps)
- std::optional<bool> InBounds;
+ // Nowrap flags common to all GEP operations involved in expression.
+ GEPNoWrapFlags NWFlags = GEPNoWrapFlags::all();
void dump() const {
print(dbgs());
dbgs() << "\n";
}
void print(raw_ostream &OS) const {
- OS << "(DecomposedGEP Base=" << Base->getName()
- << ", Offset=" << Offset
+ OS << ", inbounds=" << (NWFlags.isInBounds() ? "1" : "0")
+ << ", nuw=" << (NWFlags.hasNoUnsignedWrap() ? "1" : "0")
+ << "(DecomposedGEP Base=" << Base->getName() << ", Offset=" << Offset
<< ", VarIndices=[";
for (size_t i = 0; i < VarIndices.size(); i++) {
if (i != 0)
@@ -644,12 +644,8 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
return Decomposed;
}
- // Track whether we've seen at least one in bounds gep, and if so, whether
- // all geps parsed were in bounds.
- if (Decomposed.InBounds == std::nullopt)
- Decomposed.InBounds = GEPOp->isInBounds();
- else if (!GEPOp->isInBounds())
- Decomposed.InBounds = false;
+ // Track the common nowrap flags for all GEPs we see.
+ Decomposed.NWFlags &= GEPOp->getNoWrapFlags();
assert(GEPOp->getSourceElementType()->isSized() && "GEP must be sized");
@@ -1112,6 +1108,13 @@ AliasResult BasicAAResult::aliasGEP(
if (DecompGEP1.Base == GEP1 && DecompGEP2.Base == V2)
return AliasResult::MayAlias;
+ // Swap GEP1 and GEP2 if GEP2 has more variable indices.
+ if (DecompGEP1.VarIndices.size() < DecompGEP2.VarIndices.size()) {
+ std::swap(DecompGEP1, DecompGEP2);
+ std::swap(V1Size, V2Size);
+ std::swap(UnderlyingV1, UnderlyingV2);
+ }
+
// Subtract the GEP2 pointer from the GEP1 pointer to find out their
// symbolic difference.
subtractDecomposedGEPs(DecompGEP1, DecompGEP2, AAQI);
@@ -1120,20 +1123,19 @@ AliasResult BasicAAResult::aliasGEP(
// for the two to alias, then we can assume noalias.
// TODO: Remove !isScalable() once BasicAA fully support scalable location
// size
- if (*DecompGEP1.InBounds && DecompGEP1.VarIndices.empty() &&
+
+ if (DecompGEP1.NWFlags.isInBounds() && DecompGEP1.VarIndices.empty() &&
V2Size.hasValue() && !V2Size.isScalable() &&
DecompGEP1.Offset.sge(V2Size.getValue()) &&
isBaseOfObject(DecompGEP2.Base))
return AliasResult::NoAlias;
- if (isa<GEPOperator>(V2)) {
- // Symmetric case to above.
- if (*DecompGEP2.InBounds && DecompGEP1.VarIndices.empty() &&
- V1Size.hasValue() && !V1Size.isScalable() &&
- DecompGEP1.Offset.sle(-V1Size.getValue()) &&
- isBaseOfObject(DecompGEP1.Base))
- return AliasResult::NoAlias;
- }
+ // Symmetric case to above.
+ if (DecompGEP2.NWFlags.isInBounds() && DecompGEP1.VarIndices.empty() &&
+ V1Size.hasValue() && !V1Size.isScalable() &&
+ DecompGEP1.Offset.sle(-V1Size.getValue()) &&
+ isBaseOfObject(DecompGEP1.Base))
+ return AliasResult::NoAlias;
// For GEPs with identical offsets, we can preserve the size and AAInfo
// when performing the alias check on the underlying objects.
@@ -1239,6 +1241,20 @@ AliasResult BasicAAResult::aliasGEP(
}
}
+ // If the difference between pointers is Offset +<nuw> Indices then we know
+ // that the addition does not wrap the pointer index type (add nuw) and the
+ // constant Offset is a lower bound on the distance between the pointers. We
+ // can then prove NoAlias via Offset u>= VLeftSize.
+ // + + +
+ // | BaseOffset | +<nuw> Indices |
+ // ---------------->|-------------------->|
+ // |-->V2Size | |-------> V1Size
+ // LHS RHS
+ if (!DecompGEP1.VarIndices.empty() &&
+ DecompGEP1.NWFlags.hasNoUnsignedWrap() && V2Size.hasValue() &&
+ !V2Size.isScalable() && DecompGEP1.Offset.uge(V2Size.getValue()))
+ return AliasResult::NoAlias;
+
// Bail on analysing scalable LocationSize
if (V1Size.isScalable() || V2Size.isScalable())
return AliasResult::MayAlias;
@@ -1843,6 +1859,11 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V,
void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
const DecomposedGEP &SrcGEP,
const AAQueryInfo &AAQI) {
+ // Drop nuw flag from GEP if subtraction of constant offsets overflows in an
+ // unsigned sense.
+ if (DestGEP.Offset.ult(SrcGEP.Offset))
+ DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap();
+
DestGEP.Offset -= SrcGEP.Offset;
for (const VariableGEPIndex &Src : SrcGEP.VarIndices) {
// Find V in Dest. This is N^2, but pointer indices almost never have more
@@ -1865,6 +1886,11 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
// If we found it, subtract off Scale V's from the entry in Dest. If it
// goes to zero, remove the entry.
if (Dest.Scale != Src.Scale) {
+ // Drop nuw flag from GEP if subtraction of V's Scale overflows in an
+ // unsigned sense.
+ if (Dest.Scale.ult(Src.Scale))
+ DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap();
+
Dest.Scale -= Src.Scale;
Dest.IsNSW = false;
} else {
@@ -1879,6 +1905,9 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
VariableGEPIndex Entry = {Src.Val, Src.Scale, Src.CxtI, Src.IsNSW,
/* IsNegated */ true};
DestGEP.VarIndices.push_back(Entry);
+
+ // Drop nuw flag when we have unconsumed variable indices from SrcGEP.
+ DestGEP.NWFlags = DestGEP.NWFlags.withoutNoUnsignedWrap();
}
}
}