Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2794,7 +2794,9 @@ // 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_c_And(m_Not(m_Or(m_Value(A), m_Value(B))), m_Value(C)))) { + if (match(Op0, m_c_And(m_CombineAnd(m_Value(D), + 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)))), @@ -2820,6 +2822,13 @@ 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)); + + // (~(A | B) & C) | ~(C | (A ^ B)) -> (A & B & ~C) | ~(A | B) + if (match(Op1, m_OneUse(m_Not(m_OneUse(m_c_Or( + m_Specific(C), + m_OneUse(m_c_Xor(m_Specific(A), m_Specific(B))))))))) + return BinaryOperator::CreateOr( + Builder.CreateAnd(Builder.CreateAnd(A, B), Builder.CreateNot(C)), D); } if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder)) 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 @@ -1340,11 +1340,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %or1 = or i32 %b, %c @@ -1361,11 +1360,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor_commute1( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %or1 = or i32 %c, %b @@ -1383,11 +1381,10 @@ ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[NOT1]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization @@ -1405,11 +1402,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor_commute3( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[C]], [[B]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %or1 = or i32 %b, %c @@ -1427,11 +1423,10 @@ ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[NOT1]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[XOR1]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization @@ -1449,11 +1444,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor_commute5( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: ret i32 [[OR3]] ; %or1 = or i32 %b, %c @@ -1470,11 +1464,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor_use1( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: call void @use(i32 [[OR1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1493,11 +1486,10 @@ ; CHECK-LABEL: @and_not_or_or_not_or_xor_use2( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: call void @use(i32 [[NOT1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1517,10 +1509,10 @@ ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[A:%.*]] -; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[B]], [[C]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[XOR1]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[NOT2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[TMP3]], [[NOT1]] ; CHECK-NEXT: call void @use(i32 [[AND1]]) ; CHECK-NEXT: ret i32 [[OR3]] ;