/* Assumed in hexadecimal significand parsing, and conversion to
hexadecimal strings. */
-#define COMPILE_TIME_ASSERT(cond) extern int CTAssert[(cond) ? 1 : -1]
-COMPILE_TIME_ASSERT(integerPartWidth % 4 == 0);
+static_assert(integerPartWidth % 4 == 0, "Part width must be divisible by 4!");
namespace llvm {
assert(semantics == rhs.semantics);
precision = semantics->precision;
- newPartsCount = partCountForBits(precision * 2);
+
+ // Allocate space for twice as many bits as the original significand, plus one
+ // extra bit for the addition to overflow into.
+ newPartsCount = partCountForBits(precision * 2 + 1);
if (newPartsCount > 4)
fullSignificand = new integerPart[newPartsCount];
// *this = a23 . a22 ... a0 * 2^e1
// rhs = b23 . b22 ... b0 * 2^e2
// the result of multiplication is:
- // *this = c47 c46 . c45 ... c0 * 2^(e1+e2)
- // Note that there are two significant bits at the left-hand side of the
- // radix point. Move the radix point toward left by one bit, and adjust
- // exponent accordingly.
- exponent += 1;
-
- if (addend) {
+ // *this = c48 c47 c46 . c45 ... c0 * 2^(e1+e2)
+ // Note that there are three significant bits at the left-hand side of the
+ // 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;
+
+ if (addend && addend->isNonZero()) {
// The intermediate result of the multiplication has "2 * precision"
// signicant bit; adjust the addend to be consistent with mul result.
//
opStatus status;
unsigned int extendedPrecision;
- /* Normalize our MSB. */
- extendedPrecision = 2 * precision;
- if (omsb != extendedPrecision) {
+ // Normalize our MSB to one below the top bit to allow for overflow.
+ extendedPrecision = 2 * precision + 1;
+ if (omsb != extendedPrecision - 1) {
assert(extendedPrecision > omsb);
APInt::tcShiftLeft(fullSignificand, newPartsCount,
- extendedPrecision - omsb);
- exponent -= extendedPrecision - omsb;
+ (extendedPrecision - 1) - omsb);
+ exponent -= (extendedPrecision - 1) - omsb;
}
/* Create new semantics. */
status = extendedAddend.convert(extendedSemantics, rmTowardZero, &ignored);
assert(status == opOK);
(void)status;
+
+ // Shift the significand of the addend right by one bit. This guarantees
+ // that the high bit of the significand is zero (same as fullSignificand),
+ // so the addition will overflow (if it does overflow at all) into the top bit.
+ lost_fraction = extendedAddend.shiftSignificandRight(1);
+ assert(lost_fraction == lfExactlyZero &&
+ "Lost precision while shifting addend for fused-multiply-add.");
+
lost_fraction = addOrSubtractSignificand(extendedAddend, false);
/* Restore our state. */
// 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;
+ exponent -= 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
return false;
case rmTowardPositive:
- return sign == false;
+ return !sign;
case rmTowardNegative:
- return sign == true;
+ return sign;
}
llvm_unreachable("Invalid rounding mode found");
}
/* Determine if the operation on the absolute values is effectively
an addition or subtraction. */
- subtract ^= (sign ^ rhs.sign) ? true : false;
+ subtract ^= static_cast<bool>(sign ^ rhs.sign);
/* Are we bigger exponent-wise than the RHS? */
bits = exponent - rhs.exponent;
extended-precision calculation. */
if (isFiniteNonZero() &&
multiplicand.isFiniteNonZero() &&
- addend.isFiniteNonZero()) {
+ addend.isFinite()) {
lostFraction lost_fraction;
lost_fraction = multiplySignificand(multiplicand, &addend);
/* If two numbers add (exactly) to zero, IEEE 754 decrees it is a
positive zero unless rounding to minus infinity, except that
adding two like-signed zeroes gives that zero. */
- if (category == fcZero && sign != addend.sign)
+ if (category == fcZero && !(fs & opUnderflow) && sign != addend.sign)
sign = (rounding_mode == rmTowardNegative);
} else {
fs = multiplySpecials(multiplicand);