[llvm] [SCEV] Simplify `udiv` equality comparisons against 0 (PR #218084)
Justin Fargnoli via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 09:02:37 PDT 2026
https://github.com/justinfargnoli updated https://github.com/llvm/llvm-project/pull/218084
>From c0ea2e1d194afed4e85a8ed12d6adc087bbedd2f Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Tue, 25 Aug 2026 20:44:33 +0000
Subject: [PATCH 1/5] pre-commit tests
---
.../Transforms/IndVarSimplify/udiv-icmp.ll | 247 ++++++++++++++++++
.../runtime-unroll-scev-udiv-entry-guard.ll | 118 +++++++++
2 files changed, 365 insertions(+)
create mode 100644 llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
create mode 100644 llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
diff --git a/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll b/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
new file mode 100644
index 0000000000000..d03a4d9edfe82
--- /dev/null
+++ b/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
@@ -0,0 +1,247 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -S -passes='loop(indvars)' | FileCheck %s
+
+define i1 @quotient_eq_zero(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_eq_zero(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp eq i64 [[Q]], 0
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp eq i64 %q, 0
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp ult i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @quotient_ule_zero(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_ule_zero(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp ule i64 [[Q]], 0
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp ule i64 %q, 0
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp ult i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @quotient_ult_one(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_ult_one(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp ult i64 [[Q]], 1
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp ult i64 %q, 1
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp ult i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @quotient_ne_zero(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_ne_zero(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp ne i64 [[Q]], 0
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp ne i64 %q, 0
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp uge i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @quotient_ugt_zero(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_ugt_zero(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp ugt i64 [[Q]], 0
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp ugt i64 %q, 0
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp uge i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @quotient_uge_one(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @quotient_uge_one(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp uge i64 [[Q]], 1
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp uge i64 %q, 1
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp uge i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
+
+define i1 @constant_on_left(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @constant_on_left(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
+; CHECK-NEXT: [[GUARD:%.*]] = icmp ult i64 0, [[Q]]
+; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
+; CHECK: [[LOOP_PREHEADER]]:
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
+; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
+; CHECK: [[EXIT_LOOPEXIT]]:
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: ret i1 [[RESULT]]
+;
+entry:
+ %q = udiv i64 %a, %b
+ %guard = icmp ult i64 0, %q
+ br i1 %guard, label %loop, label %exit
+
+loop:
+ %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
+ %cmp = icmp uge i64 %same, %b
+ %same.next = add i64 %same, 1
+ br i1 false, label %loop, label %exit
+
+exit:
+ %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
+ ret i1 %result
+}
diff --git a/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll b/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
new file mode 100644
index 0000000000000..01beac717a256
--- /dev/null
+++ b/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
@@ -0,0 +1,118 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes='loop-unroll<O3;runtime>' < %s | FileCheck %s
+
+define void @openmp_loop(
+; CHECK-LABEL: define void @openmp_loop(
+; CHECK-SAME: ptr [[LOWER_BOUND_PTR:%.*]], ptr [[DENOMINATOR_PTR:%.*]], i64 [[OUTER_LIMIT:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br label %[[OUTER:.*]]
+; CHECK: [[OUTER]]:
+; CHECK-NEXT: [[OUTER_INDEX:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[NEXT_OUTER_INDEX:%.*]], %[[OUTER_LATCH:.*]] ]
+; CHECK-NEXT: [[LOWER_BOUND_I32:%.*]] = load i32, ptr [[LOWER_BOUND_PTR]], align 4
+; CHECK-NEXT: [[DENOMINATOR_I32:%.*]] = load i32, ptr [[DENOMINATOR_PTR]], align 4
+; CHECK-NEXT: [[LOWER_BOUND:%.*]] = zext i32 [[LOWER_BOUND_I32]] to i64
+; CHECK-NEXT: [[DENOMINATOR:%.*]] = zext i32 [[DENOMINATOR_I32]] to i64
+; CHECK-NEXT: [[LOWER_BOUND_TOO_LARGE:%.*]] = icmp ugt i32 [[LOWER_BOUND_I32]], 35
+; CHECK-NEXT: br i1 [[LOWER_BOUND_TOO_LARGE]], label %[[OUTER_LATCH]], label %[[COMPUTE_TRIP_COUNT:.*]]
+; CHECK: [[COMPUTE_TRIP_COUNT]]:
+; CHECK-NEXT: [[DIFFERENCE:%.*]] = sub nsw i64 [[DENOMINATOR]], [[LOWER_BOUND]]
+; CHECK-NEXT: [[NUMERATOR:%.*]] = add nsw i64 [[DIFFERENCE]], 35
+; CHECK-NEXT: [[QUOTIENT:%.*]] = udiv i64 [[NUMERATOR]], [[DENOMINATOR]]
+; CHECK-NEXT: [[SKIP_INNER:%.*]] = icmp ult i64 [[NUMERATOR]], [[DENOMINATOR]]
+; CHECK-NEXT: br i1 [[SKIP_INNER]], label %[[OUTER_LATCH]], label %[[INNER_EPIL_PREHEADER:.*]]
+; CHECK: [[INNER_EPIL_PREHEADER]]:
+; CHECK-NEXT: br label %[[INNER_EPIL:.*]]
+; CHECK: [[INNER_EPIL]]:
+; CHECK-NEXT: [[COUNT_EPIL:%.*]] = phi i64 [ [[NEXT_EPIL:%.*]], %[[INNER_EPIL]] ], [ [[QUOTIENT]], %[[INNER_EPIL_PREHEADER]] ]
+; CHECK-NEXT: [[OFFSET_EPIL:%.*]] = phi i64 [ [[NEXT_OFFSET_EPIL:%.*]], %[[INNER_EPIL]] ], [ 0, %[[INNER_EPIL_PREHEADER]] ]
+; CHECK-NEXT: [[NEXT_EPIL]] = add i64 [[COUNT_EPIL]], -1
+; CHECK-NEXT: [[NEXT_OFFSET_EPIL]] = add i64 [[OFFSET_EPIL]], [[DENOMINATOR]]
+; CHECK-NEXT: [[CONTINUE_EPIL:%.*]] = icmp ugt i64 [[COUNT_EPIL]], 1
+; CHECK-NEXT: br i1 [[CONTINUE_EPIL]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_LOOPEXIT:.*]]
+; CHECK: [[OUTER_LATCH_LOOPEXIT]]:
+; CHECK-NEXT: br label %[[OUTER_LATCH]]
+; CHECK: [[OUTER_LATCH]]:
+; CHECK-NEXT: call void @barrier()
+; CHECK-NEXT: [[NEXT_OUTER_INDEX]] = add i64 [[OUTER_INDEX]], 1
+; CHECK-NEXT: [[CONTINUE_OUTER:%.*]] = icmp ult i64 [[NEXT_OUTER_INDEX]], [[OUTER_LIMIT]]
+; CHECK-NEXT: br i1 [[CONTINUE_OUTER]], label %[[OUTER]], label %[[EXIT:.*]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+ ptr %lower_bound_ptr, ptr %denominator_ptr, i64 %outer_limit) {
+entry:
+ br label %outer
+
+outer:
+ %outer_index = phi i64 [ 0, %entry ], [ %next_outer_index, %outer_latch ]
+ %lower_bound_i32 = load i32, ptr %lower_bound_ptr
+ %denominator_i32 = load i32, ptr %denominator_ptr
+ %lower_bound = zext i32 %lower_bound_i32 to i64
+ %denominator = zext i32 %denominator_i32 to i64
+ %lower_bound_too_large = icmp ugt i32 %lower_bound_i32, 35
+ br i1 %lower_bound_too_large, label %outer_latch, label %compute_trip_count
+
+compute_trip_count:
+ %difference = sub nsw i64 %denominator, %lower_bound
+ %numerator = add nsw i64 %difference, 35
+ %quotient = udiv i64 %numerator, %denominator
+ %skip_inner = icmp ult i64 %numerator, %denominator
+ br i1 %skip_inner, label %outer_latch, label %inner
+
+inner:
+ %count = phi i64 [ %next, %inner ], [ %quotient, %compute_trip_count ]
+ %offset = phi i64 [ %next_offset, %inner ], [ 0, %compute_trip_count ]
+ %next = add i64 %count, -1
+ %next_offset = add i64 %offset, %denominator
+ %continue = icmp ugt i64 %count, 1
+ br i1 %continue, label %inner, label %outer_latch
+
+outer_latch:
+ call void @barrier()
+ %next_outer_index = add i64 %outer_index, 1
+ %continue_outer = icmp ult i64 %next_outer_index, %outer_limit
+ br i1 %continue_outer, label %outer, label %exit
+
+exit:
+ ret void
+}
+
+declare void @barrier() convergent noduplicate
+
+define void @udiv_entry_guard_reduced(ptr %denominator_ptr) {
+; CHECK-LABEL: define void @udiv_entry_guard_reduced(
+; CHECK-SAME: ptr [[DENOMINATOR_PTR:%.*]]) {
+; CHECK-NEXT: [[OUTER_LOOPEXIT_UNR_LCSSA:.*:]]
+; CHECK-NEXT: br label %[[OUTER_LOOPEXIT:.*]]
+; CHECK: [[OUTER_LOOPEXIT1:.*]]:
+; CHECK-NEXT: br label %[[OUTER_BACKEDGE:.*]]
+; CHECK: [[OUTER_LOOPEXIT]]:
+; CHECK-NEXT: [[DENOMINATOR:%.*]] = load i64, ptr [[DENOMINATOR_PTR]], align 4
+; CHECK-NEXT: [[QUOTIENT:%.*]] = udiv i64 35, [[DENOMINATOR]]
+; CHECK-NEXT: [[SKIP_INNER:%.*]] = icmp ult i64 35, [[DENOMINATOR]]
+; CHECK-NEXT: br i1 [[SKIP_INNER]], label %[[OUTER_BACKEDGE]], label %[[INNER_PREHEADER:.*]]
+; CHECK: [[OUTER_BACKEDGE]]:
+; CHECK-NEXT: br label %[[OUTER_LOOPEXIT]]
+; CHECK: [[INNER_PREHEADER]]:
+; CHECK-NEXT: br label %[[INNER_PROL:.*]]
+; CHECK: [[INNER_PROL]]:
+; CHECK-NEXT: [[COUNT_PROL:%.*]] = phi i64 [ [[NEXT_PROL:%.*]], %[[INNER_PROL]] ], [ [[QUOTIENT]], %[[INNER_PREHEADER]] ]
+; CHECK-NEXT: [[NEXT_PROL]] = add i64 [[COUNT_PROL]], -1
+; CHECK-NEXT: [[CONTINUE_PROL:%.*]] = icmp ugt i64 [[COUNT_PROL]], 1
+; CHECK-NEXT: br i1 [[CONTINUE_PROL]], label %[[INNER_PROL]], label %[[OUTER_LOOPEXIT1]]
+;
+entry:
+ br label %outer
+
+outer: ; preds = %inner, %outer, %entry
+ %denominator = load i64, ptr %denominator_ptr
+ %quotient = udiv i64 35, %denominator
+ %skip_inner = icmp ult i64 35, %denominator
+ br i1 %skip_inner, label %outer, label %inner
+
+inner: ; preds = %inner, %outer
+ %count = phi i64 [ %next, %inner ], [ %quotient, %outer ]
+ %next = add i64 %count, -1
+ %continue = icmp ugt i64 %count, 1
+ br i1 %continue, label %inner, label %outer
+}
>From 566ba48a10d542f373eee670cd1d55315a20afa3 Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Tue, 25 Aug 2026 20:45:42 +0000
Subject: [PATCH 2/5] [SCEV] Simplify udiv equality comparisons against 0
---
llvm/lib/Analysis/ScalarEvolution.cpp | 11 +++
.../Thumb2/LowOverheadLoops/while-loops.ll | 12 +--
.../IndVarSimplify/AArch64/loop-guards.ll | 9 +-
.../Transforms/IndVarSimplify/udiv-icmp.ll | 21 ++---
.../runtime-unroll-scev-udiv-entry-guard.ll | 82 +++++++++++++++++--
5 files changed, 103 insertions(+), 32 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index ba15210a3b456..a994c4d579966 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11113,6 +11113,17 @@ bool ScalarEvolution::SimplifyICmpOperands(CmpPredicate &Pred, SCEVUse &LHS,
}
}
+ // For a defined unsigned division, the quotient is zero exactly when the
+ // numerator is less than the denominator. The constant-range canonicalization
+ // above reduces equivalent zero/nonzero comparisons to EQ/NE against zero.
+ if (const auto *Div = dyn_cast<SCEVUDivExpr>(LHS);
+ Div && RHS->isZero() && ICmpInst::isEquality(Pred)) {
+ LHS = Div->getLHS();
+ RHS = Div->getRHS();
+ Pred = Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
+ Changed = true;
+ }
+
// Check for obvious equality.
if (HasSameValue(LHS, RHS)) {
if (ICmpInst::isTrueWhenEqual(Pred))
diff --git a/llvm/test/CodeGen/Thumb2/LowOverheadLoops/while-loops.ll b/llvm/test/CodeGen/Thumb2/LowOverheadLoops/while-loops.ll
index a637fe0ca446b..68cceb324cb3a 100644
--- a/llvm/test/CodeGen/Thumb2/LowOverheadLoops/while-loops.ll
+++ b/llvm/test/CodeGen/Thumb2/LowOverheadLoops/while-loops.ll
@@ -10,7 +10,7 @@ define void @simple(ptr nocapture readonly %x, ptr nocapture readnone %y, ptr no
; CHECK-NEXT: ldr r1, [sp, #8]
; CHECK-NEXT: mov r12, r3
; CHECK-NEXT: adds r3, r1, #3
-; CHECK-NEXT: lsrs r3, r3, #2
+; CHECK-NEXT: lsrs.w lr, r3, #2
; CHECK-NEXT: beq .LBB0_3
; CHECK-NEXT: @ %bb.1: @ %do.body.preheader
; CHECK-NEXT: dlstp.32 lr, r1
@@ -73,14 +73,14 @@ define void @nested(ptr nocapture readonly %x, ptr nocapture readnone %y, ptr no
; CHECK-NEXT: .LBB1_4: @ %for.body
; CHECK-NEXT: @ =>This Loop Header: Depth=1
; CHECK-NEXT: @ Child Loop BB1_6 Depth 2
-; CHECK-NEXT: add.w r6, r12, #3
-; CHECK-NEXT: lsrs r7, r6, #2
+; CHECK-NEXT: add.w r7, r12, #3
+; CHECK-NEXT: lsrs r5, r7, #2
; CHECK-NEXT: beq .LBB1_2
; CHECK-NEXT: @ %bb.5: @ %do.body.preheader
; CHECK-NEXT: @ in Loop: Header=BB1_4 Depth=1
-; CHECK-NEXT: bic r5, r6, #3
+; CHECK-NEXT: bic r7, r7, #3
+; CHECK-NEXT: add.w r8, r0, r7, lsl #2
; CHECK-NEXT: mov r4, r3
-; CHECK-NEXT: add.w r8, r0, r5, lsl #2
; CHECK-NEXT: dlstp.32 lr, r12
; CHECK-NEXT: .LBB1_6: @ %do.body
; CHECK-NEXT: @ Parent Loop BB1_4 Depth=1
@@ -90,7 +90,7 @@ define void @nested(ptr nocapture readonly %x, ptr nocapture readnone %y, ptr no
; CHECK-NEXT: letp lr, .LBB1_6
; CHECK-NEXT: @ %bb.7: @ %if.end.loopexit
; CHECK-NEXT: @ in Loop: Header=BB1_4 Depth=1
-; CHECK-NEXT: sub.w r12, r12, r5
+; CHECK-NEXT: sub.w r12, r12, r7
; CHECK-NEXT: mov r0, r8
; CHECK-NEXT: b .LBB1_3
; CHECK-NEXT: .LBB1_8:
diff --git a/llvm/test/Transforms/IndVarSimplify/AArch64/loop-guards.ll b/llvm/test/Transforms/IndVarSimplify/AArch64/loop-guards.ll
index 409622c255ea0..541875e6b0527 100644
--- a/llvm/test/Transforms/IndVarSimplify/AArch64/loop-guards.ll
+++ b/llvm/test/Transforms/IndVarSimplify/AArch64/loop-guards.ll
@@ -10,8 +10,7 @@ define i32 @guards_applied_to_add_rec(ptr %dst) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: br label %[[OUTER_HEADER:.*]]
; CHECK: [[OUTER_HEADER]]:
-; CHECK-NEXT: [[OUTER_IV_0:%.*]] = phi i32 [ 2, %[[ENTRY]] ], [ [[OUTER_IV_0_NEXT:%.*]], %[[OUTER_LATCH:.*]] ]
-; CHECK-NEXT: [[OUTER_IV_1:%.*]] = phi i32 [ 1, %[[ENTRY]] ], [ [[OUTER_IV_0]], %[[OUTER_LATCH]] ]
+; CHECK-NEXT: [[OUTER_IV_1:%.*]] = phi i32 [ [[INDVARS_IV_NEXT2:%.*]], %[[OUTER_LATCH:.*]] ], [ 1, %[[ENTRY]] ]
; CHECK-NEXT: [[SHR28:%.*]] = lshr i32 [[OUTER_IV_1]], 1
; CHECK-NEXT: [[PRE:%.*]] = icmp samesign ult i32 [[OUTER_IV_1]], 2
; CHECK-NEXT: br i1 [[PRE]], label %[[OUTER_LATCH]], label %[[INNER_PREHEADER:.*]]
@@ -24,13 +23,13 @@ define i32 @guards_applied_to_add_rec(ptr %dst) {
; CHECK-NEXT: [[TMP1:%.*]] = trunc nuw nsw i64 [[INDVARS_IV]] to i32
; CHECK-NEXT: store i32 [[TMP1]], ptr [[GEP_DST]], align 4
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
-; CHECK-NEXT: [[CMP29:%.*]] = icmp samesign ult i64 [[INDVARS_IV_NEXT]], [[TMP0]]
+; CHECK-NEXT: [[CMP29:%.*]] = icmp ne i64 [[INDVARS_IV_NEXT]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP29]], label %[[INNER]], label %[[OUTER_LATCH_LOOPEXIT:.*]]
; CHECK: [[OUTER_LATCH_LOOPEXIT]]:
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
-; CHECK-NEXT: [[OUTER_IV_0_NEXT]] = add nuw i32 [[OUTER_IV_0]], 1
-; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[OUTER_IV_0_NEXT]], -2147483647
+; CHECK-NEXT: [[INDVARS_IV_NEXT2]] = add nuw i32 [[OUTER_IV_1]], 1
+; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[INDVARS_IV_NEXT2]], -2147483648
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[OUTER_HEADER]], label %[[EXIT:.*]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: ret i32 0
diff --git a/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll b/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
index d03a4d9edfe82..d1c008f3fd3ca 100644
--- a/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
+++ b/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
@@ -11,10 +11,9 @@ define i1 @quotient_eq_zero(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -46,10 +45,9 @@ define i1 @quotient_ule_zero(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -81,10 +79,9 @@ define i1 @quotient_ult_one(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -116,10 +113,9 @@ define i1 @quotient_ne_zero(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -151,10 +147,9 @@ define i1 @quotient_ugt_zero(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -186,10 +181,9 @@ define i1 @quotient_uge_one(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
@@ -221,10 +215,9 @@ define i1 @constant_on_left(i64 %a, i64 %b) {
; CHECK: [[LOOP_PREHEADER]]:
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[CMP:%.*]] = icmp uge i64 [[A]], [[B]]
; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ [[CMP]], %[[LOOP]] ]
+; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
diff --git a/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll b/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
index 01beac717a256..e1cbb302d724e 100644
--- a/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
+++ b/llvm/test/Transforms/LoopUnroll/runtime-unroll-scev-udiv-entry-guard.ll
@@ -21,15 +21,53 @@ define void @openmp_loop(
; CHECK-NEXT: [[SKIP_INNER:%.*]] = icmp ult i64 [[NUMERATOR]], [[DENOMINATOR]]
; CHECK-NEXT: br i1 [[SKIP_INNER]], label %[[OUTER_LATCH]], label %[[INNER_EPIL_PREHEADER:.*]]
; CHECK: [[INNER_EPIL_PREHEADER]]:
+; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[QUOTIENT]], -1
+; CHECK-NEXT: [[XTRAITER:%.*]] = and i64 [[QUOTIENT]], 7
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7
+; CHECK-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER1:.*]], label %[[INNER_PREHEADER_NEW:.*]]
+; CHECK: [[INNER_PREHEADER_NEW]]:
+; CHECK-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[QUOTIENT]], [[XTRAITER]]
; CHECK-NEXT: br label %[[INNER_EPIL:.*]]
; CHECK: [[INNER_EPIL]]:
-; CHECK-NEXT: [[COUNT_EPIL:%.*]] = phi i64 [ [[NEXT_EPIL:%.*]], %[[INNER_EPIL]] ], [ [[QUOTIENT]], %[[INNER_EPIL_PREHEADER]] ]
-; CHECK-NEXT: [[OFFSET_EPIL:%.*]] = phi i64 [ [[NEXT_OFFSET_EPIL:%.*]], %[[INNER_EPIL]] ], [ 0, %[[INNER_EPIL_PREHEADER]] ]
+; CHECK-NEXT: [[COUNT:%.*]] = phi i64 [ [[QUOTIENT]], %[[INNER_PREHEADER_NEW]] ], [ [[NEXT_7:%.*]], %[[INNER_EPIL]] ]
+; CHECK-NEXT: [[OFFSET:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER_NEW]] ], [ [[NEXT_OFFSET_7:%.*]], %[[INNER_EPIL]] ]
+; CHECK-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[INNER_PREHEADER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER_EPIL]] ]
+; CHECK-NEXT: [[NEXT_OFFSET:%.*]] = add i64 [[OFFSET]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_1:%.*]] = add i64 [[NEXT_OFFSET]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_2:%.*]] = add i64 [[NEXT_OFFSET_1]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_3:%.*]] = add i64 [[NEXT_OFFSET_2]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_4:%.*]] = add i64 [[NEXT_OFFSET_3]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_5:%.*]] = add i64 [[NEXT_OFFSET_4]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_OFFSET_6:%.*]] = add i64 [[NEXT_OFFSET_5]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NEXT_7]] = add i64 [[COUNT]], -8
+; CHECK-NEXT: [[NEXT_OFFSET_7]] = add i64 [[NEXT_OFFSET_6]], [[DENOMINATOR]]
+; CHECK-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8
+; CHECK-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]]
+; CHECK-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_LOOPEXIT_UNR_LCSSA:.*]]
+; CHECK: [[OUTER_LATCH_LOOPEXIT_UNR_LCSSA]]:
+; CHECK-NEXT: [[COUNT_UNR:%.*]] = phi i64 [ [[NEXT_7]], %[[INNER_EPIL]] ]
+; CHECK-NEXT: [[OFFSET_UNR:%.*]] = phi i64 [ [[NEXT_OFFSET_7]], %[[INNER_EPIL]] ]
+; CHECK-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
+; CHECK-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER1]], label %[[OUTER_LATCH_LOOPEXIT1:.*]]
+; CHECK: [[INNER_EPIL_PREHEADER1]]:
+; CHECK-NEXT: [[COUNT_EPIL_INIT:%.*]] = phi i64 [ [[QUOTIENT]], %[[INNER_EPIL_PREHEADER]] ], [ [[COUNT_UNR]], %[[OUTER_LATCH_LOOPEXIT_UNR_LCSSA]] ]
+; CHECK-NEXT: [[OFFSET_EPIL_INIT:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[OFFSET_UNR]], %[[OUTER_LATCH_LOOPEXIT_UNR_LCSSA]] ]
+; CHECK-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]])
+; CHECK-NEXT: br label %[[INNER_EPIL1:.*]]
+; CHECK: [[INNER_EPIL1]]:
+; CHECK-NEXT: [[COUNT_EPIL:%.*]] = phi i64 [ [[NEXT_EPIL:%.*]], %[[INNER_EPIL1]] ], [ [[COUNT_EPIL_INIT]], %[[INNER_EPIL_PREHEADER1]] ]
+; CHECK-NEXT: [[OFFSET_EPIL:%.*]] = phi i64 [ [[NEXT_OFFSET_EPIL:%.*]], %[[INNER_EPIL1]] ], [ [[OFFSET_EPIL_INIT]], %[[INNER_EPIL_PREHEADER1]] ]
+; CHECK-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER1]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL1]] ]
; CHECK-NEXT: [[NEXT_EPIL]] = add i64 [[COUNT_EPIL]], -1
; CHECK-NEXT: [[NEXT_OFFSET_EPIL]] = add i64 [[OFFSET_EPIL]], [[DENOMINATOR]]
; CHECK-NEXT: [[CONTINUE_EPIL:%.*]] = icmp ugt i64 [[COUNT_EPIL]], 1
-; CHECK-NEXT: br i1 [[CONTINUE_EPIL]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_LOOPEXIT:.*]]
+; CHECK-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1
+; CHECK-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]]
+; CHECK-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL1]], label %[[OUTER_LATCH_LOOPEXIT:.*]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: [[OUTER_LATCH_LOOPEXIT]]:
+; CHECK-NEXT: br label %[[OUTER_LATCH_LOOPEXIT1]]
+; CHECK: [[OUTER_LATCH_LOOPEXIT1]]:
; CHECK-NEXT: br label %[[OUTER_LATCH]]
; CHECK: [[OUTER_LATCH]]:
; CHECK-NEXT: call void @barrier()
@@ -86,20 +124,45 @@ define void @udiv_entry_guard_reduced(ptr %denominator_ptr) {
; CHECK-NEXT: br label %[[OUTER_LOOPEXIT:.*]]
; CHECK: [[OUTER_LOOPEXIT1:.*]]:
; CHECK-NEXT: br label %[[OUTER_BACKEDGE:.*]]
+; CHECK: [[OUTER_BACKEDGE]]:
+; CHECK-NEXT: br label %[[OUTER_BACKEDGE1:.*]]
; CHECK: [[OUTER_LOOPEXIT]]:
; CHECK-NEXT: [[DENOMINATOR:%.*]] = load i64, ptr [[DENOMINATOR_PTR]], align 4
; CHECK-NEXT: [[QUOTIENT:%.*]] = udiv i64 35, [[DENOMINATOR]]
; CHECK-NEXT: [[SKIP_INNER:%.*]] = icmp ult i64 35, [[DENOMINATOR]]
-; CHECK-NEXT: br i1 [[SKIP_INNER]], label %[[OUTER_BACKEDGE]], label %[[INNER_PREHEADER:.*]]
-; CHECK: [[OUTER_BACKEDGE]]:
+; CHECK-NEXT: br i1 [[SKIP_INNER]], label %[[OUTER_BACKEDGE1]], label %[[INNER_PREHEADER:.*]]
+; CHECK: [[OUTER_BACKEDGE1]]:
; CHECK-NEXT: br label %[[OUTER_LOOPEXIT]]
; CHECK: [[INNER_PREHEADER]]:
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i64 [[QUOTIENT]], -1
+; CHECK-NEXT: [[XTRAITER:%.*]] = and i64 [[QUOTIENT]], 7
+; CHECK-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0
+; CHECK-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_PROL_PREHEADER:.*]], label %[[INNER_PROL_LOOPEXIT:.*]]
+; CHECK: [[INNER_PROL_PREHEADER]]:
; CHECK-NEXT: br label %[[INNER_PROL:.*]]
; CHECK: [[INNER_PROL]]:
-; CHECK-NEXT: [[COUNT_PROL:%.*]] = phi i64 [ [[NEXT_PROL:%.*]], %[[INNER_PROL]] ], [ [[QUOTIENT]], %[[INNER_PREHEADER]] ]
+; CHECK-NEXT: [[COUNT_PROL:%.*]] = phi i64 [ [[NEXT_PROL:%.*]], %[[INNER_PROL]] ], [ [[QUOTIENT]], %[[INNER_PROL_PREHEADER]] ]
+; CHECK-NEXT: [[PROL_ITER:%.*]] = phi i64 [ 0, %[[INNER_PROL_PREHEADER]] ], [ [[PROL_ITER_NEXT:%.*]], %[[INNER_PROL]] ]
; CHECK-NEXT: [[NEXT_PROL]] = add i64 [[COUNT_PROL]], -1
; CHECK-NEXT: [[CONTINUE_PROL:%.*]] = icmp ugt i64 [[COUNT_PROL]], 1
-; CHECK-NEXT: br i1 [[CONTINUE_PROL]], label %[[INNER_PROL]], label %[[OUTER_LOOPEXIT1]]
+; CHECK-NEXT: [[PROL_ITER_NEXT]] = add i64 [[PROL_ITER]], 1
+; CHECK-NEXT: [[PROL_ITER_CMP:%.*]] = icmp ne i64 [[PROL_ITER_NEXT]], [[XTRAITER]]
+; CHECK-NEXT: br i1 [[PROL_ITER_CMP]], label %[[INNER_PROL]], label %[[INNER_PROL_LOOPEXIT_UNR_LCSSA:.*]], !llvm.loop [[LOOP2:![0-9]+]]
+; CHECK: [[INNER_PROL_LOOPEXIT_UNR_LCSSA]]:
+; CHECK-NEXT: [[COUNT_UNR_PH:%.*]] = phi i64 [ [[NEXT_PROL]], %[[INNER_PROL]] ]
+; CHECK-NEXT: br label %[[INNER_PROL_LOOPEXIT]]
+; CHECK: [[INNER_PROL_LOOPEXIT]]:
+; CHECK-NEXT: [[COUNT_UNR:%.*]] = phi i64 [ [[QUOTIENT]], %[[INNER_PREHEADER]] ], [ [[COUNT_UNR_PH]], %[[INNER_PROL_LOOPEXIT_UNR_LCSSA]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7
+; CHECK-NEXT: br i1 [[TMP1]], label %[[OUTER_BACKEDGE]], label %[[INNER_PREHEADER_NEW:.*]]
+; CHECK: [[INNER_PREHEADER_NEW]]:
+; CHECK-NEXT: br label %[[INNER:.*]]
+; CHECK: [[INNER]]:
+; CHECK-NEXT: [[COUNT:%.*]] = phi i64 [ [[COUNT_UNR]], %[[INNER_PREHEADER_NEW]] ], [ [[NEXT_7:%.*]], %[[INNER]] ]
+; CHECK-NEXT: [[NEXT_6:%.*]] = add i64 [[COUNT]], -7
+; CHECK-NEXT: [[NEXT_7]] = add i64 [[COUNT]], -8
+; CHECK-NEXT: [[CONTINUE_7:%.*]] = icmp ugt i64 [[NEXT_6]], 1
+; CHECK-NEXT: br i1 [[CONTINUE_7]], label %[[INNER]], label %[[OUTER_LOOPEXIT1]]
;
entry:
br label %outer
@@ -116,3 +179,8 @@ inner: ; preds = %inner, %outer
%continue = icmp ugt i64 %count, 1
br i1 %continue, label %inner, label %outer
}
+;.
+; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]]}
+; CHECK: [[META1]] = !{!"llvm.loop.unroll.disable"}
+; CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[META1]]}
+;.
>From 345df03e430fec4a5420350832fd327d7f1c694f Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Tue, 25 Aug 2026 22:02:52 +0000
Subject: [PATCH 3/5] Switch to unittest
---
.../Transforms/IndVarSimplify/udiv-icmp.ll | 240 ------------------
.../Analysis/ScalarEvolutionTest.cpp | 22 ++
2 files changed, 22 insertions(+), 240 deletions(-)
delete mode 100644 llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
diff --git a/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll b/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
deleted file mode 100644
index d1c008f3fd3ca..0000000000000
--- a/llvm/test/Transforms/IndVarSimplify/udiv-icmp.ll
+++ /dev/null
@@ -1,240 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt < %s -S -passes='loop(indvars)' | FileCheck %s
-
-define i1 @quotient_eq_zero(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_eq_zero(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp eq i64 [[Q]], 0
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp eq i64 %q, 0
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp ult i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @quotient_ule_zero(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_ule_zero(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp ule i64 [[Q]], 0
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp ule i64 %q, 0
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp ult i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @quotient_ult_one(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_ult_one(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp ult i64 [[Q]], 1
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp ult i64 %q, 1
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp ult i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @quotient_ne_zero(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_ne_zero(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp ne i64 [[Q]], 0
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp ne i64 %q, 0
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp uge i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @quotient_ugt_zero(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_ugt_zero(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp ugt i64 [[Q]], 0
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp ugt i64 %q, 0
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp uge i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @quotient_uge_one(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @quotient_uge_one(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp uge i64 [[Q]], 1
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp uge i64 %q, 1
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp uge i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
-
-define i1 @constant_on_left(i64 %a, i64 %b) {
-; CHECK-LABEL: define i1 @constant_on_left(
-; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
-; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[Q:%.*]] = udiv i64 [[A]], [[B]]
-; CHECK-NEXT: [[GUARD:%.*]] = icmp ult i64 0, [[Q]]
-; CHECK-NEXT: br i1 [[GUARD]], label %[[LOOP_PREHEADER:.*]], label %[[EXIT:.*]]
-; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: br label %[[LOOP:.*]]
-; CHECK: [[LOOP]]:
-; CHECK-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT_LOOPEXIT:.*]]
-; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[CMP_LCSSA:%.*]] = phi i1 [ true, %[[LOOP]] ]
-; CHECK-NEXT: br label %[[EXIT]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ [[CMP_LCSSA]], %[[EXIT_LOOPEXIT]] ]
-; CHECK-NEXT: ret i1 [[RESULT]]
-;
-entry:
- %q = udiv i64 %a, %b
- %guard = icmp ult i64 0, %q
- br i1 %guard, label %loop, label %exit
-
-loop:
- %same = phi i64 [ %a, %entry ], [ %same.next, %loop ]
- %cmp = icmp uge i64 %same, %b
- %same.next = add i64 %same, 1
- br i1 false, label %loop, label %exit
-
-exit:
- %result = phi i1 [ false, %entry ], [ %cmp, %loop ]
- ret i1 %result
-}
diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
index 2cbac61bac13f..41d792bd171b3 100644
--- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
+++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -2124,6 +2124,28 @@ TEST_F(ScalarEvolutionsTest, SimplifyICmpOperands) {
EXPECT_EQ(NewRHS, B);
}
});
+
+ runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+ const SCEV *Numerator = SE.getSCEV(getArgByName(F, "a"));
+ const SCEV *Denominator = SE.getSCEV(getArgByName(F, "b"));
+ const SCEV *Quotient = SE.getUDivExpr(Numerator, Denominator);
+ const SCEV *Zero = SE.getZero(Numerator->getType());
+
+ auto CheckSimplification = [&](CmpPredicate Pred,
+ ICmpInst::Predicate ExpectedPred) {
+ SCEVUse LHS = Quotient;
+ SCEVUse RHS = Zero;
+ EXPECT_TRUE(SE.SimplifyICmpOperands(Pred, LHS, RHS));
+ EXPECT_EQ(Pred, ExpectedPred);
+ EXPECT_EQ(LHS, Numerator);
+ EXPECT_EQ(RHS, Denominator);
+ };
+
+ // a / b == 0 => a < b
+ CheckSimplification(ICmpInst::ICMP_EQ, ICmpInst::ICMP_ULT);
+ // a / b != 0 => a >= b
+ CheckSimplification(ICmpInst::ICMP_NE, ICmpInst::ICMP_UGE);
+ });
}
// An operand of a SCEV expression is a SCEVUse and may carry use-specific
>From 513edad9cb9fde4145f09ba288f85491887a4dcc Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Thu, 27 Aug 2026 18:09:14 +0000
Subject: [PATCH 4/5] Address review comments
---
llvm/lib/Analysis/ScalarEvolution.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index a994c4d579966..e2c2bcd5f583e 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11113,13 +11113,13 @@ bool ScalarEvolution::SimplifyICmpOperands(CmpPredicate &Pred, SCEVUse &LHS,
}
}
- // For a defined unsigned division, the quotient is zero exactly when the
- // numerator is less than the denominator. The constant-range canonicalization
- // above reduces equivalent zero/nonzero comparisons to EQ/NE against zero.
- if (const auto *Div = dyn_cast<SCEVUDivExpr>(LHS);
- Div && RHS->isZero() && ICmpInst::isEquality(Pred)) {
- LHS = Div->getLHS();
- RHS = Div->getRHS();
+ // a /u b == 0 => a < b
+ // a /u b != 0 => a >= b
+ SCEVUse UDivLHS, UDivRHS;
+ if (ICmpInst::isEquality(Pred) && RHS->isZero() &&
+ match(LHS, m_scev_UDiv(m_SCEV(UDivLHS), m_SCEV(UDivRHS)))) {
+ LHS = UDivLHS;
+ RHS = UDivRHS;
Pred = Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
Changed = true;
}
>From 4a7baf02f52f6bd8681547eca499010d0577bbf5 Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Thu, 27 Aug 2026 13:29:24 -0700
Subject: [PATCH 5/5] Address review comments pt 2
Co-authored-by: Florian Hahn <flo at fhahn.com>
---
llvm/lib/Analysis/ScalarEvolution.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e2c2bcd5f583e..2c5758194a12e 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -11115,11 +11115,8 @@ bool ScalarEvolution::SimplifyICmpOperands(CmpPredicate &Pred, SCEVUse &LHS,
// a /u b == 0 => a < b
// a /u b != 0 => a >= b
- SCEVUse UDivLHS, UDivRHS;
if (ICmpInst::isEquality(Pred) && RHS->isZero() &&
- match(LHS, m_scev_UDiv(m_SCEV(UDivLHS), m_SCEV(UDivRHS)))) {
- LHS = UDivLHS;
- RHS = UDivRHS;
+ match(LHS, m_scev_UDiv(m_SCEV(LHS), m_SCEV(RHS)))) {
Pred = Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
Changed = true;
}
More information about the llvm-commits
mailing list