Index: llvm/include/llvm/IR/ConstantRange.h =================================================================== --- llvm/include/llvm/IR/ConstantRange.h +++ llvm/include/llvm/IR/ConstantRange.h @@ -397,6 +397,10 @@ /// Return a new range that is the logical not of the current set. ConstantRange inverse() const; + /// Calculate absolute value range. If the original range contains signed + /// min, then the resulting range will also contain signed min. + ConstantRange abs() const; + /// Represents whether an operation on the given constant range is known to /// always or never overflow. enum class OverflowResult { AlwaysOverflows, MayOverflow, NeverOverflows }; Index: llvm/lib/IR/ConstantRange.cpp =================================================================== --- llvm/lib/IR/ConstantRange.cpp +++ llvm/lib/IR/ConstantRange.cpp @@ -1158,6 +1158,37 @@ return ConstantRange(Upper, Lower); } +ConstantRange ConstantRange::abs() const { + if (isEmptySet()) + return getEmpty(); + + if (isSignWrappedSet()) { + APInt Lo; + // Check whether the range crosses zero. + if (Upper.isStrictlyPositive() || !Lower.isStrictlyPositive()) + Lo = APInt::getNullValue(getBitWidth()); + else + Lo = APIntOps::umin(Lower, -Upper + 1); + + // SignedMin is included in the result range. + return ConstantRange(Lo, APInt::getSignedMinValue(getBitWidth()) + 1); + } + + APInt SMin = getSignedMin(), SMax = getSignedMax(); + + // All non-negative. + if (SMin.isNonNegative()) + return *this; + + // All negative. + if (SMax.isNegative()) + return ConstantRange(-SMax, -SMin + 1); + + // Range crosses zero. + return ConstantRange(APInt::getNullValue(getBitWidth()), + APIntOps::umax(-SMin, SMax) + 1); +} + ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) Index: llvm/unittests/IR/ConstantRangeTest.cpp =================================================================== --- llvm/unittests/IR/ConstantRangeTest.cpp +++ llvm/unittests/IR/ConstantRangeTest.cpp @@ -1787,4 +1787,30 @@ }); } +TEST_F(ConstantRangeTest, Abs) { + unsigned Bits = 4; + EnumerateConstantRanges(Bits, [&](const ConstantRange &CR) { + // We're working with unsigned integers here, because it makes the signed + // min case non-wrapping. + APInt Min = APInt::getMaxValue(Bits); + APInt Max = APInt::getMinValue(Bits); + ForeachNumInConstantRange(CR, [&](const APInt &N) { + APInt AbsN = N.abs(); + if (AbsN.ult(Min)) + Min = AbsN; + if (AbsN.ugt(Max)) + Max = AbsN; + }); + + ConstantRange AbsCR = CR.abs(); + if (Min.ugt(Max)) { + EXPECT_TRUE(AbsCR.isEmptySet()); + return; + } + + ConstantRange Exact = ConstantRange::getNonEmpty(Min, Max + 1); + EXPECT_EQ(Exact, AbsCR); + }); +} + } // anonymous namespace