[llvm] [Support][APInt] Fix sign extension, exponent and mantissa in APInt::roundToDouble (PR #192451)
Max Graey via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 16 23:49:25 PDT 2026
================
@@ -890,66 +891,25 @@ 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 |
/// |-------------------------------------- |
/// | 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<double>::infinity();
- else
- return -std::numeric_limits<double>::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);
----------------
MaxGraey wrote:
I still think it should be round to nearest integer "ties to even" instead "towards zero". Floating point semantics matching IEC 60559 (IEEE 754) are defined in Annex F of the standard, which technically is optional and IB, but in practice many compilers and libraries for targets and runtimes (like CUDA, WebAssembly) use default ties to even during integer -> float point conversion. So I’m genuinely curious as to why this particular rounding method was chosen in the first place
https://github.com/llvm/llvm-project/pull/192451
More information about the llvm-commits
mailing list