Skip to content

Commit

Permalink
[Analysis] Teach isDereferenceableAndAlignedInLoop about SCEV predica…
Browse files Browse the repository at this point in the history
…tes (llvm#106562)

Currently if a loop contains loads that we can prove at compile time
are dereferenceable when certain conditions are satisfied the function
isDereferenceableAndAlignedInLoop will still return false because
getSmallConstantMaxTripCount will return 0 when SCEV predicates
are required. This patch changes getSmallConstantMaxTripCount to take
an optional Predicates pointer argument so that we can permit
functions such as isDereferenceableAndAlignedInLoop to consider more
cases.
  • Loading branch information
david-arm authored Sep 23, 2024
1 parent 6fc2451 commit 02ee96e
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 34 deletions.
14 changes: 9 additions & 5 deletions llvm/include/llvm/Analysis/Loads.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class LoadInst;
class Loop;
class MemoryLocation;
class ScalarEvolution;
class SCEVPredicate;
template <typename T> class SmallVectorImpl;
class TargetLibraryInfo;

/// Return true if this is always a dereferenceable pointer. If the context
Expand Down Expand Up @@ -81,14 +83,16 @@ bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size,
/// that required by the header itself and could be hoisted into the header
/// if desired.) This is more powerful than the variants above when the
/// address loaded from is analyzeable by SCEV.
bool isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L,
ScalarEvolution &SE, DominatorTree &DT,
AssumptionCache *AC = nullptr);
bool isDereferenceableAndAlignedInLoop(
LoadInst *LI, Loop *L, ScalarEvolution &SE, DominatorTree &DT,
AssumptionCache *AC = nullptr,
SmallVectorImpl<const SCEVPredicate *> *Predicates = nullptr);

/// Return true if the loop \p L cannot fault on any iteration and only
/// contains read-only memory accesses.
bool isDereferenceableReadOnlyLoop(Loop *L, ScalarEvolution *SE,
DominatorTree *DT, AssumptionCache *AC);
bool isDereferenceableReadOnlyLoop(
Loop *L, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC,
SmallVectorImpl<const SCEVPredicate *> *Predicates = nullptr);

