[llvm] 191c1d9 - APFloat: Add isSmallestNormalized predicate function
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 15 11:04:48 PST 2022
Author: Matt Arsenault
Date: 2022-12-15T14:04:26-05:00
New Revision: 191c1d95e880227a13687c77c940f63baf88c594
URL: https://github.com/llvm/llvm-project/commit/191c1d95e880227a13687c77c940f63baf88c594
DIFF: https://github.com/llvm/llvm-project/commit/191c1d95e880227a13687c77c940f63baf88c594.diff
LOG: APFloat: Add isSmallestNormalized predicate function
It was annoying to write the check for this in the one case I added,
and I'm planning on adding another, so add a convenient PatternMatch
like for other special case values.
I have no idea what is going on in the DoubleAPFloat case, I reversed
this from the makeSmallestNormalized test. Also could implement this
as *this == getSmallestNormalized() for less code, but this avoids the
construction of a temporary APFloat copy and follows the style of the
other functions.
Added:
Modified:
llvm/include/llvm/ADT/APFloat.h
llvm/lib/Support/APFloat.cpp
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/unittests/ADT/APFloatTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h
index d86f72bf20dbd..a3961442b93f7 100644
--- a/llvm/include/llvm/ADT/APFloat.h
+++ b/llvm/include/llvm/ADT/APFloat.h
@@ -393,6 +393,10 @@ class IEEEFloat final : public APFloatBase {
/// magnitude in the current semantics.
bool isSmallest() const;
+ /// Returns true if this is the smallest (by magnitude) normalized finite
+ /// number in the given semantics.
+ bool isSmallestNormalized() const;
+
/// Returns true if and only if the number has the largest possible finite
/// magnitude in the current semantics.
bool isLargest() const;
@@ -517,6 +521,7 @@ class IEEEFloat final : public APFloatBase {
bool isSignificandAllOnesExceptLSB() const;
/// Return true if the significand excluding the integral bit is all zeros.
bool isSignificandAllZeros() const;
+ bool isSignificandAllZerosExceptMSB() const;
/// @}
@@ -694,6 +699,7 @@ class DoubleAPFloat final : public APFloatBase {
bool isDenormal() const;
bool isSmallest() const;
+ bool isSmallestNormalized() const;
bool isLargest() const;
bool isInteger() const;
@@ -1247,6 +1253,10 @@ class APFloat : public APFloatBase {
bool isInteger() const { APFLOAT_DISPATCH_ON_SEMANTICS(isInteger()); }
bool isIEEE() const { return usesLayout<IEEEFloat>(getSemantics()); }
+ bool isSmallestNormalized() const {
+ APFLOAT_DISPATCH_ON_SEMANTICS(isSmallestNormalized());
+ }
+
APFloat &operator=(const APFloat &RHS) = default;
APFloat &operator=(APFloat &&RHS) = default;
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 587521d55c656..bed4a3b6e3311 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -883,6 +883,11 @@ bool IEEEFloat::isSmallest() const {
significandMSB() == 0;
}
+bool IEEEFloat::isSmallestNormalized() const {
+ return getCategory() == fcNormal && exponent == semantics->minExponent &&
+ isSignificandAllZerosExceptMSB();
+}
+
bool IEEEFloat::isSignificandAllOnes() const {
// Test if the significand excluding the integral bit is all ones. This allows
// us to test for binade boundaries.
@@ -955,6 +960,21 @@ bool IEEEFloat::isSignificandAllZeros() const {
return true;
}
+bool IEEEFloat::isSignificandAllZerosExceptMSB() const {
+ const integerPart *Parts = significandParts();
+ const unsigned PartCount = partCountForBits(semantics->precision);
+
+ for (unsigned i = 0; i < PartCount - 1; i++) {
+ if (Parts[i])
+ return false;
+ }
+
+ const unsigned NumHighBits =
+ PartCount * integerPartWidth - semantics->precision + 1;
+ return Parts[PartCount - 1] == integerPart(1)
+ << (integerPartWidth - NumHighBits);
+}
+
bool IEEEFloat::isLargest() const {
if (semantics->nonFiniteBehavior == fltNonfiniteBehavior::NanOnly) {
// The largest number by magnitude in our format will be the floating point
@@ -4998,6 +5018,15 @@ bool DoubleAPFloat::isSmallest() const {
return Tmp.compare(*this) == cmpEqual;
}
+bool DoubleAPFloat::isSmallestNormalized() const {
+ if (getCategory() != fcNormal)
+ return false;
+
+ DoubleAPFloat Tmp(*this);
+ Tmp.makeSmallestNormalized(this->isNegative());
+ return Tmp.compare(*this) == cmpEqual;
+}
+
bool DoubleAPFloat::isLargest() const {
if (getCategory() != fcNormal)
return false;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c3d281e0b9c41..4877a5e42a6b0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -6781,7 +6781,7 @@ static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombinerImpl &IC) {
return nullptr;
if (!C->isPosZero()) {
- if (*C != APFloat::getSmallestNormalized(C->getSemantics()))
+ if (!C->isSmallestNormalized())
return nullptr;
const Function *F = I.getFunction();
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index c46508a87a9d2..ff295f7b40c72 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -664,6 +664,57 @@ TEST(APFloatTest, Denormal) {
}
}
+TEST(APFloatTest, IsSmallestNormalized) {
+ for (unsigned I = 0; I != APFloat::S_MaxSemantics + 1; ++I) {
+ const fltSemantics &Semantics =
+ APFloat::EnumToSemantics(static_cast<APFloat::Semantics>(I));
+
+ EXPECT_FALSE(APFloat::getZero(Semantics, false).isSmallestNormalized());
+ EXPECT_FALSE(APFloat::getZero(Semantics, true).isSmallestNormalized());
+
+ EXPECT_FALSE(APFloat::getInf(Semantics, false).isSmallestNormalized());
+ EXPECT_FALSE(APFloat::getInf(Semantics, true).isSmallestNormalized());
+
+ EXPECT_FALSE(APFloat::getQNaN(Semantics).isSmallestNormalized());
+ EXPECT_FALSE(APFloat::getSNaN(Semantics).isSmallestNormalized());
+
+ EXPECT_FALSE(APFloat::getLargest(Semantics).isSmallestNormalized());
+ EXPECT_FALSE(APFloat::getLargest(Semantics, true).isSmallestNormalized());
+
+ EXPECT_FALSE(APFloat::getSmallest(Semantics).isSmallestNormalized());
+ EXPECT_FALSE(APFloat::getSmallest(Semantics, true).isSmallestNormalized());
+
+ EXPECT_FALSE(APFloat::getAllOnesValue(Semantics).isSmallestNormalized());
+
+ APFloat PosSmallestNormalized =
+ APFloat::getSmallestNormalized(Semantics, false);
+ APFloat NegSmallestNormalized =
+ APFloat::getSmallestNormalized(Semantics, true);
+ EXPECT_TRUE(PosSmallestNormalized.isSmallestNormalized());
+ EXPECT_TRUE(NegSmallestNormalized.isSmallestNormalized());
+
+ for (APFloat *Val : {&PosSmallestNormalized, &NegSmallestNormalized}) {
+ bool OldSign = Val->isNegative();
+
+ // Step down, make sure it's still not smallest normalized.
+ EXPECT_EQ(APFloat::opOK, Val->next(false));
+ EXPECT_EQ(OldSign, Val->isNegative());
+ EXPECT_FALSE(Val->isSmallestNormalized());
+ EXPECT_EQ(OldSign, Val->isNegative());
+
+ // Step back up should restore it to being smallest normalized.
+ EXPECT_EQ(APFloat::opOK, Val->next(true));
+ EXPECT_TRUE(Val->isSmallestNormalized());
+ EXPECT_EQ(OldSign, Val->isNegative());
+
+ // Step beyond should no longer smallest normalized.
+ EXPECT_EQ(APFloat::opOK, Val->next(true));
+ EXPECT_FALSE(Val->isSmallestNormalized());
+ EXPECT_EQ(OldSign, Val->isNegative());
+ }
+ }
+}
+
TEST(APFloatTest, Zero) {
EXPECT_EQ(0.0f, APFloat(0.0f).convertToFloat());
EXPECT_EQ(-0.0f, APFloat(-0.0f).convertToFloat());
@@ -1723,6 +1774,7 @@ TEST(APFloatTest, getSmallestNormalized) {
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
test = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true);
expected = APFloat(APFloat::IEEEsingle(), "-0x1p-126");
@@ -1730,6 +1782,23 @@ TEST(APFloatTest, getSmallestNormalized) {
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
+
+ test = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false);
+ expected = APFloat(APFloat::IEEEdouble(), "0x1p-1022");
+ EXPECT_FALSE(test.isNegative());
+ EXPECT_TRUE(test.isFiniteNonZero());
+ EXPECT_FALSE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
+
+ test = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true);
+ expected = APFloat(APFloat::IEEEdouble(), "-0x1p-1022");
+ EXPECT_TRUE(test.isNegative());
+ EXPECT_TRUE(test.isFiniteNonZero());
+ EXPECT_FALSE(test.isDenormal());
+ EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), false);
expected = APFloat(APFloat::IEEEquad(), "0x1p-16382");
@@ -1737,6 +1806,7 @@ TEST(APFloatTest, getSmallestNormalized) {
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
test = APFloat::getSmallestNormalized(APFloat::IEEEquad(), true);
expected = APFloat(APFloat::IEEEquad(), "-0x1p-16382");
@@ -1744,6 +1814,7 @@ TEST(APFloatTest, getSmallestNormalized) {
EXPECT_TRUE(test.isFiniteNonZero());
EXPECT_FALSE(test.isDenormal());
EXPECT_TRUE(test.bitwiseIsEqual(expected));
+ EXPECT_TRUE(test.isSmallestNormalized());
}
TEST(APFloatTest, getZero) {
More information about the llvm-commits
mailing list