[ConstantRange] Generalize makeGuaranteedNoWrapRegion to work on ranges

This will be used in a later patch to ScalarEvolution.  Right now only
the unit tests exercise the newly added code.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@262637 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2016-03-03 18:31:16 +00:00
parent b76d92e4ad
commit 1d754782e0
3 changed files with 89 additions and 22 deletions

View File

@ -82,24 +82,26 @@ public:
static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
const ConstantRange &Other);
/// Return the largest range containing all X such that "X BinOpC C" is
/// guaranteed not to wrap (overflow).
/// Return the largest range containing all X such that "X BinOpC Y" is
/// guaranteed not to wrap (overflow) for all Y in Other.
///
/// NB! The returned set does *not* contain **all** possible values of X for
/// which "X BinOpC C" does not wrap -- some viable values of X may be
/// which "X BinOpC Y" does not wrap -- some viable values of X may be
/// missing, so you cannot use this to contrain X's range. E.g. in the last
/// example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2), but (-2)
/// is not in the set returned.
///
/// Example:
/// Examples:
/// typedef OverflowingBinaryOperator OBO;
/// makeNoWrapRegion(Add, i8 1, OBO::NoSignedWrap) == [-128, 127)
/// makeNoWrapRegion(Add, i8 1, OBO::NoUnsignedWrap) == [0, -1)
/// makeNoWrapRegion(Add, i8 0, OBO::NoUnsignedWrap) == Full Set
/// makeNoWrapRegion(Add, i8 1, OBO::NoUnsignedWrap | OBO::NoSignedWrap) ==
/// [0,INT_MAX)
/// #define MGNR makeGuaranteedNoWrapRegion
/// MGNR(Add, [i8 1, 2), OBO::NoSignedWrap) == [-128, 127)
/// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap) == [0, -1)
/// MGNR(Add, [i8 0, 1), OBO::NoUnsignedWrap) == Full Set
/// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap)
/// == [0,INT_MAX)
/// MGNR(Add, [i8 -1, 6), OBO::NoSignedWrap) == [INT_MIN+1, INT_MAX-4)
static ConstantRange makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
const APInt &C,
const ConstantRange &Other,
unsigned NoWrapKind);
/// Return the lower value for this range.

View File

@ -129,7 +129,8 @@ ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
ConstantRange
ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
const APInt &C, unsigned NoWrapKind) {
const ConstantRange &Other,
unsigned NoWrapKind) {
typedef OverflowingBinaryOperator OBO;
// Computes the intersection of CR0 and CR1. It is different from
@ -149,29 +150,36 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
NoWrapKind == (OBO::NoUnsignedWrap | OBO::NoSignedWrap)) &&
"NoWrapKind invalid!");
unsigned BitWidth = C.getBitWidth();
unsigned BitWidth = Other.getBitWidth();
if (BinOp != Instruction::Add)
// Conservative answer: empty set
return ConstantRange(BitWidth, false);
if (C.isMinValue())
// Full set: nothing signed / unsigned wraps when added to 0.
return ConstantRange(BitWidth);
if (auto *C = Other.getSingleElement())
if (C->isMinValue())
// Full set: nothing signed / unsigned wraps when added to 0.
return ConstantRange(BitWidth);
ConstantRange Result(BitWidth);
if (NoWrapKind & OBO::NoUnsignedWrap)
Result = SubsetIntersect(Result,
ConstantRange(APInt::getNullValue(BitWidth), -C));
Result =
SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth),
-Other.getUnsignedMax()));
if (NoWrapKind & OBO::NoSignedWrap) {
if (C.isStrictlyPositive())
APInt SignedMin = Other.getSignedMin();
APInt SignedMax = Other.getSignedMax();
if (SignedMax.isStrictlyPositive())
Result = SubsetIntersect(
Result, ConstantRange(APInt::getSignedMinValue(BitWidth),
APInt::getSignedMinValue(BitWidth) - C));
else
Result,
ConstantRange(APInt::getSignedMinValue(BitWidth),
APInt::getSignedMinValue(BitWidth) - SignedMax));
if (SignedMin.isNegative())
Result = SubsetIntersect(
Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - C,
Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin,
APInt::getSignedMinValue(BitWidth)));
}

View File

@ -657,6 +657,63 @@ TEST(ConstantRange, MakeOverflowingRegion) {
EXPECT_FALSE(Overflow);
}
}
auto NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
OBO::NoSignedWrap);
EXPECT_TRUE(NSWForAllValues.isSingleElement() &&
NSWForAllValues.getSingleElement()->isMinValue());
auto NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
OBO::NoUnsignedWrap);
EXPECT_TRUE(NUWForAllValues.isSingleElement() &&
NSWForAllValues.getSingleElement()->isMinValue());
auto NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
OBO::NoUnsignedWrap | OBO::NoSignedWrap);
EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() &&
NSWForAllValues.getSingleElement()->isMinValue());
ConstantRange OneToFive(APInt(32, 1), APInt(32, 6));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, OneToFive, OBO::NoSignedWrap),
ConstantRange(APInt::getSignedMinValue(32),
APInt::getSignedMaxValue(32) - 4));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, OneToFive, OBO::NoUnsignedWrap),
ConstantRange(APInt::getMinValue(32), APInt::getMinValue(32) - 5));
EXPECT_EQ(
ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
ConstantRange(APInt::getMinValue(32), APInt::getSignedMaxValue(32) - 4));
ConstantRange MinusFiveToMinusTwo(APInt(32, -5), APInt(32, -1));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusFiveToMinusTwo, OBO::NoSignedWrap),
ConstantRange(APInt::getSignedMinValue(32) + 5,
APInt::getSignedMinValue(32)));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusFiveToMinusTwo, OBO::NoUnsignedWrap),
ConstantRange(APInt(32, 0), APInt(32, 2)));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusFiveToMinusTwo,
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
ConstantRange(APInt(32, 0), APInt(32, 2)));
ConstantRange MinusOneToOne(APInt(32, -1), APInt(32, 2));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusOneToOne, OBO::NoSignedWrap),
ConstantRange(APInt::getSignedMinValue(32) + 1,
APInt::getSignedMinValue(32) - 1));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusOneToOne, OBO::NoUnsignedWrap),
ConstantRange(APInt(32, 0), APInt(32, 1)));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, MinusOneToOne,
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
ConstantRange(APInt(32, 0), APInt(32, 1)));
}
} // anonymous namespace