[llvm] [ConstantFPRange] Implement `ConstantFPRange::makeSatisfyingFCmpRegion` (PR #110891)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 2 10:09:31 PDT 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/110891
This patch adds support for `ConstantFPRange::makeSatisfyingFCmpRegion`. We only check the optimality for cases where the result can be represented by a ConstantFPRange.
This patch also adds some tests for `ConstantFPRange::fcmp` because it depends on `makeSatisfyingFCmpRegion`. Unfortunately we cannot exhaustively test this function due to time limit. I just pick some interesting ranges instead.
>From 2633b93eabc15bf208a1d11f5f74335030da691e 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/2] [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 17a08207fe1ba0..9a83de5e126e5d 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -470,4 +470,73 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
}
}
+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 3a98c87f68b10fc45fe31f04e03da051f94dd3a9 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/2] [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 9a83de5e126e5d..27121a4c017b60 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -539,4 +539,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
More information about the llvm-commits
mailing list