[llvm] [InstCombine] Fold `(x < y) ? -1 : zext(x != y)` into `u/scmp(x,y)` (PR #101049)

Volodymyr Vasylkun via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 10 05:26:02 PDT 2024


https://github.com/Poseydon42 updated https://github.com/llvm/llvm-project/pull/101049

>From 8dca7281d5177269a8f6e4b12b5181658510990e Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:43:33 +0100
Subject: [PATCH 1/9] Precommit tests

---
 llvm/test/Transforms/InstCombine/scmp.ll | 99 ++++++++++++++++++++++++
 llvm/test/Transforms/InstCombine/ucmp.ll | 99 ++++++++++++++++++++++++
 2 files changed, 198 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 2523872562cad9..53ab819a7d3405 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -183,3 +183,102 @@ define i8 @scmp_negated_multiuse(i32 %x, i32 %y) {
   %2 = sub i8 0, %1
   ret i8 %2
 }
+
+; Fold ((x s< y) ? -1 : (x != y)) into scmp(x, y)
+define i8 @scmp_from_select(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp slt i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: false value of the select is not `icmp ne x, y`
+define i8 @scmp_from_select_neg1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_neg1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp eq i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp slt i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+define i8 @scmp_from_select_neg2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_neg2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %y, %x
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp slt i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: true value of select is not -1
+define i8 @scmp_from_select_neg3(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_neg3(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 2, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp slt i32 %x, %y
+  %r = select i1 %lt, i8 2, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: false value of select is sign-extended instead of zero-extended
+define i8 @scmp_from_select_neg4(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_neg4(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %lt = icmp slt i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: condition of select is not (x s< y)
+define i8 @scmp_from_select_neg5(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_neg5(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp sgt i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 7210455094baac..08eab78d2eacb2 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -183,3 +183,102 @@ define i8 @ucmp_negated_multiuse(i32 %x, i32 %y) {
   %2 = sub i8 0, %1
   ret i8 %2
 }
+
+; Fold ((x u< y) ? -1 : (x != y)) into ucmp(x, y)
+define i8 @ucmp_from_select(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ult i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: false value of the select is not `icmp ne x, y`
+define i8 @ucmp_from_select_neg1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_neg1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp eq i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ult i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+define i8 @ucmp_from_select_neg2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_neg2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %y, %x
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ult i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: true value of select is not -1
+define i8 @ucmp_from_select_neg3(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_neg3(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 2, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ult i32 %x, %y
+  %r = select i1 %lt, i8 2, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: false value of select is sign-extended instead of zero-extended
+define i8 @ucmp_from_select_neg4(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_neg4(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %lt = icmp ult i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: condition of select is not (x s< y)
+define i8 @ucmp_from_select_neg5(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_neg5(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LT_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT_NOT]], i8 [[NE]], i8 -1
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ule i32 %x, %y
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}

>From 8bb9202ee81033dac49b84b10a5363704d2dfec2 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:44:32 +0100
Subject: [PATCH 2/9] [InstCombine] Fold (x [us]< y) ? -1 : (x != y) into
 [us]cmp(x, y)

---
 .../InstCombine/InstCombineInternal.h         |  1 +
 .../InstCombine/InstCombineSelect.cpp         | 35 +++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 64fbcc80e0edf4..19d27e277bfdac 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -731,6 +731,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
 
   // Helpers of visitSelectInst().
   Instruction *foldSelectOfBools(SelectInst &SI);
+  Instruction *foldSelectToCmp(SelectInst &SI);
   Instruction *foldSelectExtConst(SelectInst &Sel);
   Instruction *foldSelectOpOp(SelectInst &SI, Instruction *TI, Instruction *FI);
   Instruction *foldSelectIntoOp(SelectInst &SI, Value *, Value *);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index aaf4ece3249a23..a6815f92955b09 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3529,6 +3529,38 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
                                 Masked);
 }
 
+// This function tries to fold the following sequence
+//   %lt = icmp ult/slt i32 %x, %y
+//   %ne0 = icmp ne i32 %x, %y
+//   %ne = zext i1 %ne0 to iN
+//   %r = select i1 %lt, iN -1, iN %ne
+// into
+//   %r = call iN @llvm.ucmp/scmp(%x, %y)
+Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
+  if (!isa<ConstantInt>(SI.getTrueValue()) ||
+      !dyn_cast<ConstantInt>(SI.getTrueValue())->isAllOnesValue())
+    return nullptr;
+
+  Value *LHS, *RHS;
+  ICmpInst::Predicate NEPred;
+  if (!match(SI.getFalseValue(),
+             m_ZExt(m_ICmp(NEPred, m_Value(LHS), m_Value(RHS)))) ||
+      NEPred != ICmpInst::ICMP_NE)
+    return nullptr;
+
+  ICmpInst::Predicate LTPred;
+  if (!match(SI.getCondition(),
+             m_ICmp(LTPred, m_Specific(LHS), m_Specific(RHS))) ||
+      !ICmpInst::isLT(LTPred))
+    return nullptr;
+
+  bool IsSigned = ICmpInst::isSigned(LTPred);
+  Instruction *Result = Builder.CreateIntrinsic(
+      SI.getFalseValue()->getType(),
+      IsSigned ? Intrinsic::scmp : Intrinsic::ucmp, {LHS, RHS});
+  return replaceInstUsesWith(SI, Result);
+}
+
 bool InstCombinerImpl::fmulByZeroIsZero(Value *MulVal, FastMathFlags FMF,
                                         const Instruction *CtxI) const {
   KnownFPClass Known = computeKnownFPClass(MulVal, FMF, fcNegative, CtxI);
@@ -4111,5 +4143,8 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     }
   }
 
+  if (auto *Instruction = foldSelectToCmp(SI))
+    return Instruction;
+
   return nullptr;
 }

>From e7ceb669dd7e8c94314448c0c8bc01a70dfa02a2 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:47:11 +0100
Subject: [PATCH 3/9] Update tests

---
 llvm/test/Transforms/InstCombine/scmp.ll | 5 +----
 llvm/test/Transforms/InstCombine/ucmp.ll | 5 +----
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 53ab819a7d3405..5ae7970499fa7a 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -188,10 +188,7 @@ define i8 @scmp_negated_multiuse(i32 %x, i32 %y) {
 define i8 @scmp_from_select(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i8 @scmp_from_select(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %ne_bool = icmp ne i32 %x, %y
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 08eab78d2eacb2..f7ce4328856165 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -188,10 +188,7 @@ define i8 @ucmp_negated_multiuse(i32 %x, i32 %y) {
 define i8 @ucmp_from_select(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i8 @ucmp_from_select(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %ne_bool = icmp ne i32 %x, %y

>From c597f49a33efcd926f03976a6a51fe94ee6d9cc2 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:19:21 +0100
Subject: [PATCH 4/9] Add support for vector types

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 4 ++--
 llvm/test/Transforms/InstCombine/scmp.ll              | 9 +++++++++
 llvm/test/Transforms/InstCombine/ucmp.ll              | 9 +++++++++
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index a6815f92955b09..be65342c2c0581 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3537,8 +3537,8 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
 // into
 //   %r = call iN @llvm.ucmp/scmp(%x, %y)
 Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
-  if (!isa<ConstantInt>(SI.getTrueValue()) ||
-      !dyn_cast<ConstantInt>(SI.getTrueValue())->isAllOnesValue())
+  if (!isa<Constant>(SI.getTrueValue()) ||
+      !dyn_cast<Constant>(SI.getTrueValue())->isAllOnesValue())
     return nullptr;
 
   Value *LHS, *RHS;
diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index 5ae7970499fa7a..df5e6691ef407a 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -198,6 +198,15 @@ define i8 @scmp_from_select(i32 %x, i32 %y) {
   ret i8 %r
 }
 
+; Vector version
+define <4 x i8> @scmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
+  %ne_bool = icmp ne <4 x i32> %x, %y
+  %ne = zext <4 x i1> %ne_bool to <4 x i8>
+  %lt = icmp slt <4 x i32> %x, %y
+  %r = select <4 x i1> %lt, <4 x i8> splat(i8 -1), <4 x i8> %ne
+  ret <4 x i8> %r
+}
+
 ; Negative test: false value of the select is not `icmp ne x, y`
 define i8 @scmp_from_select_neg1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i8 @scmp_from_select_neg1(
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index f7ce4328856165..38ece55f37f632 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -198,6 +198,15 @@ define i8 @ucmp_from_select(i32 %x, i32 %y) {
   ret i8 %r
 }
 
+; Vector version
+define <4 x i8> @ucmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
+  %ne_bool = icmp ne <4 x i32> %x, %y
+  %ne = zext <4 x i1> %ne_bool to <4 x i8>
+  %lt = icmp ult <4 x i32> %x, %y
+  %r = select <4 x i1> %lt, <4 x i8> splat(i8 -1), <4 x i8> %ne
+  ret <4 x i8> %r
+}
+
 ; Negative test: false value of the select is not `icmp ne x, y`
 define i8 @ucmp_from_select_neg1(i32 %x, i32 %y) {
 ; CHECK-LABEL: define i8 @ucmp_from_select_neg1(

>From 7de0031aa0efc9e9f65fd3e7aa31e89a76488f99 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:19:40 +0100
Subject: [PATCH 5/9] Update existing tests

---
 llvm/test/Transforms/InstCombine/select-select.ll | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/select-select.ll b/llvm/test/Transforms/InstCombine/select-select.ll
index 84fe973093e327..36b1e50ab1160a 100644
--- a/llvm/test/Transforms/InstCombine/select-select.ll
+++ b/llvm/test/Transforms/InstCombine/select-select.ll
@@ -282,10 +282,7 @@ define i8 @strong_order_cmp_ugt_eq(i32 %a, i32 %b) {
 
 define i8 @strong_order_cmp_eq_slt(i32 %a, i32 %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_slt(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = zext i1 [[CMP_EQ]] to i8
-; CHECK-NEXT:    [[CMP_LT:%.*]] = icmp slt i32 [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_LT:%.*]] = select i1 [[CMP_LT]], i8 -1, i8 [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_LT:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
 ; CHECK-NEXT:    ret i8 [[SEL_LT]]
 ;
   %cmp.eq = icmp eq i32 %a, %b
@@ -312,10 +309,7 @@ define i8 @strong_order_cmp_eq_sgt(i32 %a, i32 %b) {
 
 define i8 @strong_order_cmp_eq_ult(i32 %a, i32 %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ult(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = zext i1 [[CMP_EQ]] to i8
-; CHECK-NEXT:    [[CMP_LT:%.*]] = icmp ult i32 [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_LT:%.*]] = select i1 [[CMP_LT]], i8 -1, i8 [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_LT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
 ; CHECK-NEXT:    ret i8 [[SEL_LT]]
 ;
   %cmp.eq = icmp eq i32 %a, %b

>From 176f3b04a45eac11ca9899e243f6f8eecda079fb Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:22:12 +0100
Subject: [PATCH 6/9] Move the fold up

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

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index be65342c2c0581..9c77d624d62af6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4064,6 +4064,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (Instruction *I = foldBitCeil(SI, Builder))
     return I;
 
+  if (Instruction *I = foldSelectToCmp(SI))
+    return I;
+
   // Fold:
   // (select A && B, T, F) -> (select A, (select B, T, F), F)
   // (select A || B, T, F) -> (select A, T, (select B, T, F))
@@ -4143,8 +4146,5 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
     }
   }
 
-  if (auto *Instruction = foldSelectToCmp(SI))
-    return Instruction;
-
   return nullptr;
 }

>From e48b35f474c06e8eae3315a8ef3f5825084fc5d5 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:04:00 +0100
Subject: [PATCH 7/9] Full rewrite to accomodate two more folds

---
 .../InstCombine/InstCombineSelect.cpp         | 70 +++++++++++++------
 1 file changed, 47 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 9c77d624d62af6..372d4eef83aa47 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3529,36 +3529,60 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
                                 Masked);
 }
 
-// This function tries to fold the following sequence
-//   %lt = icmp ult/slt i32 %x, %y
-//   %ne0 = icmp ne i32 %x, %y
-//   %ne = zext i1 %ne0 to iN
-//   %r = select i1 %lt, iN -1, iN %ne
-// into
-//   %r = call iN @llvm.ucmp/scmp(%x, %y)
+// This function tries to fold the following operations:
+//   (x < y) ? -1 : zext(x != y)
+//   (x > y) ? 1 : sext(x != y)
+//   (x >= y) ? zext(x != y) : -1
+// Into ucmp/scmp(x, y), where signedness is determined by the signedness
+// of the comparison in the original sequence
 Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
-  if (!isa<Constant>(SI.getTrueValue()) ||
-      !dyn_cast<Constant>(SI.getTrueValue())->isAllOnesValue())
-    return nullptr;
+  Value *TV = SI.getTrueValue();
+  Value *FV = SI.getFalseValue();
 
+  ICmpInst::Predicate Pred;
   Value *LHS, *RHS;
-  ICmpInst::Predicate NEPred;
-  if (!match(SI.getFalseValue(),
-             m_ZExt(m_ICmp(NEPred, m_Value(LHS), m_Value(RHS)))) ||
-      NEPred != ICmpInst::ICMP_NE)
+  if (!match(SI.getCondition(), m_ICmp(Pred, m_Value(LHS), m_Value(RHS))))
     return nullptr;
 
-  ICmpInst::Predicate LTPred;
-  if (!match(SI.getCondition(),
-             m_ICmp(LTPred, m_Specific(LHS), m_Specific(RHS))) ||
-      !ICmpInst::isLT(LTPred))
+  if (!LHS->getType()->isIntOrIntVectorTy())
     return nullptr;
 
-  bool IsSigned = ICmpInst::isSigned(LTPred);
-  Instruction *Result = Builder.CreateIntrinsic(
-      SI.getFalseValue()->getType(),
-      IsSigned ? Intrinsic::scmp : Intrinsic::ucmp, {LHS, RHS});
-  return replaceInstUsesWith(SI, Result);
+  // Try to swap operands and the predicate. We need to be careful when doing
+  // so because two of the patterns have opposite predicates, so use the
+  // constant inside select to determine if swapping operands would be
+  // beneficial to us.
+  if ((ICmpInst::isGT(Pred) && match(TV, m_AllOnes())) ||
+      (ICmpInst::isLT(Pred) && match(TV, m_One())) || ICmpInst::isLE(Pred)) {
+    Pred = ICmpInst::getSwappedPredicate(Pred);
+    std::swap(LHS, RHS);
+  }
+
+  Intrinsic::ID IID =
+      ICmpInst::isSigned(Pred) ? Intrinsic::scmp : Intrinsic::ucmp;
+
+  CallInst *Intrinsic = nullptr;
+  ICmpInst::Predicate NEPred;
+  // (x < y) ? -1 : zext(x != y)
+  if (ICmpInst::isLT(Pred) && match(TV, m_AllOnes()) &&
+      match(FV, m_ZExt(m_c_ICmp(NEPred, m_Specific(LHS), m_Specific(RHS)))) &&
+      NEPred == ICmpInst::ICMP_NE)
+    Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
+
+  // (x > y) ? 1 : sext(x != y)
+  if (ICmpInst::isGT(Pred) && match(TV, m_One()) &&
+      match(FV, m_SExt(m_c_ICmp(NEPred, m_Specific(LHS), m_Specific(RHS)))) &&
+      NEPred == ICmpInst::ICMP_NE)
+    Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
+
+  // (x >= y) ? zext(x != y) : -1
+  if (ICmpInst::isGE(Pred) &&
+      match(TV, m_ZExt(m_c_ICmp(NEPred, m_Specific(LHS), m_Specific(RHS)))) &&
+      NEPred == ICmpInst::ICMP_NE && match(FV, m_AllOnes()))
+    Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
+
+  if (Intrinsic)
+    return replaceInstUsesWith(SI, Intrinsic);
+  return nullptr;
 }
 
 bool InstCombinerImpl::fmulByZeroIsZero(Value *MulVal, FastMathFlags FMF,

>From d39b316613956e4ae0ebc7424450bfcffa87d0a6 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:04:15 +0100
Subject: [PATCH 8/9] Update tests

---
 llvm/test/Transforms/InstCombine/scmp.ll |  89 ++------
 llvm/test/Transforms/InstCombine/ucmp.ll | 245 +++++++++++++++++++++--
 2 files changed, 243 insertions(+), 91 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/scmp.ll b/llvm/test/Transforms/InstCombine/scmp.ll
index df5e6691ef407a..ea04cc03d547a4 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -185,8 +185,8 @@ define i8 @scmp_negated_multiuse(i32 %x, i32 %y) {
 }
 
 ; Fold ((x s< y) ? -1 : (x != y)) into scmp(x, y)
-define i8 @scmp_from_select(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select(
+define i8 @scmp_from_select_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_lt(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
@@ -199,7 +199,12 @@ define i8 @scmp_from_select(i32 %x, i32 %y) {
 }
 
 ; Vector version
-define <4 x i8> @scmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
+define <4 x i8> @scmp_from_select_vec_lt(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: define <4 x i8> @scmp_from_select_vec_lt(
+; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <4 x i8> @llvm.scmp.v4i8.v4i32(<4 x i32> [[X]], <4 x i32> [[Y]])
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
   %ne_bool = icmp ne <4 x i32> %x, %y
   %ne = zext <4 x i1> %ne_bool to <4 x i8>
   %lt = icmp slt <4 x i32> %x, %y
@@ -207,84 +212,30 @@ define <4 x i8> @scmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
   ret <4 x i8> %r
 }
 
-; Negative test: false value of the select is not `icmp ne x, y`
-define i8 @scmp_from_select_neg1(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select_neg1(
+; Fold (x s<= y) ? sext(x != y) : 1 into scmp(x, y)
+define i8 @scmp_from_select_le(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_le(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
-; CHECK-NEXT:    ret i8 [[R]]
-;
-  %ne_bool = icmp eq i32 %x, %y
-  %ne = zext i1 %ne_bool to i8
-  %lt = icmp slt i32 %x, %y
-  %r = select i1 %lt, i8 -1, i8 %ne
-  ret i8 %r
-}
-
-define i8 @scmp_from_select_neg2(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select_neg2(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
-; CHECK-NEXT:    ret i8 [[R]]
-;
-  %ne_bool = icmp ne i32 %y, %x
-  %ne = zext i1 %ne_bool to i8
-  %lt = icmp slt i32 %x, %y
-  %r = select i1 %lt, i8 -1, i8 %ne
-  ret i8 %r
-}
-
-; Negative test: true value of select is not -1
-define i8 @scmp_from_select_neg3(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select_neg3(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp slt i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 2, i8 [[NE]]
-; CHECK-NEXT:    ret i8 [[R]]
-;
-  %ne_bool = icmp ne i32 %x, %y
-  %ne = zext i1 %ne_bool to i8
-  %lt = icmp slt i32 %x, %y
-  %r = select i1 %lt, i8 2, i8 %ne
-  ret i8 %r
-}
-
-; Negative test: false value of select is sign-extended instead of zero-extended
-define i8 @scmp_from_select_neg4(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select_neg4(
-; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %ne_bool = icmp ne i32 %x, %y
   %ne = sext i1 %ne_bool to i8
-  %lt = icmp slt i32 %x, %y
-  %r = select i1 %lt, i8 -1, i8 %ne
+  %le = icmp sle i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 1
   ret i8 %r
 }
 
-; Negative test: condition of select is not (x s< y)
-define i8 @scmp_from_select_neg5(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @scmp_from_select_neg5(
+; Fold (x s>= y) ? zext(x != y) : -1 into scmp(x, y)
+define i8 @scmp_from_select_ge(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @scmp_from_select_ge(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp sgt i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %ne_bool = icmp ne i32 %x, %y
   %ne = zext i1 %ne_bool to i8
-  %lt = icmp sgt i32 %x, %y
-  %r = select i1 %lt, i8 -1, i8 %ne
+  %ge = icmp sge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
   ret i8 %r
 }
diff --git a/llvm/test/Transforms/InstCombine/ucmp.ll b/llvm/test/Transforms/InstCombine/ucmp.ll
index 38ece55f37f632..de05132b029fe4 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -185,8 +185,8 @@ define i8 @ucmp_negated_multiuse(i32 %x, i32 %y) {
 }
 
 ; Fold ((x u< y) ? -1 : (x != y)) into ucmp(x, y)
-define i8 @ucmp_from_select(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select(
+define i8 @ucmp_from_select_lt(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
@@ -199,7 +199,12 @@ define i8 @ucmp_from_select(i32 %x, i32 %y) {
 }
 
 ; Vector version
-define <4 x i8> @ucmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
+define <4 x i8> @ucmp_from_select_vec_lt(<4 x i32> %x, <4 x i32> %y) {
+; CHECK-LABEL: define <4 x i8> @ucmp_from_select_vec_lt(
+; CHECK-SAME: <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call <4 x i8> @llvm.ucmp.v4i8.v4i32(<4 x i32> [[X]], <4 x i32> [[Y]])
+; CHECK-NEXT:    ret <4 x i8> [[R]]
+;
   %ne_bool = icmp ne <4 x i32> %x, %y
   %ne = zext <4 x i1> %ne_bool to <4 x i8>
   %lt = icmp ult <4 x i32> %x, %y
@@ -207,33 +212,44 @@ define <4 x i8> @ucmp_from_select_vec(<4 x i32> %x, <4 x i32> %y) {
   ret <4 x i8> %r
 }
 
-; Negative test: false value of the select is not `icmp ne x, y`
-define i8 @ucmp_from_select_neg1(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select_neg1(
+; Commuted operands
+define i8 @ucmp_from_select_lt_commuted_ops1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_commuted_ops1(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
-; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
-  %ne_bool = icmp eq i32 %x, %y
+  %ne_bool = icmp ne i32 %y, %x
   %ne = zext i1 %ne_bool to i8
   %lt = icmp ult i32 %x, %y
   %r = select i1 %lt, i8 -1, i8 %ne
   ret i8 %r
 }
 
-define i8 @ucmp_from_select_neg2(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select_neg2(
+define i8 @ucmp_from_select_lt_commuted_ops2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_commuted_ops2(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
-; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %lt = icmp ugt i32 %y, %x
+  %r = select i1 %lt, i8 -1, i8 %ne
+  ret i8 %r
+}
+
+; Negative test: false value of the select is not `icmp ne x, y`
+define i8 @ucmp_from_select_lt_neg1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp eq i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
 ; CHECK-NEXT:    [[LT:%.*]] = icmp ult i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[LT]], i8 -1, i8 [[NE]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
-  %ne_bool = icmp ne i32 %y, %x
+  %ne_bool = icmp eq i32 %x, %y
   %ne = zext i1 %ne_bool to i8
   %lt = icmp ult i32 %x, %y
   %r = select i1 %lt, i8 -1, i8 %ne
@@ -241,8 +257,8 @@ define i8 @ucmp_from_select_neg2(i32 %x, i32 %y) {
 }
 
 ; Negative test: true value of select is not -1
-define i8 @ucmp_from_select_neg3(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select_neg3(
+define i8 @ucmp_from_select_lt_neg2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg2(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
@@ -258,8 +274,8 @@ define i8 @ucmp_from_select_neg3(i32 %x, i32 %y) {
 }
 
 ; Negative test: false value of select is sign-extended instead of zero-extended
-define i8 @ucmp_from_select_neg4(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select_neg4(
+define i8 @ucmp_from_select_lt_neg3(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg3(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
@@ -272,9 +288,9 @@ define i8 @ucmp_from_select_neg4(i32 %x, i32 %y) {
   ret i8 %r
 }
 
-; Negative test: condition of select is not (x s< y)
-define i8 @ucmp_from_select_neg5(i32 %x, i32 %y) {
-; CHECK-LABEL: define i8 @ucmp_from_select_neg5(
+; Negative test: condition of select is not (x u< y)
+define i8 @ucmp_from_select_lt_neg4(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_lt_neg4(
 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
 ; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
@@ -288,3 +304,188 @@ define i8 @ucmp_from_select_neg5(i32 %x, i32 %y) {
   %r = select i1 %lt, i8 -1, i8 %ne
   ret i8 %r
 }
+
+; Fold (x u<= y) ? sext(x != y) : 1 into ucmp(x, y)
+define i8 @ucmp_from_select_le(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_le(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %le = icmp ule i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 1
+  ret i8 %r
+}
+
+; Negative test: condition of select is not (x u<= y)
+define i8 @ucmp_from_select_le_neg1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_le_neg1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LE_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LE_NOT]], i8 1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ult i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %le = icmp ule i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 1
+  ret i8 %r
+}
+
+; Negative test: true value of select is zero-extended instead of sign-extended
+define i8 @ucmp_from_select_le_neg2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_le_neg2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %le = icmp ule i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 1
+  ret i8 %r
+}
+
+; Negative test: true value is not x != y
+define i8 @ucmp_from_select_le_neg3(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_le_neg3(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[LE_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[LE_NOT]], i8 1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp sgt i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %le = icmp ule i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 1
+  ret i8 %r
+}
+
+; Negative test: false value is not 1
+define i8 @ucmp_from_select_le_neg4(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_le_neg4(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %le = icmp ule i32 %x, %y
+  %r = select i1 %le, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Fold (x u>= y) ? zext(x != y) : -1 into ucmp(x, y)
+define i8 @ucmp_from_select_ge(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp uge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Commuted operands
+define i8 @ucmp_from_select_ge_commuted_ops1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_commuted_ops1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %y, %x
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp uge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+define i8 @ucmp_from_select_ge_commuted_ops2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_commuted_ops2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp ule i32 %y, %x
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Negative test: condition is not x u>= y
+define i8 @ucmp_from_select_ge_neg1(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg1(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[GE:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE]], i8 [[NE]], i8 -1
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp ult i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Negative test: true value is sign-extended instead of zero-extended
+define i8 @ucmp_from_select_ge_neg2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = sext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = sext i1 %ne_bool to i8
+  %ge = icmp uge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Negative test: true value is not x != y
+define i8 @ucmp_from_select_ge_neg3(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg3(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[GE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE_NOT]], i8 -1, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp sgt i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp uge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 -1
+  ret i8 %r
+}
+
+; Negative test: false value is not -1
+define i8 @ucmp_from_select_ge_neg4(i32 %x, i32 %y) {
+; CHECK-LABEL: define i8 @ucmp_from_select_ge_neg4(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[NE_BOOL:%.*]] = icmp ne i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[NE:%.*]] = zext i1 [[NE_BOOL]] to i8
+; CHECK-NEXT:    [[GE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[GE_NOT]], i8 3, i8 [[NE]]
+; CHECK-NEXT:    ret i8 [[R]]
+;
+  %ne_bool = icmp ne i32 %x, %y
+  %ne = zext i1 %ne_bool to i8
+  %ge = icmp uge i32 %x, %y
+  %r = select i1 %ge, i8 %ne, i8 3
+  ret i8 %r
+}

>From d3613143e4a14e31e90c4f5a20eeef425bcc1060 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:25:35 +0100
Subject: [PATCH 9/9] Update preexisting tests

---
 .../Transforms/InstCombine/select-select.ll   | 34 ++++---------------
 .../PhaseOrdering/partialord-ule.ll           |  8 +++--
 2 files changed, 13 insertions(+), 29 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/select-select.ll b/llvm/test/Transforms/InstCombine/select-select.ll
index 36b1e50ab1160a..5460ba1bc55838 100644
--- a/llvm/test/Transforms/InstCombine/select-select.ll
+++ b/llvm/test/Transforms/InstCombine/select-select.ll
@@ -294,10 +294,7 @@ define i8 @strong_order_cmp_eq_slt(i32 %a, i32 %b) {
 
 define i8 @strong_order_cmp_eq_sgt(i32 %a, i32 %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_sgt(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext i1 [[CMP_EQ]] to i8
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp sgt i32 [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
 ; CHECK-NEXT:    ret i8 [[SEL_GT]]
 ;
   %cmp.eq = icmp eq i32 %a, %b
@@ -321,10 +318,7 @@ define i8 @strong_order_cmp_eq_ult(i32 %a, i32 %b) {
 
 define i8 @strong_order_cmp_eq_ugt(i32 %a, i32 %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ugt(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext i1 [[CMP_EQ]] to i8
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt i32 [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
 ; CHECK-NEXT:    ret i8 [[SEL_GT]]
 ;
   %cmp.eq = icmp eq i32 %a, %b
@@ -398,9 +392,7 @@ define i8 @strong_order_cmp_ne_ugt_ne_not_one_use(i32 %a, i32 %b) {
 ; CHECK-LABEL: @strong_order_cmp_ne_ugt_ne_not_one_use(
 ; CHECK-NEXT:    [[CMP_NE:%.*]] = icmp ne i32 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[CMP_NE]])
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext i1 [[CMP_NE]] to i8
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt i32 [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
 ; CHECK-NEXT:    ret i8 [[SEL_GT]]
 ;
   %cmp.ne = icmp ne i32 %a, %b
@@ -529,10 +521,7 @@ define <2 x i8> @strong_order_cmp_ugt_ult_vector_poison(<2 x i32> %a, <2 x i32>
 
 define <2 x i8> @strong_order_cmp_eq_ugt_vector(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ugt_vector(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext <2 x i1> [[CMP_EQ]] to <2 x i8>
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select <2 x i1> [[CMP_GT]], <2 x i8> <i8 1, i8 1>, <2 x i8> [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
 ; CHECK-NEXT:    ret <2 x i8> [[SEL_GT]]
 ;
   %cmp.eq = icmp eq <2 x i32> %a, %b
@@ -544,10 +533,7 @@ define <2 x i8> @strong_order_cmp_eq_ugt_vector(<2 x i32> %a, <2 x i32> %b) {
 
 define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison1(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ugt_vector_poison1(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext <2 x i1> [[CMP_EQ]] to <2 x i8>
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select <2 x i1> [[CMP_GT]], <2 x i8> <i8 1, i8 1>, <2 x i8> [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
 ; CHECK-NEXT:    ret <2 x i8> [[SEL_GT]]
 ;
   %cmp.eq = icmp eq <2 x i32> %a, %b
@@ -559,10 +545,7 @@ define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison1(<2 x i32> %a, <2 x i32>
 
 define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison2(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ugt_vector_poison2(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext <2 x i1> [[CMP_EQ]] to <2 x i8>
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select <2 x i1> [[CMP_GT]], <2 x i8> <i8 1, i8 1>, <2 x i8> [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
 ; CHECK-NEXT:    ret <2 x i8> [[SEL_GT]]
 ;
   %cmp.eq = icmp eq <2 x i32> %a, %b
@@ -574,10 +557,7 @@ define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison2(<2 x i32> %a, <2 x i32>
 
 define <2 x i8> @strong_order_cmp_eq_ugt_vector_poison3(<2 x i32> %a, <2 x i32> %b) {
 ; CHECK-LABEL: @strong_order_cmp_eq_ugt_vector_poison3(
-; CHECK-NEXT:    [[CMP_EQ:%.*]] = icmp ne <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[SEL_EQ:%.*]] = sext <2 x i1> [[CMP_EQ]] to <2 x i8>
-; CHECK-NEXT:    [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A]], [[B]]
-; CHECK-NEXT:    [[SEL_GT:%.*]] = select <2 x i1> [[CMP_GT]], <2 x i8> <i8 1, i8 poison>, <2 x i8> [[SEL_EQ]]
+; CHECK-NEXT:    [[SEL_GT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
 ; CHECK-NEXT:    ret <2 x i8> [[SEL_GT]]
 ;
   %cmp.eq = icmp eq <2 x i32> %a, %b
diff --git a/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll b/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
index 23a82c29012d96..d35e7fe0a819fc 100644
--- a/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
+++ b/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
@@ -6,8 +6,12 @@
 define i1 @ule(i32 %a, i32 %b) {
 ; CHECK-LABEL: @ule(
 ; CHECK-NEXT:  start:
-; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp ule i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    ret i1 [[DOTNOT]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[SEL1:%.*]] = tail call i64 @llvm.ucmp.i64.i32(i32 [[A]], i32 [[B]])
+; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i64 [[SEL1]], 1
+; CHECK-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp ult i64 [[TMP0]], 2
+; CHECK-NEXT:    [[SWITCH_SELECTCMP:%.*]] = select i1 [[CMP1]], i1 true, i1 [[SWITCH_SELECTCMP1]]
+; CHECK-NEXT:    ret i1 [[SWITCH_SELECTCMP]]
 ;
 start:
   %cmp1 = icmp eq i32 %a, %b



More information about the llvm-commits mailing list