aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorNeil Booth <neil@daikokuya.co.uk>2007-11-01 22:43:37 +0000
committerNeil Booth <neil@daikokuya.co.uk>2007-11-01 22:43:37 +0000
commit67ab56848503581aa9f509b34500350e38458ffe (patch)
treebbc32ceae892f4871639ea11e85ec0046d09c1bc /lib
parentdb74f8e98ae6a92b8bc6bb86c88769ae2227f33e (diff)
downloadexternal_llvm-67ab56848503581aa9f509b34500350e38458ffe.zip
external_llvm-67ab56848503581aa9f509b34500350e38458ffe.tar.gz
external_llvm-67ab56848503581aa9f509b34500350e38458ffe.tar.bz2
When converting to integer, do bit manipulations in the destination
memory rather than in a copy of the APFloat. This avoids problems when the destination is wider than our significand and is cleaner. Also provide deterministic values in all cases where conversion fails, namely zero for NaNs and the minimal or maximal value respectively for underflow or overflow. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@43626 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Support/APFloat.cpp178
1 files changed, 107 insertions, 71 deletions
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index 8cc916e..1e1c5ff 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -1733,7 +1733,8 @@ APFloat::convert(const fltSemantics &toSemantics,
/* Convert a floating point number to an integer according to the
rounding mode. If the rounded integer value is out of range this
- returns an invalid operation exception. If the rounded value is in
+ returns an invalid operation exception and the contents of the
+ destination parts are unspecified. If the rounded value is in
range but the floating point number is not the exact integer, the C
standard doesn't require an inexact exception to be raised. IEEE
854 does require it so we do that.
@@ -1741,95 +1742,131 @@ APFloat::convert(const fltSemantics &toSemantics,
Note that for conversions to integer type the C standard requires
round-to-zero to always be used. */
APFloat::opStatus
-APFloat::convertToInteger(integerPart *parts, unsigned int width,
- bool isSigned,
- roundingMode rounding_mode) const
+APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width,
+ bool isSigned,
+ roundingMode rounding_mode) const
{
lostFraction lost_fraction;
- unsigned int msb, partsCount;
- int bits;
+ const integerPart *src;
+ unsigned int dstPartsCount, truncatedBits;
- assertArithmeticOK(*semantics);
- partsCount = partCountForBits(width);
-
- /* Handle the three special cases first. We produce
- a deterministic result even for the Invalid cases. */
- if (category == fcNaN) {
- // Neither sign nor isSigned affects this.
- APInt::tcSet(parts, 0, partsCount);
+ /* Handle the three special cases first. */
+ if(category == fcInfinity || category == fcNaN)
return opInvalidOp;
- }
- if (category == fcInfinity) {
- if (!sign && isSigned)
- APInt::tcSetLeastSignificantBits(parts, partsCount, width-1);
- else if (!sign && !isSigned)
- APInt::tcSetLeastSignificantBits(parts, partsCount, width);
- else if (sign && isSigned) {
- APInt::tcSetLeastSignificantBits(parts, partsCount, 1);
- APInt::tcShiftLeft(parts, partsCount, width-1);
- } else // sign && !isSigned
- APInt::tcSet(parts, 0, partsCount);
- return opInvalidOp;
- }
- if (category == fcZero) {
- APInt::tcSet(parts, 0, partsCount);
+
+ dstPartsCount = partCountForBits(width);
+
+ if(category == fcZero) {
+ APInt::tcSet(parts, 0, dstPartsCount);
return opOK;
}
- /* Shift the bit pattern so the fraction is lost. */
- APFloat tmp(*this);
-
- bits = (int) semantics->precision - 1 - exponent;
+ src = significandParts();
- if(bits > 0) {
- lost_fraction = tmp.shiftSignificandRight(bits);
+ /* Step 1: place our absolute value, with any fraction truncated, in
+ the destination. */
+ if (exponent < 0) {
+ /* Our absolute value is less than one; truncate everything. */
+ APInt::tcSet(parts, 0, dstPartsCount);
+ truncatedBits = semantics->precision;
} else {
- if ((unsigned) -bits >= semantics->precision) {
- // Unrepresentably large.
- if (!sign && isSigned)
- APInt::tcSetLeastSignificantBits(parts, partsCount, width-1);
- else if (!sign && !isSigned)
- APInt::tcSetLeastSignificantBits(parts, partsCount, width);
- else if (sign && isSigned) {
- APInt::tcSetLeastSignificantBits(parts, partsCount, 1);
- APInt::tcShiftLeft(parts, partsCount, width-1);
- } else // sign && !isSigned
- APInt::tcSet(parts, 0, partsCount);
- return (opStatus)(opOverflow | opInexact);
+ /* We want the most significant (exponent + 1) bits; the rest are
+ truncated. */
+ unsigned int bits = exponent + 1U;
+
+ /* Hopelessly large in magnitude? */
+ if (bits > width)
+ return opInvalidOp;
+
+ if (bits < semantics->precision) {
+ /* We truncate (semantics->precision - bits) bits. */
+ truncatedBits = semantics->precision - bits;
+ APInt::tcExtract(parts, dstPartsCount, src, bits, truncatedBits);
+ } else {
+ /* We want at least as many bits as are available. */
+ APInt::tcExtract(parts, dstPartsCount, src, semantics->precision, 0);
+ APInt::tcShiftLeft(parts, dstPartsCount, bits - semantics->precision);
+ truncatedBits = 0;
+ }
+ }
+
+ /* Step 2: work out any lost fraction, and increment the absolute
+ value if we would round away from zero. */
+ if (truncatedBits) {
+ lost_fraction = lostFractionThroughTruncation(src, partCount(),
+ truncatedBits);
+ if (lost_fraction != lfExactlyZero
+ && roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) {
+ if (APInt::tcIncrement(parts, dstPartsCount))
+ return opInvalidOp; /* Overflow. */
}
- tmp.shiftSignificandLeft(-bits);
+ } else {
lost_fraction = lfExactlyZero;
}
- if(lost_fraction != lfExactlyZero
- && tmp.roundAwayFromZero(rounding_mode, lost_fraction, 0))
- tmp.incrementSignificand();
+ /* Step 3: check if we fit in the destination. */
+ unsigned int omsb = APInt::tcMSB(parts, dstPartsCount) + 1;
- msb = tmp.significandMSB();
+ if (sign) {
+ if (!isSigned) {
+ /* Negative numbers cannot be represented as unsigned. */
+ if (omsb != 0)
+ return opInvalidOp;
+ } else {
+ /* It takes omsb bits to represent the unsigned integer value.
+ We lose a bit for the sign, but care is needed as the
+ maximally negative integer is a special case. */
+ if (omsb == width && APInt::tcLSB(parts, dstPartsCount) + 1 != omsb)
+ return opInvalidOp;
+
+ /* This case can happen because of rounding. */
+ if (omsb > width)
+ return opInvalidOp;
+ }
- /* Negative numbers cannot be represented as unsigned. */
- if(!isSigned && tmp.sign && msb != -1U)
- return opInvalidOp;
+ APInt::tcNegate (parts, dstPartsCount);
+ } else {
+ if (omsb >= width + !isSigned)
+ return opInvalidOp;
+ }
- /* It takes exponent + 1 bits to represent the truncated floating
- point number without its sign. We lose a bit for the sign, but
- the maximally negative integer is a special case. */
- if(msb + 1 > width) /* !! Not same as msb >= width !! */
- return opInvalidOp;
+ if (lost_fraction == lfExactlyZero)
+ return opOK;
+ else
+ return opInexact;
+}
- if(isSigned && msb + 1 == width
- && (!tmp.sign || tmp.significandLSB() != msb))
- return opInvalidOp;
+/* 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. */
+APFloat::opStatus
+APFloat::convertToInteger(integerPart *parts, unsigned int width,
+ bool isSigned,
+ roundingMode rounding_mode) const
+{
+ opStatus fs;
- APInt::tcAssign(parts, tmp.significandParts(), partsCount);
+ fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode);
- if(tmp.sign)
- APInt::tcNegate(parts, partsCount);
+ if (fs == opInvalidOp) {
+ unsigned int bits, dstPartsCount;
- if(lost_fraction == lfExactlyZero)
- return opOK;
- else
- return opInexact;
+ dstPartsCount = partCountForBits(width);
+
+ if (category == fcNaN)
+ bits = 0;
+ else if (sign)
+ bits = isSigned;
+ else
+ bits = width - isSigned;
+
+ APInt::tcSetLeastSignificantBits(parts, dstPartsCount, bits);
+ if (sign && isSigned)
+ APInt::tcShiftLeft(parts, dstPartsCount, width - 1);
+ }
+
+ return fs;
}
/* Convert an unsigned integer SRC to a floating point number,
@@ -2162,7 +2199,6 @@ APFloat::convertFromDecimalString(const char *p, roundingMode rounding_mode)
partCount++;
} while (p <= D.lastSigDigit);
- category = fcNormal;
fs = roundSignificandWithExponent(decSignificand, partCount,
D.exponent, rounding_mode);