Index: llvm/trunk/lib/Analysis/ValueTracking.cpp
===================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp
@@ -3969,17 +3969,25 @@
       }
     }
 
-    // Y >s C ? ~Y : ~C == ~Y <s ~C ? ~Y : ~C = SMIN(~Y, ~C)
+    // (X >s C) ? ~X : ~C ==> (~X <s ~C) ? ~X : ~C ==> SMIN(~X, ~C)
+    // (X <s C) ? ~X : ~C ==> (~X >s ~C) ? ~X : ~C ==> SMAX(~X, ~C)
     const APInt *C2;
-    if (match(FalseVal, m_APInt(C2))) {
-      if (Pred == ICmpInst::ICMP_SGT &&
-          CmpRHS->getType() == FalseVal->getType() && ~(*C1) == *C2 &&
-          (match(TrueVal, m_Not(m_Specific(CmpLHS))) ||
-           match(CmpLHS, m_Not(m_Specific(TrueVal))))) {
-        LHS = TrueVal;
-        RHS = FalseVal;
-        return {SPF_SMIN, SPNB_NA, false};
-      }
+    if (match(TrueVal, m_Not(m_Specific(CmpLHS))) &&
+        match(FalseVal, m_APInt(C2)) && ~(*C1) == *C2 &&
+        (Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SLT)) {
+      LHS = TrueVal;
+      RHS = FalseVal;
+      return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false};
+    }
+
+    // (X >s C) ? ~C : ~X ==> (~X <s ~C) ? ~C : ~X ==> SMAX(~C, ~X)
+    // (X <s C) ? ~C : ~X ==> (~X >s ~C) ? ~C : ~X ==> SMIN(~C, ~X)
+    if (match(FalseVal, m_Not(m_Specific(CmpLHS))) &&
+        match(TrueVal, m_APInt(C2)) && ~(*C1) == *C2 &&
+        (Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SLT)) {
+      LHS = TrueVal;
+      RHS = FalseVal;
+      return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
     }
   }
 
Index: llvm/trunk/test/CodeGen/X86/vec_minmax_match.ll
===================================================================
--- llvm/trunk/test/CodeGen/X86/vec_minmax_match.ll
+++ llvm/trunk/test/CodeGen/X86/vec_minmax_match.ll
@@ -18,16 +18,12 @@
   ret <4 x i32> %sel
 }
 
