diff options
Diffstat (limited to 'llvm/lib/Support/APFloat.cpp')
-rw-r--r-- | llvm/lib/Support/APFloat.cpp | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index cfc3c3b..e058010 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -1657,7 +1657,8 @@ APFloat::opStatus IEEEFloat::normalize(roundingMode rounding_mode, /* Before rounding normalize the exponent of fcNormal numbers. */ omsb = significandMSB() + 1; - if (omsb) { + // Only skip this `if` if the value is exactly zero. + if (omsb || lost_fraction != lfExactlyZero) { /* OMSB is numbered from 1. We want to place it in the integer bit numbered PRECISION if possible, with a compensating change in the exponent. */ @@ -1839,7 +1840,7 @@ APFloat::opStatus IEEEFloat::addOrSubtractSpecials(const IEEEFloat &rhs, /* Add or subtract two normal numbers. */ lostFraction IEEEFloat::addOrSubtractSignificand(const IEEEFloat &rhs, bool subtract) { - integerPart carry; + integerPart carry = 0; lostFraction lost_fraction; int bits; @@ -1857,11 +1858,13 @@ lostFraction IEEEFloat::addOrSubtractSignificand(const IEEEFloat &rhs, "This floating point format does not support signed values"); IEEEFloat temp_rhs(rhs); + bool lost_fraction_is_from_rhs = false; if (bits == 0) lost_fraction = lfExactlyZero; else if (bits > 0) { lost_fraction = temp_rhs.shiftSignificandRight(bits - 1); + lost_fraction_is_from_rhs = true; shiftSignificandLeft(1); } else { lost_fraction = shiftSignificandRight(-bits - 1); @@ -1869,23 +1872,40 @@ lostFraction IEEEFloat::addOrSubtractSignificand(const IEEEFloat &rhs, } // Should we reverse the subtraction. - if (compareAbsoluteValue(temp_rhs) == cmpLessThan) { - carry = temp_rhs.subtractSignificand - (*this, lost_fraction != lfExactlyZero); + cmpResult cmp_result = compareAbsoluteValue(temp_rhs); + if (cmp_result == cmpLessThan) { + bool borrow = + lost_fraction != lfExactlyZero && !lost_fraction_is_from_rhs; + if (borrow) { + // The lost fraction is being subtracted, borrow from the significand + // and invert `lost_fraction`. + if (lost_fraction == lfLessThanHalf) + lost_fraction = lfMoreThanHalf; + else if (lost_fraction == lfMoreThanHalf) + lost_fraction = lfLessThanHalf; + } + carry = temp_rhs.subtractSignificand(*this, borrow); copySignificand(temp_rhs); sign = !sign; - } else { - carry = subtractSignificand - (temp_rhs, lost_fraction != lfExactlyZero); + } else if (cmp_result == cmpGreaterThan) { + bool borrow = lost_fraction != lfExactlyZero && lost_fraction_is_from_rhs; + if (borrow) { + // The lost fraction is being subtracted, borrow from the significand + // and invert `lost_fraction`. + if (lost_fraction == lfLessThanHalf) + lost_fraction = lfMoreThanHalf; + else if (lost_fraction == lfMoreThanHalf) + lost_fraction = lfLessThanHalf; + } + carry = subtractSignificand(temp_rhs, borrow); + } else { // cmpEqual + zeroSignificand(); + if (lost_fraction != lfExactlyZero && lost_fraction_is_from_rhs) { + // rhs is slightly larger due to the lost fraction, flip the sign. + sign = !sign; + } } - /* Invert the lost fraction - it was on the RHS and - subtracted. */ - if (lost_fraction == lfLessThanHalf) - lost_fraction = lfMoreThanHalf; - else if (lost_fraction == lfMoreThanHalf) - lost_fraction = lfLessThanHalf; - /* The code above is intended to ensure that no borrow is necessary. */ assert(!carry); |