[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