softfloat: fix float*_scalnb() corner cases
float*_scalnb() were not taking into account all cases. This patch fixes some corner cases: - NaN values in input were not properly propagated and the invalid flag not correctly raised. Use propagateFloat*NaN() for that. - NaN or infinite values in input of floatx80_scalnb() were not correctly detected due to a typo. - The sum of exponent and n could overflow, leading to strange results. Additionally having int16 defined to int make that happening for a very small range of values. Fix that by saturating n to the maximum exponent range, and using an explicit wider type if needed. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
f6714d365d
commit
326b9e98a3
@ -6333,7 +6333,7 @@ MINMAX(64, 0x7ff)
|
||||
float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
int16_t aExp;
|
||||
uint32_t aSig;
|
||||
|
||||
a = float32_squash_input_denormal(a STATUS_VAR);
|
||||
@ -6342,6 +6342,9 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
aSign = extractFloat32Sign( a );
|
||||
|
||||
if ( aExp == 0xFF ) {
|
||||
if ( aSig ) {
|
||||
return propagateFloat32NaN( a, a STATUS_VAR );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
if ( aExp != 0 )
|
||||
@ -6349,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
else if ( aSig == 0 )
|
||||
return a;
|
||||
|
||||
if (n > 0x200) {
|
||||
n = 0x200;
|
||||
} else if (n < -0x200) {
|
||||
n = -0x200;
|
||||
}
|
||||
|
||||
aExp += n - 1;
|
||||
aSig <<= 7;
|
||||
return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR );
|
||||
@ -6357,7 +6366,7 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM )
|
||||
float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
int16_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
a = float64_squash_input_denormal(a STATUS_VAR);
|
||||
@ -6366,6 +6375,9 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
aSign = extractFloat64Sign( a );
|
||||
|
||||
if ( aExp == 0x7FF ) {
|
||||
if ( aSig ) {
|
||||
return propagateFloat64NaN( a, a STATUS_VAR );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
if ( aExp != 0 )
|
||||
@ -6373,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
else if ( aSig == 0 )
|
||||
return a;
|
||||
|
||||
if (n > 0x1000) {
|
||||
n = 0x1000;
|
||||
} else if (n < -0x1000) {
|
||||
n = -0x1000;
|
||||
}
|
||||
|
||||
aExp += n - 1;
|
||||
aSig <<= 10;
|
||||
return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
|
||||
@ -6382,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
|
||||
floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int16 aExp;
|
||||
int32_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
|
||||
if ( aExp == 0x7FF ) {
|
||||
if ( aExp == 0x7FFF ) {
|
||||
if ( aSig<<1 ) {
|
||||
return propagateFloatx80NaN( a, a STATUS_VAR );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
if (aExp == 0 && aSig == 0)
|
||||
return a;
|
||||
|
||||
if (n > 0x10000) {
|
||||
n = 0x10000;
|
||||
} else if (n < -0x10000) {
|
||||
n = -0x10000;
|
||||
}
|
||||
|
||||
aExp += n;
|
||||
return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
|
||||
aSign, aExp, aSig, 0 STATUS_VAR );
|
||||
@ -6405,7 +6433,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
|
||||
float128 float128_scalbn( float128 a, int n STATUS_PARAM )
|
||||
{
|
||||
flag aSign;
|
||||
int32 aExp;
|
||||
int32_t aExp;
|
||||
uint64_t aSig0, aSig1;
|
||||
|
||||
aSig1 = extractFloat128Frac1( a );
|
||||
@ -6413,6 +6441,9 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
|
||||
aExp = extractFloat128Exp( a );
|
||||
aSign = extractFloat128Sign( a );
|
||||
if ( aExp == 0x7FFF ) {
|
||||
if ( aSig0 | aSig1 ) {
|
||||
return propagateFloat128NaN( a, a STATUS_VAR );
|
||||
}
|
||||
return a;
|
||||
}
|
||||
if ( aExp != 0 )
|
||||
@ -6420,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
|
||||
else if ( aSig0 == 0 && aSig1 == 0 )
|
||||
return a;
|
||||
|
||||
if (n > 0x10000) {
|
||||
n = 0x10000;
|
||||
} else if (n < -0x10000) {
|
||||
n = -0x10000;
|
||||
}
|
||||
|
||||
aExp += n - 1;
|
||||
return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1
|
||||
STATUS_VAR );
|
||||
|
Loading…
Reference in New Issue
Block a user