[llvm] a905c54 - [InstCombine] Fold `(~(a | b) & c) | ~(a | c)` into `~((b & c) | a)`
Stanislav Mekhanoshin via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 29 10:58:22 PDT 2021
Author: Stanislav Mekhanoshin
Date: 2021-10-29T10:58:09-07:00
New Revision: a905c54b766ed44f498594b53354d40bae38c07a
URL: https://github.com/llvm/llvm-project/commit/a905c54b766ed44f498594b53354d40bae38c07a
DIFF: https://github.com/llvm/llvm-project/commit/a905c54b766ed44f498594b53354d40bae38c07a.diff
LOG: [InstCombine] Fold `(~(a | b) & c) | ~(a | c)` into `~((b & c) | a)`
```
----------------------------------------
define i4 @src(i4 %a, i4 %b, i4 %c) {
%or1 = or i4 %b, %a
%not1 = xor i4 %or1, -1
%or2 = or i4 %a, %c
%not2 = xor i4 %or2, -1
%and = and i4 %not2, %b
%or3 = or i4 %and, %not1
ret i4 %or3
}
define i4 @tgt(i4 %a, i4 %b, i4 %c) {
%and = and i4 %c, %b
%or = or i4 %and, %a
%or3 = xor i4 %or, -1
ret i4 %or3
}
Transformation seems to be correct!
```
Differential Revision: https://reviews.llvm.org/D112338
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and-xor-or.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index d8e8305ec850..ad2ed1371caf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2818,6 +2818,20 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
}
+ // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
+ // TODO: One use checks are conservative. We just need to check that a total
+ // number of multiple used values does not exceed 3.
+ 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(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(C)))))
+ return BinaryOperator::CreateNot(
+ Builder.CreateOr(Builder.CreateAnd(B, C), A));
+
+ if (match(Op1, m_Not(m_c_Or(m_Specific(B), m_Specific(C)))))
+ return BinaryOperator::CreateNot(
+ Builder.CreateOr(Builder.CreateAnd(A, C), B));
+ }
+
if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder))
return DeMorgan;
diff --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll
index 58247ca07cb6..12e161c01957 100644
--- a/llvm/test/Transforms/InstCombine/and-xor-or.ll
+++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll
@@ -1069,12 +1069,9 @@ define i32 @or_not_and_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%or1 = or i32 %b, %a
@@ -1089,12 +1086,9 @@ define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute1(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A:%.*]]
-; 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 [[B]], [[NOT2]]
-; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1109,12 +1103,9 @@ define i32 @or_and_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
define i32 @or_and_not_not_commute2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute2(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%or1 = or i32 %b, %a
@@ -1128,12 +1119,9 @@ define i32 @or_and_not_not_commute2(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_commute3(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute3(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
-; 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: ret i32 [[OR3]]
;
%or1 = or i32 %b, %a
@@ -1147,12 +1135,9 @@ define i32 @or_and_not_not_commute3(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_commute4(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute4(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
-; 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%or1 = or i32 %a, %b
@@ -1166,12 +1151,9 @@ define i32 @or_and_not_not_commute4(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_commute5(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute5(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%or1 = or i32 %b, %a
@@ -1186,12 +1168,9 @@ define i32 @or_and_not_not_commute5(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute6(
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
-; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[B]], [[NOT2]]
-; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
+; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
+; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
; CHECK-NEXT: ret i32 [[OR3]]
;
%b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization
@@ -1206,12 +1185,9 @@ define i32 @or_and_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
define i32 @or_and_not_not_commute7(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_commute7(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
-; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
-; 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: ret i32 [[OR3]]
;
%or1 = or i32 %a, %b
@@ -1227,10 +1203,9 @@ 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: [[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 [[NOT1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@@ -1289,11 +1264,9 @@ 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: [[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: [[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 [[OR1]])
; CHECK-NEXT: ret i32 [[OR3]]
;
@@ -1309,12 +1282,10 @@ define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
define i32 @or_and_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: @or_and_not_not_extra_or_use2(
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
-; 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: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
+; 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 [[OR2]])
; CHECK-NEXT: ret i32 [[OR3]]
;
More information about the llvm-commits
mailing list