[llvm] 4a66b3b - [InstCombine] Fold pattern xor(and, or) to select

via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 3 01:12:22 PST 2023


Author: chenglin.bi
Date: 2023-02-03T17:12:16+08:00
New Revision: 4a66b3b20ed68379883ce7df52359895f5373da0

URL: https://github.com/llvm/llvm-project/commit/4a66b3b20ed68379883ce7df52359895f5373da0
DIFF: https://github.com/llvm/llvm-project/commit/4a66b3b20ed68379883ce7df52359895f5373da0.diff

LOG: [InstCombine] Fold pattern xor(and, or) to select

(A & B) ^ (A | C) --> A ? ~B : C

https://alive2.llvm.org/ce/z/KCBfXr
https://alive2.llvm.org/ce/z/Pm-zJN
https://alive2.llvm.org/ce/z/VT8uC2

Reviewed By: spatel

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/xor-and-or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 9f1de3c5dec65..f11d2fdd8d5d5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -4280,6 +4280,23 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
     }
   }
 
+  // (A & B) ^ (A | C) --> A ? ~B : C -- There are 4 commuted variants.
+  if (I.getType()->isIntOrIntVectorTy(1) &&
+      match(Op0, m_OneUse(m_LogicalAnd(m_Value(A), m_Value(B)))) &&
+      match(Op1, m_OneUse(m_LogicalOr(m_Value(C), m_Value(D))))) {
+    bool NeedFreeze = isa<SelectInst>(Op0) && isa<SelectInst>(Op1) && B == D;
+    if (B == C || B == D)
+      std::swap(A, B);
+    if (A == C)
+      std::swap(C, D);
+    if (A == D) {
+      if (NeedFreeze)
+        A = Builder.CreateFreeze(A);
+      Value *NotB = Builder.CreateNot(B);
+      return SelectInst::Create(A, NotB, C);
+    }
+  }
+
   if (auto *LHS = dyn_cast<ICmpInst>(I.getOperand(0)))
     if (auto *RHS = dyn_cast<ICmpInst>(I.getOperand(1)))
       if (Value *V = foldXorOfICmps(LHS, RHS, I))

