[clang] [InstCombine] Fix transforms of two select patterns (PR #65845)

Yingwei Zheng via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 17 04:57:38 PDT 2023


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/65845

>From 91af70acd72c8e889f542ba6dfff6401b89b2dc5 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 9 Sep 2023 16:47:24 +0800
Subject: [PATCH] [InstCombine] Fix transforms of select (~a | c), a, b and
 select (c & b), a, b

---
 .../InstCombine/InstCombineSelect.cpp         |  17 +-
 .../Transforms/InstCombine/select-and-or.ll   | 214 +++++++++++++-----
 2 files changed, 166 insertions(+), 65 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 33d370690e71a8c..7913644d376f80b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3086,17 +3086,18 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
                                 m_c_LogicalOr(m_Deferred(A), m_Deferred(B)))))
     return BinaryOperator::CreateXor(A, B);
 
-  // select (~a | c), a, b -> and a, (or c, freeze(b))
+  // select (~a | c), a, b -> select a, (select c, true, b), false
   if (match(CondVal, m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))) &&
       CondVal->hasOneUse()) {
-    FalseVal = Builder.CreateFreeze(FalseVal);
-    return BinaryOperator::CreateAnd(TrueVal, Builder.CreateOr(C, FalseVal));
+    Value *OrV = Builder.CreateSelect(C, One, FalseVal);
+    return SelectInst::Create(TrueVal, OrV, Zero);
   }
