1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[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.
This commit is contained in:
Nikita Popov 2020-07-30 22:47:33 +02:00
parent c1baeb79cd
commit 9bc2ea2f9d
3 changed files with 55 additions and 27 deletions

View File

@ -464,8 +464,9 @@ public:
ConstantRange inverse() const; ConstantRange inverse() const;
/// Calculate absolute value range. If the original range contains signed /// Calculate absolute value range. If the original range contains signed
/// min, then the resulting range will also contain signed min. /// min, then the resulting range will contain signed min if and only if
ConstantRange abs() const; /// \p IntMinIsPoison is false.
ConstantRange abs(bool IntMinIsPoison = false) const;
/// Represents whether an operation on the given constant range is known to /// Represents whether an operation on the given constant range is known to
/// always or never overflow. /// always or never overflow.

View File

@ -1464,7 +1464,7 @@ ConstantRange ConstantRange::inverse() const {
return ConstantRange(Upper, Lower); return ConstantRange(Upper, Lower);
} }
ConstantRange ConstantRange::abs() const { ConstantRange ConstantRange::abs(bool IntMinIsPoison) const {
if (isEmptySet()) if (isEmptySet())
return getEmpty(); return getEmpty();
@ -1476,12 +1476,23 @@ ConstantRange ConstantRange::abs() const {
else else
Lo = APIntOps::umin(Lower, -Upper + 1); Lo = APIntOps::umin(Lower, -Upper + 1);
// SignedMin is included in the result range. // If SignedMin is not poison, then it is included in the result range.
return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); if (IntMinIsPoison)
return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()));
else
return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1);
} }
APInt SMin = getSignedMin(), SMax = getSignedMax(); 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. // All non-negative.
if (SMin.isNonNegative()) if (SMin.isNonNegative())
return *this; return *this;

View File

@ -59,6 +59,35 @@ static void ForeachNumInConstantRange(const ConstantRange &CR, Fn TestFn) {
} }
} }
template<typename Fn1, typename Fn2>
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<typename Fn1, typename Fn2> template<typename Fn1, typename Fn2>
static void TestUnsignedBinOpExhaustive( static void TestUnsignedBinOpExhaustive(
Fn1 RangeFn, Fn2 IntFn, Fn1 RangeFn, Fn2 IntFn,
@ -2270,29 +2299,16 @@ TEST_F(ConstantRangeTest, SShlSat) {
} }
TEST_F(ConstantRangeTest, Abs) { TEST_F(ConstantRangeTest, Abs) {
unsigned Bits = 4; // We're working with unsigned integers here, because it makes the signed
EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) { // min case non-wrapping.
// We're working with unsigned integers here, because it makes the signed TestUnsignedUnaryOpExhaustive(
// min case non-wrapping. [](const ConstantRange &CR) { return CR.abs(); },
APInt Min = APInt::getMaxValue(Bits); [](const APInt &N) { return N.abs(); });
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(); TestUnsignedUnaryOpExhaustive(
if (Min.ugt(Max)) { [](const ConstantRange &CR) { return CR.abs(/*IntMinIsPoison=*/true); },
EXPECT_TRUE(AbsCR.isEmptySet()); [](const APInt &N) { return N.abs(); },
return; /*SkipSignedIntMin=*/true);
}
ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1);
EXPECT_EQ(Exact, AbsCR);
});
} }
TEST_F(ConstantRangeTest, castOps) { TEST_F(ConstantRangeTest, castOps) {