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_Deferred(C), m_Deferred(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_Deferred(C), m_Deferred(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; } 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 @@ -3,10 +3,7 @@ define i1 @select_and_icmpeq_i32(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i32( -; 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 @@ -18,10 +15,7 @@ define i1 @select_and_icmpeq_i9(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpeq_i9( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[Y:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[AND:%.*]] = and i9 [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i9 [[AND]], 0 +; CHECK-NEXT: [[ICMP:%.*]] = xor i1 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret i1 [[ICMP]] ; %s1 = select i1 %x, i9 3, i9 16 @@ -33,10 +27,7 @@ define <5 x i1> @select_and_icmpeq_i1vec(<5 x i1> %x, <5 x i1> %y) { ; CHECK-LABEL: @select_and_icmpeq_i1vec( -; CHECK-NEXT: [[S1:%.*]] = select <5 x i1> [[X:%.*]], <5 x i32> , <5 x i32> -; CHECK-NEXT: [[S2:%.*]] = select <5 x i1> [[Y:%.*]], <5 x i32> , <5 x i32> -; CHECK-NEXT: [[AND:%.*]] = and <5 x i32> [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp eq <5 x i32> [[AND]], zeroinitializer +; CHECK-NEXT: [[ICMP:%.*]] = xor <5 x i1> [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: ret <5 x i1> [[ICMP]] ; %s1 = select <5 x i1> %x, <5 x i32> , <5 x i32> diff --git a/llvm/test/Transforms/InstCombine/select_and_icmpne.ll b/llvm/test/Transforms/InstCombine/select_and_icmpne.ll --- a/llvm/test/Transforms/InstCombine/select_and_icmpne.ll +++ b/llvm/test/Transforms/InstCombine/select_and_icmpne.ll @@ -3,11 +3,8 @@ define i1 @select_and_icmpne_i32(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpne_i32( -; 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 ne i32 [[AND]], 0 -; CHECK-NEXT: ret i1 [[ICMP]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] ; %s1 = select i1 %x, i32 2, i32 1 %s2 = select i1 %y, i32 2, i32 1 @@ -18,11 +15,8 @@ define i1 @select_and_icmpne_i9(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpne_i9( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[Y:%.*]], i9 3, i9 16 -; CHECK-NEXT: [[AND:%.*]] = and i9 [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i9 [[AND]], 0 -; CHECK-NEXT: ret i1 [[ICMP]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] ; %s1 = select i1 %x, i9 3, i9 16 %s2 = select i1 %y, i9 3, i9 16 @@ -33,11 +27,8 @@ define <5 x i1> @select_and_icmpne_i1vec(<5 x i1> %x, <5 x i1> %y) { ; CHECK-LABEL: @select_and_icmpne_i1vec( -; CHECK-NEXT: [[S1:%.*]] = select <5 x i1> [[X:%.*]], <5 x i32> , <5 x i32> -; CHECK-NEXT: [[S2:%.*]] = select <5 x i1> [[Y:%.*]], <5 x i32> , <5 x i32> -; CHECK-NEXT: [[AND:%.*]] = and <5 x i32> [[S2]], [[S1]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp ne <5 x i32> [[AND]], zeroinitializer -; CHECK-NEXT: ret <5 x i1> [[ICMP]] +; CHECK-NEXT: [[TMP1:%.*]] = xor <5 x i1> [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: ret <5 x i1> [[TMP1]] ; %s1 = select <5 x i1> %x, <5 x i32> , <5 x i32> %s2 = select <5 x i1> %y, <5 x i32> , <5 x i32> @@ -48,11 +39,8 @@ define i1 @select_and_icmpne_i8_negative_other_pred(i1 %x, i1 %y) { ; CHECK-LABEL: @select_and_icmpne_i8_negative_other_pred( -; CHECK-NEXT: [[S1:%.*]] = select i1 [[X:%.*]], i8 1, i8 8 -; CHECK-NEXT: [[S2:%.*]] = select i1 [[Y:%.*]], i8 1, i8 8 -; CHECK-NEXT: [[AND:%.*]] = and i8 [[S1]], [[S2]] -; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i8 [[AND]], 0 -; CHECK-NEXT: ret i1 [[ICMP]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: ret i1 [[TMP1]] ; %s1 = select i1 %x, i8 1, i8 8 %s2 = select i1 %y, i8 1, i8 8