-  // select (~c & b), a, b -> and b, (or freeze(a), c)
-  if (match(CondVal, m_c_And(m_Not(m_Value(C)), m_Specific(FalseVal))) &&
-      CondVal->hasOneUse()) {
-    TrueVal = Builder.CreateFreeze(TrueVal);
-    return BinaryOperator::CreateAnd(FalseVal, Builder.CreateOr(C, TrueVal));
+  // select (c & b), a, b -> select b, (select ~c, true, a), false
+  if (match(CondVal, m_c_And(m_Value(C), m_Specific(FalseVal))) &&
+      CondVal->hasOneUse() && isFreeToInvert(C, C->hasOneUse())) {
+    Value *NotC = Builder.CreateNot(C);
+    Value *OrV = Builder.CreateSelect(NotC, One, TrueVal);
+    return SelectInst::Create(FalseVal, OrV, Zero);
   }
   // select (a | c), a, b -> select a, true, (select ~c, b, false)
   if (match(CondVal, m_c_Or(m_Specific(TrueVal), m_Value(C))) &&
diff --git a/llvm/test/Transforms/InstCombine/select-and-or.ll b/llvm/test/Transforms/InstCombine/select-and-or.ll
index fb78f0affcb8f14..7edcd767b86ecba 100644
--- a/llvm/test/Transforms/InstCombine/select-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/select-and-or.ll
@@ -453,9 +453,8 @@ define i1 @demorgan_select_infloop2(i1 %L) {
 
 define i1 @and_or1(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @and_or1(
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nota = xor i1 %a, true
@@ -466,9 +465,8 @@ define i1 @and_or1(i1 %a, i1 %b, i1 %c) {
 
 define i1 @and_or2(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @and_or2(
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[A:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP2]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notc = xor i1 %c, true
@@ -477,32 +475,32 @@ define i1 @and_or2(i1 %a, i1 %b, i1 %c) {
   ret i1 %r
 }
 
-define i1 @and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) {
-; CHECK-LABEL: @and_or1_bundef(
-; CHECK-NEXT:    [[TMP1:%.*]] = or i1 [[C:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP1]], [[A:%.*]]
+define i1 @and_or1_commuted(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @and_or1_commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[A:%.*]], i1 [[TMP1]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %nota = xor i1 %a, true
-  %cond = or i1 %nota, %c
+  %cond = or i1 %c, %nota
   %r = select i1 %cond, i1 %a, i1 %b
   ret i1 %r
 }
 
-define i1 @and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @and_or2_aundef(
-; CHECK-NEXT:    [[TMP1:%.*]] = or i1 [[C:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP1]], [[B:%.*]]
+define i1 @and_or2_commuted(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @and_or2_commuted(
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[A:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[B:%.*]], i1 [[TMP1]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %notc = xor i1 %c, true
-  %cond = and i1 %notc, %b
+  %cond = and i1 %b, %notc
   %r = select i1 %cond, i1 %a, i1 %b
   ret i1 %r
 }
 
-define i1 @no_and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) {
-; CHECK-LABEL: @no_and_or1_bundef(
+define i1 @and_or1_multiuse(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @and_or1_multiuse(
 ; CHECK-NEXT:    [[NOTA:%.*]] = xor i1 [[A:%.*]], true
 ; CHECK-NEXT:    [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[COND]])
@@ -516,8 +514,8 @@ define i1 @no_and_or1_bundef(i1 %a, i1 noundef %b, i1 %c) {
   ret i1 %r
 }
 
-define i1 @no_and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) {
-; CHECK-LABEL: @no_and_or2_aundef(
+define i1 @and_or2_multiuse(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @and_or2_multiuse(
 ; CHECK-NEXT:    [[NOTC:%.*]] = xor i1 [[C:%.*]], true
 ; CHECK-NEXT:    [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[COND]])
@@ -531,38 +529,64 @@ define i1 @no_and_or2_aundef(i1 noundef %a, i1 %b, i1 %c) {
   ret i1 %r
 }
 
-define i1 @and_or1_op1not(i1 %a, i1 %b) {
-; CHECK-LABEL: @and_or1_op1not(
-; CHECK-NEXT:    [[C:%.*]] = call i1 @gen_i1()
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[B:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[C]], [[TMP1]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP2]], [[A:%.*]]
-; CHECK-NEXT:    ret i1 [[R]]
+define <2 x i1> @and_or1_vec(<2 x i1> %a, <2 x i1> %b) {
+; CHECK-LABEL: @and_or1_vec(
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
-  %c = call i1 @gen_i1()
-  %nota = xor i1 %a, true
-  %cond = or i1 %c, %nota
-  %r = select i1 %cond, i1 %a, i1 %b
-  ret i1 %r
+  %c = call <2 x i1> @gen_v2i1()
+  %nota = xor <2 x i1> %a, <i1 true, i1 true>
+  %cond = or <2 x i1> %nota, %c
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
 }
 
-define i1 @and_or2_op1not(i1 %a, i1 %c) {
-; CHECK-LABEL: @and_or2_op1not(
-; CHECK-NEXT:    [[B:%.*]] = call i1 @gen_i1()
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[A:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = or i1 [[TMP1]], [[C:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i1 [[B]], [[TMP2]]
-; CHECK-NEXT:    ret i1 [[R]]
+define <2 x i1> @and_or2_vec(<2 x i1> %a, <2 x i1> %b) {
+; CHECK-LABEL: @and_or2_vec(
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; 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:    ret <2 x i1> [[R]]
 ;
-  %b = call i1 @gen_i1()
-  %notc = xor i1 %c, true
-  %cond = and i1 %b, %notc
-  %r = select i1 %cond, i1 %a, i1 %b
-  ret i1 %r
+  %c = call <2 x i1> @gen_v2i1()
+  %notc = xor <2 x i1> %c, <i1 true, i1 true>
+  %cond = and <2 x i1> %notc, %b
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
 }
 
-define i1 @neg_and_or1(i1 %a, i1 %b, i1 %c, i1 %d) {
-; CHECK-LABEL: @neg_and_or1(
+define <2 x i1> @and_or1_vec_commuted(<2 x i1> %a, <2 x i1> %b) {
+; CHECK-LABEL: @and_or1_vec_commuted(
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[C]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[A:%.*]], <2 x i1> [[TMP1]], <2 x i1> zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %c = call <2 x i1> @gen_v2i1()
+  %nota = xor <2 x i1> %a, <i1 true, i1 true>
+  %cond = or <2 x i1> %c, %nota
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @and_or2_vec_commuted(<2 x i1> %a, <2 x i1> %b) {
+; CHECK-LABEL: @and_or2_vec_commuted(
+; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
+; 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:    ret <2 x i1> [[R]]
+;
+  %c = call <2 x i1> @gen_v2i1()
+  %notc = xor <2 x i1> %c, <i1 true, i1 true>
+  %cond = and <2 x i1> %b, %notc
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
+}
+
+define i1 @and_or1_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) {
+; CHECK-LABEL: @and_or1_wrong_operand(
 ; CHECK-NEXT:    [[NOTA:%.*]] = xor i1 [[A:%.*]], true
 ; CHECK-NEXT:    [[COND:%.*]] = or i1 [[NOTA]], [[C:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[D:%.*]], i1 [[B:%.*]]
@@ -574,8 +598,8 @@ define i1 @neg_and_or1(i1 %a, i1 %b, i1 %c, i1 %d) {
   ret i1 %r
 }
 
-define i1 @neg_and_or2(i1 %a, i1 %b, i1 %c, i1 %d) {
-; CHECK-LABEL: @neg_and_or2(
+define i1 @and_or2_wrong_operand(i1 %a, i1 %b, i1 %c, i1 %d) {
+; CHECK-LABEL: @and_or2_wrong_operand(
 ; CHECK-NEXT:    [[NOTC:%.*]] = xor i1 [[C:%.*]], true
 ; CHECK-NEXT:    [[COND:%.*]] = and i1 [[NOTC]], [[B:%.*]]
 ; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[D:%.*]]
@@ -587,21 +611,97 @@ define i1 @neg_and_or2(i1 %a, i1 %b, i1 %c, i1 %d) {
   ret i1 %r
 }
 
-define <2 x i1> @and_or1_op1not_vec(<2 x i1> %a, <2 x i1> %b) {
-; CHECK-LABEL: @and_or1_op1not_vec(
-; CHECK-NEXT:    [[C:%.*]] = call <2 x i1> @gen_v2i1()
-; CHECK-NEXT:    [[TMP1:%.*]] = freeze <2 x i1> [[B:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = or <2 x i1> [[C]], [[TMP1]]
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i1> [[TMP2]], [[A:%.*]]
+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:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = and i1 %b, %c
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+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:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = and i1 %c, %b
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+define i1 @and_or3_not_free_to_invert(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @and_or3_not_free_to_invert(
+; CHECK-NEXT:    [[COND:%.*]] = and i1 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[B]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %cond = and i1 %b, %c
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+define i1 @and_or3_multiuse(i1 %a, i1 %b, i32 %x, i32 %y) {
+; CHECK-LABEL: @and_or3_multiuse(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = and i1 [[C]], [[B:%.*]]
+; 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 = and i1 %b, %c
+  call void @use(i1 %cond)
+  %r = select i1 %cond, i1 %a, i1 %b
+  ret i1 %r
+}
+
+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:    ret <2 x i1> [[R]]
 ;
-  %c = call <2 x i1> @gen_v2i1()
-  %nota = xor <2 x i1> %a, <i1 true, i1 true>
-  %cond = or <2 x i1> %c, %nota
+  %c = icmp eq <2 x i32> %x, %y
+  %cond = and <2 x i1> %b, %c
   %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
   ret <2 x i1> %r
 }
 
+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:    ret <2 x i1> [[R]]
+;
+  %c = icmp eq <2 x i32> %x, %y
+  %cond = and <2 x i1> %c, %b
+  %r = select <2 x i1> %cond, <2 x i1> %a, <2 x i1> %b
+  ret <2 x i1> %r
+}
+
+define i1 @and_or3_wrong_operand(i1 %a, i1 %b, i32 %x, i32 %y, i1 %d) {
+; CHECK-LABEL: @and_or3_wrong_operand(
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[COND:%.*]] = and i1 [[C]], [[B:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[COND]], i1 [[A:%.*]], i1 [[D:%.*]]
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %c = icmp eq i32 %x, %y
+  %cond = and i1 %b, %c
+  %r = select i1 %cond, i1 %a, i1 %d
+  ret i1 %r
+}
+
 define i1 @or_and1(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @or_and1(
 ; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[C:%.*]], i1 [[A:%.*]], i1 false



More information about the cfe-commits mailing list