diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/ADT/APFloat.h | 9 | ||||
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 26 | ||||
-rw-r--r-- | llvm/unittests/ADT/APFloatTest.cpp | 128 |
3 files changed, 161 insertions, 2 deletions
diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 4d4ba8ffa17..3decdf2eca9 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -516,6 +516,8 @@ public: /// \brief Returns: X * 2^Exp for integral exponents. friend APFloat scalbn(APFloat X, int Exp, roundingMode); + friend APFloat frexp(const APFloat &X, int &Exp, roundingMode); + private: /// \name Simple Queries @@ -570,6 +572,7 @@ private: const APInt *fill); void makeInf(bool Neg = false); void makeZero(bool Neg = false); + void makeQuiet(); /// @} @@ -645,6 +648,12 @@ hash_code hash_value(const APFloat &Arg); int ilogb(const APFloat &Arg); APFloat scalbn(APFloat X, int Exp, APFloat::roundingMode); +/// \brief Equivalent of C standard library function. +/// +/// While the C standard says Exp is an unspecified value for infinity and nan, +/// this returns INT_MAX for infinities, and INT_MIN for NaNs. +APFloat frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM); + /// \brief Returns the absolute value of the argument. inline APFloat abs(APFloat X) { X.clearSign(); diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 814c72cc4d3..ada392c519b 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -3942,7 +3942,12 @@ APFloat::makeZero(bool Negative) { category = fcZero; sign = Negative; exponent = semantics->minExponent-1; - APInt::tcSet(significandParts(), 0, partCount()); + APInt::tcSet(significandParts(), 0, partCount()); +} + +void APFloat::makeQuiet() { + assert(isNaN()); + APInt::tcSetBit(significandParts(), semantics->precision - 2); } int llvm::ilogb(const APFloat &Arg) { @@ -3981,3 +3986,22 @@ APFloat llvm::scalbn(APFloat X, int Exp, APFloat::roundingMode RoundingMode) { X.normalize(RoundingMode, lfExactlyZero); return X; } + +APFloat llvm::frexp(const APFloat &Val, int &Exp, APFloat::roundingMode RM) { + Exp = ilogb(Val); + + // Quiet signalling nans. + if (Exp == APFloat::IEK_NaN) { + APFloat Quiet(Val); + Quiet.makeQuiet(); + return Quiet; + } + + if (Exp == APFloat::IEK_Inf) + return Val; + + // 1 is added because frexp is defined to return a normalized fraction in + // +/-[0.5, 1.0), rather than the usual +/-[1.0, 2.0). + Exp = Exp == APFloat::IEK_Zero ? 0 : Exp + 1; + return scalbn(Val, -Exp, RM); +} diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index e78caf3b898..01dcffa1148 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -1314,7 +1314,7 @@ TEST(APFloatTest, roundToIntegral) { P.roundToIntegral(APFloat::rmTowardZero); EXPECT_TRUE(std::isinf(P.convertToDouble()) && P.convertToDouble() < 0.0); } - + TEST(APFloatTest, isInteger) { APFloat T(-0.0); EXPECT_TRUE(T.isInteger()); @@ -3018,4 +3018,130 @@ TEST(APFloatTest, scalbn) { APFloat(APFloat::IEEEdouble, "0x1p-103") .bitwiseIsEqual(scalbn(APFloat(APFloat::IEEEdouble, "0x1p-51"), -52, RM))); } + +TEST(APFloatTest, frexp) { + const APFloat::roundingMode RM = APFloat::rmNearestTiesToEven; + + APFloat PZero = APFloat::getZero(APFloat::IEEEdouble, false); + APFloat MZero = APFloat::getZero(APFloat::IEEEdouble, true); + APFloat One(1.0); + APFloat MOne(-1.0); + APFloat Two(2.0); + APFloat MTwo(-2.0); + + APFloat LargestDenormal(APFloat::IEEEdouble, "0x1.ffffffffffffep-1023"); + APFloat NegLargestDenormal(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1023"); + + APFloat Smallest = APFloat::getSmallest(APFloat::IEEEdouble, false); + APFloat NegSmallest = APFloat::getSmallest(APFloat::IEEEdouble, true); + + APFloat Largest = APFloat::getLargest(APFloat::IEEEdouble, false); + APFloat NegLargest = APFloat::getLargest(APFloat::IEEEdouble, true); + + APFloat PInf = APFloat::getInf(APFloat::IEEEdouble, false); + APFloat MInf = APFloat::getInf(APFloat::IEEEdouble, true); + + APFloat QPNaN = APFloat::getNaN(APFloat::IEEEdouble, false); + APFloat QMNaN = APFloat::getNaN(APFloat::IEEEdouble, true); + APFloat SNaN = APFloat::getSNaN(APFloat::IEEEdouble, false); + + // Make sure highest bit of payload is preserved. + const APInt Payload(64, (UINT64_C(1) << 50) | + (UINT64_C(1) << 49) | + (UINT64_C(1234) << 32) | + 1); + + APFloat SNaNWithPayload = APFloat::getSNaN(APFloat::IEEEdouble, false, + &Payload); + + APFloat SmallestNormalized + = APFloat::getSmallestNormalized(APFloat::IEEEdouble, false); + APFloat NegSmallestNormalized + = APFloat::getSmallestNormalized(APFloat::IEEEdouble, true); + + int Exp; + APFloat Frac(APFloat::IEEEdouble); + + + Frac = frexp(PZero, Exp, RM); + EXPECT_EQ(0, Exp); + EXPECT_TRUE(Frac.isPosZero()); + + Frac = frexp(MZero, Exp, RM); + EXPECT_EQ(0, Exp); + EXPECT_TRUE(Frac.isNegZero()); + + + Frac = frexp(One, Exp, RM); + EXPECT_EQ(1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(MOne, Exp, RM); + EXPECT_EQ(1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(LargestDenormal, Exp, RM); + EXPECT_EQ(-1022, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.ffffffffffffep-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegLargestDenormal, Exp, RM); + EXPECT_EQ(-1022, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.ffffffffffffep-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(Smallest, Exp, RM); + EXPECT_EQ(-1073, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegSmallest, Exp, RM); + EXPECT_EQ(-1073, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1p-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(Largest, Exp, RM); + EXPECT_EQ(1024, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffffffffffffp-1").bitwiseIsEqual(Frac)); + + Frac = frexp(NegLargest, Exp, RM); + EXPECT_EQ(1024, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "-0x1.fffffffffffffp-1").bitwiseIsEqual(Frac)); + + + Frac = frexp(PInf, Exp, RM); + EXPECT_EQ(INT_MAX, Exp); + EXPECT_TRUE(Frac.isInfinity() && !Frac.isNegative()); + + Frac = frexp(MInf, Exp, RM); + EXPECT_EQ(INT_MAX, Exp); + EXPECT_TRUE(Frac.isInfinity() && Frac.isNegative()); + + Frac = frexp(QPNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN()); + + Frac = frexp(QMNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN()); + + Frac = frexp(SNaN, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN() && !Frac.isSignaling()); + + Frac = frexp(SNaNWithPayload, Exp, RM); + EXPECT_EQ(INT_MIN, Exp); + EXPECT_TRUE(Frac.isNaN() && !Frac.isSignaling()); + EXPECT_EQ(Payload, Frac.bitcastToAPInt().getLoBits(51)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x0.ffffp-1"), Exp, RM); + EXPECT_EQ(-1, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.fffep-1").bitwiseIsEqual(Frac)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1p-51"), Exp, RM); + EXPECT_EQ(-50, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1p-1").bitwiseIsEqual(Frac)); + + Frac = frexp(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp+51"), Exp, RM); + EXPECT_EQ(52, Exp); + EXPECT_TRUE(APFloat(APFloat::IEEEdouble, "0x1.c60f120d9f87cp-1").bitwiseIsEqual(Frac)); +} } |