[llvm] feat: Scev predicated overflow btc and testing (PR #208581)
Bavly Peter via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 30 10:46:05 PDT 2026
https://github.com/bavly-bob updated https://github.com/llvm/llvm-project/pull/208581
>From 9d2e6318c6b74e64381955c111ce3f05efe1a55c Mon Sep 17 00:00:00 2001
From: bavly-bob <bavlypeter84 at gmail.com>
Date: Thu, 9 Jul 2026 23:15:49 +0300
Subject: [PATCH 1/3] feat: Scev predicated overflow btc and testing
---
llvm/lib/Analysis/ScalarEvolution.cpp | 22 +++++++--
.../ScalarEvolution/fwrapv-assume-safety.ll | 34 ++++++++++++++
.../LoopVectorize/fwrapv-assume-safety.ll | 45 +++++++++++++++++++
.../Analysis/ScalarEvolutionTest.cpp | 32 +++++++++++++
4 files changed, 130 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Analysis/ScalarEvolution/fwrapv-assume-safety.ll
create mode 100644 llvm/test/Transforms/LoopVectorize/fwrapv-assume-safety.ll
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index ea2d72db97fb0..69f0b9c315a30 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13567,11 +13567,27 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
Stride = getUMaxExpr(Stride, getOne(Stride->getType()));
}
}
- } else if (!NoWrap) {
+ }else if (!NoWrap) {
// Avoid proven overflow cases: this will ensure that the backedge taken
// count will not generate any unsigned overflow.
- if (canIVOverflowOnLT(RHS, Stride, IsSigned))
- return getCouldNotCompute();
+ if (canIVOverflowOnLT(RHS, Stride, IsSigned)) {
+ if (!AllowPredicates)
+ return getCouldNotCompute();
+
+ unsigned BitWidth = getTypeSizeInBits(RHS->getType());
+ const SCEV *One = getOne(Stride->getType());
+ const SCEV *StrideMinusOne = getMinusSCEV(Stride, One);
+
+ APInt MaxStrideMinusOne = IsSigned ? getSignedRangeMax(StrideMinusOne)
+ : getUnsignedRangeMax(StrideMinusOne);
+ APInt Limit = (IsSigned ? APInt::getSignedMaxValue(BitWidth)
+ : APInt::getMaxValue(BitWidth)) -
+ MaxStrideMinusOne;
+
+ Predicates.push_back(getComparePredicate(
+ IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, RHS,
+ getConstant(Limit)));
+ }
}
// On all paths just preceeding, we established the following invariant:
diff --git a/llvm/test/Analysis/ScalarEvolution/fwrapv-assume-safety.ll b/llvm/test/Analysis/ScalarEvolution/fwrapv-assume-safety.ll
new file mode 100644
index 0000000000000..f8f7778cda507
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/fwrapv-assume-safety.ll
@@ -0,0 +1,34 @@
+; RUN: opt < %s -disable-output "-passes=print<scalar-evolution>" 2>&1 | FileCheck %s
+
+; Verify that ScalarEvolution can compute a predicated backedge-taken count
+; for a loop with a non-unit stride (stride = 3) and no 'nsw' flag on the
+; induction variable (e.g. from compilation under -fwrapv).
+; Without the predicate, the backedge-taken count is unpredictable.
+
+define void @fwrapv_stride3(ptr noalias %x, i32 %l, i32 %u) {
+; CHECK-LABEL: Determining loop execution counts for: @fwrapv_stride3
+; CHECK-NEXT: Loop %loop.body: Unpredictable backedge-taken count.
+; CHECK-NEXT: Loop %loop.body: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT: Loop %loop.body: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop.body: Predicated backedge-taken count is
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %u sle) 2147483645
+
+entry:
+ %cmp1 = icmp slt i32 %l, %u
+ br i1 %cmp1, label %loop.body, label %exit
+
+loop.body:
+ %i = phi i32 [ %l, %entry ], [ %i.next, %loop.body ]
+ %idxprom = sext i32 %i to i64
+ %arrayidx = getelementptr inbounds i32, ptr %x, i64 %idxprom
+ %val = load i32, ptr %arrayidx, align 4
+ %inc = add nsw i32 %val, 1
+ store i32 %inc, ptr %arrayidx, align 4
+ %i.next = add i32 %i, 3
+ %cmp = icmp slt i32 %i.next, %u
+ br i1 %cmp, label %loop.body, label %exit
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopVectorize/fwrapv-assume-safety.ll b/llvm/test/Transforms/LoopVectorize/fwrapv-assume-safety.ll
new file mode 100644
index 0000000000000..6987c4ba66201
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/fwrapv-assume-safety.ll
@@ -0,0 +1,45 @@
+; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S < %s | FileCheck %s
+
+; Verify that a loop with a non-unit stride (stride = 3) and no 'nsw' flag on the
+; induction variable (e.g. from compilation with -fwrapv) can be vectorized
+; by generating a runtime SCEV check to verify the lack of overflow/wrapping.
+
+define void @fwrapv_stride3(ptr noalias %x, i32 %l, i32 %u) {
+; CHECK-LABEL: @fwrapv_stride3(
+; CHECK: vector.scevcheck:
+; CHECK: %ident.check = icmp sgt i32 %u, 2147483645
+; CHECK: %mul = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 3, i32 {{.*}})
+; CHECK: %mul.result = extractvalue { i32, i1 } %mul, 0
+; CHECK: %mul.overflow = extractvalue { i32, i1 } %mul, 1
+; CHECK: [[IDENT:%.*]] = add i32 %l, %mul.result
+; CHECK: [[OVERFLOW:%.*]] = icmp slt i32 [[IDENT]], %l
+; CHECK: [[OVERFLOW2:%.*]] = or i1 [[OVERFLOW]], %mul.overflow
+; CHECK: [[CHECK:%.*]] = or i1 %ident.check, [[OVERFLOW2]]
+; CHECK: br i1 [[CHECK]], label %scalar.ph, label %vector.ph
+; CHECK: vector.body:
+; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body
+; CHECK: scalar.ph:
+; CHECK: [[RESUME_PHI:%.*]] = phi i32
+; CHECK: br label %loop.body
+
+entry:
+ %cmp1 = icmp slt i32 %l, %u
+ br i1 %cmp1, label %loop.body, label %exit
+
+loop.body:
+ %i = phi i32 [ %l, %entry ], [ %i.next, %loop.body ]
+ %idxprom = sext i32 %i to i64
+ %arrayidx = getelementptr inbounds i32, ptr %x, i64 %idxprom
+ %val = load i32, ptr %arrayidx, align 4
+ %inc = add nsw i32 %val, 1
+ store i32 %inc, ptr %arrayidx, align 4
+ %i.next = add i32 %i, 3
+ %cmp = icmp slt i32 %i.next, %u
+ br i1 %cmp, label %loop.body, label %exit, !llvm.loop !0
+
+exit:
+ ret void
+}
+
+!0 = distinct !{!0, !1}
+!1 = !{!"llvm.loop.vectorize.enable", i1 true}
diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
index 4bd4463dda787..849a7fec8fe51 100644
--- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
+++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -1495,6 +1495,38 @@ TEST_F(ScalarEvolutionsTest, ImpliedCond) {
});
}
+TEST_F(ScalarEvolutionsTest, PredicatedBackedgeTakenCountForOverflowingStride) {
+ LLVMContext C;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M = parseAssemblyString(
+ "define void @foo(i32 %n) { "
+ "entry: "
+ " br label %loop "
+ "loop: "
+ " %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] "
+ " %iv.next = add i32 %iv, 3 "
+ " %cmp = icmp slt i32 %iv, %n "
+ " br i1 %cmp, label %loop, label %exit "
+ "exit: "
+ " ret void "
+ "}",
+ Err, C);
+
+ ASSERT_TRUE(M && "Could not parse module?");
+ ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
+
+ runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+ const Loop *L = LI.begin() != LI.end() ? *LI.begin() : nullptr;
+ ASSERT_NE(L, nullptr);
+
+ SmallVector<const SCEVPredicate *, 4> Predicates;
+ const SCEV *BTC = SE.getPredicatedBackedgeTakenCount(L, Predicates);
+
+ EXPECT_FALSE(isa<SCEVCouldNotCompute>(BTC));
+ EXPECT_FALSE(Predicates.empty());
+ });
+}
+
TEST_F(ScalarEvolutionsTest, MatchURem) {
LLVMContext C;
SMDiagnostic Err;
>From c726c54a679e176bb2b9104eb5663a797154a313 Mon Sep 17 00:00:00 2001
From: bavly-bob <bavlypeter84 at gmail.com>
Date: Fri, 10 Jul 2026 17:12:07 +0300
Subject: [PATCH 2/3] [ScalarEvolution][test] Update expected test output
---
.../addrec-may-wrap-udiv-canonicalize.ll | 45 +++++++
.../ScalarEvolution/max-trip-count.ll | 23 ++++
.../trip-count-non-unit-stride.ll | 112 ++++++++++++++++++
3 files changed, 180 insertions(+)
diff --git a/llvm/test/Analysis/ScalarEvolution/addrec-may-wrap-udiv-canonicalize.ll b/llvm/test/Analysis/ScalarEvolution/addrec-may-wrap-udiv-canonicalize.ll
index e041c96371762..1132e7478c82a 100644
--- a/llvm/test/Analysis/ScalarEvolution/addrec-may-wrap-udiv-canonicalize.ll
+++ b/llvm/test/Analysis/ScalarEvolution/addrec-may-wrap-udiv-canonicalize.ll
@@ -28,6 +28,15 @@ define void @test_step2_div4(i64 %n) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + (0 smax %n))<nuw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 4611686018427387903
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is ((1 + (0 smax %n))<nuw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
;
entry:
br label %loop
@@ -78,6 +87,15 @@ define void @test_step3_div6(i64 %n) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((((-1 * (1 umin (0 smax %n)))<nuw><nsw> + (0 smax %n)) /u 3) + (1 umin (0 smax %n)))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775805
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 3074457345618258602
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775805
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is ((((-1 * (1 umin (0 smax %n)))<nuw><nsw> + (0 smax %n)) /u 3) + (1 umin (0 smax %n)))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775805
;
entry:
br label %loop
@@ -137,6 +155,15 @@ define void @test_step4_div4(i64 %n) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((3 + (0 smax %n))<nuw> /u 4)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775804
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 2305843009213693951
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775804
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is ((3 + (0 smax %n))<nuw> /u 4)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775804
;
entry:
br label %loop
@@ -219,6 +246,15 @@ define void @test_step2_start_outer_add_rec_step_16(i64 %n, i64 %m) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (({1,+,-16}<%outer.header> + ({0,+,16}<%outer.header> smax %n)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 9223372036854775807
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (({1,+,-16}<%outer.header> + ({0,+,16}<%outer.header> smax %n)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
; CHECK-NEXT: Loop %outer.header: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %outer.header: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %outer.header: Unpredictable symbolic max backedge-taken count.
@@ -335,6 +371,15 @@ define void @test_step2_div4_start_outer_add_rec_step_2(i64 %n, i64 %m) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (({1,+,-2}<%outer.header> + ({0,+,2}<%outer.header> smax %n)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 9223372036854775807
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (({1,+,-2}<%outer.header> + ({0,+,2}<%outer.header> smax %n)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 9223372036854775806
; CHECK-NEXT: Loop %outer.header: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %outer.header: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %outer.header: Unpredictable symbolic max backedge-taken count.
diff --git a/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll b/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
index 501aa963f9294..49051471297d0 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
@@ -446,6 +446,12 @@ define void @changing_end_bound4(i32 %start, ptr %n_addr, ptr %addr) {
; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i32 1073741823
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 2147483644
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is i32 1073741823
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 2147483644
;
entry:
br label %loop
@@ -573,10 +579,27 @@ define void @max_overflow_me(i8 %n) mustprogress {
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
; CHECK-NEXT: exit count for loop: i8 1
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for latch: i8 0
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 65
+; CHECK-EMPTY:
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i8 1
; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is i8 1
; CHECK-NEXT: symbolic max exit count for loop: i8 1
; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for latch: i8 0
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 65
+; CHECK-EMPTY:
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is i8 0
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 65
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i8 0
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 65
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is i8 0
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %n sle) 65
;
entry:
br label %loop
diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count-non-unit-stride.ll b/llvm/test/Analysis/ScalarEvolution/trip-count-non-unit-stride.ll
index b52b4a984296c..ef4d9a3ac43f6 100644
--- a/llvm/test/Analysis/ScalarEvolution/trip-count-non-unit-stride.ll
+++ b/llvm/test/Analysis/ScalarEvolution/trip-count-non-unit-stride.ll
@@ -14,11 +14,39 @@ define void @test_preinc_ult(i64 %len) {
; CHECK-NEXT: Determining loop execution counts for: @test_preinc_ult
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for loop: ((1 + %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for latch: ((-1 + (2 umax %len)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for loop: ((1 + %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for latch: ((-1 + (2 umax %len)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (((1 + %len) /u 2) umin ((-1 + (2 umax %len)) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 9223372036854775806
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (((1 + %len) /u 2) umin ((-1 + (2 umax %len)) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
;
start:
br label %loop
@@ -49,11 +77,39 @@ define void @test_postinc_ult(i64 %len) {
; CHECK-NEXT: Determining loop execution counts for: @test_postinc_ult
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for loop: ((1 umax %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for latch: ((-1 + (2 umax %len)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for loop: ((1 umax %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for latch: ((-1 + (2 umax %len)) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-EMPTY:
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (((-1 + (2 umax %len)) /u 2) umin ((1 umax %len) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 9223372036854775806
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (((-1 + (2 umax %len)) /u 2) umin ((1 umax %len) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len ule) -2
+; CHECK-NEXT: Compare predicate: %len ule) -2
;
start:
br label %loop
@@ -83,11 +139,39 @@ define void @test_preinc_slt(i64 %len) {
; CHECK-NEXT: Determining loop execution counts for: @test_preinc_slt
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for loop: ((1 + (0 smax %len))<nuw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for latch: ((-1 + (2 smax %len))<nsw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for loop: ((1 + (0 smax %len))<nuw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for latch: ((-1 + (2 smax %len))<nsw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (((1 + (0 smax %len))<nuw> /u 2) umin ((-1 + (2 smax %len))<nsw> /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 4611686018427387902
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (((1 + (0 smax %len))<nuw> /u 2) umin ((-1 + (2 smax %len))<nsw> /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
;
start:
br label %loop
@@ -118,11 +202,39 @@ define void @test_postinc_slt(i64 %len) {
; CHECK-NEXT: Determining loop execution counts for: @test_postinc_slt
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for loop: ((1 smax %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated exit count for latch: ((-1 + (2 smax %len))<nsw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
; CHECK-NEXT: symbolic max exit count for loop: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for loop: ((1 smax %len) /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
; CHECK-NEXT: symbolic max exit count for latch: ***COULDNOTCOMPUTE***
+; CHECK-NEXT: predicated symbolic max exit count for latch: ((-1 + (2 smax %len))<nsw> /u 2)
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-EMPTY:
+; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (((-1 + (2 smax %len))<nsw> /u 2) umin ((1 smax %len) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated constant max backedge-taken count is i64 4611686018427387902
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Loop %loop: Predicated symbolic max backedge-taken count is (((-1 + (2 smax %len))<nsw> /u 2) umin ((1 smax %len) /u 2))
+; CHECK-NEXT: Predicates:
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
+; CHECK-NEXT: Compare predicate: %len sle) 9223372036854775806
;
start:
br label %loop
>From 224f0409a32ab02d508657f876f61904469b6ed9 Mon Sep 17 00:00:00 2001
From: bavly-bob <bavlypeter84 at gmail.com>
Date: Thu, 30 Jul 2026 20:45:12 +0300
Subject: [PATCH 3/3] [SCEV] Avoid creating compare predicates before pointer
IV normalization howManyLessThans() can receive pointer-typed induction
variables. Creating a compare predicate before converting the pointer SCEV to
an integer SCEV violates SCEVComparePredicate's type equality invariant. Move
predicate creation after pointer normalization so both operands have matching
integer types.
---
llvm/lib/Analysis/ScalarEvolution.cpp | 38 ++++++++++++++++-----------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index b06bc2512f735..276732718e1fd 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -13535,26 +13535,12 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
Stride = getUMaxExpr(Stride, getOne(Stride->getType()));
}
}
- }else if (!NoWrap) {
+ } else if (!NoWrap) {
// Avoid proven overflow cases: this will ensure that the backedge taken
// count will not generate any unsigned overflow.
if (canIVOverflowOnLT(RHS, Stride, IsSigned)) {
if (!AllowPredicates)
return getCouldNotCompute();
-
- unsigned BitWidth = getTypeSizeInBits(RHS->getType());
- const SCEV *One = getOne(Stride->getType());
- const SCEV *StrideMinusOne = getMinusSCEV(Stride, One);
-
- APInt MaxStrideMinusOne = IsSigned ? getSignedRangeMax(StrideMinusOne)
- : getUnsignedRangeMax(StrideMinusOne);
- APInt Limit = (IsSigned ? APInt::getSignedMaxValue(BitWidth)
- : APInt::getMaxValue(BitWidth)) -
- MaxStrideMinusOne;
-
- Predicates.push_back(getComparePredicate(
- IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE, RHS,
- getConstant(Limit)));
}
}
@@ -13586,6 +13572,26 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
return RHS;
}
+ // Now that RHS has been converted to an integer type (if it was a pointer),
+ // we can safely build the overflow predicate. SCEVComparePredicate requires
+ // both operands to have identical LLVM types, which is guaranteed here
+ // because getConstant(Limit) uses the same BitWidth as RHS->getType().
+ if (!NoWrap && canIVOverflowOnLT(OrigRHS, Stride, IsSigned)) {
+ unsigned BitWidth = getTypeSizeInBits(RHS->getType());
+ const SCEV *One = getOne(Stride->getType());
+ const SCEV *StrideMinusOne = getMinusSCEV(Stride, One);
+
+ APInt MaxStrideMinusOne = IsSigned ? getSignedRangeMax(StrideMinusOne)
+ : getUnsignedRangeMax(StrideMinusOne);
+ APInt Limit = (IsSigned ? APInt::getSignedMaxValue(BitWidth)
+ : APInt::getMaxValue(BitWidth)) -
+ MaxStrideMinusOne;
+
+ Predicates.push_back(
+ getComparePredicate(IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE,
+ RHS, getConstant(Limit)));
+ }
+
const SCEV *End = nullptr, *BECount = nullptr,
*BECountIfBackedgeTaken = nullptr;
if (!isLoopInvariant(RHS, L)) {
@@ -16497,4 +16503,4 @@ const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr, const Loop *L) {
const SCEV *ScalarEvolution::applyLoopGuards(const SCEV *Expr,
const LoopGuards &Guards) {
return Guards.rewrite(Expr);
-}
+}
\ No newline at end of file
More information about the llvm-commits
mailing list