[llvm] r250975 - [IR] Add a `makeNoWrapRegion` method to `ConstantRange`
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 21 20:12:57 PDT 2015
Author: sanjoy
Date: Wed Oct 21 22:12:57 2015
New Revision: 250975
URL: http://llvm.org/viewvc/llvm-project?rev=250975&view=rev
Log:
[IR] Add a `makeNoWrapRegion` method to `ConstantRange`
Summary: This will be used in a future change to ScalarEvolution.
Reviewers: hfinkel, reames, nlewycky
Subscribers: llvm-commits
Differential Revision: http://reviews.llvm.org/D13612
Modified:
llvm/trunk/include/llvm/IR/ConstantRange.h
llvm/trunk/lib/IR/ConstantRange.cpp
llvm/trunk/unittests/IR/ConstantRangeTest.cpp
Modified: llvm/trunk/include/llvm/IR/ConstantRange.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ConstantRange.h?rev=250975&r1=250974&r2=250975&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ConstantRange.h (original)
+++ llvm/trunk/include/llvm/IR/ConstantRange.h Wed Oct 21 22:12:57 2015
@@ -82,6 +82,17 @@ public:
static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
const ConstantRange &Other);
+ /// Return the largest range containing all X such that "X BinOpC C" does not
+ /// wrap (overflow).
+ ///
+ /// Example:
+ /// typedef OverflowingBinaryOperator OBO;
+ /// makeNoWrapRegion(Add, i8 1, OBO::NoSignedWrap) == [-128, 127)
+ /// makeNoWrapRegion(Add, i8 1, OBO::NoUnsignedWrap) == [0, -1)
+ /// makeNoWrapRegion(Add, i8 0, OBO::NoUnsignedWrap) == Full Set
+ static ConstantRange makeNoWrapRegion(Instruction::BinaryOps BinOp,
+ const APInt &C, unsigned NoWrapKind);
+
/// Return the lower value for this range.
///
const APInt &getLower() const { return Lower; }
Modified: llvm/trunk/lib/IR/ConstantRange.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ConstantRange.cpp?rev=250975&r1=250974&r2=250975&view=diff
==============================================================================
--- llvm/trunk/lib/IR/ConstantRange.cpp (original)
+++ llvm/trunk/lib/IR/ConstantRange.cpp Wed Oct 21 22:12:57 2015
@@ -21,7 +21,9 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Operator.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -125,6 +127,57 @@ ConstantRange ConstantRange::makeSatisfy
.inverse();
}
+ConstantRange ConstantRange::makeNoWrapRegion(Instruction::BinaryOps BinOp,
+ const APInt &C,
+ unsigned NoWrapKind) {
+ typedef OverflowingBinaryOperator OBO;
+
+ // Computes the intersection of CR0 and CR1. It is different from
+ // intersectWith in that the ConstantRange returned will only contain elements
+ // in both CR0 and CR1 (i.e. SubsetIntersect(X, Y) is a *subset*, proper or
+ // not, of both X and Y).
+ auto SubsetIntersect =
+ [](const ConstantRange &CR0, const ConstantRange &CR1) {
+ return CR0.inverse().unionWith(CR1.inverse()).inverse();
+ };
+
+ assert(BinOp >= Instruction::BinaryOpsBegin &&
+ BinOp < Instruction::BinaryOpsEnd && "Binary operators only!");
+
+ assert((NoWrapKind == OBO::NoSignedWrap ||
+ NoWrapKind == OBO::NoUnsignedWrap ||
+ NoWrapKind == (OBO::NoUnsignedWrap | OBO::NoSignedWrap)) &&
+ "NoWrapKind invalid!");
+
+ unsigned BitWidth = C.getBitWidth();
+ if (BinOp != Instruction::Add)
+ // Conservative answer: empty set
+ return ConstantRange(BitWidth, false);
+
+ if (C.isMinValue())
+ // Full set: nothing signed / unsigned wraps when added to 0.
+ return ConstantRange(BitWidth);
+
+ ConstantRange Result(BitWidth);
+
+ if (NoWrapKind & OBO::NoUnsignedWrap)
+ Result = SubsetIntersect(Result,
+ ConstantRange(APInt::getNullValue(BitWidth), -C));
+
+ if (NoWrapKind & OBO::NoSignedWrap) {
+ if (C.isStrictlyPositive())
+ Result = SubsetIntersect(
+ Result, ConstantRange(APInt::getSignedMinValue(BitWidth),
+ APInt::getSignedMinValue(BitWidth) - C));
+ else
+ Result = SubsetIntersect(
+ Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - C,
+ APInt::getSignedMinValue(BitWidth)));
+ }
+
+ return Result;
+}
+
/// isFullSet - Return true if this set contains all of the elements possible
/// for this data-type
bool ConstantRange::isFullSet() const {
Modified: llvm/trunk/unittests/IR/ConstantRangeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/ConstantRangeTest.cpp?rev=250975&r1=250974&r2=250975&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/ConstantRangeTest.cpp (original)
+++ llvm/trunk/unittests/IR/ConstantRangeTest.cpp Wed Oct 21 22:12:57 2015
@@ -9,6 +9,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Operator.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -568,4 +569,55 @@ TEST(ConstantRange, MakeSatisfyingICmpRe
ConstantRange(APInt(8, 4), APInt(8, -128)));
}
+TEST(ConstantRange, MakeOverflowingRegion) {
+ const int IntMin4Bits = 8;
+ const int IntMax4Bits = 7;
+ typedef OverflowingBinaryOperator OBO;
+
+ for (int Const : {0, -1, -2, 1, 2, IntMin4Bits, IntMax4Bits}) {
+ APInt C(4, Const, true /* = isSigned */);
+
+ auto NUWRegion =
+ ConstantRange::makeNoWrapRegion(Instruction::Add, C, OBO::NoUnsignedWrap);
+
+ EXPECT_FALSE(NUWRegion.isEmptySet());
+
+ auto NSWRegion =
+ ConstantRange::makeNoWrapRegion(Instruction::Add, C, OBO::NoSignedWrap);
+
+ EXPECT_FALSE(NSWRegion.isEmptySet());
+
+ auto NoWrapRegion = ConstantRange::makeNoWrapRegion(
+ Instruction::Add, C, OBO::NoSignedWrap | OBO::NoUnsignedWrap);
+
+ EXPECT_FALSE(NoWrapRegion.isEmptySet());
+ EXPECT_TRUE(NUWRegion.intersectWith(NSWRegion).contains(NoWrapRegion));
+
+ for (APInt I = NUWRegion.getLower(), E = NUWRegion.getUpper(); I != E;
+ ++I) {
+ bool Overflow = false;
+ I.uadd_ov(C, Overflow);
+ EXPECT_FALSE(Overflow);
+ }
+
+ for (APInt I = NSWRegion.getLower(), E = NSWRegion.getUpper(); I != E;
+ ++I) {
+ bool Overflow = false;
+ I.sadd_ov(C, Overflow);
+ EXPECT_FALSE(Overflow);
+ }
+
+ for (APInt I = NoWrapRegion.getLower(), E = NoWrapRegion.getUpper(); I != E;
+ ++I) {
+ bool Overflow = false;
+
+ I.sadd_ov(C, Overflow);
+ EXPECT_FALSE(Overflow);
+
+ I.uadd_ov(C, Overflow);
+ EXPECT_FALSE(Overflow);
+ }
+ }
+}
+
} // anonymous namespace
More information about the llvm-commits
mailing list