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 @@ -6464,6 +6464,22 @@ if (Instruction *Res = foldReductionIdiom(I, Builder, DL)) return Res; + { + Value *A, *B; + const APInt *C, *D; + // Find hidden xor optimization (only works if `and C, D` equals `0`) + // (icmp (and (select A, C, D), (select B, C, D)), 0) --> (xor A, B) + if (I.getPredicate() == ICmpInst::ICMP_EQ && match(Op0, + m_OneUse(m_c_And( + m_OneUse(m_Select(m_Value(A), m_APInt(C), m_APInt(D))), + m_OneUse(m_Select(m_Value(B), m_APInt(C), m_APInt(D))) + )) + ) && match(Op1, m_Zero())) { + if ((*C & *D) == 0) + return BinaryOperator::CreateXor(A, B); + } + } + return Changed ? &I : nullptr; } diff --git a/llvm/test/Transforms/InstCombine/select_and_icmpeq.ll b/llvm/test/Transforms/InstCombine/select_and_icmpeq.ll --- a/llvm/test/Transforms/InstCombine/select_and_icmpeq.ll +++ b/llvm/test/Transforms/InstCombine/select_and_icmpeq.ll @@ -8,10 +8,7 @@ define i1 @select_and_icmpeq_i32_commuted1(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i32_commuted1( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i32 2, i32 1 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[Y:%.*]], i32 2, i32 1 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[S1]], [[S2]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %x, i32 2, i32 1 @@ -23,10 +20,7 @@ define i1 @select_and_icmpeq_i32_commuted2(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i32_commuted2( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[Y:%.*]], i32 4, i32 1 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[X:%.*]], i32 4, i32 1 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %y, i32 4, i32 1 @@ -38,10 +32,7 @@ define i1 @select_and_icmpeq_i32_commuted3(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i32_commuted3( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[Y:%.*]], i32 3, i32 12 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[X:%.*]], i32 3, i32 12 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[S1]], [[S2]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %y, i32 3, i32 12 @@ -53,10 +44,7 @@ define i1 @select_and_icmpeq_i32_commuted4(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i32_commuted4( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[Y:%.*]], i32 3, i32 16 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[X:%.*]], i32 3, i32 16 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %y, i32 3, i32 16 @@ -68,10 +56,7 @@ define i1 @select_and_icmpeq_i9(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i9( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[Y:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[X:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[AND:%.*]] = and i9 [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i9 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %y, i9 3, i9 16