From cc99daaaa7c4398b7cebcae40d8c9fbc2e59105c Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 10 Oct 2025 00:18:17 +0800 Subject: [PATCH 1/2] [ConstantFPRange] Add support for fneg/fabs --- llvm/include/llvm/IR/ConstantFPRange.h | 6 +++++ llvm/lib/IR/ConstantFPRange.cpp | 20 ++++++++++++++ llvm/unittests/IR/ConstantFPRangeTest.cpp | 33 +++++++++++++++++++++++ 3 files changed, 59 insertions(+) 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..969af9798bf06 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 (isEmptySet()) + 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..1384b68707577 100644 --- a/llvm/unittests/IR/ConstantFPRangeTest.cpp +++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp @@ -767,4 +767,37 @@ 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(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(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 From 87869e491e7bbf37850f07f2169fc6cff8c04c7c Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Fri, 10 Oct 2025 00:38:05 +0800 Subject: [PATCH 2/2] [ConstantFPRange] Fix abs(nan) --- llvm/lib/IR/ConstantFPRange.cpp | 2 +- llvm/unittests/IR/ConstantFPRangeTest.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp index 969af9798bf06..fba6942adfd89 100644 --- a/llvm/lib/IR/ConstantFPRange.cpp +++ b/llvm/lib/IR/ConstantFPRange.cpp @@ -393,7 +393,7 @@ ConstantFPRange ConstantFPRange::unionWith(const ConstantFPRange &CR) const { } ConstantFPRange ConstantFPRange::abs() const { - if (isEmptySet()) + if (isNaNOnly()) return *this; // Check if the range is all non-negative or all non-positive. if (Lower.isNegative() == Upper.isNegative()) { diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp index 1384b68707577..1436f0f2e2559 100644 --- a/llvm/unittests/IR/ConstantFPRangeTest.cpp +++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp @@ -779,6 +779,7 @@ TEST_F(ConstantFPRangeTest, abs) { 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(), @@ -794,6 +795,7 @@ TEST_F(ConstantFPRangeTest, negate) { 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(),