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
This commit is contained in:
Dale Johannesen
2008-10-09 23:00:39 +00:00
parent 7111b02c73
commit 23a98551ab
15 changed files with 115 additions and 55 deletions
+37 -14
View File
@@ -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;