Skip to content

Commit c0fa4ec

Browse files
committed
[ConstantRange] Add abs() support
Add support for abs() to ConstantRange. This will allow to handle SPF_ABS select flavor in LVI and will also come in handy as a primitive for the srem implementation. The implementation is slightly tricky, because a) abs of signed min is signed min and b) sign-wrapped ranges may have an abs() that is smaller than a full range, so we need to explicitly handle them. Differential Revision: https://reviews.llvm.org/D61084 llvm-svn: 359321
1 parent f30f261 commit c0fa4ec

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

llvm/include/llvm/IR/ConstantRange.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ class LLVM_NODISCARD ConstantRange {
397397
/// Return a new range that is the logical not of the current set.
398398
ConstantRange inverse() const;
399399

400+
/// Calculate absolute value range. If the original range contains signed
401+
/// min, then the resulting range will also contain signed min.
402+
ConstantRange abs() const;
403+
400404
/// Represents whether an operation on the given constant range is known to
401405
/// always or never overflow.
402406
enum class OverflowResult { AlwaysOverflows, MayOverflow, NeverOverflows };

llvm/lib/IR/ConstantRange.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,37 @@ ConstantRange ConstantRange::inverse() const {
11561156
return ConstantRange(Upper, Lower);
11571157
}
11581158

1159+
ConstantRange ConstantRange::abs() const {
1160+
if (isEmptySet())
1161+
return getEmpty();
1162+
1163+
if (isSignWrappedSet()) {
1164+
APInt Lo;
1165+
// Check whether the range crosses zero.
1166+
if (Upper.isStrictlyPositive() || !Lower.isStrictlyPositive())
1167+
Lo = APInt::getNullValue(getBitWidth());
1168+
else
1169+
Lo = APIntOps::umin(Lower, -Upper + 1);
1170+
1171+
// SignedMin is included in the result range.
1172+
return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1);
1173+
}
1174+
1175+
APInt SMin = getSignedMin(), SMax = getSignedMax();
1176+
1177+
// All non-negative.
1178+
if (SMin.isNonNegative())
1179+
return *this;
1180+
1181+
// All negative.
1182+
if (SMax.isNegative())
1183+
return ConstantRange(-SMax, -SMin + 1);
1184+
1185+
// Range crosses zero.
1186+
return ConstantRange(APInt::getNullValue(getBitWidth()),
1187+
APIntOps::umax(-SMin, SMax) + 1);
1188+
}
1189+
11591190
ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow(
11601191
const ConstantRange &Other) const {
11611192
if (isEmptySet() || Other.isEmptySet())

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,4 +1797,30 @@ TEST_F(ConstantRangeTest, SSubSat) {
17971797
});
17981798
}
17991799

1800+
TEST_F(ConstantRangeTest, Abs) {
1801+
unsigned Bits = 4;
1802+
EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) {
1803+
// We're working with unsigned integers here, because it makes the signed
1804+
// min case non-wrapping.
1805+
APInt Min = APInt::getMaxValue(Bits);
1806+
APInt Max = APInt::getMinValue(Bits);
1807+
ForeachNumInConstantRange(CR, [&](const APInt &N) {
1808+
APInt AbsN = N.abs();
1809+
if (AbsN.ult(Min))
1810+
Min = AbsN;
1811+
if (AbsN.ugt(Max))
1812+
Max = AbsN;
1813+
});
1814+
1815+
ConstantRange AbsCR = CR.abs();
1816+
if (Min.ugt(Max)) {
1817+
EXPECT_TRUE(AbsCR.isEmptySet());
1818+
return;
1819+
}
1820+
1821+
ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1);
1822+
EXPECT_EQ(Exact, AbsCR);
1823+
});
1824+
}
1825+
18001826
} // anonymous namespace

0 commit comments

Comments
 (0)