1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

Add a ConstantSignedRange class, which does for signed integers

what ConstantRange does for unsigned integers. Factor out a
common base class for common functionality.

Add some new functions for performing arithmetic on constant
ranges. Some of these are currently just stubbed out with
conservative implementations.

Add unittests for ConstantRange and ConstantSignedRange.

llvm-svn: 75177
This commit is contained in:
Dan Gohman 2009-07-09 22:07:27 +00:00
parent 08991c716a
commit 33251eff97
3 changed files with 1378 additions and 65 deletions

View File

@ -24,7 +24,9 @@
// [0, 0) = {} = Empty set
// [255, 255) = {0..255} = Full Set
//
// Note that ConstantRange always keeps unsigned values.
// Note that ConstantRange always keeps unsigned values, and
// ConstantSignedRange always keeps signed values.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_CONSTANT_RANGE_H
@ -35,11 +37,71 @@
namespace llvm {
class ConstantRange {
/// ConstantRangeBase - A base class for ConstantRange and ConstantSignedRange.
/// This class implements functionality common to both.
class ConstantRangeBase {
protected:
APInt Lower, Upper;
/// Initialize a range to hold the single specified value.
///
ConstantRangeBase(const APInt &Value);
/// @brief Initialize a range of values explicitly. This will assert out if
/// Lower==Upper and Lower != Min or Max value for its type. It will also
/// assert out if the two APInt's are not the same bit width.
ConstantRangeBase(const APInt& Lower, const APInt& Upper);
public:
/// getLower - Return the lower value for this range...
///
const APInt &getLower() const { return Lower; }
/// getUpper - Return the upper value for this range...
///
const APInt &getUpper() const { return Upper; }
/// getBitWidth - get the bit width of this ConstantRange
///
uint32_t getBitWidth() const { return Lower.getBitWidth(); }
/// getSingleElement - If this set contains a single element, return it,
/// otherwise return null.
///
const APInt *getSingleElement() const {
if (Upper == Lower + 1)
return &Lower;
return 0;
}
/// isSingleElement - Return true if this set contains exactly one member.
///
bool isSingleElement() const { return getSingleElement() != 0; }
/// operator== - Return true if this range is equal to another range.
///
bool operator==(const ConstantRangeBase &CR) const {
return Lower == CR.Lower && Upper == CR.Upper;
}
bool operator!=(const ConstantRangeBase &CR) const {
return !operator==(CR);
}
/// print - Print out the bounds to a stream...
///
void print(raw_ostream &OS) const;
/// dump - Allow printing from a debugger easily...
///
void dump() const;
};
/// ConstantRange - This class represents an range of unsigned values.
///
class ConstantRange : public ConstantRangeBase {
static ConstantRange intersect1Wrapped(const ConstantRange &LHS,
const ConstantRange &RHS);
public:
public:
/// Initialize a full (the default) or empty set for the specified bit width.
///
explicit ConstantRange(uint32_t BitWidth, bool isFullSet = true);
@ -53,18 +115,6 @@ class ConstantRange {
/// assert out if the two APInt's are not the same bit width.
ConstantRange(const APInt& Lower, const APInt& Upper);
/// getLower - Return the lower value for this range...
///
const APInt &getLower() const { return Lower; }
/// getUpper - Return the upper value for this range...
///
const APInt &getUpper() const { return Upper; }
/// getBitWidth - get the bit width of this ConstantRange
///
uint32_t getBitWidth() const { return Lower.getBitWidth(); }
/// isFullSet - Return true if this set contains all of the elements possible
/// for this data-type
///
@ -83,19 +133,6 @@ class ConstantRange {
///
bool contains(const APInt &Val) const;
/// getSingleElement - If this set contains a single element, return it,
/// otherwise return null.
///
const APInt *getSingleElement() const {
if (Upper == Lower + 1)
return &Lower;
return 0;
}
/// isSingleElement - Return true if this set contains exactly one member.
///
bool isSingleElement() const { return getSingleElement() != 0; }
/// getSetSize - Return the number of elements in this set.
///
APInt getSetSize() const;
@ -120,15 +157,6 @@ class ConstantRange {
///
APInt getSignedMin() const;
/// operator== - Return true if this range is equal to another range.
///
bool operator==(const ConstantRange &CR) const {
return Lower == CR.Lower && Upper == CR.Upper;
}
bool operator!=(const ConstantRange &CR) const {
return !operator==(CR);
}
/// subtract - Subtract the specified constant from the endpoints of this
/// constant range.
ConstantRange subtract(const APInt &CI) const;
@ -176,20 +204,170 @@ class ConstantRange {
/// truncated to the specified type.
ConstantRange truncate(uint32_t BitWidth) const;
/// print - Print out the bounds to a stream...
///
void print(raw_ostream &OS) const;
/// add - Return a new range representing the possible values resulting
/// from an addition of a value in this range and a value in Other.
ConstantRange add(const ConstantRange &Other) const;
/// dump - Allow printing from a debugger easily...
///
void dump() const;
/// multiply - Return a new range representing the possible values resulting
/// from a multiplication of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantRange multiply(const ConstantRange &Other) const;
/// smax - Return a new range representing the possible values resulting
/// from a signed maximum of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantRange smax(const ConstantRange &Other) const;
/// umax - Return a new range representing the possible values resulting
/// from an unsigned maximum of a value in this range and a value in Other.
ConstantRange umax(const ConstantRange &Other) const;
/// udiv - Return a new range representing the possible values resulting
/// from an unsigned division of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantRange udiv(const ConstantRange &Other) const;
};
inline raw_ostream &operator<<(raw_ostream &OS, const ConstantRange &CR) {
/// ConstantRange - This class represents an range of signed values.
///
class ConstantSignedRange : public ConstantRangeBase {
static ConstantSignedRange intersect1Wrapped(const ConstantSignedRange &LHS,
const ConstantSignedRange &RHS);
public:
/// Initialize a full (the default) or empty set for the specified bit width.
///
explicit ConstantSignedRange(uint32_t BitWidth, bool isFullSet = true);
/// Initialize a range to hold the single specified value.
///
ConstantSignedRange(const APInt &Value);
/// @brief Initialize a range of values explicitly. This will assert out if
/// Lower==Upper and Lower != Min or Max value for its type. It will also
/// assert out if the two APInt's are not the same bit width.
ConstantSignedRange(const APInt& Lower, const APInt& Upper);
/// isFullSet - Return true if this set contains all of the elements possible
/// for this data-type
///
bool isFullSet() const;
/// isEmptySet - Return true if this set contains no members.
///
bool isEmptySet() const;
/// isWrappedSet - Return true if this set wraps around the top of the range,
/// for example: [100, 8)
///
bool isWrappedSet() const;
/// contains - Return true if the specified value is in the set.
///
bool contains(const APInt &Val) const;
/// getSetSize - Return the number of elements in this set.
///
APInt getSetSize() const;
/// getUnsignedMax - Return the largest unsigned value contained in the
/// ConstantSignedRange.
///
APInt getUnsignedMax() const;
/// getUnsignedMin - Return the smallest unsigned value contained in the
/// ConstantSignedRange.
///
APInt getUnsignedMin() const;
/// getSignedMax - Return the largest signed value contained in the
/// ConstantSignedRange.
///
APInt getSignedMax() const;
/// getSignedMin - Return the smallest signed value contained in the
/// ConstantSignedRange.
///
APInt getSignedMin() const;
/// subtract - Subtract the specified constant from the endpoints of this
/// constant range.
ConstantSignedRange subtract(const APInt &CI) const;
/// intersectWith - Return the range that results from the intersection of
/// this range with another range. The resultant range is pruned as much as
/// possible, but there may be cases where elements are included that are in
/// one of the sets but not the other. For example: [100, 8) intersect [3,
/// 120) yields [3, 120)
///
ConstantSignedRange intersectWith(const ConstantSignedRange &CR) const;
/// maximalIntersectWith - Return the range that results from the intersection
/// of this range with another range. The resultant range is guaranteed to
/// include all elements contained in both input ranges, and to have the
/// smallest possible set size that does so. Because there may be two
/// intersections with the same set size, A.maximalIntersectWith(B) might not
/// be equal to B.maximalIntersectWith(A).
///
ConstantSignedRange maximalIntersectWith(const ConstantSignedRange &CR) const;
/// unionWith - Return the range that results from the union of this range
/// with another range. The resultant range is guaranteed to include the
/// elements of both sets, but may contain more. For example, [3, 9) union
/// [12,15) is [3, 15), which includes 9, 10, and 11, which were not included
/// in either set before.
///
ConstantSignedRange unionWith(const ConstantSignedRange &CR) const;
/// zeroExtend - Return a new range in the specified integer type, which must
/// be strictly larger than the current type. The returned range will
/// correspond to the possible range of values if the source range had been
/// zero extended to BitWidth.
ConstantSignedRange zeroExtend(uint32_t BitWidth) const;
/// signExtend - Return a new range in the specified integer type, which must
/// be strictly larger than the current type. The returned range will
/// correspond to the possible range of values if the source range had been
/// sign extended to BitWidth.
ConstantSignedRange signExtend(uint32_t BitWidth) const;
/// truncate - Return a new range in the specified integer type, which must be
/// strictly smaller than the current type. The returned range will
/// correspond to the possible range of values if the source range had been
/// truncated to the specified type.
ConstantSignedRange truncate(uint32_t BitWidth) const;
/// add - Return a new range representing the possible values resulting
/// from an addition of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantSignedRange add(const ConstantSignedRange &Other) const;
/// multiply - Return a new range representing the possible values resulting
/// from a multiplication of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantSignedRange multiply(const ConstantSignedRange &Other) const;
/// smax - Return a new range representing the possible values resulting
/// from a signed maximum of a value in this range and a value in Other.
ConstantSignedRange smax(const ConstantSignedRange &Other) const;
/// umax - Return a new range representing the possible values resulting
/// from an unsigned maximum of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantSignedRange umax(const ConstantSignedRange &Other) const;
/// udiv - Return a new range representing the possible values resulting
/// from an unsigned division of a value in this range and a value in Other.
/// TODO: This isn't fully implemented yet.
ConstantSignedRange udiv(const ConstantSignedRange &Other) const;
};
inline raw_ostream &operator<<(raw_ostream &OS, const ConstantRangeBase &CR) {
CR.print(OS);
return OS;
}
std::ostream &operator<<(std::ostream &OS, const ConstantRangeBase &CR);
} // End llvm namespace
#endif

View File

@ -25,10 +25,40 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
/// Initialize a range to hold the single specified value.
///
ConstantRangeBase::ConstantRangeBase(const APInt & V)
: Lower(V), Upper(V + 1) {}
ConstantRangeBase::ConstantRangeBase(const APInt &L, const APInt &U)
: Lower(L), Upper(U) {
assert(L.getBitWidth() == U.getBitWidth() &&
"ConstantRange with unequal bit widths");
}
/// print - Print out the bounds to a stream...
///
void ConstantRangeBase::print(raw_ostream &OS) const {
OS << "[" << Lower << "," << Upper << ")";
}
/// dump - Allow printing from a debugger easily...
///
void ConstantRangeBase::dump() const {
print(errs());
}
std::ostream &llvm::operator<<(std::ostream &o,
const ConstantRangeBase &CR) {
raw_os_ostream OS(o);
OS << CR;
return o;
}
/// Initialize a full (the default) or empty set for the specified type.
///
ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) :
Lower(BitWidth, 0), Upper(BitWidth, 0) {
ConstantRangeBase(APInt(BitWidth, 0), APInt(BitWidth, 0)) {
if (Full)
Lower = Upper = APInt::getMaxValue(BitWidth);
else
@ -37,12 +67,10 @@ ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) :
/// Initialize a range to hold the single specified value.
///
ConstantRange::ConstantRange(const APInt & V) : Lower(V), Upper(V + 1) { }
ConstantRange::ConstantRange(const APInt & V) : ConstantRangeBase(V) {}
ConstantRange::ConstantRange(const APInt &L, const APInt &U) :
Lower(L), Upper(U) {
assert(L.getBitWidth() == U.getBitWidth() &&
"ConstantRange with unequal bit widths");
ConstantRange::ConstantRange(const APInt &L, const APInt &U)
: ConstantRangeBase(L, U) {
assert((L != U || (L.isMaxValue() || L.isMinValue())) &&
"Lower == Upper, but they aren't min or max value!");
}
@ -221,9 +249,8 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const {
if (!isWrappedSet()) {
if (!CR.isWrappedSet()) {
using namespace APIntOps;
APInt L = umax(Lower, CR.Lower);
APInt U = umin(Upper, CR.Upper);
APInt L = APIntOps::umax(Lower, CR.Lower);
APInt U = APIntOps::umin(Upper, CR.Upper);
if (L.ult(U)) // If range isn't empty...
return ConstantRange(L, U);
@ -236,9 +263,8 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const {
return intersect1Wrapped(*this, CR);
else {
// Both ranges are wrapped...
using namespace APIntOps;
APInt L = umax(Lower, CR.Lower);
APInt U = umin(Upper, CR.Upper);
APInt L = APIntOps::umax(Lower, CR.Lower);
APInt U = APIntOps::umin(Upper, CR.Upper);
return ConstantRange(L, U);
}
}
@ -251,7 +277,8 @@ ConstantRange ConstantRange::intersectWith(const ConstantRange &CR) const {
/// smallest possible set size that does so. Because there may be two
/// intersections with the same set size, A.maximalIntersectWith(B) might not
/// be equal to B.maximalIntersect(A).
ConstantRange ConstantRange::maximalIntersectWith(const ConstantRange &CR) const {
ConstantRange
ConstantRange::maximalIntersectWith(const ConstantRange &CR) const {
assert(getBitWidth() == CR.getBitWidth() &&
"ConstantRange types don't agree!");
@ -459,14 +486,540 @@ ConstantRange ConstantRange::truncate(uint32_t DstTySize) const {
return ConstantRange(L, U);
}
/// print - Print out the bounds to a stream...
///
void ConstantRange::print(raw_ostream &OS) const {
OS << "[" << Lower << "," << Upper << ")";
ConstantRange
ConstantRange::add(const ConstantRange &Other) const {
if (isEmptySet() || Other.isEmptySet())
return ConstantRange(getBitWidth(), /*isFullSet=*/false);
APInt Spread_X = getSetSize(), Spread_Y = Other.getSetSize();
APInt NewLower = getLower() + Other.getLower();
APInt NewUpper = getUpper() + Other.getUpper() - 1;
if (NewLower == NewUpper)
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
ConstantRange X = ConstantRange(NewLower, NewUpper);
if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y))
// We've wrapped, therefore, full set.
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
return X;
}
/// dump - Allow printing from a debugger easily...
///
void ConstantRange::dump() const {
print(errs());
ConstantRange
ConstantRange::multiply(const ConstantRange &Other) const {
// TODO: Implement multiply.
return ConstantRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
ConstantRange
ConstantRange::smax(const ConstantRange &Other) const {
// TODO: Implement smax.
return ConstantRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
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 ConstantRange(getBitWidth(), /*isFullSet=*/false);
if (isFullSet() || Other.isFullSet())
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
APInt NewL = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin());
APInt NewU = APIntOps::umax(getUnsignedMax(), Other.getUnsignedMax()) + 1;
if (NewU == NewL)
return ConstantRange(getBitWidth(), /*isFullSet=*/true);
return ConstantRange(NewL, NewU);
}
ConstantRange
ConstantRange::udiv(const ConstantRange &Other) const {
// TODO: Implement udiv.
return ConstantRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
/// Initialize a full (the default) or empty set for the specified type.
///
ConstantSignedRange::ConstantSignedRange(uint32_t BitWidth, bool Full) :
ConstantRangeBase(APInt(BitWidth, 0), APInt(BitWidth, 0)) {
if (Full)
Lower = Upper = APInt::getSignedMaxValue(BitWidth);
else
Lower = Upper = APInt::getSignedMinValue(BitWidth);
}
/// Initialize a range to hold the single specified value.
///
ConstantSignedRange::ConstantSignedRange(const APInt & V)
: ConstantRangeBase(V) {}
ConstantSignedRange::ConstantSignedRange(const APInt &L, const APInt &U)
: ConstantRangeBase(L, U) {
assert((L != U || (L.isMaxSignedValue() || L.isMinSignedValue())) &&
"Lower == Upper, but they aren't min or max value!");
}
/// isFullSet - Return true if this set contains all of the elements possible
/// for this data-type
bool ConstantSignedRange::isFullSet() const {
return Lower == Upper && Lower.isMaxSignedValue();
}
/// isEmptySet - Return true if this set contains no members.
///
bool ConstantSignedRange::isEmptySet() const {
return Lower == Upper && Lower.isMinSignedValue();
}
/// isWrappedSet - Return true if this set wraps around the top of the range,
/// for example: [100, 8)
///
bool ConstantSignedRange::isWrappedSet() const {
return Lower.sgt(Upper);
}
/// getSetSize - Return the number of elements in this set.
///
APInt ConstantSignedRange::getSetSize() const {
if (isEmptySet())
return APInt(getBitWidth(), 0);
if (getBitWidth() == 1) {
if (Lower != Upper) // One of T or F in the set...
return APInt(2, 1);
return APInt(2, 2); // Must be full set...
}
// Simply subtract the bounds...
return Upper - Lower;
}
/// getSignedMax - Return the largest signed value contained in the
/// ConstantSignedRange.
///
APInt ConstantSignedRange::getSignedMax() const {
if (isFullSet() || isWrappedSet())
return APInt::getSignedMaxValue(getBitWidth());
else
return getUpper() - 1;
}
/// getSignedMin - Return the smallest signed value contained in the
/// ConstantSignedRange.
///
APInt ConstantSignedRange::getSignedMin() const {
if (isFullSet() || (isWrappedSet() &&
getUpper() != APInt::getSignedMinValue(getBitWidth())))
return APInt::getSignedMinValue(getBitWidth());
else
return getLower();
}
/// getUnsignedMax - Return the largest unsigned value contained in the
/// ConstantSignedRange.
///
APInt ConstantSignedRange::getUnsignedMax() const {
APInt UnsignedMax(APInt::getMaxValue(getBitWidth()));
if (!isWrappedSet()) {
if (getLower().ule(getUpper() - 1))
return getUpper() - 1;
else
return UnsignedMax;
} else {
if ((getUpper() - 1).ult(getLower())) {
if (getLower() != UnsignedMax)
return UnsignedMax;
else
return getUpper() - 1;
} else {
return getUpper() - 1;
}
}
}
/// getUnsignedMin - Return the smallest unsigned value contained in the
/// ConstantSignedRange.
///
APInt ConstantSignedRange::getUnsignedMin() const {
APInt UnsignedMin(APInt::getMinValue(getBitWidth()));
if (!isWrappedSet()) {
if (getLower().ule(getUpper() - 1))
return getLower();
else
return UnsignedMin;
} else {
if ((getUpper() - 1).ult(getLower())) {
if (getUpper() != UnsignedMin)
return UnsignedMin;
else
return getLower();
} else {
return getLower();
}
}
}
/// contains - Return true if the specified value is in the set.
///
bool ConstantSignedRange::contains(const APInt &V) const {
if (Lower == Upper)
return isFullSet();
if (!isWrappedSet())
return Lower.sle(V) && V.slt(Upper);
else
return Lower.sle(V) || V.slt(Upper);
}
/// subtract - Subtract the specified constant from the endpoints of this
/// constant range.
ConstantSignedRange ConstantSignedRange::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 ConstantSignedRange(Lower - Val, Upper - Val);
}
// intersect1Wrapped - This helper function is used to intersect two ranges when
// it is known that LHS is wrapped and RHS isn't.
//
ConstantSignedRange
ConstantSignedRange::intersect1Wrapped(const ConstantSignedRange &LHS,
const ConstantSignedRange &RHS) {
assert(LHS.isWrappedSet() && !RHS.isWrappedSet());
// Check to see if we overlap on the Left side of RHS...
//
if (RHS.Lower.slt(LHS.Upper)) {
// We do overlap on the left side of RHS, see if we overlap on the right of
// RHS...
if (RHS.Upper.sgt(LHS.Lower)) {
// Ok, the result overlaps on both the left and right sides. See if the
// resultant interval will be smaller if we wrap or not...
//
if (LHS.getSetSize().ult(RHS.getSetSize()))
return LHS;
else
return RHS;
} else {
// No overlap on the right, just on the left.
return ConstantSignedRange(RHS.Lower, LHS.Upper);
}
} else {
// We don't overlap on the left side of RHS, see if we overlap on the right
// of RHS...
if (RHS.Upper.sgt(LHS.Lower)) {
// Simple overlap...
return ConstantSignedRange(LHS.Lower, RHS.Upper);
} else {
// No overlap...
return ConstantSignedRange(LHS.getBitWidth(), false);
}
}
}
/// intersectWith - Return the range that results from the intersection of this
/// range with another range.
///
ConstantSignedRange
ConstantSignedRange::intersectWith(const ConstantSignedRange &CR) const {
assert(getBitWidth() == CR.getBitWidth() &&
"ConstantSignedRange types don't agree!");
// Handle common special cases
if (isEmptySet() || CR.isFullSet())
return *this;
if (isFullSet() || CR.isEmptySet())
return CR;
if (!isWrappedSet()) {
if (!CR.isWrappedSet()) {
APInt L = APIntOps::smax(Lower, CR.Lower);
APInt U = APIntOps::smin(Upper, CR.Upper);
if (L.slt(U)) // If range isn't empty...
return ConstantSignedRange(L, U);
else
return ConstantSignedRange(getBitWidth(), false);// Otherwise, empty set
} else
return intersect1Wrapped(CR, *this);
} else { // We know "this" is wrapped...
if (!CR.isWrappedSet())
return intersect1Wrapped(*this, CR);
else {
// Both ranges are wrapped...
APInt L = APIntOps::smax(Lower, CR.Lower);
APInt U = APIntOps::smin(Upper, CR.Upper);
return ConstantSignedRange(L, U);
}
}
return *this;
}
/// maximalIntersectWith - Return the range that results from the intersection
/// of this range with another range. The resultant range is guaranteed to
/// include all elements contained in both input ranges, and to have the
/// smallest possible set size that does so. Because there may be two
/// intersections with the same set size, A.maximalIntersectWith(B) might not
/// be equal to B.maximalIntersect(A).
ConstantSignedRange
ConstantSignedRange::maximalIntersectWith(const ConstantSignedRange &CR) const {
assert(getBitWidth() == CR.getBitWidth() &&
"ConstantSignedRange types don't agree!");
// Handle common cases.
if ( isEmptySet() || CR.isFullSet()) return *this;
if (CR.isEmptySet() || isFullSet()) return CR;
if (!isWrappedSet() && CR.isWrappedSet())
return CR.maximalIntersectWith(*this);
if (!isWrappedSet() && !CR.isWrappedSet()) {
if (Lower.slt(CR.Lower)) {
if (Upper.sle(CR.Lower))
return ConstantSignedRange(getBitWidth(), false);
if (Upper.slt(CR.Upper))
return ConstantSignedRange(CR.Lower, Upper);
return CR;
} else {
if (Upper.slt(CR.Upper))
return *this;
if (Lower.slt(CR.Upper))
return ConstantSignedRange(Lower, CR.Upper);
return ConstantSignedRange(getBitWidth(), false);
}
}
if (isWrappedSet() && !CR.isWrappedSet()) {
if (CR.Lower.slt(Upper)) {
if (CR.Upper.slt(Upper))
return CR;
if (CR.Upper.slt(Lower))
return ConstantSignedRange(CR.Lower, Upper);
if (getSetSize().ult(CR.getSetSize()))
return *this;
else
return CR;
} else if (CR.Lower.slt(Lower)) {
if (CR.Upper.sle(Lower))
return ConstantSignedRange(getBitWidth(), false);
return ConstantSignedRange(Lower, CR.Upper);
}
return CR;
}
if (CR.Upper.slt(Upper)) {
if (CR.Lower.slt(Upper)) {
if (getSetSize().ult(CR.getSetSize()))
return *this;
else
return CR;
}
if (CR.Lower.slt(Lower))
return ConstantSignedRange(Lower, CR.Upper);
return CR;
} else if (CR.Upper.slt(Lower)) {
if (CR.Lower.slt(Lower))
return *this;
return ConstantSignedRange(CR.Lower, Upper);
}
if (getSetSize().ult(CR.getSetSize()))
return *this;
else
return CR;
}
/// unionWith - Return the range that results from the union of this range with
/// another range. The resultant range is guaranteed to include the elements of
/// both sets, but may contain more. For example, [3, 9) union [12,15) is
/// [3, 15), which includes 9, 10, and 11, which were not included in either
/// set before.
///
ConstantSignedRange
ConstantSignedRange::unionWith(const ConstantSignedRange &CR) const {
assert(getBitWidth() == CR.getBitWidth() &&
"ConstantSignedRange types don't agree!");
if ( isFullSet() || CR.isEmptySet()) return *this;
if (CR.isFullSet() || isEmptySet()) return CR;
if (!isWrappedSet() && CR.isWrappedSet()) return CR.unionWith(*this);
APInt L = Lower, U = Upper;
if (!isWrappedSet() && !CR.isWrappedSet()) {
if (CR.Lower.slt(L))
L = CR.Lower;
if (CR.Upper.sgt(U))
U = CR.Upper;
}
if (isWrappedSet() && !CR.isWrappedSet()) {
if ((CR.Lower.slt(Upper) && CR.Upper.slt(Upper)) ||
(CR.Lower.sgt(Lower) && CR.Upper.sgt(Lower))) {
return *this;
}
if (CR.Lower.sle(Upper) && Lower.sle(CR.Upper)) {
return ConstantSignedRange(getBitWidth());
}
if (CR.Lower.sle(Upper) && CR.Upper.sle(Lower)) {
APInt d1 = CR.Upper - Upper, d2 = Lower - CR.Upper;
if (d1.slt(d2)) {
U = CR.Upper;
} else {
L = CR.Upper;
}
}
if (Upper.slt(CR.Lower) && CR.Upper.slt(Lower)) {
APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper;
if (d1.slt(d2)) {
U = CR.Lower + 1;
} else {
L = CR.Upper - 1;
}
}
if (Upper.slt(CR.Lower) && Lower.slt(CR.Upper)) {
APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Lower;
if (d1.slt(d2)) {
U = CR.Lower + 1;
} else {
L = CR.Lower;
}
}
}
if (isWrappedSet() && CR.isWrappedSet()) {
if (Lower.slt(CR.Upper) || CR.Lower.slt(Upper))
return ConstantSignedRange(getBitWidth());
if (CR.Upper.sgt(U)) {
U = CR.Upper;
}
if (CR.Lower.slt(L)) {
L = CR.Lower;
}
if (L == U) return ConstantSignedRange(getBitWidth());
}
return ConstantSignedRange(L, U);
}
/// zeroExtend - Return a new range in the specified integer type, which must
/// be strictly larger than the current type. The returned range will
/// correspond to the possible range of values as if the source range had been
/// zero extended.
ConstantSignedRange ConstantSignedRange::zeroExtend(uint32_t DstTySize) const {
unsigned SrcTySize = getBitWidth();
assert(SrcTySize < DstTySize && "Not a value extension");
if (isEmptySet())
return ConstantSignedRange(SrcTySize, /*isFullSet=*/false);
if (isFullSet())
// Change a source full set into [0, 1 << 8*numbytes)
return ConstantSignedRange(APInt(DstTySize,0),
APInt(DstTySize,1).shl(SrcTySize));
APInt L, U;
if (Lower.isNegative() && !Upper.isNegative()) {
L = APInt(SrcTySize, 0);
U = APInt::getSignedMinValue(SrcTySize);
} else {
L = Lower;
U = Upper;
}
L.zext(DstTySize);
U.zext(DstTySize);
return ConstantSignedRange(L, U);
}
/// signExtend - Return a new range in the specified integer type, which must
/// be strictly larger than the current type. The returned range will
/// correspond to the possible range of values as if the source range had been
/// sign extended.
ConstantSignedRange ConstantSignedRange::signExtend(uint32_t DstTySize) const {
unsigned SrcTySize = getBitWidth();
assert(SrcTySize < DstTySize && "Not a value extension");
if (isEmptySet())
return ConstantSignedRange(SrcTySize, /*isFullSet=*/false);
if (isFullSet())
return ConstantSignedRange(APInt(getSignedMin()).sext(DstTySize),
APInt(getSignedMax()).sext(DstTySize)+1);
APInt L = Lower; L.sext(DstTySize);
APInt U = Upper; U.sext(DstTySize);
return ConstantSignedRange(L, U);
}
/// truncate - Return a new range in the specified integer type, which must be
/// strictly smaller than the current type. The returned range will
/// correspond to the possible range of values as if the source range had been
/// truncated to the specified type.
ConstantSignedRange ConstantSignedRange::truncate(uint32_t DstTySize) const {
// TODO: Implement truncate.
return ConstantSignedRange(DstTySize, !isEmptySet());
}
ConstantSignedRange
ConstantSignedRange::add(const ConstantSignedRange &Other) const {
// TODO: Implement add.
return ConstantSignedRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
ConstantSignedRange
ConstantSignedRange::multiply(const ConstantSignedRange &Other) const {
// TODO: Implement multiply.
return ConstantSignedRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
ConstantSignedRange
ConstantSignedRange::smax(const ConstantSignedRange &Other) const {
// X smax Y is: range(smax(X_smin, Y_smin),
// smax(X_smax, Y_smax))
if (isEmptySet() || Other.isEmptySet())
return ConstantSignedRange(getBitWidth(), /*isFullSet=*/false);
if (isFullSet() || Other.isFullSet())
return ConstantSignedRange(getBitWidth(), /*isFullSet=*/true);
APInt NewL = APIntOps::smax(getSignedMin(), Other.getSignedMin());
APInt NewU = APIntOps::smax(getSignedMax(), Other.getSignedMax()) + 1;
if (NewU == NewL)
return ConstantSignedRange(getBitWidth(), /*isFullSet=*/true);
return ConstantSignedRange(NewL, NewU);
}
ConstantSignedRange
ConstantSignedRange::umax(const ConstantSignedRange &Other) const {
// TODO: Implement umax.
return ConstantSignedRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}
ConstantSignedRange
ConstantSignedRange::udiv(const ConstantSignedRange &Other) const {
// TODO: Implement udiv.
return ConstantSignedRange(getBitWidth(),
!(isEmptySet() || Other.isEmptySet()));
}

View File

@ -0,0 +1,582 @@
//===- llvm/unittest/Support/ConstantRangeTest.cpp - ConstantRange tests --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ConstantRange.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
TEST(ConstantRangeTest, Unsigned) {
ConstantRange Full(16);
ConstantRange Empty(16, false);
ConstantRange One(APInt(16, 0xa));
ConstantRange Some(APInt(16, 0xa), APInt(16, 0xaaa));
ConstantRange Wrap(APInt(16, 0xaaa), APInt(16, 0xa));
EXPECT_TRUE(Full.isFullSet());
EXPECT_FALSE(Full.isEmptySet());
EXPECT_FALSE(Full.isWrappedSet());
EXPECT_TRUE(Full.contains(APInt(16, 0x0)));
EXPECT_TRUE(Full.contains(APInt(16, 0x9)));
EXPECT_TRUE(Full.contains(APInt(16, 0xa)));
EXPECT_TRUE(Full.contains(APInt(16, 0xaa9)));
EXPECT_TRUE(Full.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Empty.isFullSet());
EXPECT_TRUE(Empty.isEmptySet());
EXPECT_FALSE(Empty.isWrappedSet());
EXPECT_FALSE(Empty.contains(APInt(16, 0x0)));
EXPECT_FALSE(Empty.contains(APInt(16, 0x9)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xa)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(One.isFullSet());
EXPECT_FALSE(One.isEmptySet());
EXPECT_FALSE(One.isWrappedSet());
EXPECT_FALSE(One.contains(APInt(16, 0x0)));
EXPECT_FALSE(One.contains(APInt(16, 0x9)));
EXPECT_TRUE(One.contains(APInt(16, 0xa)));
EXPECT_FALSE(One.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(One.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Some.isFullSet());
EXPECT_FALSE(Some.isEmptySet());
EXPECT_FALSE(Some.isWrappedSet());
EXPECT_FALSE(Some.contains(APInt(16, 0x0)));
EXPECT_FALSE(Some.contains(APInt(16, 0x9)));
EXPECT_TRUE(Some.contains(APInt(16, 0xa)));
EXPECT_TRUE(Some.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(Some.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Wrap.isFullSet());
EXPECT_FALSE(Wrap.isEmptySet());
EXPECT_TRUE(Wrap.isWrappedSet());
EXPECT_TRUE(Wrap.contains(APInt(16, 0x0)));
EXPECT_TRUE(Wrap.contains(APInt(16, 0x9)));
EXPECT_FALSE(Wrap.contains(APInt(16, 0xa)));
EXPECT_FALSE(Wrap.contains(APInt(16, 0xaa9)));
EXPECT_TRUE(Wrap.contains(APInt(16, 0xaaa)));
EXPECT_EQ(Full, Full);
EXPECT_EQ(Empty, Empty);
EXPECT_EQ(One, One);
EXPECT_EQ(Some, Some);
EXPECT_EQ(Wrap, Wrap);
EXPECT_NE(Full, Empty);
EXPECT_NE(Full, One);
EXPECT_NE(Full, Some);
EXPECT_NE(Full, Wrap);
EXPECT_NE(Empty, One);
EXPECT_NE(Empty, Some);
EXPECT_NE(Empty, Wrap);
EXPECT_NE(One, Some);
EXPECT_NE(One, Wrap);
EXPECT_NE(Some, Wrap);
EXPECT_EQ(Full.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(Empty.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa));
EXPECT_EQ(Some.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(Wrap.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_FALSE(Full.isSingleElement());
EXPECT_FALSE(Empty.isSingleElement());
EXPECT_TRUE(One.isSingleElement());
EXPECT_FALSE(Some.isSingleElement());
EXPECT_FALSE(Wrap.isSingleElement());
EXPECT_EQ(Full.getSetSize(), APInt(16, 0));
EXPECT_EQ(Empty.getSetSize(), APInt(16, 0));
EXPECT_EQ(One.getSetSize(), APInt(16, 1));
EXPECT_EQ(Some.getSetSize(), APInt(16, 0xaa0));
EXPECT_EQ(Wrap.getSetSize(), APInt(16, 0x10000 - 0xaa0));
EXPECT_EQ(Full.getUnsignedMax(), APInt(16, UINT16_MAX));
EXPECT_EQ(One.getUnsignedMax(), APInt(16, 0xa));
EXPECT_EQ(Some.getUnsignedMax(), APInt(16, 0xaa9));
EXPECT_EQ(Wrap.getUnsignedMax(), APInt(16, UINT16_MAX));
EXPECT_EQ(Full.getUnsignedMin(), APInt(16, 0));
EXPECT_EQ(One.getUnsignedMin(), APInt(16, 0xa));
EXPECT_EQ(Some.getUnsignedMin(), APInt(16, 0xa));
EXPECT_EQ(Wrap.getUnsignedMin(), APInt(16, 0));
EXPECT_EQ(Full.getSignedMax(), APInt(16, INT16_MAX));
EXPECT_EQ(One.getSignedMax(), APInt(16, 0xa));
EXPECT_EQ(Some.getSignedMax(), APInt(16, 0xaa9));
EXPECT_EQ(Wrap.getSignedMax(), APInt(16, INT16_MAX));
EXPECT_EQ(Full.getSignedMin(), APInt(16, INT16_MIN));
EXPECT_EQ(One.getSignedMin(), APInt(16, 0xa));
EXPECT_EQ(Some.getSignedMin(), APInt(16, 0xa));
EXPECT_EQ(Wrap.getSignedMin(), APInt(16, INT16_MIN));
ConstantRange TFull = Full.truncate(10);
ConstantRange TEmpty = Empty.truncate(10);
ConstantRange TOne = One.truncate(10);
ConstantRange TSome = Some.truncate(10);
ConstantRange TWrap = Wrap.truncate(10);
EXPECT_TRUE(TFull.isFullSet());
EXPECT_TRUE(TEmpty.isEmptySet());
EXPECT_EQ(TOne, ConstantRange(APInt(One.getLower()).trunc(10),
APInt(One.getUpper()).trunc(10)));
// TODO: ConstantRange is currently over-conservative here.
EXPECT_TRUE(TSome.isFullSet());
ConstantRange ZFull = Full.zeroExtend(20);
ConstantRange ZEmpty = Empty.zeroExtend(20);
ConstantRange ZOne = One.zeroExtend(20);
ConstantRange ZSome = Some.zeroExtend(20);
ConstantRange ZWrap = Wrap.zeroExtend(20);
EXPECT_EQ(ZFull, ConstantRange(APInt(20, 0), APInt(20, 0x10000)));
EXPECT_TRUE(ZEmpty.isEmptySet());
EXPECT_EQ(ZOne, ConstantRange(APInt(One.getLower()).zext(20),
APInt(One.getUpper()).zext(20)));
EXPECT_EQ(ZSome, ConstantRange(APInt(Some.getLower()).zext(20),
APInt(Some.getUpper()).zext(20)));
EXPECT_EQ(ZWrap, ConstantRange(APInt(Wrap.getLower()).zext(20),
APInt(Wrap.getUpper()).zext(20)));
ConstantRange SFull = Full.signExtend(20);
ConstantRange SEmpty = Empty.signExtend(20);
ConstantRange SOne = One.signExtend(20);
ConstantRange SSome = Some.signExtend(20);
ConstantRange SWrap = Wrap.signExtend(20);
EXPECT_EQ(SFull, ConstantRange(APInt(20, INT16_MIN, true),
APInt(20, INT16_MAX, true)));
EXPECT_TRUE(SEmpty.isEmptySet());
EXPECT_EQ(SOne, ConstantRange(APInt(One.getLower()).sext(20),
APInt(One.getUpper()).sext(20)));
EXPECT_EQ(SSome, ConstantRange(APInt(Some.getLower()).sext(20),
APInt(Some.getUpper()).sext(20)));
EXPECT_EQ(SWrap, ConstantRange(APInt(Wrap.getLower()).sext(20),
APInt(Wrap.getUpper()).sext(20)));
EXPECT_TRUE(Empty.intersectWith(Full).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Empty).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(One).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Some).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Wrap).isEmptySet());
EXPECT_TRUE(Full.intersectWith(Full).isFullSet());
EXPECT_TRUE(Some.intersectWith(Some) == Some);
EXPECT_TRUE(Some.intersectWith(One) == One);
EXPECT_TRUE(Full.intersectWith(One) == One);
EXPECT_TRUE(Full.intersectWith(Some) == Some);
EXPECT_TRUE(Some.intersectWith(Wrap).isEmptySet());
EXPECT_TRUE(One.intersectWith(Wrap).isEmptySet());
EXPECT_EQ(One.intersectWith(Wrap), Wrap.intersectWith(One));
EXPECT_TRUE(Empty.maximalIntersectWith(Full).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Empty).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(One).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Some).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_TRUE(Full.maximalIntersectWith(Full).isFullSet());
EXPECT_TRUE(Some.maximalIntersectWith(Some) == Some);
EXPECT_TRUE(Some.maximalIntersectWith(One) == One);
EXPECT_TRUE(Full.maximalIntersectWith(One) == One);
EXPECT_TRUE(Full.maximalIntersectWith(Some) == Some);
EXPECT_TRUE(Some.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_TRUE(One.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_EQ(One.maximalIntersectWith(Wrap), Wrap.maximalIntersectWith(One));
EXPECT_EQ(Wrap.unionWith(One),
ConstantRange(APInt(16, 0xaaa), APInt(16, 0xb)));
EXPECT_EQ(One.unionWith(Wrap), Wrap.unionWith(One));
EXPECT_TRUE(Empty.unionWith(Empty).isEmptySet());
EXPECT_TRUE(Full.unionWith(Full).isFullSet());
EXPECT_TRUE(Some.unionWith(Wrap).isFullSet());
EXPECT_TRUE(Full.subtract(APInt(16, 4)).isFullSet());
EXPECT_TRUE(Empty.subtract(APInt(16, 4)).isEmptySet());
EXPECT_EQ(Some.subtract(APInt(16, 4)),
ConstantRange(APInt(16, 0x6), APInt(16, 0xaa6)));
EXPECT_EQ(Wrap.subtract(APInt(16, 4)),
ConstantRange(APInt(16, 0xaa6), APInt(16, 0x6)));
EXPECT_EQ(One.subtract(APInt(16, 4)),
ConstantRange(APInt(16, 0x6)));
EXPECT_TRUE(Full.add(APInt(16, 4)).isFullSet());
EXPECT_TRUE(Empty.add(APInt(16, 4)).isEmptySet());
EXPECT_EQ(Some.add(APInt(16, 4)),
ConstantRange(APInt(16, 0xe), APInt(16, 0xaae)));
EXPECT_EQ(Wrap.add(APInt(16, 4)),
ConstantRange(APInt(16, 0xaae), APInt(16, 0xe)));
EXPECT_EQ(One.add(APInt(16, 4)),
ConstantRange(APInt(16, 0xe)));
EXPECT_TRUE(Full.umax(Full).isFullSet());
EXPECT_TRUE(Full.umax(Empty).isEmptySet());
EXPECT_TRUE(Full.umax(Some).isFullSet());
EXPECT_TRUE(Full.umax(Wrap).isFullSet());
EXPECT_TRUE(Full.umax(One).isFullSet());
EXPECT_EQ(Empty.umax(Empty), Empty);
EXPECT_EQ(Empty.umax(Some), Empty);
EXPECT_EQ(Empty.umax(Wrap), Empty);
EXPECT_EQ(Empty.umax(One), Empty);
EXPECT_EQ(Some.umax(Some), Some);
EXPECT_EQ(Some.umax(Wrap), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
EXPECT_EQ(Some.umax(One), Some);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Wrap.umax(Wrap), Full);
EXPECT_EQ(Wrap.umax(One), ConstantRange(APInt(16, 0xa), APInt(16, 0)));
EXPECT_EQ(One.umax(One), One);
EXPECT_EQ(Full.multiply(Full), Full);
EXPECT_EQ(Full.multiply(Empty), Empty);
EXPECT_EQ(Full.multiply(One), Full);
EXPECT_EQ(Full.multiply(Some), Full);
EXPECT_EQ(Full.multiply(Wrap), Full);
EXPECT_EQ(Empty.multiply(Empty), Empty);
EXPECT_EQ(Empty.multiply(One), Empty);
EXPECT_EQ(Empty.multiply(Some), Empty);
EXPECT_EQ(Empty.multiply(Wrap), Empty);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.multiply(One), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.multiply(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.multiply(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.multiply(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.multiply(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Wrap.multiply(Wrap), Full);
EXPECT_EQ(Full.smax(Full), Full);
EXPECT_EQ(Full.smax(Empty), Empty);
EXPECT_EQ(Full.smax(One), Full);
EXPECT_EQ(Full.smax(Some), Full);
EXPECT_EQ(Full.smax(Wrap), Full);
EXPECT_EQ(Empty.smax(Empty), Empty);
EXPECT_EQ(Empty.smax(One), Empty);
EXPECT_EQ(Empty.smax(Some), Empty);
EXPECT_EQ(Empty.smax(Wrap), Empty);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.smax(One), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.smax(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.smax(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.smax(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.smax(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Wrap.smax(Wrap), Full);
EXPECT_EQ(Full.udiv(Full), Full);
EXPECT_EQ(Full.udiv(Empty), Empty);
EXPECT_EQ(Full.udiv(One), Full);
EXPECT_EQ(Full.udiv(Some), Full);
EXPECT_EQ(Full.udiv(Wrap), Full);
EXPECT_EQ(Empty.udiv(Empty), Empty);
EXPECT_EQ(Empty.udiv(One), Empty);
EXPECT_EQ(Empty.udiv(Some), Empty);
EXPECT_EQ(Empty.udiv(Wrap), Empty);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.udiv(One), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.udiv(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(One.udiv(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.udiv(Some), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Some.udiv(Wrap), Full);
// TODO: ConstantRange is currently over-conservative here.
EXPECT_EQ(Wrap.udiv(Wrap), Full);
}
TEST(ConstantRangeTest, Signed) {
ConstantSignedRange Full(16);
ConstantSignedRange Empty(16, false);
ConstantSignedRange One(APInt(16, 0xa));
ConstantSignedRange Some(APInt(16, 0xa), APInt(16, 0xaaa));
ConstantSignedRange Wrap(APInt(16, 0xaaa), APInt(16, 0xa));
EXPECT_TRUE(Full.isFullSet());
EXPECT_FALSE(Full.isEmptySet());
EXPECT_FALSE(Full.isWrappedSet());
EXPECT_TRUE(Full.contains(APInt(16, 0x0)));
EXPECT_TRUE(Full.contains(APInt(16, 0x9)));
EXPECT_TRUE(Full.contains(APInt(16, 0xa)));
EXPECT_TRUE(Full.contains(APInt(16, 0xaa9)));
EXPECT_TRUE(Full.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Empty.isFullSet());
EXPECT_TRUE(Empty.isEmptySet());
EXPECT_FALSE(Empty.isWrappedSet());
EXPECT_FALSE(Empty.contains(APInt(16, 0x0)));
EXPECT_FALSE(Empty.contains(APInt(16, 0x9)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xa)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(Empty.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(One.isFullSet());
EXPECT_FALSE(One.isEmptySet());
EXPECT_FALSE(One.isWrappedSet());
EXPECT_FALSE(One.contains(APInt(16, 0x0)));
EXPECT_FALSE(One.contains(APInt(16, 0x9)));
EXPECT_TRUE(One.contains(APInt(16, 0xa)));
EXPECT_FALSE(One.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(One.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Some.isFullSet());
EXPECT_FALSE(Some.isEmptySet());
EXPECT_FALSE(Some.isWrappedSet());
EXPECT_FALSE(Some.contains(APInt(16, 0x0)));
EXPECT_FALSE(Some.contains(APInt(16, 0x9)));
EXPECT_TRUE(Some.contains(APInt(16, 0xa)));
EXPECT_TRUE(Some.contains(APInt(16, 0xaa9)));
EXPECT_FALSE(Some.contains(APInt(16, 0xaaa)));
EXPECT_FALSE(Wrap.isFullSet());
EXPECT_FALSE(Wrap.isEmptySet());
EXPECT_TRUE(Wrap.isWrappedSet());
EXPECT_TRUE(Wrap.contains(APInt(16, 0x0)));
EXPECT_TRUE(Wrap.contains(APInt(16, 0x9)));
EXPECT_FALSE(Wrap.contains(APInt(16, 0xa)));
EXPECT_FALSE(Wrap.contains(APInt(16, 0xaa9)));
EXPECT_TRUE(Wrap.contains(APInt(16, 0xaaa)));
EXPECT_EQ(Full, Full);
EXPECT_EQ(Empty, Empty);
EXPECT_EQ(One, One);
EXPECT_EQ(Some, Some);
EXPECT_EQ(Wrap, Wrap);
EXPECT_NE(Full, Empty);
EXPECT_NE(Full, One);
EXPECT_NE(Full, Some);
EXPECT_NE(Full, Wrap);
EXPECT_NE(Empty, One);
EXPECT_NE(Empty, Some);
EXPECT_NE(Empty, Wrap);
EXPECT_NE(One, Some);
EXPECT_NE(One, Wrap);
EXPECT_NE(Some, Wrap);
EXPECT_EQ(Full.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(Empty.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa));
EXPECT_EQ(Some.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_EQ(Wrap.getSingleElement(), static_cast<APInt *>(NULL));
EXPECT_FALSE(Full.isSingleElement());
EXPECT_FALSE(Empty.isSingleElement());
EXPECT_TRUE(One.isSingleElement());
EXPECT_FALSE(Some.isSingleElement());
EXPECT_FALSE(Wrap.isSingleElement());
EXPECT_EQ(Full.getSetSize(), APInt(16, 0));
EXPECT_EQ(Empty.getSetSize(), APInt(16, 0));
EXPECT_EQ(One.getSetSize(), APInt(16, 1));
EXPECT_EQ(Some.getSetSize(), APInt(16, 0xaa0));
EXPECT_EQ(Wrap.getSetSize(), APInt(16, 0x10000 - 0xaa0));
EXPECT_EQ(Full.getSignedMax(), APInt(16, INT16_MAX, true));
EXPECT_EQ(One.getSignedMax(), APInt(16, 0xa));
EXPECT_EQ(Some.getSignedMax(), APInt(16, 0xaa9));
EXPECT_EQ(Wrap.getSignedMax(), APInt(16, INT16_MAX));
EXPECT_EQ(Full.getSignedMin(), APInt(16, INT16_MIN));
EXPECT_EQ(One.getSignedMin(), APInt(16, 0xa));
EXPECT_EQ(Some.getSignedMin(), APInt(16, 0xa));
EXPECT_EQ(Wrap.getSignedMin(), APInt(16, INT16_MIN));
EXPECT_EQ(Full.getUnsignedMax(), APInt(16, UINT16_MAX, true));
EXPECT_EQ(One.getUnsignedMax(), APInt(16, 0xa));
EXPECT_EQ(Some.getUnsignedMax(), APInt(16, 0xaa9));
EXPECT_EQ(Wrap.getUnsignedMax(), APInt(16, UINT16_MAX));
EXPECT_EQ(Full.getUnsignedMin(), APInt(16, 0));
EXPECT_EQ(One.getUnsignedMin(), APInt(16, 0xa));
EXPECT_EQ(Some.getUnsignedMin(), APInt(16, 0xa));
EXPECT_EQ(Wrap.getUnsignedMin(), APInt(16, 0));
ConstantSignedRange TFull = Full.truncate(10);
ConstantSignedRange TEmpty = Empty.truncate(10);
ConstantSignedRange TOne = One.truncate(10);
ConstantSignedRange TSome = Some.truncate(10);
ConstantSignedRange TWrap = Wrap.truncate(10);
EXPECT_TRUE(TFull.isFullSet());
EXPECT_TRUE(TEmpty.isEmptySet());
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_TRUE(TOne.isFullSet());
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_TRUE(TSome.isFullSet());
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_TRUE(TWrap.isFullSet());
ConstantSignedRange ZFull = Full.zeroExtend(20);
ConstantSignedRange ZEmpty = Empty.zeroExtend(20);
ConstantSignedRange ZOne = One.zeroExtend(20);
ConstantSignedRange ZSome = Some.zeroExtend(20);
ConstantSignedRange ZWrap = Wrap.zeroExtend(20);
EXPECT_EQ(ZFull, ConstantSignedRange(APInt(20, 0), APInt(20, 0x10000)));
EXPECT_TRUE(ZEmpty.isEmptySet());
EXPECT_EQ(ZOne, ConstantSignedRange(APInt(One.getLower()).zext(20),
APInt(One.getUpper()).zext(20)));
EXPECT_EQ(ZSome, ConstantSignedRange(APInt(Some.getLower()).zext(20),
APInt(Some.getUpper()).zext(20)));
EXPECT_EQ(ZWrap, ConstantSignedRange(APInt(Wrap.getLower()).zext(20),
APInt(Wrap.getUpper()).zext(20)));
ConstantSignedRange SFull = Full.signExtend(20);
ConstantSignedRange SEmpty = Empty.signExtend(20);
ConstantSignedRange SOne = One.signExtend(20);
ConstantSignedRange SSome = Some.signExtend(20);
ConstantSignedRange SWrap = Wrap.signExtend(20);
EXPECT_EQ(SFull, ConstantSignedRange(APInt(20, INT16_MIN),
APInt(20, INT16_MAX+1)));
EXPECT_TRUE(SEmpty.isEmptySet());
EXPECT_EQ(SOne, ConstantSignedRange(APInt(One.getLower()).sext(20),
APInt(One.getUpper()).sext(20)));
EXPECT_EQ(SSome, ConstantSignedRange(APInt(Some.getLower()).sext(20),
APInt(Some.getUpper()).sext(20)));
EXPECT_EQ(SWrap, ConstantSignedRange(APInt(Wrap.getLower()).sext(20),
APInt(Wrap.getUpper()).sext(20)));
EXPECT_TRUE(Empty.intersectWith(Full).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Empty).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(One).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Some).isEmptySet());
EXPECT_TRUE(Empty.intersectWith(Wrap).isEmptySet());
EXPECT_TRUE(Full.intersectWith(Full).isFullSet());
EXPECT_TRUE(Some.intersectWith(Some) == Some);
EXPECT_TRUE(Some.intersectWith(One) == One);
EXPECT_TRUE(Full.intersectWith(One) == One);
EXPECT_TRUE(Full.intersectWith(Some) == Some);
EXPECT_TRUE(Some.intersectWith(Wrap).isEmptySet());
EXPECT_TRUE(One.intersectWith(Wrap).isEmptySet());
EXPECT_EQ(One.intersectWith(Wrap), Wrap.intersectWith(One));
EXPECT_TRUE(Empty.maximalIntersectWith(Full).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Empty).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(One).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Some).isEmptySet());
EXPECT_TRUE(Empty.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_TRUE(Full.maximalIntersectWith(Full).isFullSet());
EXPECT_TRUE(Some.maximalIntersectWith(Some) == Some);
EXPECT_TRUE(Some.maximalIntersectWith(One) == One);
EXPECT_TRUE(Full.maximalIntersectWith(One) == One);
EXPECT_TRUE(Full.maximalIntersectWith(Some) == Some);
EXPECT_TRUE(Some.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_TRUE(One.maximalIntersectWith(Wrap).isEmptySet());
EXPECT_EQ(One.maximalIntersectWith(Wrap), Wrap.maximalIntersectWith(One));
EXPECT_EQ(Wrap.unionWith(One),
ConstantSignedRange(APInt(16, 0xaaa), APInt(16, 0xb)));
EXPECT_EQ(One.unionWith(Wrap), Wrap.unionWith(One));
EXPECT_TRUE(Empty.unionWith(Empty).isEmptySet());
EXPECT_TRUE(Full.unionWith(Full).isFullSet());
EXPECT_TRUE(Some.unionWith(Wrap).isFullSet());
EXPECT_TRUE(Full.subtract(APInt(16, 4)).isFullSet());
EXPECT_TRUE(Empty.subtract(APInt(16, 4)).isEmptySet());
EXPECT_EQ(Some.subtract(APInt(16, 4)),
ConstantSignedRange(APInt(16, 0x6), APInt(16, 0xaa6)));
EXPECT_EQ(Wrap.subtract(APInt(16, 4)),
ConstantSignedRange(APInt(16, 0xaa6), APInt(16, 0x6)));
EXPECT_EQ(One.subtract(APInt(16, 4)),
ConstantSignedRange(APInt(16, 0x6)));
EXPECT_TRUE(Full.smax(Full).isFullSet());
EXPECT_TRUE(Full.smax(Empty).isEmptySet());
EXPECT_TRUE(Full.smax(Some).isFullSet());
EXPECT_TRUE(Full.smax(Wrap).isFullSet());
EXPECT_TRUE(Full.smax(One).isFullSet());
EXPECT_EQ(Empty.smax(Empty), Empty);
EXPECT_EQ(Empty.smax(Some), Empty);
EXPECT_EQ(Empty.smax(Wrap), Empty);
EXPECT_EQ(Empty.smax(One), Empty);
EXPECT_EQ(Some.smax(Some), Some);
EXPECT_EQ(Some.smax(Wrap), ConstantSignedRange(APInt(16, 0xa),
APInt(16, INT16_MIN)));
EXPECT_EQ(Some.smax(One), Some);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Wrap.smax(Wrap), Full);
EXPECT_EQ(Wrap.smax(One), ConstantSignedRange(APInt(16, 0xa),
APInt(16, INT16_MIN)));
EXPECT_EQ(One.smax(One), One);
EXPECT_EQ(Full.add(Full), Full);
EXPECT_EQ(Full.add(Empty), Empty);
EXPECT_EQ(Full.add(One), Full);
EXPECT_EQ(Full.add(Some), Full);
EXPECT_EQ(Full.add(Wrap), Full);
EXPECT_EQ(Empty.add(Empty), Empty);
EXPECT_EQ(Empty.add(One), Empty);
EXPECT_EQ(Empty.add(Some), Empty);
EXPECT_EQ(Empty.add(Wrap), Empty);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.add(One), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.add(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.add(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.add(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.add(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Wrap.add(Wrap), Full);
EXPECT_EQ(Full.multiply(Full), Full);
EXPECT_EQ(Full.multiply(Empty), Empty);
EXPECT_EQ(Full.multiply(One), Full);
EXPECT_EQ(Full.multiply(Some), Full);
EXPECT_EQ(Full.multiply(Wrap), Full);
EXPECT_EQ(Empty.multiply(Empty), Empty);
EXPECT_EQ(Empty.multiply(One), Empty);
EXPECT_EQ(Empty.multiply(Some), Empty);
EXPECT_EQ(Empty.multiply(Wrap), Empty);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.multiply(One), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.multiply(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.multiply(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.multiply(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.multiply(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Wrap.multiply(Wrap), Full);
EXPECT_EQ(Full.umax(Full), Full);
EXPECT_EQ(Full.umax(Empty), Empty);
EXPECT_EQ(Full.umax(One), Full);
EXPECT_EQ(Full.umax(Some), Full);
EXPECT_EQ(Full.umax(Wrap), Full);
EXPECT_EQ(Empty.umax(Empty), Empty);
EXPECT_EQ(Empty.umax(One), Empty);
EXPECT_EQ(Empty.umax(Some), Empty);
EXPECT_EQ(Empty.umax(Wrap), Empty);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.umax(One), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.umax(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(One.umax(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.umax(Some), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Some.umax(Wrap), Full);
// TODO: ConstantSignedRange is currently over-conservative here.
EXPECT_EQ(Wrap.umax(Wrap), Full);
}
} // anonymous namespace