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) ? ~X : ~C ==> (~X SMIN(~X, ~C) + // (X (~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 SMAX(~C, ~X) + // (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, @@ -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, @@ -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, 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