/// Return true if we know that executing a load from this value cannot trap.
///
Expand Down
20 changes: 16 additions & 4 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,11 @@ class ScalarEvolution {

/// Returns the upper bound of the loop trip count as a normal unsigned
/// value.
/// Returns 0 if the trip count is unknown or not constant.
unsigned getSmallConstantMaxTripCount(const Loop *L);
/// Returns 0 if the trip count is unknown, not constant or requires
/// SCEV predicates and \p Predicates is nullptr.
unsigned getSmallConstantMaxTripCount(
const Loop *L,
SmallVectorImpl<const SCEVPredicate *> *Predicates = nullptr);

/// Returns the largest constant divisor of the trip count as a normal
/// unsigned value, if possible. This means that the actual trip count is
Expand Down Expand Up @@ -905,6 +908,13 @@ class ScalarEvolution {
return getBackedgeTakenCount(L, ConstantMaximum);
}

/// Similar to getConstantMaxBackedgeTakenCount, except it will add a set of
/// SCEV predicates to Predicates that are required to be true in order for
/// the answer to be correct. Predicates can be checked with run-time
/// checks and can be used to perform loop versioning.
const SCEV *getPredicatedConstantMaxBackedgeTakenCount(
const Loop *L, SmallVectorImpl<const SCEVPredicate *> &Predicates);

/// When successful, this returns a SCEV that is greater than or equal
/// to (i.e. a "conservative over-approximation") of the value returend by
/// getBackedgeTakenCount. If such a value cannot be computed, it returns the
Expand Down Expand Up @@ -1506,7 +1516,7 @@ class ScalarEvolution {

/// Expression indicating the least constant maximum backedge-taken count of
/// the loop that is known, or a SCEVCouldNotCompute. This expression is
/// only valid if the redicates associated with all loop exits are true.
/// only valid if the predicates associated with all loop exits are true.
const SCEV *ConstantMax = nullptr;

/// Indicating if \c ExitNotTaken has an element for every exiting block in
Expand Down Expand Up @@ -1585,7 +1595,9 @@ class ScalarEvolution {
}

/// Get the constant max backedge taken count for the loop.
const SCEV *getConstantMax(ScalarEvolution *SE) const;
const SCEV *getConstantMax(
ScalarEvolution *SE,
SmallVectorImpl<const SCEVPredicate *> *Predicates = nullptr) const;

/// Get the constant max backedge taken count for the particular loop exit.
const SCEV *getConstantMax(
Expand Down
17 changes: 8 additions & 9 deletions llvm/lib/Analysis/Loads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,9 @@ static bool AreEquivalentAddressValues(const Value *A, const Value *B) {
return false;
}

bool llvm::isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L,
ScalarEvolution &SE,
DominatorTree &DT,
AssumptionCache *AC) {
bool llvm::isDereferenceableAndAlignedInLoop(
LoadInst *LI, Loop *L, ScalarEvolution &SE, DominatorTree &DT,
AssumptionCache *AC, SmallVectorImpl<const SCEVPredicate *> *Predicates) {
auto &DL = LI->getDataLayout();
Value *Ptr = LI->getPointerOperand();

Expand All @@ -304,7 +303,7 @@ bool llvm::isDereferenceableAndAlignedInLoop(LoadInst *LI, Loop *L,
if (!Step)
return false;

auto TC = SE.getSmallConstantMaxTripCount(L);
auto TC = SE.getSmallConstantMaxTripCount(L, Predicates);
if (!TC)
return false;

Expand Down Expand Up @@ -810,13 +809,13 @@ bool llvm::canReplacePointersIfEqual(const Value *From, const Value *To,
return isPointerAlwaysReplaceable(From, To, DL);
}

bool llvm::isDereferenceableReadOnlyLoop(Loop *L, ScalarEvolution *SE,
DominatorTree *DT,
AssumptionCache *AC) {
bool llvm::isDereferenceableReadOnlyLoop(
Loop *L, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC,
SmallVectorImpl<const SCEVPredicate *> *Predicates) {
for (BasicBlock *BB : L->blocks()) {
for (Instruction &I : *BB) {
if (auto *LI = dyn_cast<LoadInst>(&I)) {
if (!isDereferenceableAndAlignedInLoop(LI, L, *SE, *DT, AC))
if (!isDereferenceableAndAlignedInLoop(LI, L, *SE, *DT, AC, Predicates))
return false;
} else if (I.mayReadFromMemory() || I.mayWriteToMemory() || I.mayThrow())
return false;
Expand Down
52 changes: 42 additions & 10 deletions llvm/lib/Analysis/ScalarEvolution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8191,10 +8191,13 @@ ScalarEvolution::getSmallConstantTripCount(const Loop *L,
return getConstantTripCount(ExitCount);
}

unsigned ScalarEvolution::getSmallConstantMaxTripCount(const Loop *L) {
unsigned ScalarEvolution::getSmallConstantMaxTripCount(
const Loop *L, SmallVectorImpl<const SCEVPredicate *> *Predicates) {

const auto *MaxExitCount =
dyn_cast<SCEVConstant>(getConstantMaxBackedgeTakenCount(L));
return getConstantTripCount(MaxExitCount);
Predicates ? getPredicatedConstantMaxBackedgeTakenCount(L, *Predicates)
: getConstantMaxBackedgeTakenCount(L);
return getConstantTripCount(dyn_cast<SCEVConstant>(MaxExitCount));
}

unsigned ScalarEvolution::getSmallConstantTripMultiple(const Loop *L) {
Expand Down Expand Up @@ -8303,6 +8306,11 @@ const SCEV *ScalarEvolution::getPredicatedSymbolicMaxBackedgeTakenCount(
return getPredicatedBackedgeTakenInfo(L).getSymbolicMax(L, this, &Preds);
}

const SCEV *ScalarEvolution::getPredicatedConstantMaxBackedgeTakenCount(
const Loop *L, SmallVectorImpl<const SCEVPredicate *> &Preds) {
return getPredicatedBackedgeTakenInfo(L).getConstantMax(this, &Preds);
}

bool ScalarEvolution::isBackedgeTakenCountMaxOrZero(const Loop *L) {
return getBackedgeTakenInfo(L).isConstantMaxOrZero(this);
}
Expand Down Expand Up @@ -8624,15 +8632,19 @@ ScalarEvolution::BackedgeTakenInfo::getExitNotTaken(
}

/// getConstantMax - Get the constant max backedge taken count for the loop.
const SCEV *
ScalarEvolution::BackedgeTakenInfo::getConstantMax(ScalarEvolution *SE) const {
auto PredicateNotAlwaysTrue = [](const ExitNotTakenInfo &ENT) {
return !ENT.hasAlwaysTruePredicate();
};

if (!getConstantMax() || any_of(ExitNotTaken, PredicateNotAlwaysTrue))
const SCEV *ScalarEvolution::BackedgeTakenInfo::getConstantMax(
ScalarEvolution *SE,
SmallVectorImpl<const SCEVPredicate *> *Predicates) const {
if (!getConstantMax())
return SE->getCouldNotCompute();

for (const auto &ENT : ExitNotTaken)
if (!ENT.hasAlwaysTruePredicate()) {
if (!Predicates)
return SE->getCouldNotCompute();
append_range(*Predicates, ENT.Predicates);
}

assert((isa<SCEVCouldNotCompute>(getConstantMax()) ||
isa<SCEVConstant>(getConstantMax())) &&
"No point in having a non-constant max backedge taken count!");
Expand Down Expand Up @@ -13749,8 +13761,28 @@ static void PrintLoopInfo(raw_ostream &OS, ScalarEvolution *SE,
for (const auto *P : Preds)
P->print(OS, 4);
}
Preds.clear();

auto *PredConstantMax =
SE->getPredicatedConstantMaxBackedgeTakenCount(L, Preds);
if (PredConstantMax != ConstantBTC) {
assert(!Preds.empty() &&
"different predicated constant max BTC but no predicates");
OS << "Loop ";
L->getHeader()->printAsOperand(OS, /*PrintType=*/false);
OS << ": ";
if (!isa<SCEVCouldNotCompute>(PredConstantMax)) {
OS << "Predicated constant max backedge-taken count is ";
PrintSCEVWithTypeHint(OS, PredConstantMax);
} else
OS << "Unpredictable predicated constant max backedge-taken count.";
OS << "\n";
OS << " Predicates:\n";
for (const auto *P : Preds)
P->print(OS, 4);
}
Preds.clear();

auto *PredSymbolicMax =
SE->getPredicatedSymbolicMaxBackedgeTakenCount(L, Preds);
if (SymbolicBTC != PredSymbolicMax) {
Expand Down
12 changes: 10 additions & 2 deletions llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1334,11 +1334,17 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() {
// we restrict this to loads; stores are more complicated due to
// concurrency restrictions.
ScalarEvolution &SE = *PSE.getSE();
SmallVector<const SCEVPredicate *, 4> Predicates;
for (Instruction &I : *BB) {
LoadInst *LI = dyn_cast<LoadInst>(&I);
// Pass the Predicates pointer to isDereferenceableAndAlignedInLoop so
// that it will consider loops that need guarding by SCEV checks. The
// vectoriser will generate these checks if we decide to vectorise.
if (LI && !LI->getType()->isVectorTy() && !mustSuppressSpeculation(*LI) &&
isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT, AC))
isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT, AC,
&Predicates))
SafePointers.insert(LI->getPointerOperand());
Predicates.clear();
}
}

Expand Down Expand Up @@ -1564,7 +1570,9 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
"Expected latch predecessor to be the early exiting block");

// TODO: Handle loops that may fault.
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC)) {
Predicates.clear();
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC,
&Predicates)) {
reportVectorizationFailure(
"Loop may fault",
"Cannot vectorize potentially faulting early exit loop",
Expand Down
6 changes: 6 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/exit-count-non-strict.ll
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ define void @ule_from_zero_no_nuw(i32 %M, i32 %N) {
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((zext i32 %N to i64) umin (1 + (zext i32 %M to i64))<nuw><nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%loop> Added Flags: <nusw>
; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 4294967295
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%loop> Added Flags: <nusw>
; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is ((zext i32 %N to i64) umin (1 + (zext i32 %M to i64))<nuw><nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%loop> Added Flags: <nusw>
Expand Down Expand Up @@ -238,6 +241,9 @@ define void @sle_from_int_min_no_nsw(i32 %M, i32 %N) {
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((zext i32 (-2147483648 + %N) to i64) umin (2147483649 + (sext i32 %M to i64))<nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-2147483648,+,1}<%loop> Added Flags: <nssw>
; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 4294967295
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-2147483648,+,1}<%loop> Added Flags: <nssw>
; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is ((zext i32 (-2147483648 + %N) to i64) umin (2147483649 + (sext i32 %M to i64))<nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-2147483648,+,1}<%loop> Added Flags: <nssw>
Expand Down
6 changes: 6 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ define void @sle_pre_inc_infinite(i32 %len) {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (0 smax (1 + (sext i32 %len to i64))<nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nssw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i64 2147483648
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nssw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (0 smax (1 + (sext i32 %len to i64))<nsw>)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nssw>
Expand Down Expand Up @@ -130,6 +133,9 @@ define void @ule_pre_inc_infinite(i32 %len) {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + (zext i32 %len to i64))<nuw><nsw>
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i64 4294967296
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (1 + (zext i32 %len to i64))<nuw><nsw>
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/ne-overflow.ll
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ define void @test_zext(i64 %N) mustprogress {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (%N /u 2)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,2}<nuw><%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i64 9223372036854775807
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,2}<nuw><%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (%N /u 2)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,2}<nuw><%for.body> Added Flags: <nusw>
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/predicated-exit-count.ll
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ define i32 @multiple_exits_with_predicates(ptr %src1, ptr readonly %src2, i32 %e
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
; CHECK-EMPTY:
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i32 1023
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (1023 umin (-1 + (1 umax %end)))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ define void @test1(i64 %x, ptr %a, ptr %b) {
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
; CHECK-EMPTY:
; CHECK-NEXT: Loop %header: Predicated constant max backedge-taken count is i64 -2
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
; CHECK-NEXT: Loop %header: Predicated symbolic max backedge-taken count is (-1 + (1 umax %x))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
Expand Down Expand Up @@ -71,6 +74,9 @@ define void @test2(i64 %x, ptr %a) {
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
; CHECK-EMPTY:
; CHECK-NEXT: Loop %header: Predicated constant max backedge-taken count is i64 -2
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
; CHECK-NEXT: Loop %header: Predicated symbolic max backedge-taken count is (-1 + (1 umax %x))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%header> Added Flags: <nusw>
Expand Down
15 changes: 15 additions & 0 deletions llvm/test/Analysis/ScalarEvolution/trip-count-implied-addrec.ll
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ define void @nw_implies_nsw(i16 %n) mustprogress {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (128 + (-128 smax %n))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-128,+,1}<%for.body> Added Flags: <nssw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i16 -32641
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-128,+,1}<%for.body> Added Flags: <nssw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (128 + (-128 smax %n))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {-128,+,1}<%for.body> Added Flags: <nssw>
Expand Down Expand Up @@ -110,6 +113,9 @@ define void @actually_infinite() {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is i16 257
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i16 257
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is i16 257
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {0,+,1}<%for.body> Added Flags: <nusw>
Expand Down Expand Up @@ -138,6 +144,9 @@ define void @rhs_mustexit_1(i16 %n.raw) mustprogress {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (-1 + (1 umax (-1 + (zext i8 (trunc i16 %n.raw to i8) to i16))<nsw>))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<nw><%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i16 -2
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<nw><%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (-1 + (1 umax (-1 + (zext i8 (trunc i16 %n.raw to i8) to i16))<nsw>))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<nw><%for.body> Added Flags: <nusw>
Expand Down Expand Up @@ -266,6 +275,9 @@ define void @neg_rhs_maybe_infinite(i16 %n.raw) {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (-1 + (1 umax (-1 + (zext i8 (trunc i16 %n.raw to i8) to i16))<nsw>))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i16 -2
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is (-1 + (1 umax (-1 + (zext i8 (trunc i16 %n.raw to i8) to i16))<nsw>))
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {1,+,1}<%for.body> Added Flags: <nusw>
Expand Down Expand Up @@ -391,6 +403,9 @@ define void @ult_constant_rhs_stride2_neg(i16 %n.raw, i8 %start) {
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is ((256 + (-1 * (zext i8 (2 + %start) to i16))<nsw>)<nsw> /u 2)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {(2 + %start),+,2}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated constant max backedge-taken count is i16 128
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {(2 + %start),+,2}<%for.body> Added Flags: <nusw>
; CHECK-NEXT: Loop %for.body: Predicated symbolic max backedge-taken count is ((256 + (-1 * (zext i8 (2 + %start) to i16))<nsw>)<nsw> /u 2)
; CHECK-NEXT: Predicates:
; CHECK-NEXT: {(2 + %start),+,2}<%for.body> Added Flags: <nusw>
Expand Down
Loading

0 comments on commit 02ee96e

Please sign in to comment.