diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6472,6 +6472,35 @@ if (Instruction *Res = foldReductionIdiom(I, Builder, DL)) return Res; + { + Value *A, *B, *C, *D; + + // Find hidden xor optimization (only if `C` and `D` have no common bits) + // (icmp eq (and (select A, C, D), (select B, C, D)), 0) --> (xor A, B) + if (I.getPredicate() == ICmpInst::ICMP_EQ && + match(Op0, m_And(m_Select(m_Value(A), m_Value(C), m_Value(D)), + m_Select(m_Value(B), m_Specific(C), m_Specific(D)))) && + match(Op1, m_Zero()) && + isKnownNonZero(C, DL, /*Depth*/ 0, &AC, &I, &DT) && + isKnownNonZero(D, DL, /*Depth*/ 0, &AC, &I, &DT) && + haveNoCommonBitsSet(C, D, DL, &AC, &I, &DT)) { + return BinaryOperator::CreateXor(A, B); + } + // (icmp ne (and (select A, C, D), (select B, C, D)), 0) --> (not (xor A, + // B), true) + if (I.getPredicate() == ICmpInst::ICMP_NE && + match(Op0, m_OneUse(m_And( + m_Select(m_Value(A), m_Value(C), m_Value(D)), + m_Select(m_Value(B), m_Specific(C), m_Specific(D))))) && + match(Op1, m_Zero()) && + isKnownNonZero(C, DL, /*Depth*/ 0, &AC, &I, &DT) && + isKnownNonZero(D, DL, /*Depth*/ 0, &AC, &I, &DT) && + haveNoCommonBitsSet(C, D, DL, &AC, &I, &DT)) { + Value *Xor = Builder.CreateXor(A, B); + return BinaryOperator::CreateNeg(Xor); + } + } + return Changed ? &I : nullptr; }