[llvm] [SCEV] Handle URem pattern in getRangeRef. (PR #174456)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 6 10:46:06 PST 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/174456
>From a5a62b61476dc22a4d8c09c1b2301fe97c0ce3c7 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 6 Jan 2026 10:45:33 +0000
Subject: [PATCH 1/5] [SCEV] Add urem tests with non-constant divisor.
---
llvm/test/Analysis/ScalarEvolution/urem-0.ll | 55 ++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/llvm/test/Analysis/ScalarEvolution/urem-0.ll b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
index 74031fe1eee73..ec5bfda99a06a 100644
--- a/llvm/test/Analysis/ScalarEvolution/urem-0.ll
+++ b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
@@ -86,3 +86,58 @@ define i32 @test_trunc_zext(i32 %arg) {
%sub = sub i32 %arg, %zext
ret i32 %sub
}
+
+define i8 @urem_var_divisor_unknown(i8 %a, i8 %d) {
+; CHECK-LABEL: 'urem_var_divisor_unknown'
+; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_unknown
+; CHECK-NEXT: %t0 = urem i8 %a, %d
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_unknown
+;
+ %t0 = urem i8 %a, %d
+ ret i8 %t0
+}
+
+define i8 @urem_var_divisor_ult_10(i8 %a, i8 range(i8 0, 10) %d) {
+; CHECK-LABEL: 'urem_var_divisor_ult_10'
+; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ult_10
+; CHECK-NEXT: %t0 = urem i8 %a, %d
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ult_10
+;
+ %t0 = urem i8 %a, %d
+ ret i8 %t0
+}
+
+define i8 @urem_var_divisor_ugt_0_ult_10(i8 %a, i8 range(i8 1, 10) %d) {
+; CHECK-LABEL: 'urem_var_divisor_ugt_0_ult_10'
+; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ugt_0_ult_10
+; CHECK-NEXT: %t0 = urem i8 %a, %d
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ugt_0_ult_10
+;
+ %t0 = urem i8 %a, %d
+ ret i8 %t0
+}
+
+define i8 @urem_var_divisor_ugt_1_ult_10(i8 %a, i8 range(i8 2, 10) %d) {
+; CHECK-LABEL: 'urem_var_divisor_ugt_1_ult_10'
+; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ugt_1_ult_10
+; CHECK-NEXT: %t0 = urem i8 %a, %d
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ugt_1_ult_10
+;
+ %t0 = urem i8 %a, %d
+ ret i8 %t0
+}
+
+define i8 @urem_var_divisor_signed(i8 %a, i8 range(i8 -19, 10) %d) {
+; CHECK-LABEL: 'urem_var_divisor_signed'
+; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_signed
+; CHECK-NEXT: %t0 = urem i8 %a, %d
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_signed
+;
+ %t0 = urem i8 %a, %d
+ ret i8 %t0
+}
>From 13496f9a30db274b405d7531ca75d2d1582ca77d Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 5 Jan 2026 12:30:55 +0000
Subject: [PATCH 2/5] [SCEV] URem range
https://alive2.llvm.org/ce/z/VPxe7C
---
llvm/lib/Analysis/ScalarEvolution.cpp | 15 +++++++++++++
.../trip-multiple-guard-info.ll | 2 +-
.../Analysis/ScalarEvolution/trip-multiple.ll | 12 +++++------
llvm/test/Analysis/ScalarEvolution/urem-0.ll | 2 +-
...-vectorization-fix-scalar-resume-values.ll | 21 +++++++------------
5 files changed, 30 insertions(+), 22 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 4dcf884823a61..3efdf5e436358 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6777,6 +6777,21 @@ const ConstantRange &ScalarEvolution::getRangeRef(
}
case scAddExpr: {
const SCEVAddExpr *Add = cast<SCEVAddExpr>(S);
+ // Check if this is a URem pattern: A - (A / B) * B, which is always < B.
+ const SCEV *URemLHS = nullptr, *URemRHS = nullptr;
+ if (SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED &&
+ match(S, m_scev_URem(m_SCEV(URemLHS), m_SCEV(URemRHS), *this))) {
+ ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
+ ConstantRange RHSRange = getRangeRef(URemRHS, SignHint, Depth + 1);
+ // URem result is always in [0, min(LHS, RHS - 1)] when RHS > 0.
+ if (RHSRange.getUnsignedMin().ugt(0)) {
+ APInt MaxVal = APIntOps::umin(LHSRange.getUnsignedMax(),
+ RHSRange.getUnsignedMax() - 1);
+ ConstantRange URemRange(APInt::getZero(BitWidth), MaxVal + 1);
+ ConservativeResult =
+ ConservativeResult.intersectWith(URemRange, RangeType);
+ }
+ }
ConstantRange X = getRangeRef(Add->getOperand(0), SignHint, Depth + 1);
unsigned WrapType = OBO::AnyWrap;
if (Add->hasNoSignedWrap())
diff --git a/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
index f35c48b3e6fc5..e1807a716bb26 100644
--- a/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
@@ -481,7 +481,7 @@ define void @test_trip_multiple_5(i32 %num) {
; CHECK-LABEL: 'test_trip_multiple_5'
; CHECK-NEXT: Classifying expressions for: @test_trip_multiple_5
; CHECK-NEXT: %u = urem i32 %num, 5
-; CHECK-NEXT: --> ((-5 * (%num /u 5)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-5 * (%num /u 5)) + %num) U: [0,5) S: full-set
; CHECK-NEXT: %i.010 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%for.body> U: [0,-2147483648) S: [0,-2147483648) Exits: (-1 + %num) LoopDispositions: { %for.body: Computable }
; CHECK-NEXT: %inc = add nuw nsw i32 %i.010, 1
diff --git a/llvm/test/Analysis/ScalarEvolution/trip-multiple.ll b/llvm/test/Analysis/ScalarEvolution/trip-multiple.ll
index bd0f603db942e..a7386066e096d 100644
--- a/llvm/test/Analysis/ScalarEvolution/trip-multiple.ll
+++ b/llvm/test/Analysis/ScalarEvolution/trip-multiple.ll
@@ -16,7 +16,7 @@ define void @trip_multiple_3(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_3'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_3
; CHECK-NEXT: %rem = urem i32 %num, 3
-; CHECK-NEXT: --> ((-3 * (%num /u 3)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-3 * (%num /u 3)) + %num) U: [0,3) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
@@ -85,7 +85,7 @@ define void @trip_multiple_5(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_5'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_5
; CHECK-NEXT: %rem = urem i32 %num, 5
-; CHECK-NEXT: --> ((-5 * (%num /u 5)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-5 * (%num /u 5)) + %num) U: [0,5) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
@@ -120,7 +120,7 @@ define void @trip_multiple_6(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_6'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_6
; CHECK-NEXT: %rem = urem i32 %num, 6
-; CHECK-NEXT: --> ((-6 * (%num /u 6)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-6 * (%num /u 6)) + %num) U: [0,6) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
@@ -155,7 +155,7 @@ define void @trip_multiple_7(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_7'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_7
; CHECK-NEXT: %rem = urem i32 %num, 7
-; CHECK-NEXT: --> ((-7 * (%num /u 7)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-7 * (%num /u 7)) + %num) U: [0,7) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
@@ -224,7 +224,7 @@ define void @trip_multiple_9(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_9'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_9
; CHECK-NEXT: %rem = urem i32 %num, 9
-; CHECK-NEXT: --> ((-9 * (%num /u 9)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-9 * (%num /u 9)) + %num) U: [0,9) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
@@ -258,7 +258,7 @@ define void @trip_multiple_10(i32 noundef %num) {
; CHECK-LABEL: 'trip_multiple_10'
; CHECK-NEXT: Classifying expressions for: @trip_multiple_10
; CHECK-NEXT: %rem = urem i32 %num, 10
-; CHECK-NEXT: --> ((-10 * (%num /u 10)) + %num) U: full-set S: full-set
+; CHECK-NEXT: --> ((-10 * (%num /u 10)) + %num) U: [0,10) S: full-set
; CHECK-NEXT: %or.cond = and i1 %cmp, %cmp14
; CHECK-NEXT: --> (%cmp14 umin %cmp) U: full-set S: full-set
; CHECK-NEXT: %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
diff --git a/llvm/test/Analysis/ScalarEvolution/urem-0.ll b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
index ec5bfda99a06a..657b32c157ac5 100644
--- a/llvm/test/Analysis/ScalarEvolution/urem-0.ll
+++ b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
@@ -5,7 +5,7 @@ define i8 @foo(i8 %a) {
; CHECK-LABEL: 'foo'
; CHECK-NEXT: Classifying expressions for: @foo
; CHECK-NEXT: %t0 = urem i8 %a, 27
-; CHECK-NEXT: --> ((-27 * (%a /u 27)) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-27 * (%a /u 27)) + %a) U: [0,27) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @foo
;
%t0 = urem i8 %a, 27
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/epilogue-vectorization-fix-scalar-resume-values.ll b/llvm/test/Transforms/LoopVectorize/AArch64/epilogue-vectorization-fix-scalar-resume-values.ll
index 4eacc55a99f72..5176bccfa388f 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/epilogue-vectorization-fix-scalar-resume-values.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/epilogue-vectorization-fix-scalar-resume-values.ll
@@ -18,30 +18,23 @@ define void @epilogue_vectorization_fix_scalar_resume_values(ptr %dst, i64 %n) {
; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[REM]], [[N_MOD_VF]]
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
; CHECK: [[VECTOR_BODY]]:
-; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[DST]], i64 [[INDEX]]
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[TMP0]], i64 16
-; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[TMP0]], align 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[DST]], i64 16
+; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[DST]], align 1
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[TMP1]], align 1
-; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 32
-; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP2]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]
+; CHECK-NEXT: br label %[[MIDDLE_BLOCK:.*]]
; CHECK: [[MIDDLE_BLOCK]]:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[REM]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[VEC_EPILOG_ITER_CHECK:.*]]
; CHECK: [[VEC_EPILOG_ITER_CHECK]]:
; CHECK-NEXT: [[MIN_EPILOG_ITERS_CHECK:%.*]] = icmp ult i64 [[N_MOD_VF]], 8
-; CHECK-NEXT: br i1 [[MIN_EPILOG_ITERS_CHECK]], label %[[VEC_EPILOG_SCALAR_PH]], label %[[VEC_EPILOG_PH]], !prof [[PROF3:![0-9]+]]
+; CHECK-NEXT: br i1 [[MIN_EPILOG_ITERS_CHECK]], label %[[VEC_EPILOG_SCALAR_PH]], label %[[VEC_EPILOG_PH]], !prof [[PROF0:![0-9]+]]
; CHECK: [[VEC_EPILOG_PH]]:
-; CHECK-NEXT: [[VEC_EPILOG_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ]
+; CHECK-NEXT: [[INDEX1:%.*]] = phi i64 [ [[N_VEC]], %[[VEC_EPILOG_ITER_CHECK]] ], [ 0, %[[VECTOR_MAIN_LOOP_ITER_CHECK]] ]
; CHECK-NEXT: br label %[[VEC_EPILOG_VECTOR_BODY:.*]]
; CHECK: [[VEC_EPILOG_VECTOR_BODY]]:
-; CHECK-NEXT: [[INDEX1:%.*]] = phi i64 [ [[VEC_EPILOG_RESUME_VAL]], %[[VEC_EPILOG_PH]] ], [ [[INDEX_NEXT2:%.*]], %[[VEC_EPILOG_VECTOR_BODY]] ]
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[DST]], i64 [[INDEX1]]
; CHECK-NEXT: store <8 x i8> zeroinitializer, ptr [[TMP3]], align 1
-; CHECK-NEXT: [[INDEX_NEXT2]] = add nuw i64 [[INDEX1]], 8
-; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[INDEX_NEXT2]], 0
-; CHECK-NEXT: br i1 [[TMP4]], label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]], label %[[VEC_EPILOG_VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
+; CHECK-NEXT: br label %[[VEC_EPILOG_MIDDLE_BLOCK:.*]]
; CHECK: [[VEC_EPILOG_MIDDLE_BLOCK]]:
; CHECK-NEXT: [[CMP_N3:%.*]] = icmp eq i64 [[REM]], 0
; CHECK-NEXT: br i1 [[CMP_N3]], label %[[EXIT]], label %[[VEC_EPILOG_SCALAR_PH]]
@@ -54,7 +47,7 @@ define void @epilogue_vectorization_fix_scalar_resume_values(ptr %dst, i64 %n) {
; CHECK-NEXT: store i8 0, ptr [[GEP_DST_IV]], align 1
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[EXIT_COND:%.*]] = icmp eq i64 [[IV_NEXT]], [[REM]]
-; CHECK-NEXT: br i1 [[EXIT_COND]], label %[[EXIT]], label %[[LOOP]], !llvm.loop [[LOOP5:![0-9]+]]
+; CHECK-NEXT: br i1 [[EXIT_COND]], label %[[EXIT]], label %[[LOOP]], !llvm.loop [[LOOP1:![0-9]+]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret void
;
>From 1001dda2d45e8b727babf67a75496cd9188356cd Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 6 Jan 2026 10:54:23 +0000
Subject: [PATCH 3/5] !fixup use ConstantRange::urem
---
llvm/lib/Analysis/ScalarEvolution.cpp | 12 ++++--------
llvm/test/Analysis/ScalarEvolution/urem-0.ll | 4 ++--
2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 3efdf5e436358..0e950dc7d7418 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6781,15 +6781,11 @@ const ConstantRange &ScalarEvolution::getRangeRef(
const SCEV *URemLHS = nullptr, *URemRHS = nullptr;
if (SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED &&
match(S, m_scev_URem(m_SCEV(URemLHS), m_SCEV(URemRHS), *this))) {
- ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
ConstantRange RHSRange = getRangeRef(URemRHS, SignHint, Depth + 1);
- // URem result is always in [0, min(LHS, RHS - 1)] when RHS > 0.
- if (RHSRange.getUnsignedMin().ugt(0)) {
- APInt MaxVal = APIntOps::umin(LHSRange.getUnsignedMax(),
- RHSRange.getUnsignedMax() - 1);
- ConstantRange URemRange(APInt::getZero(BitWidth), MaxVal + 1);
- ConservativeResult =
- ConservativeResult.intersectWith(URemRange, RangeType);
+ if (!RHSRange.contains(APInt::getZero(RHSRange.getBitWidth()))) {
+ ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
+ ConservativeResult = ConservativeResult.intersectWith(
+ LHSRange.urem(RHSRange), RangeType);
}
}
ConstantRange X = getRangeRef(Add->getOperand(0), SignHint, Depth + 1);
diff --git a/llvm/test/Analysis/ScalarEvolution/urem-0.ll b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
index 657b32c157ac5..7f1260477199f 100644
--- a/llvm/test/Analysis/ScalarEvolution/urem-0.ll
+++ b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
@@ -113,7 +113,7 @@ define i8 @urem_var_divisor_ugt_0_ult_10(i8 %a, i8 range(i8 1, 10) %d) {
; CHECK-LABEL: 'urem_var_divisor_ugt_0_ult_10'
; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ugt_0_ult_10
; CHECK-NEXT: %t0 = urem i8 %a, %d
-; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: [0,9) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ugt_0_ult_10
;
%t0 = urem i8 %a, %d
@@ -124,7 +124,7 @@ define i8 @urem_var_divisor_ugt_1_ult_10(i8 %a, i8 range(i8 2, 10) %d) {
; CHECK-LABEL: 'urem_var_divisor_ugt_1_ult_10'
; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ugt_1_ult_10
; CHECK-NEXT: %t0 = urem i8 %a, %d
-; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: [0,9) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ugt_1_ult_10
;
%t0 = urem i8 %a, %d
>From b1dcccb0f0cee299efbf6eb5b13cfb535aed05df Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 6 Jan 2026 17:27:12 +0000
Subject: [PATCH 4/5] !fixup remove 0 check
---
llvm/lib/Analysis/ScalarEvolution.cpp | 8 +++-----
.../Analysis/ScalarEvolution/trip-multiple-guard-info.ll | 2 +-
llvm/test/Analysis/ScalarEvolution/urem-0.ll | 6 +++---
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 0e950dc7d7418..dc6afaae60710 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6781,12 +6781,10 @@ const ConstantRange &ScalarEvolution::getRangeRef(
const SCEV *URemLHS = nullptr, *URemRHS = nullptr;
if (SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED &&
match(S, m_scev_URem(m_SCEV(URemLHS), m_SCEV(URemRHS), *this))) {
+ ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
ConstantRange RHSRange = getRangeRef(URemRHS, SignHint, Depth + 1);
- if (!RHSRange.contains(APInt::getZero(RHSRange.getBitWidth()))) {
- ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
- ConservativeResult = ConservativeResult.intersectWith(
- LHSRange.urem(RHSRange), RangeType);
- }
+ ConservativeResult = ConservativeResult.intersectWith(
+ LHSRange.urem(RHSRange), RangeType);
}
ConstantRange X = getRangeRef(Add->getOperand(0), SignHint, Depth + 1);
unsigned WrapType = OBO::AnyWrap;
diff --git a/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
index e1807a716bb26..aeda7f61a7575 100644
--- a/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/trip-multiple-guard-info.ll
@@ -721,7 +721,7 @@ define void @test_urem_non_constant(ptr %dst, i32 %a, i32 %b) {
; CHECK-LABEL: 'test_urem_non_constant'
; CHECK-NEXT: Classifying expressions for: @test_urem_non_constant
; CHECK-NEXT: %rem = urem i32 %a, %b
-; CHECK-NEXT: --> ((-1 * (%a /u %b) * %b) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %b) * %b) + %a) U: [0,-1) S: full-set
; CHECK-NEXT: %and.0 = and i1 %pre.0, %pre.1
; CHECK-NEXT: --> (%pre.1 umin %pre.0) U: full-set S: full-set
; CHECK-NEXT: %and.1 = and i1 %and.0, %pre.2
diff --git a/llvm/test/Analysis/ScalarEvolution/urem-0.ll b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
index 7f1260477199f..4730649297045 100644
--- a/llvm/test/Analysis/ScalarEvolution/urem-0.ll
+++ b/llvm/test/Analysis/ScalarEvolution/urem-0.ll
@@ -91,7 +91,7 @@ define i8 @urem_var_divisor_unknown(i8 %a, i8 %d) {
; CHECK-LABEL: 'urem_var_divisor_unknown'
; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_unknown
; CHECK-NEXT: %t0 = urem i8 %a, %d
-; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: [0,-1) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_unknown
;
%t0 = urem i8 %a, %d
@@ -102,7 +102,7 @@ define i8 @urem_var_divisor_ult_10(i8 %a, i8 range(i8 0, 10) %d) {
; CHECK-LABEL: 'urem_var_divisor_ult_10'
; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_ult_10
; CHECK-NEXT: %t0 = urem i8 %a, %d
-; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: [0,9) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_ult_10
;
%t0 = urem i8 %a, %d
@@ -135,7 +135,7 @@ define i8 @urem_var_divisor_signed(i8 %a, i8 range(i8 -19, 10) %d) {
; CHECK-LABEL: 'urem_var_divisor_signed'
; CHECK-NEXT: Classifying expressions for: @urem_var_divisor_signed
; CHECK-NEXT: %t0 = urem i8 %a, %d
-; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: full-set S: full-set
+; CHECK-NEXT: --> ((-1 * (%a /u %d) * %d) + %a) U: [0,-1) S: full-set
; CHECK-NEXT: Determining loop execution counts for: @urem_var_divisor_signed
;
%t0 = urem i8 %a, %d
>From acb295033245a7c297899bb54dded4f9e0835181 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 6 Jan 2026 18:45:40 +0000
Subject: [PATCH 5/5] !fixup fix formatting
---
llvm/lib/Analysis/ScalarEvolution.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index dc6afaae60710..3bb9c93deb0b3 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -6783,8 +6783,8 @@ const ConstantRange &ScalarEvolution::getRangeRef(
match(S, m_scev_URem(m_SCEV(URemLHS), m_SCEV(URemRHS), *this))) {
ConstantRange LHSRange = getRangeRef(URemLHS, SignHint, Depth + 1);
ConstantRange RHSRange = getRangeRef(URemRHS, SignHint, Depth + 1);
- ConservativeResult = ConservativeResult.intersectWith(
- LHSRange.urem(RHSRange), RangeType);
+ ConservativeResult =
+ ConservativeResult.intersectWith(LHSRange.urem(RHSRange), RangeType);
}
ConstantRange X = getRangeRef(Add->getOperand(0), SignHint, Depth + 1);
unsigned WrapType = OBO::AnyWrap;
More information about the llvm-commits
mailing list