forked from OSchip/llvm-project
[ConstantRange] Support subtraction in makeGuaranteedNoWrapRegion.
Previously ConstantRange::makeGuaranteedNoWrapRegion only handled addition. This adds support for subtraction. Differential Revision: https://reviews.llvm.org/D40036 llvm-svn: 319806
This commit is contained in:
parent
3b4a475c37
commit
c32b0fc249
|
@ -96,9 +96,9 @@ public:
|
|||
///
|
||||
/// NB! The returned set does *not* contain **all** possible values of X for
|
||||
/// which "X BinOpC Y" does not wrap -- some viable values of X may be
|
||||
/// missing, so you cannot use this to constrain 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.
|
||||
/// missing, so you cannot use this to constrain X's range. E.g. in the
|
||||
/// fourth example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2),
|
||||
/// but (-2) is not in the set returned.
|
||||
///
|
||||
/// Examples:
|
||||
/// typedef OverflowingBinaryOperator OBO;
|
||||
|
@ -109,6 +109,10 @@ public:
|
|||
/// 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)
|
||||
/// MGNR(Sub, [i8 1, 2), OBO::NoSignedWrap) == [-127, 128)
|
||||
/// MGNR(Sub, [i8 1, 2), OBO::NoUnsignedWrap) == [1, 0)
|
||||
/// MGNR(Sub, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap)
|
||||
/// == [1,INT_MAX)
|
||||
static ConstantRange makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
|
||||
const ConstantRange &Other,
|
||||
unsigned NoWrapKind);
|
||||
|
|
|
@ -199,39 +199,63 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
|
|||
"NoWrapKind invalid!");
|
||||
|
||||
unsigned BitWidth = Other.getBitWidth();
|
||||
if (BinOp != Instruction::Add)
|
||||
ConstantRange Result(BitWidth);
|
||||
|
||||
switch (BinOp) {
|
||||
default:
|
||||
// Conservative answer: empty set
|
||||
return ConstantRange(BitWidth, false);
|
||||
|
||||
if (auto *C = Other.getSingleElement())
|
||||
if (C->isNullValue())
|
||||
// Full set: nothing signed / unsigned wraps when added to 0.
|
||||
return ConstantRange(BitWidth);
|
||||
case Instruction::Add:
|
||||
if (auto *C = Other.getSingleElement())
|
||||
if (C->isNullValue())
|
||||
// Full set: nothing signed / unsigned wraps when added to 0.
|
||||
return ConstantRange(BitWidth);
|
||||
if (NoWrapKind & OBO::NoUnsignedWrap)
|
||||
Result =
|
||||
SubsetIntersect(Result, 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,
|
||||
ConstantRange(APInt::getSignedMinValue(BitWidth),
|
||||
APInt::getSignedMinValue(BitWidth) - SignedMax));
|
||||
if (SignedMin.isNegative())
|
||||
Result = SubsetIntersect(
|
||||
Result,
|
||||
ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin,
|
||||
APInt::getSignedMinValue(BitWidth)));
|
||||
}
|
||||
return Result;
|
||||
|
||||
ConstantRange Result(BitWidth);
|
||||
|
||||
if (NoWrapKind & OBO::NoUnsignedWrap)
|
||||
Result =
|
||||
SubsetIntersect(Result, 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,
|
||||
ConstantRange(APInt::getSignedMinValue(BitWidth),
|
||||
APInt::getSignedMinValue(BitWidth) - SignedMax));
|
||||
|
||||
if (SignedMin.isNegative())
|
||||
Result = SubsetIntersect(
|
||||
Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin,
|
||||
APInt::getSignedMinValue(BitWidth)));
|
||||
case Instruction::Sub:
|
||||
if (auto *C = Other.getSingleElement())
|
||||
if (C->isNullValue())
|
||||
// Full set: nothing signed / unsigned wraps when subtracting 0.
|
||||
return ConstantRange(BitWidth);
|
||||
if (NoWrapKind & OBO::NoUnsignedWrap)
|
||||
Result =
|
||||
SubsetIntersect(Result, ConstantRange(Other.getUnsignedMax(),
|
||||
APInt::getMinValue(BitWidth)));
|
||||
if (NoWrapKind & OBO::NoSignedWrap) {
|
||||
const APInt &SignedMin = Other.getSignedMin();
|
||||
const APInt &SignedMax = Other.getSignedMax();
|
||||
if (SignedMax.isStrictlyPositive())
|
||||
Result = SubsetIntersect(
|
||||
Result,
|
||||
ConstantRange(APInt::getSignedMinValue(BitWidth) + SignedMax,
|
||||
APInt::getSignedMinValue(BitWidth)));
|
||||
if (SignedMin.isNegative())
|
||||
Result = SubsetIntersect(
|
||||
Result,
|
||||
ConstantRange(APInt::getSignedMinValue(BitWidth),
|
||||
APInt::getSignedMinValue(BitWidth) + SignedMin));
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool ConstantRange::isFullSet() const {
|
||||
|
|
|
@ -715,24 +715,102 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
|
|||
}
|
||||
}
|
||||
|
||||
for (int Const : {0, -1, -2, 1, 2, IntMin4Bits, IntMax4Bits}) {
|
||||
APInt C(4, Const, true /* = isSigned */);
|
||||
|
||||
auto NUWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, C, OBO::NoUnsignedWrap);
|
||||
|
||||
EXPECT_FALSE(NUWRegion.isEmptySet());
|
||||
|
||||
auto NSWRegion = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, C, OBO::NoSignedWrap);
|
||||
|
||||
EXPECT_FALSE(NSWRegion.isEmptySet());
|
||||
|
||||
auto NoWrapRegion = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, C, OBO::NoSignedWrap | OBO::NoUnsignedWrap);
|
||||
|
||||
EXPECT_FALSE(NoWrapRegion.isEmptySet());
|
||||
EXPECT_TRUE(NUWRegion.intersectWith(NSWRegion).contains(NoWrapRegion));
|
||||
|
||||
for (APInt I = NUWRegion.getLower(), E = NUWRegion.getUpper(); I != E;
|
||||
++I) {
|
||||
bool Overflow = false;
|
||||
(void)I.usub_ov(C, Overflow);
|
||||
EXPECT_FALSE(Overflow);
|
||||
}
|
||||
|
||||
for (APInt I = NSWRegion.getLower(), E = NSWRegion.getUpper(); I != E;
|
||||
++I) {
|
||||
bool Overflow = false;
|
||||
(void)I.ssub_ov(C, Overflow);
|
||||
EXPECT_FALSE(Overflow);
|
||||
}
|
||||
|
||||
for (APInt I = NoWrapRegion.getLower(), E = NoWrapRegion.getUpper(); I != E;
|
||||
++I) {
|
||||
bool Overflow = false;
|
||||
|
||||
(void)I.ssub_ov(C, Overflow);
|
||||
EXPECT_FALSE(Overflow);
|
||||
|
||||
(void)I.usub_ov(C, Overflow);
|
||||
EXPECT_FALSE(Overflow);
|
||||
}
|
||||
}
|
||||
|
||||
auto NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoSignedWrap);
|
||||
EXPECT_TRUE(NSWForAllValues.isSingleElement() &&
|
||||
NSWForAllValues.getSingleElement()->isMinValue());
|
||||
|
||||
NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoSignedWrap);
|
||||
EXPECT_TRUE(NSWForAllValues.isSingleElement() &&
|
||||
NSWForAllValues.getSingleElement()->isMaxValue());
|
||||
|
||||
auto NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoUnsignedWrap);
|
||||
EXPECT_TRUE(NUWForAllValues.isSingleElement() &&
|
||||
NUWForAllValues.getSingleElement()->isMinValue());
|
||||
|
||||
NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoUnsignedWrap);
|
||||
EXPECT_TRUE(NUWForAllValues.isSingleElement() &&
|
||||
NUWForAllValues.getSingleElement()->isMaxValue());
|
||||
|
||||
auto NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap);
|
||||
EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() &&
|
||||
NUWAndNSWForAllValues.getSingleElement()->isMinValue());
|
||||
|
||||
NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, ConstantRange(32, /* isFullSet = */ true),
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap);
|
||||
EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() &&
|
||||
NUWAndNSWForAllValues.getSingleElement()->isMaxValue());
|
||||
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, APInt(32, 0), OBO::NoUnsignedWrap).isFullSet());
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, APInt(32, 0), OBO::NoSignedWrap).isFullSet());
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, APInt(32, 0),
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap).isFullSet());
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, APInt(32, 0), OBO::NoUnsignedWrap).isFullSet());
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, APInt(32, 0), OBO::NoSignedWrap).isFullSet());
|
||||
EXPECT_TRUE(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, APInt(32, 0),
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap).isFullSet());
|
||||
|
||||
ConstantRange OneToFive(APInt(32, 1), APInt(32, 6));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, OneToFive, OBO::NoSignedWrap),
|
||||
|
@ -745,6 +823,17 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
|
|||
ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32), APInt::getSignedMaxValue(32) - 4));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, OneToFive, OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getSignedMinValue(32) + 5,
|
||||
APInt::getSignedMinValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, OneToFive, OBO::NoUnsignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32) + 5, APInt::getMinValue(32)));
|
||||
EXPECT_EQ(
|
||||
ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32) + 5, APInt::getSignedMinValue(32)));
|
||||
|
||||
ConstantRange MinusFiveToMinusTwo(APInt(32, -5), APInt(32, -1));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
|
@ -758,6 +847,19 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
|
|||
Instruction::Add, MinusFiveToMinusTwo,
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt(32, 0), APInt(32, 2)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusFiveToMinusTwo, OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getSignedMinValue(32),
|
||||
APInt::getSignedMaxValue(32) - 4));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusFiveToMinusTwo, OBO::NoUnsignedWrap),
|
||||
ConstantRange(APInt::getMaxValue(32) - 1,
|
||||
APInt::getMinValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusFiveToMinusTwo,
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getMaxValue(32) - 1,
|
||||
APInt::getMinValue(32)));
|
||||
|
||||
ConstantRange MinusOneToOne(APInt(32, -1), APInt(32, 2));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
|
@ -771,6 +873,43 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
|
|||
Instruction::Add, MinusOneToOne,
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt(32, 0), APInt(32, 1)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusOneToOne, OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getSignedMinValue(32) + 1,
|
||||
APInt::getSignedMinValue(32) - 1));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusOneToOne, OBO::NoUnsignedWrap),
|
||||
ConstantRange(APInt::getMaxValue(32),
|
||||
APInt::getMinValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, MinusOneToOne,
|
||||
OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getMaxValue(32),
|
||||
APInt::getMinValue(32)));
|
||||
|
||||
ConstantRange One(APInt(32, 1), APInt(32, 2));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, One, OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getSignedMinValue(32),
|
||||
APInt::getSignedMaxValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, One, OBO::NoUnsignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32), APInt::getMaxValue(32)));
|
||||
EXPECT_EQ(
|
||||
ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Add, One, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt(32, 0), APInt::getSignedMaxValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, One, OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getSignedMinValue(32) + 1,
|
||||
APInt::getSignedMinValue(32)));
|
||||
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, One, OBO::NoUnsignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32) + 1, APInt::getMinValue(32)));
|
||||
EXPECT_EQ(
|
||||
ConstantRange::makeGuaranteedNoWrapRegion(
|
||||
Instruction::Sub, One, OBO::NoUnsignedWrap | OBO::NoSignedWrap),
|
||||
ConstantRange(APInt::getMinValue(32) + 1, APInt::getSignedMinValue(32)));
|
||||
}
|
||||
|
||||
TEST(ConstantRange, GetEquivalentICmp) {
|
||||
|
|
Loading…
Reference in New Issue