[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