//===- ConstantRange.cpp - ConstantRange implementation -------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Represent a range of possible values that may occur when the program is run // for an integral value. This keeps track of a lower and upper bound for the // constant, which MAY wrap around the end of the numeric range. To do this, it // keeps track of a [lower, upper) bound, which specifies an interval just like // STL iterators. When used with boolean values, the following are important // ranges (other integral ranges use min/max values for special range values): // // [F, F) = {} = Empty set // [T, F) = {T} // [F, T) = {F} // [T, T) = {F, T} = Full set // //===----------------------------------------------------------------------===// #include "llvm/ADT/APInt.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Operator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include using namespace llvm; ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) : Lower(Full ? APInt::getMaxValue(BitWidth) : APInt::getMinValue(BitWidth)), Upper(Lower) {} ConstantRange::ConstantRange(APInt V) : Lower(std::move(V)), Upper(Lower + 1) {} ConstantRange::ConstantRange(APInt L, APInt U) : Lower(std::move(L)), Upper(std::move(U)) { assert(Lower.getBitWidth() == Upper.getBitWidth() && "ConstantRange with unequal bit widths"); assert((Lower != Upper || (Lower.isMaxValue() || Lower.isMinValue())) && "Lower == Upper, but they aren't min or max value!"); } ConstantRange ConstantRange::fromKnownBits(const KnownBits &Known, bool IsSigned) { assert(!Known.hasConflict() && "Expected valid KnownBits"); if (Known.isUnknown()) return getFull(Known.getBitWidth()); // For unsigned ranges, or signed ranges with known sign bit, create a simple // range between the smallest and largest possible value. if (!IsSigned || Known.isNegative() || Known.isNonNegative()) return ConstantRange(Known.getMinValue(), Known.getMaxValue() + 1); // If we don't know the sign bit, pick the lower bound as a negative number // and the upper bound as a non-negative one. APInt Lower = Known.getMinValue(), Upper = Known.getMaxValue(); Lower.setSignBit(); Upper.clearSignBit(); return ConstantRange(Lower, Upper + 1); } KnownBits ConstantRange::toKnownBits() const { // TODO: We could return conflicting known bits here, but consumers are // likely not prepared for that. if (isEmptySet()) return KnownBits(getBitWidth()); // We can only retain the top bits that are the same between min and max. APInt Min = getUnsignedMin(); APInt Max = getUnsignedMax(); KnownBits Known = KnownBits::makeConstant(Min); if (std::optional DifferentBit = APIntOps::GetMostSignificantDifferentBit(Min, Max)) { Known.Zero.clearLowBits(*DifferentBit + 1); Known.One.clearLowBits(*DifferentBit + 1); } return Known; } ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &CR) { if (CR.isEmptySet()) return CR; uint32_t W = CR.getBitWidth(); switch (Pred) { default: llvm_unreachable("Invalid ICmp predicate to makeAllowedICmpRegion()"); case CmpInst::ICMP_EQ: return CR; case CmpInst::ICMP_NE: if (CR.isSingleElement()) return ConstantRange(CR.getUpper(), CR.getLower()); return getFull(W); case CmpInst::ICMP_ULT: { APInt UMax(CR.getUnsignedMax()); if (UMax.isMinValue()) return getEmpty(W); return ConstantRange(APInt::getMinValue(W), std::move(UMax)); } case CmpInst::ICMP_SLT: { APInt SMax(CR.getSignedMax()); if (SMax.isMinSignedValue()) return getEmpty(W); return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax)); } case CmpInst::ICMP_ULE: return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1); case CmpInst::ICMP_SLE: return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1); case CmpInst::ICMP_UGT: { APInt UMin(CR.getUnsignedMin()); if (UMin.isMaxValue()) return getEmpty(W); return ConstantRange(std::move(UMin) + 1, APInt::getZero(W)); } case CmpInst::ICMP_SGT: { APInt SMin(CR.getSignedMin()); if (SMin.isMaxSignedValue()) return getEmpty(W); return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W)); } case CmpInst::ICMP_UGE: return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W)); case CmpInst::ICMP_SGE: return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W)); } } ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred, const ConstantRange &CR) { // Follows from De-Morgan's laws: // // ~(~A union ~B) == A intersect B. // return makeAllowedICmpRegion(CmpInst::getInversePredicate(Pred), CR) .inverse(); } ConstantRange ConstantRange::makeExactICmpRegion(CmpInst::Predicate Pred, const APInt &C) { // Computes the exact range that is equal to both the constant ranges returned // by makeAllowedICmpRegion and makeSatisfyingICmpRegion. This is always true // when RHS is a singleton such as an APInt and so the assert is valid. // However for non-singleton RHS, for example ult [2,5) makeAllowedICmpRegion // returns [0,4) but makeSatisfyICmpRegion returns [0,2). // assert(makeAllowedICmpRegion(Pred, C) == makeSatisfyingICmpRegion(Pred, C)); return makeAllowedICmpRegion(Pred, C); } bool ConstantRange::areInsensitiveToSignednessOfICmpPredicate( const ConstantRange &CR1, const ConstantRange &CR2) { if (CR1.isEmptySet() || CR2.isEmptySet()) return true; return (CR1.isAllNonNegative() && CR2.isAllNonNegative()) || (CR1.isAllNegative() && CR2.isAllNegative()); } bool ConstantRange::areInsensitiveToSignednessOfInvertedICmpPredicate( const ConstantRange &CR1, const ConstantRange &CR2) { if (CR1.isEmptySet() || CR2.isEmptySet()) return true; return (CR1.isAllNonNegative() && CR2.isAllNegative()) || (CR1.isAllNegative() && CR2.isAllNonNegative()); } CmpInst::Predicate ConstantRange::getEquivalentPredWithFlippedSignedness( CmpInst::Predicate Pred, const ConstantRange &CR1, const ConstantRange &CR2) { assert(CmpInst::isIntPredicate(Pred) && CmpInst::isRelational(Pred) && "Only for relational integer predicates!"); CmpInst::Predicate FlippedSignednessPred = CmpInst::getFlippedSignednessPredicate(Pred); if (areInsensitiveToSignednessOfICmpPredicate(CR1, CR2)) return FlippedSignednessPred; if (areInsensitiveToSignednessOfInvertedICmpPredicate(CR1, CR2)) return CmpInst::getInversePredicate(FlippedSignednessPred); return CmpInst::Predicate::BAD_ICMP_PREDICATE; } void ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS, APInt &Offset) const { Offset = APInt(getBitWidth(), 0); if (isFullSet() || isEmptySet()) { Pred = isEmptySet() ? CmpInst::ICMP_ULT : CmpInst::ICMP_UGE; RHS = APInt(getBitWidth(), 0); } else if (auto *OnlyElt = getSingleElement()) { Pred = CmpInst::ICMP_EQ; RHS = *OnlyElt; } else if (auto *OnlyMissingElt = getSingleMissingElement()) { Pred = CmpInst::ICMP_NE; RHS = *OnlyMissingElt; } else if (getLower().isMinSignedValue() || getLower().isMinValue()) { Pred = getLower().isMinSignedValue() ? CmpInst::ICMP_SLT : CmpInst::ICMP_ULT; RHS = getUpper(); } else if (getUpper().isMinSignedValue() || getUpper().isMinValue()) { Pred = getUpper().isMinSignedValue() ? CmpInst::ICMP_SGE : CmpInst::ICMP_UGE; RHS = getLower(); } else { Pred = CmpInst::ICMP_ULT; RHS = getUpper() - getLower(); Offset = -getLower(); } assert(ConstantRange::makeExactICmpRegion(Pred, RHS) == add(Offset) && "Bad result!"); } bool ConstantRange::getEquivalentICmp(CmpInst::Predicate &Pred, APInt &RHS) const { APInt Offset; getEquivalentICmp(Pred, RHS, Offset); return Offset.isZero(); } bool ConstantRange::icmp(CmpInst::Predicate Pred, const ConstantRange &Other) const { return makeSatisfyingICmpRegion(Pred, Other).contains(*this); } /// Exact mul nuw region for single element RHS. static ConstantRange makeExactMulNUWRegion(const APInt &V) { unsigned BitWidth = V.getBitWidth(); if (V == 0) return ConstantRange::getFull(V.getBitWidth()); return ConstantRange::getNonEmpty( APIntOps::RoundingUDiv(APInt::getMinValue(BitWidth), V, APInt::Rounding::UP), APIntOps::RoundingUDiv(APInt::getMaxValue(BitWidth), V, APInt::Rounding::DOWN) + 1); } /// Exact mul nsw region for single element RHS. static ConstantRange makeExactMulNSWRegion(const APInt &V) { // Handle 0 and -1 separately to avoid division by zero or overflow. unsigned BitWidth = V.getBitWidth(); if (V == 0) return ConstantRange::getFull(BitWidth); APInt MinValue = APInt::getSignedMinValue(BitWidth); APInt MaxValue = APInt::getSignedMaxValue(BitWidth); // e.g. Returning [-127, 127], represented as [-127, -128). if (V.isAllOnes()) return ConstantRange(-MaxValue, MinValue); APInt Lower, Upper; if (V.isNegative()) { Lower = APIntOps::RoundingSDiv(MaxValue, V, APInt::Rounding::UP); Upper = APIntOps::RoundingSDiv(MinValue, V, APInt::Rounding::DOWN); } else { Lower = APIntOps::RoundingSDiv(MinValue, V, APInt::Rounding::UP); Upper = APIntOps::RoundingSDiv(MaxValue, V, APInt::Rounding::DOWN); } return ConstantRange::getNonEmpty(Lower, Upper + 1); } ConstantRange ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, const ConstantRange &Other, unsigned NoWrapKind) { using OBO = OverflowingBinaryOperator; assert(Instruction::isBinaryOp(BinOp) && "Binary operators only!"); assert((NoWrapKind == OBO::NoSignedWrap || NoWrapKind == OBO::NoUnsignedWrap) && "NoWrapKind invalid!"); bool Unsigned = NoWrapKind == OBO::NoUnsignedWrap; unsigned BitWidth = Other.getBitWidth(); switch (BinOp) { default: llvm_unreachable("Unsupported binary op"); case Instruction::Add: { if (Unsigned) return getNonEmpty(APInt::getZero(BitWidth), -Other.getUnsignedMax()); APInt SignedMinVal = APInt::getSignedMinValue(BitWidth); APInt SMin = Other.getSignedMin(), SMax = Other.getSignedMax(); return getNonEmpty( SMin.isNegative() ? SignedMinVal - SMin : SignedMinVal, SMax.isStrictlyPositive() ? SignedMinVal - SMax : SignedMinVal); } case Instruction::Sub: { if (Unsigned) return getNonEmpty(Other.getUnsignedMax(), APInt::getMinValue(BitWidth)); APInt SignedMinVal = APInt::getSignedMinValue(BitWidth); APInt SMin = Other.getSignedMin(), SMax = Other.getSignedMax(); return getNonEmpty( SMax.isStrictlyPositive() ? SignedMinVal + SMax : SignedMinVal, SMin.isNegative() ? SignedMinVal + SMin : SignedMinVal); } case Instruction::Mul: if (Unsigned) return makeExactMulNUWRegion(Other.getUnsignedMax()); return makeExactMulNSWRegion(Other.getSignedMin()) .intersectWith(makeExactMulNSWRegion(Other.getSignedMax())); case Instruction::Shl: { // For given range of shift amounts, if we ignore all illegal shift amounts // (that always produce poison), what shift amount range is left? ConstantRange ShAmt = Other.intersectWith( ConstantRange(APInt(BitWidth, 0), APInt(BitWidth, (BitWidth - 1) + 1))); if (ShAmt.isEmptySet()) { // If the entire range of shift amounts is already poison-producing, // then we can freely add more poison-producing flags ontop of that. return getFull(BitWidth); } // There are some legal shift amounts, we can compute conservatively-correct // range of no-wrap inputs. Note that by now we have clamped the ShAmtUMax // to be at most bitwidth-1, which results in most conservative range. APInt ShAmtUMax = ShAmt.getUnsignedMax(); if (Unsigned) return getNonEmpty(APInt::getZero(BitWidth), APInt::getMaxValue(BitWidth).lshr(ShAmtUMax) + 1); return getNonEmpty(APInt::getSignedMinValue(BitWidth).ashr(ShAmtUMax), APInt::getSignedMaxValue(BitWidth).ashr(ShAmtUMax) + 1); } } } ConstantRange ConstantRange::makeExactNoWrapRegion(Instruction::BinaryOps BinOp, const APInt &Other, unsigned NoWrapKind) { // makeGuaranteedNoWrapRegion() is exact for single-element ranges, as // "for all" and "for any" coincide in this case. return makeGuaranteedNoWrapRegion(BinOp, ConstantRange(Other), NoWrapKind); } bool ConstantRange::isFullSet() const { return Lower == Upper && Lower.isMaxValue(); } bool ConstantRange::isEmptySet() const { return Lower == Upper && Lower.isMinValue(); } bool ConstantRange::isWrappedSet() const { return Lower.ugt(Upper) && !Upper.isZero(); } bool ConstantRange::isUpperWrapped() const { return Lower.ugt(Upper); } bool ConstantRange::isSignWrappedSet() const { return Lower.sgt(Upper) && !Upper.isMinSignedValue(); } bool ConstantRange::isUpperSignWrapped() const { return Lower.sgt(Upper); } bool ConstantRange::isSizeStrictlySmallerThan(const ConstantRange &Other) const { assert(getBitWidth() == Other.getBitWidth()); if (isFullSet()) return false; if (Other.isFullSet()) return true; return (Upper - Lower).ult(Other.Upper - Other.Lower); } bool ConstantRange::isSizeLargerThan(uint64_t MaxSize) const { // If this a full set, we need special handling to avoid needing an extra bit // to represent the size. if (isFullSet()) return MaxSize == 0 || APInt::getMaxValue(getBitWidth()).ugt(MaxSize - 1); return (Upper - Lower).ugt(MaxSize); } bool ConstantRange::isAllNegative() const { // Empty set is all negative, full set is not. if (isEmptySet()) return true; if (isFullSet()) return false; return !isUpperSignWrapped() && !Upper.isStrictlyPositive(); } bool ConstantRange::isAllNonNegative() const { // Empty and full set are automatically treated correctly. return !isSignWrappedSet() && Lower.isNonNegative(); } APInt ConstantRange::getUnsignedMax() const { if (isFullSet() || isUpperWrapped()) return APInt::getMaxValue(getBitWidth()); return getUpper() - 1; } APInt ConstantRange::getUnsignedMin() const { if (isFullSet() || isWrappedSet()) return APInt::getMinValue(getBitWidth()); return getLower(); } APInt ConstantRange::getSignedMax() const { if (isFullSet() || isUpperSignWrapped()) return APInt::getSignedMaxValue(getBitWidth()); return getUpper() - 1; } APInt ConstantRange::getSignedMin() const { if (isFullSet() || isSignWrappedSet()) return APInt::getSignedMinValue(getBitWidth()); return getLower(); } bool ConstantRange::contains(const APInt &V) const { if (Lower == Upper) return isFullSet(); if (!isUpperWrapped()) return Lower.ule(V) && V.ult(Upper); return Lower.ule(V) || V.ult(Upper); } bool ConstantRange::contains(const ConstantRange &Other) const { if (isFullSet() || Other.isEmptySet()) return true; if (isEmptySet() || Other.isFullSet()) return false; if (!isUpperWrapped()) { if (Other.isUpperWrapped()) return false; return Lower.ule(Other.getLower()) && Other.getUpper().ule(Upper); } if (!Other.isUpperWrapped()) return Other.getUpper().ule(Upper) || Lower.ule(Other.getLower()); return Other.getUpper().ule(Upper) && Lower.ule(Other.getLower()); } unsigned ConstantRange::getActiveBits() const { if (isEmptySet()) return 0; return getUnsignedMax().getActiveBits(); } unsigned ConstantRange::getMinSignedBits() const { if (isEmptySet()) return 0; return std::max(getSignedMin().getSignificantBits(), getSignedMax().getSignificantBits()); } ConstantRange ConstantRange::subtract(const APInt &Val) const { assert(Val.getBitWidth() == getBitWidth() && "Wrong bit width"); // If the set is empty or full, don't modify the endpoints. if (Lower == Upper) return *this; return ConstantRange(Lower - Val, Upper - Val); } ConstantRange ConstantRange::difference(const ConstantRange &CR) const { return intersectWith(CR.inverse()); } static ConstantRange getPreferredRange( const ConstantRange &CR1, const ConstantRange &CR2, ConstantRange::PreferredRangeType Type) { if (Type == ConstantRange::Unsigned) { if (!CR1.isWrappedSet() && CR2.isWrappedSet()) return CR1; if (CR1.isWrappedSet() && !CR2.isWrappedSet()) return CR2; } else if (Type == ConstantRange::Signed) { if (!CR1.isSignWrappedSet() && CR2.isSignWrappedSet()) return CR1; if (CR1.isSignWrappedSet() && !CR2.isSignWrappedSet()) return CR2; } if (CR1.isSizeStrictlySmallerThan(CR2)) return CR1; return CR2; } ConstantRange ConstantRange::intersectWith(const ConstantRange &CR, PreferredRangeType Type) const { assert(getBitWidth() == CR.getBitWidth() && "ConstantRange types don't agree!"); // Handle common cases. if ( isEmptySet() || CR.isFullSet()) return *this; if (CR.isEmptySet() || isFullSet()) return CR; if (!isUpperWrapped() && CR.isUpperWrapped()) return CR.intersectWith(*this, Type); if (!isUpperWrapped() && !CR.isUpperWrapped()) { if (Lower.ult(CR.Lower)) { // L---U : this // L---U : CR if (Upper.ule(CR.Lower)) return getEmpty(); // L---U : this // L---U : CR if (Upper.ult(CR.Upper)) return ConstantRange(CR.Lower, Upper); // L-------U : this // L---U : CR return CR; } // L---U : this // L-------U : CR if (Upper.ult(CR.Upper)) return *this; // L-----U : this // L-----U : CR if (Lower.ult(CR.Upper)) return ConstantRange(Lower, CR.Upper); // L---U : this // L---U : CR return getEmpty(); } if (isUpperWrapped() && !CR.isUpperWrapped()) { if (CR.Lower.ult(Upper)) { // ------U L--- : this // L--U : CR if (CR.Upper.ult(Upper)) return CR; // ------U L--- : this // L------U : CR if (CR.Upper.ule(Lower)) return ConstantRange(CR.Lower, Upper); // ------U L--- : this // L----------U : CR return getPreferredRange(*this, CR, Type); } if (CR.Lower.ult(Lower)) { // --U L---- : this // L--U : CR if (CR.Upper.ule(Lower)) return getEmpty(); // --U L---- : this // L------U : CR return ConstantRange(Lower, CR.Upper); } // --U L------ : this // L--U : CR return CR; } if (CR.Upper.ult(Upper)) { // ------U L-- : this // --U L------ : CR if (CR.Lower.ult(Upper)) return getPreferredRange(*this, CR, Type); // ----U L-- : this // --U L---- : CR if (CR.Lower.ult(Lower)) return ConstantRange(Lower, CR.Upper); // ----U L---- : this // --U L-- : CR return CR; } if (CR.Upper.ule(Lower)) { // --U L-- : this // ----U L---- : CR if (CR.Lower.ult(Lower)) return *this; // --U L---- : this // ----U L-- : CR return ConstantRange(CR.Lower, Upper); } // --U L------ : this // ------U L-- : CR return getPreferredRange(*this, CR, Type); } ConstantRange ConstantRange::unionWith(const ConstantRange &CR, PreferredRangeType Type) const { assert(getBitWidth() == CR.getBitWidth() && "ConstantRange types don't agree!"); if ( isFullSet() || CR.isEmptySet()) return *this; if (CR.isFullSet() || isEmptySet()) return CR; if (!isUpperWrapped() && CR.isUpperWrapped()) return CR.unionWith(*this, Type); if (!isUpperWrapped() && !CR.isUpperWrapped()) { // L---U and L---U : this // L---U L---U : CR // result in one of // L---------U // -----U L----- if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower)) return getPreferredRange( ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type); APInt L = CR.Lower.ult(Lower) ? CR.Lower : Lower; APInt U = (CR.Upper - 1).ugt(Upper - 1) ? CR.Upper : Upper; if (L.isZero() && U.isZero()) return getFull(); return ConstantRange(std::move(L), std::move(U)); } if (!CR.isUpperWrapped()) { // ------U L----- and ------U L----- : this // L--U L--U : CR if (CR.Upper.ule(Upper) || CR.Lower.uge(Lower)) return *this; // ------U L----- : this // L---------U : CR if (CR.Lower.ule(Upper) && Lower.ule(CR.Upper)) return getFull(); // ----U L---- : this // L---U : CR // results in one of // ----------U L---- // ----U L---------- if (Upper.ult(CR.Lower) && CR.Upper.ult(Lower)) return getPreferredRange( ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type); // ----U L----- : this // L----U : CR if (Upper.ult(CR.Lower) && Lower.ule(CR.Upper)) return ConstantRange(CR.Lower, Upper); // ------U L---- : this // L-----U : CR assert(CR.Lower.ule(Upper) && CR.Upper.ult(Lower) && "ConstantRange::unionWith missed a case with one range wrapped"); return ConstantRange(Lower, CR.Upper); } // ------U L---- and ------U L---- : this // -U L----------- and ------------U L : CR if (CR.Lower.ule(Upper) || Lower.ule(CR.Upper)) return getFull(); APInt L = CR.Lower.ult(Lower) ? CR.Lower : Lower; APInt U = CR.Upper.ugt(Upper) ? CR.Upper : Upper; return ConstantRange(std::move(L), std::move(U)); } std::optional ConstantRange::exactIntersectWith(const ConstantRange &CR) const { // TODO: This can be implemented more efficiently. ConstantRange Result = intersectWith(CR); if (Result == inverse().unionWith(CR.inverse()).inverse()) return Result; return std::nullopt; } std::optional ConstantRange::exactUnionWith(const ConstantRange &CR) const { // TODO: This can be implemented more efficiently. ConstantRange Result = unionWith(CR); if (Result == inverse().intersectWith(CR.inverse()).inverse()) return Result; return std::nullopt; } ConstantRange ConstantRange::castOp(Instruction::CastOps CastOp, uint32_t ResultBitWidth) const { switch (CastOp) { default: llvm_unreachable("unsupported cast type"); case Instruction::Trunc: return truncate(ResultBitWidth); case Instruction::SExt: return signExtend(ResultBitWidth); case Instruction::ZExt: return zeroExtend(ResultBitWidth); case Instruction::BitCast: return *this; case Instruction::FPToUI: case Instruction::FPToSI: if (getBitWidth() == ResultBitWidth) return *this; else return getFull(ResultBitWidth); case Instruction::UIToFP: { // TODO: use input range if available auto BW = getBitWidth(); APInt Min = APInt::getMinValue(BW); APInt Max = APInt::getMaxValue(BW); if (ResultBitWidth > BW) { Min = Min.zext(ResultBitWidth); Max = Max.zext(ResultBitWidth); } return ConstantRange(std::move(Min), std::move(Max)); } case Instruction::SIToFP: { // TODO: use input range if available auto BW = getBitWidth(); APInt SMin = APInt::getSignedMinValue(BW); APInt SMax = APInt::getSignedMaxValue(BW); if (ResultBitWidth > BW) { SMin = SMin.sext(ResultBitWidth); SMax = SMax.sext(ResultBitWidth); } return ConstantRange(std::move(SMin), std::move(SMax)); } case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::IntToPtr: case Instruction::PtrToInt: case Instruction::AddrSpaceCast: // Conservatively return getFull set. return getFull(ResultBitWidth); }; } ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const { if (isEmptySet()) return getEmpty(DstTySize); unsigned SrcTySize = getBitWidth(); assert(SrcTySize < DstTySize && "Not a value extension"); if (isFullSet() || isUpperWrapped()) { // Change into [0, 1 << src bit width) APInt LowerExt(DstTySize, 0); if (!Upper) // special case: [X, 0) -- not really wrapping around LowerExt = Lower.zext(DstTySize); return ConstantRange(std::move(LowerExt), APInt::getOneBitSet(DstTySize, SrcTySize)); } return ConstantRange(Lower.zext(DstTySize), Upper.zext(DstTySize)); } ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const { if (isEmptySet()) return getEmpty(DstTySize); unsigned SrcTySize = getBitWidth(); assert(SrcTySize < DstTySize && "Not a value extension"); // special case: [X, INT_MIN) -- not really wrapping around if (Upper.isMinSignedValue()) return ConstantRange(Lower.sext(DstTySize), Upper.zext(DstTySize)); if (isFullSet() || isSignWrappedSet()) { return ConstantRange(APInt::getHighBitsSet(DstTySize,DstTySize-SrcTySize+1), APInt::getLowBitsSet(DstTySize, SrcTySize-1) + 1); } return ConstantRange(Lower.sext(DstTySize), Upper.sext(DstTySize)); } ConstantRange ConstantRange::truncate(uint32_t DstTySize) const { assert(getBitWidth() > DstTySize && "Not a value truncation"); if (isEmptySet()) return getEmpty(DstTySize); if (isFullSet()) return getFull(DstTySize); APInt LowerDiv(Lower), UpperDiv(Upper); ConstantRange Union(DstTySize, /*isFullSet=*/false); // Analyze wrapped sets in their two parts: [0, Upper) \/ [Lower, MaxValue] // We use the non-wrapped set code to analyze the [Lower, MaxValue) part, and // then we do the union with [MaxValue, Upper) if (isUpperWrapped()) { // If Upper is greater than or equal to MaxValue(DstTy), it covers the whole // truncated range. if (Upper.getActiveBits() > DstTySize || Upper.countr_one() == DstTySize) return getFull(DstTySize); Union = ConstantRange(APInt::getMaxValue(DstTySize),Upper.trunc(DstTySize)); UpperDiv.setAllBits(); // Union covers the MaxValue case, so return if the remaining range is just // MaxValue(DstTy). if (LowerDiv == UpperDiv) return Union; } // Chop off the most significant bits that are past the destination bitwidth. if (LowerDiv.getActiveBits() > DstTySize) { // Mask to just the signficant bits and subtract from LowerDiv/UpperDiv. APInt Adjust = LowerDiv & APInt::getBitsSetFrom(getBitWidth(), DstTySize); LowerDiv -= Adjust; UpperDiv -= Adjust; } unsigned UpperDivWidth = UpperDiv.getActiveBits(); if (UpperDivWidth <= DstTySize) return ConstantRange(LowerDiv.trunc(DstTySize), UpperDiv.trunc(DstTySize)).unionWith(Union); // The truncated value wraps around. Check if we can do better than fullset. if (UpperDivWidth == DstTySize + 1) { // Clear the MSB so that UpperDiv wraps around. UpperDiv.clearBit(DstTySize); if (UpperDiv.ult(LowerDiv)) return ConstantRange(LowerDiv.trunc(DstTySize), UpperDiv.trunc(DstTySize)).unionWith(Union); } return getFull(DstTySize); } ConstantRange ConstantRange::zextOrTrunc(uint32_t DstTySize) const { unsigned SrcTySize = getBitWidth(); if (SrcTySize > DstTySize) return truncate(DstTySize); if (SrcTySize < DstTySize) return zeroExtend(DstTySize); return *this; } ConstantRange ConstantRange::sextOrTrunc(uint32_t DstTySize) const { unsigned SrcTySize = getBitWidth(); if (SrcTySize > DstTySize) return truncate(DstTySize); if (SrcTySize < DstTySize) return signExtend(DstTySize); return *this; } ConstantRange ConstantRange::binaryOp(Instruction::BinaryOps BinOp, const ConstantRange &Other) const { assert(Instruction::isBinaryOp(BinOp) && "Binary operators only!"); switch (BinOp) { case Instruction::Add: return add(Other); case Instruction::Sub: return sub(Other); case Instruction::Mul: return multiply(Other); case Instruction::UDiv: return udiv(Other); case Instruction::SDiv: return sdiv(Other); case Instruction::URem: return urem(Other); case Instruction::SRem: return srem(Other); case Instruction::Shl: return shl(Other); case Instruction::LShr: return lshr(Other); case Instruction::AShr: return ashr(Other); case Instruction::And: return binaryAnd(Other); case Instruction::Or: return binaryOr(Other); case Instruction::Xor: return binaryXor(Other); // Note: floating point operations applied to abstract ranges are just // ideal integer operations with a lossy representation case Instruction::FAdd: return add(Other); case Instruction::FSub: return sub(Other); case Instruction::FMul: return multiply(Other); default: // Conservatively return getFull set. return getFull(); } } ConstantRange ConstantRange::overflowingBinaryOp(Instruction::BinaryOps BinOp, const ConstantRange &Other, unsigned NoWrapKind) const { assert(Instruction::isBinaryOp(BinOp) && "Binary operators only!"); switch (BinOp) { case Instruction::Add: return addWithNoWrap(Other, NoWrapKind); case Instruction::Sub: return subWithNoWrap(Other, NoWrapKind); default: // Don't know about this Overflowing Binary Operation. // Conservatively fallback to plain binop handling. return binaryOp(BinOp, Other); } } bool ConstantRange::isIntrinsicSupported(Intrinsic::ID IntrinsicID) { switch (IntrinsicID) { case Intrinsic::uadd_sat: case Intrinsic::usub_sat: case Intrinsic::sadd_sat: case Intrinsic::ssub_sat: case Intrinsic::umin: case Intrinsic::umax: case Intrinsic::smin: case Intrinsic::smax: case Intrinsic::abs: case Intrinsic::ctlz: return true; default: return false; } } ConstantRange ConstantRange::intrinsic(Intrinsic::ID IntrinsicID, ArrayRef Ops) { switch (IntrinsicID) { case Intrinsic::uadd_sat: return Ops[0].uadd_sat(Ops[1]); case Intrinsic::usub_sat: return Ops[0].usub_sat(Ops[1]); case Intrinsic::sadd_sat: return Ops[0].sadd_sat(Ops[1]); case Intrinsic::ssub_sat: return Ops[0].ssub_sat(Ops[1]); case Intrinsic::umin: return Ops[0].umin(Ops[1]); case Intrinsic::umax: return Ops[0].umax(Ops[1]); case Intrinsic::smin: return Ops[0].smin(Ops[1]); case Intrinsic::smax: return Ops[0].smax(Ops[1]); case Intrinsic::abs: { const APInt *IntMinIsPoison = Ops[1].getSingleElement(); assert(IntMinIsPoison && "Must be known (immarg)"); assert(IntMinIsPoison->getBitWidth() == 1 && "Must be boolean"); return Ops[0].abs(IntMinIsPoison->getBoolValue()); } case Intrinsic::ctlz: { const APInt *ZeroIsPoison = Ops[1].getSingleElement(); assert(ZeroIsPoison && "Must be known (immarg)"); assert(ZeroIsPoison->getBitWidth() == 1 && "Must be boolean"); return Ops[0].ctlz(ZeroIsPoison->getBoolValue()); } default: assert(!isIntrinsicSupported(IntrinsicID) && "Shouldn't be supported"); llvm_unreachable("Unsupported intrinsic"); } } ConstantRange ConstantRange::add(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); if (isFullSet() || Other.isFullSet()) return getFull(); APInt NewLower = getLower() + Other.getLower(); APInt NewUpper = getUpper() + Other.getUpper() - 1; if (NewLower == NewUpper) return getFull(); ConstantRange X = ConstantRange(std::move(NewLower), std::move(NewUpper)); if (X.isSizeStrictlySmallerThan(*this) || X.isSizeStrictlySmallerThan(Other)) // We've wrapped, therefore, full set. return getFull(); return X; } ConstantRange ConstantRange::addWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind, PreferredRangeType RangeType) const { // Calculate the range for "X + Y" which is guaranteed not to wrap(overflow). // (X is from this, and Y is from Other) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); if (isFullSet() && Other.isFullSet()) return getFull(); using OBO = OverflowingBinaryOperator; ConstantRange Result = add(Other); // If an overflow happens for every value pair in these two constant ranges, // we must return Empty set. In this case, we get that for free, because we // get lucky that intersection of add() with uadd_sat()/sadd_sat() results // in an empty set. if (NoWrapKind & OBO::NoSignedWrap) Result = Result.intersectWith(sadd_sat(Other), RangeType); if (NoWrapKind & OBO::NoUnsignedWrap) Result = Result.intersectWith(uadd_sat(Other), RangeType); return Result; } ConstantRange ConstantRange::sub(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); if (isFullSet() || Other.isFullSet()) return getFull(); APInt NewLower = getLower() - Other.getUpper() + 1; APInt NewUpper = getUpper() - Other.getLower(); if (NewLower == NewUpper) return getFull(); ConstantRange X = ConstantRange(std::move(NewLower), std::move(NewUpper)); if (X.isSizeStrictlySmallerThan(*this) || X.isSizeStrictlySmallerThan(Other)) // We've wrapped, therefore, full set. return getFull(); return X; } ConstantRange ConstantRange::subWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind, PreferredRangeType RangeType) const { // Calculate the range for "X - Y" which is guaranteed not to wrap(overflow). // (X is from this, and Y is from Other) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); if (isFullSet() && Other.isFullSet()) return getFull(); using OBO = OverflowingBinaryOperator; ConstantRange Result = sub(Other); // If an overflow happens for every value pair in these two constant ranges, // we must return Empty set. In signed case, we get that for free, because we // get lucky that intersection of sub() with ssub_sat() results in an // empty set. But for unsigned we must perform the overflow check manually. if (NoWrapKind & OBO::NoSignedWrap) Result = Result.intersectWith(ssub_sat(Other), RangeType); if (NoWrapKind & OBO::NoUnsignedWrap) { if (getUnsignedMax().ult(Other.getUnsignedMin())) return getEmpty(); // Always overflows. Result = Result.intersectWith(usub_sat(Other), RangeType); } return Result; } ConstantRange ConstantRange::multiply(const ConstantRange &Other) const { // TODO: If either operand is a single element and the multiply is known to // be non-wrapping, round the result min and max value to the appropriate // multiple of that element. If wrapping is possible, at least adjust the // range according to the greatest power-of-two factor of the single element. if (isEmptySet() || Other.isEmptySet()) return getEmpty(); // Multiplication is signedness-independent. However different ranges can be // obtained depending on how the input ranges are treated. These different // ranges are all conservatively correct, but one might be better than the // other. We calculate two ranges; one treating the inputs as unsigned // and the other signed, then return the smallest of these ranges. // Unsigned range first. APInt this_min = getUnsignedMin().zext(getBitWidth() * 2); APInt this_max = getUnsignedMax().zext(getBitWidth() * 2); APInt Other_min = Other.getUnsignedMin().zext(getBitWidth() * 2); APInt Other_max = Other.getUnsignedMax().zext(getBitWidth() * 2); ConstantRange Result_zext = ConstantRange(this_min * Other_min, this_max * Other_max + 1); ConstantRange UR = Result_zext.truncate(getBitWidth()); // If the unsigned range doesn't wrap, and isn't negative then it's a range // from one positive number to another which is as good as we can generate. // In this case, skip the extra work of generating signed ranges which aren't // going to be better than this range. if (!UR.isUpperWrapped() && (UR.getUpper().isNonNegative() || UR.getUpper().isMinSignedValue())) return UR; // Now the signed range. Because we could be dealing with negative numbers // here, the lower bound is the smallest of the cartesian product of the // lower and upper ranges; for example: // [-1,4) * [-2,3) = min(-1*-2, -1*2, 3*-2, 3*2) = -6. // Similarly for the upper bound, swapping min for max. this_min = getSignedMin().sext(getBitWidth() * 2); this_max = getSignedMax().sext(getBitWidth() * 2); Other_min = Other.getSignedMin().sext(getBitWidth() * 2); Other_max = Other.getSignedMax().sext(getBitWidth() * 2); auto L = {this_min * Other_min, this_min * Other_max, this_max * Other_min, this_max * Other_max}; auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); }; ConstantRange Result_sext(std::min(L, Compare), std::max(L, Compare) + 1); ConstantRange SR = Result_sext.truncate(getBitWidth()); return UR.isSizeStrictlySmallerThan(SR) ? UR : SR; } ConstantRange ConstantRange::smul_fast(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt Min = getSignedMin(); APInt Max = getSignedMax(); APInt OtherMin = Other.getSignedMin(); APInt OtherMax = Other.getSignedMax(); bool O1, O2, O3, O4; auto Muls = {Min.smul_ov(OtherMin, O1), Min.smul_ov(OtherMax, O2), Max.smul_ov(OtherMin, O3), Max.smul_ov(OtherMax, O4)}; if (O1 || O2 || O3 || O4) return getFull(); auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); }; return getNonEmpty(std::min(Muls, Compare), std::max(Muls, Compare) + 1); } ConstantRange ConstantRange::smax(const ConstantRange &Other) const { // X smax Y is: range(smax(X_smin, Y_smin), // smax(X_smax, Y_smax)) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = APIntOps::smax(getSignedMin(), Other.getSignedMin()); APInt NewU = APIntOps::smax(getSignedMax(), Other.getSignedMax()) + 1; ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU)); if (isSignWrappedSet() || Other.isSignWrappedSet()) return Res.intersectWith(unionWith(Other, Signed), Signed); return Res; } ConstantRange ConstantRange::umax(const ConstantRange &Other) const { // X umax Y is: range(umax(X_umin, Y_umin), // umax(X_umax, Y_umax)) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()); APInt NewU = APIntOps::umax(getUnsignedMax(), Other.getUnsignedMax()) + 1; ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU)); if (isWrappedSet() || Other.isWrappedSet()) return Res.intersectWith(unionWith(Other, Unsigned), Unsigned); return Res; } ConstantRange ConstantRange::smin(const ConstantRange &Other) const { // X smin Y is: range(smin(X_smin, Y_smin), // smin(X_smax, Y_smax)) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = APIntOps::smin(getSignedMin(), Other.getSignedMin()); APInt NewU = APIntOps::smin(getSignedMax(), Other.getSignedMax()) + 1; ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU)); if (isSignWrappedSet() || Other.isSignWrappedSet()) return Res.intersectWith(unionWith(Other, Signed), Signed); return Res; } ConstantRange ConstantRange::umin(const ConstantRange &Other) const { // X umin Y is: range(umin(X_umin, Y_umin), // umin(X_umax, Y_umax)) if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = APIntOps::umin(getUnsignedMin(), Other.getUnsignedMin()); APInt NewU = APIntOps::umin(getUnsignedMax(), Other.getUnsignedMax()) + 1; ConstantRange Res = getNonEmpty(std::move(NewL), std::move(NewU)); if (isWrappedSet() || Other.isWrappedSet()) return Res.intersectWith(unionWith(Other, Unsigned), Unsigned); return Res; } ConstantRange ConstantRange::udiv(const ConstantRange &RHS) const { if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax().isZero()) return getEmpty(); APInt Lower = getUnsignedMin().udiv(RHS.getUnsignedMax()); APInt RHS_umin = RHS.getUnsignedMin(); if (RHS_umin.isZero()) { // We want the lowest value in RHS excluding zero. Usually that would be 1 // except for a range in the form of [X, 1) in which case it would be X. if (RHS.getUpper() == 1) RHS_umin = RHS.getLower(); else RHS_umin = 1; } APInt Upper = getUnsignedMax().udiv(RHS_umin) + 1; return getNonEmpty(std::move(Lower), std::move(Upper)); } ConstantRange ConstantRange::sdiv(const ConstantRange &RHS) const { // We split up the LHS and RHS into positive and negative components // and then also compute the positive and negative components of the result // separately by combining division results with the appropriate signs. APInt Zero = APInt::getZero(getBitWidth()); APInt SignedMin = APInt::getSignedMinValue(getBitWidth()); // There are no positive 1-bit values. The 1 would get interpreted as -1. ConstantRange PosFilter = getBitWidth() == 1 ? getEmpty() : ConstantRange(APInt(getBitWidth(), 1), SignedMin); ConstantRange NegFilter(SignedMin, Zero); ConstantRange PosL = intersectWith(PosFilter); ConstantRange NegL = intersectWith(NegFilter); ConstantRange PosR = RHS.intersectWith(PosFilter); ConstantRange NegR = RHS.intersectWith(NegFilter); ConstantRange PosRes = getEmpty(); if (!PosL.isEmptySet() && !PosR.isEmptySet()) // pos / pos = pos. PosRes = ConstantRange(PosL.Lower.sdiv(PosR.Upper - 1), (PosL.Upper - 1).sdiv(PosR.Lower) + 1); if (!NegL.isEmptySet() && !NegR.isEmptySet()) { // neg / neg = pos. // // We need to deal with one tricky case here: SignedMin / -1 is UB on the // IR level, so we'll want to exclude this case when calculating bounds. // (For APInts the operation is well-defined and yields SignedMin.) We // handle this by dropping either SignedMin from the LHS or -1 from the RHS. APInt Lo = (NegL.Upper - 1).sdiv(NegR.Lower); if (NegL.Lower.isMinSignedValue() && NegR.Upper.isZero()) { // Remove -1 from the LHS. Skip if it's the only element, as this would // leave us with an empty set. if (!NegR.Lower.isAllOnes()) { APInt AdjNegRUpper; if (RHS.Lower.isAllOnes()) // Negative part of [-1, X] without -1 is [SignedMin, X]. AdjNegRUpper = RHS.Upper; else // [X, -1] without -1 is [X, -2]. AdjNegRUpper = NegR.Upper - 1; PosRes = PosRes.unionWith( ConstantRange(Lo, NegL.Lower.sdiv(AdjNegRUpper - 1) + 1)); } // Remove SignedMin from the RHS. Skip if it's the only element, as this // would leave us with an empty set. if (NegL.Upper != SignedMin + 1) { APInt AdjNegLLower; if (Upper == SignedMin + 1) // Negative part of [X, SignedMin] without SignedMin is [X, -1]. AdjNegLLower = Lower; else // [SignedMin, X] without SignedMin is [SignedMin + 1, X]. AdjNegLLower = NegL.Lower + 1; PosRes = PosRes.unionWith( ConstantRange(std::move(Lo), AdjNegLLower.sdiv(NegR.Upper - 1) + 1)); } } else { PosRes = PosRes.unionWith( ConstantRange(std::move(Lo), NegL.Lower.sdiv(NegR.Upper - 1) + 1)); } } ConstantRange NegRes = getEmpty(); if (!PosL.isEmptySet() && !NegR.isEmptySet()) // pos / neg = neg. NegRes = ConstantRange((PosL.Upper - 1).sdiv(NegR.Upper - 1), PosL.Lower.sdiv(NegR.Lower) + 1); if (!NegL.isEmptySet() && !PosR.isEmptySet()) // neg / pos = neg. NegRes = NegRes.unionWith( ConstantRange(NegL.Lower.sdiv(PosR.Lower), (NegL.Upper - 1).sdiv(PosR.Upper - 1) + 1)); // Prefer a non-wrapping signed range here. ConstantRange Res = NegRes.unionWith(PosRes, PreferredRangeType::Signed); // Preserve the zero that we dropped when splitting the LHS by sign. if (contains(Zero) && (!PosR.isEmptySet() || !NegR.isEmptySet())) Res = Res.unionWith(ConstantRange(Zero)); return Res; } ConstantRange ConstantRange::urem(const ConstantRange &RHS) const { if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax().isZero()) return getEmpty(); if (const APInt *RHSInt = RHS.getSingleElement()) { // UREM by null is UB. if (RHSInt->isZero()) return getEmpty(); // Use APInt's implementation of UREM for single element ranges. if (const APInt *LHSInt = getSingleElement()) return {LHSInt->urem(*RHSInt)}; } // L % R for L < R is L. if (getUnsignedMax().ult(RHS.getUnsignedMin())) return *this; // L % R is <= L and < R. APInt Upper = APIntOps::umin(getUnsignedMax(), RHS.getUnsignedMax() - 1) + 1; return getNonEmpty(APInt::getZero(getBitWidth()), std::move(Upper)); } ConstantRange ConstantRange::srem(const ConstantRange &RHS) const { if (isEmptySet() || RHS.isEmptySet()) return getEmpty(); if (const APInt *RHSInt = RHS.getSingleElement()) { // SREM by null is UB. if (RHSInt->isZero()) return getEmpty(); // Use APInt's implementation of SREM for single element ranges. if (const APInt *LHSInt = getSingleElement()) return {LHSInt->srem(*RHSInt)}; } ConstantRange AbsRHS = RHS.abs(); APInt MinAbsRHS = AbsRHS.getUnsignedMin(); APInt MaxAbsRHS = AbsRHS.getUnsignedMax(); // Modulus by zero is UB. if (MaxAbsRHS.isZero()) return getEmpty(); if (MinAbsRHS.isZero()) ++MinAbsRHS; APInt MinLHS = getSignedMin(), MaxLHS = getSignedMax(); if (MinLHS.isNonNegative()) { // L % R for L < R is L. if (MaxLHS.ult(MinAbsRHS)) return *this; // L % R is <= L and < R. APInt Upper = APIntOps::umin(MaxLHS, MaxAbsRHS - 1) + 1; return ConstantRange(APInt::getZero(getBitWidth()), std::move(Upper)); } // Same basic logic as above, but the result is negative. if (MaxLHS.isNegative()) { if (MinLHS.ugt(-MinAbsRHS)) return *this; APInt Lower = APIntOps::umax(MinLHS, -MaxAbsRHS + 1); return ConstantRange(std::move(Lower), APInt(getBitWidth(), 1)); } // LHS range crosses zero. APInt Lower = APIntOps::umax(MinLHS, -MaxAbsRHS + 1); APInt Upper = APIntOps::umin(MaxLHS, MaxAbsRHS - 1) + 1; return ConstantRange(std::move(Lower), std::move(Upper)); } ConstantRange ConstantRange::binaryNot() const { return ConstantRange(APInt::getAllOnes(getBitWidth())).sub(*this); } ConstantRange ConstantRange::binaryAnd(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); ConstantRange KnownBitsRange = fromKnownBits(toKnownBits() & Other.toKnownBits(), false); ConstantRange UMinUMaxRange = getNonEmpty(APInt::getZero(getBitWidth()), APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()) + 1); return KnownBitsRange.intersectWith(UMinUMaxRange); } ConstantRange ConstantRange::binaryOr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); ConstantRange KnownBitsRange = fromKnownBits(toKnownBits() | Other.toKnownBits(), false); // Upper wrapped range. ConstantRange UMaxUMinRange = getNonEmpty(APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()), APInt::getZero(getBitWidth())); return KnownBitsRange.intersectWith(UMaxUMinRange); } ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); // Use APInt's implementation of XOR for single element ranges. if (isSingleElement() && Other.isSingleElement()) return {*getSingleElement() ^ *Other.getSingleElement()}; // Special-case binary complement, since we can give a precise answer. if (Other.isSingleElement() && Other.getSingleElement()->isAllOnes()) return binaryNot(); if (isSingleElement() && getSingleElement()->isAllOnes()) return Other.binaryNot(); return fromKnownBits(toKnownBits() ^ Other.toKnownBits(), /*IsSigned*/false); } ConstantRange ConstantRange::shl(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt Min = getUnsignedMin(); APInt Max = getUnsignedMax(); if (const APInt *RHS = Other.getSingleElement()) { unsigned BW = getBitWidth(); if (RHS->uge(BW)) return getEmpty(); unsigned EqualLeadingBits = (Min ^ Max).countl_zero(); if (RHS->ule(EqualLeadingBits)) return getNonEmpty(Min << *RHS, (Max << *RHS) + 1); return getNonEmpty(APInt::getZero(BW), APInt::getBitsSetFrom(BW, RHS->getZExtValue()) + 1); } APInt OtherMax = Other.getUnsignedMax(); // There's overflow! if (OtherMax.ugt(Max.countl_zero())) return getFull(); // FIXME: implement the other tricky cases Min <<= Other.getUnsignedMin(); Max <<= OtherMax; return ConstantRange::getNonEmpty(std::move(Min), std::move(Max) + 1); } ConstantRange ConstantRange::lshr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt max = getUnsignedMax().lshr(Other.getUnsignedMin()) + 1; APInt min = getUnsignedMin().lshr(Other.getUnsignedMax()); return getNonEmpty(std::move(min), std::move(max)); } ConstantRange ConstantRange::ashr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); // May straddle zero, so handle both positive and negative cases. // 'PosMax' is the upper bound of the result of the ashr // operation, when Upper of the LHS of ashr is a non-negative. // number. Since ashr of a non-negative number will result in a // smaller number, the Upper value of LHS is shifted right with // the minimum value of 'Other' instead of the maximum value. APInt PosMax = getSignedMax().ashr(Other.getUnsignedMin()) + 1; // 'PosMin' is the lower bound of the result of the ashr // operation, when Lower of the LHS is a non-negative number. // Since ashr of a non-negative number will result in a smaller // number, the Lower value of LHS is shifted right with the // maximum value of 'Other'. APInt PosMin = getSignedMin().ashr(Other.getUnsignedMax()); // 'NegMax' is the upper bound of the result of the ashr // operation, when Upper of the LHS of ashr is a negative number. // Since 'ashr' of a negative number will result in a bigger // number, the Upper value of LHS is shifted right with the // maximum value of 'Other'. APInt NegMax = getSignedMax().ashr(Other.getUnsignedMax()) + 1; // 'NegMin' is the lower bound of the result of the ashr // operation, when Lower of the LHS of ashr is a negative number. // Since 'ashr' of a negative number will result in a bigger // number, the Lower value of LHS is shifted right with the // minimum value of 'Other'. APInt NegMin = getSignedMin().ashr(Other.getUnsignedMin()); APInt max, min; if (getSignedMin().isNonNegative()) { // Upper and Lower of LHS are non-negative. min = PosMin; max = PosMax; } else if (getSignedMax().isNegative()) { // Upper and Lower of LHS are negative. min = NegMin; max = NegMax; } else { // Upper is non-negative and Lower is negative. min = NegMin; max = PosMax; } return getNonEmpty(std::move(min), std::move(max)); } ConstantRange ConstantRange::uadd_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getUnsignedMin().uadd_sat(Other.getUnsignedMin()); APInt NewU = getUnsignedMax().uadd_sat(Other.getUnsignedMax()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::sadd_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getSignedMin().sadd_sat(Other.getSignedMin()); APInt NewU = getSignedMax().sadd_sat(Other.getSignedMax()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::usub_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getUnsignedMin().usub_sat(Other.getUnsignedMax()); APInt NewU = getUnsignedMax().usub_sat(Other.getUnsignedMin()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::ssub_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getSignedMin().ssub_sat(Other.getSignedMax()); APInt NewU = getSignedMax().ssub_sat(Other.getSignedMin()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::umul_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getUnsignedMin().umul_sat(Other.getUnsignedMin()); APInt NewU = getUnsignedMax().umul_sat(Other.getUnsignedMax()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::smul_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); // Because we could be dealing with negative numbers here, the lower bound is // the smallest of the cartesian product of the lower and upper ranges; // for example: // [-1,4) * [-2,3) = min(-1*-2, -1*2, 3*-2, 3*2) = -6. // Similarly for the upper bound, swapping min for max. APInt Min = getSignedMin(); APInt Max = getSignedMax(); APInt OtherMin = Other.getSignedMin(); APInt OtherMax = Other.getSignedMax(); auto L = {Min.smul_sat(OtherMin), Min.smul_sat(OtherMax), Max.smul_sat(OtherMin), Max.smul_sat(OtherMax)}; auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); }; return getNonEmpty(std::min(L, Compare), std::max(L, Compare) + 1); } ConstantRange ConstantRange::ushl_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt NewL = getUnsignedMin().ushl_sat(Other.getUnsignedMin()); APInt NewU = getUnsignedMax().ushl_sat(Other.getUnsignedMax()) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::sshl_sat(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); APInt Min = getSignedMin(), Max = getSignedMax(); APInt ShAmtMin = Other.getUnsignedMin(), ShAmtMax = Other.getUnsignedMax(); APInt NewL = Min.sshl_sat(Min.isNonNegative() ? ShAmtMin : ShAmtMax); APInt NewU = Max.sshl_sat(Max.isNegative() ? ShAmtMin : ShAmtMax) + 1; return getNonEmpty(std::move(NewL), std::move(NewU)); } ConstantRange ConstantRange::inverse() const { if (isFullSet()) return getEmpty(); if (isEmptySet()) return getFull(); return ConstantRange(Upper, Lower); } ConstantRange ConstantRange::abs(bool IntMinIsPoison) const { if (isEmptySet()) return getEmpty(); if (isSignWrappedSet()) { APInt Lo; // Check whether the range crosses zero. if (Upper.isStrictlyPositive() || !Lower.isStrictlyPositive()) Lo = APInt::getZero(getBitWidth()); else Lo = APIntOps::umin(Lower, -Upper + 1); // If SignedMin is not poison, then it is included in the result range. if (IntMinIsPoison) return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth())); else return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); } APInt SMin = getSignedMin(), SMax = getSignedMax(); // Skip SignedMin if it is poison. if (IntMinIsPoison && SMin.isMinSignedValue()) { // The range may become empty if it *only* contains SignedMin. if (SMax.isMinSignedValue()) return getEmpty(); ++SMin; } // All non-negative. if (SMin.isNonNegative()) return ConstantRange(SMin, SMax + 1); // All negative. if (SMax.isNegative()) return ConstantRange(-SMax, -SMin + 1); // Range crosses zero. return ConstantRange::getNonEmpty(APInt::getZero(getBitWidth()), APIntOps::umax(-SMin, SMax) + 1); } ConstantRange ConstantRange::ctlz(bool ZeroIsPoison) const { if (isEmptySet()) return getEmpty(); APInt Zero = APInt::getZero(getBitWidth()); if (ZeroIsPoison && contains(Zero)) { // ZeroIsPoison is set, and zero is contained. We discern three cases, in // which a zero can appear: // 1) Lower is zero, handling cases of kind [0, 1), [0, 2), etc. // 2) Upper is zero, wrapped set, handling cases of kind [3, 0], etc. // 3) Zero contained in a wrapped set, e.g., [3, 2), [3, 1), etc. if (getLower().isZero()) { if ((getUpper() - 1).isZero()) { // We have in input interval of kind [0, 1). In this case we cannot // really help but return empty-set. return getEmpty(); } // Compute the resulting range by excluding zero from Lower. return ConstantRange( APInt(getBitWidth(), (getUpper() - 1).countl_zero()), APInt(getBitWidth(), (getLower() + 1).countl_zero() + 1)); } else if ((getUpper() - 1).isZero()) { // Compute the resulting range by excluding zero from Upper. return ConstantRange(Zero, APInt(getBitWidth(), getLower().countl_zero() + 1)); } else { return ConstantRange(Zero, APInt(getBitWidth(), getBitWidth())); } } // Zero is either safe or not in the range. The output range is composed by // the result of countLeadingZero of the two extremes. return getNonEmpty(APInt(getBitWidth(), getUnsignedMax().countl_zero()), APInt(getBitWidth(), getUnsignedMin().countl_zero() + 1)); } ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return OverflowResult::MayOverflow; APInt Min = getUnsignedMin(), Max = getUnsignedMax(); APInt OtherMin = Other.getUnsignedMin(), OtherMax = Other.getUnsignedMax(); // a u+ b overflows high iff a u> ~b. if (Min.ugt(~OtherMin)) return OverflowResult::AlwaysOverflowsHigh; if (Max.ugt(~OtherMax)) return OverflowResult::MayOverflow; return OverflowResult::NeverOverflows; } ConstantRange::OverflowResult ConstantRange::signedAddMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return OverflowResult::MayOverflow; APInt Min = getSignedMin(), Max = getSignedMax(); APInt OtherMin = Other.getSignedMin(), OtherMax = Other.getSignedMax(); APInt SignedMin = APInt::getSignedMinValue(getBitWidth()); APInt SignedMax = APInt::getSignedMaxValue(getBitWidth()); // a s+ b overflows high iff a s>=0 && b s>= 0 && a s> smax - b. // a s+ b overflows low iff a s< 0 && b s< 0 && a s< smin - b. if (Min.isNonNegative() && OtherMin.isNonNegative() && Min.sgt(SignedMax - OtherMin)) return OverflowResult::AlwaysOverflowsHigh; if (Max.isNegative() && OtherMax.isNegative() && Max.slt(SignedMin - OtherMax)) return OverflowResult::AlwaysOverflowsLow; if (Max.isNonNegative() && OtherMax.isNonNegative() && Max.sgt(SignedMax - OtherMax)) return OverflowResult::MayOverflow; if (Min.isNegative() && OtherMin.isNegative() && Min.slt(SignedMin - OtherMin)) return OverflowResult::MayOverflow; return OverflowResult::NeverOverflows; } ConstantRange::OverflowResult ConstantRange::unsignedSubMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return OverflowResult::MayOverflow; APInt Min = getUnsignedMin(), Max = getUnsignedMax(); APInt OtherMin = Other.getUnsignedMin(), OtherMax = Other.getUnsignedMax(); // a u- b overflows low iff a u< b. if (Max.ult(OtherMin)) return OverflowResult::AlwaysOverflowsLow; if (Min.ult(OtherMax)) return OverflowResult::MayOverflow; return OverflowResult::NeverOverflows; } ConstantRange::OverflowResult ConstantRange::signedSubMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return OverflowResult::MayOverflow; APInt Min = getSignedMin(), Max = getSignedMax(); APInt OtherMin = Other.getSignedMin(), OtherMax = Other.getSignedMax(); APInt SignedMin = APInt::getSignedMinValue(getBitWidth()); APInt SignedMax = APInt::getSignedMaxValue(getBitWidth()); // a s- b overflows high iff a s>=0 && b s< 0 && a s> smax + b. // a s- b overflows low iff a s< 0 && b s>= 0 && a s< smin + b. if (Min.isNonNegative() && OtherMax.isNegative() && Min.sgt(SignedMax + OtherMax)) return OverflowResult::AlwaysOverflowsHigh; if (Max.isNegative() && OtherMin.isNonNegative() && Max.slt(SignedMin + OtherMin)) return OverflowResult::AlwaysOverflowsLow; if (Max.isNonNegative() && OtherMin.isNegative() && Max.sgt(SignedMax + OtherMin)) return OverflowResult::MayOverflow; if (Min.isNegative() && OtherMax.isNonNegative() && Min.slt(SignedMin + OtherMax)) return OverflowResult::MayOverflow; return OverflowResult::NeverOverflows; } ConstantRange::OverflowResult ConstantRange::unsignedMulMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return OverflowResult::MayOverflow; APInt Min = getUnsignedMin(), Max = getUnsignedMax(); APInt OtherMin = Other.getUnsignedMin(), OtherMax = Other.getUnsignedMax(); bool Overflow; (void) Min.umul_ov(OtherMin, Overflow); if (Overflow) return OverflowResult::AlwaysOverflowsHigh; (void) Max.umul_ov(OtherMax, Overflow); if (Overflow) return OverflowResult::MayOverflow; return OverflowResult::NeverOverflows; } void ConstantRange::print(raw_ostream &OS) const { if (isFullSet()) OS << "full-set"; else if (isEmptySet()) OS << "empty-set"; else OS << "[" << Lower << "," << Upper << ")"; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void ConstantRange::dump() const { print(dbgs()); } #endif ConstantRange llvm::getConstantRangeFromMetadata(const MDNode &Ranges) { const unsigned NumRanges = Ranges.getNumOperands() / 2; assert(NumRanges >= 1 && "Must have at least one range!"); assert(Ranges.getNumOperands() % 2 == 0 && "Must be a sequence of pairs"); auto *FirstLow = mdconst::extract(Ranges.getOperand(0)); auto *FirstHigh = mdconst::extract(Ranges.getOperand(1)); ConstantRange CR(FirstLow->getValue(), FirstHigh->getValue()); for (unsigned i = 1; i < NumRanges; ++i) { auto *Low = mdconst::extract(Ranges.getOperand(2 * i + 0)); auto *High = mdconst::extract(Ranges.getOperand(2 * i + 1)); // Note: unionWith will potentially create a range that contains values not // contained in any of the original N ranges. CR = CR.unionWith(ConstantRange(Low->getValue(), High->getValue())); } return CR; }