[PATCH] [ConstantRange] Teach multiply to be cleverer about signed ranges.
James Molloy
james.molloy at arm.com
Wed Feb 25 08:18:01 PST 2015
REPOSITORY
rL LLVM
http://reviews.llvm.org/D7789
Files:
include/llvm/IR/ConstantRange.h
lib/IR/ConstantRange.cpp
unittests/IR/ConstantRangeTest.cpp
Index: include/llvm/IR/ConstantRange.h
===================================================================
--- include/llvm/IR/ConstantRange.h
+++ include/llvm/IR/ConstantRange.h
@@ -208,8 +208,8 @@
ConstantRange sub(const ConstantRange &Other) const;
/// Return a new range representing the possible values resulting
- /// from a multiplication of a value in this range and a value in \p Other.
- /// TODO: This isn't fully implemented yet.
+ /// from a multiplication of a value in this range and a value in \p Other,
+ /// treating both this and \p Other as unsigned ranges.
ConstantRange multiply(const ConstantRange &Other) const;
/// Return a new range representing the possible values resulting
Index: lib/IR/ConstantRange.cpp
===================================================================
--- lib/IR/ConstantRange.cpp
+++ lib/IR/ConstantRange.cpp
@@ -587,14 +587,40 @@
if (isEmptySet() || Other.isEmptySet())
return ConstantRange(getBitWidth(), /*isFullSet=*/false);
+ // Multiplication is signedness-independent. However different ranges can be
+ // obtained depending on how the input ranges are treated. These different
+ // ranges are all conservatively correct, but one might be better than the
+ // other. We calculate two ranges; one treating the inputs as unsigned
+ // and the other signed, then return the smallest of these ranges.
+
+ // Unsigned range first.
APInt this_min = getUnsignedMin().zext(getBitWidth() * 2);
APInt this_max = getUnsignedMax().zext(getBitWidth() * 2);
APInt Other_min = Other.getUnsignedMin().zext(getBitWidth() * 2);
APInt Other_max = Other.getUnsignedMax().zext(getBitWidth() * 2);
ConstantRange Result_zext = ConstantRange(this_min * Other_min,
this_max * Other_max + 1);
- return Result_zext.truncate(getBitWidth());
+ ConstantRange UR = Result_zext.truncate(getBitWidth());
+
+ // Now the signed range. Because we could be dealing with negative numbers
+ // here, the lower bound is the smallest of the cartesian product of the
+ // lower and upper ranges; for example:
+ // [-1,4) * [-2,3) = min(-1*-2, -1*3, 4*-2, 4*3) = -8.
+ // Similarly for the upper bound, swapping min for max.
+
+ this_min = getSignedMin().sext(getBitWidth() * 2);
+ this_max = getSignedMax().sext(getBitWidth() * 2);
+ Other_min = Other.getSignedMin().sext(getBitWidth() * 2);
+ Other_max = Other.getSignedMax().sext(getBitWidth() * 2);
+
+ auto L = {this_min * Other_min, this_min * Other_max,
+ this_max * Other_min, this_max * Other_max};
+ auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); };
+ ConstantRange Result_sext(std::min(L, Compare), std::max(L, Compare) + 1);
+ ConstantRange SR = Result_sext.truncate(getBitWidth());
+
+ return UR.getSetSize().ult(SR.getSetSize()) ? UR : SR;
}
ConstantRange
Index: unittests/IR/ConstantRangeTest.cpp
===================================================================
--- unittests/IR/ConstantRangeTest.cpp
+++ unittests/IR/ConstantRangeTest.cpp
@@ -400,6 +400,13 @@
EXPECT_EQ(ConstantRange(APInt(4, 1), APInt(4, 6)).multiply(
ConstantRange(APInt(4, 6), APInt(4, 2))),
ConstantRange(4, /*isFullSet=*/true));
+
+ EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 0)).multiply(
+ ConstantRange(APInt(8, 252), APInt(8, 4))),
+ ConstantRange(APInt(8, 250), APInt(8, 9)));
+ EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 255)).multiply(
+ ConstantRange(APInt(8, 2), APInt(8, 4))),
+ ConstantRange(APInt(8, 250), APInt(8, 253)));
}
TEST_F(ConstantRangeTest, UMax) {
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D7789.20679.patch
Type: text/x-patch
Size: 3679 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150225/3c22cc97/attachment.bin>
More information about the llvm-commits
mailing list