The macro require_valid_floatx80(value, status) will check for malformed extended precision encodings, and if one is found, generate an invalid-operation exception and return NaN. This check has been added to the beginning of the basic 80-bit float arithmetic functions.
Version 2: fix code style Signed-off-by: Andrew Dutcher <and...@andrewdutcher.com> --- fpu/softfloat-specialize.h | 12 ++++++++++++ fpu/softfloat.c | 11 +++++++++++ include/fpu/softfloat.h | 13 +++++++++++++ 3 files changed, 36 insertions(+) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 43d0890..0e6ec25 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -203,6 +203,18 @@ void float_raise(int8_t flags, float_status *status) } /*---------------------------------------------------------------------------- +| Asserts that the given value must be a valid floatx80 encoding. If The given +| value is a pseudo-NaN, pseudo-infiinty, or un-normal, raise an invalid +| operation exception and cause the parent function to return NaN. +*----------------------------------------------------------------------------*/ + +#define require_valid_floatx80(a, status) \ + if (floatx80_invalid_encoding((a))) { \ + float_raise(float_flag_invalid, (status)); \ + return floatx80_default_nan((status)); \ + } + +/*---------------------------------------------------------------------------- | Internal canonical NaN format. *----------------------------------------------------------------------------*/ typedef struct { diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 9b1eccf..a921e5e 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -5279,6 +5279,8 @@ floatx80 floatx80_add(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + require_valid_floatx80(a, status); + require_valid_floatx80(b, status); aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5300,6 +5302,8 @@ floatx80 floatx80_sub(floatx80 a, floatx80 b, float_status *status) { flag aSign, bSign; + require_valid_floatx80(a, status); + require_valid_floatx80(b, status); aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5323,6 +5327,8 @@ floatx80 floatx80_mul(floatx80 a, floatx80 b, float_status *status) int32_t aExp, bExp, zExp; uint64_t aSig, bSig, zSig0, zSig1; + require_valid_floatx80(a, status); + require_valid_floatx80(b, status); aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5380,6 +5386,8 @@ floatx80 floatx80_div(floatx80 a, floatx80 b, float_status *status) uint64_t aSig, bSig, zSig0, zSig1; uint64_t rem0, rem1, rem2, term0, term1, term2; + require_valid_floatx80(a, status); + require_valid_floatx80(b, status); aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5461,6 +5469,8 @@ floatx80 floatx80_rem(floatx80 a, floatx80 b, float_status *status) uint64_t aSig0, aSig1, bSig; uint64_t q, term0, term1, alternateASig0, alternateASig1; + require_valid_floatx80(a, status); + require_valid_floatx80(b, status); aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5556,6 +5566,7 @@ 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; + require_valid_floatx80(a, status); aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 0e57ee5..569730f 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -671,6 +671,19 @@ static inline int floatx80_is_any_nan(floatx80 a) floatx80 floatx80_default_nan(float_status *status); /*---------------------------------------------------------------------------- +| 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. +*----------------------------------------------------------------------------*/ + +static inline bool floatx80_invalid_encoding(floatx80 a) +{ + return !(a.low & 0x8000000000000000) && !!(a.high & 0x7FFF); +} + + +/*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision conversion routines. *----------------------------------------------------------------------------*/ int32_t float128_to_int32(float128, float_status *status); -- 2.7.4