summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--soft-fp/double.h4
-rw-r--r--soft-fp/extended.h4
-rw-r--r--soft-fp/op-common.h212
-rw-r--r--soft-fp/quad.h4
-rw-r--r--soft-fp/single.h2
6 files changed, 240 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index a6e6e65c91..380aa866c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 36a11a5452..96d2432aa2 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 d16fa66174..117abfc539 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 73fbe7af25..67a7818716 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 b8cd3108a3..8b7f0a04c5 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 086a558b9e..83c0de6c73 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)