diff options
author | Tim Shen <timshen91@gmail.com> | 2018-06-26 18:54:10 +0000 |
---|---|---|
committer | Tim Shen <timshen91@gmail.com> | 2018-06-26 18:54:10 +0000 |
commit | b32823cbe979a8115adb097d6ef0017b0e9a7f63 (patch) | |
tree | e1f3f170d78c3713e8b0b6e2309c036dccadcf9d | |
parent | 2c1a570aabc184e93f160992c3fe3eab8f884f74 (diff) | |
download | bcm5719-llvm-b32823cbe979a8115adb097d6ef0017b0e9a7f63.tar.gz bcm5719-llvm-b32823cbe979a8115adb097d6ef0017b0e9a7f63.zip |
[ConstantRange] Add support of mul in makeGuaranteedNoWrapRegion.
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
-rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 58 | ||||
-rw-r--r-- | llvm/unittests/IR/ConstantRangeTest.cpp | 99 |
2 files changed, 157 insertions, 0 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 157473f84f2..86cd24b2e31 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -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())); + } } } diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 351256d4993..c0a30f1b4d9 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -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 |