From 71f1ea2c15bbc5b604e20d71191a16d57d106dc0 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 2 Mar 2023 05:44:05 -0400 Subject: [PATCH] APFloat: Add classify --- llvm/include/llvm/ADT/APFloat.h | 3 +++ llvm/lib/Support/APFloat.cpp | 13 +++++++++++++ llvm/unittests/ADT/APFloatTest.cpp | 31 +++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 3823850..c306465 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1280,6 +1280,9 @@ public: APFLOAT_DISPATCH_ON_SEMANTICS(isSmallestNormalized()); } + /// Return the FPClassTest which will return true for the value. + FPClassTest classify() const; + 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 fdf16f6..0505382 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -5361,6 +5361,19 @@ APFloat::APFloat(const fltSemantics &Semantics, StringRef S) consumeError(StatusOrErr.takeError()); } +FPClassTest APFloat::classify() const { + if (isZero()) + return isNegative() ? fcNegZero : fcPosZero; + if (isNormal()) + return isNegative() ? fcNegNormal : fcPosNormal; + if (isDenormal()) + return isNegative() ? fcNegSubnormal : fcPosSubnormal; + if (isInfinity()) + return isNegative() ? fcNegInf : fcPosInf; + assert(isNaN() && "Other class of FP constant"); + return isSignaling() ? fcSNan : fcQNan; +} + APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo) { if (&getSemantics() == &ToSemantics) { diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 2ec8ebf..79c6a3f 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -53,11 +53,18 @@ TEST(APFloatTest, isSignaling) { // positive/negative distinction is included only since the getQNaN/getSNaN // API provides the option. APInt payload = APInt::getOneBitSet(4, 2); - EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), false).isSignaling()); + APFloat QNan = APFloat::getQNaN(APFloat::IEEEsingle(), false); + EXPECT_FALSE(QNan.isSignaling()); + EXPECT_EQ(fcQNan, QNan.classify()); + EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), true).isSignaling()); EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), false, &payload).isSignaling()); EXPECT_FALSE(APFloat::getQNaN(APFloat::IEEEsingle(), true, &payload).isSignaling()); - EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), false).isSignaling()); + + APFloat SNan = APFloat::getSNaN(APFloat::IEEEsingle(), false); + EXPECT_TRUE(SNan.isSignaling()); + EXPECT_EQ(fcSNan, SNan.classify()); + EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), true).isSignaling()); EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), false, &payload).isSignaling()); EXPECT_TRUE(APFloat::getSNaN(APFloat::IEEEsingle(), true, &payload).isSignaling()); @@ -626,6 +633,15 @@ TEST(APFloatTest, Denormal) { APFloat T(APFloat::IEEEsingle(), MinNormalStr); T.divide(Val2, rdmd); EXPECT_TRUE(T.isDenormal()); + EXPECT_EQ(fcPosSubnormal, T.classify()); + + + const char *NegMinNormalStr = "-1.17549435082228750797e-38"; + EXPECT_FALSE(APFloat(APFloat::IEEEsingle(), NegMinNormalStr).isDenormal()); + APFloat NegT(APFloat::IEEEsingle(), NegMinNormalStr); + NegT.divide(Val2, rdmd); + EXPECT_TRUE(NegT.isDenormal()); + EXPECT_EQ(fcNegSubnormal, NegT.classify()); } // Test double precision @@ -638,6 +654,7 @@ TEST(APFloatTest, Denormal) { APFloat T(APFloat::IEEEdouble(), MinNormalStr); T.divide(Val2, rdmd); EXPECT_TRUE(T.isDenormal()); + EXPECT_EQ(fcPosSubnormal, T.classify()); } // Test Intel double-ext @@ -650,6 +667,7 @@ TEST(APFloatTest, Denormal) { APFloat T(APFloat::x87DoubleExtended(), MinNormalStr); T.divide(Val2, rdmd); EXPECT_TRUE(T.isDenormal()); + EXPECT_EQ(fcPosSubnormal, T.classify()); } // Test quadruple precision @@ -662,6 +680,7 @@ TEST(APFloatTest, Denormal) { APFloat T(APFloat::IEEEquad(), MinNormalStr); T.divide(Val2, rdmd); EXPECT_TRUE(T.isDenormal()); + EXPECT_EQ(fcPosSubnormal, T.classify()); } } @@ -693,6 +712,8 @@ TEST(APFloatTest, IsSmallestNormalized) { APFloat::getSmallestNormalized(Semantics, true); EXPECT_TRUE(PosSmallestNormalized.isSmallestNormalized()); EXPECT_TRUE(NegSmallestNormalized.isSmallestNormalized()); + EXPECT_EQ(fcPosNormal, PosSmallestNormalized.classify()); + EXPECT_EQ(fcNegNormal, NegSmallestNormalized.classify()); for (APFloat *Val : {&PosSmallestNormalized, &NegSmallestNormalized}) { bool OldSign = Val->isNegative(); @@ -724,6 +745,9 @@ TEST(APFloatTest, Zero) { EXPECT_EQ(0.0, APFloat(0.0).convertToDouble()); EXPECT_EQ(-0.0, APFloat(-0.0).convertToDouble()); EXPECT_TRUE(APFloat(-0.0).isNegative()); + + EXPECT_EQ(fcPosZero, APFloat(0.0).classify()); + EXPECT_EQ(fcNegZero, APFloat(-0.0).classify()); } TEST(APFloatTest, DecimalStringsWithoutNullTerminators) { @@ -2195,9 +2219,12 @@ TEST(APFloatTest, isInfinity) { EXPECT_TRUE(PosInf.isInfinity()); EXPECT_TRUE(PosInf.isPosInfinity()); EXPECT_FALSE(PosInf.isNegInfinity()); + EXPECT_EQ(fcPosInf, PosInf.classify()); + EXPECT_TRUE(NegInf.isInfinity()); EXPECT_FALSE(NegInf.isPosInfinity()); EXPECT_TRUE(NegInf.isNegInfinity()); + EXPECT_EQ(fcNegInf, NegInf.classify()); EXPECT_FALSE(APFloat::getZero(APFloat::IEEEsingle(), false).isInfinity()); EXPECT_FALSE(APFloat::getNaN(APFloat::IEEEsingle(), false).isInfinity()); -- 2.7.4