[llvm] [InstCombine] Fold `select (a == V1 | a == V2), a, V2` to `select (a == V1), V1, V2` (PR #76203)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 21 21:01:34 PST 2023
https://github.com/XChy created https://github.com/llvm/llvm-project/pull/76203
Fixes #75784
Alive2 proof: https://alive2.llvm.org/ce/z/PNBSjJ
Note: when `V1 == undef` and `a == V2`, such transform is not valid: https://alive2.llvm.org/ce/z/BDT7Q9
>From 763ca8a665328a772e88f2fbc4d11a041f7c6a2d Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Fri, 22 Dec 2023 01:18:57 +0800
Subject: [PATCH 1/2] [InstCombine][NFC] Precommit tests for PR75784
---
.../Transforms/InstCombine/select-and-or.ll | 208 ++++++++++++++++--
1 file changed, 184 insertions(+), 24 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index 7edcd767b86ecb..d30b543945216d 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -613,9 +613,9 @@ define i1 @and_or2_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) {
define i1 @and_or3(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @and_or3(
-; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 true, i1 [[A:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP2]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
%c = icmp eq i32 %x, %y
@@ -626,9 +626,9 @@ define i1 @and_or3(i1 %a, i1 %b, i32 %x, i32 %y) {
define i1 @and_or3_commuted(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @and_or3_commuted(
-; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 true, i1 [[A:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP2]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
%c = icmp eq i32 %x, %y
@@ -665,9 +665,9 @@ define i1 @and_or3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) {
define <2 x i1> @and_or3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @and_or3_vec(
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP2]], <2 x i1> zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%c = icmp eq <2 x i32> %x, %y
@@ -678,9 +678,9 @@ define <2 x i1> @and_or3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %
define <2 x i1> @and_or3_vec_commuted(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @and_or3_vec_commuted(
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]]
-; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[A:%.*]]
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> [[TMP2]], <2 x i1> zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%c = icmp eq <2 x i32> %x, %y
@@ -877,9 +877,9 @@ entry:
define i1 @or_and3(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @or_and3(
-; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 false
-; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%c = icmp eq i32 %x, %y
@@ -890,9 +890,9 @@ define i1 @or_and3(i1 %a, i1 %b, i32 %x, i32 %y) {
define i1 @or_and3_commuted(i1 %a, i1 %b, i32 %x, i32 %y) {
; CHECK-LABEL: @or_and3_commuted(
-; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C]], i1 [[B:%.*]], i1 false
-; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT: [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%c = icmp eq i32 %x, %y
@@ -929,9 +929,9 @@ define i1 @or_and3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) {
define <2 x i1> @or_and3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @or_and3_vec(
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
-; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP2]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%c = icmp eq <2 x i32> %x, %y
@@ -942,9 +942,9 @@ define <2 x i1> @or_and3_vec(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %
define <2 x i1> @or_and3_vec_commuted(<2 x i1> %a, <2 x i1> %b, <2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @or_and3_vec_commuted(
-; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
-; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP1]]
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i32> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i1> [[B:%.*]], <2 x i1> zeroinitializer
+; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP2]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%c = icmp eq <2 x i32> %x, %y
@@ -965,3 +965,163 @@ define i1 @or_and3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) {
%r = select i1 %cond, i1 %d, i1 %b
ret i1 %r
}
+
+define i32 @and_eq_v1(i32 %a, i32 noundef %v1, i32 %v2) {
+; CHECK-LABEL: @and_eq_v1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp eq i32 %a, %v1
+ %cmp1 = icmp eq i32 %a, %v2
+ %cond = or i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %a, i32 %v2
+ ret i32 %select
+}
+
+define i32 @and_eq_v2(i32 %a, i32 %v1, i32 noundef %v2) {
+; CHECK-LABEL: @and_eq_v2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V1]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp eq i32 %a, %v1
+ %cmp1 = icmp eq i32 %a, %v2
+ %cond = or i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %a, i32 %v1
+ ret i32 %select
+}
+
+define i32 @and_ne_v1(i32 %a, i32 noundef %v1, i32 %v2) {
+; CHECK-LABEL: @and_ne_v1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[V2]], i32 [[A]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp ne i32 %a, %v1
+ %cmp1 = icmp ne i32 %a, %v2
+ %cond = and i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %v2, i32 %a
+ ret i32 %select
+}
+
+define i32 @and_ne_v2(i32 %a, i32 %v1, i32 noundef %v2) {
+; CHECK-LABEL: @and_ne_v2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[V1]], i32 [[A]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp ne i32 %a, %v1
+ %cmp1 = icmp ne i32 %a, %v2
+ %cond = and i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %v1, i32 %a
+ ret i32 %select
+}
+
+define i32 @and_eq_v1_multi_use(i32 %a, i32 noundef %v1, i32 %v2) {
+; CHECK-LABEL: @and_eq_v1_multi_use(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: call void @use(i1 [[CMP]])
+; CHECK-NEXT: call void @use(i1 [[CMP1]])
+; CHECK-NEXT: call void @use(i1 [[COND]])
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp eq i32 %a, %v1
+ %cmp1 = icmp eq i32 %a, %v2
+ %cond = or i1 %cmp, %cmp1
+ call void @use(i1 %cmp)
+ call void @use(i1 %cmp1)
+ call void @use(i1 %cond)
+ %select = select i1 %cond, i32 %a, i32 %v2
+ ret i32 %select
+}
+
+define <2 x i32> @and_eq_v1_vec(<2 x i32> %a, <2 x i32> noundef %v1, <2 x i32> %v2) {
+; CHECK-LABEL: @and_eq_v1_vec(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq <2 x i32> [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or <2 x i1> [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[A]], <2 x i32> [[V2]]
+; CHECK-NEXT: ret <2 x i32> [[SELECT]]
+;
+entry:
+ %cmp = icmp eq <2 x i32> %a, %v1
+ %cmp1 = icmp eq <2 x i32> %a, %v2
+ %cond = or <2 x i1> %cmp, %cmp1
+ %select = select <2 x i1> %cond, <2 x i32> %a, <2 x i32> %v2
+ ret <2 x i32> %select
+}
+
+
+define i32 @and_slt_v1_fail(i32 %a, i32 noundef %v1, i32 noundef %v2) {
+; CHECK-LABEL: @and_slt_v1_fail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp slt i32 %a, %v1
+ %cmp1 = icmp slt i32 %a, %v2
+ %cond = or i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %a, i32 %v2
+ ret i32 %select
+}
+
+define i32 @and_ne_different_operands_fail(i32 %a, i32 %b, i32 noundef %v1, i32 noundef %v2) {
+; CHECK-LABEL: @and_ne_different_operands_fail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[B:%.*]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[V1]], i32 [[A]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp ne i32 %a, %v1
+ %cmp1 = icmp ne i32 %b, %v2
+ %cond = and i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %v1, i32 %a
+ ret i32 %select
+}
+
+define i32 @and_eq_v1_undef_fail(i32 %a, i32 %v1, i32 %v2) {
+; CHECK-LABEL: @and_eq_v1_undef_fail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: ret i32 [[SELECT]]
+;
+entry:
+ %cmp = icmp eq i32 %a, %v1
+ %cmp1 = icmp eq i32 %a, %v2
+ %cond = or i1 %cmp, %cmp1
+ %select = select i1 %cond, i32 %a, i32 %v2
+ ret i32 %select
+}
>From 07938c04890d5b84b8c40852408c5fac4c3637a7 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Fri, 22 Dec 2023 03:49:05 +0800
Subject: [PATCH 2/2] [InstCombine] Fold select of and/or of icmp to select of
single icmp
---
.../InstCombine/InstCombineInternal.h | 2 +-
.../InstCombine/InstCombineSelect.cpp | 66 +++++++++++++++++++
.../Transforms/InstCombine/select-and-or.ll | 28 +++-----
3 files changed, 76 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 9e76a0cf17b183..0667b08af99f51 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -442,7 +442,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
// into simplier select instruction using isImpliedCondition.
Instruction *foldAndOrOfSelectUsingImpliedCond(Value *Op, SelectInst &SI,
bool IsAnd);
-
+ Instruction *foldSelectOfAndOr(SelectInst &SI);
Instruction *hoistFNegAboveFMulFDiv(Value *FNegOp, Instruction &FMFSource);
public:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 20bf00344b144b..90d905ac1c69a8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2683,6 +2683,69 @@ Instruction *InstCombinerImpl::foldAndOrOfSelectUsingImpliedCond(Value *Op,
}
}
+Instruction *InstCombinerImpl::foldSelectOfAndOr(SelectInst &SI) {
+ BinaryOperator *CondVal = dyn_cast<BinaryOperator>(SI.getCondition());
+ if (!CondVal)
+ return nullptr;
+
+ BinaryOperator::BinaryOps BinOpCode = CondVal->getOpcode();
+ bool IsAnd;
+
+ if (BinOpCode == BinaryOperator::Or)
+ IsAnd = false;
+ else if (BinOpCode == BinaryOperator::And)
+ IsAnd = true;
+ else
+ return nullptr;
+
+ Value *TrueVal = SI.getTrueValue(), *FalseVal = SI.getFalseValue();
+
+ // %cmp = icmp eq i32 %a, %v1 (v1 must not be undef)
+ // %cmp1 = icmp eq i32 %a, %v2
+ // %cond = or i1 %cmp, %cmp1
+ // %select = select i1 %cond, i32 %a, i32 %v2
+ // =>
+ // %cond = icmp eq i32 %a, %v1
+ // %select = select i1 %cond, i32 %v1, i32 %v2
+
+ // Or for an inverted version, we fold it like:
+ // %cmp = icmp ne i32 %a, %v1 (v1 must not be undef)
+ // %cmp1 = icmp ne i32 %a, %v2
+ // %cond = and i1 %cmp, %cmp1
+ // %select = select i1 %cond, i32 %v2, i32 %a
+ // =>
+ // %cond = icmp eq i32 %a, %v1
+ // %select = select i1 %cond, i32 %v1, i32 %v2
+
+ Value *A, *V1, *V2;
+ CmpInst::Predicate ExpectedPred =
+ IsAnd ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ;
+ CmpInst::Predicate Pred1, Pred2;
+ Value *Cmp1 = CondVal->getOperand(0);
+ Value *Cmp2 = CondVal->getOperand(1);
+ if (match(Cmp1, m_c_ICmp(Pred1, m_Value(A), m_Value(V1))) &&
+ Pred1 == ExpectedPred &&
+ match(Cmp2, m_c_ICmp(Pred2, m_Deferred(A), m_Value(V2))) &&
+ Pred2 == ExpectedPred) {
+ Value *NewFalseVal = IsAnd ? TrueVal : FalseVal;
+ Value *ExpectedA = IsAnd ? FalseVal : TrueVal;
+ if (ExpectedA == A && (NewFalseVal == V1 || NewFalseVal == V2)) {
+ Value *NewTrueVal = NewFalseVal == V1 ? V2 : V1;
+ if (!isGuaranteedNotToBeUndef(NewTrueVal, SQ.AC, &SI, &DT))
+ return nullptr;
+
+ Value *NewCond = NewTrueVal == V1 ? Cmp1 : Cmp2;
+ if (!IsAnd)
+ return SelectInst::Create(NewCond, NewTrueVal, NewFalseVal);
+ // Invert it when original select is inverted
+ return SelectInst::Create(NewCond, NewFalseVal, NewTrueVal);
+ }
+ return nullptr;
+ }
+
+ return nullptr;
+}
+
// Canonicalize select with fcmp to fabs(). -0.0 makes this tricky. We need
// fast-math-flags (nsz) or fsub with +0.0 (not fneg) for this to work.
static Instruction *foldSelectWithFCmpToFabs(SelectInst &SI,
@@ -3409,6 +3472,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
}
+ if (Instruction *I = foldSelectOfAndOr(SI))
+ return I;
+
auto *SIFPOp = dyn_cast<FPMathOperator>(&SI);
if (auto *FCmp = dyn_cast<FCmpInst>(CondVal)) {
diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index d30b543945216d..cf1b6377ff156d 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -970,9 +970,7 @@ define i32 @and_eq_v1(i32 %a, i32 noundef %v1, i32 %v2) {
; CHECK-LABEL: @and_eq_v1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[V1]], i32 [[V2:%.*]]
; CHECK-NEXT: ret i32 [[SELECT]]
;
entry:
@@ -986,10 +984,8 @@ entry:
define i32 @and_eq_v2(i32 %a, i32 %v1, i32 noundef %v2) {
; CHECK-LABEL: @and_eq_v2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A]], [[V2:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = or i1 [[CMP]], [[CMP1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V1]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], [[V2:%.*]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP1]], i32 [[V2]], i32 [[V1:%.*]]
; CHECK-NEXT: ret i32 [[SELECT]]
;
entry:
@@ -1003,10 +999,8 @@ entry:
define i32 @and_ne_v1(i32 %a, i32 noundef %v1, i32 %v2) {
; CHECK-LABEL: @and_ne_v1(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], [[V2:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = and i1 [[CMP]], [[CMP1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[V2]], i32 [[A]]
+; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[A:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[V1]], i32 [[V2:%.*]]
; CHECK-NEXT: ret i32 [[SELECT]]
;
entry:
@@ -1020,10 +1014,8 @@ entry:
define i32 @and_ne_v2(i32 %a, i32 %v1, i32 noundef %v2) {
; CHECK-LABEL: @and_ne_v2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[A:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[A]], [[V2:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = and i1 [[CMP]], [[CMP1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[V1]], i32 [[A]]
+; CHECK-NEXT: [[CMP1_NOT:%.*]] = icmp eq i32 [[A:%.*]], [[V2:%.*]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP1_NOT]], i32 [[V2]], i32 [[V1:%.*]]
; CHECK-NEXT: ret i32 [[SELECT]]
;
entry:
@@ -1043,7 +1035,7 @@ define i32 @and_eq_v1_multi_use(i32 %a, i32 noundef %v1, i32 %v2) {
; CHECK-NEXT: call void @use(i1 [[CMP]])
; CHECK-NEXT: call void @use(i1 [[CMP1]])
; CHECK-NEXT: call void @use(i1 [[COND]])
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[A]], i32 [[V2]]
+; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[V1]], i32 [[V2]]
; CHECK-NEXT: ret i32 [[SELECT]]
;
entry:
@@ -1061,9 +1053,7 @@ define <2 x i32> @and_eq_v1_vec(<2 x i32> %a, <2 x i32> noundef %v1, <2 x i32> %
; CHECK-LABEL: @and_eq_v1_vec(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp eq <2 x i32> [[A]], [[V2:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = or <2 x i1> [[CMP]], [[CMP1]]
-; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[A]], <2 x i32> [[V2]]
+; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[V1]], <2 x i32> [[V2:%.*]]
; CHECK-NEXT: ret <2 x i32> [[SELECT]]
;
entry:
More information about the llvm-commits
mailing list