Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2831,13 +2831,17 @@ Builder.CreateAnd(Builder.CreateAnd(A, B), Builder.CreateNot(C)), D); } - // (~A & B & C) | ~(A | B | C) -> ~(A | (B ^ C)) + // (~A & B & C) | ... --> ... // TODO: One use checks are conservative. We just need to check that a total - // number of multiple used values does not exceed 4. - if (match(Op0, m_OneUse(m_c_And(m_And(m_Value(B), m_Value(C)), - m_Not(m_Value(A))))) || - match(Op0, m_OneUse(m_c_And(m_c_And(m_Value(C), m_Not(m_Value(A))), - m_Value(B))))) { + // number of multiple used values. + if (match(Op0, + m_OneUse(m_c_And(m_And(m_Value(B), m_Value(C)), + m_CombineAnd(m_Value(D), m_Not(m_Value(A)))))) || + match(Op0, m_OneUse(m_c_And( + m_c_And(m_Value(C), + m_CombineAnd(m_Value(D), m_Not(m_Value(A)))), + m_Value(B))))) { + // (~A & B & C) | ~(A | B | C) -> ~(A | (B ^ C)) if (match(Op1, m_OneUse(m_Not(m_c_Or(m_c_Or(m_Specific(A), m_Specific(B)), m_Specific(C))))) || match(Op1, m_OneUse(m_Not(m_c_Or(m_c_Or(m_Specific(B), m_Specific(C)), @@ -2846,6 +2850,18 @@ m_Specific(B)))))) return BinaryOperator::CreateNot( Builder.CreateOr(Builder.CreateXor(B, C), A)); + + // (~A & B & C) | ~(A | B) -> (C | ~B) & ~A + if (match(Op1, + m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(B))))))) + return BinaryOperator::CreateAnd( + Builder.CreateOr(C, Builder.CreateNot(B)), D); + + // (~A & B & C) | ~(A | C) -> (B | ~C) & ~A + if (match(Op1, + m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C))))))) + return BinaryOperator::CreateAnd( + Builder.CreateOr(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 @@ -1889,12 +1889,10 @@ define i32 @not_and_and_or_no_or(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %or1 = or i32 %b, %a @@ -1908,12 +1906,10 @@ define i32 @not_and_and_or_no_or_commute1_and(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_commute1_and( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[C:%.*]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[NOT2]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %or1 = or i32 %b, %a @@ -1927,12 +1923,10 @@ define i32 @not_and_and_or_no_or_commute2_and(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_commute2_and( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[B]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %or1 = or i32 %b, %a @@ -1946,12 +1940,10 @@ define i32 @not_and_and_or_no_or_commute1(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_commute1( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %or1 = or i32 %a, %b @@ -1966,12 +1958,10 @@ define i32 @not_and_and_or_no_or_commute2(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_commute2( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization @@ -1987,12 +1977,10 @@ define i32 @not_and_and_or_no_or_commute3(i32 %a, i32 %b, i32 %c0) { ; CHECK-LABEL: @not_and_and_or_no_or_commute3( ; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[AND1]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[C]], [[TMP1]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: ret i32 [[OR2]] ; %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization @@ -2007,12 +1995,10 @@ define i32 @not_and_and_or_no_or_use1(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_use1( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: call void @use(i32 [[NOT2]]) ; CHECK-NEXT: ret i32 [[OR2]] ; @@ -2028,12 +2014,10 @@ define i32 @not_and_and_or_no_or_use2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_use2( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[NOT2]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: call void @use(i32 [[NOT2]]) ; CHECK-NEXT: ret i32 [[OR2]] ; @@ -2049,12 +2033,10 @@ define i32 @not_and_and_or_no_or_use3(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_use3( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[B]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: call void @use(i32 [[NOT2]]) ; CHECK-NEXT: ret i32 [[OR2]] ; @@ -2070,12 +2052,10 @@ define i32 @not_and_and_or_no_or_use4(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_use4( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[B]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: call void @use(i32 [[NOT2]]) ; CHECK-NEXT: ret i32 [[OR2]] ; @@ -2133,12 +2113,11 @@ define i32 @not_and_and_or_no_or_use7(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_and_and_or_no_or_use7( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT2]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = and i32 [[TMP2]], [[NOT2]] ; CHECK-NEXT: call void @use(i32 [[AND1]]) ; CHECK-NEXT: ret i32 [[OR2]] ;