[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
Fri Aug 16 08:22:30 PDT 2024
https://github.com/Poseydon42 updated https://github.com/llvm/llvm-project/pull/101049
>From 7513a57f5af9c77a0d1fd6f1ca6aa8323833161e Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:43:33 +0100
Subject: [PATCH 01/13] 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 460ea96b16fcfa..cee9c2226cc1ef 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -208,3 +208,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 8690e23ea2e0e5..ff705091356e06 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -207,3 +207,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 29037656b0cff60f9a7c395da373b9452212c9b3 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:44:32 +0100
Subject: [PATCH 02/13] [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 16f1c3ba15eba2..ca421176b1b95b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -729,6 +729,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 b86f27168303a1..53125175699d36 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3558,6 +3558,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);
@@ -4140,5 +4172,8 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
}
+ if (auto *Instruction = foldSelectToCmp(SI))
+ return Instruction;
+
return nullptr;
}
>From 91bb1f2259e76127ab70968d3d8925f5bbb12cd2 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 18:47:11 +0100
Subject: [PATCH 03/13] 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 cee9c2226cc1ef..2dc1e5322edb1c 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -213,10 +213,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 ff705091356e06..3764e7b61bf4c5 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -212,10 +212,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 2dbc1fdbc8bcd9a21a184e11441f31203558d74c Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:19:21 +0100
Subject: [PATCH 04/13] 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 53125175699d36..cbd3b2841f4f0b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3566,8 +3566,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 2dc1e5322edb1c..4b181ed49b9759 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -223,6 +223,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 3764e7b61bf4c5..c438cc2055befe 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -222,6 +222,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 9b9bc2e0c290c15a0d07851e0beea7bbbfb66d02 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:19:40 +0100
Subject: [PATCH 05/13] 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 84dd5e80efd3e3550da51a38ae567bb5069e67de Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 29 Jul 2024 19:22:12 +0100
Subject: [PATCH 06/13] 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 cbd3b2841f4f0b..edffcad0fc2be9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4093,6 +4093,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))
@@ -4172,8 +4175,5 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
}
- if (auto *Instruction = foldSelectToCmp(SI))
- return Instruction;
-
return nullptr;
}
>From 00006d1cd48655a5be514cff8b7fbce49a187b45 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:04:00 +0100
Subject: [PATCH 07/13] 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 edffcad0fc2be9..bacba355fd5ff1 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3558,36 +3558,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 37d60277e3f73fb804670d1e8665120784435c86 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:04:15 +0100
Subject: [PATCH 08/13] 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 4b181ed49b9759..7f374c5f9a1d64 100644
--- a/llvm/test/Transforms/InstCombine/scmp.ll
+++ b/llvm/test/Transforms/InstCombine/scmp.ll
@@ -210,8 +210,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]]
@@ -224,7 +224,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
@@ -232,84 +237,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 c438cc2055befe..ad8a57825253b0 100644
--- a/llvm/test/Transforms/InstCombine/ucmp.ll
+++ b/llvm/test/Transforms/InstCombine/ucmp.ll
@@ -209,8 +209,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]]
@@ -223,7 +223,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
@@ -231,33 +236,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
@@ -265,8 +281,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
@@ -282,8 +298,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
@@ -296,9 +312,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
@@ -312,3 +328,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 0fae60f42e236c88137ff4c118168fb09fb16494 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Sat, 10 Aug 2024 13:25:35 +0100
Subject: [PATCH 09/13] 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
>From 719e474ad2a826255f919f605ccb3a34da47f951 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Mon, 12 Aug 2024 13:19:03 +0100
Subject: [PATCH 10/13] Address review comments
---
.../Transforms/InstCombine/InstCombineSelect.cpp | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index bacba355fd5ff1..ecec0a61a4d506 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3590,23 +3590,14 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
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)
+ match(FV, m_ZExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS), m_Specific(RHS)))))
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()))
+ match(FV, m_SExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS), m_Specific(RHS)))))
Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
if (Intrinsic)
>From ad2ac722069de4f86ae776fc58d934e29a2ccc56 Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Wed, 14 Aug 2024 16:04:38 +0100
Subject: [PATCH 11/13] Update the test with regression
---
llvm/test/Transforms/PhaseOrdering/partialord-ule.ll | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll b/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
index d35e7fe0a819fc..6d4a8e31edbec0 100644
--- a/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
+++ b/llvm/test/Transforms/PhaseOrdering/partialord-ule.ll
@@ -6,12 +6,8 @@
define i1 @ule(i32 %a, i32 %b) {
; CHECK-LABEL: @ule(
; CHECK-NEXT: start:
-; 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]]
+; CHECK-NEXT: [[SWITCH_SELECTCMP1:%.*]] = icmp ule i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: ret i1 [[SWITCH_SELECTCMP1]]
;
start:
%cmp1 = icmp eq i32 %a, %b
>From e7da9123fb4cf0f865448e6a1fc431a6cfdb83ce Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Wed, 14 Aug 2024 16:07:47 +0100
Subject: [PATCH 12/13] Format the code
---
.../InstCombine/InstCombineSelect.cpp | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index ecec0a61a4d506..6dde110bc72c7b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3561,7 +3561,6 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
// 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) {
@@ -3589,19 +3588,22 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
Intrinsic::ID IID =
ICmpInst::isSigned(Pred) ? Intrinsic::scmp : Intrinsic::ucmp;
- CallInst *Intrinsic = nullptr;
+ bool Replace = false;
// (x < y) ? -1 : zext(x != y)
if (ICmpInst::isLT(Pred) && match(TV, m_AllOnes()) &&
- match(FV, m_ZExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS), m_Specific(RHS)))))
- Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
+ match(FV, m_ZExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS),
+ m_Specific(RHS)))))
+ Replace = true;
// (x > y) ? 1 : sext(x != y)
if (ICmpInst::isGT(Pred) && match(TV, m_One()) &&
- match(FV, m_SExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS), m_Specific(RHS)))))
- Intrinsic = Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS});
+ match(FV, m_SExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS),
+ m_Specific(RHS)))))
+ Replace = true;
- if (Intrinsic)
- return replaceInstUsesWith(SI, Intrinsic);
+ if (Replace)
+ return replaceInstUsesWith(
+ SI, Builder.CreateIntrinsic(SI.getType(), IID, {LHS, RHS}));
return nullptr;
}
>From 12d1a9513a5c4673600eb31b3aee394149c6712f Mon Sep 17 00:00:00 2001
From: Poseydon42 <vvmposeydon at gmail.com>
Date: Fri, 16 Aug 2024 16:21:55 +0100
Subject: [PATCH 13/13] Address review comments 2
---
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 6dde110bc72c7b..b47db91a99be75 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3562,7 +3562,7 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
// (x < y) ? -1 : zext(x != y)
// (x > y) ? 1 : sext(x != y)
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
-// of the comparison in the original sequence
+// of the comparison in the original sequence.
Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
Value *TV = SI.getTrueValue();
Value *FV = SI.getFalseValue();
@@ -3580,7 +3580,7 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
// 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)) {
+ (ICmpInst::isLT(Pred) && match(TV, m_One()))) {
Pred = ICmpInst::getSwappedPredicate(Pred);
std::swap(LHS, RHS);
}
More information about the llvm-commits
mailing list