Index: llvm/lib/Support/APFloat.cpp =================================================================== --- llvm/lib/Support/APFloat.cpp +++ llvm/lib/Support/APFloat.cpp @@ -26,6 +26,8 @@ #include #include +#define EXPONENT_MIN ExponentType(1 << (sizeof(ExponentType) * CHAR_BIT - 1)) + #define APFLOAT_DISPATCH_ON_SEMANTICS(METHOD_CALL) \ do { \ if (usesLayout(getSemantics())) \ @@ -999,7 +1001,8 @@ lostFraction IEEEFloat::multiplySignificand(const IEEEFloat &rhs, const IEEEFloat *addend) { unsigned int omsb; // One, not zero, based MSB. - unsigned int partsCount, newPartsCount, precision; + unsigned int partsCount, newPartsCount, precision, bits; + int newExponent; integerPart *lhsSignificand; integerPart scratch[4]; integerPart *fullSignificand; @@ -1027,7 +1030,7 @@ lost_fraction = lfExactlyZero; omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; - exponent += rhs.exponent; + newExponent = static_cast(exponent) + static_cast(rhs.exponent); // Assume the operands involved in the multiplication are single-precision // FP, and the two multiplicants are: @@ -1039,7 +1042,7 @@ // radix point: two for the multiplication, and an overflow bit for the // addition (that will always be zero at this point). Move the radix point // toward left by two bits, and adjust exponent accordingly. - exponent += 2; + newExponent += 2; if (addend && addend->isNonZero()) { // The intermediate result of the multiplication has "2 * precision" @@ -1057,8 +1060,21 @@ assert(extendedPrecision > omsb); APInt::tcShiftLeft(fullSignificand, newPartsCount, (extendedPrecision - 1) - omsb); - exponent -= (extendedPrecision - 1) - omsb; + newExponent -= (extendedPrecision - 1) - omsb; + } + + // Make sure the new exponent fits into ExponentType. + if (newExponent < EXPONENT_MIN) { + unsigned int significantParts; + lostFraction lf; + + significantParts = partCountForBits(omsb); + lf = shiftRight(fullSignificand, significantParts, + int(EXPONENT_MIN) - newExponent); + lost_fraction = combineLostFractions(lf, lost_fraction); + newExponent = EXPONENT_MIN; } + exponent = static_cast(newExponent); /* Create new semantics. */ extendedSemantics = *semantics; @@ -1090,6 +1106,7 @@ significand = savedSignificand; semantics = savedSemantics; + newExponent = exponent; omsb = APInt::tcMSB(fullSignificand, newPartsCount) + 1; } @@ -1097,7 +1114,7 @@ // having "precision" significant-bits. First, move the radix point from // poision "2*precision - 1" to "precision - 1". The exponent need to be // adjusted by "2*precision - 1" - "precision - 1" = "precision". - exponent -= precision + 1; + newExponent -= precision + 1; // In case MSB resides at the left-hand side of radix point, shift the // mantissa right by some amount to make sure the MSB reside right before @@ -1106,17 +1123,27 @@ // Note that the result is not normalized when "omsb < precision". So, the // caller needs to call IEEEFloat::normalize() if normalized value is // expected. - if (omsb > precision) { - unsigned int bits, significantParts; + bits = 0; + if (omsb > precision) + bits += omsb - precision; + + // Make sure the new exponent fits into ExponentType. + if (newExponent < EXPONENT_MIN) { + bits += int(EXPONENT_MIN) - newExponent; + newExponent = EXPONENT_MIN; + } + + if (bits) { + unsigned int significantParts; lostFraction lf; - bits = omsb - precision; significantParts = partCountForBits(omsb); lf = shiftRight(fullSignificand, significantParts, bits); lost_fraction = combineLostFractions(lf, lost_fraction); - exponent += bits; + newExponent += bits; } + exponent = static_cast(newExponent); APInt::tcAssign(lhsSignificand, fullSignificand, partsCount); if (newPartsCount > 4) @@ -1128,6 +1155,7 @@ /* Multiply the significands of LHS and RHS to DST. */ lostFraction IEEEFloat::divideSignificand(const IEEEFloat &rhs) { unsigned int bit, i, partsCount; + int newExponent; const integerPart *rhsSignificand; integerPart *lhsSignificand, *dividend, *divisor; integerPart scratch[4]; @@ -1153,21 +1181,21 @@ lhsSignificand[i] = 0; } - exponent -= rhs.exponent; + newExponent = exponent - rhs.exponent; unsigned int precision = semantics->precision; /* Normalize the divisor. */ bit = precision - APInt::tcMSB(divisor, partsCount) - 1; if (bit) { - exponent += bit; + newExponent += bit; APInt::tcShiftLeft(divisor, partsCount, bit); } /* Normalize the dividend. */ bit = precision - APInt::tcMSB(dividend, partsCount) - 1; if (bit) { - exponent -= bit; + newExponent -= bit; APInt::tcShiftLeft(dividend, partsCount, bit); } @@ -1175,7 +1203,7 @@ Incidentally, this means that the division loop below is guaranteed to set the integer bit to one. */ if (APInt::tcCompare(dividend, divisor, partsCount) < 0) { - exponent--; + newExponent--; APInt::tcShiftLeft(dividend, partsCount, 1); assert(APInt::tcCompare(dividend, divisor, partsCount) >= 0); } @@ -1205,6 +1233,20 @@ if (partsCount > 2) delete [] dividend; + // Make sure the new exponent fits into ExponentType. + if (newExponent < EXPONENT_MIN) { + unsigned int omsb, significantParts; + lostFraction lf; + + omsb = APInt::tcMSB(lhsSignificand, partsCount) + 1; + significantParts = partCountForBits(omsb); + lf = shiftRight(lhsSignificand, significantParts, + int(EXPONENT_MIN) - newExponent); + lost_fraction = combineLostFractions(lf, lost_fraction); + newExponent = EXPONENT_MIN; + } + exponent = static_cast(newExponent); + return lost_fraction; } Index: llvm/unittests/ADT/APFloatTest.cpp =================================================================== --- llvm/unittests/ADT/APFloatTest.cpp +++ llvm/unittests/ADT/APFloatTest.cpp @@ -2600,6 +2600,17 @@ EXPECT_TRUE((int)status == SpecialCaseTests[i].status); EXPECT_TRUE((int)x.getCategory() == SpecialCaseTests[i].category); } + + // Test exponent underflow. + { + APFloat x(APFloat::x87DoubleExtended(), "3.645199531882474602528e-4951"); + APFloat::opStatus status = x.multiply(x, APFloat::rmNearestTiesToEven); + + APFloat zero = APFloat::getZero(APFloat::x87DoubleExtended()); + + EXPECT_TRUE(x.bitwiseIsEqual(zero)); + EXPECT_TRUE((int)status == UnderflowStatus); + } } TEST(APFloatTest, divide) { @@ -2889,6 +2900,18 @@ EXPECT_TRUE((int)status == SpecialCaseTests[i].status); EXPECT_TRUE((int)x.getCategory() == SpecialCaseTests[i].category); } + + // Test exponent underflow. + { + APFloat x(APFloat::x87DoubleExtended(), "3.645199531882474602528e-4951"); + APFloat y(APFloat::x87DoubleExtended(), "1.18973149535723176502e+4932"); + APFloat::opStatus status = x.divide(y, APFloat::rmNearestTiesToEven); + + APFloat zero = APFloat::getZero(APFloat::x87DoubleExtended()); + + EXPECT_TRUE(x.bitwiseIsEqual(zero)); + EXPECT_TRUE((int)status == UnderflowStatus); + } } TEST(APFloatTest, operatorOverloads) {