mirror of
https://github.com/qemu/qemu.git
synced 2024-11-27 05:43:47 +08:00
fpu: add mechanism to check for invalid long double formats
All operations that take a floatx80 as an operand need to have their inputs checked for malformed encodings. In all of these cases, use the function floatx80_invalid_encoding to perform the check. If an invalid operand is found, raise an invalid operation exception, and then return either NaN (for fp-typed results) or the integer indefinite value (the minimum representable signed integer value, for int-typed results). For the non-quiet comparison operations, this touches adjacent code in order to pass style checks. Signed-off-by: Andrew Dutcher <andrew@andrewdutcher.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1471392895-17324-1-git-send-email-andrew@andrewdutcher.com [PMM: changed "1 << 63" to "1ULL << 63" to fix compile errors] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
9e8204b1de
commit
d1eb8f2acb
116
fpu/softfloat.c
116
fpu/softfloat.c
@ -4814,6 +4814,10 @@ int32_t floatx80_to_int32(floatx80 a, float_status *status)
|
||||
int32_t aExp, shiftCount;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1 << 31;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -4842,6 +4846,10 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status)
|
||||
uint64_t aSig, savedASig;
|
||||
int32_t z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1 << 31;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -4888,6 +4896,10 @@ int64_t floatx80_to_int64(floatx80 a, float_status *status)
|
||||
int32_t aExp, shiftCount;
|
||||
uint64_t aSig, aSigExtra;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1ULL << 63;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -4929,6 +4941,10 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status)
|
||||
uint64_t aSig;
|
||||
int64_t z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1ULL << 63;
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -4971,6 +4987,10 @@ float32 floatx80_to_float32(floatx80 a, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float32_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -4999,6 +5019,10 @@ float64 floatx80_to_float64(floatx80 a, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig, zSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float64_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5027,6 +5051,10 @@ float128 floatx80_to_float128(floatx80 a, float_status *status)
|
||||
int aExp;
|
||||
uint64_t aSig, zSig0, zSig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float128_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5052,6 +5080,10 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
|
||||
uint64_t lastBitMask, roundBitsMask;
|
||||
floatx80 z;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aExp = extractFloatx80Exp( a );
|
||||
if ( 0x403E <= aExp ) {
|
||||
if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) {
|
||||
@ -5279,6 +5311,10 @@ floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSign = extractFloatx80Sign( a );
|
||||
bSign = extractFloatx80Sign( b );
|
||||
if ( aSign == bSign ) {
|
||||
@ -5300,6 +5336,10 @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSign = extractFloatx80Sign( a );
|
||||
bSign = extractFloatx80Sign( b );
|
||||
if ( aSign == bSign ) {
|
||||
@ -5323,6 +5363,10 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status)
|
||||
int32_t aExp, bExp, zExp;
|
||||
uint64_t aSig, bSig, zSig0, zSig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5380,6 +5424,10 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status)
|
||||
uint64_t aSig, bSig, zSig0, zSig1;
|
||||
uint64_t rem0, rem1, rem2, term0, term1, term2;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5461,6 +5509,10 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status)
|
||||
uint64_t aSig0, aSig1, bSig;
|
||||
uint64_t q, term0, term1, alternateASig0, alternateASig1;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig0 = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5556,6 +5608,10 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
||||
uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0;
|
||||
uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig0 = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
@ -5620,10 +5676,11 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status)
|
||||
int floatx80_eq(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@ -5649,10 +5706,11 @@ int floatx80_le(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@ -5682,10 +5740,11 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
@ -5712,10 +5771,11 @@ int floatx80_lt(floatx80 a, floatx80 b, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int floatx80_unordered(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( b )<<1 ) )
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)
|
||||
|| (extractFloatx80Exp(a) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(a) << 1))
|
||||
|| (extractFloatx80Exp(b) == 0x7FFF
|
||||
&& (uint64_t) (extractFloatx80Frac(b) << 1))
|
||||
) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
@ -5733,6 +5793,10 @@ int floatx80_unordered(floatx80 a, floatx80 b, float_status *status)
|
||||
int floatx80_eq_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@ -5764,6 +5828,10 @@ int floatx80_le_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@ -5800,6 +5868,10 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 0;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@ -5833,6 +5905,10 @@ int floatx80_lt_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
*----------------------------------------------------------------------------*/
|
||||
int floatx80_unordered_quiet(floatx80 a, floatx80 b, float_status *status)
|
||||
{
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return 1;
|
||||
}
|
||||
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
|
||||
&& (uint64_t) ( extractFloatx80Frac( a )<<1 ) )
|
||||
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
|
||||
@ -7374,6 +7450,10 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b,
|
||||
{
|
||||
flag aSign, bSign;
|
||||
|
||||
if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return float_relation_unordered;
|
||||
}
|
||||
if (( ( extractFloatx80Exp( a ) == 0x7fff ) &&
|
||||
( extractFloatx80Frac( a )<<1 ) ) ||
|
||||
( ( extractFloatx80Exp( b ) == 0x7fff ) &&
|
||||
@ -7645,6 +7725,10 @@ floatx80 floatx80_scalbn(floatx80 a, int n, float_status *status)
|
||||
int32_t aExp;
|
||||
uint64_t aSig;
|
||||
|
||||
if (floatx80_invalid_encoding(a)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
return floatx80_default_nan(status);
|
||||
}
|
||||
aSig = extractFloatx80Frac( a );
|
||||
aExp = extractFloatx80Exp( a );
|
||||
aSign = extractFloatx80Sign( a );
|
||||
|
@ -658,6 +658,21 @@ static inline int floatx80_is_any_nan(floatx80 a)
|
||||
return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
| Return whether the given value is an invalid floatx80 encoding.
|
||||
| Invalid floatx80 encodings arise when the integer bit is not set, but
|
||||
| the exponent is not zero. The only times the integer bit is permitted to
|
||||
| be zero is in subnormal numbers and the value zero.
|
||||
| This includes what the Intel software developer's manual calls pseudo-NaNs,
|
||||
| pseudo-infinities and un-normal numbers. It does not include
|
||||
| pseudo-denormals, which must still be correctly handled as inputs even
|
||||
| if they are never generated as outputs.
|
||||
*----------------------------------------------------------------------------*/
|
||||
static inline bool floatx80_invalid_encoding(floatx80 a)
|
||||
{
|
||||
return (a.low & (1ULL << 63)) == 0 && (a.high & 0x7FFF) != 0;
|
||||
}
|
||||
|
||||
#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)
|
||||
#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL)
|
||||
#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)
|
||||
|
Loading…
Reference in New Issue
Block a user