aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/ConstantRange.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/IR/ConstantRange.cpp')
-rw-r--r--llvm/lib/IR/ConstantRange.cpp77
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