Index: include/llvm/IR/ConstantRange.h =================================================================== --- include/llvm/IR/ConstantRange.h +++ include/llvm/IR/ConstantRange.h @@ -82,6 +82,17 @@ 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::UnsignedWrap) == [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; } Index: lib/IR/ConstantRange.cpp =================================================================== --- lib/IR/ConstantRange.cpp +++ lib/IR/ConstantRange.cpp @@ -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,37 @@ .inverse(); } +ConstantRange ConstantRange::makeNoWrapRegion(Instruction::BinaryOps BinOp, + const APInt &C, + unsigned NoWrapKind) { + typedef OverflowingBinaryOperator OBO; + + assert(BinOp >= Instruction::BinaryOpsBegin && + BinOp < Instruction::BinaryOpsEnd && "Binary operators only!"); + + assert((NoWrapKind == OBO::NoSignedWrap || + NoWrapKind == OBO::NoUnsignedWrap) && "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); + + if (NoWrapKind == OBO::NoUnsignedWrap) + return ConstantRange(APInt::getNullValue(BitWidth), -C); + + if (C.isStrictlyPositive()) + return ConstantRange(APInt::getSignedMinValue(BitWidth), + APInt::getSignedMinValue(BitWidth) - C); + + return ConstantRange(APInt::getSignedMinValue(BitWidth) - C, + APInt::getSignedMinValue(BitWidth)); +} + /// isFullSet - Return true if this set contains all of the elements possible /// for this data-type bool ConstantRange::isFullSet() const { Index: unittests/IR/ConstantRangeTest.cpp =================================================================== --- unittests/IR/ConstantRangeTest.cpp +++ unittests/IR/ConstantRangeTest.cpp @@ -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,38 @@ 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()); + + 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); + } + } +} + } // anonymous namespace