diff options
Diffstat (limited to 'contrib/gcc/real.c')
-rw-r--r-- | contrib/gcc/real.c | 1526 |
1 files changed, 879 insertions, 647 deletions
diff --git a/contrib/gcc/real.c b/contrib/gcc/real.c index f775226..11927ee 100644 --- a/contrib/gcc/real.c +++ b/contrib/gcc/real.c @@ -1,8 +1,8 @@ /* real.c - software floating point emulation. - Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by Stephen L. Moshier (moshier@world.std.com). - Re-written by Richard Henderson <rth@redhat.com> + Re-written by Richard Henderson <rth@redhat.com> This file is part of GCC. @@ -23,13 +23,15 @@ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" #include "toplev.h" #include "real.h" #include "tm_p.h" /* The floating point model used internally is not exactly IEEE 754 - compliant, and close to the description in the ISO C standard, + compliant, and close to the description in the ISO C99 standard, section 5.2.4.2.2 Characteristics of floating types. Specifically @@ -47,21 +49,21 @@ significand is fractional. Normalized significands are in the range [0.5, 1.0). - A requirement of the model is that P be larger than than the - largest supported target floating-point type by at least 2 bits. - This gives us proper rounding when we truncate to the target type. - In addition, E must be large enough to hold the smallest supported - denormal number in a normalized form. + A requirement of the model is that P be larger than the largest + supported target floating-point type by at least 2 bits. This gives + us proper rounding when we truncate to the target type. In addition, + E must be large enough to hold the smallest supported denormal number + in a normalized form. Both of these requirements are easily satisfied. The largest target significand is 113 bits; we store at least 160. The smallest - denormal number fits in 17 exponent bits; we store 29. + denormal number fits in 17 exponent bits; we store 27. - Note that the decimal string conversion routines are sensitive to - rounding error. Since the raw arithmetic routines do not themselves + Note that the decimal string conversion routines are sensitive to + rounding errors. Since the raw arithmetic routines do not themselves have guard digits or rounding, the computation of 10**exp can accumulate more than a few digits of error. The previous incarnation - of real.c successfully used a 144 bit fraction; given the current + of real.c successfully used a 144-bit fraction; given the current layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits. Target floating point models that use base 16 instead of base 2 @@ -77,70 +79,54 @@ #error "Some constant folding done by hand to avoid shift count warnings" #endif -static void get_zero PARAMS ((REAL_VALUE_TYPE *, int)); -static void get_canonical_qnan PARAMS ((REAL_VALUE_TYPE *, int)); -static void get_canonical_snan PARAMS ((REAL_VALUE_TYPE *, int)); -static void get_inf PARAMS ((REAL_VALUE_TYPE *, int)); -static bool sticky_rshift_significand PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - unsigned int)); -static void rshift_significand PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - unsigned int)); -static void lshift_significand PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - unsigned int)); -static void lshift_significand_1 PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static bool add_significands PARAMS ((REAL_VALUE_TYPE *r, - const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static bool sub_significands PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, int)); -static void neg_significand PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static int cmp_significands PARAMS ((const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static int cmp_significand_0 PARAMS ((const REAL_VALUE_TYPE *)); -static void set_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int)); -static void clear_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int)); -static bool test_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int)); -static void clear_significand_below PARAMS ((REAL_VALUE_TYPE *, - unsigned int)); -static bool div_significands PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static void normalize PARAMS ((REAL_VALUE_TYPE *)); - -static void do_add PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, int)); -static void do_multiply PARAMS ((REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static void do_divide PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *)); -static int do_compare PARAMS ((const REAL_VALUE_TYPE *, - const REAL_VALUE_TYPE *, int)); -static void do_fix_trunc PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *)); - -static unsigned long rtd_divmod PARAMS ((REAL_VALUE_TYPE *, - REAL_VALUE_TYPE *)); - -static const REAL_VALUE_TYPE * ten_to_ptwo PARAMS ((int)); -static const REAL_VALUE_TYPE * ten_to_mptwo PARAMS ((int)); -static const REAL_VALUE_TYPE * real_digit PARAMS ((int)); -static void times_pten PARAMS ((REAL_VALUE_TYPE *, int)); - -static void round_for_format PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *)); +static void get_zero (REAL_VALUE_TYPE *, int); +static void get_canonical_qnan (REAL_VALUE_TYPE *, int); +static void get_canonical_snan (REAL_VALUE_TYPE *, int); +static void get_inf (REAL_VALUE_TYPE *, int); +static bool sticky_rshift_significand (REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *, unsigned int); +static void rshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + unsigned int); +static void lshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + unsigned int); +static void lshift_significand_1 (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); +static bool add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *); +static bool sub_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *, int); +static void neg_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); +static int cmp_significands (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); +static int cmp_significand_0 (const REAL_VALUE_TYPE *); +static void set_significand_bit (REAL_VALUE_TYPE *, unsigned int); +static void clear_significand_bit (REAL_VALUE_TYPE *, unsigned int); +static bool test_significand_bit (REAL_VALUE_TYPE *, unsigned int); +static void clear_significand_below (REAL_VALUE_TYPE *, unsigned int); +static bool div_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *); +static void normalize (REAL_VALUE_TYPE *); + +static bool do_add (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *, int); +static bool do_multiply (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *); +static bool do_divide (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *); +static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); +static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); + +static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *); + +static const REAL_VALUE_TYPE * ten_to_ptwo (int); +static const REAL_VALUE_TYPE * ten_to_mptwo (int); +static const REAL_VALUE_TYPE * real_digit (int); +static void times_pten (REAL_VALUE_TYPE *, int); + +static void round_for_format (const struct real_format *, REAL_VALUE_TYPE *); /* Initialize R with a positive zero. */ static inline void -get_zero (r, sign) - REAL_VALUE_TYPE *r; - int sign; +get_zero (REAL_VALUE_TYPE *r, int sign) { memset (r, 0, sizeof (*r)); r->sign = sign; @@ -149,31 +135,26 @@ get_zero (r, sign) /* Initialize R with the canonical quiet NaN. */ static inline void -get_canonical_qnan (r, sign) - REAL_VALUE_TYPE *r; - int sign; +get_canonical_qnan (REAL_VALUE_TYPE *r, int sign) { memset (r, 0, sizeof (*r)); r->class = rvc_nan; r->sign = sign; - r->sig[SIGSZ-1] = SIG_MSB >> 1; + r->canonical = 1; } static inline void -get_canonical_snan (r, sign) - REAL_VALUE_TYPE *r; - int sign; +get_canonical_snan (REAL_VALUE_TYPE *r, int sign) { memset (r, 0, sizeof (*r)); r->class = rvc_nan; r->sign = sign; - r->sig[SIGSZ-1] = SIG_MSB >> 2; + r->signalling = 1; + r->canonical = 1; } static inline void -get_inf (r, sign) - REAL_VALUE_TYPE *r; - int sign; +get_inf (REAL_VALUE_TYPE *r, int sign) { memset (r, 0, sizeof (*r)); r->class = rvc_inf; @@ -185,10 +166,8 @@ get_inf (r, sign) significand of R. If any one bits are shifted out, return true. */ static bool -sticky_rshift_significand (r, a, n) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; - unsigned int n; +sticky_rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) { unsigned long sticky = 0; unsigned int i, ofs = 0; @@ -226,10 +205,8 @@ sticky_rshift_significand (r, a, n) significand of R. */ static void -rshift_significand (r, a, n) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; - unsigned int n; +rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) { unsigned int i, ofs = n / HOST_BITS_PER_LONG; @@ -257,10 +234,8 @@ rshift_significand (r, a, n) significand of R. */ static void -lshift_significand (r, a, n) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; - unsigned int n; +lshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) { unsigned int i, ofs = n / HOST_BITS_PER_LONG; @@ -285,9 +260,7 @@ lshift_significand (r, a, n) /* Likewise, but N is specialized to 1. */ static inline void -lshift_significand_1 (r, a) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; +lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) { unsigned int i; @@ -300,9 +273,8 @@ lshift_significand_1 (r, a) true if there was carry out of the most significant word. */ static inline bool -add_significands (r, a, b) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; +add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b) { bool carry = false; int i; @@ -331,10 +303,8 @@ add_significands (r, a, b) Return true if there was borrow out of the most significant word. */ static inline bool -sub_significands (r, a, b, carry) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; - int carry; +sub_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b, int carry) { int i; @@ -355,14 +325,12 @@ sub_significands (r, a, b, carry) } return carry; -} +} /* Negate the significand A, placing the result in R. */ static inline void -neg_significand (r, a) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; +neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) { bool carry = true; int i; @@ -386,13 +354,12 @@ neg_significand (r, a) r->sig[i] = ri; } -} +} /* Compare significands. Return tri-state vs zero. */ -static inline int -cmp_significands (a, b) - const REAL_VALUE_TYPE *a, *b; +static inline int +cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b) { int i; @@ -412,9 +379,8 @@ cmp_significands (a, b) /* Return true if A is nonzero. */ -static inline int -cmp_significand_0 (a) - const REAL_VALUE_TYPE *a; +static inline int +cmp_significand_0 (const REAL_VALUE_TYPE *a) { int i; @@ -428,9 +394,7 @@ cmp_significand_0 (a) /* Set bit N of the significand of R. */ static inline void -set_significand_bit (r, n) - REAL_VALUE_TYPE *r; - unsigned int n; +set_significand_bit (REAL_VALUE_TYPE *r, unsigned int n) { r->sig[n / HOST_BITS_PER_LONG] |= (unsigned long)1 << (n % HOST_BITS_PER_LONG); @@ -439,9 +403,7 @@ set_significand_bit (r, n) /* Clear bit N of the significand of R. */ static inline void -clear_significand_bit (r, n) - REAL_VALUE_TYPE *r; - unsigned int n; +clear_significand_bit (REAL_VALUE_TYPE *r, unsigned int n) { r->sig[n / HOST_BITS_PER_LONG] &= ~((unsigned long)1 << (n % HOST_BITS_PER_LONG)); @@ -450,9 +412,7 @@ clear_significand_bit (r, n) /* Test bit N of the significand of R. */ static inline bool -test_significand_bit (r, n) - REAL_VALUE_TYPE *r; - unsigned int n; +test_significand_bit (REAL_VALUE_TYPE *r, unsigned int n) { /* ??? Compiler bug here if we return this expression directly. The conversion to bool strips the "&1" and we wind up testing @@ -464,9 +424,7 @@ test_significand_bit (r, n) /* Clear bits 0..N-1 of the significand of R. */ static void -clear_significand_below (r, n) - REAL_VALUE_TYPE *r; - unsigned int n; +clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n) { int i, w = n / HOST_BITS_PER_LONG; @@ -480,9 +438,8 @@ clear_significand_below (r, n) true if the division was inexact. */ static inline bool -div_significands (r, a, b) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; +div_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b) { REAL_VALUE_TYPE u; int i, bit = SIGNIFICAND_BITS - 1; @@ -518,8 +475,7 @@ div_significands (r, a, b) exponent is large enough to handle target denormals normalized.) */ static void -normalize (r) - REAL_VALUE_TYPE *r; +normalize (REAL_VALUE_TYPE *r) { int shift = 0, exp; int i, j; @@ -560,13 +516,12 @@ normalize (r) } } -/* Return R = A + (SUBTRACT_P ? -B : B). */ +/* Calculate R = A + (SUBTRACT_P ? -B : B). Return true if the + result may be inexact due to a loss of precision. */ -static void -do_add (r, a, b, subtract_p) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; - int subtract_p; +static bool +do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b, int subtract_p) { int dexp, sign, exp; REAL_VALUE_TYPE t; @@ -581,7 +536,7 @@ do_add (r, a, b, subtract_p) case CLASS2 (rvc_zero, rvc_zero): /* -0 + -0 = -0, -0 - +0 = -0; all other cases yield +0. */ get_zero (r, sign & !subtract_p); - return; + return false; case CLASS2 (rvc_zero, rvc_normal): case CLASS2 (rvc_zero, rvc_inf): @@ -595,7 +550,7 @@ do_add (r, a, b, subtract_p) /* R + Inf = Inf. */ *r = *b; r->sign = sign ^ subtract_p; - return; + return false; case CLASS2 (rvc_normal, rvc_zero): case CLASS2 (rvc_inf, rvc_zero): @@ -607,7 +562,7 @@ do_add (r, a, b, subtract_p) case CLASS2 (rvc_inf, rvc_normal): /* Inf + R = Inf. */ *r = *a; - return; + return false; case CLASS2 (rvc_inf, rvc_inf): if (subtract_p) @@ -616,7 +571,7 @@ do_add (r, a, b, subtract_p) else /* Inf + Inf = Inf. */ *r = *a; - return; + return false; case CLASS2 (rvc_normal, rvc_normal): break; @@ -646,7 +601,7 @@ do_add (r, a, b, subtract_p) { *r = *a; r->sign = sign; - return; + return true; } inexact |= sticky_rshift_significand (&t, b, dexp); @@ -677,7 +632,7 @@ do_add (r, a, b, subtract_p) if (++exp > MAX_EXP) { get_inf (r, sign); - return; + return true; } } } @@ -695,18 +650,20 @@ do_add (r, a, b, subtract_p) r->sign = 0; else r->sig[0] |= inexact; + + return inexact; } -/* Return R = A * B. */ +/* Calculate R = A * B. Return true if the result may be inexact. */ -static void -do_multiply (r, a, b) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; +static bool +do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b) { REAL_VALUE_TYPE u, t, *rr; unsigned int i, j, k; int sign = a->sign ^ b->sign; + bool inexact = false; switch (CLASS2 (a->class, b->class)) { @@ -715,7 +672,7 @@ do_multiply (r, a, b) case CLASS2 (rvc_normal, rvc_zero): /* +-0 * ANY = 0 with appropriate sign. */ get_zero (r, sign); - return; + return false; case CLASS2 (rvc_zero, rvc_nan): case CLASS2 (rvc_normal, rvc_nan): @@ -724,7 +681,7 @@ do_multiply (r, a, b) /* ANY * NaN = NaN. */ *r = *b; r->sign = sign; - return; + return false; case CLASS2 (rvc_nan, rvc_zero): case CLASS2 (rvc_nan, rvc_normal): @@ -732,21 +689,20 @@ do_multiply (r, a, b) /* NaN * ANY = NaN. */ *r = *a; r->sign = sign; - return; + return false; case CLASS2 (rvc_zero, rvc_inf): case CLASS2 (rvc_inf, rvc_zero): /* 0 * Inf = NaN */ get_canonical_qnan (r, sign); - return; + return false; case CLASS2 (rvc_inf, rvc_inf): case CLASS2 (rvc_normal, rvc_inf): case CLASS2 (rvc_inf, rvc_normal): /* Inf * Inf = Inf, R * Inf = Inf */ - overflow: get_inf (r, sign); - return; + return false; case CLASS2 (rvc_normal, rvc_normal): break; @@ -796,13 +752,19 @@ do_multiply (r, a, b) + (b->exp - (1-j)*(HOST_BITS_PER_LONG/2))); if (exp > MAX_EXP) - goto overflow; + { + get_inf (r, sign); + return true; + } if (exp < -MAX_EXP) - /* Would underflow to zero, which we shouldn't bother adding. */ - continue; + { + /* Would underflow to zero, which we shouldn't bother adding. */ + inexact = true; + continue; + } + memset (&u, 0, sizeof (u)); u.class = rvc_normal; - u.sign = 0; u.exp = exp; for (k = j; k < SIGSZ * 2; k += 2) @@ -817,21 +779,22 @@ do_multiply (r, a, b) } normalize (&u); - do_add (rr, rr, &u, 0); + inexact |= do_add (rr, rr, &u, 0); } } rr->sign = sign; if (rr != r) *r = t; + + return inexact; } -/* Return R = A / B. */ +/* Calculate R = A / B. Return true if the result may be inexact. */ -static void -do_divide (r, a, b) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a, *b; +static bool +do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b) { int exp, sign = a->sign ^ b->sign; REAL_VALUE_TYPE t, *rr; @@ -844,23 +807,22 @@ do_divide (r, a, b) case CLASS2 (rvc_inf, rvc_inf): /* Inf / Inf = NaN. */ get_canonical_qnan (r, sign); - return; + return false; case CLASS2 (rvc_zero, rvc_normal): case CLASS2 (rvc_zero, rvc_inf): /* 0 / ANY = 0. */ case CLASS2 (rvc_normal, rvc_inf): /* R / Inf = 0. */ - underflow: get_zero (r, sign); - return; + return false; case CLASS2 (rvc_normal, rvc_zero): /* R / 0 = Inf. */ case CLASS2 (rvc_inf, rvc_zero): /* Inf / 0 = Inf. */ get_inf (r, sign); - return; + return false; case CLASS2 (rvc_zero, rvc_nan): case CLASS2 (rvc_normal, rvc_nan): @@ -869,7 +831,7 @@ do_divide (r, a, b) /* ANY / NaN = NaN. */ *r = *b; r->sign = sign; - return; + return false; case CLASS2 (rvc_nan, rvc_zero): case CLASS2 (rvc_nan, rvc_normal): @@ -877,13 +839,12 @@ do_divide (r, a, b) /* NaN / ANY = NaN. */ *r = *a; r->sign = sign; - return; + return false; case CLASS2 (rvc_inf, rvc_normal): /* Inf / R = Inf. */ - overflow: get_inf (r, sign); - return; + return false; case CLASS2 (rvc_normal, rvc_normal): break; @@ -897,14 +858,22 @@ do_divide (r, a, b) else rr = r; + /* Make sure all fields in the result are initialized. */ + get_zero (rr, 0); rr->class = rvc_normal; rr->sign = sign; exp = a->exp - b->exp + 1; if (exp > MAX_EXP) - goto overflow; + { + get_inf (r, sign); + return true; + } if (exp < -MAX_EXP) - goto underflow; + { + get_zero (r, sign); + return true; + } rr->exp = exp; inexact = div_significands (rr, a, b); @@ -915,15 +884,16 @@ do_divide (r, a, b) if (rr != r) *r = t; + + return inexact; } /* Return a tri-state comparison of A vs B. Return NAN_RESULT if one of the two operands is a NaN. */ static int -do_compare (a, b, nan_result) - const REAL_VALUE_TYPE *a, *b; - int nan_result; +do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b, + int nan_result) { int ret; @@ -978,9 +948,7 @@ do_compare (a, b, nan_result) /* Return A truncated to an integral value toward zero. */ static void -do_fix_trunc (r, a) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *a; +do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) { *r = *a; @@ -1007,10 +975,8 @@ do_fix_trunc (r, a) For a unary operation, leave OP1 NULL. */ void -real_arithmetic (r, icode, op0, op1) - REAL_VALUE_TYPE *r; - int icode; - const REAL_VALUE_TYPE *op0, *op1; +real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) { enum tree_code code = icode; @@ -1072,9 +1038,8 @@ real_arithmetic (r, icode, op0, op1) /* Legacy. Similar, but return the result directly. */ REAL_VALUE_TYPE -real_arithmetic2 (icode, op0, op1) - int icode; - const REAL_VALUE_TYPE *op0, *op1; +real_arithmetic2 (int icode, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) { REAL_VALUE_TYPE r; real_arithmetic (&r, icode, op0, op1); @@ -1082,9 +1047,8 @@ real_arithmetic2 (icode, op0, op1) } bool -real_compare (icode, op0, op1) - int icode; - const REAL_VALUE_TYPE *op0, *op1; +real_compare (int icode, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) { enum tree_code code = icode; @@ -1125,8 +1089,7 @@ real_compare (icode, op0, op1) /* Return floor log2(R). */ int -real_exponent (r) - const REAL_VALUE_TYPE *r; +real_exponent (const REAL_VALUE_TYPE *r) { switch (r->class) { @@ -1145,10 +1108,7 @@ real_exponent (r) /* R = OP0 * 2**EXP. */ void -real_ldexp (r, op0, exp) - REAL_VALUE_TYPE *r; - const REAL_VALUE_TYPE *op0; - int exp; +real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp) { *r = *op0; switch (r->class) @@ -1176,8 +1136,7 @@ real_ldexp (r, op0, exp) /* Determine whether a floating-point value X is infinite. */ bool -real_isinf (r) - const REAL_VALUE_TYPE *r; +real_isinf (const REAL_VALUE_TYPE *r) { return (r->class == rvc_inf); } @@ -1185,8 +1144,7 @@ real_isinf (r) /* Determine whether a floating-point value X is a NaN. */ bool -real_isnan (r) - const REAL_VALUE_TYPE *r; +real_isnan (const REAL_VALUE_TYPE *r) { return (r->class == rvc_nan); } @@ -1194,8 +1152,7 @@ real_isnan (r) /* Determine whether a floating-point value X is negative. */ bool -real_isneg (r) - const REAL_VALUE_TYPE *r; +real_isneg (const REAL_VALUE_TYPE *r) { return r->sign; } @@ -1203,17 +1160,15 @@ real_isneg (r) /* Determine whether a floating-point value X is minus zero. */ bool -real_isnegzero (r) - const REAL_VALUE_TYPE *r; +real_isnegzero (const REAL_VALUE_TYPE *r) { return r->sign && r->class == rvc_zero; } /* Compare two floating-point objects for bitwise identity. */ -extern bool -real_identical (a, b) - const REAL_VALUE_TYPE *a, *b; +bool +real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b) { int i; @@ -1226,22 +1181,29 @@ real_identical (a, b) { case rvc_zero: case rvc_inf: - break; + return true; case rvc_normal: if (a->exp != b->exp) - return false; - /* FALLTHRU */ + return false; + break; + case rvc_nan: - for (i = 0; i < SIGSZ; ++i) - if (a->sig[i] != b->sig[i]) - return false; + if (a->signalling != b->signalling) + return false; + /* The significand is ignored for canonical NaNs. */ + if (a->canonical || b->canonical) + return a->canonical == b->canonical; break; default: abort (); } + for (i = 0; i < SIGSZ; ++i) + if (a->sig[i] != b->sig[i]) + return false; + return true; } @@ -1249,14 +1211,12 @@ real_identical (a, b) mode MODE. Return true if successful. */ bool -exact_real_inverse (mode, r) - enum machine_mode mode; - REAL_VALUE_TYPE *r; +exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r) { const REAL_VALUE_TYPE *one = real_digit (1); REAL_VALUE_TYPE u; int i; - + if (r->class != rvc_normal) return false; @@ -1270,7 +1230,7 @@ exact_real_inverse (mode, r) /* Find the inverse and truncate to the required mode. */ do_divide (&u, one, r); real_convert (&u, mode, &u); - + /* The rounding may have overflowed. */ if (u.class != rvc_normal) return false; @@ -1287,8 +1247,7 @@ exact_real_inverse (mode, r) /* Render R as an integer. */ HOST_WIDE_INT -real_to_integer (r) - const REAL_VALUE_TYPE *r; +real_to_integer (const REAL_VALUE_TYPE *r) { unsigned HOST_WIDE_INT i; @@ -1309,6 +1268,10 @@ real_to_integer (r) case rvc_normal: if (r->exp <= 0) goto underflow; + /* Only force overflow for unsigned overflow. Signed overflow is + undefined, so it doesn't matter what we return, and some callers + expect to be able to use this routine for both signed and + unsigned conversions. */ if (r->exp > HOST_BITS_PER_WIDE_INT) goto overflow; @@ -1337,9 +1300,8 @@ real_to_integer (r) /* Likewise, but to an integer pair, HI+LOW. */ void -real_to_integer2 (plow, phigh, r) - HOST_WIDE_INT *plow, *phigh; - const REAL_VALUE_TYPE *r; +real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh, + const REAL_VALUE_TYPE *r) { REAL_VALUE_TYPE t; HOST_WIDE_INT low, high; @@ -1369,6 +1331,10 @@ real_to_integer2 (plow, phigh, r) exp = r->exp; if (exp <= 0) goto underflow; + /* Only force overflow for unsigned overflow. Signed overflow is + undefined, so it doesn't matter what we return, and some callers + expect to be able to use this routine for both signed and + unsigned conversions. */ if (exp > 2*HOST_BITS_PER_WIDE_INT) goto overflow; @@ -1414,8 +1380,7 @@ real_to_integer2 (plow, phigh, r) small. */ static unsigned long -rtd_divmod (num, den) - REAL_VALUE_TYPE *num, *den; +rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den) { unsigned long q, msb; int expn = num->exp, expd = den->exp; @@ -1453,11 +1418,8 @@ rtd_divmod (num, den) #define M_LOG10_2 0.30102999566398119521 void -real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros) - char *str; - const REAL_VALUE_TYPE *r_orig; - size_t buf_size, digits; - int crop_trailing_zeros; +real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size, + size_t digits, int crop_trailing_zeros) { const REAL_VALUE_TYPE *one, *ten; REAL_VALUE_TYPE r, pten, u, v; @@ -1529,7 +1491,7 @@ real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros) /* Iterate over the bits of the possible powers of 10 that might be present in U and eliminate them. That is, if we find that - 10**2**M divides U evenly, keep the division and increase + 10**2**M divides U evenly, keep the division and increase DEC_EXP by 2**M. */ do { @@ -1550,7 +1512,7 @@ real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros) r = u; /* Find power of 10. Do this by dividing out 10**2**M when - this is larger than the current remainder. Fill PTEN with + this is larger than the current remainder. Fill PTEN with the power of 10 that we compute. */ if (r.exp > 0) { @@ -1705,7 +1667,7 @@ real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros) dec_exp++; } } - + /* Insert the decimal point. */ first[0] = first[1]; first[1] = '.'; @@ -1725,11 +1687,8 @@ real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros) strip trailing zeros. */ void -real_to_hexadecimal (str, r, buf_size, digits, crop_trailing_zeros) - char *str; - const REAL_VALUE_TYPE *r; - size_t buf_size, digits; - int crop_trailing_zeros; +real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size, + size_t digits, int crop_trailing_zeros) { int i, j, exp = r->exp; char *p, *first; @@ -1795,9 +1754,7 @@ real_to_hexadecimal (str, r, buf_size, digits, crop_trailing_zeros) assumed to have been syntax checked already. */ void -real_from_string (r, str) - REAL_VALUE_TYPE *r; - const char *str; +real_from_string (REAL_VALUE_TYPE *r, const char *str) { int exp = 0; bool sign = false; @@ -1812,7 +1769,7 @@ real_from_string (r, str) else if (*str == '+') str++; - if (str[0] == '0' && str[1] == 'x') + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { /* Hexadecimal floating point. */ int pos = SIGNIFICAND_BITS - 4, d; @@ -1981,9 +1938,7 @@ real_from_string (r, str) /* Legacy. Similar, but return the result directly. */ REAL_VALUE_TYPE -real_from_string2 (s, mode) - const char *s; - enum machine_mode mode; +real_from_string2 (const char *s, enum machine_mode mode) { REAL_VALUE_TYPE r; @@ -1997,12 +1952,9 @@ real_from_string2 (s, mode) /* Initialize R from the integer pair HIGH+LOW. */ void -real_from_integer (r, mode, low, high, unsigned_p) - REAL_VALUE_TYPE *r; - enum machine_mode mode; - unsigned HOST_WIDE_INT low; - HOST_WIDE_INT high; - int unsigned_p; +real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode, + unsigned HOST_WIDE_INT low, HOST_WIDE_INT high, + int unsigned_p) { if (low == 0 && high == 0) get_zero (r, 0); @@ -2049,8 +2001,7 @@ real_from_integer (r, mode, low, high, unsigned_p) /* Returns 10**2**N. */ static const REAL_VALUE_TYPE * -ten_to_ptwo (n) - int n; +ten_to_ptwo (int n) { static REAL_VALUE_TYPE tens[EXP_BITS]; @@ -2082,8 +2033,7 @@ ten_to_ptwo (n) /* Returns 10**(-2**N). */ static const REAL_VALUE_TYPE * -ten_to_mptwo (n) - int n; +ten_to_mptwo (int n) { static REAL_VALUE_TYPE tens[EXP_BITS]; @@ -2099,8 +2049,7 @@ ten_to_mptwo (n) /* Returns N. */ static const REAL_VALUE_TYPE * -real_digit (n) - int n; +real_digit (int n) { static REAL_VALUE_TYPE num[10]; @@ -2116,9 +2065,7 @@ real_digit (n) /* Multiply R by 10**EXP. */ static void -times_pten (r, exp) - REAL_VALUE_TYPE *r; - int exp; +times_pten (REAL_VALUE_TYPE *r, int exp) { REAL_VALUE_TYPE pten, *rr; bool negative = (exp < 0); @@ -2144,8 +2091,7 @@ times_pten (r, exp) /* Fills R with +Inf. */ void -real_inf (r) - REAL_VALUE_TYPE *r; +real_inf (REAL_VALUE_TYPE *r) { get_inf (r, 0); } @@ -2156,15 +2102,12 @@ real_inf (r) if the string was successfully parsed. */ bool -real_nan (r, str, quiet, mode) - REAL_VALUE_TYPE *r; - const char *str; - int quiet; - enum machine_mode mode; +real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet, + enum machine_mode mode) { const struct real_format *fmt; - fmt = real_format_for_mode[mode - QFmode]; + fmt = REAL_MODE_FORMAT (mode); if (fmt == NULL) abort (); @@ -2233,40 +2176,46 @@ real_nan (r, str, quiet, mode) /* Shift the significand into place such that the bits are in the most significant bits for the format. */ - lshift_significand (r, r, SIGNIFICAND_BITS - fmt->p); + lshift_significand (r, r, SIGNIFICAND_BITS - fmt->pnan); /* Our MSB is always unset for NaNs. */ r->sig[SIGSZ-1] &= ~SIG_MSB; /* Force quiet or signalling NaN. */ - if (quiet) - r->sig[SIGSZ-1] |= SIG_MSB >> 1; - else - r->sig[SIGSZ-1] &= ~(SIG_MSB >> 1); - - /* Force at least one bit of the significand set. */ - for (d = 0; d < SIGSZ; ++d) - if (r->sig[d]) - break; - if (d == SIGSZ) - r->sig[SIGSZ-1] |= SIG_MSB >> 2; - - /* Our intermediate format forces QNaNs to have MSB-1 set. - If the target format has QNaNs with the top bit unset, - mirror the output routines and invert the top two bits. */ - if (!fmt->qnan_msb_set) - r->sig[SIGSZ-1] ^= (SIG_MSB >> 1) | (SIG_MSB >> 2); + r->signalling = !quiet; } return true; } +/* Fills R with the largest finite value representable in mode MODE. + If SIGN is nonzero, R is set to the most negative finite value. */ + +void +real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode) +{ + const struct real_format *fmt; + int np2; + + fmt = REAL_MODE_FORMAT (mode); + if (fmt == NULL) + abort (); + + r->class = rvc_normal; + r->sign = sign; + r->signalling = 0; + r->canonical = 0; + r->exp = fmt->emax * fmt->log2_b; + + np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b; + memset (r->sig, -1, SIGSZ * sizeof (unsigned long)); + clear_significand_below (r, np2); +} + /* Fills R with 2**N. */ void -real_2expN (r, n) - REAL_VALUE_TYPE *r; - int n; +real_2expN (REAL_VALUE_TYPE *r, int n) { memset (r, 0, sizeof (*r)); @@ -2285,9 +2234,7 @@ real_2expN (r, n) static void -round_for_format (fmt, r) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; +round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) { int p2, np2, i, w; unsigned long sticky; @@ -2315,14 +2262,6 @@ round_for_format (fmt, r) case rvc_nan: clear_significand_below (r, np2); - - /* If we've cleared the entire significand, we need one bit - set for this to continue to be a NaN. */ - for (i = 0; i < SIGSZ; ++i) - if (r->sig[i]) - break; - if (i == SIGSZ) - r->sig[SIGSZ-1] = SIG_MSB >> 2; return; case rvc_normal: @@ -2426,14 +2365,12 @@ round_for_format (fmt, r) /* Extend or truncate to a new mode. */ void -real_convert (r, mode, a) - REAL_VALUE_TYPE *r; - enum machine_mode mode; - const REAL_VALUE_TYPE *a; +real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *a) { const struct real_format *fmt; - fmt = real_format_for_mode[mode - QFmode]; + fmt = REAL_MODE_FORMAT (mode); if (fmt == NULL) abort (); @@ -2448,9 +2385,7 @@ real_convert (r, mode, a) /* Legacy. Likewise, except return the struct directly. */ REAL_VALUE_TYPE -real_value_truncate (mode, a) - enum machine_mode mode; - REAL_VALUE_TYPE a; +real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a) { REAL_VALUE_TYPE r; real_convert (&r, mode, &a); @@ -2460,9 +2395,7 @@ real_value_truncate (mode, a) /* Return true if truncating to MODE is exact. */ bool -exact_real_truncate (mode, a) - enum machine_mode mode; - const REAL_VALUE_TYPE *a; +exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a) { REAL_VALUE_TYPE t; real_convert (&t, mode, a); @@ -2476,10 +2409,8 @@ exact_real_truncate (mode, a) Legacy: return word 0 for implementing REAL_VALUE_TO_TARGET_SINGLE. */ long -real_to_target_fmt (buf, r_orig, fmt) - long *buf; - const REAL_VALUE_TYPE *r_orig; - const struct real_format *fmt; +real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig, + const struct real_format *fmt) { REAL_VALUE_TYPE r; long buf1; @@ -2497,14 +2428,11 @@ real_to_target_fmt (buf, r_orig, fmt) /* Similar, but look up the format from MODE. */ long -real_to_target (buf, r, mode) - long *buf; - const REAL_VALUE_TYPE *r; - enum machine_mode mode; +real_to_target (long *buf, const REAL_VALUE_TYPE *r, enum machine_mode mode) { const struct real_format *fmt; - fmt = real_format_for_mode[mode - QFmode]; + fmt = REAL_MODE_FORMAT (mode); if (fmt == NULL) abort (); @@ -2516,41 +2444,35 @@ real_to_target (buf, r, mode) long, no matter the size of the host long. */ void -real_from_target_fmt (r, buf, fmt) - REAL_VALUE_TYPE *r; - const long *buf; - const struct real_format *fmt; +real_from_target_fmt (REAL_VALUE_TYPE *r, const long *buf, + const struct real_format *fmt) { (*fmt->decode) (fmt, r, buf); -} +} /* Similar, but look up the format from MODE. */ void -real_from_target (r, buf, mode) - REAL_VALUE_TYPE *r; - const long *buf; - enum machine_mode mode; +real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode) { const struct real_format *fmt; - fmt = real_format_for_mode[mode - QFmode]; + fmt = REAL_MODE_FORMAT (mode); if (fmt == NULL) abort (); (*fmt->decode) (fmt, r, buf); -} +} /* Return the number of bits in the significand for MODE. */ /* ??? Legacy. Should get access to real_format directly. */ int -significand_size (mode) - enum machine_mode mode; +significand_size (enum machine_mode mode) { const struct real_format *fmt; - fmt = real_format_for_mode[mode - QFmode]; + fmt = REAL_MODE_FORMAT (mode); if (fmt == NULL) return 0; @@ -2562,8 +2484,7 @@ significand_size (mode) but I didn't want to pull hashtab.h into real.h. */ unsigned int -real_hash (r) - const REAL_VALUE_TYPE *r; +real_hash (const REAL_VALUE_TYPE *r) { unsigned int h; size_t i; @@ -2573,43 +2494,46 @@ real_hash (r) { case rvc_zero: case rvc_inf: - break; + return h; case rvc_normal: h |= r->exp << 3; - /* FALLTHRU */ + break; case rvc_nan: - if (sizeof(unsigned long) > sizeof(unsigned int)) - for (i = 0; i < SIGSZ; ++i) - { - unsigned long s = r->sig[i]; - h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2)); - } - else - for (i = 0; i < SIGSZ; ++i) - h ^= r->sig[i]; + if (r->signalling) + h ^= (unsigned int)-1; + if (r->canonical) + return h; break; default: abort (); } + if (sizeof(unsigned long) > sizeof(unsigned int)) + for (i = 0; i < SIGSZ; ++i) + { + unsigned long s = r->sig[i]; + h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2)); + } + else + for (i = 0; i < SIGSZ; ++i) + h ^= r->sig[i]; + return h; } /* IEEE single-precision format. */ -static void encode_ieee_single PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_ieee_single PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_ieee_single (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_ieee_single (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_ieee_single (fmt, buf, r) - const struct real_format *fmt; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ieee_single (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image, sig, exp; unsigned long sign = r->sign; @@ -2633,10 +2557,23 @@ encode_ieee_single (fmt, buf, r) case rvc_nan: if (fmt->has_nans) { + if (r->canonical) + sig = 0; + if (r->signalling == fmt->qnan_msb_set) + sig &= ~(1 << 22); + else + sig |= 1 << 22; + /* We overload qnan_msb_set here: it's only clear for + mips_ieee_single, which wants all mantissa bits but the + quiet/signalling one set in canonical NaNs (at least + Quiet ones). */ + if (r->canonical && !fmt->qnan_msb_set) + sig |= (1 << 22) - 1; + else if (sig == 0) + sig = 1 << 21; + image |= 255 << 23; image |= sig; - if (!fmt->qnan_msb_set) - image ^= 1 << 23 | 1 << 22; } else image |= 0x7fffffff; @@ -2662,10 +2599,8 @@ encode_ieee_single (fmt, buf, r) } static void -decode_ieee_single (fmt, r, buf) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ieee_single (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) { unsigned long image = buf[0] & 0xffffffff; bool sign = (image >> 31) & 1; @@ -2694,8 +2629,8 @@ decode_ieee_single (fmt, r, buf) { r->class = rvc_nan; r->sign = sign; - if (!fmt->qnan_msb_set) - image ^= (SIG_MSB >> 1 | SIG_MSB >> 2); + r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1) + ^ fmt->qnan_msb_set); r->sig[SIGSZ-1] = image; } else @@ -2713,15 +2648,17 @@ decode_ieee_single (fmt, r, buf) } } -const struct real_format ieee_single_format = +const struct real_format ieee_single_format = { encode_ieee_single, decode_ieee_single, 2, 1, 24, + 24, -125, 128, + 31, true, true, true, @@ -2729,19 +2666,35 @@ const struct real_format ieee_single_format = true }; +const struct real_format mips_single_format = + { + encode_ieee_single, + decode_ieee_single, + 2, + 1, + 24, + 24, + -125, + 128, + 31, + true, + true, + true, + true, + false + }; + /* IEEE double-precision format. */ -static void encode_ieee_double PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_ieee_double PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_ieee_double (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_ieee_double (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_ieee_double (fmt, buf, r) - const struct real_format *fmt; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ieee_double (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image_lo, image_hi, sig_lo, sig_hi, exp; bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0; @@ -2781,10 +2734,26 @@ encode_ieee_double (fmt, buf, r) case rvc_nan: if (fmt->has_nans) { + if (r->canonical) + sig_hi = sig_lo = 0; + if (r->signalling == fmt->qnan_msb_set) + sig_hi &= ~(1 << 19); + else + sig_hi |= 1 << 19; + /* We overload qnan_msb_set here: it's only clear for + mips_ieee_single, which wants all mantissa bits but the + quiet/signalling one set in canonical NaNs (at least + Quiet ones). */ + if (r->canonical && !fmt->qnan_msb_set) + { + sig_hi |= (1 << 19) - 1; + sig_lo = 0xffffffff; + } + else if (sig_hi == 0 && sig_lo == 0) + sig_hi = 1 << 18; + image_hi |= 2047 << 20; image_hi |= sig_hi; - if (!fmt->qnan_msb_set) - image_hi ^= 1 << 19 | 1 << 18; image_lo = sig_lo; } else @@ -2818,10 +2787,8 @@ encode_ieee_double (fmt, buf, r) } static void -decode_ieee_double (fmt, r, buf) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ieee_double (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) { unsigned long image_hi, image_lo; bool sign; @@ -2874,6 +2841,7 @@ decode_ieee_double (fmt, r, buf) { r->class = rvc_nan; r->sign = sign; + r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set; if (HOST_BITS_PER_LONG == 32) { r->sig[SIGSZ-1] = image_hi; @@ -2881,9 +2849,6 @@ decode_ieee_double (fmt, r, buf) } else r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo; - - if (!fmt->qnan_msb_set) - r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2); } else { @@ -2906,15 +2871,17 @@ decode_ieee_double (fmt, r, buf) } } -const struct real_format ieee_double_format = +const struct real_format ieee_double_format = { encode_ieee_double, decode_ieee_double, 2, 1, 53, + 53, -1021, 1024, + 63, true, true, true, @@ -2922,28 +2889,36 @@ const struct real_format ieee_double_format = true }; - -/* IEEE extended double precision format. This comes in three - flavours: Intel's as a 12 byte image, Intel's as a 16 byte image, - and Motorola's. */ - -static void encode_ieee_extended PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_ieee_extended PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); - -static void encode_ieee_extended_128 PARAMS ((const struct real_format *fmt, - long *, - const REAL_VALUE_TYPE *)); -static void decode_ieee_extended_128 PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, - const long *)); +const struct real_format mips_double_format = + { + encode_ieee_double, + decode_ieee_double, + 2, + 1, + 53, + 53, + -1021, + 1024, + 63, + true, + true, + true, + true, + false + }; + +/* IEEE extended real format. This comes in three flavors: Intel's as + a 12 byte image, Intel's as a 16 byte image, and Motorola's. Intel + 12- and 16-byte images may be big- or little endian; Motorola's is + always big endian. */ + +/* Helper subroutine which converts from the internal format to the + 12-byte little-endian Intel format. Functions below adjust this + for the other possible formats. */ static void -encode_ieee_extended (fmt, buf, r) - const struct real_format *fmt; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ieee_extended (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image_hi, sig_hi, sig_lo; bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0; @@ -2988,8 +2963,12 @@ encode_ieee_extended (fmt, buf, r) sig_hi = sig_lo >> 31 >> 1; sig_lo &= 0xffffffff; } - if (!fmt->qnan_msb_set) - sig_hi ^= 1 << 30 | 1 << 29; + if (r->signalling == fmt->qnan_msb_set) + sig_hi &= ~(1 << 30); + else + sig_hi |= 1 << 30; + if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0) + sig_hi = 1 << 29; /* Intel requires the explicit integer bit to be set, otherwise it considers the value a "pseudo-nan". Motorola docs say it @@ -3009,11 +2988,11 @@ encode_ieee_extended (fmt, buf, r) /* Recall that IEEE numbers are interpreted as 1.F x 2**exp, whereas the intermediate representation is 0.F x 2**exp. - Which means we're off by one. + Which means we're off by one. Except for Motorola, which consider exp=0 and explicit integer bit set to continue to be normalized. In theory - this descrepency has been taken care of by the difference + this discrepancy has been taken care of by the difference in fmt->emin in round_for_format. */ if (denormal) @@ -3044,36 +3023,74 @@ encode_ieee_extended (fmt, buf, r) abort (); } + buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi; +} + +/* Convert from the internal format to the 12-byte Motorola format + for an IEEE extended real. */ +static void +encode_ieee_extended_motorola (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) +{ + long intermed[3]; + encode_ieee_extended (fmt, intermed, r); + + /* Motorola chips are assumed always to be big-endian. Also, the + padding in a Motorola extended real goes between the exponent and + the mantissa. At this point the mantissa is entirely within + elements 0 and 1 of intermed, and the exponent entirely within + element 2, so all we have to do is swap the order around, and + shift element 2 left 16 bits. */ + buf[0] = intermed[2] << 16; + buf[1] = intermed[1]; + buf[2] = intermed[0]; +} + +/* Convert from the internal format to the 12-byte Intel format for + an IEEE extended real. */ +static void +encode_ieee_extended_intel_96 (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) +{ if (FLOAT_WORDS_BIG_ENDIAN) - buf[0] = image_hi << 16, buf[1] = sig_hi, buf[2] = sig_lo; + { + /* All the padding in an Intel-format extended real goes at the high + end, which in this case is after the mantissa, not the exponent. + Therefore we must shift everything down 16 bits. */ + long intermed[3]; + encode_ieee_extended (fmt, intermed, r); + buf[0] = ((intermed[2] << 16) | ((unsigned long)(intermed[1] & 0xFFFF0000) >> 16)); + buf[1] = ((intermed[1] << 16) | ((unsigned long)(intermed[0] & 0xFFFF0000) >> 16)); + buf[2] = (intermed[0] << 16); + } else - buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi; + /* encode_ieee_extended produces what we want directly. */ + encode_ieee_extended (fmt, buf, r); } +/* Convert from the internal format to the 16-byte Intel format for + an IEEE extended real. */ static void -encode_ieee_extended_128 (fmt, buf, r) - const struct real_format *fmt; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ieee_extended_intel_128 (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { - buf[3 * !FLOAT_WORDS_BIG_ENDIAN] = 0; - encode_ieee_extended (fmt, buf+!!FLOAT_WORDS_BIG_ENDIAN, r); + /* All the padding in an Intel-format extended real goes at the high end. */ + encode_ieee_extended_intel_96 (fmt, buf, r); + buf[3] = 0; } +/* As above, we have a helper function which converts from 12-byte + little-endian Intel format to internal format. Functions below + adjust for the other possible formats. */ static void -decode_ieee_extended (fmt, r, buf) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ieee_extended (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) { unsigned long image_hi, sig_hi, sig_lo; bool sign; int exp; - if (FLOAT_WORDS_BIG_ENDIAN) - image_hi = buf[0] >> 16, sig_hi = buf[1], sig_lo = buf[2]; - else - sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2]; + sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2]; sig_lo &= 0xffffffff; sig_hi &= 0xffffffff; image_hi &= 0xffffffff; @@ -3120,6 +3137,7 @@ decode_ieee_extended (fmt, r, buf) { r->class = rvc_nan; r->sign = sign; + r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set; if (HOST_BITS_PER_LONG == 32) { r->sig[SIGSZ-1] = sig_hi; @@ -3127,9 +3145,6 @@ decode_ieee_extended (fmt, r, buf) } else r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo; - - if (!fmt->qnan_msb_set) - r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2); } else { @@ -3152,24 +3167,69 @@ decode_ieee_extended (fmt, r, buf) } } +/* Convert from the internal format to the 12-byte Motorola format + for an IEEE extended real. */ +static void +decode_ieee_extended_motorola (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + long intermed[3]; + + /* Motorola chips are assumed always to be big-endian. Also, the + padding in a Motorola extended real goes between the exponent and + the mantissa; remove it. */ + intermed[0] = buf[2]; + intermed[1] = buf[1]; + intermed[2] = (unsigned long)buf[0] >> 16; + + decode_ieee_extended (fmt, r, intermed); +} + +/* Convert from the internal format to the 12-byte Intel format for + an IEEE extended real. */ +static void +decode_ieee_extended_intel_96 (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + if (FLOAT_WORDS_BIG_ENDIAN) + { + /* All the padding in an Intel-format extended real goes at the high + end, which in this case is after the mantissa, not the exponent. + Therefore we must shift everything up 16 bits. */ + long intermed[3]; + + intermed[0] = (((unsigned long)buf[2] >> 16) | (buf[1] << 16)); + intermed[1] = (((unsigned long)buf[1] >> 16) | (buf[0] << 16)); + intermed[2] = ((unsigned long)buf[0] >> 16); + + decode_ieee_extended (fmt, r, intermed); + } + else + /* decode_ieee_extended produces what we want directly. */ + decode_ieee_extended (fmt, r, buf); +} + +/* Convert from the internal format to the 16-byte Intel format for + an IEEE extended real. */ static void -decode_ieee_extended_128 (fmt, r, buf) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ieee_extended_intel_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) { - decode_ieee_extended (fmt, r, buf+!!FLOAT_WORDS_BIG_ENDIAN); + /* All the padding in an Intel-format extended real goes at the high end. */ + decode_ieee_extended_intel_96 (fmt, r, buf); } -const struct real_format ieee_extended_motorola_format = +const struct real_format ieee_extended_motorola_format = { - encode_ieee_extended, - decode_ieee_extended, + encode_ieee_extended_motorola, + decode_ieee_extended_motorola, 2, 1, 64, + 64, -16382, 16384, + 95, true, true, true, @@ -3177,15 +3237,17 @@ const struct real_format ieee_extended_motorola_format = true }; -const struct real_format ieee_extended_intel_96_format = +const struct real_format ieee_extended_intel_96_format = { - encode_ieee_extended, - decode_ieee_extended, + encode_ieee_extended_intel_96, + decode_ieee_extended_intel_96, 2, 1, 64, + 64, -16381, 16384, + 79, true, true, true, @@ -3193,15 +3255,17 @@ const struct real_format ieee_extended_intel_96_format = true }; -const struct real_format ieee_extended_intel_128_format = +const struct real_format ieee_extended_intel_128_format = { - encode_ieee_extended_128, - decode_ieee_extended_128, + encode_ieee_extended_intel_128, + decode_ieee_extended_intel_128, 2, 1, 64, + 64, -16381, 16384, + 79, true, true, true, @@ -3211,15 +3275,17 @@ const struct real_format ieee_extended_intel_128_format = /* The following caters to i386 systems that set the rounding precision to 53 bits instead of 64, e.g. FreeBSD. */ -const struct real_format ieee_extended_intel_96_round_53_format = +const struct real_format ieee_extended_intel_96_round_53_format = { - encode_ieee_extended, - decode_ieee_extended, + encode_ieee_extended_intel_96, + decode_ieee_extended_intel_96, 2, 1, 53, + 53, -16381, 16384, + 79, true, true, true, @@ -3236,97 +3302,76 @@ const struct real_format ieee_extended_intel_96_round_53_format = ignored. Zeroes, Infinities, and NaNs are set in both doubles due to precedent. */ -static void encode_ibm_extended PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_ibm_extended PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_ibm_extended (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_ibm_extended (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_ibm_extended (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ibm_extended (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { - REAL_VALUE_TYPE u, v; - - switch (r->class) - { - case rvc_zero: - /* Both doubles have sign bit set. */ - buf[0] = FLOAT_WORDS_BIG_ENDIAN ? r->sign << 31 : 0; - buf[1] = FLOAT_WORDS_BIG_ENDIAN ? 0 : r->sign << 31; - buf[2] = buf[0]; - buf[3] = buf[1]; - break; + REAL_VALUE_TYPE u, normr, v; + const struct real_format *base_fmt; - case rvc_inf: - case rvc_nan: - /* Both doubles set to Inf / NaN. */ - encode_ieee_double (&ieee_double_format, &buf[0], r); - buf[2] = buf[0]; - buf[3] = buf[1]; - return; - - case rvc_normal: - /* u = IEEE double precision portion of significand. */ - u = *r; - clear_significand_below (&u, SIGNIFICAND_BITS - 53); - - normalize (&u); - /* If the upper double is zero, we have a denormal double, so - move it to the first double and leave the second as zero. */ - if (u.class == rvc_zero) - { - v = u; - u = *r; - normalize (&u); - } - else - { - /* v = remainder containing additional 53 bits of significand. */ - do_add (&v, r, &u, 1); - round_for_format (&ieee_double_format, &v); - } + base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format; - round_for_format (&ieee_double_format, &u); + /* Renormlize R before doing any arithmetic on it. */ + normr = *r; + if (normr.class == rvc_normal) + normalize (&normr); - encode_ieee_double (&ieee_double_format, &buf[0], &u); - encode_ieee_double (&ieee_double_format, &buf[2], &v); - break; + /* u = IEEE double precision portion of significand. */ + u = normr; + round_for_format (base_fmt, &u); + encode_ieee_double (base_fmt, &buf[0], &u); - default: - abort (); + if (u.class == rvc_normal) + { + do_add (&v, &normr, &u, 1); + /* Call round_for_format since we might need to denormalize. */ + round_for_format (base_fmt, &v); + encode_ieee_double (base_fmt, &buf[2], &v); + } + else + { + /* Inf, NaN, 0 are all representable as doubles, so the + least-significant part can be 0.0. */ + buf[2] = 0; + buf[3] = 0; } } static void -decode_ibm_extended (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ibm_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, REAL_VALUE_TYPE *r, + const long *buf) { REAL_VALUE_TYPE u, v; + const struct real_format *base_fmt; - decode_ieee_double (&ieee_double_format, &u, &buf[0]); + base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format; + decode_ieee_double (base_fmt, &u, &buf[0]); if (u.class != rvc_zero && u.class != rvc_inf && u.class != rvc_nan) { - decode_ieee_double (&ieee_double_format, &v, &buf[2]); + decode_ieee_double (base_fmt, &v, &buf[2]); do_add (r, &u, &v, 0); } else *r = u; } -const struct real_format ibm_extended_format = +const struct real_format ibm_extended_format = { encode_ibm_extended, decode_ibm_extended, 2, 1, 53 + 53, + 53, -1021 + 53, 1024, + -1, true, true, true, @@ -3334,19 +3379,35 @@ const struct real_format ibm_extended_format = true }; +const struct real_format mips_extended_format = + { + encode_ibm_extended, + decode_ibm_extended, + 2, + 1, + 53 + 53, + 53, + -1021 + 53, + 1024, + -1, + true, + true, + true, + true, + false + }; + /* IEEE quad precision format. */ -static void encode_ieee_quad PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_ieee_quad PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_ieee_quad (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_ieee_quad (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_ieee_quad (fmt, buf, r) - const struct real_format *fmt; - long *buf; - const REAL_VALUE_TYPE *r; +encode_ieee_quad (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image3, image2, image1, image0, exp; bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0; @@ -3381,7 +3442,12 @@ encode_ieee_quad (fmt, buf, r) { image3 |= 32767 << 16; - if (HOST_BITS_PER_LONG == 32) + if (r->canonical) + { + /* Don't use bits from the significand. The + initialization above is right. */ + } + else if (HOST_BITS_PER_LONG == 32) { image0 = u.sig[0]; image1 = u.sig[1]; @@ -3397,9 +3463,21 @@ encode_ieee_quad (fmt, buf, r) image0 &= 0xffffffff; image2 &= 0xffffffff; } - - if (!fmt->qnan_msb_set) - image3 ^= 1 << 15 | 1 << 14; + if (r->signalling == fmt->qnan_msb_set) + image3 &= ~0x8000; + else + image3 |= 0x8000; + /* We overload qnan_msb_set here: it's only clear for + mips_ieee_single, which wants all mantissa bits but the + quiet/signalling one set in canonical NaNs (at least + Quiet ones). */ + if (r->canonical && !fmt->qnan_msb_set) + { + image3 |= 0x7fff; + image2 = image1 = image0 = 0xffffffff; + } + else if (((image3 & 0xffff) | image2 | image1 | image0) == 0) + image3 |= 0x4000; } else { @@ -3459,10 +3537,8 @@ encode_ieee_quad (fmt, buf, r) } static void -decode_ieee_quad (fmt, r, buf) - const struct real_format *fmt; - REAL_VALUE_TYPE *r; - const long *buf; +decode_ieee_quad (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) { unsigned long image3, image2, image1, image0; bool sign; @@ -3524,6 +3600,7 @@ decode_ieee_quad (fmt, r, buf) { r->class = rvc_nan; r->sign = sign; + r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set; if (HOST_BITS_PER_LONG == 32) { @@ -3538,9 +3615,6 @@ decode_ieee_quad (fmt, r, buf) r->sig[1] = (image3 << 31 << 1) | image2; } lshift_significand (r, r, SIGNIFICAND_BITS - 113); - - if (!fmt->qnan_msb_set) - r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2); } else { @@ -3571,50 +3645,68 @@ decode_ieee_quad (fmt, r, buf) } } -const struct real_format ieee_quad_format = +const struct real_format ieee_quad_format = { encode_ieee_quad, decode_ieee_quad, 2, 1, 113, + 113, -16381, 16384, + 127, true, true, true, true, true }; + +const struct real_format mips_quad_format = + { + encode_ieee_quad, + decode_ieee_quad, + 2, + 1, + 113, + 113, + -16381, + 16384, + 127, + true, + true, + true, + true, + false + }; /* Descriptions of VAX floating point formats can be found beginning at - http://www.openvms.compaq.com:8000/73final/4515/4515pro_013.html#f_floating_point_format + http://h71000.www7.hp.com/doc/73FINAL/4515/4515pro_013.html#f_floating_point_format The thing to remember is that they're almost IEEE, except for word order, exponent bias, and the lack of infinities, nans, and denormals. We don't implement the H_floating format here, simply because neither the VAX or Alpha ports use it. */ - -static void encode_vax_f PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_vax_f PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); -static void encode_vax_d PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_vax_d PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); -static void encode_vax_g PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_vax_g PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); + +static void encode_vax_f (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_vax_f (const struct real_format *, + REAL_VALUE_TYPE *, const long *); +static void encode_vax_d (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_vax_d (const struct real_format *, + REAL_VALUE_TYPE *, const long *); +static void encode_vax_g (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_vax_g (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_vax_f (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long sign, exp, sig, image; @@ -3649,10 +3741,8 @@ encode_vax_f (fmt, buf, r) } static void -decode_vax_f (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long image = buf[0] & 0xffffffff; int exp = (image >> 7) & 0xff; @@ -3671,10 +3761,8 @@ decode_vax_f (fmt, r, buf) } static void -encode_vax_d (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image0, image1, sign = r->sign << 15; @@ -3727,10 +3815,8 @@ encode_vax_d (fmt, buf, r) } static void -decode_vax_d (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long image0, image1; int exp; @@ -3742,7 +3828,7 @@ decode_vax_d (fmt, r, buf) image0 &= 0xffffffff; image1 &= 0xffffffff; - exp = (image0 >> 7) & 0x7f; + exp = (image0 >> 7) & 0xff; memset (r, 0, sizeof (*r)); @@ -3775,10 +3861,8 @@ decode_vax_d (fmt, r, buf) } static void -encode_vax_g (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) { unsigned long image0, image1, sign = r->sign << 15; @@ -3831,10 +3915,8 @@ encode_vax_g (fmt, buf, r) } static void -decode_vax_g (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long image0, image1; int exp; @@ -3878,15 +3960,17 @@ decode_vax_g (fmt, r, buf) } } -const struct real_format vax_f_format = +const struct real_format vax_f_format = { encode_vax_f, decode_vax_f, 2, 1, 24, + 24, -127, 127, + 15, false, false, false, @@ -3894,15 +3978,17 @@ const struct real_format vax_f_format = false }; -const struct real_format vax_d_format = +const struct real_format vax_d_format = { encode_vax_d, decode_vax_d, 2, 1, 56, + 56, -127, 127, + 15, false, false, false, @@ -3910,15 +3996,17 @@ const struct real_format vax_d_format = false }; -const struct real_format vax_g_format = +const struct real_format vax_g_format = { encode_vax_g, decode_vax_g, 2, 1, 53, + 53, -1023, 1023, + 15, false, false, false, @@ -3933,20 +4021,18 @@ const struct real_format vax_g_format = http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/DZ9AR001/9.1?DT=19930923083613 */ -static void encode_i370_single PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_i370_single PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); -static void encode_i370_double PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_i370_double PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_i370_single (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_i370_single (const struct real_format *, + REAL_VALUE_TYPE *, const long *); +static void encode_i370_double (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_i370_double (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_i370_single (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) { unsigned long sign, exp, sig, image; @@ -3977,10 +4063,8 @@ encode_i370_single (fmt, buf, r) } static void -decode_i370_single (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long sign, sig, image = buf[0]; int exp; @@ -4002,10 +4086,8 @@ decode_i370_single (fmt, r, buf) } static void -encode_i370_double (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) { unsigned long sign, exp, image_hi, image_lo; @@ -4053,10 +4135,8 @@ encode_i370_double (fmt, buf, r) } static void -decode_i370_double (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long sign, image_hi, image_lo; int exp; @@ -4098,8 +4178,10 @@ const struct real_format i370_single_format = 16, 4, 6, + 6, -64, 63, + 31, false, false, false, /* ??? The encoding does allow for "unnormals". */ @@ -4114,8 +4196,10 @@ const struct real_format i370_double_format = 16, 4, 14, + 14, -64, 63, + 63, false, false, false, /* ??? The encoding does allow for "unnormals". */ @@ -4142,23 +4226,21 @@ const struct real_format i370_double_format = See http://www-s.ti.com/sc/psheets/spru063c/spru063c.pdf */ -static void encode_c4x_single PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_c4x_single PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); -static void encode_c4x_extended PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_c4x_extended PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_c4x_single (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_c4x_single (const struct real_format *, + REAL_VALUE_TYPE *, const long *); +static void encode_c4x_extended (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_c4x_extended (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_c4x_single (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) { unsigned long image, exp, sig; - + switch (r->class) { case rvc_zero: @@ -4194,10 +4276,8 @@ encode_c4x_single (fmt, buf, r) } static void -decode_c4x_single (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long image = buf[0]; unsigned long sig; @@ -4229,13 +4309,11 @@ decode_c4x_single (fmt, r, buf) } static void -encode_c4x_extended (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) { unsigned long exp, sig; - + switch (r->class) { case rvc_zero: @@ -4281,10 +4359,8 @@ encode_c4x_extended (fmt, buf, r) } static void -decode_c4x_extended (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { unsigned long sig; int exp, sf; @@ -4321,15 +4397,17 @@ decode_c4x_extended (fmt, r, buf) } } -const struct real_format c4x_single_format = +const struct real_format c4x_single_format = { encode_c4x_single, decode_c4x_single, 2, 1, 24, + 24, -126, 128, + -1, false, false, false, @@ -4337,15 +4415,17 @@ const struct real_format c4x_single_format = false }; -const struct real_format c4x_extended_format = +const struct real_format c4x_extended_format = { encode_c4x_extended, decode_c4x_extended, 2, 1, 32, + 32, -126, 128, + -1, false, false, false, @@ -4359,58 +4439,210 @@ const struct real_format c4x_extended_format = The encode and decode routines exist only to satisfy our paranoia harness. */ -static void encode_internal PARAMS ((const struct real_format *fmt, - long *, const REAL_VALUE_TYPE *)); -static void decode_internal PARAMS ((const struct real_format *, - REAL_VALUE_TYPE *, const long *)); +static void encode_internal (const struct real_format *fmt, + long *, const REAL_VALUE_TYPE *); +static void decode_internal (const struct real_format *, + REAL_VALUE_TYPE *, const long *); static void -encode_internal (fmt, buf, r) - const struct real_format *fmt ATTRIBUTE_UNUSED; - long *buf; - const REAL_VALUE_TYPE *r; +encode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) { memcpy (buf, r, sizeof (*r)); } static void -decode_internal (fmt, r, buf) - const struct real_format *fmt ATTRIBUTE_UNUSED; - REAL_VALUE_TYPE *r; - const long *buf; +decode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) { memcpy (r, buf, sizeof (*r)); } -const struct real_format real_internal_format = +const struct real_format real_internal_format = { encode_internal, decode_internal, 2, 1, SIGNIFICAND_BITS - 2, + SIGNIFICAND_BITS - 2, -MAX_EXP, MAX_EXP, + -1, true, true, false, true, - true + true }; -/* Set up default mode to format mapping for IEEE. Everyone else has - to set these values in OVERRIDE_OPTIONS. */ +/* Calculate the square root of X in mode MODE, and store the result + in R. Return TRUE if the operation does not raise an exception. + For details see "High Precision Division and Square Root", + Alan H. Karp and Peter Markstein, HP Lab Report 93-93-42, June + 1993. http://www.hpl.hp.com/techreports/93/HPL-93-42.pdf. */ -const struct real_format *real_format_for_mode[TFmode - QFmode + 1] = +bool +real_sqrt (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) { - NULL, /* QFmode */ - NULL, /* HFmode */ - NULL, /* TQFmode */ - &ieee_single_format, /* SFmode */ - &ieee_double_format, /* DFmode */ - - /* We explicitly don't handle XFmode. There are two formats, - pretty much equally common. Choose one in OVERRIDE_OPTIONS. */ - NULL, /* XFmode */ - &ieee_quad_format /* TFmode */ -}; + static REAL_VALUE_TYPE halfthree; + static bool init = false; + REAL_VALUE_TYPE h, t, i; + int iter, exp; + + /* sqrt(-0.0) is -0.0. */ + if (real_isnegzero (x)) + { + *r = *x; + return false; + } + + /* Negative arguments return NaN. */ + if (real_isneg (x)) + { + get_canonical_qnan (r, 0); + return false; + } + + /* Infinity and NaN return themselves. */ + if (real_isinf (x) || real_isnan (x)) + { + *r = *x; + return false; + } + + if (!init) + { + do_add (&halfthree, &dconst1, &dconsthalf, 0); + init = true; + } + + /* Initial guess for reciprocal sqrt, i. */ + exp = real_exponent (x); + real_ldexp (&i, &dconst1, -exp/2); + + /* Newton's iteration for reciprocal sqrt, i. */ + for (iter = 0; iter < 16; iter++) + { + /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x). */ + do_multiply (&t, x, &i); + do_multiply (&h, &t, &i); + do_multiply (&t, &h, &dconsthalf); + do_add (&h, &halfthree, &t, 1); + do_multiply (&t, &i, &h); + + /* Check for early convergence. */ + if (iter >= 6 && real_identical (&i, &t)) + break; + + /* ??? Unroll loop to avoid copying. */ + i = t; + } + + /* Final iteration: r = i*x + 0.5*i*x*(1.0 - i*(i*x)). */ + do_multiply (&t, x, &i); + do_multiply (&h, &t, &i); + do_add (&i, &dconst1, &h, 1); + do_multiply (&h, &t, &i); + do_multiply (&i, &dconsthalf, &h); + do_add (&h, &t, &i, 0); + + /* ??? We need a Tuckerman test to get the last bit. */ + + real_convert (r, mode, &h); + return true; +} + +/* Calculate X raised to the integer exponent N in mode MODE and store + the result in R. Return true if the result may be inexact due to + loss of precision. The algorithm is the classic "left-to-right binary + method" described in section 4.6.3 of Donald Knuth's "Seminumerical + Algorithms", "The Art of Computer Programming", Volume 2. */ + +bool +real_powi (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x, HOST_WIDE_INT n) +{ + unsigned HOST_WIDE_INT bit; + REAL_VALUE_TYPE t; + bool inexact = false; + bool init = false; + bool neg; + int i; + + if (n == 0) + { + *r = dconst1; + return false; + } + else if (n < 0) + { + /* Don't worry about overflow, from now on n is unsigned. */ + neg = true; + n = -n; + } + else + neg = false; + + t = *x; + bit = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1); + for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++) + { + if (init) + { + inexact |= do_multiply (&t, &t, &t); + if (n & bit) + inexact |= do_multiply (&t, &t, x); + } + else if (n & bit) + init = true; + bit >>= 1; + } + + if (neg) + inexact |= do_divide (&t, &dconst1, &t); + + real_convert (r, mode, &t); + return inexact; +} + +/* Round X to the nearest integer not larger in absolute value, i.e. + towards zero, placing the result in R in mode MODE. */ + +void +real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) +{ + do_fix_trunc (r, x); + if (mode != VOIDmode) + real_convert (r, mode, r); +} + +/* Round X to the largest integer not greater in value, i.e. round + down, placing the result in R in mode MODE. */ + +void +real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) +{ + do_fix_trunc (r, x); + if (! real_identical (r, x) && r->sign) + do_add (r, r, &dconstm1, 0); + if (mode != VOIDmode) + real_convert (r, mode, r); +} + +/* Round X to the smallest integer not less then argument, i.e. round + up, placing the result in R in mode MODE. */ + +void +real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) +{ + do_fix_trunc (r, x); + if (! real_identical (r, x) && ! r->sign) + do_add (r, r, &dconst1, 0); + if (mode != VOIDmode) + real_convert (r, mode, r); +} |