Index: include/llvm/IR/ConstantRange.h =================================================================== --- include/llvm/IR/ConstantRange.h +++ include/llvm/IR/ConstantRange.h @@ -261,6 +261,10 @@ /// from an addition of a value in this range and a value in \p Other. ConstantRange add(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting from a + /// known NSW addition of a value in this range and \p Other constant. + ConstantRange addWithNoSignedWrap(const APInt &Other) const; + /// Return a new range representing the possible values resulting /// from a subtraction of a value in this range and a value in \p Other. ConstantRange sub(const ConstantRange &Other) const; Index: lib/IR/ConstantRange.cpp =================================================================== --- lib/IR/ConstantRange.cpp +++ lib/IR/ConstantRange.cpp @@ -674,6 +674,20 @@ return X; } +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. + ConstantRange NSWRange = ConstantRange::makeGuaranteedNoWrapRegion( + BinaryOperator::Add, + ConstantRange(Other), + OverflowingBinaryOperator::NoSignedWrap); + ConstantRange NSWConstrainedRange = intersectWith(NSWRange); + + return NSWConstrainedRange.add(ConstantRange(Other)); +} + ConstantRange ConstantRange::sub(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) Index: unittests/IR/ConstantRangeTest.cpp =================================================================== --- unittests/IR/ConstantRangeTest.cpp +++ unittests/IR/ConstantRangeTest.cpp @@ -357,6 +357,32 @@ ConstantRange(APInt(16, 0xe))); } +TEST_F(ConstantRangeTest, AddWithNoSignedWrap) { + EXPECT_EQ(Empty.addWithNoSignedWrap(APInt(16, 1)), Empty); + EXPECT_EQ(Full.addWithNoSignedWrap(APInt(16, 1)), + ConstantRange(APInt(16, INT16_MIN+1), APInt(16, INT16_MIN))); + EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 50)).addWithNoSignedWrap(APInt(8, 10)), + ConstantRange(APInt(8, -40), APInt(8, 60))); + EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 120)).addWithNoSignedWrap(APInt(8, 10)), + ConstantRange(APInt(8, -40), APInt(8, INT8_MIN))); + EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -10)).addWithNoSignedWrap(APInt(8, 5)), + ConstantRange(APInt(8, 125), APInt(8, -5))); + EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, 10)), + ConstantRange(APInt(8, INT8_MIN+10), APInt(8, -110))); + + EXPECT_EQ(Empty.addWithNoSignedWrap(APInt(16, -1)), Empty); + EXPECT_EQ(Full.addWithNoSignedWrap(APInt(16, -1)), + ConstantRange(APInt(16, INT16_MIN), APInt(16, INT16_MAX))); + EXPECT_EQ(ConstantRange(APInt(8, -50), APInt(8, 50)).addWithNoSignedWrap(APInt(8, -10)), + ConstantRange(APInt(8, -60), APInt(8, 40))); + EXPECT_EQ(ConstantRange(APInt(8, -120), APInt(8, 50)).addWithNoSignedWrap(APInt(8, -10)), + ConstantRange(APInt(8, INT8_MIN), APInt(8, 40))); + EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, -5)), + ConstantRange(APInt(8, 115), APInt(8, -125))); + EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, -120)).addWithNoSignedWrap(APInt(8, -10)), + ConstantRange(APInt(8, 110), APInt(8, INT8_MIN-10))); +} + TEST_F(ConstantRangeTest, Sub) { EXPECT_EQ(Full.sub(APInt(16, 4)), Full); EXPECT_EQ(Full.sub(Full), Full);