diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1132,8 +1132,20 @@ APInt bitcastToAPInt() const { APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt()); } - double convertToDouble() const { return getIEEE().convertToDouble(); } - float convertToFloat() const { return getIEEE().convertToFloat(); } + + /// Converts this APFloat to host double value. + /// + /// \pre The APFloat must be built using semantics, that can be represented by + /// the host double type without loss of precision. It can be IEEEdouble and + /// shorter semantics, like IEEEsingle and others. + double convertToDouble() const; + + /// Converts this APFloat to host float value. + /// + /// \pre The APFloat must be built using semantics, that can be represented by + /// the host float type without loss of precision. It can be IEEEsingle and + /// shorter semantics, like IEEEhalf. + float convertToFloat() const; bool operator==(const APFloat &RHS) const { return compare(RHS) == cmpEqual; } diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1794,10 +1794,7 @@ double getValueAsDouble(ConstantFP *Op) { Type *Ty = Op->getType(); - if (Ty->isFloatTy()) - return Op->getValueAPF().convertToFloat(); - - if (Ty->isDoubleTy()) + if (Ty->isBFloatTy() || Ty->isHalfTy() || Ty->isFloatTy() || Ty->isDoubleTy()) return Op->getValueAPF().convertToDouble(); bool unused; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -953,9 +953,9 @@ switch (Op.getType()) { case MachineOperand::MO_FPImmediate: { APFloat APF = APFloat(Op.getFPImm()->getValueAPF()); - if (Op.getFPImm()->getType()->isFloatTy()) { - OS << (double)APF.convertToFloat(); - } else if (Op.getFPImm()->getType()->isDoubleTy()) { + Type *ImmTy = Op.getFPImm()->getType(); + if (ImmTy->isBFloatTy() || ImmTy->isHalfTy() || ImmTy->isFloatTy() || + ImmTy->isDoubleTy()) { OS << APF.convertToDouble(); } else { // There is no good way to print long double. Convert a copy to diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1368,7 +1368,7 @@ bool isInf = APF.isInfinity(); bool isNaN = APF.isNaN(); if (!isInf && !isNaN) { - double Val = isDouble ? APF.convertToDouble() : APF.convertToFloat(); + double Val = APF.convertToDouble(); SmallString<128> StrVal; APF.toString(StrVal, 6, 0, false); // Check to make sure that the stringized number is not some string like diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -1399,12 +1399,8 @@ ConstantFP *cFP = unwrap(ConstantVal) ; Type *Ty = cFP->getType(); - if (Ty->isFloatTy()) { - *LosesInfo = false; - return cFP->getValueAPF().convertToFloat(); - } - - if (Ty->isDoubleTy()) { + if (Ty->isHalfTy() || Ty->isBFloatTy() || Ty->isFloatTy() || + Ty->isDoubleTy()) { *LosesInfo = false; return cFP->getValueAPF().convertToDouble(); } diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -66,6 +66,13 @@ /* Number of bits actually used in the semantics. */ unsigned int sizeInBits; + + // Returns true if any number described by this semantics can be precisely + // represented by the specified semantics. + bool isRepresentableBy(const fltSemantics &S) const { + return maxExponent <= S.maxExponent && minExponent >= S.minExponent && + precision <= S.precision; + } }; static const fltSemantics semIEEEhalf = {15, -14, 11, 16}; @@ -4875,6 +4882,32 @@ return status; } +double APFloat::convertToDouble() const { + if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEdouble) + return getIEEE().convertToDouble(); + assert(getSemantics().isRepresentableBy(semIEEEdouble) && + "Float semantics is not representable by IEEEdouble"); + APFloat Temp = *this; + bool LosesInfo; + opStatus St = Temp.convert(semIEEEdouble, rmNearestTiesToEven, &LosesInfo); + assert(!(St & opInexact) && !LosesInfo && "Unexpected imprecision"); + (void)St; + return Temp.getIEEE().convertToDouble(); +} + +float APFloat::convertToFloat() const { + if (&getSemantics() == (const llvm::fltSemantics *)&semIEEEsingle) + return getIEEE().convertToFloat(); + assert(getSemantics().isRepresentableBy(semIEEEsingle) && + "Float semantics is not representable by IEEEsingle"); + APFloat Temp = *this; + bool LosesInfo; + opStatus St = Temp.convert(semIEEEsingle, rmNearestTiesToEven, &LosesInfo); + assert(!(St & opInexact) && !LosesInfo && "Unexpected imprecision"); + (void)St; + return Temp.getIEEE().convertToFloat(); +} + } // namespace llvm #undef APFLOAT_DISPATCH_ON_SEMANTICS diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -1271,8 +1271,10 @@ #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG TEST(APFloatTest, SemanticsDeath) { - EXPECT_DEATH(APFloat(APFloat::IEEEsingle(), 0).convertToDouble(), "Float semantics are not IEEEdouble"); - EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0).convertToFloat(), "Float semantics are not IEEEsingle"); + EXPECT_DEATH(APFloat(APFloat::IEEEquad(), 0).convertToDouble(), + "Float semantics is not representable by IEEEdouble"); + EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0).convertToFloat(), + "Float semantics is not representable by IEEEsingle"); } #endif #endif @@ -4709,4 +4711,185 @@ F.next(false); EXPECT_TRUE(ilogb(F) == -1); } + +TEST(APFloatTest, ToDouble) { + APFloat D1(0.0); + EXPECT_EQ(0.0, D1.convertToDouble()); + APFloat D2(-0.0); + EXPECT_EQ(-0.0, D1.convertToDouble()); + APFloat D3(1.0); + EXPECT_EQ(1.0, D3.convertToDouble()); + APFloat D4 = APFloat::getLargest(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits::max(), D4.convertToDouble()); + APFloat D5 = APFloat::getLargest(APFloat::IEEEdouble(), true); + EXPECT_EQ(-std::numeric_limits::max(), D5.convertToDouble()); + APFloat D6 = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits::min(), D6.convertToDouble()); + APFloat D7 = APFloat::getSmallestNormalized(APFloat::IEEEdouble(), true); + EXPECT_EQ(-std::numeric_limits::min(), D7.convertToDouble()); + APFloat D8 = APFloat::getSmallest(APFloat::IEEEdouble(), false); + EXPECT_EQ(std::numeric_limits::denorm_min(), D8.convertToDouble()); + APFloat D9(APFloat::IEEEdouble(), "0x0.FFFFFFFFFFFFFp-1022"); + EXPECT_EQ(/*0x0.FFFFFFFFFFFFFp-1022*/ 2.225073858507201e-308, + D9.convertToDouble()); + + APFloat D10 = APFloat::getInf(APFloat::IEEEdouble()); + EXPECT_TRUE(std::isinf(D10.convertToDouble())); + EXPECT_TRUE(0 < D10.convertToDouble()); + APFloat D11 = APFloat::getInf(APFloat::IEEEdouble(), true); + EXPECT_TRUE(std::isinf(D11.convertToDouble())); + EXPECT_TRUE(0 > D11.convertToDouble()); + APFloat D12 = APFloat::getQNaN(APFloat::IEEEdouble()); + EXPECT_TRUE(std::isnan(D12.convertToDouble())); + + APFloat F1(0.0F); + EXPECT_EQ(0.0, F1.convertToDouble()); + APFloat F2(-0.0F); + EXPECT_EQ(-0.0, F1.convertToDouble()); + APFloat F3(1.0F); + EXPECT_EQ(1.0, F3.convertToDouble()); + APFloat F4 = APFloat::getLargest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::max(), F4.convertToDouble()); + APFloat F5 = APFloat::getLargest(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits::max(), F5.convertToDouble()); + APFloat F6 = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::min(), F6.convertToDouble()); + APFloat F7 = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits::min(), F7.convertToDouble()); + APFloat F8 = APFloat::getSmallest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::denorm_min(), F8.convertToDouble()); + APFloat F9(APFloat::IEEEdouble(), "0x0.FFFFFEp-126"); + EXPECT_EQ(/*0x0.FFFFFEp-126*/ 1.1754942106924411e-38, F9.convertToDouble()); + + APFloat F10 = APFloat::getInf(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isinf(F10.convertToDouble())); + EXPECT_TRUE(0 < F10.convertToDouble()); + APFloat F11 = APFloat::getInf(APFloat::IEEEsingle(), true); + EXPECT_TRUE(std::isinf(F11.convertToDouble())); + EXPECT_TRUE(0 > F11.convertToDouble()); + APFloat F12 = APFloat::getQNaN(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isnan(F12.convertToDouble())); + + APFloat H1 = APFloat::getZero(APFloat::IEEEhalf()); + EXPECT_EQ(0.0, H1.convertToDouble()); + APFloat H2 = APFloat::getZero(APFloat::IEEEhalf(), true); + EXPECT_EQ(-0.0, H1.convertToDouble()); + APFloat H3(APFloat::IEEEhalf(), "1.0"); + EXPECT_EQ(1.0, H3.convertToDouble()); + APFloat H4 = APFloat::getLargest(APFloat::IEEEhalf(), false); + EXPECT_EQ(65504, H4.convertToDouble()); + APFloat H5 = APFloat::getLargest(APFloat::IEEEhalf(), true); + EXPECT_EQ(-65504, H5.convertToDouble()); + APFloat H6 = APFloat::getSmallestNormalized(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-14*/ 6.103515625e-05, H6.convertToDouble()); + APFloat H7 = APFloat::getSmallestNormalized(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.p-14*/ -6.103515625e-05, H7.convertToDouble()); + APFloat H8 = APFloat::getSmallest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-24*/ 5.960464477539063e-08, H8.convertToDouble()); + APFloat H9(APFloat::IEEEhalf(), "0x1.FFCp-14"); + EXPECT_EQ(/*0x1.FFCp-14*/ 0.00012201070785522461, H9.convertToDouble()); + + APFloat H10 = APFloat::getInf(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isinf(H10.convertToDouble())); + EXPECT_TRUE(0 < H10.convertToDouble()); + APFloat H11 = APFloat::getInf(APFloat::IEEEhalf(), true); + EXPECT_TRUE(std::isinf(H11.convertToDouble())); + EXPECT_TRUE(0 > H11.convertToDouble()); + APFloat H12 = APFloat::getQNaN(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isnan(H12.convertToDouble())); + + APFloat B1 = APFloat::getZero(APFloat::BFloat()); + EXPECT_EQ(0.0, B1.convertToDouble()); + APFloat B2 = APFloat::getZero(APFloat::BFloat(), true); + EXPECT_EQ(-0.0, B1.convertToDouble()); + APFloat B3(APFloat::BFloat(), "1.0"); + EXPECT_EQ(1.0, B3.convertToDouble()); + APFloat B4 = APFloat::getLargest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.FEp127*/ 3.3895313892515355e+38, B4.convertToDouble()); + APFloat B5 = APFloat::getLargest(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.FEp127*/ -3.3895313892515355e+38, B5.convertToDouble()); + APFloat B6 = APFloat::getSmallestNormalized(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-126*/ 1.1754943508222875e-38, B6.convertToDouble()); + APFloat B7 = APFloat::getSmallestNormalized(APFloat::BFloat(), true); + EXPECT_EQ(/*-0x1.p-126*/ -1.1754943508222875e-38, B7.convertToDouble()); + APFloat B8 = APFloat::getSmallest(APFloat::BFloat(), false); + EXPECT_EQ(/*0x1.p-133*/ 9.183549615799121e-41, B8.convertToDouble()); + APFloat B9(APFloat::BFloat(), "0x1.FCp-127"); + EXPECT_EQ(/*0x1.FCp-127*/ 1.1663108012064884e-38, B9.convertToDouble()); + + APFloat B10 = APFloat::getInf(APFloat::BFloat()); + EXPECT_TRUE(std::isinf(B10.convertToDouble())); + EXPECT_TRUE(0 < B10.convertToDouble()); + EXPECT_EQ(0x7F80ULL, B10.bitcastToAPInt().getRawData()[0]); + APFloat B11 = APFloat::getInf(APFloat::BFloat(), true); + EXPECT_TRUE(std::isinf(B11.convertToDouble())); + EXPECT_TRUE(0 > B11.convertToDouble()); + EXPECT_EQ(0xFF80ULL, B11.bitcastToAPInt().getRawData()[0]); + APFloat B12 = APFloat::getQNaN(APFloat::BFloat()); + EXPECT_TRUE(std::isnan(B12.convertToDouble())); +} + +TEST(APFloatTest, ToFloat) { + APFloat F1(0.0F); + EXPECT_EQ(0.0F, F1.convertToFloat()); + APFloat F2(-0.0F); + EXPECT_EQ(-0.0F, F1.convertToFloat()); + APFloat F3(1.0F); + EXPECT_EQ(1.0F, F3.convertToFloat()); + APFloat F4 = APFloat::getLargest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::max(), F4.convertToFloat()); + APFloat F5 = APFloat::getLargest(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits::max(), F5.convertToFloat()); + APFloat F6 = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::min(), F6.convertToFloat()); + APFloat F7 = APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true); + EXPECT_EQ(-std::numeric_limits::min(), F7.convertToFloat()); + APFloat F8 = APFloat::getSmallest(APFloat::IEEEsingle(), false); + EXPECT_EQ(std::numeric_limits::denorm_min(), F8.convertToFloat()); + APFloat F9(APFloat::IEEEsingle(), "0x1.FFFFFEp-126"); + EXPECT_EQ(/*0x1.FFFFFEp-126*/ 2.3509885615147286e-38F, F9.convertToFloat()); + + APFloat F10 = APFloat::getInf(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isinf(F10.convertToDouble())); + EXPECT_TRUE(0 < F10.convertToDouble()); + APFloat F11 = APFloat::getInf(APFloat::IEEEsingle(), true); + EXPECT_TRUE(std::isinf(F11.convertToDouble())); + EXPECT_TRUE(0 > F11.convertToDouble()); + APFloat F12 = APFloat::getQNaN(APFloat::IEEEsingle()); + EXPECT_TRUE(std::isnan(F12.convertToDouble())); + APFloat F13 = APFloat::getQNaN(APFloat::IEEEsingle(), true); + EXPECT_TRUE(std::isnan(F13.convertToDouble())); + + APFloat H1 = APFloat::getZero(APFloat::IEEEhalf()); + EXPECT_EQ(0.0F, H1.convertToDouble()); + APFloat H2 = APFloat::getZero(APFloat::IEEEhalf(), true); + EXPECT_EQ(-0.0F, H1.convertToDouble()); + APFloat H3(APFloat::IEEEhalf(), "1.0"); + EXPECT_EQ(1.0F, H3.convertToDouble()); + APFloat H4 = APFloat::getLargest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.FFCp15*/ 65504.0F, H4.convertToDouble()); + APFloat H5 = APFloat::getLargest(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.FFCp15*/ -65504.0F, H5.convertToDouble()); + APFloat H6 = APFloat::getSmallestNormalized(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-14*/ 6.103515625e-05F, H6.convertToDouble()); + APFloat H7 = APFloat::getSmallestNormalized(APFloat::IEEEhalf(), true); + EXPECT_EQ(/*-0x1.p-14*/ -6.103515625e-05F, H7.convertToDouble()); + APFloat H8 = APFloat::getSmallest(APFloat::IEEEhalf(), false); + EXPECT_EQ(/*0x1.p-24*/ 5.960464477539063e-08F, H8.convertToDouble()); + APFloat H9(APFloat::IEEEhalf(), "0x1.FFCp-14"); + EXPECT_EQ(/*0x1.FFCp-14*/ 0.00012201070785522461F, H9.convertToDouble()); + + APFloat H10 = APFloat::getInf(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isinf(H10.convertToDouble())); + EXPECT_TRUE(0 < H10.convertToDouble()); + EXPECT_EQ(0x7C00ULL, H10.bitcastToAPInt().getRawData()[0]); + APFloat H11 = APFloat::getInf(APFloat::IEEEhalf(), true); + EXPECT_TRUE(std::isinf(H11.convertToDouble())); + EXPECT_TRUE(0 > H11.convertToDouble()); + EXPECT_EQ(0xFC00ULL, H11.bitcastToAPInt().getRawData()[0]); + APFloat H12 = APFloat::getQNaN(APFloat::IEEEhalf()); + EXPECT_TRUE(std::isnan(H12.convertToDouble())); + APFloat H13 = APFloat::getQNaN(APFloat::IEEEhalf(), true); + EXPECT_TRUE(std::isnan(H13.convertToDouble())); +} }