[llvm] [ConstantFPRange] Implement `ConstantFPRange::makeAllowedFCmpRegion` (PR #110082)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 2 01:09:57 PDT 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/110082

>From 6e3ad102b74677854a59fbff1936b975edf7368c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 26 Sep 2024 12:48:51 +0800
Subject: [PATCH 1/3] [ConstantFPRange] Implement
 `ConstantFPRange::makeAllowedFCmpRegion`

---
 llvm/lib/IR/ConstantFPRange.cpp           | 102 +++++++++++++++++++++-
 llvm/unittests/IR/ConstantFPRangeTest.cpp |  41 +++++++++
 2 files changed, 141 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp
index 3f63ca8e62c258..e01212cc31d51d 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -108,11 +108,109 @@ ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
                          /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
 }
 
+/// Return [-inf, V) or [-inf, V]
+static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
+  const fltSemantics &Sem = V.getSemantics();
+  if (!(Pred & FCmpInst::FCMP_OEQ)) {
+    if (V.isNegInfinity())
+      return ConstantFPRange::getEmpty(Sem);
+    V.next(/*nextDown=*/true);
+  }
+  return ConstantFPRange::getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
+                                    std::move(V));
+}
+
+/// Return (V, +inf] or [V, +inf]
+static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
+  const fltSemantics &Sem = V.getSemantics();
+  if (!(Pred & FCmpInst::FCMP_OEQ)) {
+    if (V.isPosInfinity())
+      return ConstantFPRange::getEmpty(Sem);
+    V.next(/*nextDown=*/false);
+  }
+  return ConstantFPRange::getNonNaN(std::move(V),
+                                    APFloat::getInf(Sem, /*Negative=*/false));
+}
+
+/// Make sure that +0/-0 are both included in the range.
+static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,
+                                         FCmpInst::Predicate Pred) {
+  if (!(Pred & FCmpInst::FCMP_OEQ))
+    return CR;
+
+  APFloat Lower = CR.getLower();
+  APFloat Upper = CR.getUpper();
+  if (Lower.isPosZero())
+    Lower = APFloat::getZero(Lower.getSemantics(), /*Negative=*/true);
+  if (Upper.isNegZero())
+    Upper = APFloat::getZero(Upper.getSemantics(), /*Negative=*/false);
+  return ConstantFPRange(std::move(Lower), std::move(Upper), CR.containsQNaN(),
+                         CR.containsSNaN());
+}
+
+static ConstantFPRange setNaNField(const ConstantFPRange &CR,
+                                   FCmpInst::Predicate Pred) {
+  bool ContainsNaN = FCmpInst::isUnordered(Pred);
+  return ConstantFPRange(CR.getLower(), CR.getUpper(),
+                         /*MayBeQNaN=*/ContainsNaN, /*MayBeSNaN=*/ContainsNaN);
+}
+
 ConstantFPRange
 ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
                                        const ConstantFPRange &Other) {
-  // TODO
-  return getFull(Other.getSemantics());
+  if (Other.isEmptySet())
+    return Other;
+  if (Other.containsNaN() && FCmpInst::isUnordered(Pred))
+    return getFull(Other.getSemantics());
+  if (Other.isNaNOnly() && FCmpInst::isOrdered(Pred))
+    return getEmpty(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(extendZeroIfEqual(Other, Pred), Pred);
+  case FCmpInst::FCMP_ONE:
+  case FCmpInst::FCMP_UNE:
+    if (const APFloat *SingleElement =
+            Other.getSingleElement(/*ExcludesNaN=*/true)) {
+      const fltSemantics &Sem = SingleElement->getSemantics();
+      if (SingleElement->isPosInfinity())
+        return setNaNField(
+            getNonNaN(APFloat::getInf(Sem, /*Negative=*/true),
+                      APFloat::getLargest(Sem, /*Negative=*/false)),
+            Pred);
+      if (SingleElement->isNegInfinity())
+        return setNaNField(
+            getNonNaN(APFloat::getLargest(Sem, /*Negative=*/true),
+                      APFloat::getInf(Sem, /*Negative=*/false)),
+            Pred);
+    }
+    return Pred == FCmpInst::FCMP_ONE ? getNonNaN(Other.getSemantics())
+                                      : getFull(Other.getSemantics());
+  case FCmpInst::FCMP_OLT:
+  case FCmpInst::FCMP_OLE:
+  case FCmpInst::FCMP_ULT:
+  case FCmpInst::FCMP_ULE:
+    return setNaNField(
+        extendZeroIfEqual(makeLessThan(Other.getUpper(), Pred), Pred), Pred);
+  case FCmpInst::FCMP_OGT:
+  case FCmpInst::FCMP_OGE:
+  case FCmpInst::FCMP_UGT:
+  case FCmpInst::FCMP_UGE:
+    return setNaNField(
+        extendZeroIfEqual(makeGreaterThan(Other.getLower(), Pred), Pred), Pred);
+  default:
+    llvm_unreachable("Unexpected predicate");
+  }
 }
 
 ConstantFPRange
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index d228651b5129cc..1fe9231392d622 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -161,6 +161,19 @@ static void EnumerateValuesInConstantFPRange(const ConstantFPRange &CR,
   }
 }
 
