Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2809,8 +2809,7 @@ // 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_OneUse(m_c_And(m_OneUse(m_Not(m_Or(m_Value(A), m_Value(B)))), - m_Value(C))))) { + if (match(Op0, m_c_And(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)))), @@ -2828,12 +2827,13 @@ } // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A) - if (match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(C))))) + if (match(Op1, + m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(A), m_Specific(C))))))) return BinaryOperator::CreateNot( Builder.CreateOr(Builder.CreateAnd(B, C), A)); // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B) - if (match(Op1, m_Not(m_c_Or(m_Specific(B), m_Specific(C))))) + 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)); } 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 @@ -895,11 +895,9 @@ ; CHECK-LABEL: @or_not_and_extra_not_use1( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use(i32 [[NOT1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -942,10 +940,9 @@ ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND1]], [[AND2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[OR3:%.*]] = and i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use(i32 [[AND1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1203,9 +1200,10 @@ ; 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]] -; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]] -; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -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: call void @use(i32 [[NOT1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1221,12 +1219,11 @@ define i32 @or_and_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @or_and_not_not_extra_not_use2( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]] +; 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 [[NOT2]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1242,12 +1239,12 @@ define i32 @or_and_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @or_and_not_not_extra_and_use( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR1]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[C:%.*]] +; 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: [[AND:%.*]] = and i32 [[NOT2]], [[B:%.*]] +; 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 [[AND]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1264,9 +1261,11 @@ 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: [[TMP1:%.*]] = and i32 [[C:%.*]], [[B]] -; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A]] -; CHECK-NEXT: [[OR3:%.*]] = xor i32 [[TMP2]], -1 +; 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: call void @use(i32 [[OR1]]) ; CHECK-NEXT: ret i32 [[OR3]] ; @@ -1299,6 +1298,29 @@ ret i32 %or3 } +define i32 @or_and_not_not_2_extra_uses(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @or_and_not_not_2_extra_uses( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; 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: call void @use(i32 [[AND]]) +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[AND]], [[NOT1]] +; CHECK-NEXT: ret i32 [[OR3]] +; + %or1 = or i32 %b, %a + call void @use(i32 %or1) + %not1 = xor i32 %or1, -1 + %or2 = or i32 %a, %c + %not2 = xor i32 %or2, -1 + %and = and i32 %not2, %b + call void @use(i32 %and) + %or3 = or i32 %not1, %and + ret i32 %or3 +} + define i32 @or_and_not_not_wrong_a(i32 %a, i32 %b, i32 %c, i32 %d) { ; CHECK-LABEL: @or_and_not_not_wrong_a( ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[D:%.*]]