[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 14/22] softfloat: Add support for ties-away rounding
From: |
Peter Maydell |
Subject: |
[Qemu-devel] [PATCH 14/22] softfloat: Add support for ties-away rounding |
Date: |
Tue, 31 Dec 2013 13:35:50 +0000 |
IEEE754-2008 specifies a new rounding mode:
"roundTiesToAway: the floating-point number nearest to the infinitely
precise result shall be delivered; if the two nearest floating-point
numbers bracketing an unrepresentable infinitely precise result are
equally near, the one with larger magnitude shall be delivered."
Implement this new mode (it is needed for ARM). The general principle
is that the required code is exactly like the ties-to-even code,
except that we do not need to do the "in case of exact tie clear LSB
to round-to-even", because the rounding operation naturally causes
the exact tie to round up in magnitude.
Signed-off-by: Peter Maydell <address@hidden>
---
fpu/softfloat.c | 68 ++++++++++++++++++++++++++++++++++++-------------
include/fpu/softfloat.h | 3 ++-
2 files changed, 53 insertions(+), 18 deletions(-)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 623a4b9..ce7970f 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -107,7 +107,7 @@ static int32 roundAndPackInt32( flag zSign, uint64_t absZ
STATUS_PARAM)
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x40;
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
@@ -155,7 +155,7 @@ static int64 roundAndPackInt64( flag zSign, uint64_t absZ0,
uint64_t absZ1 STATU
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (int64_t) absZ1 < 0 );
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
@@ -206,7 +206,7 @@ static int64 roundAndPackUint64(flag zSign, uint64_t absZ0,
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = (roundingMode == float_round_nearest_even);
increment = ((int64_t)absZ1 < 0);
- if (!roundNearestEven) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if (roundingMode == float_round_to_zero) {
increment = 0;
} else if (absZ1) {
@@ -354,7 +354,7 @@ static float32 roundAndPackFloat32(flag zSign, int_fast16_t
zExp, uint32_t zSig
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x40;
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
@@ -536,7 +536,7 @@ static float64 roundAndPackFloat64(flag zSign, int_fast16_t
zExp, uint64_t zSig
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x200;
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
@@ -718,7 +718,7 @@ static floatx80
goto precision80;
}
zSig0 |= ( zSig1 != 0 );
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
@@ -1029,7 +1029,7 @@ static float128
roundingMode = STATUS(float_rounding_mode);
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (int64_t) zSig2 < 0 );
- if ( ! roundNearestEven ) {
+ if (!roundNearestEven && roundingMode != float_round_ties_away) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
@@ -1756,6 +1756,11 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
return packFloat32( aSign, 0x7F, 0 );
}
break;
+ case float_round_ties_away:
+ if (aExp == 0x7E) {
+ return packFloat32(aSign, 0x7F, 0);
+ }
+ break;
case float_round_down:
return make_float32(aSign ? 0xBF800000 : 0);
case float_round_up:
@@ -1771,8 +1776,9 @@ float32 float32_round_to_int( float32 a STATUS_PARAM)
if ( roundingMode == float_round_nearest_even ) {
z += lastBitMask>>1;
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
- }
- else if ( roundingMode != float_round_to_zero ) {
+ } else if (roundingMode == float_round_ties_away) {
+ z += lastBitMask >> 1;
+ } else if (roundingMode != float_round_to_zero) {
if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode ==
float_round_up ) ) {
z += roundBitsMask;
}
@@ -3144,6 +3150,9 @@ static float32 roundAndPackFloat16(flag zSign,
int_fast16_t zExp,
increment = zSig & (increment << 1);
}
break;
+ case float_round_ties_away:
+ increment = (mask + 1) >> 1;
+ break;
case float_round_up:
increment = zSign ? 0 : mask;
break;
@@ -3449,6 +3458,11 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
return packFloat64( aSign, 0x3FF, 0 );
}
break;
+ case float_round_ties_away:
+ if (aExp == 0x3FE) {
+ return packFloat64(aSign, 0x3ff, 0);
+ }
+ break;
case float_round_down:
return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0);
case float_round_up:
@@ -3465,8 +3479,9 @@ float64 float64_round_to_int( float64 a STATUS_PARAM )
if ( roundingMode == float_round_nearest_even ) {
z += lastBitMask>>1;
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
- }
- else if ( roundingMode != float_round_to_zero ) {
+ } else if (roundingMode == float_round_ties_away) {
+ z += lastBitMask >> 1;
+ } else if (roundingMode != float_round_to_zero) {
if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode ==
float_round_up ) ) {
z += roundBitsMask;
}
@@ -4722,6 +4737,11 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM )
packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
}
break;
+ case float_round_ties_away:
+ if (aExp == 0x3FFE) {
+ return packFloatx80(aSign, 0x3FFF, LIT64(0x8000000000000000));
+ }
+ break;
case float_round_down:
return
aSign ?
@@ -4742,8 +4762,9 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM )
if ( roundingMode == float_round_nearest_even ) {
z.low += lastBitMask>>1;
if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
- }
- else if ( roundingMode != float_round_to_zero ) {
+ } else if (roundingMode == float_round_ties_away) {
+ z.low += lastBitMask >> 1;
+ } else if (roundingMode != float_round_to_zero) {
if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
z.low += roundBitsMask;
}
@@ -5801,8 +5822,15 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1;
}
}
- }
- else if ( roundingMode != float_round_to_zero ) {
+ } else if (roundingMode == float_round_ties_away) {
+ if (lastBitMask) {
+ add128(z.high, z.low, 0, lastBitMask >> 1, &z.high, &z.low);
+ } else {
+ if ((int64_t) z.low < 0) {
+ ++z.high;
+ }
+ }
+ } else if (roundingMode != float_round_to_zero) {
if ( extractFloat128Sign( z )
^ ( roundingMode == float_round_up ) ) {
add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
@@ -5824,6 +5852,11 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
return packFloat128( aSign, 0x3FFF, 0, 0 );
}
break;
+ case float_round_ties_away:
+ if (aExp == 0x3FFE) {
+ return packFloat128(aSign, 0x3FFF, 0, 0);
+ }
+ break;
case float_round_down:
return
aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
@@ -5846,8 +5879,9 @@ float128 float128_round_to_int( float128 a STATUS_PARAM )
if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
z.high &= ~ lastBitMask;
}
- }
- else if ( roundingMode != float_round_to_zero ) {
+ } else if (roundingMode == float_round_ties_away) {
+ z.high += lastBitMask>>1;
+ } else if (roundingMode != float_round_to_zero) {
if ( extractFloat128Sign( z )
^ ( roundingMode == float_round_up ) ) {
z.high |= ( a.low != 0 );
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index 08c7559..7f50d4f 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -152,7 +152,8 @@ enum {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
- float_round_to_zero = 3
+ float_round_to_zero = 3,
+ float_round_ties_away = 4,
};
/*----------------------------------------------------------------------------
--
1.8.5
- Re: [Qemu-devel] [PATCH 18/22] target-arm: A64: Add extra VFP fixed point conversion helpers, (continued)
- [Qemu-devel] [PATCH 06/22] softfloat: Fix factor 2 error for scalbn on denormal inputs, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 05/22] softfloat: Only raise Invalid when conversions to int are out of range, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 09/22] softfloat: Fix float64_to_uint32, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 17/22] target-arm: Ignore most exceptions from scalbn when doing fixpoint conversion, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 21/22] target-arm: A64: Add 1-source 32-to-32 and 64-to-64 FP instructions, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 04/22] softfloat: Fix float64_to_uint64, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 13/22] softfloat: Add float16 <=> float64 conversion functions, Peter Maydell, 2013/12/31
- [Qemu-devel] [PATCH 14/22] softfloat: Add support for ties-away rounding,
Peter Maydell <=
- [Qemu-devel] [PATCH 12/22] softfloat: Factor out RoundAndPackFloat16 and NormalizeFloat16Subnormal, Peter Maydell, 2013/12/31