From 7513a57f5af9c77a0d1fd6f1ca6aa8323833161e Mon Sep 17 00:00:00 2001 From: Poseydon42 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 460ea96b16fcfa9..cee9c2226cc1ef4 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 8690e23ea2e0e53..ff705091356e06a 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 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 16f1c3ba15eba2d..ca421176b1b95b5 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 b86f27168303a1e..53125175699d366 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(SI.getTrueValue()) || + !dyn_cast(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 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 cee9c2226cc1ef4..2dc1e5322edb1cd 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 ff705091356e06a..3764e7b61bf4c52 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 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 53125175699d366..cbd3b2841f4f0b3 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(SI.getTrueValue()) || - !dyn_cast(SI.getTrueValue())->isAllOnesValue()) + if (!isa(SI.getTrueValue()) || + !dyn_cast(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 2dc1e5322edb1cd..4b181ed49b9759c 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 3764e7b61bf4c52..c438cc2055befe6 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 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 84fe973093e327f..36b1e50ab1160ac 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 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 cbd3b2841f4f0b3..edffcad0fc2be9e 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 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 edffcad0fc2be9e..bacba355fd5ff1a 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(SI.getTrueValue()) || - !dyn_cast(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 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 4b181ed49b9759c..7f374c5f9a1d645 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 c438cc2055befe6..ad8a57825253b0f 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 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 36b1e50ab1160ac..5460ba1bc558384 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> , <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> , <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> , <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> , <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 23a82c29012d967..d35e7fe0a819fc1 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 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 bacba355fd5ff1a..ecec0a61a4d506b 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 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 d35e7fe0a819fc1..6d4a8e31edbec05 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 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 ecec0a61a4d506b..6dde110bc72c7b6 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 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 6dde110bc72c7b6..b47db91a99be750 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); }