forked from OSchip/llvm-project
[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:
parent
5aa6038a40
commit
5731381594
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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:%.*]]
|
||||
|
|
Loading…
Reference in New Issue