From: Roman Lebedev Date: Fri, 7 Jan 2022 09:40:06 +0000 (+0300) Subject: [NFCI][IR] MinMaxIntrinsic: add some more helper methods, and use them X-Git-Tag: upstream/15.0.7~21321 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a5a6960d1c93f1da1447ba956811928b2154c8ef;p=platform%2Fupstream%2Fllvm.git [NFCI][IR] MinMaxIntrinsic: add some more helper methods, and use them --- diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h index 647a912..5906b1a 100644 --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/llvm/include/llvm/IR/IntrinsicInst.h @@ -530,8 +530,8 @@ public: Value *getRHS() const { return const_cast(getArgOperand(1)); } /// Returns the comparison predicate underlying the intrinsic. - ICmpInst::Predicate getPredicate() const { - switch (getIntrinsicID()) { + static ICmpInst::Predicate getPredicate(Intrinsic::ID ID) { + switch (ID) { case Intrinsic::umin: return ICmpInst::Predicate::ICMP_ULT; case Intrinsic::umax: @@ -545,8 +545,58 @@ public: } } + /// Returns the comparison predicate underlying the intrinsic. + ICmpInst::Predicate getPredicate() const { + return getPredicate(getIntrinsicID()); + } + /// Whether the intrinsic is signed or unsigned. - bool isSigned() const { return ICmpInst::isSigned(getPredicate()); }; + static bool isSigned(Intrinsic::ID ID) { + return ICmpInst::isSigned(getPredicate(ID)); + }; + + /// Whether the intrinsic is signed or unsigned. + bool isSigned() const { return isSigned(getIntrinsicID()); }; + + /// Min/max intrinsics are monotonic, they operate on a fixed-bitwidth values, + /// so there is a certain threshold value, upon reaching which, + /// their value can no longer change. Return said threshold. + static APInt getSaturationPoint(Intrinsic::ID ID, unsigned numBits) { + switch (ID) { + case Intrinsic::umin: + return APInt::getMinValue(numBits); + case Intrinsic::umax: + return APInt::getMaxValue(numBits); + case Intrinsic::smin: + return APInt::getSignedMinValue(numBits); + case Intrinsic::smax: + return APInt::getSignedMaxValue(numBits); + default: + llvm_unreachable("Invalid intrinsic"); + } + } + + /// Min/max intrinsics are monotonic, they operate on a fixed-bitwidth values, + /// so there is a certain threshold value, upon reaching which, + /// their value can no longer change. Return said threshold. + APInt getSaturationPoint(unsigned numBits) const { + return getSaturationPoint(getIntrinsicID(), numBits); + } + + /// Min/max intrinsics are monotonic, they operate on a fixed-bitwidth values, + /// so there is a certain threshold value, upon reaching which, + /// their value can no longer change. Return said threshold. + static Constant *getSaturationPoint(Intrinsic::ID ID, Type *Ty) { + return Constant::getIntegerValue( + Ty, getSaturationPoint(ID, Ty->getScalarSizeInBits())); + } + + /// Min/max intrinsics are monotonic, they operate on a fixed-bitwidth values, + /// so there is a certain threshold value, upon reaching which, + /// their value can no longer change. Return said threshold. + Constant *getSaturationPoint(Type *Ty) const { + return getSaturationPoint(getIntrinsicID(), Ty); + } }; /// This class represents an intrinsic that is based on a binary operation. diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index a373e69..d25694b 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -2467,36 +2467,21 @@ static Constant *ConstantFoldScalarCall2(StringRef Name, !getConstIntOrUndef(Operands[1], C1)) return nullptr; - unsigned BitWidth = Ty->getScalarSizeInBits(); switch (IntrinsicID) { default: break; case Intrinsic::smax: - if (!C0 && !C1) - return UndefValue::get(Ty); - if (!C0 || !C1) - return ConstantInt::get(Ty, APInt::getSignedMaxValue(BitWidth)); - return ConstantInt::get(Ty, C0->sgt(*C1) ? *C0 : *C1); - case Intrinsic::smin: - if (!C0 && !C1) - return UndefValue::get(Ty); - if (!C0 || !C1) - return ConstantInt::get(Ty, APInt::getSignedMinValue(BitWidth)); - return ConstantInt::get(Ty, C0->slt(*C1) ? *C0 : *C1); - case Intrinsic::umax: - if (!C0 && !C1) - return UndefValue::get(Ty); - if (!C0 || !C1) - return ConstantInt::get(Ty, APInt::getMaxValue(BitWidth)); - return ConstantInt::get(Ty, C0->ugt(*C1) ? *C0 : *C1); - case Intrinsic::umin: if (!C0 && !C1) return UndefValue::get(Ty); if (!C0 || !C1) - return ConstantInt::get(Ty, APInt::getMinValue(BitWidth)); - return ConstantInt::get(Ty, C0->ult(*C1) ? *C0 : *C1); + return MinMaxIntrinsic::getSaturationPoint(IntrinsicID, Ty); + return ConstantInt::get( + Ty, ICmpInst::compare(*C0, *C1, + MinMaxIntrinsic::getPredicate(IntrinsicID)) + ? *C0 + : *C1); case Intrinsic::usub_with_overflow: case Intrinsic::ssub_with_overflow: diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 1580089..8bdcb70 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -5615,26 +5615,6 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0, return nullptr; } -static APInt getMaxMinLimit(Intrinsic::ID IID, unsigned BitWidth) { - switch (IID) { - case Intrinsic::smax: return APInt::getSignedMaxValue(BitWidth); - case Intrinsic::smin: return APInt::getSignedMinValue(BitWidth); - case Intrinsic::umax: return APInt::getMaxValue(BitWidth); - case Intrinsic::umin: return APInt::getMinValue(BitWidth); - default: llvm_unreachable("Unexpected intrinsic"); - } -} - -static ICmpInst::Predicate getMaxMinPredicate(Intrinsic::ID IID) { - switch (IID) { - case Intrinsic::smax: return ICmpInst::ICMP_SGE; - case Intrinsic::smin: return ICmpInst::ICMP_SLE; - case Intrinsic::umax: return ICmpInst::ICMP_UGE; - case Intrinsic::umin: return ICmpInst::ICMP_ULE; - default: llvm_unreachable("Unexpected intrinsic"); - } -} - /// Given a min/max intrinsic, see if it can be removed based on having an /// operand that is another min/max intrinsic with shared operand(s). The caller /// is expected to swap the operand arguments to handle commutation. @@ -5702,19 +5682,21 @@ static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1, // Assume undef is the limit value. if (Q.isUndefValue(Op1)) - return ConstantInt::get(ReturnType, getMaxMinLimit(IID, BitWidth)); + return ConstantInt::get( + ReturnType, MinMaxIntrinsic::getSaturationPoint(IID, BitWidth)); const APInt *C; if (match(Op1, m_APIntAllowUndef(C))) { // Clamp to limit value. For example: // umax(i8 %x, i8 255) --> 255 - if (*C == getMaxMinLimit(IID, BitWidth)) + if (*C == MinMaxIntrinsic::getSaturationPoint(IID, BitWidth)) return ConstantInt::get(ReturnType, *C); // If the constant op is the opposite of the limit value, the other must // be larger/smaller or equal. For example: // umin(i8 %x, i8 255) --> %x - if (*C == getMaxMinLimit(getInverseMinMaxIntrinsic(IID), BitWidth)) + if (*C == MinMaxIntrinsic::getSaturationPoint( + getInverseMinMaxIntrinsic(IID), BitWidth)) return Op0; // Remove nested call if constant operands allow it. Example: @@ -5725,10 +5707,9 @@ static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1, Value *M00 = MinMax0->getOperand(0), *M01 = MinMax0->getOperand(1); const APInt *InnerC; if ((match(M00, m_APInt(InnerC)) || match(M01, m_APInt(InnerC))) && - ((IID == Intrinsic::smax && InnerC->sge(*C)) || - (IID == Intrinsic::smin && InnerC->sle(*C)) || - (IID == Intrinsic::umax && InnerC->uge(*C)) || - (IID == Intrinsic::umin && InnerC->ule(*C)))) + ICmpInst::compare(*InnerC, *C, + ICmpInst::getNonStrictPredicate( + MinMaxIntrinsic::getPredicate(IID)))) return Op0; } } @@ -5738,7 +5719,8 @@ static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1, if (Value *V = foldMinMaxSharedOp(IID, Op1, Op0)) return V; - ICmpInst::Predicate Pred = getMaxMinPredicate(IID); + ICmpInst::Predicate Pred = + ICmpInst::getNonStrictPredicate(MinMaxIntrinsic::getPredicate(IID)); if (isICmpTrue(Pred, Op0, Op1, Q.getWithoutUndef(), RecursionLimit)) return Op0; if (isICmpTrue(Pred, Op1, Op0, Q.getWithoutUndef(), RecursionLimit))