+template <typename Fn>
+static bool AnyOfValueInConstantFPRange(const ConstantFPRange &CR, Fn TestFn) {
+  const fltSemantics &Sem = CR.getSemantics();
+  unsigned Bits = APFloat::semanticsSizeInBits(Sem);
+  assert(Bits < 32 && "Too many bits");
+  for (unsigned I = 0, E = (1U << Bits) - 1; I != E; ++I) {
+    APFloat V(Sem, APInt(Bits, I));
+    if (CR.contains(V) && TestFn(V))
+      return true;
+  }
+  return false;
+}
+
 TEST_F(ConstantFPRangeTest, Basics) {
   EXPECT_TRUE(Full.isFullSet());
   EXPECT_FALSE(Full.isEmptySet());
@@ -429,4 +442,32 @@ TEST_F(ConstantFPRangeTest, MismatchedSemantics) {
 #endif
 #endif
 
+TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
+  for (auto Pred : FCmpInst::predicates()) {
+    EnumerateConstantFPRanges(
+        [Pred](const ConstantFPRange &CR) {
+          ConstantFPRange Res =
+              ConstantFPRange::makeAllowedFCmpRegion(Pred, CR);
+          ConstantFPRange Optimal =
+              ConstantFPRange::getEmpty(CR.getSemantics());
+          EnumerateValuesInConstantFPRange(
+              ConstantFPRange::getFull(CR.getSemantics()),
+              [&](const APFloat &V) {
+                if (AnyOfValueInConstantFPRange(CR, [&](const APFloat &U) {
+                      return FCmpInst::compare(V, U, Pred);
+                    }))
+                  Optimal = Optimal.unionWith(ConstantFPRange(V));
+              });
+
+          ASSERT_TRUE(Res.contains(Optimal))
+              << "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR
+              << "). Expected " << Optimal << ", but got " << Res;
+          EXPECT_EQ(Res, Optimal)
+              << "Suboptimal result for makeAllowedFCmpRegion(" << Pred << ", "
+              << CR << ")";
+        },
+        /*Exhaustive=*/false);
+  }
+}
+
 } // anonymous namespace

>From 23f064f3fab3ab70c08d769fb378af03eb2aabd0 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 1 Oct 2024 10:47:38 +0800
Subject: [PATCH 2/3] [ConstantFPRange] Address review comments. NFC.

---
 llvm/lib/IR/ConstantFPRange.cpp           | 6 +++---
 llvm/unittests/IR/ConstantFPRangeTest.cpp | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp
index e01212cc31d51d..29d9a9c0981e3c 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -111,7 +111,7 @@ ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
 /// Return [-inf, V) or [-inf, V]
 static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
   const fltSemantics &Sem = V.getSemantics();
