[llvm] [InstCombine] Use context in select-to-umin nonzero check (PR #225381)

Nopileos Isemados via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 21:01:34 PDT 2026


https://github.com/134ARG updated https://github.com/llvm/llvm-project/pull/225381

>From 94d38e697d4ef010516e8b4b22824e45b1cb2ab5 Mon Sep 17 00:00:00 2001
From: 134ARG <xen134 at outlook.com>
Date: Tue, 22 Sep 2026 17:31:02 +0800
Subject: [PATCH 1/2] [InstCombine] Use context in select-to-umin nonzero check

Query the decrement operand at the comparison so the existing fold can use a dominating assume or branch fact. Cover both positive contexts and the no-fact case in minmax-fold.ll.
---
 .../InstCombine/InstCombineSelect.cpp         |  2 +-
 .../Transforms/InstCombine/minmax-fold.ll     | 48 +++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index a4061bbd607707..39564744aec33e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -732,7 +732,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   // canonicalized to "add %x, -1" discarding the nuw flag.
   if (Pred == CmpInst::ICMP_ULT &&
       match(FVal, m_Add(m_Specific(CmpRHS), m_AllOnes())) &&
-      isKnownNonZero(CmpRHS, SQ)) {
+      isKnownNonZero(CmpRHS, SQ.getWithInstruction(Cmp))) {
     cast<Instruction>(FVal)->setHasNoSignedWrap(false);
     cast<Instruction>(FVal)->setHasNoUnsignedWrap(false);
     return Builder.CreateBinaryIntrinsic(Intrinsic::umin, TVal, FVal);
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index 3234ed5055f803..b6ef57286472bd 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1647,6 +1647,54 @@ define i32 @test_umin_sub1_nuw(i32 %x, i32 range(i32 1, 0) %w) {
   ret i32 %r
 }
 
+declare void @llvm.assume(i1)
+
+define i32 @test_umin_sub1_assume_nonzero(i32 %x, i32 %w) {
+; CHECK-LABEL: @test_umin_sub1_assume_nonzero(
+; CHECK:       call void @llvm.assume(i1
+; CHECK:       [[SUB:%.*]] = add i32 [[W:%.*]], -1
+; CHECK-NEXT:  [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
+; CHECK-NEXT:  ret i32 [[R]]
+  %nonzero = icmp ne i32 %w, 0
+  call void @llvm.assume(i1 %nonzero)
+  %cmp = icmp ult i32 %x, %w
+  %sub = add i32 %w, -1
+  %r = select i1 %cmp, i32 %x, i32 %sub
+  ret i32 %r
+}
+
+define i32 @test_umin_sub1_guard_nonzero(i32 %x, i32 %w) {
+; CHECK-LABEL: @test_umin_sub1_guard_nonzero(
+; CHECK:       use:
+; CHECK:       [[SUB:%.*]] = add i32 [[W:%.*]], -1
+; CHECK-NEXT:  [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
+; CHECK-NEXT:  ret i32 [[R]]
+entry:
+  %zero = icmp eq i32 %w, 0
+  br i1 %zero, label %zero.bb, label %use
+
+zero.bb:
+  ret i32 0
+
+use:
+  %cmp = icmp ult i32 %x, %w
+  %sub = add i32 %w, -1
+  %r = select i1 %cmp, i32 %x, i32 %sub
+  ret i32 %r
+}
+
+define i32 @test_umin_sub1_unknown_nonzero(i32 %x, i32 %w) {
+; CHECK-LABEL: @test_umin_sub1_unknown_nonzero(
+; CHECK:       [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT:  [[SUB:%.*]] = add i32 [[W]], -1
+; CHECK-NEXT:  [[R:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[SUB]]
+; CHECK-NEXT:  ret i32 [[R]]
+  %cmp = icmp ult i32 %x, %w
+  %sub = add i32 %w, -1
+  %r = select i1 %cmp, i32 %x, i32 %sub
+  ret i32 %r
+}
+
 define i32 @test_smin_sub1_nsw_swapped(i32 %x, i32 %w) {
 ; CHECK-LABEL: @test_smin_sub1_nsw_swapped(
 ; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[W:%.*]], -1

>From 6c97612d19f1a3ff14c01458c6aa3ff198a24946 Mon Sep 17 00:00:00 2001
From: 134ARG <xen134 at outlook.com>
Date: Wed, 23 Sep 2026 11:55:30 +0800
Subject: [PATCH 2/2] fix comments

---
 .../InstCombine/InstCombineSelect.cpp         |  5 +--
 .../Transforms/InstCombine/minmax-fold.ll     | 31 ++++++++++++-------
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 39564744aec33e..8b757a972b9c21 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -732,7 +732,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   // canonicalized to "add %x, -1" discarding the nuw flag.
   if (Pred == CmpInst::ICMP_ULT &&
       match(FVal, m_Add(m_Specific(CmpRHS), m_AllOnes())) &&
-      isKnownNonZero(CmpRHS, SQ.getWithInstruction(Cmp))) {
+      isKnownNonZero(CmpRHS, SQ)) {
     cast<Instruction>(FVal)->setHasNoSignedWrap(false);
     cast<Instruction>(FVal)->setHasNoUnsignedWrap(false);
     return Builder.CreateBinaryIntrinsic(Intrinsic::umin, TVal, FVal);
@@ -2462,7 +2462,8 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
     return &SI;
   }
 
-  if (Value *V = foldSelectICmpMinMax(ICI, TrueVal, FalseVal, Builder, SQ))
+  if (Value *V = foldSelectICmpMinMax(
+          ICI, TrueVal, FalseVal, Builder, SQ.getWithInstruction(&SI)))
     return replaceInstUsesWith(SI, V);
 
   if (Value *V = foldSelectICmpAndZeroShl(ICI, TrueVal, FalseVal, Builder))
diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll
index b6ef57286472bd..0b797776929465 100644
--- a/llvm/test/Transforms/InstCombine/minmax-fold.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll
@@ -1651,10 +1651,12 @@ declare void @llvm.assume(i1)
 
 define i32 @test_umin_sub1_assume_nonzero(i32 %x, i32 %w) {
 ; CHECK-LABEL: @test_umin_sub1_assume_nonzero(
-; CHECK:       call void @llvm.assume(i1
-; CHECK:       [[SUB:%.*]] = add i32 [[W:%.*]], -1
-; CHECK-NEXT:  [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
-; CHECK-NEXT:  ret i32 [[R]]
+; CHECK-NEXT:    [[NONZERO:%.*]] = icmp ne i32 [[W:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NONZERO]])
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[W]], -1
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
   %nonzero = icmp ne i32 %w, 0
   call void @llvm.assume(i1 %nonzero)
   %cmp = icmp ult i32 %x, %w
@@ -1665,10 +1667,16 @@ define i32 @test_umin_sub1_assume_nonzero(i32 %x, i32 %w) {
 
 define i32 @test_umin_sub1_guard_nonzero(i32 %x, i32 %w) {
 ; CHECK-LABEL: @test_umin_sub1_guard_nonzero(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ZERO:%.*]] = icmp eq i32 [[W:%.*]], 0
+; CHECK-NEXT:    br i1 [[ZERO]], label [[ZERO_BB:%.*]], label [[USE:%.*]]
+; CHECK:       zero.bb:
+; CHECK-NEXT:    ret i32 0
 ; CHECK:       use:
-; CHECK:       [[SUB:%.*]] = add i32 [[W:%.*]], -1
-; CHECK-NEXT:  [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
-; CHECK-NEXT:  ret i32 [[R]]
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[W]], -1
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.umin.i32(i32 [[X:%.*]], i32 [[SUB]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
 entry:
   %zero = icmp eq i32 %w, 0
   br i1 %zero, label %zero.bb, label %use
@@ -1685,10 +1693,11 @@ use:
 
 define i32 @test_umin_sub1_unknown_nonzero(i32 %x, i32 %w) {
 ; CHECK-LABEL: @test_umin_sub1_unknown_nonzero(
-; CHECK:       [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[W:%.*]]
-; CHECK-NEXT:  [[SUB:%.*]] = add i32 [[W]], -1
-; CHECK-NEXT:  [[R:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[SUB]]
-; CHECK-NEXT:  ret i32 [[R]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[W]], -1
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[SUB]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
   %cmp = icmp ult i32 %x, %w
   %sub = add i32 %w, -1
   %r = select i1 %cmp, i32 %x, i32 %sub



More information about the llvm-commits mailing list