[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
This commit is contained in:
Dávid Bolvanský 2021-01-12 19:28:01 +01:00
parent bb9ebf6baf
commit 0529946b5b
2 changed files with 23 additions and 24 deletions

View File

@ -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

View File

@ -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