}
}
/* Zero plus something non-zero : just return the something */
+ if (flags & float_muladd_halve_result) {
+ if (cExp == 0) {
+ normalizeFloat32Subnormal(cSig, &cExp, &cSig);
+ }
+ /* Subtract one to halve, and one again because roundAndPackFloat32
+ * wants one less than the true exponent.
+ */
+ cExp -= 2;
+ cSig = (cSig | 0x00800000) << 7;
+ return roundAndPackFloat32(cSign ^ signflip, cExp, cSig STATUS_VAR);
+ }
return packFloat32(cSign ^ signflip, cExp, cSig);
}
/* Throw out the special case of c being an exact zero now */
shift64RightJamming(pSig64, 32, &pSig64);
pSig = pSig64;
+ if (flags & float_muladd_halve_result) {
+ pExp--;
+ }
return roundAndPackFloat32(zSign, pExp - 1,
pSig STATUS_VAR);
}
zSig64 <<= shiftcount;
zExp -= shiftcount;
}
+ if (flags & float_muladd_halve_result) {
+ zExp--;
+ }
+
shift64RightJamming(zSig64, 32, &zSig64);
return roundAndPackFloat32(zSign, zExp, zSig64 STATUS_VAR);
}
}
}
/* Zero plus something non-zero : just return the something */
+ if (flags & float_muladd_halve_result) {
+ if (cExp == 0) {
+ normalizeFloat64Subnormal(cSig, &cExp, &cSig);
+ }
+ /* Subtract one to halve, and one again because roundAndPackFloat64
+ * wants one less than the true exponent.
+ */
+ cExp -= 2;
+ cSig = (cSig | 0x0010000000000000ULL) << 10;
+ return roundAndPackFloat64(cSign ^ signflip, cExp, cSig STATUS_VAR);
+ }
return packFloat64(cSign ^ signflip, cExp, cSig);
}
if (!cSig) {
/* Throw out the special case of c being an exact zero now */
shift128RightJamming(pSig0, pSig1, 64, &pSig0, &pSig1);
+ if (flags & float_muladd_halve_result) {
+ pExp--;
+ }
return roundAndPackFloat64(zSign, pExp - 1,
pSig1 STATUS_VAR);
}
zExp--;
}
shift128RightJamming(zSig0, zSig1, 64, &zSig0, &zSig1);
+ if (flags & float_muladd_halve_result) {
+ zExp--;
+ }
return roundAndPackFloat64(zSign, zExp, zSig1 STATUS_VAR);
} else {
/* Subtraction */
zExp -= (shiftcount + 64);
}
}
+ if (flags & float_muladd_halve_result) {
+ zExp--;
+ }
return roundAndPackFloat64(zSign, zExp, zSig0 STATUS_VAR);
}
}
| Using these differs from negating an input or output before calling
| the muladd function in that this means that a NaN doesn't have its
| sign bit inverted before it is propagated.
+| We also support halving the result before rounding, as a special
+| case to support the ARM fused-sqrt-step instruction FRSQRTS.
*----------------------------------------------------------------------------*/
enum {
float_muladd_negate_c = 1,
float_muladd_negate_product = 2,
float_muladd_negate_result = 4,
+ float_muladd_halve_result = 8,
};
/*----------------------------------------------------------------------------