mirror of
https://github.com/yuzu-emu/unicorn
synced 2024-11-24 12:28:14 +00:00
softfloat: Support float_round_to_odd more places
Previously this was only supported for roundAndPackFloat64. New support in round_canonical, round_to_int, float128_round_to_int, roundAndPackFloat32, roundAndPackInt32, roundAndPackInt64, roundAndPackUint64. This does not include any of the floatx80 routines, as we do not have users for that rounding mode there. Backports commit 5d64abb32ffe558e616545819f3e53dd66335994 from qemu
This commit is contained in:
parent
7373819b1a
commit
11679ff3cf
1 changed files with 59 additions and 5 deletions
|
@ -698,6 +698,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm,
|
|||
static FloatParts round_canonical(FloatParts p, float_status *s,
|
||||
const FloatFmt *parm)
|
||||
{
|
||||
const uint64_t frac_lsb = parm->frac_lsb;
|
||||
const uint64_t frac_lsbm1 = parm->frac_lsbm1;
|
||||
const uint64_t round_mask = parm->round_mask;
|
||||
const uint64_t roundeven_mask = parm->roundeven_mask;
|
||||
|
@ -733,6 +734,10 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
|
|||
inc = p.sign ? round_mask : 0;
|
||||
overflow_norm = !p.sign;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
overflow_norm = true;
|
||||
inc = frac & frac_lsb ? 0 : round_mask;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -780,9 +785,14 @@ static FloatParts round_canonical(FloatParts p, float_status *s,
|
|||
shift64RightJamming(frac, 1 - exp, &frac);
|
||||
if (frac & round_mask) {
|
||||
/* Need to recompute round-to-even. */
|
||||
if (s->float_rounding_mode == float_round_nearest_even) {
|
||||
switch (s->float_rounding_mode) {
|
||||
case float_round_nearest_even:
|
||||
inc = ((frac & roundeven_mask) != frac_lsbm1
|
||||
? frac_lsbm1 : 0);
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
inc = frac & frac_lsb ? 0 : round_mask;
|
||||
break;
|
||||
}
|
||||
flags |= float_flag_inexact;
|
||||
frac += inc;
|
||||
|
@ -1980,6 +1990,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
|
|||
case float_round_down:
|
||||
one = a.sign;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
one = true;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -2013,6 +2026,9 @@ static FloatParts round_to_int(FloatParts a, int rmode,
|
|||
case float_round_down:
|
||||
inc = a.sign ? rnd_mask : 0;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
inc = a.frac & frac_lsb ? 0 : rnd_mask;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -3305,6 +3321,9 @@ static int32_t roundAndPackInt32(flag zSign, uint64_t absZ, float_status *status
|
|||
case float_round_down:
|
||||
roundIncrement = zSign ? 0x7f : 0;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
roundIncrement = absZ & 0x80 ? 0 : 0x7f;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
@ -3359,6 +3378,9 @@ static int64_t roundAndPackInt64(flag zSign, uint64_t absZ0, uint64_t absZ1,
|
|||
case float_round_down:
|
||||
increment = zSign && absZ1;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
increment = !(absZ0 & 1) && absZ1;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
@ -3415,6 +3437,9 @@ static int64_t roundAndPackUint64(flag zSign, uint64_t absZ0,
|
|||
case float_round_down:
|
||||
increment = zSign && absZ1;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
increment = !(absZ0 & 1) && absZ1;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
@ -3517,6 +3542,9 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
|
|||
case float_round_down:
|
||||
roundIncrement = zSign ? 0x7f : 0;
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
roundIncrement = zSig & 0x80 ? 0 : 0x7f;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
|
@ -3527,8 +3555,10 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
|
|||
|| ( ( zExp == 0xFD )
|
||||
&& ( (int32_t) ( zSig + roundIncrement ) < 0 ) )
|
||||
) {
|
||||
bool overflow_to_inf = roundingMode != float_round_to_odd &&
|
||||
roundIncrement != 0;
|
||||
float_raise(float_flag_overflow | float_flag_inexact, status);
|
||||
return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
|
||||
return packFloat32(zSign, 0xFF, -!overflow_to_inf);
|
||||
}
|
||||
if ( zExp < 0 ) {
|
||||
if (status->flush_to_zero) {
|
||||
|
@ -3546,6 +3576,13 @@ static float32 roundAndPackFloat32(flag zSign, int zExp, uint32_t zSig,
|
|||
if (isTiny && roundBits) {
|
||||
float_raise(float_flag_underflow, status);
|
||||
}
|
||||
if (roundingMode == float_round_to_odd) {
|
||||
/*
|
||||
* For round-to-odd case, the roundIncrement depends on
|
||||
* zSig which just changed.
|
||||
*/
|
||||
roundIncrement = zSig & 0x80 ? 0 : 0x7f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (roundBits) {
|
||||
|
@ -6979,6 +7016,15 @@ float128 float128_round_to_int(float128 a, float_status *status)
|
|||
add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
|
||||
}
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
/*
|
||||
* Note that if lastBitMask == 0, the last bit is the lsb
|
||||
* of high, and roundBitsMask == -1.
|
||||
*/
|
||||
if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) {
|
||||
add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
@ -6990,7 +7036,7 @@ float128 float128_round_to_int(float128 a, float_status *status)
|
|||
status->float_exception_flags |= float_flag_inexact;
|
||||
aSign = extractFloat128Sign( a );
|
||||
switch (status->float_rounding_mode) {
|
||||
case float_round_nearest_even:
|
||||
case float_round_nearest_even:
|
||||
if ( ( aExp == 0x3FFE )
|
||||
&& ( extractFloat128Frac0( a )
|
||||
| extractFloat128Frac1( a ) )
|
||||
|
@ -7003,14 +7049,16 @@ float128 float128_round_to_int(float128 a, float_status *status)
|
|||
return packFloat128(aSign, 0x3FFF, 0, 0);
|
||||
}
|
||||
break;
|
||||
case float_round_down:
|
||||
case float_round_down:
|
||||
return
|
||||
aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
|
||||
: packFloat128( 0, 0, 0, 0 );
|
||||
case float_round_up:
|
||||
case float_round_up:
|
||||
return
|
||||
aSign ? packFloat128( 1, 0, 0, 0 )
|
||||
: packFloat128( 0, 0x3FFF, 0, 0 );
|
||||
case float_round_to_odd:
|
||||
return packFloat128(aSign, 0x3FFF, 0, 0);
|
||||
}
|
||||
return packFloat128( aSign, 0, 0, 0 );
|
||||
}
|
||||
|
@ -7043,6 +7091,12 @@ float128 float128_round_to_int(float128 a, float_status *status)
|
|||
z.high += roundBitsMask;
|
||||
}
|
||||
break;
|
||||
case float_round_to_odd:
|
||||
if ((z.high & lastBitMask) == 0) {
|
||||
z.high |= (a.low != 0);
|
||||
z.high += roundBitsMask;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue