[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

llvm-svn: 250975
This commit is contained in:
Sanjoy Das 2015-10-22 03:12:57 +00:00
parent b7c31d3a27
commit e4442f028b
3 changed files with 116 additions and 0 deletions

View File

@ -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; }

View File

@ -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::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
.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 {

View File

@ -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, MakeSatisfyingICmpRegion) {
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