diff options
author | Maciej W. Rozycki <macro@codesourcery.com> | 2013-05-16 23:33:55 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@codesourcery.com> | 2013-05-16 23:33:55 +0100 |
commit | 2848b105856e49d98f3c5026b6d8d790f9723c0c (patch) | |
tree | 66e6cc9d3c1c6d95324e50ceb1140d0eed52ec37 /soft-fp | |
parent | c58b274f01658400ba75886b04cb044ba9467a94 (diff) | |
download | glibc-2848b105856e49d98f3c5026b6d8d790f9723c0c.zip glibc-2848b105856e49d98f3c5026b6d8d790f9723c0c.tar.gz glibc-2848b105856e49d98f3c5026b6d8d790f9723c0c.tar.bz2 |
MIPS: soft-fp NaN representation corrections
[BZ #15442] This adds support for the inverse interpretation of the
quiet bit of IEEE 754 floating-point NaN data that some processors
use. This includes in particular MIPS architecture processors; the
payload used for the canonical qNaN encoding is updated accordingly
so as not to interfere with the quiet bit.
Diffstat (limited to 'soft-fp')
-rw-r--r-- | soft-fp/op-common.h | 57 | ||||
-rw-r--r-- | soft-fp/testit.c | 8 |
2 files changed, 54 insertions, 11 deletions
diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h index a9d94d7..8b73b58 100644 --- a/soft-fp/op-common.h +++ b/soft-fp/op-common.h @@ -35,6 +35,16 @@ _FP_I_TYPE X##_e; \ _FP_FRAC_DECL_##wc(X) +/* Test whether the qNaN bit denotes a signaling NaN. */ +#define _FP_FRAC_SNANP(fs, X) \ + ((_FP_QNANNEGATEDP) \ + ? (_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ + : !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) +#define _FP_FRAC_SNANP_SEMIRAW(fs, X) \ + ((_FP_QNANNEGATEDP) \ + ? (_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs) \ + : !(_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs)) + /* * Finish truely unpacking a native fp value by classifying the kind * of fp value and normalizing both the exponent and the fraction. @@ -74,7 +84,7 @@ do { \ { \ X##_c = FP_CLS_NAN; \ /* Check for signaling NaN */ \ - if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ + if (_FP_FRAC_SNANP(fs, X)) \ FP_SET_EXCEPTION(FP_EX_INVALID); \ } \ break; \ @@ -112,7 +122,7 @@ do { \ do { \ if (X##_e == _FP_EXPMAX_##fs \ && !_FP_FRAC_ZEROP_##wc(X) \ - && !(_FP_FRAC_HIGH_##fs(X) & _FP_QNANBIT_SH_##fs)) \ + && _FP_FRAC_SNANP_SEMIRAW(fs, X)) \ FP_SET_EXCEPTION(FP_EX_INVALID); \ } while (0) @@ -127,6 +137,39 @@ do { \ _FP_FRAC_SLL_##wc(R, _FP_WORKBITS); \ } while (0) +/* Make the fractional part a quiet NaN, preserving the payload + if possible, otherwise make it the canonical quiet NaN and set + the sign bit accordingly. */ +#define _FP_SETQNAN(fs, wc, X) \ +do { \ + if (_FP_QNANNEGATEDP) \ + { \ + _FP_FRAC_HIGH_RAW_##fs(X) &= _FP_QNANBIT_##fs - 1; \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + { \ + X##_s = _FP_NANSIGN_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ + } \ + } \ + else \ + _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ +} while (0) +#define _FP_SETQNAN_SEMIRAW(fs, wc, X) \ +do { \ + if (_FP_QNANNEGATEDP) \ + { \ + _FP_FRAC_HIGH_##fs(X) &= _FP_QNANBIT_SH_##fs - 1; \ + if (_FP_FRAC_ZEROP_##wc(X)) \ + { \ + X##_s = _FP_NANSIGN_##fs; \ + _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ + _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ + } \ + } \ + else \ + _FP_FRAC_HIGH_##fs(X) |= _FP_QNANBIT_SH_##fs; \ +} while (0) + /* Test whether a biased exponent is normal (not zero or maximum). */ #define _FP_EXP_NORMAL(fs, wc, X) (((X##_e + 1) & _FP_EXPMAX_##fs) > 1) @@ -159,7 +202,7 @@ do { \ X##_s = _FP_NANSIGN_##fs; \ } \ else \ - _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ + _FP_SETQNAN(fs, wc, X); \ } \ } while (0) @@ -273,7 +316,7 @@ do { \ X##_s = _FP_NANSIGN_##fs; \ } \ else \ - _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ + _FP_SETQNAN(fs, wc, X); \ break; \ } \ } while (0) @@ -287,7 +330,7 @@ do { \ if (X##_e == _FP_EXPMAX_##fs) \ { \ if (!_FP_FRAC_ZEROP_##wc(X) \ - && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ + && _FP_FRAC_SNANP(fs, X)) \ __ret = 1; \ } \ __ret; \ @@ -1199,7 +1242,7 @@ do { \ D##_e = _FP_EXPMAX_##dfs; \ if (!_FP_FRAC_ZEROP_##swc(S)) \ { \ - if (!(_FP_FRAC_HIGH_RAW_##sfs(S) & _FP_QNANBIT_##sfs)) \ + if (_FP_FRAC_SNANP(sfs, S)) \ FP_SET_EXCEPTION(FP_EX_INVALID); \ _FP_FRAC_SLL_##dwc(D, (_FP_FRACBITS_##dfs \ - _FP_FRACBITS_##sfs)); \ @@ -1286,7 +1329,7 @@ do { \ /* Semi-raw NaN must have all workbits cleared. */ \ _FP_FRAC_LOW_##dwc(D) \ &= ~(_FP_W_TYPE) ((1 << _FP_WORKBITS) - 1); \ - _FP_FRAC_HIGH_##dfs(D) |= _FP_QNANBIT_SH_##dfs; \ + _FP_SETQNAN_SEMIRAW(dfs, dwc, D); \ } \ } \ } \ diff --git a/soft-fp/testit.c b/soft-fp/testit.c index 46a50c4..f1e9b54 100644 --- a/soft-fp/testit.c +++ b/soft-fp/testit.c @@ -200,17 +200,17 @@ double gen_special_double(int i) case 0: X_c = FP_CLS_NAN; #if _FP_W_TYPE_SIZE < _FP_FRACBITS_D - __FP_FRAC_SET_2(X, _FP_QNANBIT_D, 0x1234); + __FP_FRAC_SET_2(X, _FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D, 0x1234); #else - _FP_FRAC_SET_1(X, _FP_QNANBIT_D | 0x1234); + _FP_FRAC_SET_1(X, (_FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D) | 0x1234); #endif break; case 2: X_c = FP_CLS_NAN; #if _FP_W_TYPE_SIZE < _FP_FRACBITS_D - __FP_FRAC_SET_2(X, _FP_QNANBIT_D, 0x1); + __FP_FRAC_SET_2(X, _FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D, 0x1); #else - _FP_FRAC_SET_1(X, _FP_QNANBIT_D | 0x1); + _FP_FRAC_SET_1(X, (_FP_QNANNEGATEDP ? 0 : _FP_QNANBIT_D) | 0x1); #endif break; case 4: |