[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