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;
/// 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.

View File

@ -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;

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>
static void TestUnsignedBinOpExhaustive(
Fn1 RangeFn, Fn2 IntFn,
@ -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;
});
// 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(); });
ConstantRange AbsCR = CR.abs();
if (Min.ugt(Max)) {
EXPECT_TRUE(AbsCR.isEmptySet());
return;
}
ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1);
EXPECT_EQ(Exact, AbsCR);
});
TestUnsignedUnaryOpExhaustive(
[](const ConstantRange &CR) { return CR.abs(/*IntMinIsPoison=*/true); },
[](const APInt &N) { return N.abs(); },
/*SkipSignedIntMin=*/true);
}
TEST_F(ConstantRangeTest, castOps) {