forked from OSchip/llvm-project
[InstCombine] (~A | B) & (A ^ B) -> ~A & B
This is part of a set of 2-variable logic optimizations suggested here: https://lists.llvm.org/pipermail/llvm-dev/2021-December/154470.html The 'not' op must not propagate undef elements of a vector, so this patch creates a new 'full' not, but I am not counting that as an extra-use restriction because it should get folded with the existing value by CSE. https://alive2.llvm.org/ce/z/7v65im
This commit is contained in:
parent
0b13789d58
commit
1d21667ce2
|
@ -2081,21 +2081,37 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
|
|||
if (Op0->hasOneUse() || isFreeToInvert(C, C->hasOneUse()))
|
||||
return BinaryOperator::CreateAnd(Op1, Builder.CreateNot(C));
|
||||
|
||||
// (A | B) & ((~A) ^ B) -> (A & B)
|
||||
// (A | B) & (B ^ (~A)) -> (A & B)
|
||||
// (B | A) & ((~A) ^ B) -> (A & B)
|
||||
// (B | A) & (B ^ (~A)) -> (A & B)
|
||||
// (A | B) & (~A ^ B) -> A & B
|
||||
// (A | B) & (B ^ ~A) -> A & B
|
||||
// (B | A) & (~A ^ B) -> A & B
|
||||
// (B | A) & (B ^ ~A) -> A & B
|
||||
if (match(Op1, m_c_Xor(m_Not(m_Value(A)), m_Value(B))) &&
|
||||
match(Op0, m_c_Or(m_Specific(A), m_Specific(B))))
|
||||
return BinaryOperator::CreateAnd(A, B);
|
||||
|
||||
// ((~A) ^ B) & (A | B) -> (A & B)
|
||||
// ((~A) ^ B) & (B | A) -> (A & B)
|
||||
// (B ^ (~A)) & (A | B) -> (A & B)
|
||||
// (B ^ (~A)) & (B | A) -> (A & B)
|
||||
// (~A ^ B) & (A | B) -> A & B
|
||||
// (~A ^ B) & (B | A) -> A & B
|
||||
// (B ^ ~A) & (A | B) -> A & B
|
||||
// (B ^ ~A) & (B | A) -> A & B
|
||||
if (match(Op0, m_c_Xor(m_Not(m_Value(A)), m_Value(B))) &&
|
||||
match(Op1, m_c_Or(m_Specific(A), m_Specific(B))))
|
||||
return BinaryOperator::CreateAnd(A, B);
|
||||
|
||||
// (~A | B) & (A ^ B) -> ~A & B
|
||||
// (~A | B) & (B ^ A) -> ~A & B
|
||||
// (B | ~A) & (A ^ B) -> ~A & B
|
||||
// (B | ~A) & (B ^ A) -> ~A & B
|
||||
if (match(Op0, m_c_Or(m_Not(m_Value(A)), m_Value(B))) &&
|
||||
match(Op1, m_c_Xor(m_Specific(A), m_Specific(B))))
|
||||
return BinaryOperator::CreateAnd(Builder.CreateNot(A), B);
|
||||
|
||||
// (A ^ B) & (~A | B) -> ~A & B
|
||||
// (B ^ A) & (~A | B) -> ~A & B
|
||||
// (A ^ B) & (B | ~A) -> ~A & B
|
||||
// (B ^ A) & (B | ~A) -> ~A & B
|
||||
if (match(Op1, m_c_Or(m_Not(m_Value(A)), m_Value(B))) &&
|
||||
match(Op0, m_c_Xor(m_Specific(A), m_Specific(B))))
|
||||
return BinaryOperator::CreateAnd(Builder.CreateNot(A), B);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -3641,10 +3641,8 @@ define i32 @not_or_or_and_no_and_use8(i32 %a, i32 %b, i32 %c) {
|
|||
|
||||
define i4 @and_orn_xor(i4 %a, i4 %b) {
|
||||
; CHECK-LABEL: @and_orn_xor(
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i4 [[A:%.*]], [[B:%.*]]
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i4 [[A]], -1
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i4 [[NOTA]], [[B]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and i4 [[OR]], [[XOR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[A:%.*]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i4 [[TMP1]], [[B:%.*]]
|
||||
; CHECK-NEXT: ret i4 [[R]]
|
||||
;
|
||||
%xor = xor i4 %a, %b
|
||||
|
@ -3656,10 +3654,8 @@ define i4 @and_orn_xor(i4 %a, i4 %b) {
|
|||
|
||||
define <2 x i4> @and_orn_xor_commute1(<2 x i4> %a, <2 x i4> %b) {
|
||||
; CHECK-LABEL: @and_orn_xor_commute1(
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor <2 x i4> [[A:%.*]], [[B:%.*]]
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor <2 x i4> [[A]], <i4 -1, i4 undef>
|
||||
; CHECK-NEXT: [[OR:%.*]] = or <2 x i4> [[NOTA]], [[B]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and <2 x i4> [[XOR]], [[OR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i4> [[A:%.*]], <i4 -1, i4 -1>
|
||||
; CHECK-NEXT: [[R:%.*]] = and <2 x i4> [[TMP1]], [[B:%.*]]
|
||||
; CHECK-NEXT: ret <2 x i4> [[R]]
|
||||
;
|
||||
%xor = xor <2 x i4> %a, %b
|
||||
|
@ -3673,9 +3669,8 @@ define i32 @and_orn_xor_commute2(i32 %a, i32 %b) {
|
|||
; CHECK-LABEL: @and_orn_xor_commute2(
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
|
||||
; CHECK-NEXT: call void @use(i32 [[XOR]])
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOTA]], [[B]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[OR]], [[XOR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[TMP1]], [[B]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%xor = xor i32 %b, %a
|
||||
|
@ -3688,11 +3683,10 @@ define i32 @and_orn_xor_commute2(i32 %a, i32 %b) {
|
|||
|
||||
define i32 @and_orn_xor_commute3(i32 %a, i32 %b) {
|
||||
; CHECK-LABEL: @and_orn_xor_commute3(
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1
|
||||
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOTA]], [[B]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[XOR]], [[OR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[TMP1]], [[B:%.*]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%xor = xor i32 %b, %a
|
||||
|
@ -3707,11 +3701,11 @@ define i32 @and_orn_xor_commute5(i32 %pa, i32 %pb) {
|
|||
; CHECK-LABEL: @and_orn_xor_commute5(
|
||||
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA:%.*]], [[PA]]
|
||||
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB:%.*]], [[PB]]
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A]], [[B]]
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
||||
; CHECK-NEXT: call void @use(i32 [[OR]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[OR]], [[XOR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = mul i32 %pa, %pa
|
||||
|
@ -3732,8 +3726,8 @@ define i32 @and_orn_xor_commute6(i32 %pa, i32 %pb) {
|
|||
; CHECK-NEXT: call void @use(i32 [[XOR]])
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[XOR]], [[OR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = mul i32 %pa, %pa
|
||||
|
@ -3757,7 +3751,8 @@ define i32 @and_orn_xor_commute7(i32 %pa, i32 %pb) {
|
|||
; CHECK-NEXT: call void @use(i32 [[NOTA]])
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
||||
; CHECK-NEXT: call void @use(i32 [[OR]])
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[OR]], [[XOR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = mul i32 %pa, %pa
|
||||
|
@ -3776,10 +3771,8 @@ define i32 @and_orn_xor_commute8(i32 %pa, i32 %pb) {
|
|||
; CHECK-LABEL: @and_orn_xor_commute8(
|
||||
; CHECK-NEXT: [[A:%.*]] = mul i32 [[PA:%.*]], [[PA]]
|
||||
; CHECK-NEXT: [[B:%.*]] = mul i32 [[PB:%.*]], [[PB]]
|
||||
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[B]], [[A]]
|
||||
; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOTA]]
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[XOR]], [[OR]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[A]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = and i32 [[B]], [[TMP1]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
%a = mul i32 %pa, %pa
|
||||
|
|
Loading…
Reference in New Issue