[InstCombine] Relax and reorganize one use checks in the ~(a | b) & c

Since there is just a single check for LHS in ~(A | B) & C | ...
transforms and multiple RHS checks inside with more coming I am
removing m_OneUse checks for LHS and adding new checks for RHS.
This is non essential as long as there is total benefit.

In addition (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
checks were overly restrictive, it should be good without any
additional checks.

Differential Revision: https://reviews.llvm.org/D113141
This commit is contained in:
Stanislav Mekhanoshin 2021-11-03 13:16:03 -07:00
parent 5aa6038a40
commit 5731381594
2 changed files with 31 additions and 29 deletions

View File

@ -2640,8 +2640,7 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
// TODO: One use checks are conservative. We just need to check that a total
// number of multiple used values does not exceed reduction
// in operations.
if (match(Op0, m_OneUse(m_c_And(m_OneUse(m_Not(m_Or(m_Value(A), m_Value(B)))),
m_Value(C))))) {
if (match(Op0, m_c_And(m_Not(m_Or(m_Value(A), m_Value(B))), m_Value(C)))) {
// (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
if (match(Op1, m_OneUse(m_c_And(
m_OneUse(m_Not(m_c_Or(m_Specific(A), m_Specific(C)))),
@ -2659,12 +2658,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
// (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
if (match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(C)))))
if (match(Op1,
m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C)))))))
return BinaryOperator::CreateNot(
Builder.CreateOr(Builder.CreateAnd(B, C), A));
// (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
if (match(Op1, m_Not(m_c_Or(m_Specific(B), m_Specific(C)))))
if (match(Op1,
m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(B), m_Specific(C)))))))
return BinaryOperator::CreateNot(
Builder.CreateOr(Builder.CreateAnd(A, C), B));
}

View File

@ -895,11 +895,9 @@ define i32 @or_not_and_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_not_and_extra_not_use1(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: call void @use(i32 [[NOT1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -942,10 +940,9 @@ define i32 @or_not_and_extra_and_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1
; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
; CHECK-NEXT: call void @use(i32 [[AND1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -1615,9 +1612,10 @@ define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_not_use1(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT: call void @use(i32 [[NOT1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -1633,12 +1631,11 @@ define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_not_use2(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[NOT2]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -1654,12 +1651,12 @@ define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_and_use(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B]]
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: call void @use(i32 [[AND]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -1676,9 +1673,11 @@ define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_or_use1(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
; CHECK-NEXT: call void @use(i32 [[OR1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@ -1711,6 +1710,8 @@ define i32 @or_and_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
ret i32 %or3
}
; Check the use limit. It can be adjusted in the future in terms of
; LHS and RHS uses distribution to be more flexible.
define i32 @or_and_not_not_2_extra_uses(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_2_extra_uses(
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]