summaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/BasicAliasAnalysis.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2024-07-26 22:04:10 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-07-26 22:04:10 +0000
commitac9a064cb179f3425b310fa2847f8764ac970a4d (patch)
tree6f945cdaa68c2b4c688dcf9fec4f922d35f4d1a4 /llvm/lib/Analysis/BasicAliasAnalysis.cpp
parent4df029cc74e5ec124f14a5682e44999ce4f086df (diff)
Diffstat (limited to 'llvm/lib/Analysis/BasicAliasAnalysis.cpp')
-rw-r--r--llvm/lib/Analysis/BasicAliasAnalysis.cpp164
1 files changed, 120 insertions, 44 deletions
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 3178e2d27816..161a3034e482 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -44,6 +44,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
+#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
@@ -89,7 +90,7 @@ bool BasicAAResult::invalidate(Function &Fn, const PreservedAnalyses &PA,
// may be created without handles to some analyses and in that case don't
// depend on them.
if (Inv.invalidate<AssumptionAnalysis>(Fn, PA) ||
- (DT && Inv.invalidate<DominatorTreeAnalysis>(Fn, PA)))
+ (DT_ && Inv.invalidate<DominatorTreeAnalysis>(Fn, PA)))
return true;
// Otherwise this analysis result remains valid.
@@ -188,6 +189,12 @@ static bool isObjectSize(const Value *V, TypeSize Size, const DataLayout &DL,
return ObjectSize && *ObjectSize == Size;
}
+/// Return true if both V1 and V2 are VScale
+static bool areBothVScale(const Value *V1, const Value *V2) {
+ return PatternMatch::match(V1, PatternMatch::m_VScale()) &&
+ PatternMatch::match(V2, PatternMatch::m_VScale());
+}
+
//===----------------------------------------------------------------------===//
// CaptureInfo implementations
//===----------------------------------------------------------------------===//
@@ -261,31 +268,43 @@ struct CastedValue {
unsigned ZExtBits = 0;
unsigned SExtBits = 0;
unsigned TruncBits = 0;
+ /// Whether trunc(V) is non-negative.
+ bool IsNonNegative = false;
explicit CastedValue(const Value *V) : V(V) {}
explicit CastedValue(const Value *V, unsigned ZExtBits, unsigned SExtBits,
- unsigned TruncBits)
- : V(V), ZExtBits(ZExtBits), SExtBits(SExtBits), TruncBits(TruncBits) {}
+ unsigned TruncBits, bool IsNonNegative)
+ : V(V), ZExtBits(ZExtBits), SExtBits(SExtBits), TruncBits(TruncBits),
+ IsNonNegative(IsNonNegative) {}
unsigned getBitWidth() const {
return V->getType()->getPrimitiveSizeInBits() - TruncBits + ZExtBits +
SExtBits;
}
- CastedValue withValue(const Value *NewV) const {
- return CastedValue(NewV, ZExtBits, SExtBits, TruncBits);
+ CastedValue withValue(const Value *NewV, bool PreserveNonNeg) const {
+ return CastedValue(NewV, ZExtBits, SExtBits, TruncBits,
+ IsNonNegative && PreserveNonNeg);
}
/// Replace V with zext(NewV)
- CastedValue withZExtOfValue(const Value *NewV) const {
+ CastedValue withZExtOfValue(const Value *NewV, bool ZExtNonNegative) const {
unsigned ExtendBy = V->getType()->getPrimitiveSizeInBits() -
NewV->getType()->getPrimitiveSizeInBits();
if (ExtendBy <= TruncBits)
- return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy);
+ // zext<nneg>(trunc(zext(NewV))) == zext<nneg>(trunc(NewV))
+ // The nneg can be preserved on the outer zext here.
+ return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy,
+ IsNonNegative);
// zext(sext(zext(NewV))) == zext(zext(zext(NewV)))
ExtendBy -= TruncBits;
- return CastedValue(NewV, ZExtBits + SExtBits + ExtendBy, 0, 0);
+ // zext<nneg>(zext(NewV)) == zext(NewV)
+ // zext(zext<nneg>(NewV)) == zext<nneg>(NewV)
+ // The nneg can be preserved from the inner zext here but must be dropped
+ // from the outer.
+ return CastedValue(NewV, ZExtBits + SExtBits + ExtendBy, 0, 0,
+ ZExtNonNegative);
}
/// Replace V with sext(NewV)
@@ -293,11 +312,16 @@ struct CastedValue {
unsigned ExtendBy = V->getType()->getPrimitiveSizeInBits() -
NewV->getType()->getPrimitiveSizeInBits();
if (ExtendBy <= TruncBits)
- return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy);
+ // zext<nneg>(trunc(sext(NewV))) == zext<nneg>(trunc(NewV))
+ // The nneg can be preserved on the outer zext here
+ return CastedValue(NewV, ZExtBits, SExtBits, TruncBits - ExtendBy,
+ IsNonNegative);
// zext(sext(sext(NewV)))
ExtendBy -= TruncBits;
- return CastedValue(NewV, ZExtBits, SExtBits + ExtendBy, 0);
+ // zext<nneg>(sext(sext(NewV))) = zext<nneg>(sext(NewV))
+ // The nneg can be preserved on the outer zext here
+ return CastedValue(NewV, ZExtBits, SExtBits + ExtendBy, 0, IsNonNegative);
}
APInt evaluateWith(APInt N) const {
@@ -326,8 +350,15 @@ struct CastedValue {
}
bool hasSameCastsAs(const CastedValue &Other) const {
- return ZExtBits == Other.ZExtBits && SExtBits == Other.SExtBits &&
- TruncBits == Other.TruncBits;
+ if (ZExtBits == Other.ZExtBits && SExtBits == Other.SExtBits &&
+ TruncBits == Other.TruncBits)
+ return true;
+ // If either CastedValue has a nneg zext then the sext/zext bits are
+ // interchangable for that value.
+ if (IsNonNegative || Other.IsNonNegative)
+ return (ZExtBits + SExtBits == Other.ZExtBits + Other.SExtBits &&
+ TruncBits == Other.TruncBits);
+ return false;
}
};
@@ -403,21 +434,21 @@ static LinearExpression GetLinearExpression(
[[fallthrough]];
case Instruction::Add: {
- E = GetLinearExpression(Val.withValue(BOp->getOperand(0)), DL,
+ E = GetLinearExpression(Val.withValue(BOp->getOperand(0), false), DL,
Depth + 1, AC, DT);
E.Offset += RHS;
E.IsNSW &= NSW;
break;
}
case Instruction::Sub: {
- E = GetLinearExpression(Val.withValue(BOp->getOperand(0)), DL,
+ E = GetLinearExpression(Val.withValue(BOp->getOperand(0), false), DL,
Depth + 1, AC, DT);
E.Offset -= RHS;
E.IsNSW &= NSW;
break;
}
case Instruction::Mul:
- E = GetLinearExpression(Val.withValue(BOp->getOperand(0)), DL,
+ E = GetLinearExpression(Val.withValue(BOp->getOperand(0), false), DL,
Depth + 1, AC, DT)
.mul(RHS, NSW);
break;
@@ -430,7 +461,7 @@ static LinearExpression GetLinearExpression(
if (RHS.getLimitedValue() > Val.getBitWidth())
return Val;
- E = GetLinearExpression(Val.withValue(BOp->getOperand(0)), DL,
+ E = GetLinearExpression(Val.withValue(BOp->getOperand(0), NSW), DL,
Depth + 1, AC, DT);
E.Offset <<= RHS.getLimitedValue();
E.Scale <<= RHS.getLimitedValue();
@@ -441,10 +472,10 @@ static LinearExpression GetLinearExpression(
}
}
- if (isa<ZExtInst>(Val.V))
+ if (const auto *ZExt = dyn_cast<ZExtInst>(Val.V))
return GetLinearExpression(
- Val.withZExtOfValue(cast<CastInst>(Val.V)->getOperand(0)),
- DL, Depth + 1, AC, DT);
+ Val.withZExtOfValue(ZExt->getOperand(0), ZExt->hasNonNeg()), DL,
+ Depth + 1, AC, DT);
if (isa<SExtInst>(Val.V))
return GetLinearExpression(
@@ -666,7 +697,7 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
unsigned SExtBits = IndexSize > Width ? IndexSize - Width : 0;
unsigned TruncBits = IndexSize < Width ? Width - IndexSize : 0;
LinearExpression LE = GetLinearExpression(
- CastedValue(Index, 0, SExtBits, TruncBits), DL, 0, AC, DT);
+ CastedValue(Index, 0, SExtBits, TruncBits, false), DL, 0, AC, DT);
// Scale by the type size.
unsigned TypeSize = AllocTypeSize.getFixedValue();
@@ -679,7 +710,8 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
// A[x][x] -> x*16 + x*4 -> x*20
// This also ensures that 'x' only appears in the index list once.
for (unsigned i = 0, e = Decomposed.VarIndices.size(); i != e; ++i) {
- if (Decomposed.VarIndices[i].Val.V == LE.Val.V &&
+ if ((Decomposed.VarIndices[i].Val.V == LE.Val.V ||
+ areBothVScale(Decomposed.VarIndices[i].Val.V, LE.Val.V)) &&
Decomposed.VarIndices[i].Val.hasSameCastsAs(LE.Val)) {
Scale += Decomposed.VarIndices[i].Scale;
LE.IsNSW = false; // We cannot guarantee nsw for the merge.
@@ -1063,6 +1095,7 @@ AliasResult BasicAAResult::aliasGEP(
: AliasResult::MayAlias;
}
+ DominatorTree *DT = getDT(AAQI);
DecomposedGEP DecompGEP1 = DecomposeGEPExpression(GEP1, DL, &AC, DT);
DecomposedGEP DecompGEP2 = DecomposeGEPExpression(V2, DL, &AC, DT);
@@ -1112,10 +1145,6 @@ AliasResult BasicAAResult::aliasGEP(
return BaseAlias;
}
- // Bail on analysing scalable LocationSize
- if (V1Size.isScalable() || V2Size.isScalable())
- return AliasResult::MayAlias;
-
// If there is a constant difference between the pointers, but the difference
// is less than the size of the associated memory object, then we know
// that the objects are partially overlapping. If the difference is
@@ -1145,24 +1174,69 @@ AliasResult BasicAAResult::aliasGEP(
if (!VLeftSize.hasValue())
return AliasResult::MayAlias;
- const uint64_t LSize = VLeftSize.getValue();
- if (Off.ult(LSize)) {
- // Conservatively drop processing if a phi was visited and/or offset is
- // too big.
- AliasResult AR = AliasResult::PartialAlias;
- if (VRightSize.hasValue() && Off.ule(INT32_MAX) &&
- (Off + VRightSize.getValue()).ule(LSize)) {
- // Memory referenced by right pointer is nested. Save the offset in
- // cache. Note that originally offset estimated as GEP1-V2, but
- // AliasResult contains the shift that represents GEP1+Offset=V2.
- AR.setOffset(-Off.getSExtValue());
- AR.swap(Swapped);
+ const TypeSize LSize = VLeftSize.getValue();
+ if (!LSize.isScalable()) {
+ if (Off.ult(LSize)) {
+ // Conservatively drop processing if a phi was visited and/or offset is
+ // too big.
+ AliasResult AR = AliasResult::PartialAlias;
+ if (VRightSize.hasValue() && !VRightSize.isScalable() &&
+ Off.ule(INT32_MAX) && (Off + VRightSize.getValue()).ule(LSize)) {
+ // Memory referenced by right pointer is nested. Save the offset in
+ // cache. Note that originally offset estimated as GEP1-V2, but
+ // AliasResult contains the shift that represents GEP1+Offset=V2.
+ AR.setOffset(-Off.getSExtValue());
+ AR.swap(Swapped);
+ }
+ return AR;
}
- return AR;
+ return AliasResult::NoAlias;
+ } else {
+ // We can use the getVScaleRange to prove that Off >= (CR.upper * LSize).
+ ConstantRange CR = getVScaleRange(&F, Off.getBitWidth());
+ bool Overflow;
+ APInt UpperRange = CR.getUnsignedMax().umul_ov(
+ APInt(Off.getBitWidth(), LSize.getKnownMinValue()), Overflow);
+ if (!Overflow && Off.uge(UpperRange))
+ return AliasResult::NoAlias;
}
- return AliasResult::NoAlias;
}
+ // VScale Alias Analysis - Given one scalable offset between accesses and a
+ // scalable typesize, we can divide each side by vscale, treating both values
+ // as a constant. We prove that Offset/vscale >= TypeSize/vscale.
+ if (DecompGEP1.VarIndices.size() == 1 &&
+ DecompGEP1.VarIndices[0].Val.TruncBits == 0 &&
+ DecompGEP1.Offset.isZero() &&
+ PatternMatch::match(DecompGEP1.VarIndices[0].Val.V,
+ PatternMatch::m_VScale())) {
+ const VariableGEPIndex &ScalableVar = DecompGEP1.VarIndices[0];
+ APInt Scale =
+ ScalableVar.IsNegated ? -ScalableVar.Scale : ScalableVar.Scale;
+ LocationSize VLeftSize = Scale.isNegative() ? V1Size : V2Size;
+
+ // Check if the offset is known to not overflow, if it does then attempt to
+ // prove it with the known values of vscale_range.
+ bool Overflows = !DecompGEP1.VarIndices[0].IsNSW;
+ if (Overflows) {
+ ConstantRange CR = getVScaleRange(&F, Scale.getBitWidth());
+ (void)CR.getSignedMax().smul_ov(Scale, Overflows);
+ }
+
+ if (!Overflows) {
+ // Note that we do not check that the typesize is scalable, as vscale >= 1
+ // so noalias still holds so long as the dependency distance is at least
+ // as big as the typesize.
+ if (VLeftSize.hasValue() &&
+ Scale.abs().uge(VLeftSize.getValue().getKnownMinValue()))
+ return AliasResult::NoAlias;
+ }
+ }
+
+ // Bail on analysing scalable LocationSize
+ if (V1Size.isScalable() || V2Size.isScalable())
+ return AliasResult::MayAlias;
+
// We need to know both acess sizes for all the following heuristics.
if (!V1Size.hasValue() || !V2Size.hasValue())
return AliasResult::MayAlias;
@@ -1234,7 +1308,7 @@ AliasResult BasicAAResult::aliasGEP(
// VarIndex = Scale*V.
const VariableGEPIndex &Var = DecompGEP1.VarIndices[0];
if (Var.Val.TruncBits == 0 &&
- isKnownNonZero(Var.Val.V, DL, 0, &AC, Var.CxtI, DT)) {
+ isKnownNonZero(Var.Val.V, SimplifyQuery(DL, DT, &AC, Var.CxtI))) {
// Check if abs(V*Scale) >= abs(Scale) holds in the presence of
// potentially wrapping math.
auto MultiplyByScaleNoWrap = [](const VariableGEPIndex &Var) {
@@ -1556,6 +1630,7 @@ AliasResult BasicAAResult::aliasCheck(const Value *V1, LocationSize V1Size,
const Value *HintO1 = getUnderlyingObject(Hint1);
const Value *HintO2 = getUnderlyingObject(Hint2);
+ DominatorTree *DT = getDT(AAQI);
auto ValidAssumeForPtrContext = [&](const Value *Ptr) {
if (const Instruction *PtrI = dyn_cast<Instruction>(Ptr)) {
return isValidAssumeForContext(Assume, PtrI, DT,
@@ -1735,7 +1810,7 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V,
if (!Inst || Inst->getParent()->isEntryBlock())
return true;
- return isNotInCycle(Inst, DT, /*LI*/ nullptr);
+ return isNotInCycle(Inst, getDT(AAQI), /*LI*/ nullptr);
}
/// Computes the symbolic difference between two de-composed GEPs.
@@ -1749,7 +1824,8 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
bool Found = false;
for (auto I : enumerate(DestGEP.VarIndices)) {
VariableGEPIndex &Dest = I.value();
- if (!isValueEqualInPotentialCycles(Dest.Val.V, Src.Val.V, AAQI) ||
+ if ((!isValueEqualInPotentialCycles(Dest.Val.V, Src.Val.V, AAQI) &&
+ !areBothVScale(Dest.Val.V, Src.Val.V)) ||
!Dest.Val.hasSameCastsAs(Src.Val))
continue;
@@ -1843,7 +1919,7 @@ BasicAAResult BasicAA::run(Function &F, FunctionAnalysisManager &AM) {
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
auto &AC = AM.getResult<AssumptionAnalysis>(F);
auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
- return BasicAAResult(F.getParent()->getDataLayout(), F, TLI, AC, DT);
+ return BasicAAResult(F.getDataLayout(), F, TLI, AC, DT);
}
BasicAAWrapperPass::BasicAAWrapperPass() : FunctionPass(ID) {
@@ -1871,7 +1947,7 @@ bool BasicAAWrapperPass::runOnFunction(Function &F) {
auto &TLIWP = getAnalysis<TargetLibraryInfoWrapperPass>();
auto &DTWP = getAnalysis<DominatorTreeWrapperPass>();
- Result.reset(new BasicAAResult(F.getParent()->getDataLayout(), F,
+ Result.reset(new BasicAAResult(F.getDataLayout(), F,
TLIWP.getTLI(F), ACT.getAssumptionCache(F),
&DTWP.getDomTree()));