[PATCH] D60952: [ConstantRange] Add urem support
Nikita Popov via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 21 13:04:24 PDT 2019
nikic created this revision.
nikic added a reviewer: lebedev.ri.
Herald added subscribers: llvm-commits, hiraditya.
Herald added a project: LLVM.
Add urem support to ConstantRange, so we can handle in in LVI. This is an approximate implementation that tries to capture the most useful conditions: If the LHS is always strictly smaller than the RHS, then the urem is a no-op and the result is the same as the LHS range. Otherwise the lower bound is zero and the upper bound is min(LHSMax, RHSMax - 1).
Repository:
rL LLVM
https://reviews.llvm.org/D60952
Files:
llvm/include/llvm/IR/ConstantRange.h
llvm/lib/IR/ConstantRange.cpp
llvm/unittests/IR/ConstantRangeTest.cpp
Index: llvm/unittests/IR/ConstantRangeTest.cpp
===================================================================
--- llvm/unittests/IR/ConstantRangeTest.cpp
+++ llvm/unittests/IR/ConstantRangeTest.cpp
@@ -759,6 +759,33 @@
EXPECT_EQ(Wrap.udiv(Wrap), Full);
}
+TEST_F(ConstantRangeTest, URem) {
+ EXPECT_EQ(Full.urem(Empty), Empty);
+ EXPECT_EQ(Empty.urem(Full), Empty);
+ // urem by zero is poison.
+ EXPECT_EQ(Full.urem(ConstantRange(APInt(16, 0))), Empty);
+ // urem by full range doesn't contain MaxValue.
+ EXPECT_EQ(Full.urem(Full), ConstantRange(APInt(16, 0), APInt(16, 0xffff)));
+ // urem is upper bounded by maximum RHS minus one.
+ EXPECT_EQ(Full.urem(ConstantRange(APInt(16, 0), APInt(16, 123))),
+ ConstantRange(APInt(16, 0), APInt(16, 122)));
+ // urem is upper bounded by maximum LHS.
+ EXPECT_EQ(ConstantRange(APInt(16, 0), APInt(16, 123)).urem(Full),
+ ConstantRange(APInt(16, 0), APInt(16, 123)));
+ // If the LHS is always lower than the RHS, the result is the LHS.
+ EXPECT_EQ(ConstantRange(APInt(16, 10), APInt(16, 20))
+ .urem(ConstantRange(APInt(16, 20), APInt(16, 30))),
+ ConstantRange(APInt(16, 10), APInt(16, 20)));
+ // It has to be strictly lower, otherwise the top value may wrap to zero.
+ EXPECT_EQ(ConstantRange(APInt(16, 10), APInt(16, 20))
+ .urem(ConstantRange(APInt(16, 19), APInt(16, 30))),
+ ConstantRange(APInt(16, 0), APInt(16, 20)));
+ // [12, 14] % 10 is [2, 4], but we conservatively compute [0, 9].
+ EXPECT_EQ(ConstantRange(APInt(16, 12), APInt(16, 15))
+ .urem(ConstantRange(APInt(16, 10))),
+ ConstantRange(APInt(16, 0), APInt(16, 10)));
+}
+
TEST_F(ConstantRangeTest, Shl) {
ConstantRange Some2(APInt(16, 0xfff), APInt(16, 0x8000));
ConstantRange WrapNullMax(APInt(16, 0x1), APInt(16, 0x0));
Index: llvm/lib/IR/ConstantRange.cpp
===================================================================
--- llvm/lib/IR/ConstantRange.cpp
+++ llvm/lib/IR/ConstantRange.cpp
@@ -794,6 +794,8 @@
return multiply(Other);
case Instruction::UDiv:
return udiv(Other);
+ case Instruction::URem:
+ return urem(Other);
case Instruction::Shl:
return shl(Other);
case Instruction::LShr:
@@ -991,6 +993,18 @@
return getNonEmpty(std::move(Lower), std::move(Upper));
}
+ConstantRange ConstantRange::urem(const ConstantRange &RHS) const {
+ if (isEmptySet() || RHS.isEmptySet() || RHS.getUnsignedMax().isNullValue())
+ return getEmpty();
+
+ // L % R for L < R is L.
+ APInt Lower = getUnsignedMax().ult(RHS.getUnsignedMin())
+ ? getUnsignedMin() : APInt::getNullValue(getBitWidth());
+ // L % R is <= L and < R.
+ APInt Upper = APIntOps::umin(getUnsignedMax(), RHS.getUnsignedMax() - 1) + 1;
+ return getNonEmpty(std::move(Lower), std::move(Upper));
+}
+
ConstantRange
ConstantRange::binaryAnd(const ConstantRange &Other) const {
if (isEmptySet() || Other.isEmptySet())
Index: llvm/include/llvm/IR/ConstantRange.h
===================================================================
--- llvm/include/llvm/IR/ConstantRange.h
+++ llvm/include/llvm/IR/ConstantRange.h
@@ -356,6 +356,11 @@
/// \p Other.
ConstantRange udiv(const ConstantRange &Other) const;
+ /// Return a new range representing the possible values resulting
+ /// from an unsigned remainder operation of a value in this range and a
+ /// value in \p Other.
+ ConstantRange urem(const ConstantRange &Other) const;
+
/// Return a new range representing the possible values resulting
/// from a binary-and of a value in this range by a value in \p Other.
ConstantRange binaryAnd(const ConstantRange &Other) const;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D60952.196012.patch
Type: text/x-patch
Size: 3703 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190421/f109e3fe/attachment.bin>
More information about the llvm-commits
mailing list