[llvm] Missed optimization when `b - a` is known nonnegative inside `select` instruction (PR #187898)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 29 18:24:56 PDT 2026


https://github.com/user1342234 updated https://github.com/llvm/llvm-project/pull/187898

>From 6bbda790d11183dc77d72efa34e5c1111a392667 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Sat, 21 Mar 2026 18:51:41 -0700
Subject: [PATCH 1/9] Missed optimization when `b - a` is known nonnegative
 inside `select` instruction

---
 .../InstCombine/InstCombineSelect.cpp         |  40 +++++-
 .../Transforms/InstCombine/sext-nonneg-sub.ll | 116 ++++++++++++++++++
 2 files changed, 154 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 1de03254e8182..3d11820afa24d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -664,10 +664,46 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
                                    Value *FVal,
                                    InstCombiner::BuilderTy &Builder,
                                    const SimplifyQuery &SQ) {
-  const Value *CmpLHS = Cmp->getOperand(0);
-  const Value *CmpRHS = Cmp->getOperand(1);
+  Value *CmpLHS = Cmp->getOperand(0);
+  Value *CmpRHS = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
 
+  if (isKnownNonNegative(TVal, SQ)) {
+    // (X < Y) ? C : (X - Y)     (C non-negative)
+    if (Pred == CmpInst::ICMP_SLT &&
+        match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
+      Value *SMin =
+          Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
+      return Builder.CreateNSWSub(CmpRHS, SMin);
+    }
+
+    // (X > Y) ? C : (Y - X)    (C non-negative)
+    if (Pred == CmpInst::ICMP_SGT && isKnownNonNegative(TVal, SQ) &&
+        match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
+      Value *SMin =
+          Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
+      return Builder.CreateNSWSub(CmpRHS, SMin);
+    }
+  }
+
+  if (isKnownNonNegative(FVal, SQ)) {
+    // (X < Y) ? (Y - X) : C    (C non-negative)
+    if (Pred == CmpInst::ICMP_SLT &&
+        match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
+      Value *SMin =
+          Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
+      return Builder.CreateNSWSub(CmpRHS, SMin);
+    }
+
+    // (X > Y) ? (X - Y) : C    (C non-negative)
+    if (Pred == CmpInst::ICMP_SGT && isKnownNonNegative(FVal, SQ) &&
+        match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
+      Value *SMin =
+          Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpLHS, CmpRHS);
+      return Builder.CreateNSWSub(CmpLHS, SMin);
+    }
+  }
+
   // (X > Y) ? X : (Y - 1) ==> MIN(X, Y - 1)
   // (X < Y) ? X : (Y + 1) ==> MAX(X, Y + 1)
   // This transformation is valid when overflow corresponding to the sign of
diff --git a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
index b1121637c83b4..78e223d8960b8 100644
--- a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
+++ b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
@@ -61,3 +61,119 @@ define i64 @neg_unguarded_sub(i32 %a, i32 %b) {
   %ext = sext i32 %sub to i64
   ret i64 %ext
 }
