diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index ef84e0c69b3c..b8ff6beccae5 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2902,6 +2902,24 @@ static bool isSignedMinMaxClamp(const Value *Select, const Value *&In, return CLow->sle(*CHigh); } +static bool isSignedMinMaxIntrinsicClamp(const IntrinsicInst *II, + const APInt *&CLow, + const APInt *&CHigh) { + assert((II->getIntrinsicID() == Intrinsic::smin || + II->getIntrinsicID() == Intrinsic::smax) && "Must be smin/smax"); + + Intrinsic::ID InverseID = getInverseMinMaxIntrinsic(II->getIntrinsicID()); + auto *InnerII = dyn_cast(II->getArgOperand(0)); + if (!InnerII || InnerII->getIntrinsicID() != InverseID || + !match(II->getArgOperand(1), m_APInt(CLow)) || + !match(InnerII->getArgOperand(1), m_APInt(CHigh))) + return false; + + if (II->getIntrinsicID() == Intrinsic::smin) + std::swap(CLow, CHigh); + return CLow->sle(*CHigh); +} + /// For vector constants, loop over the elements and find the constant with the /// minimum number of sign bits. Return 0 if the value is not a vector constant /// or if any element was not analyzed; otherwise, return the count for the @@ -3242,6 +3260,12 @@ static unsigned ComputeNumSignBitsImpl(const Value *V, // Absolute value reduces number of sign bits by at most 1. return Tmp - 1; + case Intrinsic::smin: + case Intrinsic::smax: { + const APInt *CLow, *CHigh; + if (isSignedMinMaxIntrinsicClamp(II, CLow, CHigh)) + return std::min(CLow->getNumSignBits(), CHigh->getNumSignBits()); + } } } } diff --git a/llvm/test/Transforms/InstCombine/max_known_bits.ll b/llvm/test/Transforms/InstCombine/max_known_bits.ll index a9f5795f9e8c..7ae179d843c1 100644 --- a/llvm/test/Transforms/InstCombine/max_known_bits.ll +++ b/llvm/test/Transforms/InstCombine/max_known_bits.ll @@ -116,7 +116,7 @@ define i16 @min_max_clamp_intrinsic_2(i16 %x) { ; CHECK-LABEL: @min_max_clamp_intrinsic_2( ; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) ; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048) -; CHECK-NEXT: [[C:%.*]] = add i16 [[B]], 1 +; CHECK-NEXT: [[C:%.*]] = add nsw i16 [[B]], 1 ; CHECK-NEXT: ret i16 [[C]] ; %a = call i16 @llvm.smin.i16(i16 %x, i16 2047) @@ -144,10 +144,8 @@ define i32 @min_max_clamp_intrinsic_4(i16 %x) { ; CHECK-LABEL: @min_max_clamp_intrinsic_4( ; CHECK-NEXT: [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047) ; CHECK-NEXT: [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048) -; CHECK-NEXT: [[C:%.*]] = add i16 [[B]], 1 -; CHECK-NEXT: [[D:%.*]] = sext i16 [[C]] to i32 -; CHECK-NEXT: [[E:%.*]] = add nsw i32 [[D]], -1 -; CHECK-NEXT: ret i32 [[E]] +; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[B]] to i32 +; CHECK-NEXT: ret i32 [[TMP1]] ; %a = call i16 @llvm.smin.i16(i16 %x, i16 2047) %b = call i16 @llvm.smax.i16(i16 %a, i16 -2048)