[llvm-branch-commits] [llvm] 0529946 - [instCombine] Add (A ^ B) | ~(A | B) -> ~(A & B)

Dávid Bolvanský via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jan 12 10:33:50 PST 2021


Author: Dávid Bolvanský
Date: 2021-01-12T19:29:17+01:00
New Revision: 0529946b5bafafd10d77b946ee9fa96f388860ef

URL: https://github.com/llvm/llvm-project/commit/0529946b5bafafd10d77b946ee9fa96f388860ef
DIFF: https://github.com/llvm/llvm-project/commit/0529946b5bafafd10d77b946ee9fa96f388860ef.diff

LOG: [instCombine] Add (A ^ B) | ~(A | B) -> ~(A & B)

define i32 @src(i32 %x, i32 %y) {
%0:
  %xor = xor i32 %y, %x
  %or = or i32 %y, %x
  %neg = xor i32 %or, 4294967295
  %or1 = or i32 %xor, %neg
  ret i32 %or1
}
=>
define i32 @tgt(i32 %x, i32 %y) {
%0:
  %and = and i32 %x, %y
  %neg = xor i32 %and, 4294967295
  ret i32 %neg
}
Transformation seems to be correct!

https://alive2.llvm.org/ce/z/Cvca4a

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 15dcf2d19c15..352126fa07ca 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1627,6 +1627,14 @@ static Instruction *foldOrToXor(BinaryOperator &I,
         match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
       return BinaryOperator::CreateNot(Builder.CreateXor(A, B));
 
+  // Operand complexity canonicalization guarantees that the 'xor' is Op0.
+  // (A ^ B) | ~(A | B) --> ~(A & B)
+  // (A ^ B) | ~(B | A) --> ~(A & B)
+  if (Op0->hasOneUse() || Op1->hasOneUse())
+    if (match(Op0, m_Xor(m_Value(A), m_Value(B))) &&
+        match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B)))))
+      return BinaryOperator::CreateNot(Builder.CreateAnd(A, B));
+
   // (A & ~B) | (~A & B) --> A ^ B
   // (A & ~B) | (B & ~A) --> A ^ B
   // (~B & A) | (~A & B) --> A ^ B

diff  --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index d41b8d53dd40..b5da1734c102 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1004,10 +1004,8 @@ end:
 
 define i32 @test1(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test1(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor i32 [[TMP1]], -1
 ; CHECK-NEXT:    ret i32 [[OR1]]
 ;
   %xor = xor i32 %y, %x
@@ -1019,13 +1017,11 @@ define i32 @test1(i32 %x, i32 %y) {
 
 define i32 @test2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test2(
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor i32 [[TMP1]], -1
 ; CHECK-NEXT:    ret i32 [[OR1]]
 ;
-  %or = or i32 %y, %x
+  %or = or i32 %x, %y
   %neg = xor i32 %or, -1
   %xor = xor i32 %y, %x
   %or1 = or i32 %xor, %neg
@@ -1034,25 +1030,21 @@ define i32 @test2(i32 %x, i32 %y) {
 
 define i32 @test3(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test3(
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor i32 [[TMP1]], -1
 ; CHECK-NEXT:    ret i32 [[OR1]]
 ;
   %or = or i32 %y, %x
   %neg = xor i32 %or, -1
-  %xor = xor i32 %y, %x
+  %xor = xor i32 %x, %y
   %or1 = or i32 %xor, %neg
   ret i32 %or1
 }
 
 define <2 x i32> @test4_vec(<2 x i32> %x, <2 x i32> %y) {
 ; CHECK-LABEL: @test4_vec(
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[NEG:%.*]] = xor <2 x i32> [[OR]], <i32 -1, i32 -1>
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[Y]], [[X]]
-; CHECK-NEXT:    [[OR1:%.*]] = or <2 x i32> [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor <2 x i32> [[TMP1]], <i32 -1, i32 -1>
 ; CHECK-NEXT:    ret <2 x i32> [[OR1]]
 ;
   %or = or <2 x i32> %y, %x
@@ -1066,9 +1058,9 @@ define i32 @test5_use(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test5_use(
 ; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y]], [[X]]
 ; CHECK-NEXT:    call void @use(i32 [[NEG]])
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor i32 [[TMP1]], -1
 ; CHECK-NEXT:    ret i32 [[OR1]]
 ;
   %or = or i32 %y, %x
@@ -1081,11 +1073,10 @@ define i32 @test5_use(i32 %x, i32 %y) {
 
 define i32 @test5_use2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test5_use2(
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[NEG:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[XOR]])
-; CHECK-NEXT:    [[OR1:%.*]] = or i32 [[XOR]], [[NEG]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT:    [[OR1:%.*]] = xor i32 [[TMP1]], -1
 ; CHECK-NEXT:    ret i32 [[OR1]]
 ;
   %or = or i32 %y, %x


        


More information about the llvm-branch-commits mailing list