diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp index 6aa5fc615a302..3c4b61310c3dc 100644 --- a/llvm/lib/Support/APInt.cpp +++ b/llvm/lib/Support/APInt.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/APInt.h" +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" @@ -890,7 +891,8 @@ APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) { return isNeg ? -Tmp : Tmp; } -/// This function converts this APInt to a double. +/// Converts this APInt to a double with rounding towards zero. +/// /// The layout for double is as following (IEEE Standard 754): /// -------------------------------------- /// | Sign Exponent Fraction Bias | @@ -898,58 +900,16 @@ APInt llvm::APIntOps::RoundDoubleToAPInt(double Double, unsigned width) { /// | 1[63] 11[62-52] 52[51-00] 1023 | /// -------------------------------------- double APInt::roundToDouble(bool isSigned) const { - // Handle the simple case where the value is contained in one uint64_t. - // It is wrong to optimize getWord(0) to VAL; there might be more than one word. - if (isSingleWord() || getActiveBits() <= APINT_BITS_PER_WORD) { - if (isSigned) { - int64_t sext = SignExtend64(getWord(0), BitWidth); - return double(sext); - } - return double(getWord(0)); - } - - // Determine if the value is negative. - bool isNeg = isSigned ? (*this)[BitWidth-1] : false; - - // Construct the absolute value if we're negative. - APInt Tmp(isNeg ? -(*this) : (*this)); - - // Figure out how many bits we're using. - unsigned n = Tmp.getActiveBits(); - - // The exponent (without bias normalization) is just the number of bits - // we are using. Note that the sign bit is gone since we constructed the - // absolute value. - uint64_t exp = n; + // Early exit for zero-length values; APFloat::convertFromAPInt only + // applies to values with at least one word. + if (BitWidth == 0) + return 0.0; - // Return infinity for exponent overflow - if (exp > 1023) { - if (!isSigned || !isNeg) - return std::numeric_limits::infinity(); - else - return -std::numeric_limits::infinity(); - } - exp += 1023; // Increment for 1023 bias - - // Number of bits in mantissa is 52. To obtain the mantissa value, we must - // extract the high 52 bits from the correct words in pVal. - uint64_t mantissa; - unsigned hiWord = whichWord(n-1); - if (hiWord == 0) { - mantissa = Tmp.U.pVal[0]; - if (n > 52) - mantissa >>= n - 52; // shift down, we want the top 52 bits. - } else { - assert(hiWord > 0 && "huh?"); - uint64_t hibits = Tmp.U.pVal[hiWord] << (52 - n % APINT_BITS_PER_WORD); - uint64_t lobits = Tmp.U.pVal[hiWord-1] >> (11 + n % APINT_BITS_PER_WORD); - mantissa = hibits | lobits; - } + APFloat f(APFloat::IEEEdouble()); + f.convertFromAPInt(*this, isSigned, + llvm::APFloatBase::roundingMode::TowardZero); - // The leading bit of mantissa is implicit, so get rid of it. - uint64_t sign = isNeg ? (1ULL << (APINT_BITS_PER_WORD - 1)) : 0; - uint64_t I = sign | (exp << 52) | mantissa; - return bit_cast(I); + return f.convertToDouble(); } // Truncate to new width. diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp index ee4c59de34fc4..56cf0a83fc807 100644 --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3980,4 +3980,43 @@ TEST(APIntTest, clmulh) { .getSExtValue(), 21845); } + +TEST(APIntTest, roundToDouble) { + EXPECT_EQ(APInt(0, 0, false).roundToDouble(false), 0.0); + + // Single-word, positive + EXPECT_EQ(APInt(64, 0, false).roundToDouble(false), 0.0); + EXPECT_EQ(APInt(64, 1, false).roundToDouble(false), 1.0); + EXPECT_EQ(APInt(64, 2, false).roundToDouble(false), 2.0); + EXPECT_EQ(APInt(64, 1ULL << 63, false).roundToDouble(false), + 9223372036854775808.0); + + // Single-word, negative + EXPECT_EQ(APInt(64, 0, true).roundToDouble(true), 0.0); + EXPECT_EQ(APInt(64, -1, true).roundToDouble(true), -1.0); + EXPECT_EQ(APInt(64, -2, true).roundToDouble(true), -2.0); + EXPECT_EQ(APInt(64, 1ULL << 63, true).roundToDouble(true), + -9223372036854775808.0); + + // Multi-word, positive, active bits in first word + EXPECT_EQ(APInt(65, 0, false).roundToDouble(false), 0.0); + EXPECT_EQ(APInt(65, 1, false).roundToDouble(false), 1.0); + EXPECT_EQ(APInt(65, 2, false).roundToDouble(false), 2.0); + EXPECT_EQ(APInt(65, 1ULL << 63, false).roundToDouble(true), + 9223372036854775808.0); + + // Multi-word, positive, active bits outside first word + EXPECT_EQ( + APInt(65, "18446744073709551616" /* 2^64 */, 10).roundToDouble(false), + 18446744073709551616.0); + + // Multi-word, negative + EXPECT_EQ(APInt(65, 0, true).roundToDouble(true), 0.0); + + EXPECT_EQ(APInt(65, -1, true).roundToDouble(true), -1.0); + EXPECT_EQ(APInt(65, -2, true).roundToDouble(true), -2.0); + EXPECT_EQ( + APInt(65, "18446744073709551616" /* 2^64 */, 10).roundToDouble(true), + -18446744073709551616.0); +} } // end anonymous namespace