-; FIXME: These are signed min/max ops.
-
 define <4 x i32> @smin_vec2(<4 x i32> %x) {
 ; CHECK-LABEL: smin_vec2:
 ; CHECK:       # BB#0:
 ; CHECK-NEXT:    vpcmpeqd %xmm1, %xmm1, %xmm1
-; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm1
-; CHECK-NEXT:    vpxor %xmm2, %xmm2, %xmm2
-; CHECK-NEXT:    vpcmpgtd %xmm0, %xmm2, %xmm0
-; CHECK-NEXT:    vpor %xmm1, %xmm0, %xmm0
+; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm0
+; CHECK-NEXT:    vpminsd %xmm1, %xmm0, %xmm0
 ; CHECK-NEXT:    retq
 ;
   %not_x = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
@@ -40,11 +36,8 @@
 ; CHECK-LABEL: smax_vec1:
 ; CHECK:       # BB#0:
 ; CHECK-NEXT:    vpcmpeqd %xmm1, %xmm1, %xmm1
-; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm2
-; CHECK-NEXT:    vpxor %xmm3, %xmm3, %xmm3
-; CHECK-NEXT:    vpcmpgtd %xmm0, %xmm3, %xmm0
 ; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm0
-; CHECK-NEXT:    vpor %xmm2, %xmm0, %xmm0
+; CHECK-NEXT:    vpmaxsd %xmm1, %xmm0, %xmm0
 ; CHECK-NEXT:    retq
 ;
   %not_x = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
@@ -57,10 +50,8 @@
 ; CHECK-LABEL: smax_vec2:
 ; CHECK:       # BB#0:
 ; CHECK-NEXT:    vpcmpeqd %xmm1, %xmm1, %xmm1
-; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm1
-; CHECK-NEXT:    vpxor %xmm2, %xmm2, %xmm2
-; CHECK-NEXT:    vpcmpgtd %xmm2, %xmm0, %xmm0
-; CHECK-NEXT:    vpor %xmm1, %xmm0, %xmm0
+; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm0
+; CHECK-NEXT:    vpmaxsd %xmm1, %xmm0, %xmm0
 ; CHECK-NEXT:    retq
 ;
   %not_x = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
Index: llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll
===================================================================
--- llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll
+++ llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll
@@ -140,12 +140,7 @@
 ; max(min(%a, -1), -1) == -1 (swap predicate and select ops)
 define i32 @max_of_min_swap(i32 %a) {
 ; CHECK-LABEL: @max_of_min_swap(
-; CHECK-NEXT:    [[NOT_A:%.*]] = xor i32 %a, -1
-; CHECK-NEXT:    [[C0:%.*]] = icmp slt i32 %a, 0
-; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C0]], i32 -1, i32 [[NOT_A]]
-; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i32 [[S0]], -1
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
-; CHECK-NEXT:    ret i32 [[S1]]
+; CHECK-NEXT:    ret i32 -1
 ;
   %not_a = xor i32 %a, -1
   %c0 = icmp slt i32 %a, 0
@@ -158,12 +153,7 @@
 ; min(max(%a, -1), -1) == -1
 define i32 @min_of_max(i32 %a) {
 ; CHECK-LABEL: @min_of_max(
-; CHECK-NEXT:    [[NOT_A:%.*]] = xor i32 %a, -1
-; CHECK-NEXT:    [[C0:%.*]] = icmp slt i32 %a, 0
-; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1
-; CHECK-NEXT:    [[C1:%.*]] = icmp slt i32 [[S0]], -1
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
-; CHECK-NEXT:    ret i32 [[S1]]
+; CHECK-NEXT:    ret i32 -1
 ;
   %not_a = xor i32 %a, -1
   %c0 = icmp slt i32 %a, 0
@@ -176,12 +166,7 @@
 ; min(max(%a, -1), -1) == -1 (swap predicate and select ops)
 define i32 @min_of_max_swap(i32 %a) {
 ; CHECK-LABEL: @min_of_max_swap(
-; CHECK-NEXT:    [[NOT_A:%.*]] = xor i32 %a, -1
-; CHECK-NEXT:    [[C0:%.*]] = icmp sgt i32 %a, 0
-; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C0]], i32 -1, i32 [[NOT_A]]
-; CHECK-NEXT:    [[C1:%.*]] = icmp slt i32 [[S0]], -1
-; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
-; CHECK-NEXT:    ret i32 [[S1]]
+; CHECK-NEXT:    ret i32 -1
 ;
   %not_a = xor i32 %a, -1
   %c0 = icmp sgt i32 %a, 0
Index: llvm/trunk/test/Transforms/InstCombine/select.ll
===================================================================
--- llvm/trunk/test/Transforms/InstCombine/select.ll
+++ llvm/trunk/test/Transforms/InstCombine/select.ll
@@ -1,4 +1,3 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -instcombine -S | FileCheck %s
 
 ; PR1822
@@ -1765,14 +1764,15 @@
   ret i32 %sel
 }
 
+; max(max(~a, -1), -1) --> max(~a, -1)
+
 define i32 @PR27137(i32 %a) {
 ; CHECK-LABEL: @PR27137(
-; CHECK-NEXT:  %not_a = xor i32 %a, -1
-; CHECK-NEXT:  %c0 = icmp slt i32 %a, 0
-; CHECK-NEXT:  %s0 = select i1 %c0, i32 %not_a, i32 -1
-; CHECK-NEXT:  %c1 = icmp sgt i32 %s0, -1
-; CHECK-NEXT:  %s1 = select i1 %c1, i32 %s0, i32 -1
-; CHECK-NEXT:  ret i32 %s1
+; CHECK-NEXT:    [[NOT_A:%.*]] = xor i32 %a, -1
+; CHECK-NEXT:    [[C0:%.*]] = icmp slt i32 %a, 0
+; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1
+; CHECK-NEXT:    ret i32 [[S0]]
+;
 
   %not_a = xor i32 %a, -1
   %c0 = icmp slt i32 %a, 0