[InstSimplify] Handle (~A & ~B) | (~A ^ B) -> ~A ^ B

The code Sanjay Patel moved over from InstCombine doesn't work properly if the 'and' has both inputs as nots because we used a commuted op matcher on the 'and' first. But this will bind to the first 'not' on 'and' when there could be two 'not's. InstCombine could rely on DeMorgan to ensure the 'and' wouldn't have two 'not's eventually, but InstSimplify can't rely on that.

This patch matches the xor first then checks for the ands and allows a not of either operand of the xor.

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

llvm-svn: 301329
This commit is contained in:
Craig Topper 2017-04-25 17:01:32 +00:00
parent 3c0ede7f7a
commit 0b650d3569
2 changed files with 72 additions and 4 deletions

View File

@ -1886,15 +1886,21 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
// (A & ~B) | (A ^ B) -> (A ^ B)
// (~B & A) | (A ^ B) -> (A ^ B)
if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
match(Op1, m_Xor(m_Specific(A), m_Specific(B))))
// (A & ~B) | (B ^ A) -> (B ^ A)
// (~B & A) | (B ^ A) -> (B ^ A)
if (match(Op1, m_Xor(m_Value(A), m_Value(B))) &&
(match(Op0, m_c_And(m_Specific(A), m_Not(m_Specific(B)))) ||
match(Op0, m_c_And(m_Not(m_Specific(A)), m_Specific(B)))))
return Op1;
// Commute the 'or' operands.
// (A ^ B) | (A & ~B) -> (A ^ B)
// (A ^ B) | (~B & A) -> (A ^ B)
if (match(Op1, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
match(Op0, m_Xor(m_Specific(A), m_Specific(B))))
// (B ^ A) | (A & ~B) -> (B ^ A)
// (B ^ A) | (~B & A) -> (B ^ A)
if (match(Op0, m_Xor(m_Value(A), m_Value(B))) &&
(match(Op1, m_c_And(m_Specific(A), m_Not(m_Specific(B)))) ||
match(Op1, m_c_And(m_Not(m_Specific(A)), m_Specific(B)))))
return Op0;
if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {

View File

@ -521,3 +521,65 @@ define i32 @test44_commuted_and(i32 %a, i32 %b) {
ret i32 %or
}
; (~A & ~B) | (~A ^ B) -> ~A ^ B
define i32 @test45(i32 %a, i32 %b) {
; CHECK-LABEL: @test45(
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%negb = xor i32 %b, -1
%and = and i32 %nega, %negb
%xor = xor i32 %a, %negb
%or = or i32 %and, %xor
ret i32 %or
}
define i32 @test45_commuted_and(i32 %a, i32 %b) {
; CHECK-LABEL: @test45(
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%negb = xor i32 %b, -1
%and = and i32 %negb, %nega
%xor = xor i32 %a, %negb
%or = or i32 %and, %xor
ret i32 %or
}
; Commute operands of the 'or'.
; (~A ^ B) | (~A & ~B) -> ~A ^ B
define i32 @test46(i32 %a, i32 %b) {
; CHECK-LABEL: @test46(
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%negb = xor i32 %b, -1
%and = and i32 %nega, %negb
%xor = xor i32 %a, %negb
%or = or i32 %xor, %and
ret i32 %or
}
; (~A & ~B) | (~A ^ B) -> ~A ^ B
define i32 @test46_commuted_and(i32 %a, i32 %b) {
; CHECK-LABEL: @test45(
; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
; CHECK-NEXT: ret i32 [[XOR]]
;
%nega = xor i32 %a, -1
%negb = xor i32 %b, -1
%and = and i32 %negb, %nega
%xor = xor i32 %a, %negb
%or = or i32 %xor, %and
ret i32 %or
}