Skip to content

Commit 5731381

Browse files
committed
[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
1 parent 5aa6038 commit 5731381

File tree

2 files changed

+31
-29
lines changed

2 files changed

+31
-29
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2640,8 +2640,7 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
26402640
// TODO: One use checks are conservative. We just need to check that a total
26412641
// number of multiple used values does not exceed reduction
26422642
// in operations.
2643-
if (match(Op0, m_OneUse(m_c_And(m_OneUse(m_Not(m_Or(m_Value(A), m_Value(B)))),
2644-
m_Value(C))))) {
2643+
if (match(Op0, m_c_And(m_Not(m_Or(m_Value(A), m_Value(B))), m_Value(C)))) {
26452644
// (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A
26462645
if (match(Op1, m_OneUse(m_c_And(
26472646
m_OneUse(m_Not(m_c_Or(m_Specific(A), m_Specific(C)))),
@@ -2659,12 +2658,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
26592658
}
26602659

26612660
// (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
2662-
if (match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(C)))))
2661+
if (match(Op1,
2662+
m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C)))))))
26632663
return BinaryOperator::CreateNot(
26642664
Builder.CreateOr(Builder.CreateAnd(B, C), A));
26652665

26662666
// (~(A | B) & C) | ~(B | C) --> ~((A & C) | B)
2667-
if (match(Op1, m_Not(m_c_Or(m_Specific(B), m_Specific(C)))))
2667+
if (match(Op1,
2668+
m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(B), m_Specific(C)))))))
26682669
return BinaryOperator::CreateNot(
26692670
Builder.CreateOr(Builder.CreateAnd(A, C), B));
26702671
}

llvm/test/Transforms/InstCombine/and-xor-or.ll

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -895,11 +895,9 @@ define i32 @or_not_and_extra_not_use1(i32 %a, i32 %b, i32 %c) {
895895
; CHECK-LABEL: @or_not_and_extra_not_use1(
896896
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
897897
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
898-
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
899-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]]
900-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
901-
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
902-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
898+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]]
899+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1
900+
; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
903901
; CHECK-NEXT: call void @use(i32 [[NOT1]])
904902
; CHECK-NEXT: ret i32 [[OR3]]
905903
;
@@ -942,10 +940,9 @@ define i32 @or_not_and_extra_and_use1(i32 %a, i32 %b, i32 %c) {
942940
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
943941
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
944942
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]]
945-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]]
946-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
947-
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]]
948-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]]
943+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]]
944+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1
945+
; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]]
949946
; CHECK-NEXT: call void @use(i32 [[AND1]])
950947
; CHECK-NEXT: ret i32 [[OR3]]
951948
;
@@ -1615,9 +1612,10 @@ define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
16151612
; CHECK-LABEL: @or_and_not_not_extra_not_use1(
16161613
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
16171614
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1618-
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
1619-
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1620-
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
1615+
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1616+
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1617+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1618+
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
16211619
; CHECK-NEXT: call void @use(i32 [[NOT1]])
16221620
; CHECK-NEXT: ret i32 [[OR3]]
16231621
;
@@ -1633,12 +1631,11 @@ define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
16331631

16341632
define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
16351633
; CHECK-LABEL: @or_and_not_not_extra_not_use2(
1636-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1637-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1638-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1634+
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
16391635
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1640-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1641-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1636+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B:%.*]]
1637+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1638+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
16421639
; CHECK-NEXT: call void @use(i32 [[NOT2]])
16431640
; CHECK-NEXT: ret i32 [[OR3]]
16441641
;
@@ -1654,12 +1651,12 @@ define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) {
16541651

16551652
define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
16561653
; CHECK-LABEL: @or_and_not_not_extra_and_use(
1657-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1658-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1659-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1654+
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
16601655
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1661-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1662-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1656+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B:%.*]]
1657+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B]]
1658+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1659+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
16631660
; CHECK-NEXT: call void @use(i32 [[AND]])
16641661
; CHECK-NEXT: ret i32 [[OR3]]
16651662
;
@@ -1676,9 +1673,11 @@ define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
16761673
define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
16771674
; CHECK-LABEL: @or_and_not_not_extra_or_use1(
16781675
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1679-
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
1680-
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1681-
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
1676+
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1677+
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1678+
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1679+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1680+
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
16821681
; CHECK-NEXT: call void @use(i32 [[OR1]])
16831682
; CHECK-NEXT: ret i32 [[OR3]]
16841683
;
@@ -1711,6 +1710,8 @@ define i32 @or_and_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
17111710
ret i32 %or3
17121711
}
17131712

1713+
; Check the use limit. It can be adjusted in the future in terms of
1714+
; LHS and RHS uses distribution to be more flexible.
17141715
define i32 @or_and_not_not_2_extra_uses(i32 %a, i32 %b, i32 %c) {
17151716
; CHECK-LABEL: @or_and_not_not_2_extra_uses(
17161717
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]

0 commit comments

Comments
 (0)