Commit fe76d97653d6611df19dacc4e326fc7d3d057237
1 parent
5c7908ed
Implement flush-to-zero mode (denormal results are replaced with zero).
Signed-off-by: Paul Brook <paul@codesourcery.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6107 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
25 additions
and
4 deletions
fpu/softfloat.c
| ... | ... | @@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained. |
| 30 | 30 | |
| 31 | 31 | =============================================================================*/ |
| 32 | 32 | |
| 33 | +/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also | |
| 34 | + be flushed to zero. */ | |
| 33 | 35 | #include "softfloat.h" |
| 34 | 36 | |
| 35 | 37 | /*---------------------------------------------------------------------------- |
| ... | ... | @@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P |
| 294 | 296 | return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); |
| 295 | 297 | } |
| 296 | 298 | if ( zExp < 0 ) { |
| 299 | + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); | |
| 297 | 300 | isTiny = |
| 298 | 301 | ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) |
| 299 | 302 | || ( zExp < -1 ) |
| ... | ... | @@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P |
| 457 | 460 | return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); |
| 458 | 461 | } |
| 459 | 462 | if ( zExp < 0 ) { |
| 463 | + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); | |
| 460 | 464 | isTiny = |
| 461 | 465 | ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) |
| 462 | 466 | || ( zExp < -1 ) |
| ... | ... | @@ -635,6 +639,7 @@ static floatx80 |
| 635 | 639 | goto overflow; |
| 636 | 640 | } |
| 637 | 641 | if ( zExp <= 0 ) { |
| 642 | + if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 ); | |
| 638 | 643 | isTiny = |
| 639 | 644 | ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) |
| 640 | 645 | || ( zExp < 0 ) |
| ... | ... | @@ -965,6 +970,7 @@ static float128 |
| 965 | 970 | return packFloat128( zSign, 0x7FFF, 0, 0 ); |
| 966 | 971 | } |
| 967 | 972 | if ( zExp < 0 ) { |
| 973 | + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); | |
| 968 | 974 | isTiny = |
| 969 | 975 | ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) |
| 970 | 976 | || ( zExp < -1 ) |
| ... | ... | @@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) |
| 1637 | 1643 | if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); |
| 1638 | 1644 | return a; |
| 1639 | 1645 | } |
| 1640 | - if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); | |
| 1646 | + if ( aExp == 0 ) { | |
| 1647 | + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); | |
| 1648 | + return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); | |
| 1649 | + } | |
| 1641 | 1650 | zSig = 0x40000000 + aSig + bSig; |
| 1642 | 1651 | zExp = aExp; |
| 1643 | 1652 | goto roundAndPack; |
| ... | ... | @@ -2595,7 +2604,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) |
| 2595 | 2604 | if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); |
| 2596 | 2605 | return a; |
| 2597 | 2606 | } |
| 2598 | - if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); | |
| 2607 | + if ( aExp == 0 ) { | |
| 2608 | + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); | |
| 2609 | + return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); | |
| 2610 | + } | |
| 2599 | 2611 | zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; |
| 2600 | 2612 | zExp = aExp; |
| 2601 | 2613 | goto roundAndPack; |
| ... | ... | @@ -4597,7 +4609,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM |
| 4597 | 4609 | return a; |
| 4598 | 4610 | } |
| 4599 | 4611 | add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); |
| 4600 | - if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); | |
| 4612 | + if ( aExp == 0 ) { | |
| 4613 | + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); | |
| 4614 | + return packFloat128( zSign, 0, zSig0, zSig1 ); | |
| 4615 | + } | |
| 4601 | 4616 | zSig2 = 0; |
| 4602 | 4617 | zSig0 |= LIT64( 0x0002000000000000 ); |
| 4603 | 4618 | zExp = aExp; | ... | ... |
fpu/softfloat.h
| ... | ... | @@ -190,11 +190,16 @@ typedef struct float_status { |
| 190 | 190 | #ifdef FLOATX80 |
| 191 | 191 | signed char floatx80_rounding_precision; |
| 192 | 192 | #endif |
| 193 | + flag flush_to_zero; | |
| 193 | 194 | flag default_nan_mode; |
| 194 | 195 | } float_status; |
| 195 | 196 | |
| 196 | 197 | void set_float_rounding_mode(int val STATUS_PARAM); |
| 197 | 198 | void set_float_exception_flags(int val STATUS_PARAM); |
| 199 | +INLINE void set_flush_to_zero(flag val STATUS_PARAM) | |
| 200 | +{ | |
| 201 | + STATUS(flush_to_zero) = val; | |
| 202 | +} | |
| 198 | 203 | INLINE void set_default_nan_mode(flag val STATUS_PARAM) |
| 199 | 204 | { |
| 200 | 205 | STATUS(default_nan_mode) = val; | ... | ... |
target-arm/helper.c
| ... | ... | @@ -2334,12 +2334,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) |
| 2334 | 2334 | } |
| 2335 | 2335 | set_float_rounding_mode(i, &env->vfp.fp_status); |
| 2336 | 2336 | } |
| 2337 | + if (changed & (1 << 24)) | |
| 2338 | + set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); | |
| 2337 | 2339 | if (changed & (1 << 25)) |
| 2338 | 2340 | set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); |
| 2339 | 2341 | |
| 2340 | 2342 | i = vfp_exceptbits_to_host((val >> 8) & 0x1f); |
| 2341 | 2343 | set_float_exception_flags(i, &env->vfp.fp_status); |
| 2342 | - /* XXX: FZ and DN are not implemented. */ | |
| 2343 | 2344 | } |
| 2344 | 2345 | |
| 2345 | 2346 | #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) | ... | ... |