Skip to content

Commit

Permalink
[ConstantRange] Disallow NUW | NSW in makeGuaranteedNoWrapRegion()
Browse files Browse the repository at this point in the history
As motivated in D60598, this drops support for specifying both NUW and
NSW in makeGuaranteedNoWrapRegion(). None of the users of this function
currently make use of this.

When both NUW and NSW are specified, the exact nowrap region has two
disjoint parts and makeGNWR() returns one of them. This result doesn't
seem to be useful for anything, but makes the semantics of the function
fuzzier.

Differential Revision: https://reviews.llvm.org/D60632

llvm-svn: 358340
  • Loading branch information
nikic committed Apr 13, 2019
1 parent 95e5f28 commit a96480e
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 136 deletions.
14 changes: 2 additions & 12 deletions llvm/include/llvm/IR/ConstantRange.h
Expand Up @@ -116,30 +116,20 @@ class LLVM_NODISCARD ConstantRange {
static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred,
const APInt &Other);

/// Return the largest range containing all X such that "X BinOpC Y" is
/// Return the exact range containing all X such that "X BinOpC Y" is
/// guaranteed not to wrap (overflow) for all Y in Other.
///
/// If only one of NoUnsignedWrap or NoSignedWrap is specified, the returned
/// range is exact: It contains *all* possible values of X for which
/// "X BinOpC Y" does not wrap. However, if both NUW and NSW are specified, it
/// may return only a subset of non-wrapping values. In this case the
/// returned region cannot be used 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.
/// NoWrapKind must be one of OBO::NoUnsignedWrap or OBO::NoSignedWrap.
///
/// Examples:
/// typedef OverflowingBinaryOperator OBO;
/// #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)
/// 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);
Expand Down
32 changes: 14 additions & 18 deletions llvm/lib/IR/ConstantRange.cpp
Expand Up @@ -214,8 +214,7 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
assert(Instruction::isBinaryOp(BinOp) && "Binary operators only!");

assert((NoWrapKind == OBO::NoSignedWrap ||
NoWrapKind == OBO::NoUnsignedWrap ||
NoWrapKind == (OBO::NoUnsignedWrap | OBO::NoSignedWrap)) &&
NoWrapKind == OBO::NoUnsignedWrap) &&
"NoWrapKind invalid!");

unsigned BitWidth = Other.getBitWidth();
Expand All @@ -231,11 +230,12 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
if (C->isNullValue())
// Full set: nothing signed / unsigned wraps when added to 0.
return getFull(BitWidth);
if (NoWrapKind & OBO::NoUnsignedWrap)
Result =
SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth),
-Other.getUnsignedMax()));
if (NoWrapKind & OBO::NoSignedWrap) {

if (NoWrapKind == OBO::NoUnsignedWrap)
return ConstantRange(APInt::getNullValue(BitWidth),
-Other.getUnsignedMax());

if (NoWrapKind == OBO::NoSignedWrap) {
const APInt &SignedMin = Other.getSignedMin();
const APInt &SignedMax = Other.getSignedMax();
if (SignedMax.isStrictlyPositive())
Expand All @@ -256,11 +256,12 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
if (C->isNullValue())
// Full set: nothing signed / unsigned wraps when subtracting 0.
return getFull(BitWidth);
if (NoWrapKind & OBO::NoUnsignedWrap)
Result =
SubsetIntersect(Result, ConstantRange(Other.getUnsignedMax(),
APInt::getMinValue(BitWidth)));
if (NoWrapKind & OBO::NoSignedWrap) {

if (NoWrapKind == OBO::NoUnsignedWrap)
return ConstantRange(Other.getUnsignedMax(),
APInt::getMinValue(BitWidth));

if (NoWrapKind == OBO::NoSignedWrap) {
const APInt &SignedMin = Other.getSignedMin();
const APInt &SignedMax = Other.getSignedMax();
if (SignedMax.isStrictlyPositive())
Expand All @@ -275,13 +276,8 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
APInt::getSignedMinValue(BitWidth) + SignedMin));
}
return Result;
case Instruction::Mul: {
if (NoWrapKind == (OBO::NoSignedWrap | OBO::NoUnsignedWrap)) {
return SubsetIntersect(
makeGuaranteedNoWrapRegion(BinOp, Other, OBO::NoSignedWrap),
makeGuaranteedNoWrapRegion(BinOp, Other, OBO::NoUnsignedWrap));
}

case Instruction::Mul: {
// Equivalent to calling makeGuaranteedNoWrapRegion() on [V, V+1).
const bool Unsigned = NoWrapKind == OBO::NoUnsignedWrap;
const auto makeSingleValueRegion = [Unsigned,
Expand Down
106 changes: 0 additions & 106 deletions llvm/unittests/IR/ConstantRangeTest.cpp
Expand Up @@ -922,12 +922,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {

EXPECT_FALSE(NSWRegion.isEmptySet());

auto NoWrapRegion = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Add, 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;
Expand All @@ -941,17 +935,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
(void)I.sadd_ov(C, Overflow);
EXPECT_FALSE(Overflow);
}

for (APInt I = NoWrapRegion.getLower(), E = NoWrapRegion.getUpper(); I != E;
++I) {
bool Overflow = false;

(void)I.sadd_ov(C, Overflow);
EXPECT_FALSE(Overflow);

(void)I.uadd_ov(C, Overflow);
EXPECT_FALSE(Overflow);
}
}

for (int Const : {0, -1, -2, 1, 2, IntMin4Bits, IntMax4Bits}) {
Expand All @@ -967,12 +950,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {

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;
Expand All @@ -986,17 +963,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
(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(
Expand All @@ -1023,32 +989,14 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
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(
Expand All @@ -1058,21 +1006,13 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
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));
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(
Expand All @@ -1082,10 +1022,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
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)));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Sub, MinusFiveToMinusTwo, OBO::NoSignedWrap),
ConstantRange(APInt::getSignedMinValue(32),
Expand All @@ -1094,11 +1030,6 @@ TEST(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(
Expand All @@ -1108,10 +1039,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
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)));
EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Sub, MinusOneToOne, OBO::NoSignedWrap),
ConstantRange(APInt::getSignedMinValue(32) + 1,
Expand All @@ -1120,11 +1047,6 @@ TEST(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(
Expand All @@ -1134,21 +1056,13 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
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)));
}

template<typename Fn>
Expand Down Expand Up @@ -1342,26 +1256,6 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulSignedSingleValue) {
}
}

TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulUnsignedAndSignedSingleValue) {
typedef OverflowingBinaryOperator OBO;

for (uint64_t I = std::numeric_limits<uint8_t>::min();
I <= std::numeric_limits<uint8_t>::max(); I++) {
auto Range = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Mul, ConstantRange(APInt(8, I), APInt(8, I + 1)),
OBO::NoUnsignedWrap | OBO::NoSignedWrap);

for (uint64_t V = std::numeric_limits<uint8_t>::min();
V <= std::numeric_limits<uint8_t>::max(); V++) {
bool UOverflow;
(void)APInt(8, I).umul_ov(APInt(8, V), UOverflow);
bool SOverflow;
(void)APInt(8, I).smul_ov(APInt(8, V), SOverflow);
EXPECT_EQ(!(UOverflow || SOverflow), Range.contains(APInt(8, V)));
}
}
}

TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulUnsignedRange) {
typedef OverflowingBinaryOperator OBO;

Expand Down

0 comments on commit a96480e

Please sign in to comment.