Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2826,6 +2826,16 @@ Builder.CreateOr(Builder.CreateAnd(A, C), B)); } + // (A & ~(B | C)) | ~(A | (B ^ C)) -> (~A & B & C) | ~(B | C) + if (match(Op0, m_c_And(m_Value(A), + m_CombineAnd(m_Value(D), + m_Not(m_Or(m_Value(B), m_Value(C))))))) + if (match(Op1, m_OneUse(m_Not(m_OneUse(m_c_Or( + m_Specific(A), + m_OneUse(m_c_Xor(m_Specific(B), m_Specific(C))))))))) + return BinaryOperator::CreateOr( + Builder.CreateAnd(Builder.CreateAnd(B, C), Builder.CreateNot(A)), D); + 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 @@ -1343,11 +1343,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 @@ -1364,11 +1363,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 @@ -1386,11 +1384,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 @@ -1408,11 +1405,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 @@ -1430,11 +1426,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 @@ -1452,11 +1447,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 @@ -1473,11 +1467,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]] ; @@ -1496,11 +1489,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]] ; @@ -1520,10 +1512,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]] ;