From fe76d97653d6611df19dacc4e326fc7d3d057237 Mon Sep 17 00:00:00 2001 From: pbrook Date: Fri, 19 Dec 2008 14:33:59 +0000 Subject: [PATCH] Implement flush-to-zero mode (denormal results are replaced with zero). Signed-off-by: Paul Brook git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6107 c046a42c-6fe2-441c-8c8c-71466251a162 --- fpu/softfloat.c | 21 ++++++++++++++++++--- fpu/softfloat.h | 5 +++++ target-arm/helper.c | 3 ++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e66a5d46c8..3d5169db93 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ +/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also + be flushed to zero. */ #include "softfloat.h" /*---------------------------------------------------------------------------- @@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -635,6 +639,7 @@ static floatx80 goto overflow; } if ( zExp <= 0 ) { + if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < 0 ) @@ -965,6 +970,7 @@ static float128 return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); return a; } - if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + } zSig = 0x40000000 + aSig + bSig; zExp = aExp; goto roundAndPack; @@ -2595,7 +2604,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); return a; } - if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + } zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; zExp = aExp; goto roundAndPack; @@ -4597,7 +4609,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM return a; } add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + return packFloat128( zSign, 0, zSig0, zSig1 ); + } zSig2 = 0; zSig0 |= LIT64( 0x0002000000000000 ); zExp = aExp; diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 6cd4facc88..b46d63ca60 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -190,11 +190,16 @@ typedef struct float_status { #ifdef FLOATX80 signed char floatx80_rounding_precision; #endif + flag flush_to_zero; flag default_nan_mode; } float_status; void set_float_rounding_mode(int val STATUS_PARAM); void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_flush_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_to_zero) = val; +} INLINE void set_default_nan_mode(flag val STATUS_PARAM) { STATUS(default_nan_mode) = val; diff --git a/target-arm/helper.c b/target-arm/helper.c index 79163b8287..81663c8f3b 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2334,12 +2334,13 @@ void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) } set_float_rounding_mode(i, &env->vfp.fp_status); } + if (changed & (1 << 24)) + set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status); if (changed & (1 << 25)) set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status); i = vfp_exceptbits_to_host((val >> 8) & 0x1f); set_float_exception_flags(i, &env->vfp.fp_status); - /* XXX: FZ and DN are not implemented. */ } #define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))