Skip to content

Commit

Permalink
[ConstantRange] Add support of mul in makeGuaranteedNoWrapRegion.
Browse files Browse the repository at this point in the history
Summary: This is trying to add support for r334428.

Reviewers: sanjoy

Subscribers: jlebar, hiraditya, bixia, llvm-commits

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

llvm-svn: 335646
  • Loading branch information
timshen91 committed Jun 26, 2018
1 parent 2c1a570 commit b32823c
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 0 deletions.
58 changes: 58 additions & 0 deletions llvm/lib/IR/ConstantRange.cpp
Expand Up @@ -255,6 +255,64 @@ 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));
}

// Equivalent to calling makeGuaranteedNoWrapRegion() on [V, V+1).
const bool Unsigned = NoWrapKind == OBO::NoUnsignedWrap;
const auto makeSingleValueRegion = [Unsigned,
BitWidth](APInt V) -> ConstantRange {
// Handle special case for 0, -1 and 1. See the last for reason why we
// specialize -1 and 1.
if (V == 0 || V.isOneValue())
return ConstantRange(BitWidth, true);

APInt MinValue, MaxValue;
if (Unsigned) {
MinValue = APInt::getMinValue(BitWidth);
MaxValue = APInt::getMaxValue(BitWidth);
} else {
MinValue = APInt::getSignedMinValue(BitWidth);
MaxValue = APInt::getSignedMaxValue(BitWidth);
}
// e.g. Returning [-127, 127], represented as [-127, -128).
if (!Unsigned && V.isAllOnesValue())
return ConstantRange(-MaxValue, MinValue);

APInt Lower, Upper;
if (!Unsigned && V.isNegative()) {
Lower = APIntOps::RoundingSDiv(MaxValue, V, APInt::Rounding::UP);
Upper = APIntOps::RoundingSDiv(MinValue, V, APInt::Rounding::DOWN);
} else if (Unsigned) {
Lower = APIntOps::RoundingUDiv(MinValue, V, APInt::Rounding::UP);
Upper = APIntOps::RoundingUDiv(MaxValue, V, APInt::Rounding::DOWN);
} else {
Lower = APIntOps::RoundingSDiv(MinValue, V, APInt::Rounding::UP);
Upper = APIntOps::RoundingSDiv(MaxValue, V, APInt::Rounding::DOWN);
}
if (Unsigned) {
Lower = Lower.zextOrSelf(BitWidth);
Upper = Upper.zextOrSelf(BitWidth);
} else {
Lower = Lower.sextOrSelf(BitWidth);
Upper = Upper.sextOrSelf(BitWidth);
}
// ConstantRange ctor take a half inclusive interval [Lower, Upper + 1).
// Upper + 1 is guanranteed not to overflow, because |divisor| > 1. 0, -1,
// and 1 are already handled as special cases.
return ConstantRange(Lower, Upper + 1);
};

if (Unsigned)
return makeSingleValueRegion(Other.getUnsignedMax());

return SubsetIntersect(makeSingleValueRegion(Other.getSignedMin()),
makeSingleValueRegion(Other.getSignedMax()));
}
}
}

Expand Down
99 changes: 99 additions & 0 deletions llvm/unittests/IR/ConstantRangeTest.cpp
Expand Up @@ -1021,4 +1021,103 @@ TEST(ConstantRange, GetEquivalentICmp) {
EXPECT_EQ(RHS, APInt(32, -1));
}

TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulUnsignedSingleValue) {
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);

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

TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulSignedSingleValue) {
typedef OverflowingBinaryOperator OBO;

for (int64_t I = std::numeric_limits<int8_t>::min();
I <= std::numeric_limits<int8_t>::max(); I++) {
auto Range = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Mul,
ConstantRange(APInt(8, I, /*isSigned=*/true),
APInt(8, I + 1, /*isSigned=*/true)),
OBO::NoSignedWrap);

for (int64_t V = std::numeric_limits<int8_t>::min();
V <= std::numeric_limits<int8_t>::max(); V++) {
bool Overflow;
(void)APInt(8, I, /*isSigned=*/true)
.smul_ov(APInt(8, V, /*isSigned=*/true), Overflow);
EXPECT_EQ(!Overflow, Range.contains(APInt(8, V, /*isSigned=*/true)));
}
}
}

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;

for (uint64_t Lo = std::numeric_limits<uint8_t>::min();
Lo <= std::numeric_limits<uint8_t>::max(); Lo++) {
for (uint64_t Hi = Lo; Hi <= std::numeric_limits<uint8_t>::max(); Hi++) {
EXPECT_EQ(
ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Mul, ConstantRange(APInt(8, Lo), APInt(8, Hi + 1)),
OBO::NoUnsignedWrap),
ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Mul, ConstantRange(APInt(8, Hi), APInt(8, Hi + 1)),
OBO::NoUnsignedWrap));
}
}
}

TEST(ConstantRange, MakeGuaranteedNoWrapRegionMulSignedRange) {
typedef OverflowingBinaryOperator OBO;

int Lo = -12, Hi = 16;
auto Range = ConstantRange::makeGuaranteedNoWrapRegion(
Instruction::Mul,
ConstantRange(APInt(8, Lo, /*isSigned=*/true),
APInt(8, Hi + 1, /*isSigned=*/true)),
OBO::NoSignedWrap);

for (int64_t V = std::numeric_limits<int8_t>::min();
V <= std::numeric_limits<int8_t>::max(); V++) {
bool AnyOverflow = false;
for (int64_t I = Lo; I <= Hi; I++) {
bool Overflow;
(void)APInt(8, I, /*isSigned=*/true)
.smul_ov(APInt(8, V, /*isSigned=*/true), Overflow);
AnyOverflow |= Overflow;
}
EXPECT_EQ(!AnyOverflow, Range.contains(APInt(8, V, /*isSigned=*/true)));
}
}

} // anonymous namespace

0 comments on commit b32823c

Please sign in to comment.