summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/IR/ConstantRange.h8
-rw-r--r--llvm/lib/IR/ConstantRange.cpp3
-rw-r--r--llvm/unittests/IR/ConstantRangeTest.cpp70
3 files changed, 76 insertions, 5 deletions
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index d98bf96a21c..d35e11abdd9 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -119,9 +119,11 @@ public:
/// Return the largest range containing all X such that "X BinOpC Y" is
/// guaranteed not to wrap (overflow) for all Y in Other.
///
- /// NB! The returned set does *not* contain **all** possible values of X for
- /// which "X BinOpC Y" does not wrap -- some viable values of X may be
- /// missing, so you cannot use this to constrain X's range. E.g. in the
+ /// If only one of NoUnsignedWrap or NoSignedWrap is specified, the returned
+ /// range is exact: It contains *all* possible values of X for which
+ /// "X BinOpC Y" does not wrap. However, if both NUW and NSW are specified, it
+ /// may return only a subset of non-wrapping values. In this case the
+ /// returned region cannot be used to constrain X's range. E.g. in the
/// fourth example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2),
/// but (-2) is not in the set returned.
///
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 35c2b0e2e2c..fe67059a892 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -869,8 +869,7 @@ ConstantRange::add(const ConstantRange &Other) const {
ConstantRange ConstantRange::addWithNoSignedWrap(const APInt &Other) const {
// Calculate the subset of this range such that "X + Other" is
// guaranteed not to wrap (overflow) for all X in this subset.
- // makeGuaranteedNoWrapRegion will produce an exact NSW range since we are
- // passing a single element range.
+ // makeGuaranteedNoWrapRegion will produce an exact NSW range.
auto NSWRange = ConstantRange::makeGuaranteedNoWrapRegion(BinaryOperator::Add,
ConstantRange(Other),
OverflowingBinaryOperator::NoSignedWrap);
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 6d1b512d229..322be45bb28 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1151,6 +1151,76 @@ TEST(ConstantRange, MakeGuaranteedNoWrapRegion) {
ConstantRange(APInt::getMinValue(32) + 1, APInt::getSignedMinValue(32)));
}
+template<typename Fn>
+void TestNoWrapRegionExhaustive(Instruction::BinaryOps BinOp,
+ unsigned NoWrapKind, Fn OverflowFn) {
+ // When using 4 bits this test needs ~3s on a debug build.
+ unsigned Bits = 3;
+ EnumerateTwoConstantRanges(Bits,
+ [&](const ConstantRange &CR1, const ConstantRange &CR2) {
+ if (CR2.isEmptySet())
+ return;
+
+ ConstantRange NoWrap =
+ ConstantRange::makeGuaranteedNoWrapRegion(BinOp, CR2, NoWrapKind);
+ ForeachNumInConstantRange(CR1, [&](const APInt &N1) {
+ bool NoOverflow = true;
+ ForeachNumInConstantRange(CR2, [&](const APInt &N2) {
+ if (OverflowFn(N1, N2))
+ NoOverflow = false;
+ });
+ EXPECT_EQ(NoOverflow, NoWrap.contains(N1));
+ });
+ });
+}
+
+// Show that makeGuaranteedNoWrapRegion is precise if only one of
+// NoUnsignedWrap or NoSignedWrap is used.
+TEST(ConstantRange, NoWrapRegionExhaustive) {
+ TestNoWrapRegionExhaustive(
+ Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.uadd_ov(N2, Overflow);
+ return Overflow;
+ });
+ TestNoWrapRegionExhaustive(
+ Instruction::Add, OverflowingBinaryOperator::NoSignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.sadd_ov(N2, Overflow);
+ return Overflow;
+ });
+ TestNoWrapRegionExhaustive(
+ Instruction::Sub, OverflowingBinaryOperator::NoUnsignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.usub_ov(N2, Overflow);
+ return Overflow;
+ });
+ TestNoWrapRegionExhaustive(
+ Instruction::Sub, OverflowingBinaryOperator::NoSignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.ssub_ov(N2, Overflow);
+ return Overflow;
+ });
+ TestNoWrapRegionExhaustive(
+ Instruction::Mul, OverflowingBinaryOperator::NoUnsignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.umul_ov(N2, Overflow);
+ return Overflow;
+ });
+ TestNoWrapRegionExhaustive(
+ Instruction::Mul, OverflowingBinaryOperator::NoSignedWrap,
+ [](const APInt &N1, const APInt &N2) {
+ bool Overflow;
+ (void) N1.smul_ov(N2, Overflow);
+ return Overflow;
+ });
+}
+
TEST(ConstantRange, GetEquivalentICmp) {
APInt RHS;
CmpInst::Predicate Pred;
OpenPOWER on IntegriCloud