Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2796,6 +2796,18 @@ if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A)))) return BinaryOperator::CreateOr(Op1, Builder.CreateAnd(A, C)); + // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A) + 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_OneUse(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_OneUse(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; Index: llvm/test/Transforms/InstCombine/and-xor-or.ll =================================================================== --- llvm/test/Transforms/InstCombine/and-xor-or.ll +++ llvm/test/Transforms/InstCombine/and-xor-or.ll @@ -996,12 +996,9 @@ 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 @@ -1015,12 +1012,9 @@ define i32 @or_and_not_not_commute1(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @or_and_not_not_commute1( -; 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 @@ -1034,12 +1028,9 @@ 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 @@ -1053,12 +1044,9 @@ 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 @@ -1072,12 +1060,9 @@ 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 @@ -1091,12 +1076,9 @@ 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 @@ -1110,12 +1092,9 @@ define i32 @or_and_not_not_commute6(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @or_and_not_not_commute6( -; 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 @@ -1129,12 +1108,9 @@ 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 @@ -1212,11 +1188,9 @@ 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]] ; @@ -1232,12 +1206,10 @@ 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]] ;