Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2829,6 +2829,14 @@ m_OneUse(m_c_Xor(m_Specific(A), m_Specific(B))))))))) return BinaryOperator::CreateOr( Builder.CreateAnd(Builder.CreateAnd(A, B), Builder.CreateNot(C)), D); + + // (~(A | B) & C) | ~(A | (B | C)) --> ~(A | B) + // (~(A | B) & C) | ~(B | (A | C)) --> ~(A | B) + if (match(Op1, m_Not(m_c_Or(m_c_Or(m_Specific(B), m_Specific(C)), + m_Specific(A)))) || + match(Op1, m_Not(m_c_Or(m_c_Or(m_Specific(A), m_Specific(C)), + m_Specific(B))))) + return replaceInstUsesWith(I, 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 @@ -2224,14 +2224,9 @@ define i32 @not_or_and_or_not_or_or(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_or_and_or_not_or_or( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %or1 = or i32 %b, %c %or2 = or i32 %or1, %a @@ -2245,14 +2240,9 @@ define i32 @not_or_and_or_not_or_or_commute1(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_or_and_or_not_or_or_commute1( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %or1 = or i32 %a, %c %or2 = or i32 %or1, %b @@ -2266,14 +2256,9 @@ define i32 @not_or_and_or_not_or_or_commute2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @not_or_and_or_not_or_or_commute2( -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %or1 = or i32 %c, %b %or2 = or i32 %or1, %a @@ -2288,14 +2273,9 @@ define i32 @not_or_and_or_not_or_or_commute3(i32 %a0, i32 %b, i32 %c) { ; CHECK-LABEL: @not_or_and_or_not_or_or_commute3( ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[A]], [[OR1]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[A]], [[B:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization %or1 = or i32 %b, %c @@ -2311,14 +2291,9 @@ define i32 @not_or_and_or_not_or_or_commute4(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @not_or_and_or_not_or_or_commute4( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[A:%.*]], [[C:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[OR1]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization %or1 = or i32 %a, %c @@ -2333,15 +2308,9 @@ define i32 @not_or_and_or_not_or_or_commute5(i32 %a, i32 %b, i32 %c0) { ; CHECK-LABEL: @not_or_and_or_not_or_or_commute5( -; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]] -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[A:%.*]] -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 -; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[NOT2]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization %or1 = or i32 %c, %a @@ -2361,10 +2330,8 @@ ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 ; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] ; CHECK-NEXT: call void @use(i32 [[NOT1]]) -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %or1 = or i32 %b, %c %or2 = or i32 %or1, %a @@ -2384,10 +2351,8 @@ ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 ; CHECK-NEXT: [[OR3:%.*]] = or i32 [[B]], [[A]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[OR3]], -1 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[NOT2]], [[C]] -; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] ; CHECK-NEXT: call void @use(i32 [[NOT1]]) -; CHECK-NEXT: ret i32 [[OR4]] +; CHECK-NEXT: ret i32 [[NOT2]] ; %or1 = or i32 %a, %c %or2 = or i32 %or1, %b