diff  --git a/llvm/test/Transforms/InstCombine/xor-and-or.ll b/llvm/test/Transforms/InstCombine/xor-and-or.ll
index 69635a7859a02..06b1f23b240e0 100644
--- a/llvm/test/Transforms/InstCombine/xor-and-or.ll
+++ b/llvm/test/Transforms/InstCombine/xor-and-or.ll
@@ -15,9 +15,8 @@ define i1 @xor_logic_and_logic_or1(i1 %c, i1 %x, i1 %y) {
 
 define i1 @xor_logic_and_logic_or2(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_logic_and_logic_or2(
-; CHECK-NEXT:    [[O:%.*]] = select i1 [[Y:%.*]], i1 true, i1 [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select i1 [[C]], i1 [[X:%.*]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = select i1 %y, i1 true, i1 %c
@@ -28,9 +27,9 @@ define i1 @xor_logic_and_logic_or2(i1 %c, i1 %x, i1 %y) {
 
 define i1 @xor_logic_and_logic_or3(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_logic_and_logic_or3(
-; CHECK-NEXT:    [[O:%.*]] = select i1 [[Y:%.*]], i1 true, i1 [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select i1 [[X:%.*]], i1 [[C]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i1 [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i1 [[TMP2]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = select i1 %y, i1 true, i1 %c
@@ -41,9 +40,8 @@ define i1 @xor_logic_and_logic_or3(i1 %c, i1 %x, i1 %y) {
 
 define i1 @xor_logic_and_logic_or4(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_logic_and_logic_or4(
-; CHECK-NEXT:    [[O:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[Y:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select i1 [[X:%.*]], i1 [[C]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = select i1 %c, i1 true, i1 %y
@@ -66,9 +64,9 @@ define <3 x i1> @xor_logic_and_logic_or_vector1(<3 x i1> %c, <3 x i1> %x, <3 x i
 
 define <3 x i1> @xor_logic_and_logic_or_vector2(<3 x i1> %c, <3 x i1> %x, <3 x i1> %y) {
 ; CHECK-LABEL: @xor_logic_and_logic_or_vector2(
-; CHECK-NEXT:    [[O:%.*]] = select <3 x i1> [[Y:%.*]], <3 x i1> <i1 true, i1 true, i1 true>, <3 x i1> [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select <3 x i1> [[X:%.*]], <3 x i1> [[C]], <3 x i1> zeroinitializer
-; CHECK-NEXT:    [[R:%.*]] = xor <3 x i1> [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze <3 x i1> [[C:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor <3 x i1> [[X:%.*]], <i1 true, i1 true, i1 true>
+; CHECK-NEXT:    [[R:%.*]] = select <3 x i1> [[TMP1]], <3 x i1> [[TMP2]], <3 x i1> [[Y:%.*]]
 ; CHECK-NEXT:    ret <3 x i1> [[R]]
 ;
   %o = select <3 x i1> %y, <3 x i1> <i1 true, i1 true, i1 true>, <3 x i1> %c
@@ -103,9 +101,8 @@ define <3 x i1> @xor_logic_and_logic_or_vector_poison2(<3 x i1> %c, <3 x i1> %x,
 
 define i1 @xor_and_logic_or1(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_and_logic_or1(
-; CHECK-NEXT:    [[O:%.*]] = select i1 [[C:%.*]], i1 true, i1 [[Y:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = and i1 [[C]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = select i1 %c, i1 true, i1 %y
@@ -116,9 +113,8 @@ define i1 @xor_and_logic_or1(i1 %c, i1 %x, i1 %y) {
 
 define i1 @xor_and_logic_or2(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_and_logic_or2(
-; CHECK-NEXT:    [[O:%.*]] = select i1 [[Y:%.*]], i1 true, i1 [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = and i1 [[X:%.*]], [[C]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = select i1 %y, i1 true, i1 %c
@@ -129,9 +125,8 @@ define i1 @xor_and_logic_or2(i1 %c, i1 %x, i1 %y) {
 
 define <2 x i1> @xor_and_logic_or_vector(<2 x i1> %c, <2 x i1> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @xor_and_logic_or_vector(
-; CHECK-NEXT:    [[O:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[Y:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = and <2 x i1> [[C]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor <2 x i1> [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[TMP1]], <2 x i1> [[Y:%.*]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %o = select <2 x i1> %c, <2 x i1> <i1 true, i1 true>, <2 x i1> %y
@@ -155,9 +150,8 @@ define <2 x i1> @xor_and_logic_or_vector_poison(<2 x i1> %c, <2 x i1> %x, <2 x i
 
 define i1 @xor_logic_and_or1(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_logic_and_or1(
-; CHECK-NEXT:    [[O:%.*]] = or i1 [[Y:%.*]], [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select i1 [[C]], i1 [[X:%.*]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = or i1 %y, %c
@@ -168,9 +162,8 @@ define i1 @xor_logic_and_or1(i1 %c, i1 %x, i1 %y) {
 
 define i1 @xor_logic_and_or2(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_logic_and_or2(
-; CHECK-NEXT:    [[O:%.*]] = or i1 [[C:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select i1 [[X:%.*]], i1 [[C]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = or i1 %c, %y
@@ -181,9 +174,8 @@ define i1 @xor_logic_and_or2(i1 %c, i1 %x, i1 %y) {
 
 define <2 x i1> @xor_logic_and_or_vector(<2 x i1> %c, <2 x i1> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @xor_logic_and_or_vector(
-; CHECK-NEXT:    [[O:%.*]] = or <2 x i1> [[Y:%.*]], [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = select <2 x i1> [[C]], <2 x i1> [[X:%.*]], <2 x i1> zeroinitializer
-; CHECK-NEXT:    [[R:%.*]] = xor <2 x i1> [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[C:%.*]], <2 x i1> [[TMP1]], <2 x i1> [[Y:%.*]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %o = or <2 x i1> %y, %c
@@ -205,12 +197,12 @@ define <2 x i1> @xor_logic_and_or_vector_poison(<2 x i1> %c, <2 x i1> %x, <2 x i
   ret <2 x i1> %r
 }
 
-;; TODO: do we really need to do this transform?
+;; even through we save a instruction here, select is heavier than normal 
+;; and/or/xor on most backend,  do we really need to do this transform?
 define i1 @xor_and_or(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_and_or(
-; CHECK-NEXT:    [[O:%.*]] = or i1 [[Y:%.*]], [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = and i1 [[C]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[C:%.*]], i1 [[TMP1]], i1 [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %o = or i1 %y, %c
@@ -219,12 +211,12 @@ define i1 @xor_and_or(i1 %c, i1 %x, i1 %y) {
   ret i1 %r
 }
 
-;; TODO: do we really need to do this transform?
+;; even through we save a instruction here, select is heavier than normal 
+;; and/or/xor on most backend,  do we really need to do this transform?
 define <4 x i1> @xor_and_or_vector(<4 x i1> %c, <4 x i1> %x, <4 x i1> %y) {
 ; CHECK-LABEL: @xor_and_or_vector(
-; CHECK-NEXT:    [[O:%.*]] = or <4 x i1> [[Y:%.*]], [[C:%.*]]
-; CHECK-NEXT:    [[A:%.*]] = and <4 x i1> [[C]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor <4 x i1> [[A]], [[O]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <4 x i1> [[X:%.*]], <i1 true, i1 true, i1 true, i1 true>
+; CHECK-NEXT:    [[R:%.*]] = select <4 x i1> [[C:%.*]], <4 x i1> [[TMP1]], <4 x i1> [[Y:%.*]]
 ; CHECK-NEXT:    ret <4 x i1> [[R]]
 ;
   %o = or <4 x i1> %y, %c
@@ -233,6 +225,7 @@ define <4 x i1> @xor_and_or_vector(<4 x i1> %c, <4 x i1> %x, <4 x i1> %y) {
   ret <4 x i1> %r
 }
 
+; Negative test, more than one use
 define i1 @xor_and_or_negative_oneuse(i1 %c, i1 %x, i1 %y) {
 ; CHECK-LABEL: @xor_and_or_negative_oneuse(
 ; CHECK-NEXT:    [[O:%.*]] = or i1 [[Y:%.*]], [[C:%.*]]


        


More information about the llvm-commits mailing list