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,31 @@
   if (Instruction *Res = foldReductionIdiom(I, Builder, DL))
     return Res;
 
+  {
+    Value *A, *B, *C, *D;
+
+    // Find hidden xor optimization (only works 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_c_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) --> (xot (xor A, B), true)
+    if (I.getPredicate() == ICmpInst::ICMP_NE && match(Op0,
+      m_OneUse(m_c_And(
+        m_OneUse(m_Select(m_Value(A), m_Value(C), m_Value(D))),
+        m_OneUse(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
@@ -1,11 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
 
-declare void @use32(i32)
-declare void @use16(i16)
-declare void @use7(i7)
-declare void @use3(i3)
-
 define i1 @select_and_icmpeq_i32_commuted1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpeq_i32_commuted1(
 ; CHECK-NEXT:    [[ICMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
@@ -68,10 +63,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> [[Y:%.*]], <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
-; CHECK-NEXT:    [[S2:%.*]] = select <5 x i1> [[X:%.*]], <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
-; 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> [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    ret <5 x i1> [[ICMP]]
 ;
   %s1 = select <5 x i1> %y, <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
@@ -81,74 +73,24 @@
   ret <5 x i1> %icmp
 }
 
-define i1 @select_and_icmpeq_i32_multiuse_select1(i1 %x, i1 %y) {
-; CHECK-LABEL: @select_and_icmpeq_i32_multiuse_select1(
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[Y:%.*]], i32 4, i32 1
-; CHECK-NEXT:    call void @use32(i32 [[S1]])
-; 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:    ret i1 [[ICMP]]
+define i1 @select_and_icmpeq_i32_negative1(i1 %x, i1 %y) {
+; CHECK-LABEL: @select_and_icmpeq_i32_negative1(
+; CHECK-NEXT:    ret i1 false
 ;
-  %s1 = select i1 %y, i32 4, i32 1
-  call void @use32(i32 %s1) ; extra use of first select
-  %s2 = select i1 %x, i32 4, i32 1
-  %and = and i32 %s2, %s1
+  %s1 = select i1 %x, i32 5, i32 1
+  %s2 = select i1 %y, i32 5, i32 1
+  %and = and i32 %s1, %s2
   %icmp = icmp eq i32 %and, 0
   ret i1 %icmp
 }
 
-define i1 @select_and_icmpeq_i16_multiuse_select2(i1 %x, i1 %y) {
-; CHECK-LABEL: @select_and_icmpeq_i16_multiuse_select2(
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[Y:%.*]], i16 4, i16 1
-; CHECK-NEXT:    [[S2:%.*]] = select i1 [[X:%.*]], i16 4, i16 1
-; CHECK-NEXT:    call void @use16(i16 [[S2]])
-; CHECK-NEXT:    [[AND:%.*]] = and i16 [[S2]], [[S1]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i16 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
-;
-  %s1 = select i1 %y, i16 4, i16 1
-  %s2 = select i1 %x, i16 4, i16 1
-  call void @use16(i16 %s2) ; extra use of second select
-  %and = and i16 %s2, %s1
-  %icmp = icmp eq i16 %and, 0
-  ret i1 %icmp
-}
-
-define i1 @select_and_icmpeq_i3_multiuse_and(i1 %x, i1 %y) {
-; CHECK-LABEL: @select_and_icmpeq_i3_multiuse_and(
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[Y:%.*]], i3 1, i3 2
-; CHECK-NEXT:    [[S2:%.*]] = select i1 [[X:%.*]], i3 1, i3 2
-; CHECK-NEXT:    [[AND:%.*]] = and i3 [[S2]], [[S1]]
-; CHECK-NEXT:    call void @use3(i3 [[AND]])
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i3 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
-;
-  %s1 = select i1 %y, i3 1, i3 2
-  %s2 = select i1 %x, i3 1, i3 2
-  %and = and i3 %s2, %s1
-  call void @use3(i3 %and) ; extra use of and
-  %icmp = icmp eq i3 %and, 0
-  ret i1 %icmp
-}
-
-define i1 @select_and_icmpeq_i7_multiuse_all(i1 %x, i1 %y) {
-; CHECK-LABEL: @select_and_icmpeq_i7_multiuse_all(
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[Y:%.*]], i7 1, i7 2
-; CHECK-NEXT:    [[S2:%.*]] = select i1 [[X:%.*]], i7 1, i7 2
-; CHECK-NEXT:    [[AND:%.*]] = and i7 [[S2]], [[S1]]
-; CHECK-NEXT:    call void @use7(i7 [[S1]])
-; CHECK-NEXT:    call void @use7(i7 [[S2]])
-; CHECK-NEXT:    call void @use7(i7 [[AND]])
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i7 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
+define i1 @select_and_icmpeq_i6_negative2(i1 %x, i1 %y) {
+; CHECK-LABEL: @select_and_icmpeq_i6_negative2(
+; CHECK-NEXT:    ret i1 false
 ;
-  %s1 = select i1 %y, i7 1, i7 2
-  %s2 = select i1 %x, i7 1, i7 2
-  %and = and i7 %s2, %s1
-  call void @use7(i7 %s1) ; extra use of first select
-  call void @use7(i7 %s2) ; extra use of second select
-  call void @use7(i7 %and) ; extra use of and
-  %icmp = icmp eq i7 %and, 0
+  %s1 = select i1 %x, i6 2, i6 7
+  %s2 = select i1 %y, i6 2, i6 7
+  %and = and i6 %s1, %s2
+  %icmp = icmp eq i6 %and, 0
   ret i1 %icmp
 }
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
@@ -8,11 +8,8 @@
 
 define i1 @select_and_icmpne_i32_commuted1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpne_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 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
@@ -23,11 +20,8 @@
 
 define i1 @select_and_icmpne_i32_commuted2(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpne_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 ne i32 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %s1 = select i1 %y, i32 4, i32 1
   %s2 = select i1 %x, i32 4, i32 1
@@ -38,11 +32,8 @@
 
 define i1 @select_and_icmpne_i32_commuted3(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpne_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 ne i32 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %s1 = select i1 %y, i32 3, i32 12
   %s2 = select i1 %x, i32 3, i32 12
@@ -53,11 +44,8 @@
 
 define i1 @select_and_icmpne_i32_commuted4(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpne_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 ne i32 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %s1 = select i1 %y, i32 3, i32 16
   %s2 = select i1 %x, i32 3, i32 16
@@ -68,11 +56,8 @@
 
 define i1 @select_and_icmpne_i9(i1 %x, i1 %y) {
 ; CHECK-LABEL: @select_and_icmpne_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 ne i9 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[ICMP]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %s1 = select i1 %y, i9 3, i9 16
   %s2 = select i1 %x, i9 3, i9 16
@@ -83,11 +68,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> [[Y:%.*]], <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
-; CHECK-NEXT:    [[S2:%.*]] = select <5 x i1> [[X:%.*]], <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
-; 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> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    ret <5 x i1> [[TMP1]]
 ;
   %s1 = select <5 x i1> %y, <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
   %s2 = select <5 x i1> %x, <5 x i32> <i32 7, i32 6, i32 5, i32 4, i32 3>, <5 x i32> <i32 8, i32 24, i32 16, i32 256, i32 192>
@@ -167,3 +149,25 @@
   %icmp = icmp ne i7 %and, 0
   ret i1 %icmp
 }
+
+define i1 @select_and_icmpne_i32_negative1(i1 %x, i1 %y) {
+; CHECK-LABEL: @select_and_icmpne_i32_negative1(
+; CHECK-NEXT:    ret i1 true
+;
+  %s1 = select i1 %x, i32 5, i32 1
+  %s2 = select i1 %y, i32 5, i32 1
+  %and = and i32 %s1, %s2
+  %icmp = icmp ne i32 %and, 0
+  ret i1 %icmp
+}
+
+define i1 @select_and_icmpne_i6_negative2(i1 %x, i1 %y) {
+; CHECK-LABEL: @select_and_icmpne_i6_negative2(
+; CHECK-NEXT:    ret i1 true
+;
+  %s1 = select i1 %x, i6 2, i6 7
+  %s2 = select i1 %y, i6 2, i6 7
+  %and = and i6 %s1, %s2
+  %icmp = icmp ne i6 %and, 0
+  ret i1 %icmp
+}