Skip to content

Commit a905c54

Browse files
committed
[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
1 parent d0ca059 commit a905c54

File tree

2 files changed

+48
-63
lines changed

2 files changed

+48
-63
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,6 +2818,20 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
28182818
}
28192819
}
28202820

2821+
// (~(A | B) & C) | ~(A | C) --> ~((B & C) | A)
2822+
// TODO: One use checks are conservative. We just need to check that a total
2823+
// number of multiple used values does not exceed 3.
2824+
if (match(Op0, m_OneUse(m_c_And(m_OneUse(m_Not(m_Or(m_Value(A), m_Value(B)))),
2825+
m_Value(C))))) {
2826+
if (match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(C)))))
2827+
return BinaryOperator::CreateNot(
2828+
Builder.CreateOr(Builder.CreateAnd(B, C), A));
2829+
2830+
if (match(Op1, m_Not(m_c_Or(m_Specific(B), m_Specific(C)))))
2831+
return BinaryOperator::CreateNot(
2832+
Builder.CreateOr(Builder.CreateAnd(A, C), B));
2833+
}
2834+
28212835
if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder))
28222836
return DeMorgan;
28232837

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

Lines changed: 34 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,12 +1069,9 @@ define i32 @or_not_and_wrong_b(i32 %a, i32 %b, i32 %c, i32 %d) {
10691069

10701070
define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {
10711071
; CHECK-LABEL: @or_and_not_not(
1072-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1073-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1074-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1075-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1076-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1077-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1072+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1073+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1074+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
10781075
; CHECK-NEXT: ret i32 [[OR3]]
10791076
;
10801077
%or1 = or i32 %b, %a
@@ -1089,12 +1086,9 @@ define i32 @or_and_not_not(i32 %a, i32 %b, i32 %c) {
10891086
define i32 @or_and_not_not_commute1(i32 %a, i32 %b0, i32 %c) {
10901087
; CHECK-LABEL: @or_and_not_not_commute1(
10911088
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
1092-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A:%.*]]
1093-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1094-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1095-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1096-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[B]], [[NOT2]]
1097-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1089+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
1090+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1091+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
10981092
; CHECK-NEXT: ret i32 [[OR3]]
10991093
;
11001094
%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) {
11091103

11101104
define i32 @or_and_not_not_commute2(i32 %a, i32 %b, i32 %c) {
11111105
; CHECK-LABEL: @or_and_not_not_commute2(
1112-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1113-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1114-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1115-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1116-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1117-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1106+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1107+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1108+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
11181109
; CHECK-NEXT: ret i32 [[OR3]]
11191110
;
11201111
%or1 = or i32 %b, %a
@@ -1128,12 +1119,9 @@ define i32 @or_and_not_not_commute2(i32 %a, i32 %b, i32 %c) {
11281119

11291120
define i32 @or_and_not_not_commute3(i32 %a, i32 %b, i32 %c) {
11301121
; CHECK-LABEL: @or_and_not_not_commute3(
1131-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1132-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1133-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
1134-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1135-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1136-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1122+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1123+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1124+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
11371125
; CHECK-NEXT: ret i32 [[OR3]]
11381126
;
11391127
%or1 = or i32 %b, %a
@@ -1147,12 +1135,9 @@ define i32 @or_and_not_not_commute3(i32 %a, i32 %b, i32 %c) {
11471135

11481136
define i32 @or_and_not_not_commute4(i32 %a, i32 %b, i32 %c) {
11491137
; CHECK-LABEL: @or_and_not_not_commute4(
1150-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
1151-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1152-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1153-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1154-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1155-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1138+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1139+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1140+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
11561141
; CHECK-NEXT: ret i32 [[OR3]]
11571142
;
11581143
%or1 = or i32 %a, %b
@@ -1166,12 +1151,9 @@ define i32 @or_and_not_not_commute4(i32 %a, i32 %b, i32 %c) {
11661151

11671152
define i32 @or_and_not_not_commute5(i32 %a, i32 %b, i32 %c) {
11681153
; CHECK-LABEL: @or_and_not_not_commute5(
1169-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1170-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1171-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1172-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1173-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1174-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1154+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1155+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1156+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
11751157
; CHECK-NEXT: ret i32 [[OR3]]
11761158
;
11771159
%or1 = or i32 %b, %a
@@ -1186,12 +1168,9 @@ define i32 @or_and_not_not_commute5(i32 %a, i32 %b, i32 %c) {
11861168
define i32 @or_and_not_not_commute6(i32 %a, i32 %b0, i32 %c) {
11871169
; CHECK-LABEL: @or_and_not_not_commute6(
11881170
; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]]
1189-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A:%.*]]
1190-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1191-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
1192-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1193-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[B]], [[NOT2]]
1194-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1171+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
1172+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1173+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
11951174
; CHECK-NEXT: ret i32 [[OR3]]
11961175
;
11971176
%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) {
12061185

12071186
define i32 @or_and_not_not_commute7(i32 %a, i32 %b, i32 %c) {
12081187
; CHECK-LABEL: @or_and_not_not_commute7(
1209-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
1210-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1211-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[C:%.*]], [[A]]
1212-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1213-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1214-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1188+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B:%.*]]
1189+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
1190+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
12151191
; CHECK-NEXT: ret i32 [[OR3]]
12161192
;
12171193
%or1 = or i32 %a, %b
@@ -1227,10 +1203,9 @@ define i32 @or_and_not_not_extra_not_use1(i32 %a, i32 %b, i32 %c) {
12271203
; CHECK-LABEL: @or_and_not_not_extra_not_use1(
12281204
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
12291205
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1230-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1231-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1232-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1233-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1206+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
1207+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1208+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
12341209
; CHECK-NEXT: call void @use(i32 [[NOT1]])
12351210
; CHECK-NEXT: ret i32 [[OR3]]
12361211
;
@@ -1289,11 +1264,9 @@ define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) {
12891264
define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
12901265
; CHECK-LABEL: @or_and_not_not_extra_or_use1(
12911266
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1292-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1293-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1294-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1295-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1296-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1267+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]]
1268+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1269+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
12971270
; CHECK-NEXT: call void @use(i32 [[OR1]])
12981271
; CHECK-NEXT: ret i32 [[OR3]]
12991272
;
@@ -1309,12 +1282,10 @@ define i32 @or_and_not_not_extra_or_use1(i32 %a, i32 %b, i32 %c) {
13091282

13101283
define i32 @or_and_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) {
13111284
; CHECK-LABEL: @or_and_not_not_extra_or_use2(
1312-
; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]]
1313-
; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1
1314-
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]]
1315-
; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1
1316-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[NOT2]], [[B]]
1317-
; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]]
1285+
; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A:%.*]], [[C:%.*]]
1286+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B:%.*]]
1287+
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]]
1288+
; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1
13181289
; CHECK-NEXT: call void @use(i32 [[OR2]])
13191290
; CHECK-NEXT: ret i32 [[OR3]]
13201291
;

0 commit comments

Comments
 (0)