Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1795,6 +1795,34 @@ } } + // Same version of the LHS which is not demorganed if any subexpressions are + // used multiple times, thus match it in this form: + // (~A & ~B & C) | ... --> ... + // (~A | ~B | C) | ... --> ... + // TODO: Generalize it to work with all patterns in the above block instead + // of a separate pattern here. + if (Op0->hasOneUse() && + (match(Op0, + m_c_BinOp(FlippedOpcode, + m_c_BinOp(FlippedOpcode, m_Value(C), m_Not(m_Value(B))), + m_Not(m_Value(A)))) || + match(Op0, m_c_BinOp(FlippedOpcode, + m_c_BinOp(FlippedOpcode, m_Not(m_Value(A)), + m_Not(m_Value(B))), + m_Value(C))))) { + // (~A & ~B & C) | ~(A | (B | C)) --> ~(A | B) + // (~A & ~B & C) | ~(B | (A | C)) --> ~(A | B) + // (~A | ~B | C) & ~(A & (B & C)) --> ~(A & B) + // (~A | ~B | C) & ~(B & (A & C)) --> ~(A & B) + if (match(Op1, m_Not(m_c_BinOp( + Opcode, m_c_BinOp(Opcode, m_Specific(B), m_Specific(C)), + m_Specific(A)))) || + match(Op1, m_Not(m_c_BinOp( + Opcode, m_c_BinOp(Opcode, m_Specific(A), m_Specific(C)), + m_Specific(B))))) + return BinaryOperator::CreateNot(Builder.CreateBinOp(Opcode, A, B)); + } + // (~A & B & C) | ... --> ... // (~A | B | C) | ... --> ... // TODO: One use checks are conservative. We just need to check that a total 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 @@ -3638,3 +3638,777 @@ call void @use(i32 %or2) ret i32 %and2 } + +; (~a & ~b & c) | ~(a | (b | c)) -> ~(a | b) +; (~a & ~b & c) | ~(b | (a | c)) -> ~(a | b) + +define i32 @not_and_not_and_or_not_or_or(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute1(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute1( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %a, %c + %or2 = or i32 %or1, %b + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute2(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute2( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %c, %b + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute3(i32 %a0, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute3( +; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization + %or1 = or i32 %b, %c + %or2 = or i32 %a, %or1 + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute4(i32 %a, i32 %b0, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute4( +; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization + %or1 = or i32 %a, %c + %or2 = or i32 %b, %or1 + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute5(i32 %a, i32 %b, i32 %c0) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute5( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization + %or1 = or i32 %c, %a + %or2 = or i32 %or1, %b + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute6(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute6( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %notb, %nota + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute7(i32 %a, i32 %b, i32 %c0) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute7( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %c, %and1 + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute8(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute8( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[TMP2]], [[C]] +; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %c + %and2 = and i32 %and1, %notb + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_commute9(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_commute9( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[A]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[TMP2]], [[C]] +; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %notb, %c + %and2 = and i32 %and1, %nota + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_use1(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_use1( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]] +; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %or1) + call void @use(i32 %or2) + call void @use(i32 %not1) + call void @use(i32 %and1) + call void @use(i32 %and2) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_use2(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_use2( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C]] +; CHECK-NEXT: [[OR4:%.*]] = or i32 [[AND2]], [[NOT1]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %or2) + call void @use(i32 %not1) + call void @use(i32 %and1) + call void @use(i32 %and2) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_use3(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_use3( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %or1) + call void @use(i32 %or2) + call void @use(i32 %not1) + call void @use(i32 %and1) + ret i32 %or4 +} + +define i32 @not_and_not_and_or_not_or_or_use4(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_and_not_and_or_not_or_or_use4( +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[OR2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[A]], [[B]] +; CHECK-NEXT: [[OR4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: ret i32 [[OR4]] +; + %or1 = or i32 %b, %c + %or2 = or i32 %or1, %a + %not1 = xor i32 %or2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %and1 = and i32 %nota, %notb + %and2 = and i32 %and1, %c + %or4 = or i32 %and2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %or1) + call void @use(i32 %or2) + call void @use(i32 %not1) + ret i32 %or4 +} + +; (~a | ~b | c) | ~(a & (b & c)) -> ~(a & b) +; (~a | ~b | c) | ~(b & (a & c)) -> ~(a & b) + +define i32 @not_or_not_or_and_not_and_and(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute1(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute1( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %a, %c + %and2 = and i32 %and1, %b + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute2(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute2( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %c, %b + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute3(i32 %a0, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute3( +; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization + %and1 = and i32 %b, %c + %and2 = and i32 %a, %and1 + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute4(i32 %a, i32 %b0, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute4( +; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[A]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization + %and1 = and i32 %a, %c + %and2 = and i32 %b, %and1 + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute5(i32 %a, i32 %b, i32 %c0) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute5( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization + %and1 = and i32 %c, %a + %and2 = and i32 %and1, %b + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute6(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute6( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[A]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %notb, %nota + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute7(i32 %a, i32 %b, i32 %c0) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute7( +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A:%.*]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B:%.*]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %c, %or1 + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute8(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute8( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[TMP2]], [[C]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[AND2]], [[OR2]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %c + %or2 = or i32 %or1, %notb + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_commute9(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_commute9( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B]], [[A]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[TMP2]], [[C]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[AND2]], [[OR2]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %notb, %c + %or2 = or i32 %or1, %nota + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_use1(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_use1( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[AND2]], [[OR2]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %and1) + call void @use(i32 %and2) + call void @use(i32 %not1) + call void @use(i32 %or1) + call void @use(i32 %or2) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_use2(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_use2( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[OR2:%.*]] = or i32 [[OR1]], [[C]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[AND2]], [[OR2]] +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: call void @use(i32 [[OR2]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %and2) + call void @use(i32 %not1) + call void @use(i32 %or1) + call void @use(i32 %or2) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_use3(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_use3( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOTA]], [[NOTB]] +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: call void @use(i32 [[OR1]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %and1) + call void @use(i32 %and2) + call void @use(i32 %not1) + call void @use(i32 %or1) + ret i32 %and4 +} + +define i32 @not_or_not_or_and_not_and_and_use4(i32 %a, i32 %b, i32 %c) { +; CHECK-LABEL: @not_or_not_or_and_not_and_and_use4( +; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[A:%.*]] +; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND2]], -1 +; CHECK-NEXT: [[NOTA:%.*]] = xor i32 [[A]], -1 +; CHECK-NEXT: [[NOTB:%.*]] = xor i32 [[B]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A]], [[B]] +; CHECK-NEXT: [[AND4:%.*]] = xor i32 [[TMP1]], -1 +; CHECK-NEXT: call void @use(i32 [[NOTA]]) +; CHECK-NEXT: call void @use(i32 [[NOTB]]) +; CHECK-NEXT: call void @use(i32 [[AND1]]) +; CHECK-NEXT: call void @use(i32 [[AND2]]) +; CHECK-NEXT: call void @use(i32 [[NOT1]]) +; CHECK-NEXT: ret i32 [[AND4]] +; + %and1 = and i32 %b, %c + %and2 = and i32 %and1, %a + %not1 = xor i32 %and2, -1 + %nota = xor i32 %a, -1 + %notb = xor i32 %b, -1 + %or1 = or i32 %nota, %notb + %or2 = or i32 %or1, %c + %and4 = and i32 %or2, %not1 + call void @use(i32 %nota) + call void @use(i32 %notb) + call void @use(i32 %and1) + call void @use(i32 %and2) + call void @use(i32 %not1) + ret i32 %and4 +}