diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1715,6 +1715,72 @@ return new ZExtInst(Builder.CreateAnd(NewBO, X), Ty); } +/// Try folding relatively complex patterns for both And and Or operations +/// with all And and Or swapped. +static Instruction *foldComplexAndOrPatterns(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + const Instruction::BinaryOps Opcode = I.getOpcode(); + assert(Opcode == Instruction::And || Opcode == Instruction::Or); + + // Flip the logic operation. + const Instruction::BinaryOps FlippedOpcode = + (Opcode == Instruction::And) ? Instruction::Or : Instruction::And; + + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + Value *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 reduction + // in operations. + if (match(Op0, m_c_BinOp(FlippedOpcode, + m_Not(m_BinOp(Opcode, m_Value(A), m_Value(B))), + m_Value(C)))) { + // (~(A | B) & C) | (~(A | C) & B) --> (B ^ C) & ~A + // (~(A & B) | C) & (~(A & C) | B) --> ~((B ^ C) & A) + if (match(Op1, + m_OneUse(m_c_BinOp(FlippedOpcode, + m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(A), + m_Specific(C)))), + m_Specific(B))))) { + Value *Xor = Builder.CreateXor(B, C); + return (Opcode == Instruction::Or) + ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A)) + : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, A)); + } + + // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B + // (~(A & B) | C) & (~(B & C) | A) --> ~((A ^ C) & B) + if (match(Op1, + m_OneUse(m_c_BinOp(FlippedOpcode, + m_OneUse(m_Not(m_c_BinOp(Opcode, m_Specific(B), + m_Specific(C)))), + m_Specific(A))))) { + Value *Xor = Builder.CreateXor(A, C); + return (Opcode == Instruction::Or) + ? BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B)) + : BinaryOperator::CreateNot(Builder.CreateAnd(Xor, B)); + } + + // (~(A | B) & C) | ~(A | C) --> ~((B & C) | A) + // (~(A & B) | C) & ~(A & C) --> ~((B | C) & A) + if (match(Op1, m_OneUse(m_Not(m_OneUse( + m_c_BinOp(Opcode, m_Specific(A), m_Specific(C))))))) + return BinaryOperator::CreateNot(Builder.CreateBinOp( + Opcode, Builder.CreateBinOp(FlippedOpcode, B, C), A)); + + // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B) + // (~(A & B) | C) & ~(B & C) --> ~((A | C) & B) + if (match(Op1, m_OneUse(m_Not(m_OneUse( + m_c_BinOp(Opcode, m_Specific(B), m_Specific(C))))))) + return BinaryOperator::CreateNot(Builder.CreateBinOp( + Opcode, Builder.CreateBinOp(FlippedOpcode, A, C), B)); + } + + return nullptr; +} + // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. @@ -1740,6 +1806,9 @@ if (Instruction *Xor = foldAndToXor(I, Builder)) return Xor; + if (Instruction *X = foldComplexAndOrPatterns(I, Builder)) + return X; + // (A|B)&(A|C) -> A|(B&C) etc if (Value *V = SimplifyUsingDistributiveLaws(I)) return replaceInstUsesWith(I, V); @@ -2489,6 +2558,9 @@ if (Instruction *Xor = foldOrToXor(I, Builder)) return Xor; + if (Instruction *X = foldComplexAndOrPatterns(I, Builder)) + return X; + // (A&B)|(A&C) -> A&(B|C) etc if (Value *V = SimplifyUsingDistributiveLaws(I)) return replaceInstUsesWith(I, V); @@ -2624,40 +2696,6 @@ if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A)))) return BinaryOperator::CreateOr(Op1, Builder.CreateAnd(A, 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 reduction - // in operations. - 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)))), - m_Specific(B))))) { - Value *Xor = Builder.CreateXor(B, C); - return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(A)); - } - - // (~(A | B) & C) | (~(B | C) & A) --> (A ^ C) & ~B - if (match(Op1, m_OneUse(m_c_And( - m_OneUse(m_Not(m_c_Or(m_Specific(B), m_Specific(C)))), - m_Specific(A))))) { - Value *Xor = Builder.CreateXor(A, C); - return BinaryOperator::CreateAnd(Xor, Builder.CreateNot(B)); - } - - // (~(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::CreateNot( - Builder.CreateOr(Builder.CreateAnd(B, C), A)); - - // (~(A | B) & C) | ~(B | C) --> ~((A & C) | B) - if (match(Op1, - m_OneUse(m_Not(m_OneUse(m_c_Or(m_Specific(B), m_Specific(C))))))) - return BinaryOperator::CreateNot( - Builder.CreateOr(Builder.CreateAnd(A, C), B)); - } - if (Instruction *DeMorgan = matchDeMorgansLaws(I, Builder)) return DeMorgan; diff --git a/llvm/test/Transforms/InstCombine/and-xor-or.ll b/llvm/test/Transforms/InstCombine/and-xor-or.ll --- a/llvm/test/Transforms/InstCombine/and-xor-or.ll +++ b/llvm/test/Transforms/InstCombine/and-xor-or.ll @@ -1066,13 +1066,9 @@ define i32 @and_not_or(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %a, %b @@ -1088,13 +1084,9 @@ define i32 @and_not_or_commute1(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @and_not_or_commute1( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization @@ -1111,13 +1103,9 @@ define i32 @and_not_or_commute2(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @and_not_or_commute2( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR2]], [[OR1]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization @@ -1133,13 +1121,9 @@ define i32 @and_not_or_commute3(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or_commute3( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1155,13 +1139,9 @@ define i32 @and_not_or_commute4(i32 %a, i32 %b, i32 %c0) { ; CHECK-LABEL: @and_not_or_commute4( ; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %c = sdiv i32 42, %c0 ; thwart complexity-based canonicalization @@ -1179,13 +1159,9 @@ ; CHECK-LABEL: @and_not_or_commute5( ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] ; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[C]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization @@ -1202,13 +1178,9 @@ define i32 @and_not_or_commute6(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or_commute6( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %a, %b @@ -1223,13 +1195,9 @@ define i32 @and_not_or_commute7(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or_commute7( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1246,13 +1214,9 @@ ; CHECK-LABEL: @and_not_or_commute8( ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization @@ -1272,13 +1236,9 @@ ; CHECK-NEXT: [[A:%.*]] = sdiv i32 42, [[A0:%.*]] ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] ; CHECK-NEXT: [[C:%.*]] = sdiv i32 42, [[C0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A]], [[B]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[C]], [[NOT1]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %a = sdiv i32 42, %a0 ; thwart complexity-based canonicalization @@ -1298,11 +1258,9 @@ ; CHECK-LABEL: @and_not_or_extra_not_use1( ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[NOT1]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -1345,10 +1303,9 @@ ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 ; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[OR1]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -1389,12 +1346,9 @@ define i32 @and_not_or_extra_or_use1(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or_extra_or_use1( ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[AND1]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -1411,13 +1365,10 @@ define i32 @and_not_or_extra_or_use2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_not_or_extra_or_use2( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[NOT1:%.*]] = xor i32 [[AND1]], -1 -; CHECK-NEXT: [[OR1:%.*]] = or i32 [[NOT1]], [[C:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR2:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = and i32 [[OR1]], [[OR2]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[B:%.*]], [[C]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[AND2]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -1777,11 +1728,9 @@ define i32 @and_or_not_not(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1796,11 +1745,9 @@ define i32 @and_or_not_not_commute1(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute1( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization @@ -1815,11 +1762,9 @@ define i32 @and_or_not_not_commute2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute2( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1833,11 +1778,9 @@ define i32 @and_or_not_not_commute3(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute3( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1851,11 +1794,9 @@ define i32 @and_or_not_not_commute4(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute4( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %a, %b @@ -1869,11 +1810,9 @@ define i32 @and_or_not_not_commute5(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute5( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %b, %a @@ -1888,11 +1827,9 @@ define i32 @and_or_not_not_commute6(i32 %a, i32 %b0, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute6( ; CHECK-NEXT: [[B:%.*]] = sdiv i32 42, [[B0:%.*]] -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[B]], [[NOT2]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B]], [[C:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %b = sdiv i32 42, %b0 ; thwart complexity-based canonicalization @@ -1907,11 +1844,9 @@ define i32 @and_or_not_not_commute7(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_commute7( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[C:%.*]], [[A]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: ret i32 [[AND3]] ; %and1 = and i32 %a, %b @@ -1946,11 +1881,11 @@ define i32 @and_or_not_not_extra_not_use2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_extra_not_use2( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[NOT2]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -1966,11 +1901,12 @@ define i32 @and_or_not_not_extra_and_use(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_extra_and_use( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]] ; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[OR]]) ; CHECK-NEXT: ret i32 [[AND3]] ; @@ -2006,11 +1942,10 @@ define i32 @and_or_not_not_extra_or_use2(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @and_or_not_not_extra_or_use2( -; CHECK-NEXT: [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A]], [[C:%.*]] -; CHECK-NEXT: [[NOT2:%.*]] = xor i32 [[AND2]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[NOT2]], [[B]] -; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[AND1]], [[OR]] +; CHECK-NEXT: [[AND2:%.*]] = and i32 [[A:%.*]], [[C:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[C]], [[B:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A]] +; CHECK-NEXT: [[AND3:%.*]] = xor i32 [[TMP2]], -1 ; CHECK-NEXT: call void @use(i32 [[AND2]]) ; CHECK-NEXT: ret i32 [[AND3]] ;