From c12b133d00f9797c19fe8a9e2c8aadda3353e2fd Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 28 Feb 2010 12:49:50 +0000 Subject: Properly clear all the extra bits in a significand when making a NaN from an APInt. Be certain to set the integer bit in an x87 extended-precision significand so that we don't accidentally make a pseudo-NaN. llvm-svn: 97382 --- llvm/lib/Support/APFloat.cpp | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'llvm/lib/Support') diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index 4f1b85431cc..16a0c232927 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -631,25 +631,45 @@ void APFloat::makeNaN(bool SNaN, bool Negative, const APInt *fill) category = fcNaN; sign = Negative; + integerPart *significand = significandParts(); + unsigned numParts = partCount(); + // Set the significand bits to the fill. - if (!fill || fill->getNumWords() < partCount()) - APInt::tcSet(significandParts(), 0, partCount()); - if (fill) - APInt::tcAssign(significandParts(), fill->getRawData(), partCount()); + if (!fill || fill->getNumWords() < numParts) + APInt::tcSet(significand, 0, numParts); + if (fill) { + APInt::tcAssign(significand, fill->getRawData(), partCount()); + + // Zero out the excess bits of the significand. + unsigned bitsToPreserve = semantics->precision - 1; + unsigned part = bitsToPreserve / 64; + bitsToPreserve %= 64; + significand[part] &= ((1ULL << bitsToPreserve) - 1); + for (part++; part != numParts; ++part) + significand[part] = 0; + } + + unsigned QNaNBit = semantics->precision - 2; if (SNaN) { // We always have to clear the QNaN bit to make it an SNaN. - APInt::tcClearBit(significandParts(), semantics->precision - 2); + APInt::tcClearBit(significand, QNaNBit); // If there are no bits set in the payload, we have to set // *something* to make it a NaN instead of an infinity; // conventionally, this is the next bit down from the QNaN bit. - if (APInt::tcIsZero(significandParts(), partCount())) - APInt::tcSetBit(significandParts(), semantics->precision - 3); + if (APInt::tcIsZero(significand, numParts)) + APInt::tcSetBit(significand, QNaNBit - 1); } else { // We always have to set the QNaN bit to make it a QNaN. - APInt::tcSetBit(significandParts(), semantics->precision - 2); + APInt::tcSetBit(significand, QNaNBit); } + + // For x87 extended precision, we want to make a NaN, not a + // pseudo-NaN. Maybe we should expose the ability to make + // pseudo-NaNs? + if (semantics == &APFloat::x87DoubleExtended) + APInt::tcSetBit(significand, QNaNBit + 1); } APFloat APFloat::makeNaN(const fltSemantics &Sem, bool SNaN, bool Negative, -- cgit v1.2.3