diff options
Diffstat (limited to 'llvm/lib/IR/ConstantRange.cpp')
| -rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index a0f2179bddb4..9d239101d8fd 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -75,6 +75,24 @@ ConstantRange ConstantRange::fromKnownBits(const KnownBits &Known, 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 (Optional<unsigned> 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()) @@ -721,15 +739,23 @@ ConstantRange ConstantRange::castOp(Instruction::CastOps CastOp, case Instruction::UIToFP: { // TODO: use input range if available auto BW = getBitWidth(); - APInt Min = APInt::getMinValue(BW).zextOrSelf(ResultBitWidth); - APInt Max = APInt::getMaxValue(BW).zextOrSelf(ResultBitWidth); + 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).sextOrSelf(ResultBitWidth); - APInt SMax = APInt::getSignedMaxValue(BW).sextOrSelf(ResultBitWidth); + 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: @@ -1212,7 +1238,10 @@ ConstantRange ConstantRange::sdiv(const ConstantRange &RHS) const { // separately by combining division results with the appropriate signs. APInt Zero = APInt::getZero(getBitWidth()); APInt SignedMin = APInt::getSignedMinValue(getBitWidth()); - ConstantRange PosFilter(APInt(getBitWidth(), 1), SignedMin); + // 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); @@ -1368,34 +1397,29 @@ ConstantRange ConstantRange::binaryNot() const { return ConstantRange(APInt::getAllOnes(getBitWidth())).sub(*this); } -ConstantRange -ConstantRange::binaryAnd(const ConstantRange &Other) const { +ConstantRange ConstantRange::binaryAnd(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); - // Use APInt's implementation of AND for single element ranges. - if (isSingleElement() && Other.isSingleElement()) - return {*getSingleElement() & *Other.getSingleElement()}; - - // TODO: replace this with something less conservative - - APInt umin = APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()); - return getNonEmpty(APInt::getZero(getBitWidth()), std::move(umin) + 1); + 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 { +ConstantRange ConstantRange::binaryOr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); - // Use APInt's implementation of OR for single element ranges. - if (isSingleElement() && Other.isSingleElement()) - return {*getSingleElement() | *Other.getSingleElement()}; - - // TODO: replace this with something less conservative - - APInt umax = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()); - return getNonEmpty(std::move(umax), APInt::getZero(getBitWidth())); + 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 { @@ -1412,8 +1436,7 @@ ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const { if (isSingleElement() && getSingleElement()->isAllOnes()) return Other.binaryNot(); - // TODO: replace this with something less conservative - return getFull(); + return fromKnownBits(toKnownBits() ^ Other.toKnownBits(), /*IsSigned*/false); } ConstantRange |
