diff --git a/ChangeLog b/ChangeLog index 985a702292..fa354c2334 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2014-10-09 Joseph Myers + + * soft-fp/soft-fp.h (FP_EX_INVALID_SNAN): New macro. + (FP_EX_INVALID_IMZ): Likewise. + (FP_EX_INVALID_IMZ_FMA): Likewise. + (FP_EX_INVALID_ISI): Likewise. + (FP_EX_INVALID_ZDZ): Likewise. + (FP_EX_INVALID_IDI): Likewise. + (FP_EX_INVALID_SQRT): Likewise. + (FP_EX_INVALID_CVI): Likewise. + (FP_EX_INVALID_VC): Likewise. + * soft-fp/op-common.h (_FP_UNPACK_CANONICAL): Specify more precise + "invalid" exceptions. + (_FP_CHECK_SIGNAN_SEMIRAW): Likewise. + (_FP_ADD_INTERNAL): Likewise. + (_FP_MUL): Likewise. + (_FP_FMA): Likewise. + (_FP_DIV): Likewise. + (_FP_CMP_CHECK_NAN): Likewise. + (_FP_SQRT): Likewise. + (_FP_TO_INT): Likewise. + (FP_EXTEND): Likewise. + 2014-10-09 Allan McRae * po/fr.po: Update French translation from translation project. diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h index 3da234ba33..8344be5aad 100644 --- a/soft-fp/op-common.h +++ b/soft-fp/op-common.h @@ -93,7 +93,8 @@ X##_c = FP_CLS_NAN; \ /* Check for signaling NaN. */ \ if (_FP_FRAC_SNANP (fs, X)) \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID \ + | FP_EX_INVALID_SNAN); \ } \ break; \ } \ @@ -144,14 +145,14 @@ /* Check for a semi-raw value being a signaling NaN and raise the invalid exception if so. */ -#define _FP_CHECK_SIGNAN_SEMIRAW(fs, wc, X) \ - do \ - { \ - if (X##_e == _FP_EXPMAX_##fs \ - && !_FP_FRAC_ZEROP_##wc (X) \ - && _FP_FRAC_SNANP_SEMIRAW (fs, X)) \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ - } \ +#define _FP_CHECK_SIGNAN_SEMIRAW(fs, wc, X) \ + do \ + { \ + if (X##_e == _FP_EXPMAX_##fs \ + && !_FP_FRAC_ZEROP_##wc (X) \ + && _FP_FRAC_SNANP_SEMIRAW (fs, X)) \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_SNAN); \ + } \ while (0) /* Choose a NaN result from an operation on two semi-raw NaN @@ -764,7 +765,8 @@ R##_s = _FP_NANSIGN_##fs; \ _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ _FP_FRAC_SLL_##wc (R, _FP_WORKBITS); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID \ + | FP_EX_INVALID_ISI); \ } \ else \ { \ @@ -916,7 +918,7 @@ R##_s = _FP_NANSIGN_##fs; \ R##_c = FP_CLS_NAN; \ _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_IMZ); \ break; \ \ default: \ @@ -1080,7 +1082,7 @@ _FP_FMA_T##_s = _FP_NANSIGN_##fs; \ _FP_FMA_T##_c = FP_CLS_NAN; \ _FP_FRAC_SET_##wc (_FP_FMA_T, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_IMZ_FMA); \ break; \ \ default: \ @@ -1125,7 +1127,7 @@ R##_s = _FP_NANSIGN_##fs; \ R##_c = FP_CLS_NAN; \ _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_ISI); \ } \ break; \ \ @@ -1199,7 +1201,10 @@ R##_s = _FP_NANSIGN_##fs; \ R##_c = FP_CLS_NAN; \ _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID \ + | (X##_c == FP_CLS_INF \ + ? FP_EX_INVALID_IDI \ + : FP_EX_INVALID_ZDZ)); \ break; \ \ default: \ @@ -1211,19 +1216,36 @@ /* Helper for comparisons. EX is 0 not to raise exceptions, 1 to raise exceptions for signaling NaN operands, 2 to raise exceptions - for all NaN operands. */ + for all NaN operands. Conditionals are organized to allow the + compiler to optimize away code based on the value of EX. */ -#define _FP_CMP_CHECK_NAN(fs, wc, X, Y, ex) \ - do \ - { \ - if (ex) \ - { \ - if ((ex) == 2 \ - || _FP_ISSIGNAN (fs, wc, X) \ - || _FP_ISSIGNAN (fs, wc, Y)) \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ - } \ - } \ +#define _FP_CMP_CHECK_NAN(fs, wc, X, Y, ex) \ + do \ + { \ + /* The arguments are unordered, which may or may not result in \ + an exception. */ \ + if (ex) \ + { \ + /* At least some cases of unordered arguments result in \ + exceptions; check whether this is one. */ \ + if (FP_EX_INVALID_SNAN || FP_EX_INVALID_VC) \ + { \ + /* Check separately for each case of "invalid" \ + exceptions. */ \ + if ((ex) == 2) \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_VC); \ + if (_FP_ISSIGNAN (fs, wc, X) \ + || _FP_ISSIGNAN (fs, wc, Y)) \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_SNAN); \ + } \ + /* Otherwise, we only need to check whether to raise an \ + exception, not which case or cases it is. */ \ + else if ((ex) == 2 \ + || _FP_ISSIGNAN (fs, wc, X) \ + || _FP_ISSIGNAN (fs, wc, Y)) \ + FP_SET_EXCEPTION (FP_EX_INVALID); \ + } \ + } \ while (0) /* Main differential comparison routine. The inputs should be raw not @@ -1314,58 +1336,58 @@ /* Main square root routine. The input value should be cooked. */ -#define _FP_SQRT(fs, wc, R, X) \ - do \ - { \ - _FP_FRAC_DECL_##wc (_FP_SQRT_T); \ - _FP_FRAC_DECL_##wc (_FP_SQRT_S); \ - _FP_W_TYPE _FP_SQRT_q; \ - switch (X##_c) \ - { \ - case FP_CLS_NAN: \ - _FP_FRAC_COPY_##wc (R, X); \ - R##_s = X##_s; \ - R##_c = FP_CLS_NAN; \ - break; \ - case FP_CLS_INF: \ - if (X##_s) \ - { \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; /* NAN */ \ - _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ - } \ - else \ - { \ - R##_s = 0; \ - R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ - } \ - break; \ - case FP_CLS_ZERO: \ - R##_s = X##_s; \ - R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ - break; \ - case FP_CLS_NORMAL: \ - R##_s = 0; \ - if (X##_s) \ - { \ - R##_c = FP_CLS_NAN; /* NAN */ \ - R##_s = _FP_NANSIGN_##fs; \ - _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ - break; \ - } \ - R##_c = FP_CLS_NORMAL; \ - if (X##_e & 1) \ - _FP_FRAC_SLL_##wc (X, 1); \ - R##_e = X##_e >> 1; \ - _FP_FRAC_SET_##wc (_FP_SQRT_S, _FP_ZEROFRAC_##wc); \ - _FP_FRAC_SET_##wc (R, _FP_ZEROFRAC_##wc); \ - _FP_SQRT_q = _FP_OVERFLOW_##fs >> 1; \ - _FP_SQRT_MEAT_##wc (R, _FP_SQRT_S, _FP_SQRT_T, X, \ - _FP_SQRT_q); \ - } \ - } \ +#define _FP_SQRT(fs, wc, R, X) \ + do \ + { \ + _FP_FRAC_DECL_##wc (_FP_SQRT_T); \ + _FP_FRAC_DECL_##wc (_FP_SQRT_S); \ + _FP_W_TYPE _FP_SQRT_q; \ + switch (X##_c) \ + { \ + case FP_CLS_NAN: \ + _FP_FRAC_COPY_##wc (R, X); \ + R##_s = X##_s; \ + R##_c = FP_CLS_NAN; \ + break; \ + case FP_CLS_INF: \ + if (X##_s) \ + { \ + R##_s = _FP_NANSIGN_##fs; \ + R##_c = FP_CLS_NAN; /* NAN */ \ + _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_SQRT); \ + } \ + else \ + { \ + R##_s = 0; \ + R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ + } \ + break; \ + case FP_CLS_ZERO: \ + R##_s = X##_s; \ + R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ + break; \ + case FP_CLS_NORMAL: \ + R##_s = 0; \ + if (X##_s) \ + { \ + R##_c = FP_CLS_NAN; /* NAN */ \ + R##_s = _FP_NANSIGN_##fs; \ + _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_SQRT); \ + break; \ + } \ + R##_c = FP_CLS_NORMAL; \ + if (X##_e & 1) \ + _FP_FRAC_SLL_##wc (X, 1); \ + R##_e = X##_e >> 1; \ + _FP_FRAC_SET_##wc (_FP_SQRT_S, _FP_ZEROFRAC_##wc); \ + _FP_FRAC_SET_##wc (R, _FP_ZEROFRAC_##wc); \ + _FP_SQRT_q = _FP_OVERFLOW_##fs >> 1; \ + _FP_SQRT_MEAT_##wc (R, _FP_SQRT_S, _FP_SQRT_T, X, \ + _FP_SQRT_q); \ + } \ + } \ while (0) /* Convert from FP to integer. Input is raw. */ @@ -1434,12 +1456,17 @@ }) \ : 0); \ if (!_FP_FRAC_ZEROP_##wc (X)) \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); \ else if (_FP_TO_INT_inexact) \ FP_SET_EXCEPTION (FP_EX_INEXACT); \ } \ else \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID \ + | FP_EX_INVALID_CVI \ + | ((FP_EX_INVALID_SNAN \ + && _FP_ISSIGNAN (fs, wc, X)) \ + ? FP_EX_INVALID_SNAN \ + : 0)); \ } \ else \ { \ @@ -1601,7 +1628,8 @@ if (!_FP_FRAC_ZEROP_##swc (S)) \ { \ if (_FP_FRAC_SNANP (sfs, S)) \ - FP_SET_EXCEPTION (FP_EX_INVALID); \ + FP_SET_EXCEPTION (FP_EX_INVALID \ + | FP_EX_INVALID_SNAN); \ _FP_FRAC_SLL_##dwc (D, (_FP_FRACBITS_##dfs \ - _FP_FRACBITS_##sfs)); \ _FP_SETQNAN (dfs, dwc, D); \ diff --git a/soft-fp/soft-fp.h b/soft-fp/soft-fp.h index 3ac269ecf7..05fcca0aba 100644 --- a/soft-fp/soft-fp.h +++ b/soft-fp/soft-fp.h @@ -83,6 +83,44 @@ # define FP_EX_DENORM 0 #endif +/* Sub-exceptions of "invalid". */ +/* Signaling NaN operand. */ +#ifndef FP_EX_INVALID_SNAN +# define FP_EX_INVALID_SNAN 0 +#endif +/* Inf * 0. */ +#ifndef FP_EX_INVALID_IMZ +# define FP_EX_INVALID_IMZ 0 +#endif +/* fma (Inf, 0, c). */ +#ifndef FP_EX_INVALID_IMZ_FMA +# define FP_EX_INVALID_IMZ_FMA 0 +#endif +/* Inf - Inf. */ +#ifndef FP_EX_INVALID_ISI +# define FP_EX_INVALID_ISI 0 +#endif +/* 0 / 0. */ +#ifndef FP_EX_INVALID_ZDZ +# define FP_EX_INVALID_ZDZ 0 +#endif +/* Inf / Inf. */ +#ifndef FP_EX_INVALID_IDI +# define FP_EX_INVALID_IDI 0 +#endif +/* sqrt (negative). */ +#ifndef FP_EX_INVALID_SQRT +# define FP_EX_INVALID_SQRT 0 +#endif +/* Invalid conversion to integer. */ +#ifndef FP_EX_INVALID_CVI +# define FP_EX_INVALID_CVI 0 +#endif +/* Invalid comparison. */ +#ifndef FP_EX_INVALID_VC +# define FP_EX_INVALID_VC 0 +#endif + /* _FP_STRUCT_LAYOUT may be defined as an attribute to determine the struct layout variant used for structures where bit-fields are used to access specific parts of binary floating-point numbers. This is