Index: include/llvm/IR/ConstantRange.h =================================================================== --- include/llvm/IR/ConstantRange.h +++ include/llvm/IR/ConstantRange.h @@ -214,6 +214,12 @@ /// in either set before. ConstantRange unionWith(const ConstantRange &CR) const; + /// Computes the intersection of this range with another range. It is + /// different from intersectWith in that the ConstantRange returned will only + /// contain elements in both CR0 and CR1 (i.e. subsetIntersectWith(X, Y) is a + /// *subset*, proper or not, of both X and Y). + ConstantRange subsetIntersectWith(const ConstantRange &CR) const; + /// Return a new range representing the possible values resulting /// from an application of the specified cast operator to this range. \p /// BitWidth is the target bitwidth of the cast. For casts which don't Index: lib/IR/ConstantRange.cpp =================================================================== --- lib/IR/ConstantRange.cpp +++ lib/IR/ConstantRange.cpp @@ -172,15 +172,6 @@ unsigned NoWrapKind) { typedef OverflowingBinaryOperator OBO; - // Computes the intersection of CR0 and CR1. It is different from - // intersectWith in that the ConstantRange returned will only contain elements - // in both CR0 and CR1 (i.e. SubsetIntersect(X, Y) is a *subset*, proper or - // not, of both X and Y). - auto SubsetIntersect = - [](const ConstantRange &CR0, const ConstantRange &CR1) { - return CR0.inverse().unionWith(CR1.inverse()).inverse(); - }; - assert(BinOp >= Instruction::BinaryOpsBegin && BinOp < Instruction::BinaryOpsEnd && "Binary operators only!"); @@ -192,34 +183,32 @@ unsigned BitWidth = Other.getBitWidth(); if (BinOp != Instruction::Add) // Conservative answer: empty set - return ConstantRange(BitWidth, false); + return ConstantRange(BitWidth, /* empty */ false); if (auto *C = Other.getSingleElement()) if (C->isNullValue()) // Full set: nothing signed / unsigned wraps when added to 0. - return ConstantRange(BitWidth); + return ConstantRange(BitWidth, /* full */ true); ConstantRange Result(BitWidth); if (NoWrapKind & OBO::NoUnsignedWrap) - Result = - SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth), - -Other.getUnsignedMax())); + Result = Result.subsetIntersectWith( + ConstantRange(APInt::getNullValue(BitWidth), -Other.getUnsignedMax())); if (NoWrapKind & OBO::NoSignedWrap) { const APInt &SignedMin = Other.getSignedMin(); const APInt &SignedMax = Other.getSignedMax(); if (SignedMax.isStrictlyPositive()) - Result = SubsetIntersect( - Result, + Result = Result.subsetIntersectWith( ConstantRange(APInt::getSignedMinValue(BitWidth), APInt::getSignedMinValue(BitWidth) - SignedMax)); if (SignedMin.isNegative()) - Result = SubsetIntersect( - Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, - APInt::getSignedMinValue(BitWidth))); + Result = Result.subsetIntersectWith( + ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, + APInt::getSignedMinValue(BitWidth))); } return Result; @@ -492,6 +481,83 @@ return ConstantRange(std::move(L), std::move(U)); } +ConstantRange +ConstantRange::subsetIntersectWith(const ConstantRange &CR) const { + assert(getBitWidth() == CR.getBitWidth() && + "ConstantRange types don't agree!"); + + if (isFullSet() || CR.isEmptySet()) + return CR; + if (CR.isFullSet() || isEmptySet()) + return *this; + + if (!isWrappedSet() && CR.isWrappedSet()) + return CR.subsetIntersectWith(*this); + + if (!isWrappedSet() && !CR.isWrappedSet()) { + // If the ranges are disjoint, return empty set. + if (CR.Upper.ule(Lower) || Upper.ule(CR.Lower)) + return ConstantRange(getBitWidth(), /* empty */ false); + + // Ranges overlap. + APInt L = CR.Lower.ugt(Lower) ? CR.Lower : Lower; + APInt U = (CR.Upper - 1).ult(Upper - 1) ? CR.Upper : Upper; + + assert(L != U); + + return ConstantRange(std::move(L), std::move(U)); + } + + if (!CR.isWrappedSet()) { + // ------U L----- and ------U L----- : this + // L--U L--U : CR + if (CR.Upper.ule(Upper) || CR.Lower.uge(Lower)) + return CR; + + // ------U L----- : this + // L---------U : CR + if (CR.Lower.ule(Upper) && Lower.ule(CR.Upper)) { + // Find the largest range and return it. + APInt d1 = Upper - CR.Lower; APInt d2 = CR.Upper - Lower; + if (d1.uge(d2)) + return ConstantRange(CR.Lower, Upper); + return ConstantRange(Lower, CR.Upper); + } + + // ----U L---- : this + // L---U : CR + // + if (Upper.ule(CR.Lower) && CR.Upper.ule(Lower)) + return ConstantRange(getBitWidth(), /* empty */ false); + + // ----U L----- : this + // L----U : CR + if (Upper.ult(CR.Lower) && Lower.ult(CR.Upper)) + return ConstantRange(Lower, CR.Upper); + + // ------U L---- : this + // L-----U : CR + assert(CR.Lower.ult(Upper) && CR.Upper.ult(Lower) && + "ConstantRange::subsetIntersectWith missed a case with one range " + "wrapped"); + return ConstantRange(CR.Lower, Upper); + } + + // ------U L---- and ------U L---- : this + // -U L----------- and ------------U L : CR + if (CR.Lower.ult(Upper) || Lower.ult(CR.Upper)) { + APInt d1 = Upper - CR.Lower; APInt d2 = CR.Upper - Lower; + if (d1.uge(d2)) + return ConstantRange(CR.Lower, Upper); + return ConstantRange(Lower, CR.Upper); + } + + APInt L = CR.Lower.ugt(Lower) ? CR.Lower : Lower; + APInt U = CR.Upper.ult(Upper) ? CR.Upper: Upper; + + return ConstantRange(std::move(L), std::move(U)); +} + ConstantRange ConstantRange::castOp(Instruction::CastOps CastOp, uint32_t ResultBitWidth) const { switch (CastOp) {