[llvm] 0529946 - [instCombine] Add (A ^ B) | ~(A | B) -> ~(A & B)
Dávid Bolvanský via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 12 10:29:38 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-commits
mailing list