diff --git a/llvm/include/llvm/IR/ConstantFPRange.h b/llvm/include/llvm/IR/ConstantFPRange.h index 930c6f98c033f..4a54caa87eaca 100644 --- a/llvm/include/llvm/IR/ConstantFPRange.h +++ b/llvm/include/llvm/IR/ConstantFPRange.h @@ -200,6 +200,12 @@ class [[nodiscard]] ConstantFPRange { /// with another range. The resultant range is guaranteed to include the /// elements of both sets, but may contain more. LLVM_ABI ConstantFPRange unionWith(const ConstantFPRange &CR) const; + + /// Calculate absolute value range. + LLVM_ABI ConstantFPRange abs() const; + + /// Calculate range of negated values. + LLVM_ABI ConstantFPRange negate() const; }; inline raw_ostream &operator<<(raw_ostream &OS, const ConstantFPRange &CR) { diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp index 7509188128524..fba6942adfd89 100644 --- a/llvm/lib/IR/ConstantFPRange.cpp +++ b/llvm/lib/IR/ConstantFPRange.cpp @@ -391,3 +391,23 @@ ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const { return ConstantFPRange(minnum(Lower, CR.Lower), maxnum(Upper, CR.Upper), MayBeQNaN | CR.MayBeQNaN, MayBeSNaN | CR.MayBeSNaN); } + +ConstantFPRange ConstantFPRange::abs() const { + if (isNaNOnly()) + return *this; + // Check if the range is all non-negative or all non-positive. + if (Lower.isNegative() == Upper.isNegative()) { + if (Lower.isNegative()) + return negate(); + return *this; + } + // The range contains both positive and negative values. + APFloat NewLower = APFloat::getZero(getSemantics()); + APFloat NewUpper = maxnum(-Lower, Upper); + return ConstantFPRange(std::move(NewLower), std::move(NewUpper), MayBeQNaN, + MayBeSNaN); +} + +ConstantFPRange ConstantFPRange::negate() const { + return ConstantFPRange(-Upper, -Lower, MayBeQNaN, MayBeSNaN); +} diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp index 255f62d77b748..1436f0f2e2559 100644 --- a/llvm/unittests/IR/ConstantFPRangeTest.cpp +++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp @@ -767,4 +767,39 @@ TEST_F(ConstantFPRangeTest, makeExactFCmpRegion) { } } +TEST_F(ConstantFPRangeTest, abs) { + EXPECT_EQ(Full.abs(), + ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/false), + APFloat::getInf(Sem, /*Negative=*/false), + /*MayBeQNaN=*/true, + /*MayBeSNaN=*/true)); + EXPECT_EQ(Empty.abs(), Empty); + EXPECT_EQ(Zero.abs(), PosZero); + EXPECT_EQ(PosInf.abs(), PosInf); + EXPECT_EQ(NegInf.abs(), PosInf); + EXPECT_EQ(Some.abs(), SomePos); + EXPECT_EQ(SomeNeg.abs(), SomePos); + EXPECT_EQ(NaN.abs(), NaN); + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0)).abs(), + ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(3.0))); + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0)).abs(), + ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(3.0))); +} + +TEST_F(ConstantFPRangeTest, negate) { + EXPECT_EQ(Full.negate(), Full); + EXPECT_EQ(Empty.negate(), Empty); + EXPECT_EQ(Zero.negate(), Zero); + EXPECT_EQ(PosInf.negate(), NegInf); + EXPECT_EQ(NegInf.negate(), PosInf); + EXPECT_EQ(Some.negate(), Some); + EXPECT_EQ(SomePos.negate(), SomeNeg); + EXPECT_EQ(SomeNeg.negate(), SomePos); + EXPECT_EQ(NaN.negate(), NaN); + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0)).negate(), + ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0))); + EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(2.0)).negate(), + ConstantFPRange::getNonNaN(APFloat(-2.0), APFloat(3.0))); +} + } // anonymous namespace