[llvm] [ConstantFPRange] Add support for add/sub (PR #162962)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 11 10:24:36 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/162962
>From aa26a6df28763f8b736ae62b9f561c99eb4b5745 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 11 Oct 2025 10:54:15 +0800
Subject: [PATCH 1/2] [ConstantFPRange] Add support for add/sub
---
llvm/include/llvm/IR/ConstantFPRange.h | 8 +
llvm/lib/IR/ConstantFPRange.cpp | 66 ++++++++-
llvm/unittests/IR/ConstantFPRangeTest.cpp | 171 +++++++++++++++++++---
3 files changed, 221 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/IR/ConstantFPRange.h b/llvm/include/llvm/IR/ConstantFPRange.h
index d47f6c02c883d..39dc7c100d6f7 100644
--- a/llvm/include/llvm/IR/ConstantFPRange.h
+++ b/llvm/include/llvm/IR/ConstantFPRange.h
@@ -222,6 +222,14 @@ class [[nodiscard]] ConstantFPRange {
LLVM_ABI ConstantFPRange
cast(const fltSemantics &DstSem,
APFloat::roundingMode RM = APFloat::rmNearestTiesToEven) const;
+
+ /// Return a new range representing the possible values resulting
+ /// from an addition of a value in this range and a value in \p Other.
+ LLVM_ABI ConstantFPRange add(const ConstantFPRange &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.
+ LLVM_ABI ConstantFPRange sub(const ConstantFPRange &Other) 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 070e833f4d1c0..a62b0d36b93a8 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -414,15 +414,31 @@ ConstantFPRange ConstantFPRange::negate() const {
return ConstantFPRange(-Upper, -Lower, MayBeQNaN, MayBeSNaN);
}
+// Return true if the finite part is not empty after removing infinities.
+static bool removeInf(APFloat &Lower, APFloat &Upper, bool &HasPosInf,
+ bool &HasNegInf) {
+ assert(strictCompare(Lower, Upper) != APFloat::cmpGreaterThan &&
+ "Non-NaN part is empty.");
+ auto &Sem = Lower.getSemantics();
+ if (Lower.isNegInfinity()) {
+ Lower = APFloat::getLargest(Sem, /*Negative=*/true);
+ HasNegInf = true;
+ }
+ if (Upper.isPosInfinity()) {
+ Upper = APFloat::getLargest(Sem, /*Negative=*/false);
+ HasPosInf = true;
+ }
+ return strictCompare(Lower, Upper) != APFloat::cmpGreaterThan;
+}
+
ConstantFPRange ConstantFPRange::getWithoutInf() const {
if (isNaNOnly())
return *this;
APFloat NewLower = Lower;
APFloat NewUpper = Upper;
- if (Lower.isNegInfinity())
- NewLower = APFloat::getLargest(getSemantics(), /*Negative=*/true);
- if (Upper.isPosInfinity())
- NewUpper = APFloat::getLargest(getSemantics(), /*Negative=*/false);
+ bool UnusedFlag;
+ removeInf(NewLower, NewUpper, /*HasPosInf=*/UnusedFlag,
+ /*HasNegInf=*/UnusedFlag);
canonicalizeRange(NewLower, NewUpper);
return ConstantFPRange(std::move(NewLower), std::move(NewUpper), MayBeQNaN,
MayBeSNaN);
@@ -444,3 +460,45 @@ ConstantFPRange ConstantFPRange::cast(const fltSemantics &DstSem,
/*MayBeQNaNVal=*/MayBeQNaN || MayBeSNaN,
/*MayBeSNaNVal=*/false);
}
+
+ConstantFPRange ConstantFPRange::add(const ConstantFPRange &Other) const {
+ bool MayBeQNaN =
+ (MayBeQNaN || MayBeSNaN) && (Other.MayBeQNaN || Other.MayBeSNaN);
+ if (isNaNOnly() || Other.isNaNOnly())
+ return getNaNOnly(getSemantics(), /*MayBeQNaN=*/MayBeQNaN,
+ /*MayBeSNaN=*/false);
+ bool LHSHasNegInf = false, LHSHasPosInf = false;
+ APFloat LHSLower = Lower, LHSUpper = Upper;
+ bool LHSFiniteIsNonEmpty =
+ removeInf(LHSLower, LHSUpper, LHSHasPosInf, LHSHasNegInf);
+ bool RHSHasNegInf = false, RHSHasPosInf = false;
+ APFloat RHSLower = Other.Lower, RHSUpper = Other.Upper;
+ bool RHSFiniteIsNonEmpty =
+ removeInf(RHSLower, RHSUpper, RHSHasPosInf, RHSHasNegInf);
+ // -inf + +inf = QNaN
+ MayBeQNaN |= (LHSHasNegInf && RHSHasPosInf) || (LHSHasPosInf && RHSHasNegInf);
+ // +inf + finite/+inf = +inf, -inf + finite/-inf = -inf
+ bool HasNegInf = (LHSHasNegInf && (RHSFiniteIsNonEmpty || RHSHasNegInf)) ||
+ (RHSHasNegInf && (LHSFiniteIsNonEmpty || LHSHasNegInf));
+ bool HasPosInf = (LHSHasPosInf && (RHSFiniteIsNonEmpty || RHSHasPosInf)) ||
+ (RHSHasPosInf && (LHSFiniteIsNonEmpty || LHSHasPosInf));
+ if (LHSFiniteIsNonEmpty && RHSFiniteIsNonEmpty) {
+ APFloat NewLower =
+ HasNegInf ? APFloat::getInf(LHSLower.getSemantics(), /*Negative=*/true)
+ : LHSLower + RHSLower;
+ APFloat NewUpper =
+ HasPosInf ? APFloat::getInf(LHSUpper.getSemantics(), /*Negative=*/false)
+ : LHSUpper + RHSUpper;
+ return ConstantFPRange(NewLower, NewUpper, MayBeQNaN, /*MayBeSNaN=*/false);
+ }
+ // If both HasNegInf and HasPosInf are true, the non-NaN part is empty.
+ return ConstantFPRange(
+ APFloat::getInf(Lower.getSemantics(), /*Negative=*/HasNegInf),
+ APFloat::getInf(Upper.getSemantics(), /*Negative=*/!HasPosInf), MayBeQNaN,
+ /*MayBeSNaN=*/false);
+}
+
+ConstantFPRange ConstantFPRange::sub(const ConstantFPRange &Other) const {
+ // fsub X, Y = fadd X, (fneg Y)
+ return add(Other.negate());
+}
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index 58a65b9a96ab8..4eb97564af0e3 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -79,15 +79,21 @@ static void strictNext(APFloat &V) {
V.next(/*nextDown=*/false);
}
+enum class SparseLevel {
+ Dense,
+ SpecialValuesWithAllPowerOfTwos,
+ SpecialValuesOnly,
+};
+
template <typename Fn>
-static void EnumerateConstantFPRangesImpl(Fn TestFn, bool Exhaustive,
+static void EnumerateConstantFPRangesImpl(Fn TestFn, SparseLevel Level,
bool MayBeQNaN, bool MayBeSNaN) {
const fltSemantics &Sem = APFloat::Float8E4M3();
APFloat PosInf = APFloat::getInf(Sem, /*Negative=*/false);
APFloat NegInf = APFloat::getInf(Sem, /*Negative=*/true);
TestFn(ConstantFPRange(PosInf, NegInf, MayBeQNaN, MayBeSNaN));
- if (!Exhaustive) {
+ if (Level != SparseLevel::Dense) {
SmallVector<APFloat, 36> Values;
Values.push_back(APFloat::getInf(Sem, /*Negative=*/true));
Values.push_back(APFloat::getLargest(Sem, /*Negative=*/true));
@@ -95,10 +101,13 @@ static void EnumerateConstantFPRangesImpl(Fn TestFn, bool Exhaustive,
unsigned Exponents = APFloat::semanticsMaxExponent(Sem) -
APFloat::semanticsMinExponent(Sem) + 3;
unsigned MantissaBits = APFloat::semanticsPrecision(Sem) - 1;
- // Add -2^(max exponent), -2^(max exponent-1), ..., -2^(min exponent)
- for (unsigned M = Exponents - 2; M != 0; --M)
- Values.push_back(
- APFloat(Sem, APInt(BitWidth, (M + Exponents) << MantissaBits)));
+ if (Level == SparseLevel::SpecialValuesWithAllPowerOfTwos) {
+ // Add -2^(max exponent), -2^(max exponent-1), ..., -2^(min exponent)
+ for (unsigned M = Exponents - 2; M != 0; --M)
+ Values.push_back(
+ APFloat(Sem, APInt(BitWidth, (M + Exponents) << MantissaBits)));
+ }
+ Values.push_back(APFloat::getSmallestNormalized(Sem, /*Negative=*/true));
Values.push_back(APFloat::getSmallest(Sem, /*Negative=*/true));
Values.push_back(APFloat::getZero(Sem, /*Negative=*/true));
size_t E = Values.size();
@@ -127,26 +136,30 @@ static void EnumerateConstantFPRangesImpl(Fn TestFn, bool Exhaustive,
}
template <typename Fn>
-static void EnumerateConstantFPRanges(Fn TestFn, bool Exhaustive) {
- EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/false,
+static void EnumerateConstantFPRanges(Fn TestFn, SparseLevel Level,
+ bool IgnoreNaNs = false) {
+ EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,
/*MayBeSNaN=*/false);
- EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/false,
+ if (IgnoreNaNs)
+ return;
+ EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,
/*MayBeSNaN=*/true);
- EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/true,
+ EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,
/*MayBeSNaN=*/false);
- EnumerateConstantFPRangesImpl(TestFn, Exhaustive, /*MayBeQNaN=*/true,
+ EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,
/*MayBeSNaN=*/true);
}
template <typename Fn>
static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn,
- bool Exhaustive) {
+ SparseLevel Level) {
EnumerateConstantFPRanges(
[&](const ConstantFPRange &CR1) {
EnumerateConstantFPRanges(
- [&](const ConstantFPRange &CR2) { TestFn(CR1, CR2); }, Exhaustive);
+ [&](const ConstantFPRange &CR2) { TestFn(CR1, CR2); }, Level,
+ /*IgnoreNaNs=*/true);
},
- Exhaustive);
+ Level, /*IgnoreNaNs=*/true);
}
template <typename Fn>
@@ -348,16 +361,25 @@ TEST_F(ConstantFPRangeTest, ExhaustivelyEnumerate) {
constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);
unsigned Count = 0;
EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },
- /*Exhaustive=*/true);
+ SparseLevel::Dense);
EXPECT_EQ(Expected, Count);
}
TEST_F(ConstantFPRangeTest, Enumerate) {
- constexpr unsigned NNaNValues = 2 * ((1 << 4) - 2 + 4);
+ constexpr unsigned NNaNValues = 2 * ((1 << 4) - 2 + 5);
+ constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);
+ unsigned Count = 0;
+ EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },
+ SparseLevel::SpecialValuesWithAllPowerOfTwos);
+ EXPECT_EQ(Expected, Count);
+}
+
+TEST_F(ConstantFPRangeTest, EnumerateWithSpecialValuesOnly) {
+ constexpr unsigned NNaNValues = 2 * 5;
constexpr unsigned Expected = 4 * ((NNaNValues + 1) * NNaNValues / 2 + 1);
unsigned Count = 0;
EnumerateConstantFPRanges([&](const ConstantFPRange &) { ++Count; },
- /*Exhaustive=*/false);
+ SparseLevel::SpecialValuesOnly);
EXPECT_EQ(Expected, Count);
}
@@ -459,7 +481,7 @@ TEST_F(ConstantFPRangeTest, FPClassify) {
EXPECT_EQ(SignBit, CR.getSignBit()) << CR;
EXPECT_EQ(Mask, CR.classify()) << CR;
},
- /*Exhaustive=*/true);
+ SparseLevel::Dense);
#endif
}
@@ -560,7 +582,7 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
<< "Suboptimal result for makeAllowedFCmpRegion(" << Pred << ", "
<< CR << ")";
},
- /*Exhaustive=*/false);
+ SparseLevel::SpecialValuesWithAllPowerOfTwos);
}
#endif
}
@@ -671,7 +693,7 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
<< ", " << CR << ")";
}
},
- /*Exhaustive=*/false);
+ SparseLevel::SpecialValuesWithAllPowerOfTwos);
}
#endif
}
@@ -925,4 +947,113 @@ TEST_F(ConstantFPRangeTest, cast) {
/*IgnoreNaNPayload=*/true);
}
+TEST_F(ConstantFPRangeTest, add) {
+ EXPECT_EQ(Full.add(Full), ConstantFPRange::getNonNaN(Sem).unionWith(QNaN));
+ EXPECT_EQ(Full.add(Empty), Empty);
+ EXPECT_EQ(Empty.add(Full), Empty);
+ EXPECT_EQ(Empty.add(Empty), Empty);
+ EXPECT_EQ(One.add(One), ConstantFPRange(APFloat(2.0)));
+ EXPECT_EQ(Some.add(Some),
+ ConstantFPRange::getNonNaN(APFloat(-6.0), APFloat(6.0)));
+ EXPECT_EQ(SomePos.add(SomeNeg),
+ ConstantFPRange::getNonNaN(APFloat(-3.0), APFloat(3.0)));
+ EXPECT_EQ(PosInf.add(PosInf), PosInf);
+ EXPECT_EQ(NegInf.add(NegInf), NegInf);
+ EXPECT_EQ(PosInf.add(Finite.unionWith(PosInf)), PosInf);
+ EXPECT_EQ(NegInf.add(Finite.unionWith(NegInf)), NegInf);
+ EXPECT_EQ(PosInf.add(Finite.unionWith(NegInf)), PosInf.unionWith(QNaN));
+ EXPECT_EQ(NegInf.add(Finite.unionWith(PosInf)), NegInf.unionWith(QNaN));
+ EXPECT_EQ(PosInf.add(NegInf), QNaN);
+ EXPECT_EQ(NegInf.add(PosInf), QNaN);
+ EXPECT_EQ(PosZero.add(NegZero), PosZero);
+ EXPECT_EQ(PosZero.add(Zero), PosZero);
+ EXPECT_EQ(NegZero.add(NegZero), NegZero);
+ EXPECT_EQ(NegZero.add(Zero), Zero);
+ EXPECT_EQ(NaN.add(NaN), QNaN);
+
+#if defined(EXPENSIVE_CHECKS)
+ EnumerateTwoInterestingConstantFPRanges(
+ [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {
+ ConstantFPRange Res = LHS.add(RHS);
+ ConstantFPRange Expected =
+ ConstantFPRange::getEmpty(LHS.getSemantics());
+ EnumerateValuesInConstantFPRange(
+ LHS,
+ [&](const APFloat &LHSC) {
+ EnumerateValuesInConstantFPRange(
+ RHS,
+ [&](const APFloat &RHSC) {
+ APFloat Sum = LHSC + RHSC;
+ EXPECT_TRUE(Res.contains(Sum))
+ << "Wrong result for " << LHS << " + " << RHS
+ << ". The result " << Res << " should contain " << Sum;
+ if (!Expected.contains(Sum))
+ Expected = Expected.unionWith(ConstantFPRange(Sum));
+ },
+ /*IgnoreNaNPayload=*/true);
+ },
+ /*IgnoreNaNPayload=*/true);
+ EXPECT_EQ(Res, Expected)
+ << "Suboptimal result for " << LHS << " + " << RHS << ". Expected "
+ << Expected << ", but got " << Res;
+ },
+ SparseLevel::SpecialValuesOnly);
+#endif
+}
+
+TEST_F(ConstantFPRangeTest, sub) {
+ EXPECT_EQ(Full.sub(Full), ConstantFPRange::getNonNaN(Sem).unionWith(QNaN));
+ EXPECT_EQ(Full.sub(Empty), Empty);
+ EXPECT_EQ(Empty.sub(Full), Empty);
+ EXPECT_EQ(Empty.sub(Empty), Empty);
+ EXPECT_EQ(One.sub(One), ConstantFPRange(APFloat(0.0)));
+ EXPECT_EQ(Some.sub(Some),
+ ConstantFPRange::getNonNaN(APFloat(-6.0), APFloat(6.0)));
+ EXPECT_EQ(SomePos.sub(SomeNeg),
+ ConstantFPRange::getNonNaN(APFloat(0.0), APFloat(6.0)));
+ EXPECT_EQ(PosInf.sub(NegInf), PosInf);
+ EXPECT_EQ(NegInf.sub(PosInf), NegInf);
+ EXPECT_EQ(PosInf.sub(Finite.unionWith(NegInf)), PosInf);
+ EXPECT_EQ(NegInf.sub(Finite.unionWith(PosInf)), NegInf);
+ EXPECT_EQ(PosInf.sub(Finite.unionWith(PosInf)), PosInf.unionWith(QNaN));
+ EXPECT_EQ(NegInf.sub(Finite.unionWith(NegInf)), NegInf.unionWith(QNaN));
+ EXPECT_EQ(PosInf.sub(PosInf), QNaN);
+ EXPECT_EQ(NegInf.sub(NegInf), QNaN);
+ EXPECT_EQ(PosZero.sub(NegZero), PosZero);
+ EXPECT_EQ(PosZero.sub(Zero), PosZero);
+ EXPECT_EQ(NegZero.sub(NegZero), PosZero);
+ EXPECT_EQ(NegZero.sub(PosZero), NegZero);
+ EXPECT_EQ(NegZero.sub(Zero), Zero);
+ EXPECT_EQ(NaN.sub(NaN), QNaN);
+
+#if defined(EXPENSIVE_CHECKS)
+ EnumerateTwoInterestingConstantFPRanges(
+ [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) {
+ ConstantFPRange Res = LHS.sub(RHS);
+ ConstantFPRange Expected =
+ ConstantFPRange::getEmpty(LHS.getSemantics());
+ EnumerateValuesInConstantFPRange(
+ LHS,
+ [&](const APFloat &LHSC) {
+ EnumerateValuesInConstantFPRange(
+ RHS,
+ [&](const APFloat &RHSC) {
+ APFloat Diff = LHSC - RHSC;
+ EXPECT_TRUE(Res.contains(Diff))
+ << "Wrong result for " << LHS << " - " << RHS
+ << ". The result " << Res << " should contain " << Diff;
+ if (!Expected.contains(Diff))
+ Expected = Expected.unionWith(ConstantFPRange(Diff));
+ },
+ /*IgnoreNaNPayload=*/true);
+ },
+ /*IgnoreNaNPayload=*/true);
+ EXPECT_EQ(Res, Expected)
+ << "Suboptimal result for " << LHS << " - " << RHS << ". Expected "
+ << Expected << ", but got " << Res;
+ },
+ SparseLevel::SpecialValuesOnly);
+#endif
+}
+
} // anonymous namespace
>From ed81b0d9eabf3636a01c3e241be31f8c99317d83 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 12 Oct 2025 01:23:42 +0800
Subject: [PATCH 2/2] [ConstantFPRange] Fix NaN handling
---
llvm/lib/IR/ConstantFPRange.cpp | 15 +++++++-----
llvm/unittests/IR/ConstantFPRangeTest.cpp | 29 +++++++++++++++--------
2 files changed, 28 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp
index a62b0d36b93a8..d149e4206a9a1 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -462,10 +462,10 @@ ConstantFPRange ConstantFPRange::cast(const fltSemantics &DstSem,
}
ConstantFPRange ConstantFPRange::add(const ConstantFPRange &Other) const {
- bool MayBeQNaN =
- (MayBeQNaN || MayBeSNaN) && (Other.MayBeQNaN || Other.MayBeSNaN);
+ bool ResMayBeQNaN = ((MayBeQNaN || MayBeSNaN) && !Other.isEmptySet()) ||
+ ((Other.MayBeQNaN || Other.MayBeSNaN) && !isEmptySet());
if (isNaNOnly() || Other.isNaNOnly())
- return getNaNOnly(getSemantics(), /*MayBeQNaN=*/MayBeQNaN,
+ return getNaNOnly(getSemantics(), /*MayBeQNaN=*/ResMayBeQNaN,
/*MayBeSNaN=*/false);
bool LHSHasNegInf = false, LHSHasPosInf = false;
APFloat LHSLower = Lower, LHSUpper = Upper;
@@ -476,7 +476,8 @@ ConstantFPRange ConstantFPRange::add(const ConstantFPRange &Other) const {
bool RHSFiniteIsNonEmpty =
removeInf(RHSLower, RHSUpper, RHSHasPosInf, RHSHasNegInf);
// -inf + +inf = QNaN
- MayBeQNaN |= (LHSHasNegInf && RHSHasPosInf) || (LHSHasPosInf && RHSHasNegInf);
+ ResMayBeQNaN |=
+ (LHSHasNegInf && RHSHasPosInf) || (LHSHasPosInf && RHSHasNegInf);
// +inf + finite/+inf = +inf, -inf + finite/-inf = -inf
bool HasNegInf = (LHSHasNegInf && (RHSFiniteIsNonEmpty || RHSHasNegInf)) ||
(RHSHasNegInf && (LHSFiniteIsNonEmpty || LHSHasNegInf));
@@ -489,12 +490,14 @@ ConstantFPRange ConstantFPRange::add(const ConstantFPRange &Other) const {
APFloat NewUpper =
HasPosInf ? APFloat::getInf(LHSUpper.getSemantics(), /*Negative=*/false)
: LHSUpper + RHSUpper;
- return ConstantFPRange(NewLower, NewUpper, MayBeQNaN, /*MayBeSNaN=*/false);
+ return ConstantFPRange(NewLower, NewUpper, ResMayBeQNaN,
+ /*MayBeSNaN=*/false);
}
// If both HasNegInf and HasPosInf are true, the non-NaN part is empty.
return ConstantFPRange(
APFloat::getInf(Lower.getSemantics(), /*Negative=*/HasNegInf),
- APFloat::getInf(Upper.getSemantics(), /*Negative=*/!HasPosInf), MayBeQNaN,
+ APFloat::getInf(Upper.getSemantics(), /*Negative=*/!HasPosInf),
+ ResMayBeQNaN,
/*MayBeSNaN=*/false);
}
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index 4eb97564af0e3..cf9b31cf88480 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -22,6 +22,7 @@ class ConstantFPRangeTest : public ::testing::Test {
static ConstantFPRange Full;
static ConstantFPRange Empty;
static ConstantFPRange Finite;
+ static ConstantFPRange NonNaN;
static ConstantFPRange One;
static ConstantFPRange PosZero;
static ConstantFPRange NegZero;
@@ -44,6 +45,8 @@ ConstantFPRange ConstantFPRangeTest::Empty =
ConstantFPRange::getEmpty(APFloat::IEEEdouble());
ConstantFPRange ConstantFPRangeTest::Finite =
ConstantFPRange::getFinite(APFloat::IEEEdouble());
+ConstantFPRange ConstantFPRangeTest::NonNaN =
+ ConstantFPRange::getNonNaN(APFloat::IEEEdouble());
ConstantFPRange ConstantFPRangeTest::One = ConstantFPRange(APFloat(1.0));
ConstantFPRange ConstantFPRangeTest::PosZero = ConstantFPRange(
APFloat::getZero(APFloat::IEEEdouble(), /*Negative=*/false));
@@ -137,15 +140,15 @@ static void EnumerateConstantFPRangesImpl(Fn TestFn, SparseLevel Level,
template <typename Fn>
static void EnumerateConstantFPRanges(Fn TestFn, SparseLevel Level,
- bool IgnoreNaNs = false) {
+ bool IgnoreSNaNs = false) {
EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,
/*MayBeSNaN=*/false);
- if (IgnoreNaNs)
+ EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,
+ /*MayBeSNaN=*/false);
+ if (IgnoreSNaNs)
return;
EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/false,
/*MayBeSNaN=*/true);
- EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,
- /*MayBeSNaN=*/false);
EnumerateConstantFPRangesImpl(TestFn, Level, /*MayBeQNaN=*/true,
/*MayBeSNaN=*/true);
}
@@ -157,9 +160,9 @@ static void EnumerateTwoInterestingConstantFPRanges(Fn TestFn,
[&](const ConstantFPRange &CR1) {
EnumerateConstantFPRanges(
[&](const ConstantFPRange &CR2) { TestFn(CR1, CR2); }, Level,
- /*IgnoreNaNs=*/true);
+ /*IgnoreSNaNs=*/true);
},
- Level, /*IgnoreNaNs=*/true);
+ Level, /*IgnoreSNaNs=*/true);
}
template <typename Fn>
@@ -826,13 +829,13 @@ TEST_F(ConstantFPRangeTest, negate) {
}
TEST_F(ConstantFPRangeTest, getWithout) {
- EXPECT_EQ(Full.getWithoutNaN(), ConstantFPRange::getNonNaN(Sem));
+ EXPECT_EQ(Full.getWithoutNaN(), NonNaN);
EXPECT_EQ(NaN.getWithoutNaN(), Empty);
EXPECT_EQ(NaN.getWithoutInf(), NaN);
EXPECT_EQ(PosInf.getWithoutInf(), Empty);
EXPECT_EQ(NegInf.getWithoutInf(), Empty);
- EXPECT_EQ(ConstantFPRange::getNonNaN(Sem).getWithoutInf(), Finite);
+ EXPECT_EQ(NonNaN.getWithoutInf(), Finite);
EXPECT_EQ(Zero.getWithoutInf(), Zero);
EXPECT_EQ(ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
APFloat(3.0))
@@ -948,7 +951,7 @@ TEST_F(ConstantFPRangeTest, cast) {
}
TEST_F(ConstantFPRangeTest, add) {
- EXPECT_EQ(Full.add(Full), ConstantFPRange::getNonNaN(Sem).unionWith(QNaN));
+ EXPECT_EQ(Full.add(Full), NonNaN.unionWith(QNaN));
EXPECT_EQ(Full.add(Empty), Empty);
EXPECT_EQ(Empty.add(Full), Empty);
EXPECT_EQ(Empty.add(Empty), Empty);
@@ -970,6 +973,11 @@ TEST_F(ConstantFPRangeTest, add) {
EXPECT_EQ(NegZero.add(NegZero), NegZero);
EXPECT_EQ(NegZero.add(Zero), Zero);
EXPECT_EQ(NaN.add(NaN), QNaN);
+ EXPECT_EQ(NaN.add(Finite), QNaN);
+ EXPECT_EQ(NonNaN.unionWith(NaN).add(NonNaN), NonNaN.unionWith(QNaN));
+ EXPECT_EQ(PosInf.unionWith(QNaN).add(PosInf), PosInf.unionWith(QNaN));
+ EXPECT_EQ(PosInf.unionWith(NaN).add(ConstantFPRange(APFloat(24.0))),
+ PosInf.unionWith(QNaN));
#if defined(EXPENSIVE_CHECKS)
EnumerateTwoInterestingConstantFPRanges(
@@ -1002,7 +1010,7 @@ TEST_F(ConstantFPRangeTest, add) {
}
TEST_F(ConstantFPRangeTest, sub) {
- EXPECT_EQ(Full.sub(Full), ConstantFPRange::getNonNaN(Sem).unionWith(QNaN));
+ EXPECT_EQ(Full.sub(Full), NonNaN.unionWith(QNaN));
EXPECT_EQ(Full.sub(Empty), Empty);
EXPECT_EQ(Empty.sub(Full), Empty);
EXPECT_EQ(Empty.sub(Empty), Empty);
@@ -1025,6 +1033,7 @@ TEST_F(ConstantFPRangeTest, sub) {
EXPECT_EQ(NegZero.sub(PosZero), NegZero);
EXPECT_EQ(NegZero.sub(Zero), Zero);
EXPECT_EQ(NaN.sub(NaN), QNaN);
+ EXPECT_EQ(NaN.add(Finite), QNaN);
#if defined(EXPENSIVE_CHECKS)
EnumerateTwoInterestingConstantFPRanges(
More information about the llvm-commits
mailing list