-  if (!(Pred & FCmpInst::FCMP_OEQ)) {
+  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred))) {
     if (V.isNegInfinity())
       return ConstantFPRange::getEmpty(Sem);
     V.next(/*nextDown=*/true);
@@ -123,7 +123,7 @@ static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
 /// Return (V, +inf] or [V, +inf]
 static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
   const fltSemantics &Sem = V.getSemantics();
-  if (!(Pred & FCmpInst::FCMP_OEQ)) {
+  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred))) {
     if (V.isPosInfinity())
       return ConstantFPRange::getEmpty(Sem);
     V.next(/*nextDown=*/false);
@@ -135,7 +135,7 @@ static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
 /// Make sure that +0/-0 are both included in the range.
 static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,
                                          FCmpInst::Predicate Pred) {
-  if (!(Pred & FCmpInst::FCMP_OEQ))
+  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred)))
     return CR;
 
   APFloat Lower = CR.getLower();
diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp
index 1fe9231392d622..17a08207fe1ba0 100644
--- a/llvm/unittests/IR/ConstantFPRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp
@@ -459,7 +459,7 @@ TEST_F(ConstantFPRangeTest, makeAllowedFCmpRegion) {
                   Optimal = Optimal.unionWith(ConstantFPRange(V));
               });
 
-          ASSERT_TRUE(Res.contains(Optimal))
+          EXPECT_TRUE(Res.contains(Optimal))
               << "Wrong result for makeAllowedFCmpRegion(" << Pred << ", " << CR
               << "). Expected " << Optimal << ", but got " << Res;
           EXPECT_EQ(Res, Optimal)

>From 5da6f23f6a935e23d286efaf2e2d6a38fbdbe54f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 2 Oct 2024 16:09:17 +0800
Subject: [PATCH 3/3] [ConstantFPRange] Address review comments. NFC.

---
 llvm/lib/IR/ConstantFPRange.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/IR/ConstantFPRange.cpp b/llvm/lib/IR/ConstantFPRange.cpp
index 29d9a9c0981e3c..74c9797d969f9d 100644
--- a/llvm/lib/IR/ConstantFPRange.cpp
+++ b/llvm/lib/IR/ConstantFPRange.cpp
@@ -108,10 +108,15 @@ ConstantFPRange ConstantFPRange::getNonNaN(const fltSemantics &Sem) {
                          /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
 }
 
+/// Return true for ULT/UGT/OLT/OGT
+static bool fcmpPredExcludesEqual(FCmpInst::Predicate Pred) {
+  return !(Pred & FCmpInst::FCMP_OEQ);
+}
+
 /// Return [-inf, V) or [-inf, V]
 static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
   const fltSemantics &Sem = V.getSemantics();
-  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred))) {
+  if (fcmpPredExcludesEqual(Pred)) {
     if (V.isNegInfinity())
       return ConstantFPRange::getEmpty(Sem);
     V.next(/*nextDown=*/true);
@@ -123,7 +128,7 @@ static ConstantFPRange makeLessThan(APFloat V, FCmpInst::Predicate Pred) {
 /// Return (V, +inf] or [V, +inf]
 static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
   const fltSemantics &Sem = V.getSemantics();
-  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred))) {
+  if (fcmpPredExcludesEqual(Pred)) {
     if (V.isPosInfinity())
       return ConstantFPRange::getEmpty(Sem);
     V.next(/*nextDown=*/false);
@@ -135,7 +140,7 @@ static ConstantFPRange makeGreaterThan(APFloat V, FCmpInst::Predicate Pred) {
 /// Make sure that +0/-0 are both included in the range.
 static ConstantFPRange extendZeroIfEqual(const ConstantFPRange &CR,
                                          FCmpInst::Predicate Pred) {
-  if (FCmpInst::isFalseWhenEqual(FCmpInst::getOrderedPredicate(Pred)))
+  if (fcmpPredExcludesEqual(Pred))
     return CR;
 
   APFloat Lower = CR.getLower();



More information about the llvm-commits mailing list