[llvm] [ConstantFPRange] Implement `ConstantFPRange::makeSatisfyingFCmpRegion` (PR #110891)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 7 21:20:06 PDT 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/110891
>From fba9d95ab94cde251b2cbd0eeab4227bc149e6d8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 3 Oct 2024 00:28:14 +0800
Subject: [PATCH 1/3] [ConstantFPRange] Implement
`ConstantFPRange::makeSatisfyingFCmpRegion`
---
llvm/lib/IR/ConstantFPRange.cpp | 44 ++++++++++++++-
llvm/unittests/IR/ConstantFPRangeTest.cpp | 69 +++++++++++++++++++++++
2 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp
index 74c9797d969f9d..d3c89daa9ce148 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -221,8 +221,48 @@ ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
ConstantFPRange
ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
const ConstantFPRange &Other) {
- // TODO
- return getEmpty(Other.getSemantics());
+ if (Other.isEmptySet())
+ return getFull(Other.getSemantics());
+ if (Other.containsNaN() && FCmpInst::isOrdered(Pred))
+ return getEmpty(Other.getSemantics());
+ if (Other.isNaNOnly() && FCmpInst::isUnordered(Pred))
+ return getFull(Other.getSemantics());
+
+ switch (Pred) {
+ case FCmpInst::FCMP_TRUE:
+ return getFull(Other.getSemantics());
+ case FCmpInst::FCMP_FALSE:
+ return getEmpty(Other.getSemantics());
+ case FCmpInst::FCMP_ORD:
+ return getNonNaN(Other.getSemantics());
+ case FCmpInst::FCMP_UNO:
+ return getNaNOnly(Other.getSemantics(), /*MayBeQNaN=*/true,
+ /*MayBeSNaN=*/true);
+ case FCmpInst::FCMP_OEQ:
+ case FCmpInst::FCMP_UEQ:
+ return setNaNField(Other.isSingleElement(/*ExcludesNaN=*/true) ||
+ ((Other.classify() & ~fcNan) == fcZero)
+ ? extendZeroIfEqual(Other, Pred)
+ : getEmpty(Other.getSemantics()),
+ Pred);
+ case FCmpInst::FCMP_ONE:
+ case FCmpInst::FCMP_UNE:
+ return getEmpty(Other.getSemantics());
+ case FCmpInst::FCMP_OLT:
+ case FCmpInst::FCMP_OLE:
+ case FCmpInst::FCMP_ULT:
+ case FCmpInst::FCMP_ULE:
+ return setNaNField(
+ extendZeroIfEqual(makeLessThan(Other.getLower(), Pred), Pred), Pred);
+ case FCmpInst::FCMP_OGT:
+ case FCmpInst::FCMP_OGE:
+ case FCmpInst::FCMP_UGT:
+ case FCmpInst::FCMP_UGE:
+ return setNaNField(
+ extendZeroIfEqual(makeGreaterThan(Other.getUpper(), Pred), Pred), Pred);
+ default:
+ llvm_unreachable("Unexpected predicate");
+ }
}
std::optional<ConstantFPRange>
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index 3c6e468b05bfda..e0883c297658a5 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -564,4 +564,73 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
#endif
}
+TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
+ for (auto Pred : FCmpInst::predicates()) {
+ EnumerateConstantFPRanges(
+ [Pred](const ConstantFPRange &CR) {
+ ConstantFPRange Res =
+ ConstantFPRange::makeSatisfyingFCmpRegion(Pred, CR);
+ // Super set of the optimal set excluding NaNs
+ ConstantFPRange SuperSet(CR.getSemantics());
+ bool ContainsSNaN = false;
+ bool ContainsQNaN = false;
+ unsigned NonNaNValsInOptimalSet = 0;
+ EnumerateValuesInConstantFPRange(
+ ConstantFPRange::getFull(CR.getSemantics()),
+ [&](const APFloat &V) {
+ if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
+ return !FCmpInst::compare(V, U, Pred);
+ })) {
+ EXPECT_FALSE(Res.contains(V))
+ << "Wrong result for makeSatisfyingFCmpRegion(" << Pred
+ << ", " << CR << "). The result " << Res
+ << " should not contain " << V;
+ } else {
+ if (V.isNaN()) {
+ if (V.isSignaling())
+ ContainsSNaN = true;
+ else
+ ContainsQNaN = true;
+ } else {
+ SuperSet = SuperSet.unionWith(ConstantFPRange(V));
+ ++NonNaNValsInOptimalSet;
+ }
+ }
+ });
+
+ // Check optimality
+
+ // The usefullness of making the result optimal for one/une is
+ // questionable.
+ if (Pred == FCmpInst::FCMP_ONE || Pred == FCmpInst::FCMP_UNE)
+ return;
+
+ EXPECT_FALSE(ContainsSNaN && !Res.containsSNaN())
+ << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
+ << ", " << CR << "), should contain SNaN, but got " << Res;
+ EXPECT_FALSE(ContainsQNaN && !Res.containsQNaN())
+ << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
+ << ", " << CR << "), should contain QNaN, but got " << Res;
+
+ // We only care about the cases where the result is representable by
+ // ConstantFPRange.
+ unsigned NonNaNValsInSuperSet = 0;
+ EnumerateValuesInConstantFPRange(SuperSet, [&](const APFloat &V) {
+ if (!V.isNaN())
+ ++NonNaNValsInSuperSet;
+ });
+
+ if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) {
+ ConstantFPRange Optimal =
+ ConstantFPRange(SuperSet.getLower(), SuperSet.getUpper(),
+ ContainsQNaN, ContainsSNaN);
+ EXPECT_EQ(Res, Optimal)
+ << "Suboptimal result for makeSatisfyingFCmpRegion(" << Pred
+ << ", " << CR << ")";
+ }
+ },
+ /*Exhaustive=*/false);
+ }
+}
+
} // anonymous namespace
>From c5045b578549adb8649e82c7906898090c5f11cf Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 3 Oct 2024 01:01:51 +0800
Subject: [PATCH 2/3] [ConstantFPRange] Add unittests for fcmp. NFC.
---
llvm/unittests/IR/ConstantFPRangeTest.cpp | 61 +++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index e0883c297658a5..03b9e4c6611f3d 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -633,4 +633,65 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
}
}
+TEST_F(ConstantFPRangeTest, fcmp) {
+ std::vector<ConstantFPRange> InterestingRanges;
+ const fltSemantics &Sem = APFloat::Float8E4M3();
+ auto FpImm = [&](double V) {
+ bool ignored;
+ APFloat APF(V);
+ APF.convert(Sem, APFloat::rmNearestTiesToEven, &ignored);
+ return APF;
+ };
+
+ InterestingRanges.push_back(ConstantFPRange::getEmpty(Sem));
+ InterestingRanges.push_back(ConstantFPRange::getFull(Sem));
+ InterestingRanges.push_back(ConstantFPRange::getFinite(Sem));
+ InterestingRanges.push_back(ConstantFPRange(FpImm(1.0)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/false)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getZero(Sem, /*Negative=*/true)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/false)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getSmallest(Sem, /*Negative=*/true)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/false)));
+ InterestingRanges.push_back(
+ ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true)));
+ InterestingRanges.push_back(
+ ConstantFPRange::getNaNOnly(Sem, /*MayBeQNaN=*/true, /*MayBeSNaN=*/true));
+ InterestingRanges.push_back(
+ ConstantFPRange::getNonNaN(FpImm(0.0), FpImm(1.0)));
+ InterestingRanges.push_back(
+ ConstantFPRange::getNonNaN(FpImm(2.0), FpImm(3.0)));
+ InterestingRanges.push_back(
+ ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(1.0)));
+ InterestingRanges.push_back(
+ ConstantFPRange::getNonNaN(FpImm(-1.0), FpImm(-0.0)));
+ InterestingRanges.push_back(ConstantFPRange::getNonNaN(
+ APFloat::getInf(Sem, /*Negative=*/true), FpImm(-1.0)));
+ InterestingRanges.push_back(ConstantFPRange::getNonNaN(
+ FpImm(1.0), APFloat::getInf(Sem, /*Negative=*/false)));
+
+ for (auto &LHS : InterestingRanges) {
+ for (auto &RHS : InterestingRanges) {
+ for (auto Pred : FCmpInst::predicates()) {
+ if (LHS.fcmp(Pred, RHS)) {
+ EnumerateValuesInConstantFPRange(LHS, [&](const APFloat &LHSC) {
+ EnumerateValuesInConstantFPRange(RHS, [&](const APFloat &RHSC) {
+ EXPECT_TRUE(FCmpInst::compare(LHSC, RHSC, Pred))
+ << LHS << " " << Pred << " " << RHS << " doesn't hold";
+ });
+ });
+ }
+ }
+ }
+ }
+}
+
} // anonymous namespace
>From 6e8377a76e96d13e2b364720005dd8896a28a362 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 8 Oct 2024 12:11:12 +0800
Subject: [PATCH 3/3] [ConstantFPRange] Guard exhaustive checks by
EXPENSIVE_CHECKS
---
llvm/unittests/IR/ConstantFPRangeTest.cpp | 77 ++++++++++++++++++-----
1 file changed, 63 insertions(+), 14 deletions(-)
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index 03b9e4c6611f3d..3ce64c64447e21 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -565,6 +565,40 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
}
TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
+ EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OLE,
+ ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
+ ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
+ APFloat(1.0)));
+ EXPECT_EQ(
+ ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OLT, ConstantFPRange::getNonNaN(
+ APFloat::getSmallest(Sem, /*Negative=*/false),
+ APFloat::getInf(Sem, /*Negative=*/false))),
+ ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
+ APFloat::getZero(Sem, /*Negative=*/false)));
+ EXPECT_EQ(
+ ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OGT, ConstantFPRange::getNonNaN(
+ APFloat::getZero(Sem, /*Negative=*/true),
+ APFloat::getZero(Sem, /*Negative=*/false))),
+ ConstantFPRange::getNonNaN(APFloat::getSmallest(Sem, /*Negative=*/false),
+ APFloat::getInf(Sem, /*Negative=*/false)));
+ EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OGE,
+ ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
+ ConstantFPRange::getNonNaN(
+ APFloat(2.0), APFloat::getInf(Sem, /*Negative=*/false)));
+ EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OEQ,
+ ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(2.0))),
+ ConstantFPRange::getEmpty(Sem));
+ EXPECT_EQ(ConstantFPRange::makeSatisfyingFCmpRegion(
+ FCmpInst::FCMP_OEQ,
+ ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0))),
+ ConstantFPRange::getNonNaN(APFloat(1.0), APFloat(1.0)));
+
+#if defined(EXPENSIVE_CHECKS)
for (auto Pred : FCmpInst::predicates()) {
EnumerateConstantFPRanges(
[Pred](const ConstantFPRange &CR) {
@@ -578,9 +612,12 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
EnumerateValuesInConstantFPRange(
ConstantFPRange::getFull(CR.getSemantics()),
[&](const APFloat &V) {
- if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
- return !FCmpInst::compare(V, U, Pred);
- })) {
+ if (AnyOfValueInConstantFPRange(
+ CR,
+ [&](const APFloat &U) {
+ return !FCmpInst::compare(V, U, Pred);
+ },
+ /*IgnoreNaNPayload=*/true)) {
EXPECT_FALSE(Res.contains(V))
<< "Wrong result for makeSatisfyingFCmpRegion(" << Pred
<< ", " << CR << "). The result " << Res
@@ -596,7 +633,8 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
++NonNaNValsInOptimalSet;
}
}
- });
+ },
+ /*IgnoreNaNPayload=*/true);
// Check optimality
@@ -615,10 +653,13 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
// We only care about the cases where the result is representable by
// ConstantFPRange.
unsigned NonNaNValsInSuperSet = 0;
- EnumerateValuesInConstantFPRange(SuperSet, [&](const APFloat &V) {
- if (!V.isNaN())
- ++NonNaNValsInSuperSet;
- });
+ EnumerateValuesInConstantFPRange(
+ SuperSet,
+ [&](const APFloat &V) {
+ if (!V.isNaN())
+ ++NonNaNValsInSuperSet;
+ },
+ /*IgnoreNaNPayload=*/true);
if (NonNaNValsInSuperSet == NonNaNValsInOptimalSet) {
ConstantFPRange Optimal =
@@ -631,6 +672,7 @@ TEST_F(ConstantFPRangeTest, makeSatisfyingFCmpRegion) {
},
/*Exhaustive=*/false);
}
+#endif
}
TEST_F(ConstantFPRangeTest, fcmp) {
@@ -682,12 +724,19 @@ TEST_F(ConstantFPRangeTest, fcmp) {
for (auto &RHS : InterestingRanges) {
for (auto Pred : FCmpInst::predicates()) {
if (LHS.fcmp(Pred, RHS)) {
- EnumerateValuesInConstantFPRange(LHS, [&](const APFloat &LHSC) {
- EnumerateValuesInConstantFPRange(RHS, [&](const APFloat &RHSC) {
- EXPECT_TRUE(FCmpInst::compare(LHSC, RHSC, Pred))
- << LHS << " " << Pred << " " << RHS << " doesn't hold";
- });
- });
+ EnumerateValuesInConstantFPRange(
+ LHS,
+ [&](const APFloat &LHSC) {
+ EnumerateValuesInConstantFPRange(
+ RHS,
+ [&](const APFloat &RHSC) {
+ EXPECT_TRUE(FCmpInst::compare(LHSC, RHSC, Pred))
+ << LHS << " " << Pred << " " << RHS
+ << " doesn't hold";
+ },
+ /*IgnoreNaNPayload=*/true);
+ },
+ /*IgnoreNaNPayload=*/true);
}
}
}
More information about the llvm-commits
mailing list