From: Sanjoy Das Date: Thu, 3 Mar 2016 18:31:16 +0000 (+0000) Subject: [ConstantRange] Generalize makeGuaranteedNoWrapRegion to work on ranges X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f3867e64a82570990461e377c44887a310389ce8;p=platform%2Fupstream%2Fllvm.git [ConstantRange] Generalize makeGuaranteedNoWrapRegion to work on ranges This will be used in a later patch to ScalarEvolution. Right now only the unit tests exercise the newly added code. llvm-svn: 262637 --- diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index 5038ae1..89af6bb 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -82,24 +82,26 @@ public: static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other); - /// Return the largest range containing all X such that "X BinOpC C" is - /// guaranteed not to wrap (overflow). + /// 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 C" does not wrap -- some viable values of X may be + /// which "X BinOpC Y" does not wrap -- some viable values of X may be /// missing, so you cannot use this to contrain X's range. E.g. in the last /// example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2), but (-2) /// is not in the set returned. /// - /// Example: + /// Examples: /// 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 - /// makeNoWrapRegion(Add, i8 1, OBO::NoUnsignedWrap | OBO::NoSignedWrap) == - /// [0,INT_MAX) + /// #define MGNR makeGuaranteedNoWrapRegion + /// MGNR(Add, [i8 1, 2), OBO::NoSignedWrap) == [-128, 127) + /// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap) == [0, -1) + /// MGNR(Add, [i8 0, 1), OBO::NoUnsignedWrap) == Full Set + /// MGNR(Add, [i8 1, 2), OBO::NoUnsignedWrap | OBO::NoSignedWrap) + /// == [0,INT_MAX) + /// MGNR(Add, [i8 -1, 6), OBO::NoSignedWrap) == [INT_MIN+1, INT_MAX-4) static ConstantRange makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, - const APInt &C, + const ConstantRange &Other, unsigned NoWrapKind); /// Return the lower value for this range. diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 521511a..417b752 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -129,7 +129,8 @@ ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred, ConstantRange ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, - const APInt &C, unsigned NoWrapKind) { + const ConstantRange &Other, + unsigned NoWrapKind) { typedef OverflowingBinaryOperator OBO; // Computes the intersection of CR0 and CR1. It is different from @@ -149,29 +150,36 @@ ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, NoWrapKind == (OBO::NoUnsignedWrap | OBO::NoSignedWrap)) && "NoWrapKind invalid!"); - unsigned BitWidth = C.getBitWidth(); + unsigned BitWidth = Other.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 (auto *C = Other.getSingleElement()) + 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)); + Result = + SubsetIntersect(Result, ConstantRange(APInt::getNullValue(BitWidth), + -Other.getUnsignedMax())); if (NoWrapKind & OBO::NoSignedWrap) { - if (C.isStrictlyPositive()) + APInt SignedMin = Other.getSignedMin(); + APInt SignedMax = Other.getSignedMax(); + + if (SignedMax.isStrictlyPositive()) Result = SubsetIntersect( - Result, ConstantRange(APInt::getSignedMinValue(BitWidth), - APInt::getSignedMinValue(BitWidth) - C)); - else + Result, + ConstantRange(APInt::getSignedMinValue(BitWidth), + APInt::getSignedMinValue(BitWidth) - SignedMax)); + + if (SignedMin.isNegative()) Result = SubsetIntersect( - Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - C, + Result, ConstantRange(APInt::getSignedMinValue(BitWidth) - SignedMin, APInt::getSignedMinValue(BitWidth))); } diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 35b1db3..a06483d 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -657,6 +657,63 @@ TEST(ConstantRange, MakeOverflowingRegion) { EXPECT_FALSE(Overflow); } } + + auto NSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, ConstantRange(32, /* isFullSet = */ true), + OBO::NoSignedWrap); + EXPECT_TRUE(NSWForAllValues.isSingleElement() && + NSWForAllValues.getSingleElement()->isMinValue()); + + auto NUWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, ConstantRange(32, /* isFullSet = */ true), + OBO::NoUnsignedWrap); + EXPECT_TRUE(NUWForAllValues.isSingleElement() && + NSWForAllValues.getSingleElement()->isMinValue()); + + auto NUWAndNSWForAllValues = ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, ConstantRange(32, /* isFullSet = */ true), + OBO::NoUnsignedWrap | OBO::NoSignedWrap); + EXPECT_TRUE(NUWAndNSWForAllValues.isSingleElement() && + NSWForAllValues.getSingleElement()->isMinValue()); + + ConstantRange OneToFive(APInt(32, 1), APInt(32, 6)); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, OneToFive, OBO::NoSignedWrap), + ConstantRange(APInt::getSignedMinValue(32), + APInt::getSignedMaxValue(32) - 4)); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, OneToFive, OBO::NoUnsignedWrap), + ConstantRange(APInt::getMinValue(32), APInt::getMinValue(32) - 5)); + EXPECT_EQ( + ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, OneToFive, OBO::NoUnsignedWrap | OBO::NoSignedWrap), + ConstantRange(APInt::getMinValue(32), APInt::getSignedMaxValue(32) - 4)); + + ConstantRange MinusFiveToMinusTwo(APInt(32, -5), APInt(32, -1)); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusFiveToMinusTwo, OBO::NoSignedWrap), + ConstantRange(APInt::getSignedMinValue(32) + 5, + APInt::getSignedMinValue(32))); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusFiveToMinusTwo, OBO::NoUnsignedWrap), + ConstantRange(APInt(32, 0), APInt(32, 2))); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusFiveToMinusTwo, + OBO::NoUnsignedWrap | OBO::NoSignedWrap), + ConstantRange(APInt(32, 0), APInt(32, 2))); + + ConstantRange MinusOneToOne(APInt(32, -1), APInt(32, 2)); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusOneToOne, OBO::NoSignedWrap), + ConstantRange(APInt::getSignedMinValue(32) + 1, + APInt::getSignedMinValue(32) - 1)); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusOneToOne, OBO::NoUnsignedWrap), + ConstantRange(APInt(32, 0), APInt(32, 1))); + EXPECT_EQ(ConstantRange::makeGuaranteedNoWrapRegion( + Instruction::Add, MinusOneToOne, + OBO::NoUnsignedWrap | OBO::NoSignedWrap), + ConstantRange(APInt(32, 0), APInt(32, 1))); } } // anonymous namespace