diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | soft-fp/double.h | 4 | ||||
-rw-r--r-- | soft-fp/extended.h | 4 | ||||
-rw-r--r-- | soft-fp/op-common.h | 212 | ||||
-rw-r--r-- | soft-fp/quad.h | 4 | ||||
-rw-r--r-- | soft-fp/single.h | 2 |
6 files changed, 240 insertions, 0 deletions
@@ -1,3 +1,17 @@ +2014-11-04 Joseph Myers <joseph@codesourcery.com> + + * soft-fp/op-common.h (_FP_TO_INT_ROUND): New macro. + * soft-fp/double.h [_FP_W_TYPE_SIZE < 64] (FP_TO_INT_ROUND_D): New + macro. + [_FP_W_TYPE_SIZE >= 64] (FP_TO_INT_ROUND_D): Likewise. + * soft-fp/extended.h [_FP_W_TYPE_SIZE < 64] (FP_TO_INT_ROUND_E): + New macro. + [_FP_W_TYPE_SIZE >= 64] (FP_TO_INT_ROUND_E): Likewise. + * soft-fp/quad.h [_FP_W_TYPE_SIZE < 64] (FP_TO_INT_ROUND_Q): New + macro. + [_FP_W_TYPE_SIZE >= 64] (FP_TO_INT_ROUND_Q): Likewise. + * soft-fp/single.h (FP_TO_INT_ROUND_S): New macro. + 2014-11-04 Andreas Schwab <schwab@suse.de> * posix/regex_internal.h: Don't include <locale/elem-hash.h>. diff --git a/soft-fp/double.h b/soft-fp/double.h index 36a11a5..96d2432 100644 --- a/soft-fp/double.h +++ b/soft-fp/double.h @@ -182,6 +182,8 @@ union _FP_UNION_D # define FP_CMP_UNORD_D(r, X, Y, ex) _FP_CMP_UNORD (D, 2, (r), X, Y, (ex)) # define FP_TO_INT_D(r, X, rsz, rsg) _FP_TO_INT (D, 2, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_D(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (D, 2, (r), X, (rsz), (rsg)) # define FP_FROM_INT_D(X, r, rs, rt) _FP_FROM_INT (D, 2, X, (r), (rs), rt) # define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_2 (X) @@ -304,6 +306,8 @@ union _FP_UNION_D # define FP_CMP_UNORD_D(r, X, Y, ex) _FP_CMP_UNORD (D, 1, (r), X, Y, (ex)) # define FP_TO_INT_D(r, X, rsz, rsg) _FP_TO_INT (D, 1, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_D(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (D, 1, (r), X, (rsz), (rsg)) # define FP_FROM_INT_D(X, r, rs, rt) _FP_FROM_INT (D, 1, X, (r), (rs), rt) # define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_1 (X) diff --git a/soft-fp/extended.h b/soft-fp/extended.h index d16fa66..117abfc 100644 --- a/soft-fp/extended.h +++ b/soft-fp/extended.h @@ -292,6 +292,8 @@ union _FP_UNION_E # define FP_CMP_UNORD_E(r, X, Y, ex) _FP_CMP_UNORD (E, 4, (r), X, Y, (ex)) # define FP_TO_INT_E(r, X, rsz, rsg) _FP_TO_INT (E, 4, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_E(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (E, 4, (r), X, (rsz), (rsg)) # define FP_FROM_INT_E(X, r, rs, rt) _FP_FROM_INT (E, 4, X, (r), (rs), rt) # define _FP_FRAC_HIGH_E(X) (X##_f[2]) @@ -494,6 +496,8 @@ union _FP_UNION_E # define FP_CMP_UNORD_E(r, X, Y, ex) _FP_CMP_UNORD (E, 2, (r), X, Y, (ex)) # define FP_TO_INT_E(r, X, rsz, rsg) _FP_TO_INT (E, 2, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_E(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (E, 2, (r), X, (rsz), (rsg)) # define FP_FROM_INT_E(X, r, rs, rt) _FP_FROM_INT (E, 2, X, (r), (rs), rt) # define _FP_FRAC_HIGH_E(X) (X##_f1) diff --git a/soft-fp/op-common.h b/soft-fp/op-common.h index 73fbe7a..67a7818 100644 --- a/soft-fp/op-common.h +++ b/soft-fp/op-common.h @@ -1525,6 +1525,218 @@ } \ while (0) +/* Convert from floating point to integer, rounding according to the + current rounding direction. Input is raw. RSIGNED is as for + _FP_TO_INT. */ +#define _FP_TO_INT_ROUND(fs, wc, r, X, rsize, rsigned) \ + do \ + { \ + if (X##_e < _FP_EXPBIAS_##fs) \ + { \ + int _FP_TO_INT_ROUND_rounds_away = 0; \ + if (X##_e == 0) \ + { \ + if (_FP_FRAC_ZEROP_##wc (X)) \ + { \ + (r) = 0; \ + goto _FP_TO_INT_ROUND_done; \ + } \ + else \ + { \ + FP_SET_EXCEPTION (FP_EX_DENORM); \ + if (FP_DENORM_ZERO) \ + { \ + (r) = 0; \ + goto _FP_TO_INT_ROUND_done; \ + } \ + } \ + } \ + /* The result is 0, 1 or -1 depending on the rounding mode; \ + -1 may cause overflow in the unsigned case. */ \ + switch (FP_ROUNDMODE) \ + { \ + case FP_RND_NEAREST: \ + _FP_TO_INT_ROUND_rounds_away \ + = (X##_e == _FP_EXPBIAS_##fs - 1 \ + && !_FP_FRAC_ZEROP_##wc (X)); \ + break; \ + case FP_RND_ZERO: \ + /* _FP_TO_INT_ROUND_rounds_away is already 0. */ \ + break; \ + case FP_RND_PINF: \ + _FP_TO_INT_ROUND_rounds_away = !X##_s; \ + break; \ + case FP_RND_MINF: \ + _FP_TO_INT_ROUND_rounds_away = X##_s; \ + break; \ + } \ + if ((rsigned) == 0 && _FP_TO_INT_ROUND_rounds_away && X##_s) \ + { \ + /* Result of -1 for an unsigned conversion. */ \ + (r) = 0; \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); \ + } \ + else if ((rsize) == 1 && (rsigned) > 0 \ + && _FP_TO_INT_ROUND_rounds_away && !X##_s) \ + { \ + /* Converting to a 1-bit signed bit-field, which cannot \ + represent +1. */ \ + (r) = ((rsigned) == 2 ? -1 : 0); \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); \ + } \ + else \ + { \ + (r) = (_FP_TO_INT_ROUND_rounds_away \ + ? (X##_s ? -1 : 1) \ + : 0); \ + FP_SET_EXCEPTION (FP_EX_INEXACT); \ + } \ + } \ + else if ((rsigned) == 2 \ + && (X##_e \ + >= ((_FP_EXPMAX_##fs \ + < _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + (rsize) - 1) \ + ? _FP_EXPMAX_##fs \ + : _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs + (rsize) - 1))) \ + { \ + /* Overflow resulting in 0. */ \ + (r) = 0; \ + 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 if ((rsigned) != 2 \ + && (X##_e >= (_FP_EXPMAX_##fs < _FP_EXPBIAS_##fs + (rsize) \ + ? _FP_EXPMAX_##fs \ + : (_FP_EXPBIAS_##fs + (rsize) \ + - ((rsigned) > 0 && !X##_s))) \ + || ((rsigned) == 0 && X##_s))) \ + { \ + /* Definite overflow (does not require rounding to tell). */ \ + if ((rsigned) != 0) \ + { \ + (r) = 1; \ + (r) <<= (rsize) - 1; \ + (r) -= 1 - X##_s; \ + } \ + else \ + { \ + (r) = 0; \ + if (!X##_s) \ + (r) = ~(r); \ + } \ + \ + 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 \ + { \ + /* The value is finite, with magnitude at least 1. If \ + the conversion is unsigned, the value is positive. \ + If RSIGNED is not 2, the value does not definitely \ + overflow by virtue of its exponent, but may still turn \ + out to overflow after rounding; if RSIGNED is 2, the \ + exponent may be such that the value definitely overflows, \ + but at least one mantissa bit will not be shifted out. */ \ + int _FP_TO_INT_ROUND_inexact = 0; \ + _FP_FRAC_HIGH_RAW_##fs (X) |= _FP_IMPLBIT_##fs; \ + if (X##_e >= _FP_EXPBIAS_##fs + _FP_FRACBITS_##fs - 1) \ + { \ + /* The value is an integer, no rounding needed. */ \ + _FP_FRAC_ASSEMBLE_##wc ((r), X, (rsize)); \ + (r) <<= X##_e - _FP_EXPBIAS_##fs - _FP_FRACBITS_##fs + 1; \ + } \ + else \ + { \ + /* May need to shift in order to round (unless there \ + are exactly _FP_WORKBITS fractional bits already). */ \ + int _FP_TO_INT_ROUND_rshift \ + = (_FP_FRACBITS_##fs + _FP_EXPBIAS_##fs \ + - 1 - _FP_WORKBITS - X##_e); \ + if (_FP_TO_INT_ROUND_rshift > 0) \ + _FP_FRAC_SRS_##wc (X, _FP_TO_INT_ROUND_rshift, \ + _FP_WFRACBITS_##fs); \ + else if (_FP_TO_INT_ROUND_rshift < 0) \ + _FP_FRAC_SLL_##wc (X, -_FP_TO_INT_ROUND_rshift); \ + /* Round like _FP_ROUND, but setting \ + _FP_TO_INT_ROUND_inexact instead of directly setting \ + the "inexact" exception, since it may turn out we \ + should set "invalid" instead. */ \ + if (_FP_FRAC_LOW_##wc (X) & 7) \ + { \ + _FP_TO_INT_ROUND_inexact = 1; \ + switch (FP_ROUNDMODE) \ + { \ + case FP_RND_NEAREST: \ + _FP_ROUND_NEAREST (wc, X); \ + break; \ + case FP_RND_ZERO: \ + _FP_ROUND_ZERO (wc, X); \ + break; \ + case FP_RND_PINF: \ + _FP_ROUND_PINF (wc, X); \ + break; \ + case FP_RND_MINF: \ + _FP_ROUND_MINF (wc, X); \ + break; \ + } \ + } \ + _FP_FRAC_SRL_##wc (X, _FP_WORKBITS); \ + _FP_FRAC_ASSEMBLE_##wc ((r), X, (rsize)); \ + } \ + if ((rsigned) != 0 && X##_s) \ + (r) = -(r); \ + /* An exponent of RSIZE - 1 always needs testing for \ + overflow (either directly overflowing, or overflowing \ + when rounding up results in 2^RSIZE). An exponent of \ + RSIZE - 2 can overflow for positive values when rounding \ + up to 2^(RSIZE-1), but cannot overflow for negative \ + values. Smaller exponents cannot overflow. */ \ + if (X##_e >= (_FP_EXPBIAS_##fs + (rsize) - 1 \ + - ((rsigned) > 0 && !X##_s))) \ + { \ + if (X##_e > _FP_EXPBIAS_##fs + (rsize) - 1 \ + || (X##_e == _FP_EXPBIAS_##fs + (rsize) - 1 \ + && (X##_s \ + ? (r) != (((typeof (r)) 1) << ((rsize) - 1)) \ + : ((rsigned) > 0 || (r) == 0))) \ + || ((rsigned) > 0 \ + && !X##_s \ + && X##_e == _FP_EXPBIAS_##fs + (rsize) - 2 \ + && (r) == (((typeof (r)) 1) << ((rsize) - 1)))) \ + { \ + if ((rsigned) != 2) \ + { \ + if ((rsigned) != 0) \ + { \ + (r) = 1; \ + (r) <<= (rsize) - 1; \ + (r) -= 1 - X##_s; \ + } \ + else \ + { \ + (r) = 0; \ + (r) = ~(r); \ + } \ + } \ + _FP_TO_INT_ROUND_inexact = 0; \ + FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); \ + } \ + } \ + if (_FP_TO_INT_ROUND_inexact) \ + FP_SET_EXCEPTION (FP_EX_INEXACT); \ + } \ + _FP_TO_INT_ROUND_done: ; \ + } \ + while (0) + /* Convert integer to fp. Output is raw. RTYPE is unsigned even if input is signed. */ #define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ diff --git a/soft-fp/quad.h b/soft-fp/quad.h index b8cd310..8b7f0a0 100644 --- a/soft-fp/quad.h +++ b/soft-fp/quad.h @@ -187,6 +187,8 @@ union _FP_UNION_Q # define FP_CMP_UNORD_Q(r, X, Y, ex) _FP_CMP_UNORD (Q, 4, (r), X, Y, (ex)) # define FP_TO_INT_Q(r, X, rsz, rsg) _FP_TO_INT (Q, 4, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_Q(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (Q, 4, (r), X, (rsz), (rsg)) # define FP_FROM_INT_Q(X, r, rs, rt) _FP_FROM_INT (Q, 4, X, (r), (rs), rt) # define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_4 (X) @@ -311,6 +313,8 @@ union _FP_UNION_Q # define FP_CMP_UNORD_Q(r, X, Y, ex) _FP_CMP_UNORD (Q, 2, (r), X, Y, (ex)) # define FP_TO_INT_Q(r, X, rsz, rsg) _FP_TO_INT (Q, 2, (r), X, (rsz), (rsg)) +# define FP_TO_INT_ROUND_Q(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (Q, 2, (r), X, (rsz), (rsg)) # define FP_FROM_INT_Q(X, r, rs, rt) _FP_FROM_INT (Q, 2, X, (r), (rs), rt) # define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_2 (X) diff --git a/soft-fp/single.h b/soft-fp/single.h index 086a558..83c0de6 100644 --- a/soft-fp/single.h +++ b/soft-fp/single.h @@ -180,6 +180,8 @@ union _FP_UNION_S #define FP_CMP_UNORD_S(r, X, Y, ex) _FP_CMP_UNORD (S, 1, (r), X, Y, (ex)) #define FP_TO_INT_S(r, X, rsz, rsg) _FP_TO_INT (S, 1, (r), X, (rsz), (rsg)) +#define FP_TO_INT_ROUND_S(r, X, rsz, rsg) \ + _FP_TO_INT_ROUND (S, 1, (r), X, (rsz), (rsg)) #define FP_FROM_INT_S(X, r, rs, rt) _FP_FROM_INT (S, 1, X, (r), (rs), rt) #define _FP_FRAC_HIGH_S(X) _FP_FRAC_HIGH_1 (X) |