From: Nikita Popov Date: Thu, 30 Jul 2020 20:47:33 +0000 (+0200) Subject: [ConstantRange] Support abs with poison flag X-Git-Tag: llvmorg-13-init~16238 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=94f8120cb9d368602df5aefa32211e001338e296;p=platform%2Fupstream%2Fllvm.git [ConstantRange] Support abs with poison flag This just adds the ConstantRange support, including exhaustive testing. It's not wired up to the IR intrinsic flag yet. --- diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index a027292..318532b 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -464,8 +464,9 @@ public: ConstantRange inverse() const; /// Calculate absolute value range. If the original range contains signed - /// min, then the resulting range will also contain signed min. - ConstantRange abs() const; + /// min, then the resulting range will contain signed min if and only if + /// \p IntMinIsPoison is false. + ConstantRange abs(bool IntMinIsPoison = false) const; /// Represents whether an operation on the given constant range is known to /// always or never overflow. diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index d379140..6e0b5a0 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -1464,7 +1464,7 @@ ConstantRange ConstantRange::inverse() const { return ConstantRange(Upper, Lower); } -ConstantRange ConstantRange::abs() const { +ConstantRange ConstantRange::abs(bool IntMinIsPoison) const { if (isEmptySet()) return getEmpty(); @@ -1476,12 +1476,23 @@ ConstantRange ConstantRange::abs() const { else Lo = APIntOps::umin(Lower, -Upper + 1); - // SignedMin is included in the result range. - return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); + // If SignedMin is not poison, then it is included in the result range. + if (IntMinIsPoison) + return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth())); + else + return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); } APInt SMin = getSignedMin(), SMax = getSignedMax(); + // Skip SignedMin if it is poison. + if (IntMinIsPoison && SMin.isMinSignedValue()) { + // The range may become empty if it *only* contains SignedMin. + if (SMax.isMinSignedValue()) + return getEmpty(); + ++SMin; + } + // All non-negative. if (SMin.isNonNegative()) return *this; diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 4d19dd5..8bcc6ef 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -60,6 +60,35 @@ static void ForeachNumInConstantRange(const ConstantRange &CR, Fn TestFn) { } template +static void TestUnsignedUnaryOpExhaustive( + Fn1 RangeFn, Fn2 IntFn, bool SkipSignedIntMin = false) { + unsigned Bits = 4; + EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) { + APInt Min = APInt::getMaxValue(Bits); + APInt Max = APInt::getMinValue(Bits); + ForeachNumInConstantRange(CR, [&](const APInt &N) { + if (SkipSignedIntMin && N.isMinSignedValue()) + return; + + APInt AbsN = IntFn(N); + if (AbsN.ult(Min)) + Min = AbsN; + if (AbsN.ugt(Max)) + Max = AbsN; + }); + + ConstantRange ResultCR = RangeFn(CR); + if (Min.ugt(Max)) { + EXPECT_TRUE(ResultCR.isEmptySet()); + return; + } + + ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1); + EXPECT_EQ(Exact, ResultCR); + }); +} + +template static void TestUnsignedBinOpExhaustive( Fn1 RangeFn, Fn2 IntFn, bool SkipZeroRHS = false, bool CorrectnessOnly = false) { @@ -2270,29 +2299,16 @@ TEST_F(ConstantRangeTest, SShlSat) { } TEST_F(ConstantRangeTest, Abs) { - unsigned Bits = 4; - EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) { - // We're working with unsigned integers here, because it makes the signed - // min case non-wrapping. - APInt Min = APInt::getMaxValue(Bits); - APInt Max = APInt::getMinValue(Bits); - ForeachNumInConstantRange(CR, [&](const APInt &N) { - APInt AbsN = N.abs(); - if (AbsN.ult(Min)) - Min = AbsN; - if (AbsN.ugt(Max)) - Max = AbsN; - }); - - ConstantRange AbsCR = CR.abs(); - if (Min.ugt(Max)) { - EXPECT_TRUE(AbsCR.isEmptySet()); - return; - } - - ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1); - EXPECT_EQ(Exact, AbsCR); - }); + // We're working with unsigned integers here, because it makes the signed + // min case non-wrapping. + TestUnsignedUnaryOpExhaustive( + [](const ConstantRange &CR) { return CR.abs(); }, + [](const APInt &N) { return N.abs(); }); + + TestUnsignedUnaryOpExhaustive( + [](const ConstantRange &CR) { return CR.abs(/*IntMinIsPoison=*/true); }, + [](const APInt &N) { return N.abs(); }, + /*SkipSignedIntMin=*/true); } TEST_F(ConstantRangeTest, castOps) {