From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/real.c | 5043 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5043 insertions(+) create mode 100644 gcc/real.c (limited to 'gcc/real.c') diff --git a/gcc/real.c b/gcc/real.c new file mode 100644 index 000000000..6d3b4356d --- /dev/null +++ b/gcc/real.c @@ -0,0 +1,5043 @@ +/* real.c - software floating point emulation. + Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, + 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. + Contributed by Stephen L. Moshier (moshier@world.std.com). + Re-written by Richard Henderson + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "diagnostic-core.h" +#include "real.h" +#include "realmpfr.h" +#include "tm_p.h" +#include "dfp.h" + +/* The floating point model used internally is not exactly IEEE 754 + compliant, and close to the description in the ISO C99 standard, + section 5.2.4.2.2 Characteristics of floating types. + + Specifically + + x = s * b^e * \sum_{k=1}^p f_k * b^{-k} + + where + s = sign (+- 1) + b = base or radix, here always 2 + e = exponent + p = precision (the number of base-b digits in the significand) + f_k = the digits of the significand. + + We differ from typical IEEE 754 encodings in that the entire + significand is fractional. Normalized significands are in the + range [0.5, 1.0). + + 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 26. + + 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 + layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits. */ + + +/* Used to classify two numbers simultaneously. */ +#define CLASS2(A, B) ((A) << 2 | (B)) + +#if HOST_BITS_PER_LONG != 64 && HOST_BITS_PER_LONG != 32 + #error "Some constant folding done by hand to avoid shift count warnings" +#endif + +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 void decimal_from_integer (REAL_VALUE_TYPE *); +static void decimal_integer_string (char *, const REAL_VALUE_TYPE *, + size_t); + +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 (REAL_VALUE_TYPE *r, int sign) +{ + memset (r, 0, sizeof (*r)); + r->sign = sign; +} + +/* Initialize R with the canonical quiet NaN. */ + +static inline void +get_canonical_qnan (REAL_VALUE_TYPE *r, int sign) +{ + memset (r, 0, sizeof (*r)); + r->cl = rvc_nan; + r->sign = sign; + r->canonical = 1; +} + +static inline void +get_canonical_snan (REAL_VALUE_TYPE *r, int sign) +{ + memset (r, 0, sizeof (*r)); + r->cl = rvc_nan; + r->sign = sign; + r->signalling = 1; + r->canonical = 1; +} + +static inline void +get_inf (REAL_VALUE_TYPE *r, int sign) +{ + memset (r, 0, sizeof (*r)); + r->cl = rvc_inf; + r->sign = sign; +} + + +/* Right-shift the significand of A by N bits; put the result in the + significand of R. If any one bits are shifted out, return true. */ + +static bool +sticky_rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) +{ + unsigned long sticky = 0; + unsigned int i, ofs = 0; + + if (n >= HOST_BITS_PER_LONG) + { + for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i) + sticky |= a->sig[i]; + n &= HOST_BITS_PER_LONG - 1; + } + + if (n != 0) + { + sticky |= a->sig[ofs] & (((unsigned long)1 << n) - 1); + for (i = 0; i < SIGSZ; ++i) + { + r->sig[i] + = (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n) + | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1]) + << (HOST_BITS_PER_LONG - n))); + } + } + else + { + for (i = 0; ofs + i < SIGSZ; ++i) + r->sig[i] = a->sig[ofs + i]; + for (; i < SIGSZ; ++i) + r->sig[i] = 0; + } + + return sticky != 0; +} + +/* Right-shift the significand of A by N bits; put the result in the + significand of R. */ + +static void +rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) +{ + unsigned int i, ofs = n / HOST_BITS_PER_LONG; + + n &= HOST_BITS_PER_LONG - 1; + if (n != 0) + { + for (i = 0; i < SIGSZ; ++i) + { + r->sig[i] + = (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n) + | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1]) + << (HOST_BITS_PER_LONG - n))); + } + } + else + { + for (i = 0; ofs + i < SIGSZ; ++i) + r->sig[i] = a->sig[ofs + i]; + for (; i < SIGSZ; ++i) + r->sig[i] = 0; + } +} + +/* Left-shift the significand of A by N bits; put the result in the + significand of R. */ + +static void +lshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + unsigned int n) +{ + unsigned int i, ofs = n / HOST_BITS_PER_LONG; + + n &= HOST_BITS_PER_LONG - 1; + if (n == 0) + { + for (i = 0; ofs + i < SIGSZ; ++i) + r->sig[SIGSZ-1-i] = a->sig[SIGSZ-1-i-ofs]; + for (; i < SIGSZ; ++i) + r->sig[SIGSZ-1-i] = 0; + } + else + for (i = 0; i < SIGSZ; ++i) + { + r->sig[SIGSZ-1-i] + = (((ofs + i >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs]) << n) + | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs-1]) + >> (HOST_BITS_PER_LONG - n))); + } +} + +/* Likewise, but N is specialized to 1. */ + +static inline void +lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) +{ + unsigned int i; + + for (i = SIGSZ - 1; i > 0; --i) + r->sig[i] = (a->sig[i] << 1) | (a->sig[i-1] >> (HOST_BITS_PER_LONG - 1)); + r->sig[0] = a->sig[0] << 1; +} + +/* Add the significands of A and B, placing the result in R. Return + true if there was carry out of the most significant word. */ + +static inline bool +add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b) +{ + bool carry = false; + int i; + + for (i = 0; i < SIGSZ; ++i) + { + unsigned long ai = a->sig[i]; + unsigned long ri = ai + b->sig[i]; + + if (carry) + { + carry = ri < ai; + carry |= ++ri == 0; + } + else + carry = ri < ai; + + r->sig[i] = ri; + } + + return carry; +} + +/* Subtract the significands of A and B, placing the result in R. CARRY is + true if there's a borrow incoming to the least significant word. + Return true if there was borrow out of the most significant word. */ + +static inline bool +sub_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, + const REAL_VALUE_TYPE *b, int carry) +{ + int i; + + for (i = 0; i < SIGSZ; ++i) + { + unsigned long ai = a->sig[i]; + unsigned long ri = ai - b->sig[i]; + + if (carry) + { + carry = ri > ai; + carry |= ~--ri == 0; + } + else + carry = ri > ai; + + r->sig[i] = ri; + } + + return carry; +} + +/* Negate the significand A, placing the result in R. */ + +static inline void +neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) +{ + bool carry = true; + int i; + + for (i = 0; i < SIGSZ; ++i) + { + unsigned long ri, ai = a->sig[i]; + + if (carry) + { + if (ai) + { + ri = -ai; + carry = false; + } + else + ri = ai; + } + else + ri = ~ai; + + r->sig[i] = ri; + } +} + +/* Compare significands. Return tri-state vs zero. */ + +static inline int +cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b) +{ + int i; + + for (i = SIGSZ - 1; i >= 0; --i) + { + unsigned long ai = a->sig[i]; + unsigned long bi = b->sig[i]; + + if (ai > bi) + return 1; + if (ai < bi) + return -1; + } + + return 0; +} + +/* Return true if A is nonzero. */ + +static inline int +cmp_significand_0 (const REAL_VALUE_TYPE *a) +{ + int i; + + for (i = SIGSZ - 1; i >= 0; --i) + if (a->sig[i]) + return 1; + + return 0; +} + +/* Set bit N of the significand of R. */ + +static inline void +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); +} + +/* Clear bit N of the significand of R. */ + +static inline void +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)); +} + +/* Test bit N of the significand of R. */ + +static inline bool +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 + e.g. 2 != 0 -> true. Seen in gcc version 3.2 20020520. */ + int t = (r->sig[n / HOST_BITS_PER_LONG] >> (n % HOST_BITS_PER_LONG)) & 1; + return t; +} + +/* Clear bits 0..N-1 of the significand of R. */ + +static void +clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n) +{ + int i, w = n / HOST_BITS_PER_LONG; + + for (i = 0; i < w; ++i) + r->sig[i] = 0; + + r->sig[w] &= ~(((unsigned long)1 << (n % HOST_BITS_PER_LONG)) - 1); +} + +/* Divide the significands of A and B, placing the result in R. Return + true if the division was inexact. */ + +static inline bool +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; + unsigned long msb, inexact; + + u = *a; + memset (r->sig, 0, sizeof (r->sig)); + + msb = 0; + goto start; + do + { + msb = u.sig[SIGSZ-1] & SIG_MSB; + lshift_significand_1 (&u, &u); + start: + if (msb || cmp_significands (&u, b) >= 0) + { + sub_significands (&u, &u, b, 0); + set_significand_bit (r, bit); + } + } + while (--bit >= 0); + + for (i = 0, inexact = 0; i < SIGSZ; i++) + inexact |= u.sig[i]; + + return inexact != 0; +} + +/* Adjust the exponent and significand of R such that the most + significant bit is set. We underflow to zero and overflow to + infinity here, without denormals. (The intermediate representation + exponent is large enough to handle target denormals normalized.) */ + +static void +normalize (REAL_VALUE_TYPE *r) +{ + int shift = 0, exp; + int i, j; + + if (r->decimal) + return; + + /* Find the first word that is nonzero. */ + for (i = SIGSZ - 1; i >= 0; i--) + if (r->sig[i] == 0) + shift += HOST_BITS_PER_LONG; + else + break; + + /* Zero significand flushes to zero. */ + if (i < 0) + { + r->cl = rvc_zero; + SET_REAL_EXP (r, 0); + return; + } + + /* Find the first bit that is nonzero. */ + for (j = 0; ; j++) + if (r->sig[i] & ((unsigned long)1 << (HOST_BITS_PER_LONG - 1 - j))) + break; + shift += j; + + if (shift > 0) + { + exp = REAL_EXP (r) - shift; + if (exp > MAX_EXP) + get_inf (r, r->sign); + else if (exp < -MAX_EXP) + get_zero (r, r->sign); + else + { + SET_REAL_EXP (r, exp); + lshift_significand (r, r, shift); + } + } +} + +/* Calculate R = A + (SUBTRACT_P ? -B : B). Return true if the + result may be inexact due to a loss of precision. */ + +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; + bool inexact = false; + + /* Determine if we need to add or subtract. */ + sign = a->sign; + subtract_p = (sign ^ b->sign) ^ subtract_p; + + switch (CLASS2 (a->cl, b->cl)) + { + case CLASS2 (rvc_zero, rvc_zero): + /* -0 + -0 = -0, -0 - +0 = -0; all other cases yield +0. */ + get_zero (r, sign & !subtract_p); + return false; + + case CLASS2 (rvc_zero, rvc_normal): + case CLASS2 (rvc_zero, rvc_inf): + case CLASS2 (rvc_zero, rvc_nan): + /* 0 + ANY = ANY. */ + case CLASS2 (rvc_normal, rvc_nan): + case CLASS2 (rvc_inf, rvc_nan): + case CLASS2 (rvc_nan, rvc_nan): + /* ANY + NaN = NaN. */ + case CLASS2 (rvc_normal, rvc_inf): + /* R + Inf = Inf. */ + *r = *b; + r->sign = sign ^ subtract_p; + return false; + + case CLASS2 (rvc_normal, rvc_zero): + case CLASS2 (rvc_inf, rvc_zero): + case CLASS2 (rvc_nan, rvc_zero): + /* ANY + 0 = ANY. */ + case CLASS2 (rvc_nan, rvc_normal): + case CLASS2 (rvc_nan, rvc_inf): + /* NaN + ANY = NaN. */ + case CLASS2 (rvc_inf, rvc_normal): + /* Inf + R = Inf. */ + *r = *a; + return false; + + case CLASS2 (rvc_inf, rvc_inf): + if (subtract_p) + /* Inf - Inf = NaN. */ + get_canonical_qnan (r, 0); + else + /* Inf + Inf = Inf. */ + *r = *a; + return false; + + case CLASS2 (rvc_normal, rvc_normal): + break; + + default: + gcc_unreachable (); + } + + /* Swap the arguments such that A has the larger exponent. */ + dexp = REAL_EXP (a) - REAL_EXP (b); + if (dexp < 0) + { + const REAL_VALUE_TYPE *t; + t = a, a = b, b = t; + dexp = -dexp; + sign ^= subtract_p; + } + exp = REAL_EXP (a); + + /* If the exponents are not identical, we need to shift the + significand of B down. */ + if (dexp > 0) + { + /* If the exponents are too far apart, the significands + do not overlap, which makes the subtraction a noop. */ + if (dexp >= SIGNIFICAND_BITS) + { + *r = *a; + r->sign = sign; + return true; + } + + inexact |= sticky_rshift_significand (&t, b, dexp); + b = &t; + } + + if (subtract_p) + { + if (sub_significands (r, a, b, inexact)) + { + /* We got a borrow out of the subtraction. That means that + A and B had the same exponent, and B had the larger + significand. We need to swap the sign and negate the + significand. */ + sign ^= 1; + neg_significand (r, r); + } + } + else + { + if (add_significands (r, a, b)) + { + /* We got carry out of the addition. This means we need to + shift the significand back down one bit and increase the + exponent. */ + inexact |= sticky_rshift_significand (r, r, 1); + r->sig[SIGSZ-1] |= SIG_MSB; + if (++exp > MAX_EXP) + { + get_inf (r, sign); + return true; + } + } + } + + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp); + /* Zero out the remaining fields. */ + r->signalling = 0; + r->canonical = 0; + r->decimal = 0; + + /* Re-normalize the result. */ + normalize (r); + + /* Special case: if the subtraction results in zero, the result + is positive. */ + if (r->cl == rvc_zero) + r->sign = 0; + else + r->sig[0] |= inexact; + + return inexact; +} + +/* Calculate R = A * B. Return true if the result may be inexact. */ + +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->cl, b->cl)) + { + case CLASS2 (rvc_zero, rvc_zero): + case CLASS2 (rvc_zero, rvc_normal): + case CLASS2 (rvc_normal, rvc_zero): + /* +-0 * ANY = 0 with appropriate sign. */ + get_zero (r, sign); + return false; + + case CLASS2 (rvc_zero, rvc_nan): + case CLASS2 (rvc_normal, rvc_nan): + case CLASS2 (rvc_inf, rvc_nan): + case CLASS2 (rvc_nan, rvc_nan): + /* ANY * NaN = NaN. */ + *r = *b; + r->sign = sign; + return false; + + case CLASS2 (rvc_nan, rvc_zero): + case CLASS2 (rvc_nan, rvc_normal): + case CLASS2 (rvc_nan, rvc_inf): + /* NaN * ANY = NaN. */ + *r = *a; + r->sign = sign; + return false; + + case CLASS2 (rvc_zero, rvc_inf): + case CLASS2 (rvc_inf, rvc_zero): + /* 0 * Inf = NaN */ + get_canonical_qnan (r, sign); + 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 */ + get_inf (r, sign); + return false; + + case CLASS2 (rvc_normal, rvc_normal): + break; + + default: + gcc_unreachable (); + } + + if (r == a || r == b) + rr = &t; + else + rr = r; + get_zero (rr, 0); + + /* Collect all the partial products. Since we don't have sure access + to a widening multiply, we split each long into two half-words. + + Consider the long-hand form of a four half-word multiplication: + + A B C D + * E F G H + -------------- + DE DF DG DH + CE CF CG CH + BE BF BG BH + AE AF AG AH + + We construct partial products of the widened half-word products + that are known to not overlap, e.g. DF+DH. Each such partial + product is given its proper exponent, which allows us to sum them + and obtain the finished product. */ + + for (i = 0; i < SIGSZ * 2; ++i) + { + unsigned long ai = a->sig[i / 2]; + if (i & 1) + ai >>= HOST_BITS_PER_LONG / 2; + else + ai &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1; + + if (ai == 0) + continue; + + for (j = 0; j < 2; ++j) + { + int exp = (REAL_EXP (a) - (2*SIGSZ-1-i)*(HOST_BITS_PER_LONG/2) + + (REAL_EXP (b) - (1-j)*(HOST_BITS_PER_LONG/2))); + + if (exp > MAX_EXP) + { + get_inf (r, sign); + return true; + } + if (exp < -MAX_EXP) + { + /* Would underflow to zero, which we shouldn't bother adding. */ + inexact = true; + continue; + } + + memset (&u, 0, sizeof (u)); + u.cl = rvc_normal; + SET_REAL_EXP (&u, exp); + + for (k = j; k < SIGSZ * 2; k += 2) + { + unsigned long bi = b->sig[k / 2]; + if (k & 1) + bi >>= HOST_BITS_PER_LONG / 2; + else + bi &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1; + + u.sig[k / 2] = ai * bi; + } + + normalize (&u); + inexact |= do_add (rr, rr, &u, 0); + } + } + + rr->sign = sign; + if (rr != r) + *r = t; + + return inexact; +} + +/* Calculate R = A / B. Return true if the result may be inexact. */ + +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; + bool inexact; + + switch (CLASS2 (a->cl, b->cl)) + { + case CLASS2 (rvc_zero, rvc_zero): + /* 0 / 0 = NaN. */ + case CLASS2 (rvc_inf, rvc_inf): + /* Inf / Inf = NaN. */ + get_canonical_qnan (r, sign); + 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. */ + get_zero (r, sign); + 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 false; + + case CLASS2 (rvc_zero, rvc_nan): + case CLASS2 (rvc_normal, rvc_nan): + case CLASS2 (rvc_inf, rvc_nan): + case CLASS2 (rvc_nan, rvc_nan): + /* ANY / NaN = NaN. */ + *r = *b; + r->sign = sign; + return false; + + case CLASS2 (rvc_nan, rvc_zero): + case CLASS2 (rvc_nan, rvc_normal): + case CLASS2 (rvc_nan, rvc_inf): + /* NaN / ANY = NaN. */ + *r = *a; + r->sign = sign; + return false; + + case CLASS2 (rvc_inf, rvc_normal): + /* Inf / R = Inf. */ + get_inf (r, sign); + return false; + + case CLASS2 (rvc_normal, rvc_normal): + break; + + default: + gcc_unreachable (); + } + + if (r == a || r == b) + rr = &t; + else + rr = r; + + /* Make sure all fields in the result are initialized. */ + get_zero (rr, 0); + rr->cl = rvc_normal; + rr->sign = sign; + + exp = REAL_EXP (a) - REAL_EXP (b) + 1; + if (exp > MAX_EXP) + { + get_inf (r, sign); + return true; + } + if (exp < -MAX_EXP) + { + get_zero (r, sign); + return true; + } + SET_REAL_EXP (rr, exp); + + inexact = div_significands (rr, a, b); + + /* Re-normalize the result. */ + normalize (rr); + rr->sig[0] |= inexact; + + 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 (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b, + int nan_result) +{ + int ret; + + switch (CLASS2 (a->cl, b->cl)) + { + case CLASS2 (rvc_zero, rvc_zero): + /* Sign of zero doesn't matter for compares. */ + return 0; + + case CLASS2 (rvc_normal, rvc_zero): + /* Decimal float zero is special and uses rvc_normal, not rvc_zero. */ + if (a->decimal) + return decimal_do_compare (a, b, nan_result); + /* Fall through. */ + case CLASS2 (rvc_inf, rvc_zero): + case CLASS2 (rvc_inf, rvc_normal): + return (a->sign ? -1 : 1); + + case CLASS2 (rvc_inf, rvc_inf): + return -a->sign - -b->sign; + + case CLASS2 (rvc_zero, rvc_normal): + /* Decimal float zero is special and uses rvc_normal, not rvc_zero. */ + if (b->decimal) + return decimal_do_compare (a, b, nan_result); + /* Fall through. */ + case CLASS2 (rvc_zero, rvc_inf): + case CLASS2 (rvc_normal, rvc_inf): + return (b->sign ? 1 : -1); + + case CLASS2 (rvc_zero, rvc_nan): + case CLASS2 (rvc_normal, rvc_nan): + case CLASS2 (rvc_inf, rvc_nan): + case CLASS2 (rvc_nan, rvc_nan): + case CLASS2 (rvc_nan, rvc_zero): + case CLASS2 (rvc_nan, rvc_normal): + case CLASS2 (rvc_nan, rvc_inf): + return nan_result; + + case CLASS2 (rvc_normal, rvc_normal): + break; + + default: + gcc_unreachable (); + } + + if (a->sign != b->sign) + return -a->sign - -b->sign; + + if (a->decimal || b->decimal) + return decimal_do_compare (a, b, nan_result); + + if (REAL_EXP (a) > REAL_EXP (b)) + ret = 1; + else if (REAL_EXP (a) < REAL_EXP (b)) + ret = -1; + else + ret = cmp_significands (a, b); + + return (a->sign ? -ret : ret); +} + +/* Return A truncated to an integral value toward zero. */ + +static void +do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) +{ + *r = *a; + + switch (r->cl) + { + case rvc_zero: + case rvc_inf: + case rvc_nan: + break; + + case rvc_normal: + if (r->decimal) + { + decimal_do_fix_trunc (r, a); + return; + } + if (REAL_EXP (r) <= 0) + get_zero (r, r->sign); + else if (REAL_EXP (r) < SIGNIFICAND_BITS) + clear_significand_below (r, SIGNIFICAND_BITS - REAL_EXP (r)); + break; + + default: + gcc_unreachable (); + } +} + +/* Perform the binary or unary operation described by CODE. + For a unary operation, leave OP1 NULL. This function returns + true if the result may be inexact due to loss of precision. */ + +bool +real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + enum tree_code code = (enum tree_code) icode; + + if (op0->decimal || (op1 && op1->decimal)) + return decimal_real_arithmetic (r, code, op0, op1); + + switch (code) + { + case PLUS_EXPR: + /* Clear any padding areas in *r if it isn't equal to one of the + operands so that we can later do bitwise comparisons later on. */ + if (r != op0 && r != op1) + memset (r, '\0', sizeof (*r)); + return do_add (r, op0, op1, 0); + + case MINUS_EXPR: + if (r != op0 && r != op1) + memset (r, '\0', sizeof (*r)); + return do_add (r, op0, op1, 1); + + case MULT_EXPR: + if (r != op0 && r != op1) + memset (r, '\0', sizeof (*r)); + return do_multiply (r, op0, op1); + + case RDIV_EXPR: + if (r != op0 && r != op1) + memset (r, '\0', sizeof (*r)); + return do_divide (r, op0, op1); + + case MIN_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (do_compare (op0, op1, -1) < 0) + *r = *op0; + else + *r = *op1; + break; + + case MAX_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (do_compare (op0, op1, 1) < 0) + *r = *op1; + else + *r = *op0; + break; + + case NEGATE_EXPR: + *r = *op0; + r->sign ^= 1; + break; + + case ABS_EXPR: + *r = *op0; + r->sign = 0; + break; + + case FIX_TRUNC_EXPR: + do_fix_trunc (r, op0); + break; + + default: + gcc_unreachable (); + } + return false; +} + +REAL_VALUE_TYPE +real_value_negate (const REAL_VALUE_TYPE *op0) +{ + REAL_VALUE_TYPE r; + real_arithmetic (&r, NEGATE_EXPR, op0, NULL); + return r; +} + +REAL_VALUE_TYPE +real_value_abs (const REAL_VALUE_TYPE *op0) +{ + REAL_VALUE_TYPE r; + real_arithmetic (&r, ABS_EXPR, op0, NULL); + return r; +} + +bool +real_compare (int icode, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + enum tree_code code = (enum tree_code) icode; + + switch (code) + { + case LT_EXPR: + return do_compare (op0, op1, 1) < 0; + case LE_EXPR: + return do_compare (op0, op1, 1) <= 0; + case GT_EXPR: + return do_compare (op0, op1, -1) > 0; + case GE_EXPR: + return do_compare (op0, op1, -1) >= 0; + case EQ_EXPR: + return do_compare (op0, op1, -1) == 0; + case NE_EXPR: + return do_compare (op0, op1, -1) != 0; + case UNORDERED_EXPR: + return op0->cl == rvc_nan || op1->cl == rvc_nan; + case ORDERED_EXPR: + return op0->cl != rvc_nan && op1->cl != rvc_nan; + case UNLT_EXPR: + return do_compare (op0, op1, -1) < 0; + case UNLE_EXPR: + return do_compare (op0, op1, -1) <= 0; + case UNGT_EXPR: + return do_compare (op0, op1, 1) > 0; + case UNGE_EXPR: + return do_compare (op0, op1, 1) >= 0; + case UNEQ_EXPR: + return do_compare (op0, op1, 0) == 0; + case LTGT_EXPR: + return do_compare (op0, op1, 0) != 0; + + default: + gcc_unreachable (); + } +} + +/* Return floor log2(R). */ + +int +real_exponent (const REAL_VALUE_TYPE *r) +{ + switch (r->cl) + { + case rvc_zero: + return 0; + case rvc_inf: + case rvc_nan: + return (unsigned int)-1 >> 1; + case rvc_normal: + return REAL_EXP (r); + default: + gcc_unreachable (); + } +} + +/* R = OP0 * 2**EXP. */ + +void +real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp) +{ + *r = *op0; + switch (r->cl) + { + case rvc_zero: + case rvc_inf: + case rvc_nan: + break; + + case rvc_normal: + exp += REAL_EXP (op0); + if (exp > MAX_EXP) + get_inf (r, r->sign); + else if (exp < -MAX_EXP) + get_zero (r, r->sign); + else + SET_REAL_EXP (r, exp); + break; + + default: + gcc_unreachable (); + } +} + +/* Determine whether a floating-point value X is infinite. */ + +bool +real_isinf (const REAL_VALUE_TYPE *r) +{ + return (r->cl == rvc_inf); +} + +/* Determine whether a floating-point value X is a NaN. */ + +bool +real_isnan (const REAL_VALUE_TYPE *r) +{ + return (r->cl == rvc_nan); +} + +/* Determine whether a floating-point value X is finite. */ + +bool +real_isfinite (const REAL_VALUE_TYPE *r) +{ + return (r->cl != rvc_nan) && (r->cl != rvc_inf); +} + +/* Determine whether a floating-point value X is negative. */ + +bool +real_isneg (const REAL_VALUE_TYPE *r) +{ + return r->sign; +} + +/* Determine whether a floating-point value X is minus zero. */ + +bool +real_isnegzero (const REAL_VALUE_TYPE *r) +{ + return r->sign && r->cl == rvc_zero; +} + +/* Compare two floating-point objects for bitwise identity. */ + +bool +real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b) +{ + int i; + + if (a->cl != b->cl) + return false; + if (a->sign != b->sign) + return false; + + switch (a->cl) + { + case rvc_zero: + case rvc_inf: + return true; + + case rvc_normal: + if (a->decimal != b->decimal) + return false; + if (REAL_EXP (a) != REAL_EXP (b)) + return false; + break; + + case rvc_nan: + 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: + gcc_unreachable (); + } + + for (i = 0; i < SIGSZ; ++i) + if (a->sig[i] != b->sig[i]) + return false; + + return true; +} + +/* Try to change R into its exact multiplicative inverse in machine + mode MODE. Return true if successful. */ + +bool +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->cl != rvc_normal) + return false; + + /* Check for a power of two: all significand bits zero except the MSB. */ + for (i = 0; i < SIGSZ-1; ++i) + if (r->sig[i] != 0) + return false; + if (r->sig[SIGSZ-1] != SIG_MSB) + return false; + + /* 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.cl != rvc_normal) + return false; + for (i = 0; i < SIGSZ-1; ++i) + if (u.sig[i] != 0) + return false; + if (u.sig[SIGSZ-1] != SIG_MSB) + return false; + + *r = u; + return true; +} + +/* Return true if arithmetic on values in IMODE that were promoted + from values in TMODE is equivalent to direct arithmetic on values + in TMODE. */ + +bool +real_can_shorten_arithmetic (enum machine_mode imode, enum machine_mode tmode) +{ + const struct real_format *tfmt, *ifmt; + tfmt = REAL_MODE_FORMAT (tmode); + ifmt = REAL_MODE_FORMAT (imode); + /* These conditions are conservative rather than trying to catch the + exact boundary conditions; the main case to allow is IEEE float + and double. */ + return (ifmt->b == tfmt->b + && ifmt->p > 2 * tfmt->p + && ifmt->emin < 2 * tfmt->emin - tfmt->p - 2 + && ifmt->emin < tfmt->emin - tfmt->emax - tfmt->p - 2 + && ifmt->emax > 2 * tfmt->emax + 2 + && ifmt->emax > tfmt->emax - tfmt->emin + tfmt->p + 2 + && ifmt->round_towards_zero == tfmt->round_towards_zero + && (ifmt->has_sign_dependent_rounding + == tfmt->has_sign_dependent_rounding) + && ifmt->has_nans >= tfmt->has_nans + && ifmt->has_inf >= tfmt->has_inf + && ifmt->has_signed_zero >= tfmt->has_signed_zero + && !MODE_COMPOSITE_P (tmode) + && !MODE_COMPOSITE_P (imode)); +} + +/* Render R as an integer. */ + +HOST_WIDE_INT +real_to_integer (const REAL_VALUE_TYPE *r) +{ + unsigned HOST_WIDE_INT i; + + switch (r->cl) + { + case rvc_zero: + underflow: + return 0; + + case rvc_inf: + case rvc_nan: + overflow: + i = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1); + if (!r->sign) + i--; + return i; + + case rvc_normal: + if (r->decimal) + return decimal_real_to_integer (r); + + if (REAL_EXP (r) <= 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 (REAL_EXP (r) > HOST_BITS_PER_WIDE_INT) + goto overflow; + + if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG) + i = r->sig[SIGSZ-1]; + else + { + gcc_assert (HOST_BITS_PER_WIDE_INT == 2 * HOST_BITS_PER_LONG); + i = r->sig[SIGSZ-1]; + i = i << (HOST_BITS_PER_LONG - 1) << 1; + i |= r->sig[SIGSZ-2]; + } + + i >>= HOST_BITS_PER_WIDE_INT - REAL_EXP (r); + + if (r->sign) + i = -i; + return i; + + default: + gcc_unreachable (); + } +} + +/* Likewise, but to an integer pair, HI+LOW. */ + +void +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; + int exp; + + switch (r->cl) + { + case rvc_zero: + underflow: + low = high = 0; + break; + + case rvc_inf: + case rvc_nan: + overflow: + high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1); + if (r->sign) + low = 0; + else + { + high--; + low = -1; + } + break; + + case rvc_normal: + if (r->decimal) + { + decimal_real_to_integer2 (plow, phigh, r); + return; + } + + exp = REAL_EXP (r); + 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; + + rshift_significand (&t, r, 2*HOST_BITS_PER_WIDE_INT - exp); + if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG) + { + high = t.sig[SIGSZ-1]; + low = t.sig[SIGSZ-2]; + } + else + { + gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG); + high = t.sig[SIGSZ-1]; + high = high << (HOST_BITS_PER_LONG - 1) << 1; + high |= t.sig[SIGSZ-2]; + + low = t.sig[SIGSZ-3]; + low = low << (HOST_BITS_PER_LONG - 1) << 1; + low |= t.sig[SIGSZ-4]; + } + + if (r->sign) + { + if (low == 0) + high = -high; + else + low = -low, high = ~high; + } + break; + + default: + gcc_unreachable (); + } + + *plow = low; + *phigh = high; +} + +/* A subroutine of real_to_decimal. Compute the quotient and remainder + of NUM / DEN. Return the quotient and place the remainder in NUM. + It is expected that NUM / DEN are close enough that the quotient is + small. */ + +static unsigned long +rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den) +{ + unsigned long q, msb; + int expn = REAL_EXP (num), expd = REAL_EXP (den); + + if (expn < expd) + return 0; + + q = msb = 0; + goto start; + do + { + msb = num->sig[SIGSZ-1] & SIG_MSB; + q <<= 1; + lshift_significand_1 (num, num); + start: + if (msb || cmp_significands (num, den) >= 0) + { + sub_significands (num, num, den, 0); + q |= 1; + } + } + while (--expn >= expd); + + SET_REAL_EXP (num, expd); + normalize (num); + + return q; +} + +/* Render R as a decimal floating point constant. Emit DIGITS significant + digits in the result, bounded by BUF_SIZE. If DIGITS is 0, choose the + maximum for the representation. If CROP_TRAILING_ZEROS, strip trailing + zeros. If MODE is VOIDmode, round to nearest value. Otherwise, round + to a string that, when parsed back in mode MODE, yields the same value. */ + +#define M_LOG10_2 0.30102999566398119521 + +void +real_to_decimal_for_mode (char *str, const REAL_VALUE_TYPE *r_orig, + size_t buf_size, size_t digits, + int crop_trailing_zeros, enum machine_mode mode) +{ + const struct real_format *fmt = NULL; + const REAL_VALUE_TYPE *one, *ten; + REAL_VALUE_TYPE r, pten, u, v; + int dec_exp, cmp_one, digit; + size_t max_digits; + char *p, *first, *last; + bool sign; + bool round_up; + + if (mode != VOIDmode) + { + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + } + + r = *r_orig; + switch (r.cl) + { + case rvc_zero: + strcpy (str, (r.sign ? "-0.0" : "0.0")); + return; + case rvc_normal: + break; + case rvc_inf: + strcpy (str, (r.sign ? "-Inf" : "+Inf")); + return; + case rvc_nan: + /* ??? Print the significand as well, if not canonical? */ + sprintf (str, "%c%cNaN", (r_orig->sign ? '-' : '+'), + (r_orig->signalling ? 'S' : 'Q')); + return; + default: + gcc_unreachable (); + } + + if (r.decimal) + { + decimal_real_to_decimal (str, &r, buf_size, digits, crop_trailing_zeros); + return; + } + + /* Bound the number of digits printed by the size of the representation. */ + max_digits = SIGNIFICAND_BITS * M_LOG10_2; + if (digits == 0 || digits > max_digits) + digits = max_digits; + + /* Estimate the decimal exponent, and compute the length of the string it + will print as. Be conservative and add one to account for possible + overflow or rounding error. */ + dec_exp = REAL_EXP (&r) * M_LOG10_2; + for (max_digits = 1; dec_exp ; max_digits++) + dec_exp /= 10; + + /* Bound the number of digits printed by the size of the output buffer. */ + max_digits = buf_size - 1 - 1 - 2 - max_digits - 1; + gcc_assert (max_digits <= buf_size); + if (digits > max_digits) + digits = max_digits; + + one = real_digit (1); + ten = ten_to_ptwo (0); + + sign = r.sign; + r.sign = 0; + + dec_exp = 0; + pten = *one; + + cmp_one = do_compare (&r, one, 0); + if (cmp_one > 0) + { + int m; + + /* Number is greater than one. Convert significand to an integer + and strip trailing decimal zeros. */ + + u = r; + SET_REAL_EXP (&u, SIGNIFICAND_BITS - 1); + + /* Largest M, such that 10**2**M fits within SIGNIFICAND_BITS. */ + m = floor_log2 (max_digits); + + /* 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 + DEC_EXP by 2**M. */ + do + { + REAL_VALUE_TYPE t; + + do_divide (&t, &u, ten_to_ptwo (m)); + do_fix_trunc (&v, &t); + if (cmp_significands (&v, &t) == 0) + { + u = t; + dec_exp += 1 << m; + } + } + while (--m >= 0); + + /* Revert the scaling to integer that we performed earlier. */ + SET_REAL_EXP (&u, REAL_EXP (&u) + REAL_EXP (&r) + - (SIGNIFICAND_BITS - 1)); + 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 + the power of 10 that we compute. */ + if (REAL_EXP (&r) > 0) + { + m = floor_log2 ((int)(REAL_EXP (&r) * M_LOG10_2)) + 1; + do + { + const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m); + if (do_compare (&u, ptentwo, 0) >= 0) + { + do_divide (&u, &u, ptentwo); + do_multiply (&pten, &pten, ptentwo); + dec_exp += 1 << m; + } + } + while (--m >= 0); + } + else + /* We managed to divide off enough tens in the above reduction + loop that we've now got a negative exponent. Fall into the + less-than-one code to compute the proper value for PTEN. */ + cmp_one = -1; + } + if (cmp_one < 0) + { + int m; + + /* Number is less than one. Pad significand with leading + decimal zeros. */ + + v = r; + while (1) + { + /* Stop if we'd shift bits off the bottom. */ + if (v.sig[0] & 7) + break; + + do_multiply (&u, &v, ten); + + /* Stop if we're now >= 1. */ + if (REAL_EXP (&u) > 0) + break; + + v = u; + dec_exp -= 1; + } + r = v; + + /* Find power of 10. Do this by multiplying in P=10**2**M when + the current remainder is smaller than 1/P. Fill PTEN with the + power of 10 that we compute. */ + m = floor_log2 ((int)(-REAL_EXP (&r) * M_LOG10_2)) + 1; + do + { + const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m); + const REAL_VALUE_TYPE *ptenmtwo = ten_to_mptwo (m); + + if (do_compare (&v, ptenmtwo, 0) <= 0) + { + do_multiply (&v, &v, ptentwo); + do_multiply (&pten, &pten, ptentwo); + dec_exp -= 1 << m; + } + } + while (--m >= 0); + + /* Invert the positive power of 10 that we've collected so far. */ + do_divide (&pten, one, &pten); + } + + p = str; + if (sign) + *p++ = '-'; + first = p++; + + /* At this point, PTEN should contain the nearest power of 10 smaller + than R, such that this division produces the first digit. + + Using a divide-step primitive that returns the complete integral + remainder avoids the rounding error that would be produced if + we were to use do_divide here and then simply multiply by 10 for + each subsequent digit. */ + + digit = rtd_divmod (&r, &pten); + + /* Be prepared for error in that division via underflow ... */ + if (digit == 0 && cmp_significand_0 (&r)) + { + /* Multiply by 10 and try again. */ + do_multiply (&r, &r, ten); + digit = rtd_divmod (&r, &pten); + dec_exp -= 1; + gcc_assert (digit != 0); + } + + /* ... or overflow. */ + if (digit == 10) + { + *p++ = '1'; + if (--digits > 0) + *p++ = '0'; + dec_exp += 1; + } + else + { + gcc_assert (digit <= 10); + *p++ = digit + '0'; + } + + /* Generate subsequent digits. */ + while (--digits > 0) + { + do_multiply (&r, &r, ten); + digit = rtd_divmod (&r, &pten); + *p++ = digit + '0'; + } + last = p; + + /* Generate one more digit with which to do rounding. */ + do_multiply (&r, &r, ten); + digit = rtd_divmod (&r, &pten); + + /* Round the result. */ + if (fmt && fmt->round_towards_zero) + { + /* If the format uses round towards zero when parsing the string + back in, we need to always round away from zero here. */ + if (cmp_significand_0 (&r)) + digit++; + round_up = digit > 0; + } + else + { + if (digit == 5) + { + /* Round to nearest. If R is nonzero there are additional + nonzero digits to be extracted. */ + if (cmp_significand_0 (&r)) + digit++; + /* Round to even. */ + else if ((p[-1] - '0') & 1) + digit++; + } + + round_up = digit > 5; + } + + if (round_up) + { + while (p > first) + { + digit = *--p; + if (digit == '9') + *p = '0'; + else + { + *p = digit + 1; + break; + } + } + + /* Carry out of the first digit. This means we had all 9's and + now have all 0's. "Prepend" a 1 by overwriting the first 0. */ + if (p == first) + { + first[1] = '1'; + dec_exp++; + } + } + + /* Insert the decimal point. */ + first[0] = first[1]; + first[1] = '.'; + + /* If requested, drop trailing zeros. Never crop past "1.0". */ + if (crop_trailing_zeros) + while (last > first + 3 && last[-1] == '0') + last--; + + /* Append the exponent. */ + sprintf (last, "e%+d", dec_exp); + +#ifdef ENABLE_CHECKING + /* Verify that we can read the original value back in. */ + if (mode != VOIDmode) + { + real_from_string (&r, str); + real_convert (&r, mode, &r); + gcc_assert (real_identical (&r, r_orig)); + } +#endif +} + +/* Likewise, except always uses round-to-nearest. */ + +void +real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size, + size_t digits, int crop_trailing_zeros) +{ + real_to_decimal_for_mode (str, r_orig, buf_size, + digits, crop_trailing_zeros, VOIDmode); +} + +/* Render R as a hexadecimal floating point constant. Emit DIGITS + significant digits in the result, bounded by BUF_SIZE. If DIGITS is 0, + choose the maximum for the representation. If CROP_TRAILING_ZEROS, + strip trailing zeros. */ + +void +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 = REAL_EXP (r); + char *p, *first; + char exp_buf[16]; + size_t max_digits; + + switch (r->cl) + { + case rvc_zero: + exp = 0; + break; + case rvc_normal: + break; + case rvc_inf: + strcpy (str, (r->sign ? "-Inf" : "+Inf")); + return; + case rvc_nan: + /* ??? Print the significand as well, if not canonical? */ + sprintf (str, "%c%cNaN", (r->sign ? '-' : '+'), + (r->signalling ? 'S' : 'Q')); + return; + default: + gcc_unreachable (); + } + + if (r->decimal) + { + /* Hexadecimal format for decimal floats is not interesting. */ + strcpy (str, "N/A"); + return; + } + + if (digits == 0) + digits = SIGNIFICAND_BITS / 4; + + /* Bound the number of digits printed by the size of the output buffer. */ + + sprintf (exp_buf, "p%+d", exp); + max_digits = buf_size - strlen (exp_buf) - r->sign - 4 - 1; + gcc_assert (max_digits <= buf_size); + if (digits > max_digits) + digits = max_digits; + + p = str; + if (r->sign) + *p++ = '-'; + *p++ = '0'; + *p++ = 'x'; + *p++ = '0'; + *p++ = '.'; + first = p; + + for (i = SIGSZ - 1; i >= 0; --i) + for (j = HOST_BITS_PER_LONG - 4; j >= 0; j -= 4) + { + *p++ = "0123456789abcdef"[(r->sig[i] >> j) & 15]; + if (--digits == 0) + goto out; + } + + out: + if (crop_trailing_zeros) + while (p > first + 1 && p[-1] == '0') + p--; + + sprintf (p, "p%+d", exp); +} + +/* Initialize R from a decimal or hexadecimal string. The string is + assumed to have been syntax checked already. Return -1 if the + value underflows, +1 if overflows, and 0 otherwise. */ + +int +real_from_string (REAL_VALUE_TYPE *r, const char *str) +{ + int exp = 0; + bool sign = false; + + get_zero (r, 0); + + if (*str == '-') + { + sign = true; + str++; + } + else if (*str == '+') + str++; + + if (!strncmp (str, "QNaN", 4)) + { + get_canonical_qnan (r, sign); + return 0; + } + else if (!strncmp (str, "SNaN", 4)) + { + get_canonical_snan (r, sign); + return 0; + } + else if (!strncmp (str, "Inf", 3)) + { + get_inf (r, sign); + return 0; + } + + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + { + /* Hexadecimal floating point. */ + int pos = SIGNIFICAND_BITS - 4, d; + + str += 2; + + while (*str == '0') + str++; + while (1) + { + d = hex_value (*str); + if (d == _hex_bad) + break; + if (pos >= 0) + { + r->sig[pos / HOST_BITS_PER_LONG] + |= (unsigned long) d << (pos % HOST_BITS_PER_LONG); + pos -= 4; + } + else if (d) + /* Ensure correct rounding by setting last bit if there is + a subsequent nonzero digit. */ + r->sig[0] |= 1; + exp += 4; + str++; + } + if (*str == '.') + { + str++; + if (pos == SIGNIFICAND_BITS - 4) + { + while (*str == '0') + str++, exp -= 4; + } + while (1) + { + d = hex_value (*str); + if (d == _hex_bad) + break; + if (pos >= 0) + { + r->sig[pos / HOST_BITS_PER_LONG] + |= (unsigned long) d << (pos % HOST_BITS_PER_LONG); + pos -= 4; + } + else if (d) + /* Ensure correct rounding by setting last bit if there is + a subsequent nonzero digit. */ + r->sig[0] |= 1; + str++; + } + } + + /* If the mantissa is zero, ignore the exponent. */ + if (!cmp_significand_0 (r)) + goto is_a_zero; + + if (*str == 'p' || *str == 'P') + { + bool exp_neg = false; + + str++; + if (*str == '-') + { + exp_neg = true; + str++; + } + else if (*str == '+') + str++; + + d = 0; + while (ISDIGIT (*str)) + { + d *= 10; + d += *str - '0'; + if (d > MAX_EXP) + { + /* Overflowed the exponent. */ + if (exp_neg) + goto underflow; + else + goto overflow; + } + str++; + } + if (exp_neg) + d = -d; + + exp += d; + } + + r->cl = rvc_normal; + SET_REAL_EXP (r, exp); + + normalize (r); + } + else + { + /* Decimal floating point. */ + const REAL_VALUE_TYPE *ten = ten_to_ptwo (0); + int d; + + while (*str == '0') + str++; + while (ISDIGIT (*str)) + { + d = *str++ - '0'; + do_multiply (r, r, ten); + if (d) + do_add (r, r, real_digit (d), 0); + } + if (*str == '.') + { + str++; + if (r->cl == rvc_zero) + { + while (*str == '0') + str++, exp--; + } + while (ISDIGIT (*str)) + { + d = *str++ - '0'; + do_multiply (r, r, ten); + if (d) + do_add (r, r, real_digit (d), 0); + exp--; + } + } + + /* If the mantissa is zero, ignore the exponent. */ + if (r->cl == rvc_zero) + goto is_a_zero; + + if (*str == 'e' || *str == 'E') + { + bool exp_neg = false; + + str++; + if (*str == '-') + { + exp_neg = true; + str++; + } + else if (*str == '+') + str++; + + d = 0; + while (ISDIGIT (*str)) + { + d *= 10; + d += *str - '0'; + if (d > MAX_EXP) + { + /* Overflowed the exponent. */ + if (exp_neg) + goto underflow; + else + goto overflow; + } + str++; + } + if (exp_neg) + d = -d; + exp += d; + } + + if (exp) + times_pten (r, exp); + } + + r->sign = sign; + return 0; + + is_a_zero: + get_zero (r, sign); + return 0; + + underflow: + get_zero (r, sign); + return -1; + + overflow: + get_inf (r, sign); + return 1; +} + +/* Legacy. Similar, but return the result directly. */ + +REAL_VALUE_TYPE +real_from_string2 (const char *s, enum machine_mode mode) +{ + REAL_VALUE_TYPE r; + + real_from_string (&r, s); + if (mode != VOIDmode) + real_convert (&r, mode, &r); + + return r; +} + +/* Initialize R from string S and desired MODE. */ + +void +real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode) +{ + if (DECIMAL_FLOAT_MODE_P (mode)) + decimal_real_from_string (r, s); + else + real_from_string (r, s); + + if (mode != VOIDmode) + real_convert (r, mode, r); +} + +/* Initialize R from the integer pair HIGH+LOW. */ + +void +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); + else + { + memset (r, 0, sizeof (*r)); + r->cl = rvc_normal; + r->sign = high < 0 && !unsigned_p; + SET_REAL_EXP (r, 2 * HOST_BITS_PER_WIDE_INT); + + if (r->sign) + { + high = ~high; + if (low == 0) + high += 1; + else + low = -low; + } + + if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT) + { + r->sig[SIGSZ-1] = high; + r->sig[SIGSZ-2] = low; + } + else + { + gcc_assert (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT); + r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1; + r->sig[SIGSZ-2] = high; + r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1; + r->sig[SIGSZ-4] = low; + } + + normalize (r); + } + + if (DECIMAL_FLOAT_MODE_P (mode)) + decimal_from_integer (r); + else if (mode != VOIDmode) + real_convert (r, mode, r); +} + +/* Render R, an integral value, as a floating point constant with no + specified exponent. */ + +static void +decimal_integer_string (char *str, const REAL_VALUE_TYPE *r_orig, + size_t buf_size) +{ + int dec_exp, digit, digits; + REAL_VALUE_TYPE r, pten; + char *p; + bool sign; + + r = *r_orig; + + if (r.cl == rvc_zero) + { + strcpy (str, "0."); + return; + } + + sign = r.sign; + r.sign = 0; + + dec_exp = REAL_EXP (&r) * M_LOG10_2; + digits = dec_exp + 1; + gcc_assert ((digits + 2) < (int)buf_size); + + pten = *real_digit (1); + times_pten (&pten, dec_exp); + + p = str; + if (sign) + *p++ = '-'; + + digit = rtd_divmod (&r, &pten); + gcc_assert (digit >= 0 && digit <= 9); + *p++ = digit + '0'; + while (--digits > 0) + { + times_pten (&r, 1); + digit = rtd_divmod (&r, &pten); + *p++ = digit + '0'; + } + *p++ = '.'; + *p++ = '\0'; +} + +/* Convert a real with an integral value to decimal float. */ + +static void +decimal_from_integer (REAL_VALUE_TYPE *r) +{ + char str[256]; + + decimal_integer_string (str, r, sizeof (str) - 1); + decimal_real_from_string (r, str); +} + +/* Returns 10**2**N. */ + +static const REAL_VALUE_TYPE * +ten_to_ptwo (int n) +{ + static REAL_VALUE_TYPE tens[EXP_BITS]; + + gcc_assert (n >= 0); + gcc_assert (n < EXP_BITS); + + if (tens[n].cl == rvc_zero) + { + if (n < (HOST_BITS_PER_WIDE_INT == 64 ? 5 : 4)) + { + HOST_WIDE_INT t = 10; + int i; + + for (i = 0; i < n; ++i) + t *= t; + + real_from_integer (&tens[n], VOIDmode, t, 0, 1); + } + else + { + const REAL_VALUE_TYPE *t = ten_to_ptwo (n - 1); + do_multiply (&tens[n], t, t); + } + } + + return &tens[n]; +} + +/* Returns 10**(-2**N). */ + +static const REAL_VALUE_TYPE * +ten_to_mptwo (int n) +{ + static REAL_VALUE_TYPE tens[EXP_BITS]; + + gcc_assert (n >= 0); + gcc_assert (n < EXP_BITS); + + if (tens[n].cl == rvc_zero) + do_divide (&tens[n], real_digit (1), ten_to_ptwo (n)); + + return &tens[n]; +} + +/* Returns N. */ + +static const REAL_VALUE_TYPE * +real_digit (int n) +{ + static REAL_VALUE_TYPE num[10]; + + gcc_assert (n >= 0); + gcc_assert (n <= 9); + + if (n > 0 && num[n].cl == rvc_zero) + real_from_integer (&num[n], VOIDmode, n, 0, 1); + + return &num[n]; +} + +/* Multiply R by 10**EXP. */ + +static void +times_pten (REAL_VALUE_TYPE *r, int exp) +{ + REAL_VALUE_TYPE pten, *rr; + bool negative = (exp < 0); + int i; + + if (negative) + { + exp = -exp; + pten = *real_digit (1); + rr = &pten; + } + else + rr = r; + + for (i = 0; exp > 0; ++i, exp >>= 1) + if (exp & 1) + do_multiply (rr, rr, ten_to_ptwo (i)); + + if (negative) + do_divide (r, r, &pten); +} + +/* Returns the special REAL_VALUE_TYPE corresponding to 'e'. */ + +const REAL_VALUE_TYPE * +dconst_e_ptr (void) +{ + static REAL_VALUE_TYPE value; + + /* Initialize mathematical constants for constant folding builtins. + These constants need to be given to at least 160 bits precision. */ + if (value.cl == rvc_zero) + { + mpfr_t m; + mpfr_init2 (m, SIGNIFICAND_BITS); + mpfr_set_ui (m, 1, GMP_RNDN); + mpfr_exp (m, m, GMP_RNDN); + real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN); + mpfr_clear (m); + + } + return &value; +} + +/* Returns the special REAL_VALUE_TYPE corresponding to 1/3. */ + +const REAL_VALUE_TYPE * +dconst_third_ptr (void) +{ + static REAL_VALUE_TYPE value; + + /* Initialize mathematical constants for constant folding builtins. + These constants need to be given to at least 160 bits precision. */ + if (value.cl == rvc_zero) + { + real_arithmetic (&value, RDIV_EXPR, &dconst1, real_digit (3)); + } + return &value; +} + +/* Returns the special REAL_VALUE_TYPE corresponding to sqrt(2). */ + +const REAL_VALUE_TYPE * +dconst_sqrt2_ptr (void) +{ + static REAL_VALUE_TYPE value; + + /* Initialize mathematical constants for constant folding builtins. + These constants need to be given to at least 160 bits precision. */ + if (value.cl == rvc_zero) + { + mpfr_t m; + mpfr_init2 (m, SIGNIFICAND_BITS); + mpfr_sqrt_ui (m, 2, GMP_RNDN); + real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN); + mpfr_clear (m); + } + return &value; +} + +/* Fills R with +Inf. */ + +void +real_inf (REAL_VALUE_TYPE *r) +{ + get_inf (r, 0); +} + +/* Fills R with a NaN whose significand is described by STR. If QUIET, + we force a QNaN, else we force an SNaN. The string, if not empty, + is parsed as a number and placed in the significand. Return true + if the string was successfully parsed. */ + +bool +real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet, + enum machine_mode mode) +{ + const struct real_format *fmt; + + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + + if (*str == 0) + { + if (quiet) + get_canonical_qnan (r, 0); + else + get_canonical_snan (r, 0); + } + else + { + int base = 10, d; + + memset (r, 0, sizeof (*r)); + r->cl = rvc_nan; + + /* Parse akin to strtol into the significand of R. */ + + while (ISSPACE (*str)) + str++; + if (*str == '-') + str++; + else if (*str == '+') + str++; + if (*str == '0') + { + str++; + if (*str == 'x' || *str == 'X') + { + base = 16; + str++; + } + else + base = 8; + } + + while ((d = hex_value (*str)) < base) + { + REAL_VALUE_TYPE u; + + switch (base) + { + case 8: + lshift_significand (r, r, 3); + break; + case 16: + lshift_significand (r, r, 4); + break; + case 10: + lshift_significand_1 (&u, r); + lshift_significand (r, r, 3); + add_significands (r, r, &u); + break; + default: + gcc_unreachable (); + } + + get_zero (&u, 0); + u.sig[0] = d; + add_significands (r, r, &u); + + str++; + } + + /* Must have consumed the entire string for success. */ + if (*str != 0) + return false; + + /* 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->pnan); + + /* Our MSB is always unset for NaNs. */ + r->sig[SIGSZ-1] &= ~SIG_MSB; + + /* Force quiet or signalling NaN. */ + 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); + gcc_assert (fmt); + memset (r, 0, sizeof (*r)); + + if (fmt->b == 10) + decimal_real_maxval (r, sign, mode); + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, fmt->emax); + + np2 = SIGNIFICAND_BITS - fmt->p; + memset (r->sig, -1, SIGSZ * sizeof (unsigned long)); + clear_significand_below (r, np2); + + if (fmt->pnan < fmt->p) + /* This is an IBM extended double format made up of two IEEE + doubles. The value of the long double is the sum of the + values of the two parts. The most significant part is + required to be the value of the long double rounded to the + nearest double. Rounding means we need a slightly smaller + value for LDBL_MAX. */ + clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan - 1); + } +} + +/* Fills R with 2**N. */ + +void +real_2expN (REAL_VALUE_TYPE *r, int n, enum machine_mode fmode) +{ + memset (r, 0, sizeof (*r)); + + n++; + if (n > MAX_EXP) + r->cl = rvc_inf; + else if (n < -MAX_EXP) + ; + else + { + r->cl = rvc_normal; + SET_REAL_EXP (r, n); + r->sig[SIGSZ-1] = SIG_MSB; + } + if (DECIMAL_FLOAT_MODE_P (fmode)) + decimal_real_convert (r, fmode, r); +} + + +static void +round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) +{ + int p2, np2, i, w; + int emin2m1, emax2; + bool round_up = false; + + if (r->decimal) + { + if (fmt->b == 10) + { + decimal_round_for_format (fmt, r); + return; + } + /* FIXME. We can come here via fp_easy_constant + (e.g. -O0 on '_Decimal32 x = 1.0 + 2.0dd'), but have not + investigated whether this convert needs to be here, or + something else is missing. */ + decimal_real_convert (r, DFmode, r); + } + + p2 = fmt->p; + emin2m1 = fmt->emin - 1; + emax2 = fmt->emax; + + np2 = SIGNIFICAND_BITS - p2; + switch (r->cl) + { + underflow: + get_zero (r, r->sign); + case rvc_zero: + if (!fmt->has_signed_zero) + r->sign = 0; + return; + + overflow: + get_inf (r, r->sign); + case rvc_inf: + return; + + case rvc_nan: + clear_significand_below (r, np2); + return; + + case rvc_normal: + break; + + default: + gcc_unreachable (); + } + + /* Check the range of the exponent. If we're out of range, + either underflow or overflow. */ + if (REAL_EXP (r) > emax2) + goto overflow; + else if (REAL_EXP (r) <= emin2m1) + { + int diff; + + if (!fmt->has_denorm) + { + /* Don't underflow completely until we've had a chance to round. */ + if (REAL_EXP (r) < emin2m1) + goto underflow; + } + else + { + diff = emin2m1 - REAL_EXP (r) + 1; + if (diff > p2) + goto underflow; + + /* De-normalize the significand. */ + r->sig[0] |= sticky_rshift_significand (r, r, diff); + SET_REAL_EXP (r, REAL_EXP (r) + diff); + } + } + + if (!fmt->round_towards_zero) + { + /* There are P2 true significand bits, followed by one guard bit, + followed by one sticky bit, followed by stuff. Fold nonzero + stuff into the sticky bit. */ + unsigned long sticky; + bool guard, lsb; + + sticky = 0; + for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i) + sticky |= r->sig[i]; + sticky |= r->sig[w] + & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1); + + guard = test_significand_bit (r, np2 - 1); + lsb = test_significand_bit (r, np2); + + /* Round to even. */ + round_up = guard && (sticky || lsb); + } + + if (round_up) + { + REAL_VALUE_TYPE u; + get_zero (&u, 0); + set_significand_bit (&u, np2); + + if (add_significands (r, r, &u)) + { + /* Overflow. Means the significand had been all ones, and + is now all zeros. Need to increase the exponent, and + possibly re-normalize it. */ + SET_REAL_EXP (r, REAL_EXP (r) + 1); + if (REAL_EXP (r) > emax2) + goto overflow; + r->sig[SIGSZ-1] = SIG_MSB; + } + } + + /* Catch underflow that we deferred until after rounding. */ + if (REAL_EXP (r) <= emin2m1) + goto underflow; + + /* Clear out trailing garbage. */ + clear_significand_below (r, np2); +} + +/* Extend or truncate to a new mode. */ + +void +real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *a) +{ + const struct real_format *fmt; + + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + + *r = *a; + + if (a->decimal || fmt->b == 10) + decimal_real_convert (r, mode, a); + + round_for_format (fmt, r); + + /* round_for_format de-normalizes denormals. Undo just that part. */ + if (r->cl == rvc_normal) + normalize (r); +} + +/* Legacy. Likewise, except return the struct directly. */ + +REAL_VALUE_TYPE +real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a) +{ + REAL_VALUE_TYPE r; + real_convert (&r, mode, &a); + return r; +} + +/* Return true if truncating to MODE is exact. */ + +bool +exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a) +{ + const struct real_format *fmt; + REAL_VALUE_TYPE t; + int emin2m1; + + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + + /* Don't allow conversion to denormals. */ + emin2m1 = fmt->emin - 1; + if (REAL_EXP (a) <= emin2m1) + return false; + + /* After conversion to the new mode, the value must be identical. */ + real_convert (&t, mode, a); + return real_identical (&t, a); +} + +/* Write R to the given target format. Place the words of the result + in target word order in BUF. There are always 32 bits in each + long, no matter the size of the host long. + + Legacy: return word 0 for implementing REAL_VALUE_TO_TARGET_SINGLE. */ + +long +real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig, + const struct real_format *fmt) +{ + REAL_VALUE_TYPE r; + long buf1; + + r = *r_orig; + round_for_format (fmt, &r); + + if (!buf) + buf = &buf1; + (*fmt->encode) (fmt, buf, &r); + + return *buf; +} + +/* Similar, but look up the format from MODE. */ + +long +real_to_target (long *buf, const REAL_VALUE_TYPE *r, enum machine_mode mode) +{ + const struct real_format *fmt; + + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + + return real_to_target_fmt (buf, r, fmt); +} + +/* Read R from the given target format. Read the words of the result + in target word order in BUF. There are always 32 bits in each + long, no matter the size of the host long. */ + +void +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 (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode) +{ + const struct real_format *fmt; + + fmt = REAL_MODE_FORMAT (mode); + gcc_assert (fmt); + + (*fmt->decode) (fmt, r, buf); +} + +/* Return the number of bits of the largest binary value that the + significand of MODE will hold. */ +/* ??? Legacy. Should get access to real_format directly. */ + +int +significand_size (enum machine_mode mode) +{ + const struct real_format *fmt; + + fmt = REAL_MODE_FORMAT (mode); + if (fmt == NULL) + return 0; + + if (fmt->b == 10) + { + /* Return the size in bits of the largest binary value that can be + held by the decimal coefficient for this mode. This is one more + than the number of bits required to hold the largest coefficient + of this mode. */ + double log2_10 = 3.3219281; + return fmt->p * log2_10; + } + return fmt->p; +} + +/* Return a hash value for the given real value. */ +/* ??? The "unsigned int" return value is intended to be hashval_t, + but I didn't want to pull hashtab.h into real.h. */ + +unsigned int +real_hash (const REAL_VALUE_TYPE *r) +{ + unsigned int h; + size_t i; + + h = r->cl | (r->sign << 2); + switch (r->cl) + { + case rvc_zero: + case rvc_inf: + return h; + + case rvc_normal: + h |= REAL_EXP (r) << 3; + break; + + case rvc_nan: + if (r->signalling) + h ^= (unsigned int)-1; + if (r->canonical) + return h; + break; + + default: + gcc_unreachable (); + } + + 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 (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 (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) +{ + unsigned long image, sig, exp; + unsigned long sign = r->sign; + bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0; + + image = sign << 31; + sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff; + + switch (r->cl) + { + case rvc_zero: + break; + + case rvc_inf: + if (fmt->has_inf) + image |= 255 << 23; + else + image |= 0x7fffffff; + break; + + case rvc_nan: + if (fmt->has_nans) + { + if (r->canonical) + sig = (fmt->canonical_nan_lsbs_set ? (1 << 22) - 1 : 0); + if (r->signalling == fmt->qnan_msb_set) + sig &= ~(1 << 22); + else + sig |= 1 << 22; + if (sig == 0) + sig = 1 << 21; + + image |= 255 << 23; + image |= sig; + } + else + image |= 0x7fffffff; + break; + + case rvc_normal: + /* 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. */ + if (denormal) + exp = 0; + else + exp = REAL_EXP (r) + 127 - 1; + image |= exp << 23; + image |= sig; + break; + + default: + gcc_unreachable (); + } + + buf[0] = image; +} + +static void +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; + int exp = (image >> 23) & 0xff; + + memset (r, 0, sizeof (*r)); + image <<= HOST_BITS_PER_LONG - 24; + image &= ~SIG_MSB; + + if (exp == 0) + { + if (image && fmt->has_denorm) + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, -126); + r->sig[SIGSZ-1] = image << 1; + normalize (r); + } + else if (fmt->has_signed_zero) + r->sign = sign; + } + else if (exp == 255 && (fmt->has_nans || fmt->has_inf)) + { + if (image) + { + r->cl = rvc_nan; + r->sign = sign; + r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1) + ^ fmt->qnan_msb_set); + r->sig[SIGSZ-1] = image; + } + else + { + r->cl = rvc_inf; + r->sign = sign; + } + } + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp - 127 + 1); + r->sig[SIGSZ-1] = image | SIG_MSB; + } +} + +const struct real_format ieee_single_format = + { + encode_ieee_single, + decode_ieee_single, + 2, + 24, + 24, + -125, + 128, + 31, + 31, + false, + true, + true, + true, + true, + true, + true, + false + }; + +const struct real_format mips_single_format = + { + encode_ieee_single, + decode_ieee_single, + 2, + 24, + 24, + -125, + 128, + 31, + 31, + false, + true, + true, + true, + true, + true, + false, + true + }; + +const struct real_format motorola_single_format = + { + encode_ieee_single, + decode_ieee_single, + 2, + 24, + 24, + -125, + 128, + 31, + 31, + false, + true, + true, + true, + true, + true, + true, + true + }; + +/* SPU Single Precision (Extended-Range Mode) format is the same as IEEE + single precision with the following differences: + - Infinities are not supported. Instead MAX_FLOAT or MIN_FLOAT + are generated. + - NaNs are not supported. + - The range of non-zero numbers in binary is + (001)[1.]000...000 to (255)[1.]111...111. + - Denormals can be represented, but are treated as +0.0 when + used as an operand and are never generated as a result. + - -0.0 can be represented, but a zero result is always +0.0. + - the only supported rounding mode is trunction (towards zero). */ +const struct real_format spu_single_format = + { + encode_ieee_single, + decode_ieee_single, + 2, + 24, + 24, + -125, + 129, + 31, + 31, + true, + false, + false, + false, + true, + true, + false, + false + }; + +/* IEEE double-precision format. */ + +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 (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; + + image_hi = r->sign << 31; + image_lo = 0; + + if (HOST_BITS_PER_LONG == 64) + { + sig_hi = r->sig[SIGSZ-1]; + sig_lo = (sig_hi >> (64 - 53)) & 0xffffffff; + sig_hi = (sig_hi >> (64 - 53 + 1) >> 31) & 0xfffff; + } + else + { + sig_hi = r->sig[SIGSZ-1]; + sig_lo = r->sig[SIGSZ-2]; + sig_lo = (sig_hi << 21) | (sig_lo >> 11); + sig_hi = (sig_hi >> 11) & 0xfffff; + } + + switch (r->cl) + { + case rvc_zero: + break; + + case rvc_inf: + if (fmt->has_inf) + image_hi |= 2047 << 20; + else + { + image_hi |= 0x7fffffff; + image_lo = 0xffffffff; + } + break; + + case rvc_nan: + if (fmt->has_nans) + { + if (r->canonical) + { + if (fmt->canonical_nan_lsbs_set) + { + sig_hi = (1 << 19) - 1; + sig_lo = 0xffffffff; + } + else + { + sig_hi = 0; + sig_lo = 0; + } + } + if (r->signalling == fmt->qnan_msb_set) + sig_hi &= ~(1 << 19); + else + sig_hi |= 1 << 19; + if (sig_hi == 0 && sig_lo == 0) + sig_hi = 1 << 18; + + image_hi |= 2047 << 20; + image_hi |= sig_hi; + image_lo = sig_lo; + } + else + { + image_hi |= 0x7fffffff; + image_lo = 0xffffffff; + } + break; + + case rvc_normal: + /* 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. */ + if (denormal) + exp = 0; + else + exp = REAL_EXP (r) + 1023 - 1; + image_hi |= exp << 20; + image_hi |= sig_hi; + image_lo = sig_lo; + break; + + default: + gcc_unreachable (); + } + + if (FLOAT_WORDS_BIG_ENDIAN) + buf[0] = image_hi, buf[1] = image_lo; + else + buf[0] = image_lo, buf[1] = image_hi; +} + +static void +decode_ieee_double (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + unsigned long image_hi, image_lo; + bool sign; + int exp; + + if (FLOAT_WORDS_BIG_ENDIAN) + image_hi = buf[0], image_lo = buf[1]; + else + image_lo = buf[0], image_hi = buf[1]; + image_lo &= 0xffffffff; + image_hi &= 0xffffffff; + + sign = (image_hi >> 31) & 1; + exp = (image_hi >> 20) & 0x7ff; + + memset (r, 0, sizeof (*r)); + + image_hi <<= 32 - 21; + image_hi |= image_lo >> 21; + image_hi &= 0x7fffffff; + image_lo <<= 32 - 21; + + if (exp == 0) + { + if ((image_hi || image_lo) && fmt->has_denorm) + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, -1022); + if (HOST_BITS_PER_LONG == 32) + { + image_hi = (image_hi << 1) | (image_lo >> 31); + image_lo <<= 1; + r->sig[SIGSZ-1] = image_hi; + r->sig[SIGSZ-2] = image_lo; + } + else + { + image_hi = (image_hi << 31 << 2) | (image_lo << 1); + r->sig[SIGSZ-1] = image_hi; + } + normalize (r); + } + else if (fmt->has_signed_zero) + r->sign = sign; + } + else if (exp == 2047 && (fmt->has_nans || fmt->has_inf)) + { + if (image_hi || image_lo) + { + r->cl = 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; + r->sig[SIGSZ-2] = image_lo; + } + else + r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo; + } + else + { + r->cl = rvc_inf; + r->sign = sign; + } + } + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp - 1023 + 1); + if (HOST_BITS_PER_LONG == 32) + { + r->sig[SIGSZ-1] = image_hi | SIG_MSB; + r->sig[SIGSZ-2] = image_lo; + } + else + r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo | SIG_MSB; + } +} + +const struct real_format ieee_double_format = + { + encode_ieee_double, + decode_ieee_double, + 2, + 53, + 53, + -1021, + 1024, + 63, + 63, + false, + true, + true, + true, + true, + true, + true, + false + }; + +const struct real_format mips_double_format = + { + encode_ieee_double, + decode_ieee_double, + 2, + 53, + 53, + -1021, + 1024, + 63, + 63, + false, + true, + true, + true, + true, + true, + false, + true + }; + +const struct real_format motorola_double_format = + { + encode_ieee_double, + decode_ieee_double, + 2, + 53, + 53, + -1021, + 1024, + 63, + 63, + false, + true, + true, + true, + true, + true, + true, + true + }; + +/* 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 (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; + + image_hi = r->sign << 15; + sig_hi = sig_lo = 0; + + switch (r->cl) + { + case rvc_zero: + break; + + case rvc_inf: + if (fmt->has_inf) + { + image_hi |= 32767; + + /* Intel requires the explicit integer bit to be set, otherwise + it considers the value a "pseudo-infinity". Motorola docs + say it doesn't care. */ + sig_hi = 0x80000000; + } + else + { + image_hi |= 32767; + sig_lo = sig_hi = 0xffffffff; + } + break; + + case rvc_nan: + if (fmt->has_nans) + { + image_hi |= 32767; + if (r->canonical) + { + if (fmt->canonical_nan_lsbs_set) + { + sig_hi = (1 << 30) - 1; + sig_lo = 0xffffffff; + } + } + else if (HOST_BITS_PER_LONG == 32) + { + sig_hi = r->sig[SIGSZ-1]; + sig_lo = r->sig[SIGSZ-2]; + } + else + { + sig_lo = r->sig[SIGSZ-1]; + sig_hi = sig_lo >> 31 >> 1; + sig_lo &= 0xffffffff; + } + 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 + doesn't care. */ + sig_hi |= 0x80000000; + } + else + { + image_hi |= 32767; + sig_lo = sig_hi = 0xffffffff; + } + break; + + case rvc_normal: + { + int exp = REAL_EXP (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. + + Except for Motorola, which consider exp=0 and explicit + integer bit set to continue to be normalized. In theory + this discrepancy has been taken care of by the difference + in fmt->emin in round_for_format. */ + + if (denormal) + exp = 0; + else + { + exp += 16383 - 1; + gcc_assert (exp >= 0); + } + image_hi |= exp; + + if (HOST_BITS_PER_LONG == 32) + { + sig_hi = r->sig[SIGSZ-1]; + sig_lo = r->sig[SIGSZ-2]; + } + else + { + sig_lo = r->sig[SIGSZ-1]; + sig_hi = sig_lo >> 31 >> 1; + sig_lo &= 0xffffffff; + } + } + break; + + default: + gcc_unreachable (); + } + + 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) + { + /* 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 + /* 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_intel_128 (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *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 (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + unsigned long image_hi, sig_hi, sig_lo; + bool sign; + int exp; + + sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2]; + sig_lo &= 0xffffffff; + sig_hi &= 0xffffffff; + image_hi &= 0xffffffff; + + sign = (image_hi >> 15) & 1; + exp = image_hi & 0x7fff; + + memset (r, 0, sizeof (*r)); + + if (exp == 0) + { + if ((sig_hi || sig_lo) && fmt->has_denorm) + { + r->cl = rvc_normal; + r->sign = sign; + + /* When the IEEE format contains a hidden bit, we know that + it's zero at this point, and so shift up the significand + and decrease the exponent to match. In this case, Motorola + defines the explicit integer bit to be valid, so we don't + know whether the msb is set or not. */ + SET_REAL_EXP (r, fmt->emin); + if (HOST_BITS_PER_LONG == 32) + { + r->sig[SIGSZ-1] = sig_hi; + r->sig[SIGSZ-2] = sig_lo; + } + else + r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo; + + normalize (r); + } + else if (fmt->has_signed_zero) + r->sign = sign; + } + else if (exp == 32767 && (fmt->has_nans || fmt->has_inf)) + { + /* See above re "pseudo-infinities" and "pseudo-nans". + Short summary is that the MSB will likely always be + set, and that we don't care about it. */ + sig_hi &= 0x7fffffff; + + if (sig_hi || sig_lo) + { + r->cl = 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; + r->sig[SIGSZ-2] = sig_lo; + } + else + r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo; + } + else + { + r->cl = rvc_inf; + r->sign = sign; + } + } + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp - 16383 + 1); + if (HOST_BITS_PER_LONG == 32) + { + r->sig[SIGSZ-1] = sig_hi; + r->sig[SIGSZ-2] = sig_lo; + } + else + r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo; + } +} + +/* 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_intel_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + /* 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 = + { + encode_ieee_extended_motorola, + decode_ieee_extended_motorola, + 2, + 64, + 64, + -16382, + 16384, + 95, + 95, + false, + true, + true, + true, + true, + true, + true, + true + }; + +const struct real_format ieee_extended_intel_96_format = + { + encode_ieee_extended_intel_96, + decode_ieee_extended_intel_96, + 2, + 64, + 64, + -16381, + 16384, + 79, + 79, + false, + true, + true, + true, + true, + true, + true, + false + }; + +const struct real_format ieee_extended_intel_128_format = + { + encode_ieee_extended_intel_128, + decode_ieee_extended_intel_128, + 2, + 64, + 64, + -16381, + 16384, + 79, + 79, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* 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 = + { + encode_ieee_extended_intel_96, + decode_ieee_extended_intel_96, + 2, + 53, + 53, + -16381, + 16384, + 79, + 79, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* IBM 128-bit extended precision format: a pair of IEEE double precision + numbers whose sum is equal to the extended precision value. The number + with greater magnitude is first. This format has the same magnitude + range as an IEEE double precision value, but effectively 106 bits of + significand precision. Infinity and NaN are represented by their IEEE + double precision value stored in the first number, the second number is + +0.0 or -0.0 for Infinity and don't-care for NaN. */ + +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 (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) +{ + REAL_VALUE_TYPE u, normr, v; + const struct real_format *base_fmt; + + base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format; + + /* Renormalize R before doing any arithmetic on it. */ + normr = *r; + if (normr.cl == rvc_normal) + normalize (&normr); + + /* u = IEEE double precision portion of significand. */ + u = normr; + round_for_format (base_fmt, &u); + encode_ieee_double (base_fmt, &buf[0], &u); + + if (u.cl == 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 (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; + + base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format; + decode_ieee_double (base_fmt, &u, &buf[0]); + + if (u.cl != rvc_zero && u.cl != rvc_inf && u.cl != rvc_nan) + { + decode_ieee_double (base_fmt, &v, &buf[2]); + do_add (r, &u, &v, 0); + } + else + *r = u; +} + +const struct real_format ibm_extended_format = + { + encode_ibm_extended, + decode_ibm_extended, + 2, + 53 + 53, + 53, + -1021 + 53, + 1024, + 127, + -1, + false, + true, + true, + true, + true, + true, + true, + false + }; + +const struct real_format mips_extended_format = + { + encode_ibm_extended, + decode_ibm_extended, + 2, + 53 + 53, + 53, + -1021 + 53, + 1024, + 127, + -1, + false, + true, + true, + true, + true, + true, + false, + true + }; + + +/* IEEE quad precision format. */ + +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 (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; + REAL_VALUE_TYPE u; + + image3 = r->sign << 31; + image2 = 0; + image1 = 0; + image0 = 0; + + rshift_significand (&u, r, SIGNIFICAND_BITS - 113); + + switch (r->cl) + { + case rvc_zero: + break; + + case rvc_inf: + if (fmt->has_inf) + image3 |= 32767 << 16; + else + { + image3 |= 0x7fffffff; + image2 = 0xffffffff; + image1 = 0xffffffff; + image0 = 0xffffffff; + } + break; + + case rvc_nan: + if (fmt->has_nans) + { + image3 |= 32767 << 16; + + if (r->canonical) + { + if (fmt->canonical_nan_lsbs_set) + { + image3 |= 0x7fff; + image2 = image1 = image0 = 0xffffffff; + } + } + else if (HOST_BITS_PER_LONG == 32) + { + image0 = u.sig[0]; + image1 = u.sig[1]; + image2 = u.sig[2]; + image3 |= u.sig[3] & 0xffff; + } + else + { + image0 = u.sig[0]; + image1 = image0 >> 31 >> 1; + image2 = u.sig[1]; + image3 |= (image2 >> 31 >> 1) & 0xffff; + image0 &= 0xffffffff; + image2 &= 0xffffffff; + } + if (r->signalling == fmt->qnan_msb_set) + image3 &= ~0x8000; + else + image3 |= 0x8000; + if (((image3 & 0xffff) | image2 | image1 | image0) == 0) + image3 |= 0x4000; + } + else + { + image3 |= 0x7fffffff; + image2 = 0xffffffff; + image1 = 0xffffffff; + image0 = 0xffffffff; + } + break; + + case rvc_normal: + /* 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. */ + if (denormal) + exp = 0; + else + exp = REAL_EXP (r) + 16383 - 1; + image3 |= exp << 16; + + if (HOST_BITS_PER_LONG == 32) + { + image0 = u.sig[0]; + image1 = u.sig[1]; + image2 = u.sig[2]; + image3 |= u.sig[3] & 0xffff; + } + else + { + image0 = u.sig[0]; + image1 = image0 >> 31 >> 1; + image2 = u.sig[1]; + image3 |= (image2 >> 31 >> 1) & 0xffff; + image0 &= 0xffffffff; + image2 &= 0xffffffff; + } + break; + + default: + gcc_unreachable (); + } + + if (FLOAT_WORDS_BIG_ENDIAN) + { + buf[0] = image3; + buf[1] = image2; + buf[2] = image1; + buf[3] = image0; + } + else + { + buf[0] = image0; + buf[1] = image1; + buf[2] = image2; + buf[3] = image3; + } +} + +static void +decode_ieee_quad (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + unsigned long image3, image2, image1, image0; + bool sign; + int exp; + + if (FLOAT_WORDS_BIG_ENDIAN) + { + image3 = buf[0]; + image2 = buf[1]; + image1 = buf[2]; + image0 = buf[3]; + } + else + { + image0 = buf[0]; + image1 = buf[1]; + image2 = buf[2]; + image3 = buf[3]; + } + image0 &= 0xffffffff; + image1 &= 0xffffffff; + image2 &= 0xffffffff; + + sign = (image3 >> 31) & 1; + exp = (image3 >> 16) & 0x7fff; + image3 &= 0xffff; + + memset (r, 0, sizeof (*r)); + + if (exp == 0) + { + if ((image3 | image2 | image1 | image0) && fmt->has_denorm) + { + r->cl = rvc_normal; + r->sign = sign; + + SET_REAL_EXP (r, -16382 + (SIGNIFICAND_BITS - 112)); + if (HOST_BITS_PER_LONG == 32) + { + r->sig[0] = image0; + r->sig[1] = image1; + r->sig[2] = image2; + r->sig[3] = image3; + } + else + { + r->sig[0] = (image1 << 31 << 1) | image0; + r->sig[1] = (image3 << 31 << 1) | image2; + } + + normalize (r); + } + else if (fmt->has_signed_zero) + r->sign = sign; + } + else if (exp == 32767 && (fmt->has_nans || fmt->has_inf)) + { + if (image3 | image2 | image1 | image0) + { + r->cl = rvc_nan; + r->sign = sign; + r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set; + + if (HOST_BITS_PER_LONG == 32) + { + r->sig[0] = image0; + r->sig[1] = image1; + r->sig[2] = image2; + r->sig[3] = image3; + } + else + { + r->sig[0] = (image1 << 31 << 1) | image0; + r->sig[1] = (image3 << 31 << 1) | image2; + } + lshift_significand (r, r, SIGNIFICAND_BITS - 113); + } + else + { + r->cl = rvc_inf; + r->sign = sign; + } + } + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp - 16383 + 1); + + if (HOST_BITS_PER_LONG == 32) + { + r->sig[0] = image0; + r->sig[1] = image1; + r->sig[2] = image2; + r->sig[3] = image3; + } + else + { + r->sig[0] = (image1 << 31 << 1) | image0; + r->sig[1] = (image3 << 31 << 1) | image2; + } + lshift_significand (r, r, SIGNIFICAND_BITS - 113); + r->sig[SIGSZ-1] |= SIG_MSB; + } +} + +const struct real_format ieee_quad_format = + { + encode_ieee_quad, + decode_ieee_quad, + 2, + 113, + 113, + -16381, + 16384, + 127, + 127, + false, + true, + true, + true, + true, + true, + true, + false + }; + +const struct real_format mips_quad_format = + { + encode_ieee_quad, + decode_ieee_quad, + 2, + 113, + 113, + -16381, + 16384, + 127, + 127, + false, + true, + true, + true, + true, + true, + false, + true + }; + +/* Descriptions of VAX floating point formats can be found beginning at + + 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 (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 (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) +{ + unsigned long sign, exp, sig, image; + + sign = r->sign << 15; + + switch (r->cl) + { + case rvc_zero: + image = 0; + break; + + case rvc_inf: + case rvc_nan: + image = 0xffff7fff | sign; + break; + + case rvc_normal: + sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff; + exp = REAL_EXP (r) + 128; + + image = (sig << 16) & 0xffff0000; + image |= sign; + image |= exp << 7; + image |= sig >> 16; + break; + + default: + gcc_unreachable (); + } + + buf[0] = image; +} + +static void +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; + + memset (r, 0, sizeof (*r)); + + if (exp != 0) + { + r->cl = rvc_normal; + r->sign = (image >> 15) & 1; + SET_REAL_EXP (r, exp - 128); + + image = ((image & 0x7f) << 16) | ((image >> 16) & 0xffff); + r->sig[SIGSZ-1] = (image << (HOST_BITS_PER_LONG - 24)) | SIG_MSB; + } +} + +static void +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; + + switch (r->cl) + { + case rvc_zero: + image0 = image1 = 0; + break; + + case rvc_inf: + case rvc_nan: + image0 = 0xffff7fff | sign; + image1 = 0xffffffff; + break; + + case rvc_normal: + /* Extract the significand into straight hi:lo. */ + if (HOST_BITS_PER_LONG == 64) + { + image0 = r->sig[SIGSZ-1]; + image1 = (image0 >> (64 - 56)) & 0xffffffff; + image0 = (image0 >> (64 - 56 + 1) >> 31) & 0x7fffff; + } + else + { + image0 = r->sig[SIGSZ-1]; + image1 = r->sig[SIGSZ-2]; + image1 = (image0 << 24) | (image1 >> 8); + image0 = (image0 >> 8) & 0xffffff; + } + + /* Rearrange the half-words of the significand to match the + external format. */ + image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff007f; + image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff; + + /* Add the sign and exponent. */ + image0 |= sign; + image0 |= (REAL_EXP (r) + 128) << 7; + break; + + default: + gcc_unreachable (); + } + + if (FLOAT_WORDS_BIG_ENDIAN) + buf[0] = image1, buf[1] = image0; + else + buf[0] = image0, buf[1] = image1; +} + +static void +decode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + unsigned long image0, image1; + int exp; + + if (FLOAT_WORDS_BIG_ENDIAN) + image1 = buf[0], image0 = buf[1]; + else + image0 = buf[0], image1 = buf[1]; + image0 &= 0xffffffff; + image1 &= 0xffffffff; + + exp = (image0 >> 7) & 0xff; + + memset (r, 0, sizeof (*r)); + + if (exp != 0) + { + r->cl = rvc_normal; + r->sign = (image0 >> 15) & 1; + SET_REAL_EXP (r, exp - 128); + + /* Rearrange the half-words of the external format into + proper ascending order. */ + image0 = ((image0 & 0x7f) << 16) | ((image0 >> 16) & 0xffff); + image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff); + + if (HOST_BITS_PER_LONG == 64) + { + image0 = (image0 << 31 << 1) | image1; + image0 <<= 64 - 56; + image0 |= SIG_MSB; + r->sig[SIGSZ-1] = image0; + } + else + { + r->sig[SIGSZ-1] = image0; + r->sig[SIGSZ-2] = image1; + lshift_significand (r, r, 2*HOST_BITS_PER_LONG - 56); + r->sig[SIGSZ-1] |= SIG_MSB; + } + } +} + +static void +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; + + switch (r->cl) + { + case rvc_zero: + image0 = image1 = 0; + break; + + case rvc_inf: + case rvc_nan: + image0 = 0xffff7fff | sign; + image1 = 0xffffffff; + break; + + case rvc_normal: + /* Extract the significand into straight hi:lo. */ + if (HOST_BITS_PER_LONG == 64) + { + image0 = r->sig[SIGSZ-1]; + image1 = (image0 >> (64 - 53)) & 0xffffffff; + image0 = (image0 >> (64 - 53 + 1) >> 31) & 0xfffff; + } + else + { + image0 = r->sig[SIGSZ-1]; + image1 = r->sig[SIGSZ-2]; + image1 = (image0 << 21) | (image1 >> 11); + image0 = (image0 >> 11) & 0xfffff; + } + + /* Rearrange the half-words of the significand to match the + external format. */ + image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff000f; + image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff; + + /* Add the sign and exponent. */ + image0 |= sign; + image0 |= (REAL_EXP (r) + 1024) << 4; + break; + + default: + gcc_unreachable (); + } + + if (FLOAT_WORDS_BIG_ENDIAN) + buf[0] = image1, buf[1] = image0; + else + buf[0] = image0, buf[1] = image1; +} + +static void +decode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + unsigned long image0, image1; + int exp; + + if (FLOAT_WORDS_BIG_ENDIAN) + image1 = buf[0], image0 = buf[1]; + else + image0 = buf[0], image1 = buf[1]; + image0 &= 0xffffffff; + image1 &= 0xffffffff; + + exp = (image0 >> 4) & 0x7ff; + + memset (r, 0, sizeof (*r)); + + if (exp != 0) + { + r->cl = rvc_normal; + r->sign = (image0 >> 15) & 1; + SET_REAL_EXP (r, exp - 1024); + + /* Rearrange the half-words of the external format into + proper ascending order. */ + image0 = ((image0 & 0xf) << 16) | ((image0 >> 16) & 0xffff); + image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff); + + if (HOST_BITS_PER_LONG == 64) + { + image0 = (image0 << 31 << 1) | image1; + image0 <<= 64 - 53; + image0 |= SIG_MSB; + r->sig[SIGSZ-1] = image0; + } + else + { + r->sig[SIGSZ-1] = image0; + r->sig[SIGSZ-2] = image1; + lshift_significand (r, r, 64 - 53); + r->sig[SIGSZ-1] |= SIG_MSB; + } + } +} + +const struct real_format vax_f_format = + { + encode_vax_f, + decode_vax_f, + 2, + 24, + 24, + -127, + 127, + 15, + 15, + false, + false, + false, + false, + false, + false, + false, + false + }; + +const struct real_format vax_d_format = + { + encode_vax_d, + decode_vax_d, + 2, + 56, + 56, + -127, + 127, + 15, + 15, + false, + false, + false, + false, + false, + false, + false, + false + }; + +const struct real_format vax_g_format = + { + encode_vax_g, + decode_vax_g, + 2, + 53, + 53, + -1023, + 1023, + 15, + 15, + false, + false, + false, + false, + false, + false, + false, + false + }; + +/* Encode real R into a single precision DFP value in BUF. */ +static void +encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf ATTRIBUTE_UNUSED, + const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED) +{ + encode_decimal32 (fmt, buf, r); +} + +/* Decode a single precision DFP value in BUF into a real R. */ +static void +decode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED, + const long *buf ATTRIBUTE_UNUSED) +{ + decode_decimal32 (fmt, r, buf); +} + +/* Encode real R into a double precision DFP value in BUF. */ +static void +encode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf ATTRIBUTE_UNUSED, + const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED) +{ + encode_decimal64 (fmt, buf, r); +} + +/* Decode a double precision DFP value in BUF into a real R. */ +static void +decode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED, + const long *buf ATTRIBUTE_UNUSED) +{ + decode_decimal64 (fmt, r, buf); +} + +/* Encode real R into a quad precision DFP value in BUF. */ +static void +encode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf ATTRIBUTE_UNUSED, + const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED) +{ + encode_decimal128 (fmt, buf, r); +} + +/* Decode a quad precision DFP value in BUF into a real R. */ +static void +decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED, + const long *buf ATTRIBUTE_UNUSED) +{ + decode_decimal128 (fmt, r, buf); +} + +/* Single precision decimal floating point (IEEE 754). */ +const struct real_format decimal_single_format = + { + encode_decimal_single, + decode_decimal_single, + 10, + 7, + 7, + -94, + 97, + 31, + 31, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* Double precision decimal floating point (IEEE 754). */ +const struct real_format decimal_double_format = + { + encode_decimal_double, + decode_decimal_double, + 10, + 16, + 16, + -382, + 385, + 63, + 63, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* Quad precision decimal floating point (IEEE 754). */ +const struct real_format decimal_quad_format = + { + encode_decimal_quad, + decode_decimal_quad, + 10, + 34, + 34, + -6142, + 6145, + 127, + 127, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* Encode half-precision floats. This routine is used both for the IEEE + ARM alternative encodings. */ +static void +encode_ieee_half (const struct real_format *fmt, long *buf, + const REAL_VALUE_TYPE *r) +{ + unsigned long image, sig, exp; + unsigned long sign = r->sign; + bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0; + + image = sign << 15; + sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 11)) & 0x3ff; + + switch (r->cl) + { + case rvc_zero: + break; + + case rvc_inf: + if (fmt->has_inf) + image |= 31 << 10; + else + image |= 0x7fff; + break; + + case rvc_nan: + if (fmt->has_nans) + { + if (r->canonical) + sig = (fmt->canonical_nan_lsbs_set ? (1 << 9) - 1 : 0); + if (r->signalling == fmt->qnan_msb_set) + sig &= ~(1 << 9); + else + sig |= 1 << 9; + if (sig == 0) + sig = 1 << 8; + + image |= 31 << 10; + image |= sig; + } + else + image |= 0x3ff; + break; + + case rvc_normal: + /* 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. */ + if (denormal) + exp = 0; + else + exp = REAL_EXP (r) + 15 - 1; + image |= exp << 10; + image |= sig; + break; + + default: + gcc_unreachable (); + } + + buf[0] = image; +} + +/* Decode half-precision floats. This routine is used both for the IEEE + ARM alternative encodings. */ +static void +decode_ieee_half (const struct real_format *fmt, REAL_VALUE_TYPE *r, + const long *buf) +{ + unsigned long image = buf[0] & 0xffff; + bool sign = (image >> 15) & 1; + int exp = (image >> 10) & 0x1f; + + memset (r, 0, sizeof (*r)); + image <<= HOST_BITS_PER_LONG - 11; + image &= ~SIG_MSB; + + if (exp == 0) + { + if (image && fmt->has_denorm) + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, -14); + r->sig[SIGSZ-1] = image << 1; + normalize (r); + } + else if (fmt->has_signed_zero) + r->sign = sign; + } + else if (exp == 31 && (fmt->has_nans || fmt->has_inf)) + { + if (image) + { + r->cl = rvc_nan; + r->sign = sign; + r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1) + ^ fmt->qnan_msb_set); + r->sig[SIGSZ-1] = image; + } + else + { + r->cl = rvc_inf; + r->sign = sign; + } + } + else + { + r->cl = rvc_normal; + r->sign = sign; + SET_REAL_EXP (r, exp - 15 + 1); + r->sig[SIGSZ-1] = image | SIG_MSB; + } +} + +/* Half-precision format, as specified in IEEE 754R. */ +const struct real_format ieee_half_format = + { + encode_ieee_half, + decode_ieee_half, + 2, + 11, + 11, + -13, + 16, + 15, + 15, + false, + true, + true, + true, + true, + true, + true, + false + }; + +/* ARM's alternative half-precision format, similar to IEEE but with + no reserved exponent value for NaNs and infinities; rather, it just + extends the range of exponents by one. */ +const struct real_format arm_half_format = + { + encode_ieee_half, + decode_ieee_half, + 2, + 11, + 11, + -13, + 17, + 15, + 15, + false, + true, + false, + false, + true, + true, + false, + false + }; + +/* A synthetic "format" for internal arithmetic. It's the size of the + internal significand minus the two bits needed for proper rounding. + The encode and decode routines exist only to satisfy our paranoia + harness. */ + +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 (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf, + const REAL_VALUE_TYPE *r) +{ + memcpy (buf, r, sizeof (*r)); +} + +static void +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 = + { + encode_internal, + decode_internal, + 2, + SIGNIFICAND_BITS - 2, + SIGNIFICAND_BITS - 2, + -MAX_EXP, + MAX_EXP, + -1, + -1, + false, + false, + true, + true, + false, + true, + true, + false + }; + +/* 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. */ + +bool +real_sqrt (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) +{ + 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_isfinite (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) +{ + REAL_VALUE_TYPE t; + + do_fix_trunc (&t, x); + if (! real_identical (&t, x) && x->sign) + do_add (&t, &t, &dconstm1, 0); + if (mode != VOIDmode) + real_convert (r, mode, &t); + else + *r = t; +} + +/* 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) +{ + REAL_VALUE_TYPE t; + + do_fix_trunc (&t, x); + if (! real_identical (&t, x) && ! x->sign) + do_add (&t, &t, &dconst1, 0); + if (mode != VOIDmode) + real_convert (r, mode, &t); + else + *r = t; +} + +/* Round X to the nearest integer, but round halfway cases away from + zero. */ + +void +real_round (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *x) +{ + do_add (r, x, &dconsthalf, x->sign); + do_fix_trunc (r, r); + if (mode != VOIDmode) + real_convert (r, mode, r); +} + +/* Set the sign of R to the sign of X. */ + +void +real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x) +{ + r->sign = x->sign; +} + +/* Check whether the real constant value given is an integer. */ + +bool +real_isinteger (const REAL_VALUE_TYPE *c, enum machine_mode mode) +{ + REAL_VALUE_TYPE cint; + + real_trunc (&cint, mode, c); + return real_identical (c, &cint); +} + +/* Write into BUF the maximum representable finite floating-point + number, (1 - b**-p) * b**emax for a given FP format FMT as a hex + float string. LEN is the size of BUF, and the buffer must be large + enough to contain the resulting string. */ + +void +get_max_float (const struct real_format *fmt, char *buf, size_t len) +{ + int i, n; + char *p; + + strcpy (buf, "0x0."); + n = fmt->p; + for (i = 0, p = buf + 4; i + 3 < n; i += 4) + *p++ = 'f'; + if (i < n) + *p++ = "08ce"[n - i]; + sprintf (p, "p%d", fmt->emax); + if (fmt->pnan < fmt->p) + { + /* This is an IBM extended double format made up of two IEEE + doubles. The value of the long double is the sum of the + values of the two parts. The most significant part is + required to be the value of the long double rounded to the + nearest double. Rounding means we need a slightly smaller + value for LDBL_MAX. */ + buf[4 + fmt->pnan / 4] = "7bde"[fmt->pnan % 4]; + } + + gcc_assert (strlen (buf) < len); +} -- cgit v1.2.3