rewrite code for biasing unmasked underflow for floatx80 in softfloat3e (from hack to clean code)

This commit is contained in:
Stanislav Shwartsman 2024-04-28 06:41:29 +03:00
parent 805bb6b985
commit 632d8780de

View File

@ -76,25 +76,29 @@ extFloat80_t
/*----------------------------------------------------------------
*----------------------------------------------------------------*/
isTiny = (exp < 0) || (sig <= (uint64_t) (sig + roundIncrement));
sig = softfloat_shiftRightJam64(sig, 1 - exp);
sigExact = sig;
roundBits = sig & roundMask;
sig += roundIncrement;
exp = ((sig & UINT64_C(0x8000000000000000)) != 0);
roundIncrement = roundMask + 1;
if (roundNearEven && (roundBits<<1 == roundIncrement)) {
roundMask |= roundIncrement;
if (isTiny && sig && ! softfloat_isMaskedException(status, softfloat_flag_underflow)) {
softfloat_raiseFlags(status, softfloat_flag_underflow);
exp += 0x6000;
}
sig &= ~roundMask;
if (isTiny) {
if (roundBits || (sig && ! softfloat_isMaskedException(status, softfloat_flag_underflow)))
softfloat_raiseFlags(status, softfloat_flag_underflow);
else {
sig = softfloat_shiftRightJam64(sig, 1 - exp);
roundBits = sig & roundMask;
sigExact = sig;
sig += roundIncrement;
exp = ((sig & UINT64_C(0x8000000000000000)) != 0);
roundIncrement = roundMask + 1;
if (roundNearEven && (roundBits<<1 == roundIncrement)) {
roundMask |= roundIncrement;
}
sig &= ~roundMask;
if (roundBits) {
softfloat_raiseFlags(status, softfloat_flag_inexact);
if (sig > sigExact) softfloat_setRoundingUp(status);
if (isTiny)
softfloat_raiseFlags(status, softfloat_flag_underflow);
}
return packToExtF80(sign, exp, sig);
}
if (roundBits) {
softfloat_raiseFlags(status, softfloat_flag_inexact);
if (sig > sigExact) softfloat_setRoundingUp(status);
}
return packToExtF80(sign, exp, sig);
}
if ((0x7FFE < exp) || ((exp == 0x7FFE) && ((uint64_t) (sig + roundIncrement) < sig))) {
goto overflow;
@ -102,9 +106,6 @@ extFloat80_t
}
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
if (roundBits) {
softfloat_raiseFlags(status, softfloat_flag_inexact);
}
sigExact = sig;
sig = (uint64_t) (sig + roundIncrement);
if (sig < roundIncrement) {
@ -117,7 +118,10 @@ extFloat80_t
roundMask |= roundIncrement;
}
sig &= ~roundMask;
if (sig > sigExact) softfloat_setRoundingUp(status);
if (roundBits) {
softfloat_raiseFlags(status, softfloat_flag_inexact);
if (sig > sigExact) softfloat_setRoundingUp(status);
}
return packToExtF80(sign, exp, sig);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
@ -134,30 +138,35 @@ extFloat80_t
/*----------------------------------------------------------------
*----------------------------------------------------------------*/
isTiny = (exp < 0) || ! doIncrement || (sig < UINT64_C(0xFFFFFFFFFFFFFFFF));
sig64Extra = softfloat_shiftRightJam64Extra(sig, sigExtra, 1 - exp);
exp = 0;
sig = sig64Extra.v;
sigExtra = sig64Extra.extra;
if (isTiny) {
if (sigExtra || (sig && ! softfloat_isMaskedException(status, softfloat_flag_underflow)))
softfloat_raiseFlags(status, softfloat_flag_underflow);
if (isTiny && sig && ! softfloat_isMaskedException(status, softfloat_flag_underflow)) {
softfloat_raiseFlags(status, softfloat_flag_underflow);
exp += 0x6000;
}
if (sigExtra)
softfloat_raiseFlags(status, softfloat_flag_inexact);
doIncrement = (UINT64_C(0x8000000000000000) <= sigExtra);
if (! roundNearEven && (roundingMode != softfloat_round_near_maxMag)) {
doIncrement =
(roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra;
else {
sig64Extra = softfloat_shiftRightJam64Extra(sig, sigExtra, 1 - exp);
exp = 0;
sig = sig64Extra.v;
sigExtra = sig64Extra.extra;
if (sigExtra) {
softfloat_raiseFlags(status, softfloat_flag_inexact);
if (isTiny)
softfloat_raiseFlags(status, softfloat_flag_underflow);
}
doIncrement = (UINT64_C(0x8000000000000000) <= sigExtra);
if (! roundNearEven && (roundingMode != softfloat_round_near_maxMag)) {
doIncrement =
(roundingMode == (sign ? softfloat_round_min : softfloat_round_max)) && sigExtra;
}
if (doIncrement) {
sigExact = sig;
++sig;
sig &= ~(uint64_t) (! (sigExtra & UINT64_C(0x7FFFFFFFFFFFFFFF)) & roundNearEven);
exp = ((sig & UINT64_C(0x8000000000000000)) != 0);
if (sig > sigExact)
softfloat_setRoundingUp(status);
}
return packToExtF80(sign, exp, sig);
}
if (doIncrement) {
sigExact = sig;
++sig;
sig &= ~(uint64_t) (! (sigExtra & UINT64_C(0x7FFFFFFFFFFFFFFF)) & roundNearEven);
exp = ((sig & UINT64_C(0x8000000000000000)) != 0);
if (sig > sigExact)
softfloat_setRoundingUp(status);
}
return packToExtF80(sign, exp, sig);
}
if ((0x7FFE < exp) || ((exp == 0x7FFE) && (sig == UINT64_C(0xFFFFFFFFFFFFFFFF)) && doIncrement)) {
/*----------------------------------------------------------------
@ -206,18 +215,11 @@ extFloat80_t
extFloat80_t
softfloat_roundPackToExtF80(bool sign, int32_t exp, uint64_t sig, uint64_t sigExtra, uint8_t roundingPrecision, struct softfloat_status_t *status)
{
softfloat_status_t round_status = *status;
extFloat80_t result = SoftFloat_roundPackToExtF80(sign, exp, sig, sigExtra, roundingPrecision, status);
// bias unmasked underflow
if (status->softfloat_exceptionFlags & ~status->softfloat_exceptionMasks & softfloat_flag_underflow) {
softfloat_raiseFlags(&round_status, softfloat_flag_underflow);
result = SoftFloat_roundPackToExtF80(sign, exp + 0x6000, sig, sigExtra, roundingPrecision, &round_status);
*status = round_status;
}
// bias unmasked overflow
if (status->softfloat_exceptionFlags & ~status->softfloat_exceptionMasks & softfloat_flag_overflow) {
softfloat_status_t round_status = *status;
softfloat_raiseFlags(&round_status, softfloat_flag_overflow);
result = SoftFloat_roundPackToExtF80(sign, exp - 0x6000, sig, sigExtra, roundingPrecision, &round_status);
*status = round_status;