+
+; Test that select i1 (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
+define i64 @select_nonnegative_slt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @select_nonnegative_slt(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
+; CHECK-NEXT:    [[COND:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i32 [[COND]] to i64
+; CHECK-NEXT:    ret i64 [[CONV]]
+;
+
+  %cmp = icmp slt i32 %x, %y ; b < a
+  %sub = sub nsw i32 %x, %y ; b - a
+  %cond = select i1 %cmp, i32 0, i32 %sub ; (X < Y) ? 0 : X - Y
+  %conv = sext i32 %cond to i64
+  ret i64 %conv
+}
+
+define i64 @slt_commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @slt_commuted(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[SMIN]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SUB]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp sgt i32 %y, %x
+  %sub = sub nsw i32 %y, %x
+  %sel = select i1 %cmp, i32 %sub, i32 0 ; (X < Y) ? Y - X : 0
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}
+
+define i64 @sgt_commuted(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sgt_commuted(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    [[SEL:%.*]] = sub nsw i32 [[X]], [[TMP1]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp slt i32 %y, %x ;
+  %sub = sub nsw i32 %x, %y ;
+  %sel = select i1 %cmp, i32 %sub, i32 0 ; (X > Y) ? X - Y : 0
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}
+
+; TVal strictly greater than 0
+define i64 @slt_positive_tval(i32 %x, i32 %y) {
+;
+; CHECK-LABEL: define i64 @slt_positive_tval(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
+; CHECK-NEXT:    [[SEL:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp slt i32 %x, %y
+  %sub = sub nsw i32 %x, %y
+  %sel = select i1 %cmp, i32 1, i32 %sub ; (X < Y) ? 1 : X - Y
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}
+
+; NEGATIVE TEST: FVal is negative
+define i64 @sgt_negative_fval(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @sgt_negative_fval(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 -1
+; CHECK-NEXT:    [[EXT:%.*]] = sext i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp slt i32 %y, %x ;
+  %sub = sub nsw i32 %x, %y ;
+  %sel = select i1 %cmp, i32 %sub, i32 -1 ; (X > Y) ? X - Y : -1
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}
+
+; NEGATIVE TEST: Wrong operand in select arm
+define i64 @slt_wrong_sub_order(i32 %x, i32 %y) {
+; CHECK-LABEL: define i64 @slt_wrong_sub_order(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
+; CHECK-NEXT:    [[EXT:%.*]] = sext i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp slt i32 %x, %y
+  %sub = sub nsw i32 %x, %y
+  %sel = select i1 %cmp, i32 %sub, i32 0 ; (X < Y) ? X - Y : 0
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}
+
+; NEGATIVE TEST: TVal is negative
+define i64 @slt_negative_tval(i32 %x, i32 %y) {
+;
+; CHECK-LABEL: define i64 @slt_negative_tval(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 -1, i32 [[SUB]]
+; CHECK-NEXT:    [[EXT:%.*]] = sext i32 [[SEL]] to i64
+; CHECK-NEXT:    ret i64 [[EXT]]
+;
+  %cmp = icmp slt i32 %x, %y
+  %sub = sub nsw i32 %y, %x
+  %sel = select i1 %cmp, i32 -1, i32 %sub ; (X < Y) ? -1 : Y - X
+  %ext = sext i32 %sel to i64
+  ret i64 %ext
+}

>From a96e32cbf0dfe337c2d17e67289b6537fa6ae9f2 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Sat, 21 Mar 2026 20:15:31 -0700
Subject: [PATCH 2/9] Fixing failing tests

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 3d11820afa24d..e42fd3bdc4875 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -668,7 +668,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   Value *CmpRHS = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
 
-  if (isKnownNonNegative(TVal, SQ)) {
+  if (TVal->getType()->isIntegerTy() && isKnownNonNegative(TVal, SQ)) {
     // (X < Y) ? C : (X - Y)     (C non-negative)
     if (Pred == CmpInst::ICMP_SLT &&
         match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
@@ -686,7 +686,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
   }
 
-  if (isKnownNonNegative(FVal, SQ)) {
+  if (FVal->getType()->isIntegerTy() && isKnownNonNegative(FVal, SQ)) {
     // (X < Y) ? (Y - X) : C    (C non-negative)
     if (Pred == CmpInst::ICMP_SLT &&
         match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {

>From 8b5b4e758884b1de48fb8c86380429f96b98ba69 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Sun, 22 Mar 2026 03:00:08 -0700
Subject: [PATCH 3/9] Modifying failing tests

---
 llvm/test/Transforms/InstCombine/or.ll                |  5 ++---
 llvm/test/Transforms/InstCombine/select-min-max.ll    | 10 ++++------
 llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll |  6 +++---
 3 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 64797d4d111a1..5a5e9ac20d710 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -2131,10 +2131,9 @@ define i8 @or_positive_minus_non_positive_to_abs(i8 %a){
 ; TODO: Fold to smax https://alive2.llvm.org/ce/z/wDiDh2
 define i8 @or_select_smax_neg_to_abs(i8 %a){
 ; CHECK-LABEL: @or_select_smax_neg_to_abs(
-; CHECK-NEXT:    [[SGT0:%.*]] = icmp sgt i8 [[A:%.*]], 0
+; CHECK-NEXT:    [[A:%.*]] = call i8 @llvm.smin.i8(i8 [[A1:%.*]], i8 0)
 ; CHECK-NEXT:    [[NEG:%.*]] = sub nsw i8 0, [[A]]
-; CHECK-NEXT:    [[OR:%.*]] = select i1 [[SGT0]], i8 0, i8 [[NEG]]
-; CHECK-NEXT:    ret i8 [[OR]]
+; CHECK-NEXT:    ret i8 [[NEG]]
 ;
   %sgt0 = icmp sgt i8 %a, 0
   %neg = sub nsw i8 0, %a
diff --git a/llvm/test/Transforms/InstCombine/select-min-max.ll b/llvm/test/Transforms/InstCombine/select-min-max.ll
index 99906620f8df2..d9aebf029172d 100644
--- a/llvm/test/Transforms/InstCombine/select-min-max.ll
+++ b/llvm/test/Transforms/InstCombine/select-min-max.ll
@@ -252,10 +252,9 @@ define i8 @umin_umax(i8 %x) {
 
 define i8 @not_smax(i8 %i41, i8 %i43) {
 ; CHECK-LABEL: @not_smax(
-; CHECK-NEXT:    [[I44:%.*]] = icmp slt i8 [[I41:%.*]], [[I43:%.*]]
+; CHECK-NEXT:    [[I43:%.*]] = call i8 @llvm.smin.i8(i8 [[I41:%.*]], i8 [[I42:%.*]])
 ; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I41]], [[I43]]
-; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[I44]], i8 0, i8 [[I46]]
-; CHECK-NEXT:    ret i8 [[SPEC_SELECT]]
+; CHECK-NEXT:    ret i8 [[I46]]
 ;
   %i44 = icmp slt i8 %i41, %i43
   %i46 = sub nsw i8 %i41, %i43
@@ -265,10 +264,9 @@ define i8 @not_smax(i8 %i41, i8 %i43) {
 
 define i8 @not_smax_swap(i8 %i41, i8 %i43) {
 ; CHECK-LABEL: @not_smax_swap(
-; CHECK-NEXT:    [[I44:%.*]] = icmp sgt i8 [[I41:%.*]], [[I43:%.*]]
+; CHECK-NEXT:    [[I43:%.*]] = call i8 @llvm.smin.i8(i8 [[I41:%.*]], i8 [[I44:%.*]])
 ; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I41]], [[I43]]
-; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[I44]], i8 [[I46]], i8 0
-; CHECK-NEXT:    ret i8 [[SPEC_SELECT]]
+; CHECK-NEXT:    ret i8 [[I46]]
 ;
   %i44 = icmp sgt i8 %i41, %i43
   %i46 = sub nsw i8 %i41, %i43
diff --git a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
index b3d98e053a7b8..8896e4dd45dbe 100644
--- a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
+++ b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
@@ -12,10 +12,10 @@
 define i8 @smax_nsw(i8 %a, i8 %b) {
 ; CHECK-LABEL: @smax_nsw(
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 [[A]], [[B]]
-; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 0, i8 [[SUB]]
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call i8 @llvm.smin.i8(i8 [[B]], i8 [[A]])
+; CHECK-NEXT:    [[M1_NEG:%.*]] = sub i8 [[TMP2]], [[B]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
-; CHECK-NEXT:    [[R:%.*]] = sub i8 [[TMP1]], [[M1]]
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[M1_NEG]], [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %sub = sub nsw i8 %a, %b

>From 22a65f904e02e82085d992e2bb7c713b37bc8d12 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Mon, 23 Mar 2026 02:47:11 -0700
Subject: [PATCH 4/9] Resolved bug in CreateNSWSub parameter order and fixed
 tests again

---
 .../InstCombine/InstCombineSelect.cpp         | 21 +++++++++----------
 .../Transforms/InstCombine/select-min-max.ll  |  2 +-
 .../Transforms/InstCombine/sext-nonneg-sub.ll | 19 +----------------
 .../LoopVectorize/bzip_reverse_loops.ll       |  2 +-
 .../PhaseOrdering/min-max-abs-cse.ll          |  3 ++-
 5 files changed, 15 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e42fd3bdc4875..4dff5f9667637 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -668,17 +668,17 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   Value *CmpRHS = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
 
-  if (TVal->getType()->isIntegerTy() && isKnownNonNegative(TVal, SQ)) {
-    // (X < Y) ? C : (X - Y)     (C non-negative)
+  if (match(TVal, m_Zero())) {
+    // (X < Y) ? 0 : (X - Y)
     if (Pred == CmpInst::ICMP_SLT &&
         match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
-      return Builder.CreateNSWSub(CmpRHS, SMin);
+      return Builder.CreateNSWSub(CmpLHS, SMin);
     }
 
-    // (X > Y) ? C : (Y - X)    (C non-negative)
-    if (Pred == CmpInst::ICMP_SGT && isKnownNonNegative(TVal, SQ) &&
+    // (X > Y) ? 0 : (Y - X)
+    if (Pred == CmpInst::ICMP_SGT &&
         match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -686,24 +686,23 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
   }
 
-  if (FVal->getType()->isIntegerTy() && isKnownNonNegative(FVal, SQ)) {
-    // (X < Y) ? (Y - X) : C    (C non-negative)
+  if (match(FVal, m_Zero())) {
+    // (X < Y) ? (Y - X) : 0
     if (Pred == CmpInst::ICMP_SLT &&
         match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
-      return Builder.CreateNSWSub(CmpRHS, SMin);
+      return Builder.CreateNSWSub(CmpRHS, SMin); // y - smin(x,y) => y-x
     }
 
-    // (X > Y) ? (X - Y) : C    (C non-negative)
-    if (Pred == CmpInst::ICMP_SGT && isKnownNonNegative(FVal, SQ) &&
+    // (X > Y) ? (X - Y) : 0
+    if (Pred == CmpInst::ICMP_SGT &&
         match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpLHS, CmpRHS);
       return Builder.CreateNSWSub(CmpLHS, SMin);
     }
   }
-
   // (X > Y) ? X : (Y - 1) ==> MIN(X, Y - 1)
   // (X < Y) ? X : (Y + 1) ==> MAX(X, Y + 1)
   // This transformation is valid when overflow corresponding to the sign of
diff --git a/llvm/test/Transforms/InstCombine/select-min-max.ll b/llvm/test/Transforms/InstCombine/select-min-max.ll
index d9aebf029172d..29501fa82bd34 100644
--- a/llvm/test/Transforms/InstCombine/select-min-max.ll
+++ b/llvm/test/Transforms/InstCombine/select-min-max.ll
@@ -253,7 +253,7 @@ define i8 @umin_umax(i8 %x) {
 define i8 @not_smax(i8 %i41, i8 %i43) {
 ; CHECK-LABEL: @not_smax(
 ; CHECK-NEXT:    [[I43:%.*]] = call i8 @llvm.smin.i8(i8 [[I41:%.*]], i8 [[I42:%.*]])
-; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I41]], [[I43]]
+; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I42]], [[I43]]
 ; CHECK-NEXT:    ret i8 [[I46]]
 ;
   %i44 = icmp slt i8 %i41, %i43
diff --git a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
index 78e223d8960b8..f9ba2cfa92f36 100644
--- a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
+++ b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
@@ -67,7 +67,7 @@ define i64 @select_nonnegative_slt(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i64 @select_nonnegative_slt(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
-; CHECK-NEXT:    [[COND:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
+; CHECK-NEXT:    [[COND:%.*]] = sub nsw i32 [[X]], [[TMP1]]
 ; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i32 [[COND]] to i64
 ; CHECK-NEXT:    ret i64 [[CONV]]
 ;
@@ -109,23 +109,6 @@ define i64 @sgt_commuted(i32 %x, i32 %y) {
   ret i64 %ext
 }
 
-; TVal strictly greater than 0
-define i64 @slt_positive_tval(i32 %x, i32 %y) {
-;
-; CHECK-LABEL: define i64 @slt_positive_tval(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
-; CHECK-NEXT:    [[SEL:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
-; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
-; CHECK-NEXT:    ret i64 [[EXT]]
-;
-  %cmp = icmp slt i32 %x, %y
-  %sub = sub nsw i32 %x, %y
-  %sel = select i1 %cmp, i32 1, i32 %sub ; (X < Y) ? 1 : X - Y
-  %ext = sext i32 %sel to i64
-  ret i64 %ext
-}
-
 ; NEGATIVE TEST: FVal is negative
 define i64 @sgt_negative_fval(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i64 @sgt_negative_fval(
diff --git a/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll b/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
index 056d8813ab81e..3ad3a61f1e46f 100644
--- a/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
+++ b/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
@@ -40,8 +40,8 @@ do.end:                                           ; preds = %cond.end
 ;CHECK: example1
 ;CHECK: load <4 x i32>
 ;CHECK-NEXT: shufflevector <4 x i32>
+;CHECK: call <4 x i32> @llvm.smin.v4i32
 ;CHECK: sub nsw <4 x i32>
-;CHECK: select <4 x i1>
 ;CHECK: store <4 x i32>
 ;CHECK: ret
 define void @example1(ptr nocapture %a, i32 %n, i32 %wsize) nounwind uwtable ssp {
diff --git a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
index 8896e4dd45dbe..7773a06db8b71 100644
--- a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
+++ b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
@@ -13,11 +13,12 @@ define i8 @smax_nsw(i8 %a, i8 %b) {
 ; CHECK-LABEL: @smax_nsw(
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = tail call i8 @llvm.smin.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[M1_NEG:%.*]] = sub i8 [[TMP2]], [[B]]
+; CHECK-NEXT:    [[M1_NEG:%.*]] = sub i8 [[TMP2]], [[A]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
 ; CHECK-NEXT:    [[R:%.*]] = add i8 [[M1_NEG]], [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
+; CHECK-
   %sub = sub nsw i8 %a, %b
   %cmp1 = icmp slt i8 %a, %b
   %cmp2 = icmp sgt i8 %sub, 0

>From b8ebfa72a5019dd163e2661b05c7c12a8ccd5326 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Mon, 23 Mar 2026 04:30:58 -0700
Subject: [PATCH 5/9] Added vector tests

---
 .../Transforms/InstCombine/sext-nonneg-sub.ll | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
index f9ba2cfa92f36..5bde4f9a3e1b0 100644
--- a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
+++ b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
@@ -79,6 +79,38 @@ define i64 @select_nonnegative_slt(i32 %x, i32 %y) {
   ret i64 %conv
 }
 
+; Test that select <4 x i1> (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
+define <4 x i64> @select_nonnegative_slt_vec(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: define <4 x i64> @select_nonnegative_slt_vec(
+; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.smin.v4i32(<4 x i32> [[Y]], <4 x i32> [[X]])
+; CHECK-NEXT:    [[COND:%.*]] = sub nsw <4 x i32> [[X]], [[TMP1]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg <4 x i32> [[COND]] to <4 x i64>
+; CHECK-NEXT:    ret <4 x i64> [[CONV]]
+;
+  %cmp = icmp slt <4 x i32> %x, %y
+  %sub = sub nsw <4 x i32> %x, %y
+  %cond = select <4 x i1> %cmp, <4 x i32> zeroinitializer, <4 x i32> %sub
+  %conv = sext <4 x i32> %cond to <4 x i64>
+  ret <4 x i64> %conv
+}
+
+; Scalable vector should transform
+define <vscale x 4 x i64> @select_nonnegative_slt_scalable(<vscale x 4 x i32> %x, <vscale x 4 x i32> %y) {
+; CHECK-LABEL: define <vscale x 4 x i64> @select_nonnegative_slt_scalable(
+; CHECK-SAME: <vscale x 4 x i32> [[X:%.*]], <vscale x 4 x i32> [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.smin.nxv4i32(<vscale x 4 x i32> [[Y]], <vscale x 4 x i32> [[X]])
+; CHECK-NEXT:    [[COND:%.*]] = sub nsw <vscale x 4 x i32> [[X]], [[TMP1]]
+; CHECK-NEXT:    [[CONV:%.*]] = zext nneg <vscale x 4 x i32> [[COND]] to <vscale x 4 x i64>
+; CHECK-NEXT:    ret <vscale x 4 x i64> [[CONV]]
+;
+  %cmp = icmp slt <vscale x 4 x i32> %x, %y
+  %sub = sub nsw <vscale x 4 x i32> %x, %y
+  %cond = select <vscale x 4 x i1> %cmp, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> %sub
+  %conv = sext <vscale x 4 x i32> %cond to <vscale x 4 x i64>
+  ret <vscale x 4 x i64> %conv
+}
+
 define i64 @slt_commuted(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i64 @slt_commuted(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {

>From 42186b39e44c4b1f1a8b3fc226bd635a60b8fd07 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Thu, 26 Mar 2026 22:16:45 -0700
Subject: [PATCH 6/9] Added undef Guard to each non-negative case and resolved
 affected test cases

---
 .../InstCombine/InstCombineSelect.cpp         | 10 ++---
 .../Transforms/InstCombine/select-min-max.ll  | 10 +++--
 .../Transforms/InstCombine/sext-nonneg-sub.ll | 38 +++++++++----------
 .../LoopVectorize/bzip_reverse_loops.ll       |  2 +-
 .../PhaseOrdering/min-max-abs-cse.ll          |  7 ++--
 5 files changed, 34 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 4dff5f9667637..43d69185e51df 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -667,10 +667,10 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   Value *CmpLHS = Cmp->getOperand(0);
   Value *CmpRHS = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
-
+ //  (isGuaranteedNotToBeUndef(NewOp, SQ.AC, &Sel, &DT))
   if (match(TVal, m_Zero())) {
     // (X < Y) ? 0 : (X - Y)
-    if (Pred == CmpInst::ICMP_SLT &&
+    if (Pred == CmpInst::ICMP_SLT && isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
         match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -678,7 +678,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
 
     // (X > Y) ? 0 : (Y - X)
-    if (Pred == CmpInst::ICMP_SGT &&
+    if (Pred == CmpInst::ICMP_SGT && isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
         match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -688,7 +688,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
 
   if (match(FVal, m_Zero())) {
     // (X < Y) ? (Y - X) : 0
-    if (Pred == CmpInst::ICMP_SLT &&
+    if (Pred == CmpInst::ICMP_SLT && isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
         match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -696,7 +696,7 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
 
     // (X > Y) ? (X - Y) : 0
-    if (Pred == CmpInst::ICMP_SGT &&
+    if (Pred == CmpInst::ICMP_SGT && isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
         match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpLHS, CmpRHS);
diff --git a/llvm/test/Transforms/InstCombine/select-min-max.ll b/llvm/test/Transforms/InstCombine/select-min-max.ll
index 29501fa82bd34..4db75b84e12e7 100644
--- a/llvm/test/Transforms/InstCombine/select-min-max.ll
+++ b/llvm/test/Transforms/InstCombine/select-min-max.ll
@@ -252,9 +252,10 @@ define i8 @umin_umax(i8 %x) {
 
 define i8 @not_smax(i8 %i41, i8 %i43) {
 ; CHECK-LABEL: @not_smax(
-; CHECK-NEXT:    [[I43:%.*]] = call i8 @llvm.smin.i8(i8 [[I41:%.*]], i8 [[I42:%.*]])
+; CHECK-NEXT:    [[I44:%.*]] = icmp slt i8 [[I42:%.*]], [[I43:%.*]]
 ; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I42]], [[I43]]
-; CHECK-NEXT:    ret i8 [[I46]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[I44]], i8 0, i8 [[I46]]
+; CHECK-NEXT:    ret i8 [[SPEC_SELECT]]
 ;
   %i44 = icmp slt i8 %i41, %i43
   %i46 = sub nsw i8 %i41, %i43
@@ -264,9 +265,10 @@ define i8 @not_smax(i8 %i41, i8 %i43) {
 
 define i8 @not_smax_swap(i8 %i41, i8 %i43) {
 ; CHECK-LABEL: @not_smax_swap(
-; CHECK-NEXT:    [[I43:%.*]] = call i8 @llvm.smin.i8(i8 [[I41:%.*]], i8 [[I44:%.*]])
+; CHECK-NEXT:    [[I44:%.*]] = icmp sgt i8 [[I41:%.*]], [[I43:%.*]]
 ; CHECK-NEXT:    [[I46:%.*]] = sub nsw i8 [[I41]], [[I43]]
-; CHECK-NEXT:    ret i8 [[I46]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[I44]], i8 [[I46]], i8 0
+; CHECK-NEXT:    ret i8 [[SPEC_SELECT]]
 ;
   %i44 = icmp sgt i8 %i41, %i43
   %i46 = sub nsw i8 %i41, %i43
diff --git a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
index 5bde4f9a3e1b0..458c88ed0c62b 100644
--- a/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
+++ b/llvm/test/Transforms/InstCombine/sext-nonneg-sub.ll
@@ -63,9 +63,9 @@ define i64 @neg_unguarded_sub(i32 %a, i32 %b) {
 }
 
 ; Test that select i1 (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
-define i64 @select_nonnegative_slt(i32 %x, i32 %y) {
+define i64 @select_nonnegative_slt(i32 noundef %x, i32 %y) {
 ; CHECK-LABEL: define i64 @select_nonnegative_slt(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
 ; CHECK-NEXT:    [[COND:%.*]] = sub nsw i32 [[X]], [[TMP1]]
 ; CHECK-NEXT:    [[CONV:%.*]] = zext nneg i32 [[COND]] to i64
@@ -80,9 +80,9 @@ define i64 @select_nonnegative_slt(i32 %x, i32 %y) {
 }
 
 ; Test that select <4 x i1> (X < Y) ? 0 : X - Y is recognized as non-negative, converting sext to zext
-define <4 x i64> @select_nonnegative_slt_vec(<4 x i32> %x, <4 x i32> %y) {
+define <4 x i64> @select_nonnegative_slt_vec(<4 x i32> noundef %x, <4 x i32> %y) {
 ; CHECK-LABEL: define <4 x i64> @select_nonnegative_slt_vec(
-; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
+; CHECK-SAME: <4 x i32> noundef [[X:%.*]], <4 x i32> [[Y:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.smin.v4i32(<4 x i32> [[Y]], <4 x i32> [[X]])
 ; CHECK-NEXT:    [[COND:%.*]] = sub nsw <4 x i32> [[X]], [[TMP1]]
 ; CHECK-NEXT:    [[CONV:%.*]] = zext nneg <4 x i32> [[COND]] to <4 x i64>
@@ -96,9 +96,9 @@ define <4 x i64> @select_nonnegative_slt_vec(<4 x i32> %x, <4 x i32> %y) {
 }
 
 ; Scalable vector should transform
-define <vscale x 4 x i64> @select_nonnegative_slt_scalable(<vscale x 4 x i32> %x, <vscale x 4 x i32> %y) {
+define <vscale x 4 x i64> @select_nonnegative_slt_scalable(<vscale x 4 x i32> noundef %x, <vscale x 4 x i32> %y) {
 ; CHECK-LABEL: define <vscale x 4 x i64> @select_nonnegative_slt_scalable(
-; CHECK-SAME: <vscale x 4 x i32> [[X:%.*]], <vscale x 4 x i32> [[Y:%.*]]) {
+; CHECK-SAME: <vscale x 4 x i32> noundef [[X:%.*]], <vscale x 4 x i32> [[Y:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.smin.nxv4i32(<vscale x 4 x i32> [[Y]], <vscale x 4 x i32> [[X]])
 ; CHECK-NEXT:    [[COND:%.*]] = sub nsw <vscale x 4 x i32> [[X]], [[TMP1]]
 ; CHECK-NEXT:    [[CONV:%.*]] = zext nneg <vscale x 4 x i32> [[COND]] to <vscale x 4 x i64>
@@ -111,12 +111,12 @@ define <vscale x 4 x i64> @select_nonnegative_slt_scalable(<vscale x 4 x i32> %x
   ret <vscale x 4 x i64> %conv
 }
 
-define i64 @slt_commuted(i32 %x, i32 %y) {
+define i64 @slt_commuted(i32 %x, i32 noundef %y) {
 ; CHECK-LABEL: define i64 @slt_commuted(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[SMIN]]
-; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SUB]] to i64
+; CHECK-SAME: i32 [[X:%.*]], i32 noundef [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[Y]], i32 [[X]])
+; CHECK-NEXT:    [[SEL:%.*]] = sub nsw i32 [[Y]], [[TMP1]]
+; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
 ; CHECK-NEXT:    ret i64 [[EXT]]
 ;
   %cmp = icmp sgt i32 %y, %x
@@ -126,9 +126,9 @@ define i64 @slt_commuted(i32 %x, i32 %y) {
   ret i64 %ext
 }
 
-define i64 @sgt_commuted(i32 %x, i32 %y) {
+define i64 @sgt_commuted(i32 noundef %x, i32 %y) {
 ; CHECK-LABEL: define i64 @sgt_commuted(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.smin.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    [[SEL:%.*]] = sub nsw i32 [[X]], [[TMP1]]
 ; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[SEL]] to i64
@@ -142,9 +142,9 @@ define i64 @sgt_commuted(i32 %x, i32 %y) {
 }
 
 ; NEGATIVE TEST: FVal is negative
-define i64 @sgt_negative_fval(i32 %x, i32 %y) {
+define i64 @sgt_negative_fval(i32 noundef %x, i32 %y) {
 ; CHECK-LABEL: define i64 @sgt_negative_fval(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[Y]], [[X]]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 -1
@@ -159,9 +159,9 @@ define i64 @sgt_negative_fval(i32 %x, i32 %y) {
 }
 
 ; NEGATIVE TEST: Wrong operand in select arm
-define i64 @slt_wrong_sub_order(i32 %x, i32 %y) {
+define i64 @slt_wrong_sub_order(i32 noundef %x, i32 %y) {
 ; CHECK-LABEL: define i64 @slt_wrong_sub_order(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-SAME: i32 noundef [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
@@ -176,10 +176,10 @@ define i64 @slt_wrong_sub_order(i32 %x, i32 %y) {
 }
 
 ; NEGATIVE TEST: TVal is negative
-define i64 @slt_negative_tval(i32 %x, i32 %y) {
+define i64 @slt_negative_tval(i32 %x, i32 noundef %y) {
 ;
 ; CHECK-LABEL: define i64 @slt_negative_tval(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-SAME: i32 [[X:%.*]], i32 noundef [[Y:%.*]]) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]]
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 -1, i32 [[SUB]]
diff --git a/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll b/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
index 3ad3a61f1e46f..056d8813ab81e 100644
--- a/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
+++ b/llvm/test/Transforms/LoopVectorize/bzip_reverse_loops.ll
@@ -40,8 +40,8 @@ do.end:                                           ; preds = %cond.end
 ;CHECK: example1
 ;CHECK: load <4 x i32>
 ;CHECK-NEXT: shufflevector <4 x i32>
-;CHECK: call <4 x i32> @llvm.smin.v4i32
 ;CHECK: sub nsw <4 x i32>
+;CHECK: select <4 x i1>
 ;CHECK: store <4 x i32>
 ;CHECK: ret
 define void @example1(ptr nocapture %a, i32 %n, i32 %wsize) nounwind uwtable ssp {
diff --git a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
index 7773a06db8b71..b3d98e053a7b8 100644
--- a/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
+++ b/llvm/test/Transforms/PhaseOrdering/min-max-abs-cse.ll
@@ -12,13 +12,12 @@
 define i8 @smax_nsw(i8 %a, i8 %b) {
 ; CHECK-LABEL: @smax_nsw(
 ; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = tail call i8 @llvm.smin.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[M1_NEG:%.*]] = sub i8 [[TMP2]], [[A]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 [[A]], [[B]]
+; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 0, i8 [[SUB]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 @llvm.smax.i8(i8 [[SUB]], i8 0)
-; CHECK-NEXT:    [[R:%.*]] = add i8 [[M1_NEG]], [[TMP1]]
+; CHECK-NEXT:    [[R:%.*]] = sub i8 [[TMP1]], [[M1]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
-; CHECK-
   %sub = sub nsw i8 %a, %b
   %cmp1 = icmp slt i8 %a, %b
   %cmp2 = icmp sgt i8 %sub, 0

>From c92c6cff9852c84e651506c464b0c2ab6d9429ce Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Thu, 26 Mar 2026 22:38:51 -0700
Subject: [PATCH 7/9] Formatting

---
 .../Transforms/InstCombine/InstCombineSelect.cpp   | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 43d69185e51df..de72824d06aad 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -667,10 +667,11 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   Value *CmpLHS = Cmp->getOperand(0);
   Value *CmpRHS = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
- //  (isGuaranteedNotToBeUndef(NewOp, SQ.AC, &Sel, &DT))
+
   if (match(TVal, m_Zero())) {
     // (X < Y) ? 0 : (X - Y)
-    if (Pred == CmpInst::ICMP_SLT && isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
+    if (Pred == CmpInst::ICMP_SLT &&
+        isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
         match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -678,7 +679,8 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
 
     // (X > Y) ? 0 : (Y - X)
-    if (Pred == CmpInst::ICMP_SGT && isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
+    if (Pred == CmpInst::ICMP_SGT &&
+        isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
         match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -688,7 +690,8 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
 
   if (match(FVal, m_Zero())) {
     // (X < Y) ? (Y - X) : 0
-    if (Pred == CmpInst::ICMP_SLT && isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
+    if (Pred == CmpInst::ICMP_SLT &&
+        isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
         match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
@@ -696,7 +699,8 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
     }
 
     // (X > Y) ? (X - Y) : 0
-    if (Pred == CmpInst::ICMP_SGT && isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
+    if (Pred == CmpInst::ICMP_SGT &&
+        isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
         match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpLHS, CmpRHS);

>From 3d985189faa3b4b266a2097b3ec948b46836f19a Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Wed, 29 Apr 2026 17:46:25 -0700
Subject: [PATCH 8/9] Fixes

---
 .../InstCombine/InstCombineSelect.cpp         | 36 ++++++++++---------
 1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index de72824d06aad..7f7668f1a9d54 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -669,19 +669,21 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   ICmpInst::Predicate Pred = Cmp->getPredicate();
 
   if (match(TVal, m_Zero())) {
-    // (X < Y) ? 0 : (X - Y)
-    if (Pred == CmpInst::ICMP_SLT &&
-        isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
-        match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
+    // (X <= Y) ? 0 : (X - Y)
+    if (Pred == CmpInst::ICMP_SLT ||
+        Pred == CmpInst::ICMP_SLE &&
+            match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))) &&
+            isGuaranteedNotToBeUndef(CmpLHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
       return Builder.CreateNSWSub(CmpLHS, SMin);
     }
 
-    // (X > Y) ? 0 : (Y - X)
-    if (Pred == CmpInst::ICMP_SGT &&
-        isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
-        match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
+    // (X >= Y) ? 0 : (Y - X)
+    if (Pred == CmpInst::ICMP_SGT ||
+        Pred == CmpInst::ICMP_SGE &&
+            match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS))) &&
+            isGuaranteedNotToBeUndef(CmpRHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
       return Builder.CreateNSWSub(CmpRHS, SMin);
@@ -689,19 +691,19 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
   }
 
   if (match(FVal, m_Zero())) {
-    // (X < Y) ? (Y - X) : 0
-    if (Pred == CmpInst::ICMP_SLT &&
-        isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, Cmp, nullptr) &&
-        match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS)))) {
+    // (X <= Y) ? (Y - X) : 0
+    if ((Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE) &&
+        match(TVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS))) &&
+        isGuaranteedNotToBeUndef(CmpRHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
-      return Builder.CreateNSWSub(CmpRHS, SMin); // y - smin(x,y) => y-x
+      return Builder.CreateNSWSub(CmpRHS, SMin);
     }
 
-    // (X > Y) ? (X - Y) : 0
-    if (Pred == CmpInst::ICMP_SGT &&
-        isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, Cmp, nullptr) &&
-        match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
+    // (X >= Y) ? (X - Y) : 0
+    if ((Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) &&
+        match(TVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))) &&
+        isGuaranteedNotToBeUndef(CmpLHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpLHS, CmpRHS);
       return Builder.CreateNSWSub(CmpLHS, SMin);

>From bdbc2d5b464b76b0e670a7d26c29f9a3963a4814 Mon Sep 17 00:00:00 2001
From: abu <ayywarepremium at gmail.com>
Date: Wed, 29 Apr 2026 18:24:30 -0700
Subject: [PATCH 9/9] Fixed ambiguous operator `&&`

---
 .../Transforms/InstCombine/InstCombineSelect.cpp   | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7f7668f1a9d54..102cf7f77c02c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -670,20 +670,18 @@ static Value *foldSelectICmpMinMax(const ICmpInst *Cmp, Value *TVal,
 
   if (match(TVal, m_Zero())) {
     // (X <= Y) ? 0 : (X - Y)
-    if (Pred == CmpInst::ICMP_SLT ||
-        Pred == CmpInst::ICMP_SLE &&
-            match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))) &&
-            isGuaranteedNotToBeUndef(CmpLHS, nullptr, Cmp, nullptr)) {
+    if ((Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE) &&
+        match(FVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))) &&
+        isGuaranteedNotToBeUndef(CmpLHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
       return Builder.CreateNSWSub(CmpLHS, SMin);
     }
 
     // (X >= Y) ? 0 : (Y - X)
-    if (Pred == CmpInst::ICMP_SGT ||
-        Pred == CmpInst::ICMP_SGE &&
-            match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS))) &&
-            isGuaranteedNotToBeUndef(CmpRHS, nullptr, Cmp, nullptr)) {
+    if ((Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) &&
+        match(FVal, m_NSWSub(m_Specific(CmpRHS), m_Specific(CmpLHS))) &&
+        isGuaranteedNotToBeUndef(CmpRHS, nullptr, Cmp, nullptr)) {
       Value *SMin =
           Builder.CreateBinaryIntrinsic(Intrinsic::smin, CmpRHS, CmpLHS);
       return Builder.CreateNSWSub(CmpRHS, SMin);



More information about the llvm-commits mailing list