-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ConstantFPRange] Implement ConstantFPRange::makeSatisfyingFCmpRegion
#110891
Conversation
@llvm/pr-subscribers-llvm-ir Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds support for This patch also adds some tests for Full diff: https://github.com/llvm/llvm-project/pull/110891.diff 2 Files Affected:
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..27121a4c017b60 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -470,4 +470,134 @@ 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);
+ }
+}
+
+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
|
3a98c87
to
6e8377a
Compare
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 onmakeSatisfyingFCmpRegion
. Unfortunately we cannot exhaustively test this function due to time limit. I just pick some interesting ranges instead.