/* real.c - software floating point emulation.
- Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2002, 2003 Free Software Foundation, Inc.
Contributed by Stephen L. Moshier (moshier@world.std.com).
Re-written by Richard Henderson <rth@redhat.com>
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "toplev.h"
#include "real.h"
significand is fractional. Normalized significands are in the
range [0.5, 1.0).
- A requirement of the model is that P be larger than than the
+ A requirement of the model is that P be larger than than the
largest supported target floating-point type by at least 2 bits.
This gives us proper rounding when we truncate to the target type.
In addition, E must be large enough to hold the smallest supported
denormal number in a normalized form.
- Both of these requirements are easily satisfied. The largest
- target significand is 113 bits; we store 128. The smallest
+ Both of these requirements are easily satisfied. The largest target
+ significand is 113 bits; we store at least 160. The smallest
denormal number fits in 17 exponent bits; we store 29.
+ Note that the decimal string conversion routines are sensitive to
+ rounding error. 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.
+
Target floating point models that use base 16 instead of base 2
(i.e. IBM 370), are handled during round_for_format, in which we
canonicalize the exponent to be a multiple of 4 (log2(16)), and
#error "Some constant folding done by hand to avoid shift count warnings"
#endif
-static void get_zero PARAMS ((REAL_VALUE_TYPE *, int));
-static void get_canonical_qnan PARAMS ((REAL_VALUE_TYPE *, int));
-static void get_canonical_snan PARAMS ((REAL_VALUE_TYPE *, int));
-static void get_inf PARAMS ((REAL_VALUE_TYPE *, int));
-static void sticky_rshift_significand PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- unsigned int));
-static void rshift_significand PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- unsigned int));
-static void lshift_significand PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- unsigned int));
-static void lshift_significand_1 PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static bool add_significands PARAMS ((REAL_VALUE_TYPE *r,
- const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static bool sub_significands PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static void neg_significand PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static int cmp_significands PARAMS ((const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static void set_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
-static void clear_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
-static bool test_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
-static void clear_significand_below PARAMS ((REAL_VALUE_TYPE *,
- unsigned int));
-static bool div_significands PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static void normalize PARAMS ((REAL_VALUE_TYPE *));
-
-static void do_add PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *, int));
-static void do_multiply PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static void do_divide PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-static int do_compare PARAMS ((const REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *, int));
-static void do_fix_trunc PARAMS ((REAL_VALUE_TYPE *,
- const REAL_VALUE_TYPE *));
-
-static const REAL_VALUE_TYPE * ten_to_ptwo PARAMS ((int));
-static const REAL_VALUE_TYPE * real_digit PARAMS ((int));
-
-static void round_for_format PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *));
+static void get_zero (REAL_VALUE_TYPE *, int);
+static void get_canonical_qnan (REAL_VALUE_TYPE *, int);
+static void get_canonical_snan (REAL_VALUE_TYPE *, int);
+static void get_inf (REAL_VALUE_TYPE *, int);
+static bool sticky_rshift_significand (REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, unsigned int);
+static void rshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ unsigned int);
+static void lshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ unsigned int);
+static void lshift_significand_1 (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static bool add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static bool sub_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, int);
+static void neg_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static int cmp_significands (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static int cmp_significand_0 (const REAL_VALUE_TYPE *);
+static void set_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static void clear_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static bool test_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static void clear_significand_below (REAL_VALUE_TYPE *, unsigned int);
+static bool div_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static void normalize (REAL_VALUE_TYPE *);
+
+static bool do_add (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, int);
+static bool do_multiply (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static bool do_divide (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int);
+static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+
+static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *);
+
+static const REAL_VALUE_TYPE * ten_to_ptwo (int);
+static const REAL_VALUE_TYPE * ten_to_mptwo (int);
+static const REAL_VALUE_TYPE * real_digit (int);
+static void times_pten (REAL_VALUE_TYPE *, int);
+
+static void round_for_format (const struct real_format *, REAL_VALUE_TYPE *);
\f
/* Initialize R with a positive zero. */
static inline void
-get_zero (r, sign)
- REAL_VALUE_TYPE *r;
- int sign;
+get_zero (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->sign = sign;
/* Initialize R with the canonical quiet NaN. */
static inline void
-get_canonical_qnan (r, sign)
- REAL_VALUE_TYPE *r;
- int sign;
+get_canonical_qnan (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->class = rvc_nan;
r->sign = sign;
- r->sig[SIGSZ-1] = SIG_MSB >> 1;
+ r->canonical = 1;
}
static inline void
-get_canonical_snan (r, sign)
- REAL_VALUE_TYPE *r;
- int sign;
+get_canonical_snan (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->class = rvc_nan;
r->sign = sign;
- r->sig[SIGSZ-1] = SIG_MSB >> 2;
+ r->signalling = 1;
+ r->canonical = 1;
}
static inline void
-get_inf (r, sign)
- REAL_VALUE_TYPE *r;
- int sign;
+get_inf (REAL_VALUE_TYPE *r, int sign)
{
memset (r, 0, sizeof (*r));
r->class = rvc_inf;
\f
/* Right-shift the significand of A by N bits; put the result in the
- significand of R. If any one bits are shifted out, set the least
- significant bit of R. */
+ significand of R. If any one bits are shifted out, return true. */
-static void
-sticky_rshift_significand (r, a, n)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
- unsigned int n;
+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;
{
for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i)
sticky |= a->sig[i];
- n -= ofs * HOST_BITS_PER_LONG;
+ n &= HOST_BITS_PER_LONG - 1;
}
if (n != 0)
r->sig[i] = 0;
}
- r->sig[0] |= (sticky != 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 (r, a, n)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
- unsigned int n;
+rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ unsigned int n)
{
unsigned int i, ofs = n / HOST_BITS_PER_LONG;
- n -= ofs * HOST_BITS_PER_LONG;
+ n &= HOST_BITS_PER_LONG - 1;
if (n != 0)
{
for (i = 0; i < SIGSZ; ++i)
significand of R. */
static void
-lshift_significand (r, a, n)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
- unsigned int n;
+lshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ unsigned int n)
{
unsigned int i, ofs = n / HOST_BITS_PER_LONG;
- n -= ofs * HOST_BITS_PER_LONG;
+ n &= HOST_BITS_PER_LONG - 1;
if (n == 0)
{
for (i = 0; ofs + i < SIGSZ; ++i)
/* Likewise, but N is specialized to 1. */
static inline void
-lshift_significand_1 (r, a)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
+lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
unsigned int i;
true if there was carry out of the most significant word. */
static inline bool
-add_significands (r, a, b)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
+add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
bool carry = false;
int i;
if (carry)
{
- carry = ri < ai;
+ carry = ri < ai;
carry |= ++ri == 0;
}
else
- carry = ri < ai;
+ carry = ri < ai;
r->sig[i] = ri;
}
return carry;
}
-/* Subtract the significands of A and B, placing the result in R.
- Return true if there was carry out of the most significant word. */
+/* 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 (r, a, b)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
+sub_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b, int carry)
{
- bool carry = false;
int i;
for (i = 0; i < SIGSZ; ++i)
if (carry)
{
- carry = ri > ai;
+ carry = ri > ai;
carry |= ~--ri == 0;
}
else
- carry = ri > ai;
+ carry = ri > ai;
r->sig[i] = ri;
}
return carry;
-}
+}
/* Negate the significand A, placing the result in R. */
static inline void
-neg_significand (r, a)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
+neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
bool carry = true;
int i;
r->sig[i] = ri;
}
-}
+}
/* Compare significands. Return tri-state vs zero. */
-static inline int
-cmp_significands (a, b)
- const REAL_VALUE_TYPE *a, *b;
+static inline int
+cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
{
int i;
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 (r, n)
- REAL_VALUE_TYPE *r;
- unsigned int n;
+set_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
r->sig[n / HOST_BITS_PER_LONG]
|= (unsigned long)1 << (n % HOST_BITS_PER_LONG);
/* Clear bit N of the significand of R. */
static inline void
-clear_significand_bit (r, n)
- REAL_VALUE_TYPE *r;
- unsigned int n;
+clear_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
r->sig[n / HOST_BITS_PER_LONG]
&= ~((unsigned long)1 << (n % HOST_BITS_PER_LONG));
/* Test bit N of the significand of R. */
static inline bool
-test_significand_bit (r, n)
- REAL_VALUE_TYPE *r;
- unsigned int n;
+test_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
/* ??? Compiler bug here if we return this expression directly.
The conversion to bool strips the "&1" and we wind up testing
/* Clear bits 0..N-1 of the significand of R. */
static void
-clear_significand_below (r, n)
- REAL_VALUE_TYPE *r;
- unsigned int n;
+clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n)
{
int i, w = n / HOST_BITS_PER_LONG;
true if the division was inexact. */
static inline bool
-div_significands (r, a, b)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
+div_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
REAL_VALUE_TYPE u;
- int bit = SIGNIFICAND_BITS - 1;
- int i;
- long inexact;
+ int i, bit = SIGNIFICAND_BITS - 1;
+ unsigned long msb, inexact;
u = *a;
memset (r->sig, 0, sizeof (r->sig));
+ msb = 0;
goto start;
do
{
- if ((u.sig[SIGSZ-1] & SIG_MSB) == 0)
+ msb = u.sig[SIGSZ-1] & SIG_MSB;
+ lshift_significand_1 (&u, &u);
+ start:
+ if (msb || cmp_significands (&u, b) >= 0)
{
- lshift_significand_1 (&u, &u);
- start:
- if (cmp_significands (&u, b) >= 0)
- {
- sub_significands (&u, &u, b);
- set_significand_bit (r, bit);
- }
- }
- else
- {
- /* We lose a bit here, and thus know the next quotient bit
- will be one. */
- lshift_significand_1 (&u, &u);
- sub_significands (&u, &u, b);
+ sub_significands (&u, &u, b, 0);
set_significand_bit (r, bit);
}
}
exponent is large enough to handle target denormals normalized.) */
static void
-normalize (r)
- REAL_VALUE_TYPE *r;
+normalize (REAL_VALUE_TYPE *r)
{
int shift = 0, exp;
int i, j;
}
}
\f
-/* Return R = A + (SUBTRACT_P ? -B : B). */
+/* Calculate R = A + (SUBTRACT_P ? -B : B). Return true if the
+ result may be inexact due to a loss of precision. */
-static void
-do_add (r, a, b, subtract_p)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
- int subtract_p;
+static bool
+do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b, int subtract_p)
{
int dexp, sign, exp;
REAL_VALUE_TYPE t;
+ bool inexact = false;
/* Determine if we need to add or subtract. */
sign = a->sign;
switch (CLASS2 (a->class, b->class))
{
case CLASS2 (rvc_zero, rvc_zero):
- /* +-0 +/- +-0 = +0. */
- get_zero (r, 0);
- return;
+ /* -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):
/* R + Inf = Inf. */
*r = *b;
r->sign = sign ^ subtract_p;
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_zero):
case CLASS2 (rvc_inf, rvc_zero):
case CLASS2 (rvc_inf, rvc_normal):
/* Inf + R = Inf. */
*r = *a;
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_inf):
if (subtract_p)
else
/* Inf + Inf = Inf. */
*r = *a;
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
{
*r = *a;
r->sign = sign;
- return;
+ return true;
}
- sticky_rshift_significand (&t, b, dexp);
+ inexact |= sticky_rshift_significand (&t, b, dexp);
b = &t;
}
if (subtract_p)
{
- if (sub_significands (r, a, b))
+ 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
/* We got carry out of the addition. This means we need to
shift the significand back down one bit and increase the
exponent. */
- sticky_rshift_significand (r, r, 1);
+ inexact |= sticky_rshift_significand (r, r, 1);
r->sig[SIGSZ-1] |= SIG_MSB;
if (++exp > MAX_EXP)
{
get_inf (r, sign);
- return;
+ return true;
}
}
}
is positive. */
if (r->class == rvc_zero)
r->sign = 0;
+ else
+ r->sig[0] |= inexact;
+
+ return inexact;
}
-/* Return R = A * B. */
+/* Calculate R = A * B. Return true if the result may be inexact. */
-static void
-do_multiply (r, a, b)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
+static bool
+do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
REAL_VALUE_TYPE u, t, *rr;
unsigned int i, j, k;
int sign = a->sign ^ b->sign;
+ bool inexact = false;
switch (CLASS2 (a->class, b->class))
{
case CLASS2 (rvc_normal, rvc_zero):
/* +-0 * ANY = 0 with appropriate sign. */
get_zero (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
/* ANY * NaN = NaN. */
*r = *b;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
/* NaN * ANY = NaN. */
*r = *a;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_inf):
case CLASS2 (rvc_inf, rvc_zero):
/* 0 * Inf = NaN */
get_canonical_qnan (r, sign);
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_inf):
case CLASS2 (rvc_normal, rvc_inf):
case CLASS2 (rvc_inf, rvc_normal):
/* Inf * Inf = Inf, R * Inf = Inf */
- overflow:
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
A B C D
* E F G H
--------------
- DE DF DG DH
+ DE DF DG DH
CE CF CG CH
BE BF BG BH
AE AF AG AH
+ (b->exp - (1-j)*(HOST_BITS_PER_LONG/2)));
if (exp > MAX_EXP)
- goto overflow;
+ {
+ get_inf (r, sign);
+ return true;
+ }
if (exp < -MAX_EXP)
- /* Would underflow to zero, which we shouldn't bother adding. */
- continue;
+ {
+ /* Would underflow to zero, which we shouldn't bother adding. */
+ inexact = true;
+ continue;
+ }
u.class = rvc_normal;
u.sign = 0;
}
normalize (&u);
- do_add (rr, rr, &u, 0);
+ inexact |= do_add (rr, rr, &u, 0);
}
}
rr->sign = sign;
if (rr != r)
*r = t;
+
+ return inexact;
}
-/* Return R = A / B. */
+/* Calculate R = A / B. Return true if the result may be inexact. */
-static void
-do_divide (r, a, b)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a, *b;
+static bool
+do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
int exp, sign = a->sign ^ b->sign;
REAL_VALUE_TYPE t, *rr;
{
case CLASS2 (rvc_zero, rvc_zero):
/* 0 / 0 = NaN. */
- case CLASS2 (rvc_inf, rvc_zero):
- /* Inf / 0 = NaN. */
case CLASS2 (rvc_inf, rvc_inf):
/* Inf / Inf = NaN. */
get_canonical_qnan (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_normal):
case CLASS2 (rvc_zero, rvc_inf):
/* 0 / ANY = 0. */
case CLASS2 (rvc_normal, rvc_inf):
/* R / Inf = 0. */
- underflow:
get_zero (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_zero):
/* R / 0 = Inf. */
+ case CLASS2 (rvc_inf, rvc_zero):
+ /* Inf / 0 = Inf. */
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_zero, rvc_nan):
case CLASS2 (rvc_normal, rvc_nan):
/* ANY / NaN = NaN. */
*r = *b;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_nan, rvc_zero):
case CLASS2 (rvc_nan, rvc_normal):
/* NaN / ANY = NaN. */
*r = *a;
r->sign = sign;
- return;
+ return false;
case CLASS2 (rvc_inf, rvc_normal):
/* Inf / R = Inf. */
- overflow:
get_inf (r, sign);
- return;
+ return false;
case CLASS2 (rvc_normal, rvc_normal):
break;
exp = a->exp - b->exp + 1;
if (exp > MAX_EXP)
- goto overflow;
+ {
+ get_inf (r, sign);
+ return true;
+ }
if (exp < -MAX_EXP)
- goto underflow;
+ {
+ get_zero (r, sign);
+ return true;
+ }
rr->exp = exp;
inexact = div_significands (rr, a, b);
- rr->sig[0] |= inexact;
/* 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 (a, b, nan_result)
- const REAL_VALUE_TYPE *a, *b;
- int nan_result;
+do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
+ int nan_result)
{
int ret;
/* Return A truncated to an integral value toward zero. */
static void
-do_fix_trunc (r, a)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *a;
+do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
*r = *a;
- switch (a->class)
+ switch (r->class)
{
case rvc_zero:
case rvc_inf:
For a unary operation, leave OP1 NULL. */
void
-real_arithmetic (r, icode, op0, op1)
- REAL_VALUE_TYPE *r;
- int icode;
- const REAL_VALUE_TYPE *op0, *op1;
+real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
{
enum tree_code code = icode;
/* Legacy. Similar, but return the result directly. */
REAL_VALUE_TYPE
-real_arithmetic2 (icode, op0, op1)
- int icode;
- const REAL_VALUE_TYPE *op0, *op1;
+real_arithmetic2 (int icode, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
{
REAL_VALUE_TYPE r;
real_arithmetic (&r, icode, op0, op1);
}
bool
-real_compare (icode, op0, op1)
- int icode;
- const REAL_VALUE_TYPE *op0, *op1;
+real_compare (int icode, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
{
enum tree_code code = icode;
/* Return floor log2(R). */
int
-real_exponent (r)
- const REAL_VALUE_TYPE *r;
+real_exponent (const REAL_VALUE_TYPE *r)
{
switch (r->class)
{
/* R = OP0 * 2**EXP. */
void
-real_ldexp (r, op0, exp)
- REAL_VALUE_TYPE *r;
- const REAL_VALUE_TYPE *op0;
- int exp;
+real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp)
{
*r = *op0;
switch (r->class)
/* Determine whether a floating-point value X is infinite. */
bool
-real_isinf (r)
- const REAL_VALUE_TYPE *r;
+real_isinf (const REAL_VALUE_TYPE *r)
{
return (r->class == rvc_inf);
}
/* Determine whether a floating-point value X is a NaN. */
bool
-real_isnan (r)
- const REAL_VALUE_TYPE *r;
+real_isnan (const REAL_VALUE_TYPE *r)
{
return (r->class == rvc_nan);
}
/* Determine whether a floating-point value X is negative. */
bool
-real_isneg (r)
- const REAL_VALUE_TYPE *r;
+real_isneg (const REAL_VALUE_TYPE *r)
{
return r->sign;
}
/* Determine whether a floating-point value X is minus zero. */
bool
-real_isnegzero (r)
- const REAL_VALUE_TYPE *r;
+real_isnegzero (const REAL_VALUE_TYPE *r)
{
return r->sign && r->class == rvc_zero;
}
/* Compare two floating-point objects for bitwise identity. */
-extern bool
-real_identical (a, b)
- const REAL_VALUE_TYPE *a, *b;
+bool
+real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
{
int i;
{
case rvc_zero:
case rvc_inf:
- break;
+ return true;
case rvc_normal:
if (a->exp != b->exp)
- return false;
- /* FALLTHRU */
+ return false;
+ break;
+
case rvc_nan:
- for (i = 0; i < SIGSZ; ++i)
- if (a->sig[i] != b->sig[i])
- return false;
+ if (a->signalling != b->signalling)
+ return false;
+ /* The significand is ignored for canonical NaNs. */
+ if (a->canonical || b->canonical)
+ return a->canonical == b->canonical;
break;
default:
abort ();
}
+ for (i = 0; i < SIGSZ; ++i)
+ if (a->sig[i] != b->sig[i])
+ return false;
+
return true;
}
mode MODE. Return true if successful. */
bool
-exact_real_inverse (mode, r)
- enum machine_mode mode;
- REAL_VALUE_TYPE *r;
+exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
{
const REAL_VALUE_TYPE *one = real_digit (1);
REAL_VALUE_TYPE u;
int i;
-
+
if (r->class != rvc_normal)
return false;
/* Find the inverse and truncate to the required mode. */
do_divide (&u, one, r);
real_convert (&u, mode, &u);
-
+
/* The rounding may have overflowed. */
if (u.class != rvc_normal)
return false;
/* Render R as an integer. */
HOST_WIDE_INT
-real_to_integer (r)
- const REAL_VALUE_TYPE *r;
+real_to_integer (const REAL_VALUE_TYPE *r)
{
unsigned HOST_WIDE_INT i;
case rvc_normal:
if (r->exp <= 0)
goto underflow;
+ /* Only force overflow for unsigned overflow. Signed overflow is
+ undefined, so it doesn't matter what we return, and some callers
+ expect to be able to use this routine for both signed and
+ unsigned conversions. */
if (r->exp > HOST_BITS_PER_WIDE_INT)
goto overflow;
/* Likewise, but to an integer pair, HI+LOW. */
void
-real_to_integer2 (plow, phigh, r)
- HOST_WIDE_INT *plow, *phigh;
- const REAL_VALUE_TYPE *r;
+real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
+ const REAL_VALUE_TYPE *r)
{
REAL_VALUE_TYPE t;
HOST_WIDE_INT low, high;
exp = r->exp;
if (exp <= 0)
goto underflow;
- if (exp >= 2*HOST_BITS_PER_WIDE_INT)
+ /* 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);
*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 = num->exp, expd = den->exp;
+
+ 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);
+
+ num->exp = expd;
+ normalize (num);
+
+ return q;
+}
+
/* Render R as a decimal floating point constant. Emit DIGITS significant
- digits in the result. If DIGITS <= 0, choose the maximum for the
- representation. If DIGITS < 0, strip trailing zeros. */
+ 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. */
#define M_LOG10_2 0.30102999566398119521
void
-real_to_decimal (str, r_orig, digits)
- char *str;
- const REAL_VALUE_TYPE *r_orig;
- int digits;
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
{
- REAL_VALUE_TYPE r;
const REAL_VALUE_TYPE *one, *ten;
- int dec_exp, max_digits, d, cmp_half;
+ REAL_VALUE_TYPE r, pten, u, v;
+ int dec_exp, cmp_one, digit;
+ size_t max_digits;
char *p, *first, *last;
bool sign;
- bool crop_trailing_zeros;
r = *r_orig;
switch (r.class)
case rvc_normal:
break;
case rvc_inf:
- strcpy (str, (r.sign ? "+Inf" : "-Inf"));
+ strcpy (str, (r.sign ? "-Inf" : "+Inf"));
return;
case rvc_nan:
/* ??? Print the significand as well, if not canonical? */
- strcpy (str, (r.sign ? "+NaN" : "-NaN"));
+ strcpy (str, (r.sign ? "-NaN" : "+NaN"));
return;
default:
abort ();
}
+ /* Bound the number of digits printed by the size of the representation. */
max_digits = SIGNIFICAND_BITS * M_LOG10_2;
- crop_trailing_zeros = digits < 0;
- if (digits <= 0 || digits > max_digits)
+ 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 = r.exp * 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;
+ if (max_digits > buf_size)
+ abort ();
+ if (digits > max_digits)
digits = max_digits;
one = real_digit (1);
sign = r.sign;
r.sign = 0;
- /* Estimate the decimal exponent. */
- dec_exp = r.exp * M_LOG10_2;
-
- /* Scale the number such that it is in [1, 10). */
- if (dec_exp > 0)
- {
- int i;
- for (i = EXP_BITS - 1; i >= 0; --i)
- if (dec_exp & (1 << i))
- do_divide (&r, &r, ten_to_ptwo (i));
- }
- else if (dec_exp < 0)
+ dec_exp = 0;
+ pten = *one;
+
+ cmp_one = do_compare (&r, one, 0);
+ if (cmp_one > 0)
{
- int i, pos_exp = -(--dec_exp);
+ int m;
- for (i = EXP_BITS - 1; i >= 0; --i)
- if (pos_exp & (1 << i))
- do_multiply (&r, &r, ten_to_ptwo (i));
- }
+ /* Number is greater than one. Convert significand to an integer
+ and strip trailing decimal zeros. */
- /* Assert that the number is in the proper range. Round-off can
- prevent the above from working exactly. */
- if (do_compare (&r, one, -1) < 0)
- {
- do_multiply (&r, &r, ten);
- dec_exp--;
+ u = r;
+ u.exp = 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. */
+ u.exp += r.exp - (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 (r.exp > 0)
+ {
+ m = floor_log2 ((int)(r.exp * 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;
}
- else if (do_compare (&r, ten, 1) >= 0)
+ if (cmp_one < 0)
{
- do_divide (&r, &r, ten);
- dec_exp++;
+ 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 (u.exp > 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)(-r.exp * 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++;
- while (1)
+
+ /* 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;
+ if (digit == 0)
+ abort ();
+ }
+
+ /* ... or overflow. */
+ if (digit == 10)
{
- d = real_to_integer ((const REAL_VALUE_TYPE *) &r);
- do_add (&r, &r, real_digit (d), 1);
+ *p++ = '1';
+ if (--digits > 0)
+ *p++ = '0';
+ dec_exp += 1;
+ }
+ else if (digit > 10)
+ abort ();
+ else
+ *p++ = digit + '0';
- *p++ = d + '0';
- if (--digits == 0)
- break;
+ /* Generate subsequent digits. */
+ while (--digits > 0)
+ {
do_multiply (&r, &r, ten);
+ digit = rtd_divmod (&r, &pten);
+ *p++ = digit + '0';
}
last = p;
- /* Round the result. Compare R vs 0.5 by doing R*2 vs 1.0. */
- r.exp += 1;
- cmp_half = do_compare (&r, one, -1);
- if (cmp_half == 0)
- /* Round to even. */
- cmp_half += d & 1;
- if (cmp_half > 0)
+ /* Generate one more digit with which to do rounding. */
+ do_multiply (&r, &r, ten);
+ digit = rtd_divmod (&r, &pten);
+
+ /* Round the result. */
+ 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++;
+ }
+ if (digit > 5)
{
while (p > first)
{
- d = *--p;
- if (d == '9')
+ digit = *--p;
+ if (digit == '9')
*p = '0';
else
{
- *p = d + 1;
+ *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);
}
/* Render R as a hexadecimal floating point constant. Emit DIGITS
- significant digits in the result. If DIGITS <= 0, choose the maximum
- for the representation. If DIGITS < 0, strip trailing zeros. */
+ 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 (str, r, digits)
- char *str;
- const REAL_VALUE_TYPE *r;
- int digits;
+real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
{
int i, j, exp = r->exp;
char *p, *first;
- bool crop_trailing_zeros;
+ char exp_buf[16];
+ size_t max_digits;
switch (r->class)
{
case rvc_normal:
break;
case rvc_inf:
- strcpy (str, (r->sign ? "+Inf" : "-Inf"));
+ strcpy (str, (r->sign ? "-Inf" : "+Inf"));
return;
case rvc_nan:
/* ??? Print the significand as well, if not canonical? */
- strcpy (str, (r->sign ? "+NaN" : "-NaN"));
+ strcpy (str, (r->sign ? "-NaN" : "+NaN"));
return;
default:
abort ();
}
- crop_trailing_zeros = digits < 0;
- if (digits <= 0)
+ 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;
+ if (max_digits > buf_size)
+ abort ();
+ if (digits > max_digits)
+ digits = max_digits;
+
p = str;
if (r->sign)
*p++ = '-';
out:
if (crop_trailing_zeros)
- while (p > first + 2 && p[-1] == '0')
+ while (p > first + 1 && p[-1] == '0')
p--;
sprintf (p, "p%+d", exp);
assumed to have been syntax checked already. */
void
-real_from_string (r, str)
- REAL_VALUE_TYPE *r;
- const char *str;
+real_from_string (REAL_VALUE_TYPE *r, const char *str)
{
int exp = 0;
bool sign = false;
exp += d;
}
- if (exp < 0)
- {
- exp = -exp;
- for (d = 0; d < EXP_BITS; ++d)
- if (exp & (1 << d))
- do_divide (r, r, ten_to_ptwo (d));
- }
- else if (exp > 0)
- {
- for (d = 0; d < EXP_BITS; ++d)
- if (exp & (1 << d))
- do_multiply (r, r, ten_to_ptwo (d));
- }
+ if (exp)
+ times_pten (r, exp);
}
r->sign = sign;
/* Legacy. Similar, but return the result directly. */
REAL_VALUE_TYPE
-real_from_string2 (s, mode)
- const char *s;
- enum machine_mode mode;
+real_from_string2 (const char *s, enum machine_mode mode)
{
REAL_VALUE_TYPE r;
/* Initialize R from the integer pair HIGH+LOW. */
void
-real_from_integer (r, mode, low, high, unsigned_p)
- REAL_VALUE_TYPE *r;
- enum machine_mode mode;
- unsigned HOST_WIDE_INT low;
- HOST_WIDE_INT high;
- int unsigned_p;
+real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ unsigned HOST_WIDE_INT low, HOST_WIDE_INT high,
+ int unsigned_p)
{
if (low == 0 && high == 0)
get_zero (r, 0);
real_convert (r, mode, r);
}
-/* Returns 10**2**n. */
+/* Returns 10**2**N. */
static const REAL_VALUE_TYPE *
-ten_to_ptwo (n)
- int n;
+ten_to_ptwo (int n)
{
static REAL_VALUE_TYPE tens[EXP_BITS];
return &tens[n];
}
+/* Returns 10**(-2**N). */
+
+static const REAL_VALUE_TYPE *
+ten_to_mptwo (int n)
+{
+ static REAL_VALUE_TYPE tens[EXP_BITS];
+
+ if (n < 0 || n >= EXP_BITS)
+ abort ();
+
+ if (tens[n].class == 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 (n)
- int n;
+real_digit (int n)
{
static REAL_VALUE_TYPE num[10];
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);
+}
+
/* Fills R with +Inf. */
void
-real_inf (r)
- REAL_VALUE_TYPE *r;
+real_inf (REAL_VALUE_TYPE *r)
{
get_inf (r, 0);
}
if the string was successfully parsed. */
bool
-real_nan (r, str, quiet, mode)
- REAL_VALUE_TYPE *r;
- const char *str;
- int quiet;
- enum machine_mode mode;
+real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet,
+ enum machine_mode mode)
{
const struct real_format *fmt;
/* Shift the significand into place such that the bits
are in the most significant bits for the format. */
- lshift_significand (r, r, SIGNIFICAND_BITS - fmt->p);
+ lshift_significand (r, r, SIGNIFICAND_BITS - fmt->pnan);
/* Our MSB is always unset for NaNs. */
r->sig[SIGSZ-1] &= ~SIG_MSB;
/* Force quiet or signalling NaN. */
- if (quiet)
- r->sig[SIGSZ-1] |= SIG_MSB >> 1;
- else
- r->sig[SIGSZ-1] &= ~(SIG_MSB >> 1);
-
- /* Force at least one bit of the significand set. */
- for (d = 0; d < SIGSZ; ++d)
- if (r->sig[d])
- break;
- if (d == SIGSZ)
- r->sig[SIGSZ-1] |= SIG_MSB >> 2;
-
- /* Our intermediate format forces QNaNs to have MSB-1 set.
- If the target format has QNaNs with the top bit unset,
- mirror the output routines and invert the top two bits. */
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1) | (SIG_MSB >> 2);
+ r->signalling = !quiet;
}
return true;
}
+/* Fills R with the largest finite value representable in mode MODE.
+ If SIGN is nonzero, R is set to the most negative finite value. */
+
+void
+real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
+{
+ const struct real_format *fmt;
+ int np2;
+
+ fmt = real_format_for_mode[mode - QFmode];
+ if (fmt == NULL)
+ abort ();
+
+ r->class = rvc_normal;
+ r->sign = sign;
+ r->signalling = 0;
+ r->canonical = 0;
+ r->exp = fmt->emax * fmt->log2_b;
+
+ np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+ memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+ clear_significand_below (r, np2);
+}
+
/* Fills R with 2**N. */
void
-real_2expN (r, n)
- REAL_VALUE_TYPE *r;
- int n;
+real_2expN (REAL_VALUE_TYPE *r, int n)
{
memset (r, 0, sizeof (*r));
\f
static void
-round_for_format (fmt, r)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
+round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
{
int p2, np2, i, w;
unsigned long sticky;
case rvc_nan:
clear_significand_below (r, np2);
-
- /* If we've cleared the entire significand, we need one bit
- set for this to continue to be a NaN. */
- for (i = 0; i < SIGSZ; ++i)
- if (r->sig[i])
- break;
- if (i == SIGSZ)
- r->sig[SIGSZ-1] = SIG_MSB >> 2;
return;
case rvc_normal:
if (shift)
{
shift = fmt->log2_b - shift;
- sticky_rshift_significand (r, r, shift);
+ r->sig[0] |= sticky_rshift_significand (r, r, shift);
r->exp += shift;
}
}
if (diff > p2)
goto underflow;
- /* De-normalize the significand. */
- sticky_rshift_significand (r, r, diff);
- r->exp += diff;
- }
+ /* De-normalize the significand. */
+ r->sig[0] |= sticky_rshift_significand (r, r, diff);
+ r->exp += diff;
+ }
}
/* There are P2 true significand bits, followed by one guard bit,
if (shift)
{
shift = fmt->log2_b - shift;
- sticky_rshift_significand (r, r, shift);
+ rshift_significand (r, r, shift);
r->exp += shift;
if (r->exp > emax2)
goto overflow;
/* Extend or truncate to a new mode. */
void
-real_convert (r, mode, a)
- REAL_VALUE_TYPE *r;
- enum machine_mode mode;
- const REAL_VALUE_TYPE *a;
+real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *a)
{
const struct real_format *fmt;
/* Legacy. Likewise, except return the struct directly. */
REAL_VALUE_TYPE
-real_value_truncate (mode, a)
- enum machine_mode mode;
- REAL_VALUE_TYPE a;
+real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a)
{
REAL_VALUE_TYPE r;
real_convert (&r, mode, &a);
/* Return true if truncating to MODE is exact. */
bool
-exact_real_truncate (mode, a)
- enum machine_mode mode;
- const REAL_VALUE_TYPE *a;
+exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
{
REAL_VALUE_TYPE t;
real_convert (&t, mode, a);
Legacy: return word 0 for implementing REAL_VALUE_TO_TARGET_SINGLE. */
long
-real_to_target_fmt (buf, r_orig, fmt)
- long *buf;
- const REAL_VALUE_TYPE *r_orig;
- const struct real_format *fmt;
+real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig,
+ const struct real_format *fmt)
{
REAL_VALUE_TYPE r;
long buf1;
/* Similar, but look up the format from MODE. */
long
-real_to_target (buf, r, mode)
- long *buf;
- const REAL_VALUE_TYPE *r;
- enum machine_mode mode;
+real_to_target (long *buf, const REAL_VALUE_TYPE *r, enum machine_mode mode)
{
const struct real_format *fmt;
long, no matter the size of the host long. */
void
-real_from_target_fmt (r, buf, fmt)
- REAL_VALUE_TYPE *r;
- const long *buf;
- const struct real_format *fmt;
+real_from_target_fmt (REAL_VALUE_TYPE *r, const long *buf,
+ const struct real_format *fmt)
{
(*fmt->decode) (fmt, r, buf);
-}
+}
/* Similar, but look up the format from MODE. */
void
-real_from_target (r, buf, mode)
- REAL_VALUE_TYPE *r;
- const long *buf;
- enum machine_mode mode;
+real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode)
{
const struct real_format *fmt;
abort ();
(*fmt->decode) (fmt, r, buf);
-}
+}
/* Return the number of bits in the significand for MODE. */
/* ??? Legacy. Should get access to real_format directly. */
int
-significand_size (mode)
- enum machine_mode mode;
+significand_size (enum machine_mode mode)
{
const struct real_format *fmt;
but I didn't want to pull hashtab.h into real.h. */
unsigned int
-real_hash (r)
- const REAL_VALUE_TYPE *r;
+real_hash (const REAL_VALUE_TYPE *r)
{
unsigned int h;
size_t i;
{
case rvc_zero:
case rvc_inf:
- break;
+ return h;
case rvc_normal:
h |= r->exp << 3;
- /* FALLTHRU */
+ break;
case rvc_nan:
- if (sizeof(unsigned long) > sizeof(unsigned int))
- for (i = 0; i < SIGSZ; ++i)
- {
- unsigned long s = r->sig[i];
- h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2));
- }
- else
- for (i = 0; i < SIGSZ; ++i)
- h ^= r->sig[i];
+ if (r->signalling)
+ h ^= (unsigned int)-1;
+ if (r->canonical)
+ return h;
break;
default:
abort ();
}
+ if (sizeof(unsigned long) > sizeof(unsigned int))
+ for (i = 0; i < SIGSZ; ++i)
+ {
+ unsigned long s = r->sig[i];
+ h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2));
+ }
+ else
+ for (i = 0; i < SIGSZ; ++i)
+ h ^= r->sig[i];
+
return h;
}
\f
/* IEEE single-precision format. */
-static void encode_ieee_single PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_ieee_single PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_ieee_single (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_single (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_ieee_single (fmt, buf, r)
- const struct real_format *fmt;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ieee_single (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image, sig, exp;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
case rvc_nan:
if (fmt->has_nans)
{
+ if (r->canonical)
+ sig = 0;
+ if (r->signalling == fmt->qnan_msb_set)
+ sig &= ~(1 << 22);
+ else
+ sig |= 1 << 22;
+ /* We overload qnan_msb_set here: it's only clear for
+ mips_ieee_single, which wants all mantissa bits but the
+ quiet/signalling one set in canonical NaNs (at least
+ Quiet ones). */
+ if (r->canonical && !fmt->qnan_msb_set)
+ sig |= (1 << 22) - 1;
+ else if (sig == 0)
+ sig = 1 << 21;
+
image |= 255 << 23;
image |= sig;
- if (!fmt->qnan_msb_set)
- image ^= 1 << 23 | 1 << 22;
}
else
image |= 0x7fffffff;
}
static void
-decode_ieee_single (fmt, r, buf)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ieee_single (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
unsigned long image = buf[0] & 0xffffffff;
bool sign = (image >> 31) & 1;
{
r->class = rvc_nan;
r->sign = sign;
- if (!fmt->qnan_msb_set)
- image ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
+ r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+ ^ fmt->qnan_msb_set);
r->sig[SIGSZ-1] = image;
}
else
}
}
-const struct real_format ieee_single_format =
+const struct real_format ieee_single_format =
{
encode_ieee_single,
decode_ieee_single,
2,
1,
24,
+ 24,
-125,
128,
+ 31,
true,
true,
true,
true
};
+const struct real_format mips_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 1,
+ 24,
+ 24,
+ -125,
+ 128,
+ 31,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
\f
/* IEEE double-precision format. */
-static void encode_ieee_double PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_ieee_double PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_ieee_double (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_double (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_ieee_double (fmt, buf, r)
- const struct real_format *fmt;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ieee_double (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image_lo, image_hi, sig_lo, sig_hi, exp;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
case rvc_nan:
if (fmt->has_nans)
{
+ if (r->canonical)
+ sig_hi = sig_lo = 0;
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 19);
+ else
+ sig_hi |= 1 << 19;
+ /* We overload qnan_msb_set here: it's only clear for
+ mips_ieee_single, which wants all mantissa bits but the
+ quiet/signalling one set in canonical NaNs (at least
+ Quiet ones). */
+ if (r->canonical && !fmt->qnan_msb_set)
+ {
+ sig_hi |= (1 << 19) - 1;
+ sig_lo = 0xffffffff;
+ }
+ else if (sig_hi == 0 && sig_lo == 0)
+ sig_hi = 1 << 18;
+
image_hi |= 2047 << 20;
image_hi |= sig_hi;
- if (!fmt->qnan_msb_set)
- image_hi ^= 1 << 19 | 1 << 18;
image_lo = sig_lo;
}
else
}
static void
-decode_ieee_double (fmt, r, buf)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ieee_double (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
unsigned long image_hi, image_lo;
bool sign;
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = image_hi;
}
else
r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
}
}
-const struct real_format ieee_double_format =
+const struct real_format ieee_double_format =
{
encode_ieee_double,
decode_ieee_double,
2,
1,
53,
+ 53,
-1021,
1024,
+ 63,
true,
true,
true,
true
};
+const struct real_format mips_double_format =
+ {
+ encode_ieee_double,
+ decode_ieee_double,
+ 2,
+ 1,
+ 53,
+ 53,
+ -1021,
+ 1024,
+ 63,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
\f
/* IEEE extended double precision format. This comes in three
- flavours: Intel's as a 12 byte image, Intel's as a 16 byte image,
+ flavors: Intel's as a 12 byte image, Intel's as a 16 byte image,
and Motorola's. */
-static void encode_ieee_extended PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_ieee_extended PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_ieee_extended (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_extended (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-static void encode_ieee_extended_128 PARAMS ((const struct real_format *fmt,
- long *,
- const REAL_VALUE_TYPE *));
-static void decode_ieee_extended_128 PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *,
- const long *));
+static void encode_ieee_extended_128 (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_extended_128 (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_ieee_extended (fmt, buf, r)
- const struct real_format *fmt;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ieee_extended (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image_hi, sig_hi, sig_lo;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
sig_hi = sig_lo >> 31 >> 1;
sig_lo &= 0xffffffff;
}
- if (!fmt->qnan_msb_set)
- sig_hi ^= 1 << 30 | 1 << 29;
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 30);
+ else
+ sig_hi |= 1 << 30;
+ if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
+ sig_hi = 1 << 29;
/* Intel requires the explicit integer bit to be set, otherwise
it considers the value a "pseudo-nan". Motorola docs say it
/* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
whereas the intermediate representation is 0.F x 2**exp.
- Which means we're off by one.
+ Which means we're off by one.
Except for Motorola, which consider exp=0 and explicit
integer bit set to continue to be normalized. In theory
- this descrepency has been taken care of by the difference
+ this discrepancy has been taken care of by the difference
in fmt->emin in round_for_format. */
if (denormal)
}
static void
-encode_ieee_extended_128 (fmt, buf, r)
- const struct real_format *fmt;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ieee_extended_128 (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
buf[3 * !FLOAT_WORDS_BIG_ENDIAN] = 0;
encode_ieee_extended (fmt, buf+!!FLOAT_WORDS_BIG_ENDIAN, r);
}
static void
-decode_ieee_extended (fmt, r, buf)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ieee_extended (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
unsigned long image_hi, sig_hi, sig_lo;
bool sign;
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[SIGSZ-1] = sig_hi;
}
else
r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
}
static void
-decode_ieee_extended_128 (fmt, r, buf)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ieee_extended_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
decode_ieee_extended (fmt, r, buf+!!FLOAT_WORDS_BIG_ENDIAN);
}
-const struct real_format ieee_extended_motorola_format =
+const struct real_format ieee_extended_motorola_format =
{
encode_ieee_extended,
decode_ieee_extended,
2,
1,
64,
+ 64,
-16382,
16384,
+ 95,
true,
true,
true,
true
};
-const struct real_format ieee_extended_intel_96_format =
+const struct real_format ieee_extended_intel_96_format =
{
encode_ieee_extended,
decode_ieee_extended,
2,
1,
64,
+ 64,
-16381,
16384,
+ 79,
true,
true,
true,
true
};
-const struct real_format ieee_extended_intel_128_format =
+const struct real_format ieee_extended_intel_128_format =
{
encode_ieee_extended_128,
decode_ieee_extended_128,
2,
1,
64,
+ 64,
-16381,
16384,
+ 79,
true,
true,
true,
true
};
+/* 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,
+ decode_ieee_extended,
+ 2,
+ 1,
+ 53,
+ 53,
+ -16381,
+ 16384,
+ 79,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
\f
/* IBM 128-bit extended precision format: a pair of IEEE double precision
numbers whose sum is equal to the extended precision value. The number
ignored. Zeroes, Infinities, and NaNs are set in both doubles
due to precedent. */
-static void encode_ibm_extended PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_ibm_extended PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_ibm_extended (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ibm_extended (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_ibm_extended (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ibm_extended (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
REAL_VALUE_TYPE u, v;
+ const struct real_format *base_fmt;
+
+ base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
switch (r->class)
{
case rvc_inf:
case rvc_nan:
/* Both doubles set to Inf / NaN. */
- encode_ieee_double (&ieee_double_format, &buf[0], r);
+ encode_ieee_double (base_fmt, &buf[0], r);
buf[2] = buf[0];
buf[3] = buf[1];
return;
-
+
case rvc_normal:
/* u = IEEE double precision portion of significand. */
u = *r;
clear_significand_below (&u, SIGNIFICAND_BITS - 53);
- /* v = remainder containing additional 53 bits of significand. */
- do_add (&v, r, &u, 1);
+ normalize (&u);
+ /* If the upper double is zero, we have a denormal double, so
+ move it to the first double and leave the second as zero. */
+ if (u.class == rvc_zero)
+ {
+ v = u;
+ u = *r;
+ normalize (&u);
+ }
+ else
+ {
+ /* v = remainder containing additional 53 bits of significand. */
+ do_add (&v, r, &u, 1);
+ round_for_format (base_fmt, &v);
+ }
+
+ round_for_format (base_fmt, &u);
- encode_ieee_double (&ieee_double_format, &buf[0], &u);
- encode_ieee_double (&ieee_double_format, &buf[2], &v);
+ encode_ieee_double (base_fmt, &buf[0], &u);
+ encode_ieee_double (base_fmt, &buf[2], &v);
break;
default:
}
static void
-decode_ibm_extended (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ibm_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, REAL_VALUE_TYPE *r,
+ const long *buf)
{
REAL_VALUE_TYPE u, v;
+ const struct real_format *base_fmt;
- decode_ieee_double (&ieee_double_format, &u, &buf[0]);
+ base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
+ decode_ieee_double (base_fmt, &u, &buf[0]);
if (u.class != rvc_zero && u.class != rvc_inf && u.class != rvc_nan)
{
- decode_ieee_double (&ieee_double_format, &v, &buf[2]);
+ decode_ieee_double (base_fmt, &v, &buf[2]);
do_add (r, &u, &v, 0);
}
else
*r = u;
}
-const struct real_format ibm_extended_format =
+const struct real_format ibm_extended_format =
{
encode_ibm_extended,
decode_ibm_extended,
2,
1,
53 + 53,
- -1021,
+ 53,
+ -1021 + 53,
1024,
+ -1,
true,
true,
true,
true
};
+const struct real_format mips_extended_format =
+ {
+ encode_ibm_extended,
+ decode_ibm_extended,
+ 2,
+ 1,
+ 53 + 53,
+ 53,
+ -1021 + 53,
+ 1024,
+ -1,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
\f
/* IEEE quad precision format. */
-static void encode_ieee_quad PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_ieee_quad PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_ieee_quad (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_quad (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_ieee_quad (fmt, buf, r)
- const struct real_format *fmt;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_ieee_quad (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image3, image2, image1, image0, exp;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
{
image3 |= 32767 << 16;
- if (HOST_BITS_PER_LONG == 32)
+ if (r->canonical)
+ {
+ /* Don't use bits from the significand. The
+ initialization above is right. */
+ }
+ else if (HOST_BITS_PER_LONG == 32)
{
image0 = u.sig[0];
image1 = u.sig[1];
image0 &= 0xffffffff;
image2 &= 0xffffffff;
}
-
- if (!fmt->qnan_msb_set)
- image3 ^= 1 << 15 | 1 << 14;
+ if (r->signalling == fmt->qnan_msb_set)
+ image3 &= ~0x8000;
+ else
+ image3 |= 0x8000;
+ /* We overload qnan_msb_set here: it's only clear for
+ mips_ieee_single, which wants all mantissa bits but the
+ quiet/signalling one set in canonical NaNs (at least
+ Quiet ones). */
+ if (r->canonical && !fmt->qnan_msb_set)
+ {
+ image3 |= 0x7fff;
+ image2 = image1 = image0 = 0xffffffff;
+ }
+ else if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
+ image3 |= 0x4000;
}
else
{
}
static void
-decode_ieee_quad (fmt, r, buf)
- const struct real_format *fmt;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_ieee_quad (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
unsigned long image3, image2, image1, image0;
bool sign;
{
r->class = rvc_nan;
r->sign = sign;
+ r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
if (HOST_BITS_PER_LONG == 32)
{
r->sig[1] = (image3 << 31 << 1) | image2;
}
lshift_significand (r, r, SIGNIFICAND_BITS - 113);
-
- if (!fmt->qnan_msb_set)
- r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
}
else
{
}
}
-const struct real_format ieee_quad_format =
+const struct real_format ieee_quad_format =
{
encode_ieee_quad,
decode_ieee_quad,
2,
1,
113,
+ 113,
-16381,
16384,
+ 127,
true,
true,
true,
true,
true
};
+
+const struct real_format mips_quad_format =
+ {
+ encode_ieee_quad,
+ decode_ieee_quad,
+ 2,
+ 1,
+ 113,
+ 113,
+ -16381,
+ 16384,
+ 127,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
\f
/* Descriptions of VAX floating point formats can be found beginning at
We don't implement the H_floating format here, simply because neither
the VAX or Alpha ports use it. */
-
-static void encode_vax_f PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_vax_f PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
-static void encode_vax_d PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_vax_d PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
-static void encode_vax_g PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_vax_g PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+
+static void encode_vax_f (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_f (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_vax_d (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_d (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_vax_g (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_g (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_vax_f (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, sig, image;
}
static void
-decode_vax_f (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image = buf[0] & 0xffffffff;
int exp = (image >> 7) & 0xff;
}
static void
-encode_vax_d (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image0, image1, sign = r->sign << 15;
}
static void
-decode_vax_d (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image0, image1;
int exp;
}
static void
-encode_vax_g (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
{
unsigned long image0, image1, sign = r->sign << 15;
}
static void
-decode_vax_g (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image0, image1;
int exp;
}
}
-const struct real_format vax_f_format =
+const struct real_format vax_f_format =
{
encode_vax_f,
decode_vax_f,
2,
1,
24,
+ 24,
-127,
127,
+ 15,
false,
false,
false,
false
};
-const struct real_format vax_d_format =
+const struct real_format vax_d_format =
{
encode_vax_d,
decode_vax_d,
2,
1,
56,
+ 56,
-127,
127,
+ 15,
false,
false,
false,
false
};
-const struct real_format vax_g_format =
+const struct real_format vax_g_format =
{
encode_vax_g,
decode_vax_g,
2,
1,
53,
+ 53,
-1023,
1023,
+ 15,
false,
false,
false,
http://publibz.boulder.ibm.com/cgi-bin/bookmgr_OS390/BOOKS/DZ9AR001/9.1?DT=19930923083613
*/
-static void encode_i370_single PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_i370_single PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
-static void encode_i370_double PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_i370_double PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_i370_single (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_i370_single (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_i370_double (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_i370_double (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_i370_single (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, sig, image;
}
static void
-decode_i370_single (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sign, sig, image = buf[0];
int exp;
}
static void
-encode_i370_double (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long sign, exp, image_hi, image_lo;
}
static void
-decode_i370_double (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_i370_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sign, image_hi, image_lo;
int exp;
16,
4,
6,
+ 6,
-64,
63,
+ 31,
false,
false,
false, /* ??? The encoding does allow for "unnormals". */
16,
4,
14,
+ 14,
-64,
63,
+ 63,
false,
false,
false, /* ??? The encoding does allow for "unnormals". */
See http://www-s.ti.com/sc/psheets/spru063c/spru063c.pdf */
-static void encode_c4x_single PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_c4x_single PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
-static void encode_c4x_extended PARAMS ((const struct real_format *fmt,
- long *, const REAL_VALUE_TYPE *));
-static void decode_c4x_extended PARAMS ((const struct real_format *,
- REAL_VALUE_TYPE *, const long *));
+static void encode_c4x_single (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_c4x_single (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_c4x_extended (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_c4x_extended (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
static void
-encode_c4x_single (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long image, exp, sig;
-
+
switch (r->class)
{
case rvc_zero:
}
static void
-decode_c4x_single (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_c4x_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long image = buf[0];
unsigned long sig;
}
static void
-encode_c4x_extended (fmt, buf, r)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- long *buf;
- const REAL_VALUE_TYPE *r;
+encode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf, const REAL_VALUE_TYPE *r)
{
unsigned long exp, sig;
-
+
switch (r->class)
{
case rvc_zero:
}
static void
-decode_c4x_extended (fmt, r, buf)
- const struct real_format *fmt ATTRIBUTE_UNUSED;
- REAL_VALUE_TYPE *r;
- const long *buf;
+decode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
unsigned long sig;
int exp, sf;
}
}
-const struct real_format c4x_single_format =
+const struct real_format c4x_single_format =
{
encode_c4x_single,
decode_c4x_single,
2,
1,
24,
+ 24,
-126,
128,
+ -1,
false,
false,
false,
false
};
-const struct real_format c4x_extended_format =
+const struct real_format c4x_extended_format =
{
encode_c4x_extended,
decode_c4x_extended,
2,
1,
32,
+ 32,
-126,
128,
+ -1,
false,
false,
false,
false,
false
};
+
+\f
+/* 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,
+ 1,
+ SIGNIFICAND_BITS - 2,
+ SIGNIFICAND_BITS - 2,
+ -MAX_EXP,
+ MAX_EXP,
+ -1,
+ true,
+ true,
+ false,
+ true,
+ true
+ };
\f
/* Set up default mode to format mapping for IEEE. Everyone else has
to set these values in OVERRIDE_OPTIONS. */
NULL, /* XFmode */
&ieee_quad_format /* TFmode */
};
+
+\f
+/* 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))
+ {
+ /* Mode is ignored for canonical NaN. */
+ real_nan (r, "", 1, SFmode);
+ return false;
+ }
+
+ /* Infinity and NaN return themselves. */
+ if (real_isinf (x) || real_isnan (x))
+ {
+ *r = *x;
+ return false;
+ }
+
+ if (!init)
+ {
+ do_add (&halfthree, &dconst1, &dconsthalf, 0);
+ init = true;
+ }
+
+ /* Initial guess for reciprocal sqrt, i. */
+ exp = real_exponent (x);
+ real_ldexp (&i, &dconst1, -exp/2);
+
+ /* Newton's iteration for reciprocal sqrt, i. */
+ for (iter = 0; iter < 16; iter++)
+ {
+ /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x). */
+ do_multiply (&t, x, &i);
+ do_multiply (&h, &t, &i);
+ do_multiply (&t, &h, &dconsthalf);
+ do_add (&h, &halfthree, &t, 1);
+ do_multiply (&t, &i, &h);
+
+ /* Check for early convergence. */
+ if (iter >= 6 && real_identical (&i, &t))
+ break;
+
+ /* ??? Unroll loop to avoid copying. */
+ i = t;
+ }
+
+ /* Final iteration: r = i*x + 0.5*i*x*(1.0 - i*(i*x)). */
+ do_multiply (&t, x, &i);
+ do_multiply (&h, &t, &i);
+ do_add (&i, &dconst1, &h, 1);
+ do_multiply (&h, &t, &i);
+ do_multiply (&i, &dconsthalf, &h);
+ do_add (&h, &t, &i, 0);
+
+ /* ??? We need a Tuckerman test to get the last bit. */
+
+ real_convert (r, mode, &h);
+ return true;
+}
+
+/* Calculate X raised to the integer exponent N in mode MODE and store
+ the result in R. Return true if the result may be inexact due to
+ loss of precision. The algorithm is the classic "left-to-right binary
+ method" described in section 4.6.3 of Donald Knuth's "Seminumerical
+ Algorithms", "The Art of Computer Programming", Volume 2. */
+
+bool
+real_powi (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x, HOST_WIDE_INT n)
+{
+ unsigned HOST_WIDE_INT bit;
+ REAL_VALUE_TYPE t;
+ bool inexact = false;
+ bool init = false;
+ bool neg;
+ int i;
+
+ if (n == 0)
+ {
+ *r = dconst1;
+ return false;
+ }
+ else if (n < 0)
+ {
+ /* Don't worry about overflow, from now on n is unsigned. */
+ neg = true;
+ n = -n;
+ }
+ else
+ neg = false;
+
+ t = *x;
+ bit = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+ for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
+ {
+ if (init)
+ {
+ inexact |= do_multiply (&t, &t, &t);
+ if (n & bit)
+ inexact |= do_multiply (&t, &t, x);
+ }
+ else if (n & bit)
+ init = true;
+ bit >>= 1;
+ }
+
+ if (neg)
+ inexact |= do_divide (&t, &dconst1, &t);
+
+ real_convert (r, mode, &t);
+ return inexact;
+}
+
+/* Round X to the nearest integer not larger in absolute value, i.e.
+ towards zero, placing the result in R in mode MODE. */
+
+void
+real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_fix_trunc (r, x);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Round X to the largest integer not greater in value, i.e. round
+ down, placing the result in R in mode MODE. */
+
+void
+real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_fix_trunc (r, x);
+ if (! real_identical (r, x) && r->sign)
+ do_add (r, r, &dconstm1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Round X to the smallest integer not less then argument, i.e. round
+ up, placing the result in R in mode MODE. */
+
+void
+real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_fix_trunc (r, x);
+ if (! real_identical (r, x) && ! r->sign)
+ do_add (r, r, &dconst1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}