[llvm] 074f23e - [InstCombine] Fold two select patterns into or-and

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 29 09:58:26 PDT 2023


Author: Yingwei Zheng
Date: 2023-08-30T00:57:08+08:00
New Revision: 074f23e3e199a8067f0295302e07e9837c6f16d1

URL: https://github.com/llvm/llvm-project/commit/074f23e3e199a8067f0295302e07e9837c6f16d1
DIFF: https://github.com/llvm/llvm-project/commit/074f23e3e199a8067f0295302e07e9837c6f16d1.diff

LOG: [InstCombine] Fold two select patterns into or-and

This patch is the follow-up improvement of D122152.
Fixes https://github.com/llvm/llvm-project/issues/64558.

`select (a | c), a, b -> select a, true, (select ~c, b, false)` where `c` is free to invert
`select (c & ~b), a, b -> select b, true, (select c, a, false)`
Alive2: https://alive2.llvm.org/ce/z/KwxtMA

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D158983

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/select-and-or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index d5be03dd425773..4fa31ed7518995 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3083,6 +3083,19 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
     TrueVal = Builder.CreateFreeze(TrueVal);
     return BinaryOperator::CreateAnd(FalseVal, Builder.CreateOr(C, TrueVal));
   }
+  // select (a | c), a, b -> select a, true, (select ~c, b, false)
+  if (match(CondVal, m_c_Or(m_Specific(TrueVal), m_Value(C))) &&
+      CondVal->hasOneUse() && isFreeToInvert(C, C->hasOneUse())) {
+    Value *NotC = Builder.CreateNot(C);
+    Value *AndV = Builder.CreateSelect(NotC, FalseVal, Zero);
+    return SelectInst::Create(TrueVal, One, AndV);
+  }
+  // select (c & ~b), a, b -> select b, true, (select c, a, false)
+  if (match(CondVal, m_c_And(m_Value(C), m_Not(m_Specific(FalseVal)))) &&
+      CondVal->hasOneUse()) {
+    Value *AndV = Builder.CreateSelect(C, TrueVal, Zero);
+    return SelectInst::Create(FalseVal, One, AndV);
+  }
 
   if (match(FalseVal, m_Zero()) || match(TrueVal, m_One())) {
     Use *Y = nullptr;

diff  --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index 275268cd9bd047..fb78f0affcb8f1 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -604,9 +604,8 @@ define <2 x i1> @and_or1_op1not_vec(<2 x i1> %a, <2 x i1> %b) {
 
 define i1 @or_and1(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @or_and1(
-; CHECK-NEXT:    [[NOTB:%.*]] = xor i1 [[B:%.*]], true
-; CHECK-NEXT:    [[COND:%.*]] = and i1 [[NOTB]], [[C:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notb = xor i1 %b, true
@@ -617,9 +616,8 @@ define i1 @or_and1(i1 %a, i1 %b, i1 %c) {
 
 define i1 @or_and2(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @or_and2(
-; CHECK-NEXT:    [[NOTC:%.*]] = xor i1 [[C:%.*]], true
-; CHECK-NEXT:    [[COND:%.*]] = or i1 [[NOTC]], [[A:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notc = xor i1 %c, true
@@ -628,30 +626,24 @@ define i1 @or_and2(i1 %a, i1 %b, i1 %c) {
   ret i1 %r
 }
 
-define i1 @or_and1_commuted(i1 %a, i1 %b) {
+define i1 @or_and1_commuted(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @or_and1_commuted(
-; CHECK-NEXT:    [[C:%.*]] = call i1 @gen_i1()
-; CHECK-NEXT:    [[NOTB:%.*]] = xor i1 [[B:%.*]], true
-; CHECK-NEXT:    [[COND:%.*]] = and i1 [[C]], [[NOTB]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i1 true, i1 [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
-  %c = call i1 @gen_i1()
   %notb = xor i1 %b, true
   %cond = and i1 %c, %notb
   %r = select i1 %cond, i1 %a, i1 %b
   ret i1 %r
 }
 
-define i1 @or_and2_commuted(i1 %b, i1 %c) {
+define i1 @or_and2_commuted(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @or_and2_commuted(
-; CHECK-NEXT:    [[A:%.*]] = call i1 @gen_i1()
-; CHECK-NEXT:    [[NOTC:%.*]] = xor i1 [[C:%.*]], true
-; CHECK-NEXT:    [[COND:%.*]] = or i1 [[A]], [[NOTC]]
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[B:%.*]], i1 false
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
-  %a = call i1 @gen_i1()
   %notc = xor i1 %c, true
   %cond = or i1 %a, %notc
   %r = select i1 %cond, i1 %a, i1 %b
@@ -688,28 +680,30 @@ define i1 @or_and2_multiuse(i1 %a, i1 %b, i1 %c) {
   ret i1 %r
 }
 
-define <2 x i1> @or_and1_vec(<2 x i1> %a, <2 x i1> %b, <2 x i1> %c) {
+define <2 x i1> @or_and1_vec(<2 x i1> %a, <2 x i1> %b) {
 ; CHECK-LABEL: @or_and1_vec(
-; CHECK-NEXT:    [[NOTB:%.*]] = xor <2 x i1> [[B:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[COND:%.*]] = and <2 x i1> [[NOTB]], [[C:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A:%.*]], <2 x i1> [[B]]
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> [[A:%.*]], <2 x i1> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP1]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
+  %c = call <2 x i1> @gen_v2i1()
   %notb = xor <2 x i1> %b, <i1 true, i1 true>
-  %cond = and <2 x i1> %notb, %c
+  %cond = and <2 x i1> %c, %notb
   %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
   ret <2 x i1> %r
 }
 
-define <2 x i1> @or_and2_vec(<2 x i1> %a, <2 x i1> %b, <2 x i1> %c) {
+define <2 x i1> @or_and2_vec(<2 x i1> %a, <2 x i1> %b) {
 ; CHECK-LABEL: @or_and2_vec(
-; CHECK-NEXT:    [[NOTC:%.*]] = xor <2 x i1> [[C:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[COND:%.*]] = or <2 x i1> [[NOTC]], [[A:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A]], <2 x i1> [[B:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; 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:    ret <2 x i1> [[R]]
 ;
+  %c = call <2 x i1> @gen_v2i1()
   %notc = xor <2 x i1> %c, <i1 true, i1 true>
-  %cond = or <2 x i1> %notc, %a
+  %cond = or <2 x i1> %a, %notc
   %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
   ret <2 x i1> %r
 }
@@ -717,29 +711,27 @@ define <2 x i1> @or_and2_vec(<2 x i1> %a, <2 x i1> %b, <2 x i1> %c) {
 define <2 x i1> @or_and1_vec_commuted(<2 x i1> %a, <2 x i1> %b) {
 ; CHECK-LABEL: @or_and1_vec_commuted(
 ; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
-; CHECK-NEXT:    [[NOTB:%.*]] = xor <2 x i1> [[B:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[COND:%.*]] = and <2 x i1> [[C]], [[NOTB]]
-; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A:%.*]], <2 x i1> [[B]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> [[A:%.*]], <2 x i1> zeroinitializer
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[B:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[TMP1]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %c = call <2 x i1> @gen_v2i1()
   %notb = xor <2 x i1> %b, <i1 true, i1 true>
-  %cond = and <2 x i1> %c, %notb
+  %cond = and <2 x i1> %notb, %c
   %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
   ret <2 x i1> %r
 }
 
-define <2 x i1> @or_and2_vec_commuted(<2 x i1> %b, <2 x i1> %c) {
+define <2 x i1> @or_and2_vec_commuted(<2 x i1> %a, <2 x i1> %b) {
 ; CHECK-LABEL: @or_and2_vec_commuted(
-; CHECK-NEXT:    [[A:%.*]] = call <2 x i1> @gen_v2i1()
-; CHECK-NEXT:    [[NOTC:%.*]] = xor <2 x i1> [[C:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[COND:%.*]] = or <2 x i1> [[A]], [[NOTC]]
-; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[COND]], <2 x i1> [[A]], <2 x i1> [[B:%.*]]
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; 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:    ret <2 x i1> [[R]]
 ;
-  %a = call <2 x i1> @gen_v2i1()
+  %c = call <2 x i1> @gen_v2i1()
   %notc = xor <2 x i1> %c, <i1 true, i1 true>
-  %cond = or <2 x i1> %a, %notc
+  %cond = or <2 x i1> %notc, %a
   %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
   ret <2 x i1> %r
 }
@@ -773,9 +765,7 @@ define i1 @or_and2_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) {
 define i1 @pr64558(i1 noundef %a, i1 noundef %b) {
 ; CHECK-LABEL: @pr64558(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[LNOT:%.*]] = xor i1 [[B:%.*]], true
-; CHECK-NEXT:    [[AND11:%.*]] = and i1 [[LNOT]], [[A:%.*]]
-; CHECK-NEXT:    [[COND_V:%.*]] = select i1 [[AND11]], i1 [[A]], i1 [[B]]
+; CHECK-NEXT:    [[COND_V:%.*]] = or i1 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    ret i1 [[COND_V]]
 ;
 entry:
@@ -784,3 +774,94 @@ entry:
   %cond.v = select i1 %and11, i1 %a, i1 %b
   ret i1 %cond.v
 }
+
+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:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = or i1 %a, %c
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+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:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = or i1 %c, %a
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+define i1 @or_and3_not_free_to_invert(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @or_and3_not_free_to_invert(
+; CHECK-NEXT:    [[COND:%.*]] = or i1 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %cond = or i1 %a, %c
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+define i1 @or_and3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) {
+; CHECK-LABEL: @or_and3_multiuse(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = or i1 [[C]], [[A:%.*]]
+; CHECK-NEXT:    call void @use(i1 [[COND]])
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A]], i1 [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = or i1 %a, %c
+  call void @use(i1 %cond)
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+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:    ret <2 x i1> [[R]]
+;
+  %c = icmp eq <2 x i32> %x, %y
+  %cond = or <2 x i1> %a, %c
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
+}
+
+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:    ret <2 x i1> [[R]]
+;
+  %c = icmp eq <2 x i32> %x, %y
+  %cond = or <2 x i1> %c, %a
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
+}
+
+define i1 @or_and3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) {
+; CHECK-LABEL: @or_and3_wrong_operand(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = or i1 [[C]], [[A:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[D:%.*]], i1 [[B:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = or i1 %a, %c
+  %r = select i1 %cond, i1 %d, i1 %b
+  ret i1 %r
+}


        


More information about the llvm-commits mailing list