Commit fe76d97653d6611df19dacc4e326fc7d3d057237

Authored by pbrook
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
fpu/softfloat.c
@@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained. @@ -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 #include "softfloat.h" 35 #include "softfloat.h"
34 36
35 /*---------------------------------------------------------------------------- 37 /*----------------------------------------------------------------------------
@@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P @@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
294 return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); 296 return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
295 } 297 }
296 if ( zExp < 0 ) { 298 if ( zExp < 0 ) {
  299 + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
297 isTiny = 300 isTiny =
298 ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) 301 ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
299 || ( zExp < -1 ) 302 || ( zExp < -1 )
@@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P @@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
457 return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); 460 return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
458 } 461 }
459 if ( zExp < 0 ) { 462 if ( zExp < 0 ) {
  463 + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
460 isTiny = 464 isTiny =
461 ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) 465 ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
462 || ( zExp < -1 ) 466 || ( zExp < -1 )
@@ -635,6 +639,7 @@ static floatx80 @@ -635,6 +639,7 @@ static floatx80
635 goto overflow; 639 goto overflow;
636 } 640 }
637 if ( zExp <= 0 ) { 641 if ( zExp <= 0 ) {
  642 + if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
638 isTiny = 643 isTiny =
639 ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) 644 ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
640 || ( zExp < 0 ) 645 || ( zExp < 0 )
@@ -965,6 +970,7 @@ static float128 @@ -965,6 +970,7 @@ static float128
965 return packFloat128( zSign, 0x7FFF, 0, 0 ); 970 return packFloat128( zSign, 0x7FFF, 0, 0 );
966 } 971 }
967 if ( zExp < 0 ) { 972 if ( zExp < 0 ) {
  973 + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
968 isTiny = 974 isTiny =
969 ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) 975 ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
970 || ( zExp < -1 ) 976 || ( zExp < -1 )
@@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) @@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
1637 if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); 1643 if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR );
1638 return a; 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 zSig = 0x40000000 + aSig + bSig; 1650 zSig = 0x40000000 + aSig + bSig;
1642 zExp = aExp; 1651 zExp = aExp;
1643 goto roundAndPack; 1652 goto roundAndPack;
@@ -2595,7 +2604,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) @@ -2595,7 +2604,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
2595 if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); 2604 if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR );
2596 return a; 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 zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; 2611 zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
2600 zExp = aExp; 2612 zExp = aExp;
2601 goto roundAndPack; 2613 goto roundAndPack;
@@ -4597,7 +4609,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM @@ -4597,7 +4609,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
4597 return a; 4609 return a;
4598 } 4610 }
4599 add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); 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 zSig2 = 0; 4616 zSig2 = 0;
4602 zSig0 |= LIT64( 0x0002000000000000 ); 4617 zSig0 |= LIT64( 0x0002000000000000 );
4603 zExp = aExp; 4618 zExp = aExp;
fpu/softfloat.h
@@ -190,11 +190,16 @@ typedef struct float_status { @@ -190,11 +190,16 @@ typedef struct float_status {
190 #ifdef FLOATX80 190 #ifdef FLOATX80
191 signed char floatx80_rounding_precision; 191 signed char floatx80_rounding_precision;
192 #endif 192 #endif
  193 + flag flush_to_zero;
193 flag default_nan_mode; 194 flag default_nan_mode;
194 } float_status; 195 } float_status;
195 196
196 void set_float_rounding_mode(int val STATUS_PARAM); 197 void set_float_rounding_mode(int val STATUS_PARAM);
197 void set_float_exception_flags(int val STATUS_PARAM); 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 INLINE void set_default_nan_mode(flag val STATUS_PARAM) 203 INLINE void set_default_nan_mode(flag val STATUS_PARAM)
199 { 204 {
200 STATUS(default_nan_mode) = val; 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,12 +2334,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
2334 } 2334 }
2335 set_float_rounding_mode(i, &env->vfp.fp_status); 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 if (changed & (1 << 25)) 2339 if (changed & (1 << 25))
2338 set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); 2340 set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
2339 2341
2340 i = vfp_exceptbits_to_host((val >> 8) & 0x1f); 2342 i = vfp_exceptbits_to_host((val >> 8) & 0x1f);
2341 set_float_exception_flags(i, &env->vfp.fp_status); 2343 set_float_exception_flags(i, &env->vfp.fp_status);
2342 - /* XXX: FZ and DN are not implemented. */  
2343 } 2344 }
2344 2345
2345 #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) 2346 #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))