diff options
author | Dale Johannesen <dalej@apple.com> | 2008-10-09 23:00:39 +0000 |
---|---|---|
committer | Dale Johannesen <dalej@apple.com> | 2008-10-09 23:00:39 +0000 |
commit | 23a98551ab65eeb8fe5019df8b7db4891582a4bd (patch) | |
tree | 90d6731fd446c04df49383b8a23da0461337ba09 /lib/Support/APFloat.cpp | |
parent | 7111b02c734c992b8c97d9918118768026dad79e (diff) |
Add a "loses information" return value to APFloat::convert
and APFloat::convertToInteger. Restore return value to
IEEE754. Adjust all users accordingly.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57329 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support/APFloat.cpp')
-rw-r--r-- | lib/Support/APFloat.cpp | 51 |
1 files changed, 37 insertions, 14 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index a8691f495a..a65e55afb5 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -788,6 +788,7 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) integerPart scratch[4]; integerPart *fullSignificand; lostFraction lost_fraction; + bool ignored; assert(semantics == rhs.semantics); @@ -836,7 +837,7 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend) semantics = &extendedSemantics; APFloat extendedAddend(*addend); - status = extendedAddend.convert(extendedSemantics, rmTowardZero); + status = extendedAddend.convert(extendedSemantics, rmTowardZero, &ignored); assert(status == opOK); lost_fraction = addOrSubtractSignificand(extendedAddend, false); @@ -1528,8 +1529,9 @@ APFloat::mod(const APFloat &rhs, roundingMode rounding_mode) int parts = partCount(); integerPart *x = new integerPart[parts]; + bool ignored; fs = V.convertToInteger(x, parts * integerPartWidth, true, - rmNearestTiesToEven); + rmNearestTiesToEven, &ignored); if (fs==opInvalidOp) return fs; @@ -1670,9 +1672,16 @@ APFloat::compare(const APFloat &rhs) const return result; } +/// APFloat::convert - convert a value of one floating point type to another. +/// The return value corresponds to the IEEE754 exceptions. *losesInfo +/// records whether the transformation lost information, i.e. whether +/// converting the result back to the original type will produce the +/// original value (this is almost the same as return value==fsOK, but there +/// are edge cases where this is not so). + APFloat::opStatus APFloat::convert(const fltSemantics &toSemantics, - roundingMode rounding_mode) + roundingMode rounding_mode, bool *losesInfo) { lostFraction lostFraction; unsigned int newPartCount, oldPartCount; @@ -1718,38 +1727,41 @@ APFloat::convert(const fltSemantics &toSemantics, exponent += toSemantics.precision - semantics->precision; semantics = &toSemantics; fs = normalize(rounding_mode, lostFraction); + *losesInfo = (fs != opOK); } else if (category == fcNaN) { int shift = toSemantics.precision - semantics->precision; // Do this now so significandParts gets the right answer const fltSemantics *oldSemantics = semantics; semantics = &toSemantics; - fs = opOK; + *losesInfo = false; // No normalization here, just truncate if (shift>0) APInt::tcShiftLeft(significandParts(), newPartCount, shift); else if (shift < 0) { unsigned ushift = -shift; - // We mark this as Inexact if we are losing information. This happens + // Figure out if we are losing information. This happens // if are shifting out something other than 0s, or if the x87 long // double input did not have its integer bit set (pseudo-NaN), or if the // x87 long double input did not have its QNan bit set (because the x87 // hardware sets this bit when converting a lower-precision NaN to // x87 long double). if (APInt::tcLSB(significandParts(), newPartCount) < ushift) - fs = opInexact; + *losesInfo = true; if (oldSemantics == &APFloat::x87DoubleExtended && (!(*significandParts() & 0x8000000000000000ULL) || !(*significandParts() & 0x4000000000000000ULL))) - fs = opInexact; + *losesInfo = true; APInt::tcShiftRight(significandParts(), newPartCount, ushift); } // gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // does not give you back the same bits. This is dubious, and we // don't currently do it. You're really supposed to get // an invalid operation signal at runtime, but nobody does that. + fs = opOK; } else { semantics = &toSemantics; fs = opOK; + *losesInfo = false; } return fs; @@ -1768,7 +1780,8 @@ APFloat::convert(const fltSemantics &toSemantics, APFloat::opStatus APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width, bool isSigned, - roundingMode rounding_mode) const + roundingMode rounding_mode, + bool *isExact) const { lostFraction lost_fraction; const integerPart *src; @@ -1776,6 +1789,8 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width, assertArithmeticOK(*semantics); + *isExact = false; + /* Handle the three special cases first. */ if(category == fcInfinity || category == fcNaN) return opInvalidOp; @@ -1785,7 +1800,8 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width, if(category == fcZero) { APInt::tcSet(parts, 0, dstPartsCount); // Negative zero can't be represented as an int. - return sign ? opInexact : opOK; + *isExact = !sign; + return opOK; } src = significandParts(); @@ -1857,24 +1873,31 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width, return opInvalidOp; } - if (lost_fraction == lfExactlyZero) + if (lost_fraction == lfExactlyZero) { + *isExact = true; return opOK; - else + } else return opInexact; } /* Same as convertToSignExtendedInteger, except we provide deterministic values in case of an invalid operation exception, namely zero for NaNs and the minimal or maximal value respectively - for underflow or overflow. */ + for underflow or overflow. + The *isExact output tells whether the result is exact, in the sense + that converting it back to the original floating point type produces + the original value. This is almost equivalent to result==opOK, + except for negative zeroes. +*/ APFloat::opStatus APFloat::convertToInteger(integerPart *parts, unsigned int width, bool isSigned, - roundingMode rounding_mode) const + roundingMode rounding_mode, bool *isExact) const { opStatus fs; - fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode); + fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode, + isExact); if (fs == opInvalidOp) { unsigned int bits, dstPartsCount; |