OSDN Git Service

Josef Zlomek <zlomekj@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / real.c
index 5859f0f..cd27d3e 100644 (file)
@@ -1,8 +1,8 @@
 /* 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, 2004 Free Software Foundation, Inc.
    Contributed by Stephen L. Moshier (moshier@world.std.com).
-   Re-written by Richard Henderson  <rth@redhat.com>
+   Re-written by Richard Henderson <rth@redhat.com>
 
    This file is part of GCC.
 
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "toplev.h"
 #include "real.h"
 #include "tm_p.h"
 
 /* The floating point model used internally is not exactly IEEE 754
-   compliant, and close to the description in the ISO C standard,
+   compliant, and close to the description in the ISO C99 standard,
    section 5.2.4.2.2 Characteristics of floating types.
 
    Specifically
    significand is fractional.  Normalized significands are in the
    range [0.5, 1.0).
 
-   A requirement of the model is that P be larger than than the 
-   largest supported target floating-point type by at least 2 bits.
-   This gives us proper rounding when we truncate to the target type.
-   In addition, E must be large enough to hold the smallest supported
-   denormal number in a normalized form.
+   A requirement of the model is that P be larger than the largest
+   supported target floating-point type by at least 2 bits.  This gives
+   us proper rounding when we truncate to the target type.  In addition,
+   E must be large enough to hold the smallest supported denormal number
+   in a normalized form.
 
-   Both of these requirements are easily satisfied.  The largest
-   target significand is 113 bits; we store 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 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.
+
    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
    adjust the significand to match.  */
 
 
-/* Enumerate the special cases of numbers that we encounter.  */
-enum real_value_class {
-  rvc_zero,
-  rvc_normal,
-  rvc_inf,
-  rvc_nan
-};
-
 /* Used to classify two numbers simultaneously.  */
 #define CLASS2(A, B)  ((A) << 2 | (B))
 
-/* An expanded form of the represented number.  */
-
-#define SIGNIFICAND_BITS       128
-#define EXP_BITS               (32 - 3)
-#define MAX_EXP                        ((1 << (EXP_BITS - 1)) - 1)
-#define SIGSZ                  (SIGNIFICAND_BITS / HOST_BITS_PER_LONG)
-#define SIG_MSB                        ((unsigned long)1 << (HOST_BITS_PER_LONG - 1))
-
 #if HOST_BITS_PER_LONG != 64 && HOST_BITS_PER_LONG != 32
  #error "Some constant folding done by hand to avoid shift count warnings"
 #endif
 
-struct real_value
-{
-  enum real_value_class class : 2;
-  unsigned int sign : 1;
-  int exp : EXP_BITS;
-  unsigned long sig[SIGSZ];
-};
-
-/* Describes the properties of the specific target format in use.  */
-struct real_format
-{
-  /* Move to and from the target bytes.  */
-  void (*encode) (const struct real_format *, long *,
-                 const struct real_value *);
-  void (*decode) (const struct real_format *, struct real_value *,
-                 const long *);
-
-  /* The radix of the exponent and digits of the significand.  */
-  int b;
-
-  /* log2(b).  */
-  int log2_b;
-
-  /* Size of the significand in digits of radix B.  */
-  int p;
-
-  /* The minimum negative integer, x, such that b**(x-1) is normalized.  */
-  int emin;
-
-  /* The maximum integer, x, such that b**(x-1) is representable.  */
-  int emax;
-
-  /* Properties of the format.  */
-  bool has_nans;
-  bool has_inf;
-  bool has_denorm;
-  bool has_signed_zero;
-  bool qnan_msb_set;
-};
-
-
-static const struct real_format *fmt_for_mode[TFmode - QFmode + 1];
-
-
-static void get_zero PARAMS ((struct real_value *, int));
-static void get_canonical_qnan PARAMS ((struct real_value *, int));
-static void get_canonical_snan PARAMS ((struct real_value *, int));
-static void get_inf PARAMS ((struct real_value *, int));
-static void sticky_rshift_significand PARAMS ((struct real_value *,
-                                              const struct real_value *,
-                                              unsigned int));
-static void rshift_significand PARAMS ((struct real_value *,
-                                       const struct real_value *,
-                                       unsigned int));
-static void lshift_significand PARAMS ((struct real_value *,
-                                       const struct real_value *,
-                                       unsigned int));
-static void lshift_significand_1 PARAMS ((struct real_value *,
-                                         const struct real_value *));
-static bool add_significands PARAMS ((struct real_value *r,
-                                     const struct real_value *,
-                                     const struct real_value *));
-static bool sub_significands PARAMS ((struct real_value *,
-                                     const struct real_value *,
-                                     const struct real_value *));
-static void neg_significand PARAMS ((struct real_value *,
-                                    const struct real_value *));
-static int cmp_significands PARAMS ((const struct real_value *,
-                                    const struct real_value *));
-static void set_significand_bit PARAMS ((struct real_value *, unsigned int));
-static void clear_significand_bit PARAMS ((struct real_value *, unsigned int));
-static bool test_significand_bit PARAMS ((struct real_value *, unsigned int));
-static void clear_significand_below PARAMS ((struct real_value *,
-                                            unsigned int));
-static bool div_significands PARAMS ((struct real_value *,
-                                     const struct real_value *,
-                                     const struct real_value *));
-static void normalize PARAMS ((struct real_value *));
-
-static void do_add PARAMS ((struct real_value *, const struct real_value *,
-                           const struct real_value *, int));
-static void do_multiply PARAMS ((struct real_value *,
-                                const struct real_value *,
-                                const struct real_value *));
-static void do_divide PARAMS ((struct real_value *, const struct real_value *,
-                              const struct real_value *));
-static int do_compare PARAMS ((const struct real_value *,
-                              const struct real_value *, int));
-
-static const struct real_value * ten_to_ptwo PARAMS ((int));
-static const struct real_value * real_digit PARAMS ((int));
-
-static void round_for_format PARAMS ((const struct real_format *,
-                                     struct real_value *));
+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)
-     struct real_value *r;
-     int sign;
+get_zero (REAL_VALUE_TYPE *r, int sign)
 {
   memset (r, 0, sizeof (*r));
   r->sign = sign;
@@ -195,31 +135,26 @@ get_zero (r, sign)
 /* Initialize R with the canonical quiet NaN.  */
 
 static inline void
-get_canonical_qnan (r, sign)
-     struct real_value *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)
-     struct real_value *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)
-     struct real_value *r;
-     int sign;
+get_inf (REAL_VALUE_TYPE *r, int sign)
 {
   memset (r, 0, sizeof (*r));
   r->class = rvc_inf;
@@ -228,23 +163,20 @@ get_inf (r, sign)
 
 \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)
-     struct real_value *r;
-     const struct real_value *a;
-     unsigned int n;
+static bool
+sticky_rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+                          unsigned int n)
 {
-  bool sticky = false;
+  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 -= ofs * HOST_BITS_PER_LONG;
+      n &= HOST_BITS_PER_LONG - 1;
     }
 
   if (n != 0)
@@ -266,21 +198,19 @@ sticky_rshift_significand (r, a, n)
        r->sig[i] = 0;
     }
 
-  r->sig[0] |= sticky;
+  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)
-     struct real_value *r;
-     const struct real_value *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)
@@ -304,14 +234,12 @@ rshift_significand (r, a, n)
    significand of R.  */
 
 static void
-lshift_significand (r, a, n)
-     struct real_value *r;
-     const struct real_value *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)
@@ -332,9 +260,7 @@ lshift_significand (r, a, n)
 /* Likewise, but N is specialized to 1.  */
 
 static inline void
-lshift_significand_1 (r, a)
-     struct real_value *r;
-     const struct real_value *a;
+lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
 {
   unsigned int i;
 
@@ -347,9 +273,8 @@ lshift_significand_1 (r, a)
    true if there was carry out of the most significant word.  */
 
 static inline bool
-add_significands (r, a, b)
-     struct real_value *r;
-     const struct real_value *a, *b;
+add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+                 const REAL_VALUE_TYPE *b)
 {
   bool carry = false;
   int i;
@@ -361,11 +286,11 @@ add_significands (r, a, b)
 
       if (carry)
        {
-          carry = ri < ai;
+         carry = ri < ai;
          carry |= ++ri == 0;
        }
       else
-        carry = ri < ai;
+       carry = ri < ai;
 
       r->sig[i] = ri;
     }
@@ -373,15 +298,14 @@ add_significands (r, a, b)
   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)
-     struct real_value *r;
-     const struct real_value *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)
@@ -391,24 +315,22 @@ sub_significands (r, a, b)
 
       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)
-     struct real_value *r;
-     const struct real_value *a;
+neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
 {
   bool carry = true;
   int i;
@@ -432,13 +354,12 @@ neg_significand (r, a)
 
       r->sig[i] = ri;
     }
-}  
+}
 
 /* Compare significands.  Return tri-state vs zero.  */
 
-static inline int 
-cmp_significands (a, b)
-     const struct real_value *a, *b;
+static inline int
+cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
 {
   int i;
 
@@ -456,12 +377,24 @@ cmp_significands (a, b)
   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)
-     struct real_value *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);
@@ -470,9 +403,7 @@ set_significand_bit (r, n)
 /* Clear bit N of the significand of R.  */
 
 static inline void
-clear_significand_bit (r, n)
-     struct real_value *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));
@@ -481,9 +412,7 @@ clear_significand_bit (r, n)
 /* Test bit N of the significand of R.  */
 
 static inline bool
-test_significand_bit (r, n)
-     struct real_value *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
@@ -495,9 +424,7 @@ test_significand_bit (r, n)
 /* Clear bits 0..N-1 of the significand of R.  */
 
 static void
-clear_significand_below (r, n)
-     struct real_value *r;
-     unsigned int n;
+clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n)
 {
   int i, w = n / HOST_BITS_PER_LONG;
 
@@ -511,37 +438,26 @@ clear_significand_below (r, n)
    true if the division was inexact.  */
 
 static inline bool
-div_significands (r, a, b)
-     struct real_value *r;
-     const struct real_value *a, *b;
+div_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+                 const REAL_VALUE_TYPE *b)
 {
-  struct real_value u;
-  int bit = SIGNIFICAND_BITS - 1;
-  int i;
-  long inexact;
+  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
     {
-      if ((u.sig[SIGSZ-1] & SIG_MSB) == 0)
-       {
-         lshift_significand_1 (&u, &u);
-       start:
-         if (cmp_significands (&u, b) >= 0)
-           {
-             sub_significands (&u, &u, b);
-             set_significand_bit (r, bit);
-           }
-       }
-      else
+      msb = u.sig[SIGSZ-1] & SIG_MSB;
+      lshift_significand_1 (&u, &u);
+    start:
+      if (msb || cmp_significands (&u, b) >= 0)
        {
-         /* 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);
        }
     }
@@ -559,13 +475,12 @@ div_significands (r, a, b)
    exponent is large enough to handle target denormals normalized.)  */
 
 static void
-normalize (r)
-     struct real_value *r;
+normalize (REAL_VALUE_TYPE *r)
 {
   int shift = 0, exp;
   int i, j;
 
-  /* Find the first word that is non-zero.  */
+  /* Find the first word that is nonzero.  */
   for (i = SIGSZ - 1; i >= 0; i--)
     if (r->sig[i] == 0)
       shift += HOST_BITS_PER_LONG;
@@ -580,7 +495,7 @@ normalize (r)
       return;
     }
 
-  /* Find the first bit that is non-zero.  */
+  /* 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;
@@ -601,16 +516,16 @@ normalize (r)
     }
 }
 \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)
-     struct real_value *r;
-     const struct real_value *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;
-  struct real_value t;
+  REAL_VALUE_TYPE t;
+  bool inexact = false;
 
   /* Determine if we need to add or subtract.  */
   sign = a->sign;
@@ -619,9 +534,9 @@ do_add (r, a, b, subtract_p)
   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):
@@ -635,7 +550,7 @@ do_add (r, a, b, subtract_p)
       /* R + Inf = Inf.  */
       *r = *b;
       r->sign = sign ^ subtract_p;
-      return;
+      return false;
 
     case CLASS2 (rvc_normal, rvc_zero):
     case CLASS2 (rvc_inf, rvc_zero):
@@ -647,7 +562,7 @@ do_add (r, a, b, subtract_p)
     case CLASS2 (rvc_inf, rvc_normal):
       /* Inf + R = Inf.  */
       *r = *a;
-      return;
+      return false;
 
     case CLASS2 (rvc_inf, rvc_inf):
       if (subtract_p)
@@ -656,7 +571,7 @@ do_add (r, a, b, subtract_p)
       else
        /* Inf + Inf = Inf.  */
        *r = *a;
-      return;
+      return false;
 
     case CLASS2 (rvc_normal, rvc_normal):
       break;
@@ -669,7 +584,7 @@ do_add (r, a, b, subtract_p)
   dexp = a->exp - b->exp;
   if (dexp < 0)
     {
-      const struct real_value *t;
+      const REAL_VALUE_TYPE *t;
       t = a, a = b, b = t;
       dexp = -dexp;
       sign ^= subtract_p;
@@ -686,16 +601,16 @@ do_add (r, a, b, subtract_p)
        {
          *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
@@ -712,12 +627,12 @@ do_add (r, a, b, subtract_p)
          /* 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;
            }
        }
     }
@@ -733,18 +648,22 @@ do_add (r, a, b, subtract_p)
      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)
-     struct real_value *r;
-     const struct real_value *a, *b;
+static bool
+do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+            const REAL_VALUE_TYPE *b)
 {
-  struct real_value u, t, *rr;
+  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))
     {
@@ -753,7 +672,7 @@ do_multiply (r, a, b)
     case CLASS2 (rvc_normal, rvc_zero):
       /* +-0 * ANY = 0 with appropriate sign.  */
       get_zero (r, sign);
-      return;
+      return false;
 
     case CLASS2 (rvc_zero, rvc_nan):
     case CLASS2 (rvc_normal, rvc_nan):
@@ -762,7 +681,7 @@ do_multiply (r, a, b)
       /* ANY * NaN = NaN.  */
       *r = *b;
       r->sign = sign;
-      return;
+      return false;
 
     case CLASS2 (rvc_nan, rvc_zero):
     case CLASS2 (rvc_nan, rvc_normal):
@@ -770,21 +689,20 @@ do_multiply (r, a, b)
       /* NaN * ANY = NaN.  */
       *r = *a;
       r->sign = sign;
-      return;
+      return false;
 
     case CLASS2 (rvc_zero, rvc_inf):
     case CLASS2 (rvc_inf, rvc_zero):
       /* 0 * Inf = NaN */
       get_canonical_qnan (r, sign);
-      return;
+      return false;
 
     case CLASS2 (rvc_inf, rvc_inf):
     case CLASS2 (rvc_normal, rvc_inf):
     case CLASS2 (rvc_inf, rvc_normal):
       /* Inf * Inf = Inf, R * Inf = Inf */
-    overflow:
       get_inf (r, sign);
-      return;
+      return false;
 
     case CLASS2 (rvc_normal, rvc_normal):
       break;
@@ -799,9 +717,6 @@ do_multiply (r, a, b)
     rr = r;
   get_zero (rr, 0);
 
-  u.class = rvc_normal;
-  u.sign = 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.
 
@@ -810,7 +725,7 @@ do_multiply (r, a, b)
                 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
@@ -837,11 +752,19 @@ do_multiply (r, a, b)
                     + (b->exp - (1-j)*(HOST_BITS_PER_LONG/2)));
 
          if (exp > MAX_EXP)
-           goto overflow;
+           {
+             get_inf (r, sign);
+             return true;
+           }
          if (exp < -MAX_EXP)
-           /* Would underflow to zero, which we shouldn't bother adding.  */
-           continue;
+           {
+             /* Would underflow to zero, which we shouldn't bother adding.  */
+             inexact = true;
+             continue;
+           }
 
+         memset (&u, 0, sizeof (u));
+         u.class = rvc_normal;
          u.exp = exp;
 
          for (k = j; k < SIGSZ * 2; k += 2)
@@ -855,50 +778,51 @@ do_multiply (r, a, b)
              u.sig[k / 2] = ai * bi;
            }
 
-         do_add (rr, rr, &u, 0);
+         normalize (&u);
+         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)
-     struct real_value *r;
-     const struct real_value *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;
-  struct real_value t, *rr;
+  REAL_VALUE_TYPE t, *rr;
   bool inexact;
 
   switch (CLASS2 (a->class, b->class))
     {
     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):
@@ -907,7 +831,7 @@ do_divide (r, a, b)
       /* ANY / NaN = NaN.  */
       *r = *b;
       r->sign = sign;
-      return;
+      return false;
 
     case CLASS2 (rvc_nan, rvc_zero):
     case CLASS2 (rvc_nan, rvc_normal):
@@ -915,13 +839,12 @@ do_divide (r, a, b)
       /* NaN / ANY = NaN.  */
       *r = *a;
       r->sign = sign;
-      return;
+      return false;
 
     case CLASS2 (rvc_inf, rvc_normal):
       /* Inf / R = Inf.  */
-    overflow:
       get_inf (r, sign);
-      return;
+      return false;
 
     case CLASS2 (rvc_normal, rvc_normal):
       break;
@@ -935,33 +858,42 @@ do_divide (r, a, b)
   else
     rr = r;
 
+  /* Make sure all fields in the result are initialized.  */
+  get_zero (rr, 0);
   rr->class = rvc_normal;
   rr->sign = sign;
 
   exp = a->exp - b->exp + 1;
   if (exp > MAX_EXP)
-    goto overflow;
+    {
+      get_inf (r, sign);
+      return true;
+    }
   if (exp < -MAX_EXP)
-    goto underflow;
+    {
+      get_zero (r, sign);
+      return true;
+    }
   rr->exp = exp;
 
   inexact = div_significands (rr, a, b);
-  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 struct real_value *a, *b;
-     int nan_result;
+do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
+           int nan_result)
 {
   int ret;
 
@@ -1013,18 +945,39 @@ do_compare (a, b, nan_result)
   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->class)
+    {
+    case rvc_zero:
+    case rvc_inf:
+    case rvc_nan:
+      break;
+
+    case rvc_normal:
+      if (r->exp <= 0)
+       get_zero (r, r->sign);
+      else if (r->exp < SIGNIFICAND_BITS)
+       clear_significand_below (r, SIGNIFICAND_BITS - r->exp);
+      break;
+
+    default:
+      abort ();
+    }
+}
+
 /* Perform the binary or unary operation described by CODE.
    For a unary operation, leave OP1 NULL.  */
 
 void
-real_arithmetic (tr, icode, top0, top1)
-     REAL_VALUE_TYPE *tr;
-     int icode;
-     const REAL_VALUE_TYPE *top0, *top1;
-{
-  struct real_value *r = (struct real_value *) tr;
-  const struct real_value *op0 = (const struct real_value *) top0;
-  const struct real_value *op1 = (const struct real_value *) top1;
+real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
+                const REAL_VALUE_TYPE *op1)
+{
   enum tree_code code = icode;
 
   switch (code)
@@ -1073,6 +1026,10 @@ real_arithmetic (tr, icode, top0, top1)
       r->sign = 0;
       break;
 
+    case FIX_TRUNC_EXPR:
+      do_fix_trunc (r, op0);
+      break;
+
     default:
       abort ();
     }
@@ -1081,23 +1038,19 @@ real_arithmetic (tr, icode, top0, top1)
 /* Legacy.  Similar, but return the result directly.  */
 
 REAL_VALUE_TYPE
-real_arithmetic2 (icode, top0, top1)
-     int icode;
-     const REAL_VALUE_TYPE *top0, *top1;
+real_arithmetic2 (int icode, const REAL_VALUE_TYPE *op0,
+                 const REAL_VALUE_TYPE *op1)
 {
   REAL_VALUE_TYPE r;
-  real_arithmetic (&r, icode, top0, top1);
+  real_arithmetic (&r, icode, op0, op1);
   return r;
 }
 
 bool
-real_compare (icode, top0, top1)
-     int icode;
-     const REAL_VALUE_TYPE *top0, *top1;
+real_compare (int icode, const REAL_VALUE_TYPE *op0,
+             const REAL_VALUE_TYPE *op1)
 {
   enum tree_code code = icode;
-  const struct real_value *op0 = (const struct real_value *) top0;
-  const struct real_value *op1 = (const struct real_value *) top1;
 
   switch (code)
     {
@@ -1136,11 +1089,8 @@ real_compare (icode, top0, top1)
 /* Return floor log2(R).  */
 
 int
-real_exponent (tr)
-     const REAL_VALUE_TYPE *tr;
+real_exponent (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
-
   switch (r->class)
     {
     case rvc_zero:
@@ -1155,18 +1105,11 @@ real_exponent (tr)
     }
 }
 
-
 /* R = OP0 * 2**EXP.  */
 
 void
-real_ldexp (tr, top0, exp)
-     REAL_VALUE_TYPE *tr;
-     const REAL_VALUE_TYPE *top0;
-     int exp;
+real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp)
 {
-  struct real_value *r = (struct real_value *) tr;
-  const struct real_value *op0 = (const struct real_value *) top0;
-
   *r = *op0;
   switch (r->class)
     {
@@ -1193,51 +1136,40 @@ real_ldexp (tr, top0, exp)
 /* Determine whether a floating-point value X is infinite.  */
 
 bool
-real_isinf (tr)
-     const REAL_VALUE_TYPE *tr;
+real_isinf (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
   return (r->class == rvc_inf);
 }
 
 /* Determine whether a floating-point value X is a NaN.  */
 
 bool
-real_isnan (tr)
-     const REAL_VALUE_TYPE *tr;
+real_isnan (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
   return (r->class == rvc_nan);
 }
 
 /* Determine whether a floating-point value X is negative.  */
 
 bool
-real_isneg (tr)
-     const REAL_VALUE_TYPE *tr;
+real_isneg (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
   return r->sign;
 }
 
 /* Determine whether a floating-point value X is minus zero.  */
 
 bool
-real_isnegzero (tr)
-     const REAL_VALUE_TYPE *tr;
+real_isnegzero (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
   return r->sign && r->class == rvc_zero;
 }
 
 /* Compare two floating-point objects for bitwise identity.  */
 
-extern bool
-real_identical (ta, tb)
-     const REAL_VALUE_TYPE *ta, *tb;
+bool
+real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
 {
-  const struct real_value *a = (const struct real_value *) ta;
-  const struct real_value *b = (const struct real_value *) tb;
   int i;
 
   if (a->class != b->class)
@@ -1249,22 +1181,29 @@ real_identical (ta, tb)
     {
     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;
 }
 
@@ -1272,15 +1211,12 @@ real_identical (ta, tb)
    mode MODE.  Return true if successful.  */
 
 bool
-exact_real_inverse (mode, tr)
-     enum machine_mode mode;
-     REAL_VALUE_TYPE *tr;
+exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
 {
-  const struct real_value *one = real_digit (1);
-  struct real_value *r = (struct real_value *) tr;
-  struct real_value u;
+  const REAL_VALUE_TYPE *one = real_digit (1);
+  REAL_VALUE_TYPE u;
   int i;
-  
+
   if (r->class != rvc_normal)
     return false;
 
@@ -1293,8 +1229,8 @@ exact_real_inverse (mode, tr)
 
   /* Find the inverse and truncate to the required mode.  */
   do_divide (&u, one, r);
-  real_convert ((REAL_VALUE_TYPE *)&u, mode, (REAL_VALUE_TYPE *)&u);
-  
+  real_convert (&u, mode, &u);
+
   /* The rounding may have overflowed.  */
   if (u.class != rvc_normal)
     return false;
@@ -1311,10 +1247,8 @@ exact_real_inverse (mode, tr)
 /* Render R as an integer.  */
 
 HOST_WIDE_INT
-real_to_integer (tr)
-     const REAL_VALUE_TYPE *tr;
+real_to_integer (const REAL_VALUE_TYPE *r)
 {
-  const struct real_value *r = (const struct real_value *) tr;
   unsigned HOST_WIDE_INT i;
 
   switch (r->class)
@@ -1334,6 +1268,10 @@ real_to_integer (tr)
     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;
 
@@ -1362,16 +1300,14 @@ real_to_integer (tr)
 /* Likewise, but to an integer pair, HI+LOW.  */
 
 void
-real_to_integer2 (plow, phigh, tr)
-     HOST_WIDE_INT *plow, *phigh;
-     const REAL_VALUE_TYPE *tr;
+real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
+                 const REAL_VALUE_TYPE *r)
 {
-  struct real_value r;
+  REAL_VALUE_TYPE t;
   HOST_WIDE_INT low, high;
   int exp;
 
-  r = *(const struct real_value *) tr;
-  switch (r.class)
+  switch (r->class)
     {
     case rvc_zero:
     underflow:
@@ -1382,7 +1318,7 @@ real_to_integer2 (plow, phigh, tr)
     case rvc_nan:
     overflow:
       high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
-      if (r.sign)
+      if (r->sign)
        low = 0;
       else
        {
@@ -1392,32 +1328,36 @@ real_to_integer2 (plow, phigh, tr)
       break;
 
     case rvc_normal:
-      exp = r.exp;
+      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 (&r, &r, 2*HOST_BITS_PER_WIDE_INT - exp);
+      rshift_significand (&t, r, 2*HOST_BITS_PER_WIDE_INT - exp);
       if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
        {
-         high = r.sig[SIGSZ-1];
-         low = r.sig[SIGSZ-2];
+         high = t.sig[SIGSZ-1];
+         low = t.sig[SIGSZ-2];
        }
       else if (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG)
        {
-         high = r.sig[SIGSZ-1];
+         high = t.sig[SIGSZ-1];
          high = high << (HOST_BITS_PER_LONG - 1) << 1;
-         high |= r.sig[SIGSZ-2];
+         high |= t.sig[SIGSZ-2];
 
-         low = r.sig[SIGSZ-3];
+         low = t.sig[SIGSZ-3];
          low = low << (HOST_BITS_PER_LONG - 1) << 1;
-         low |= r.sig[SIGSZ-4];
+         low |= t.sig[SIGSZ-4];
        }
       else
        abort ();
 
-      if (r.sign)
+      if (r->sign)
        {
          if (low == 0)
            high = -high;
@@ -1434,25 +1374,61 @@ real_to_integer2 (plow, phigh, tr)
   *phigh = high;
 }
 
-/* Render R as a decimal floating point constant.  Emit DIGITS
-   significant digits in the result.  If DIGITS <= 0, choose the
-   maximum for the representation.  */
+/* 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, 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;
-{
-  struct real_value r;
-  const struct real_value *one, *ten;
-  int dec_exp, max_digits, d, cmp_half;
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+                size_t digits, int crop_trailing_zeros)
+{
+  const REAL_VALUE_TYPE *one, *ten;
+  REAL_VALUE_TYPE r, pten, u, v;
+  int dec_exp, cmp_one, digit;
+  size_t max_digits;
   char *p, *first, *last;
   bool sign;
 
-  r = *(const struct real_value *)r_orig;
+  r = *r_orig;
   switch (r.class)
     {
     case rvc_zero:
@@ -1461,18 +1437,33 @@ real_to_decimal (str, r_orig, digits)
     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;
-  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);
@@ -1481,160 +1472,298 @@ real_to_decimal (str, r_orig, digits)
   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))
     {
-      d = real_to_integer ((const REAL_VALUE_TYPE *) &r);
-      do_add (&r, &r, real_digit (d), 1);
+      /* Multiply by 10 and try again.  */
+      do_multiply (&r, &r, ten);
+      digit = rtd_divmod (&r, &pten);
+      dec_exp -= 1;
+      if (digit == 0)
+       abort ();
+    }
 
-      *p++ = d + '0';
-      if (--digits == 0)
-       break;
+  /* ... or overflow.  */
+  if (digit == 10)
+    {
+      *p++ = '1';
+      if (--digits > 0)
+       *p++ = '0';
+      dec_exp += 1;
+    }
+  else if (digit > 10)
+    abort ();
+  else
+    *p++ = digit + '0';
+
+  /* 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.  */
+   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, tr, digits)
-     char *str;
-     const REAL_VALUE_TYPE *tr;
-     int digits;
+real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
+                    size_t digits, int crop_trailing_zeros)
 {
-  struct real_value r;
-  int i, j;
-  char *p;
+  int i, j, exp = r->exp;
+  char *p, *first;
+  char exp_buf[16];
+  size_t max_digits;
 
-  r = *(const struct real_value *) tr;
-
-  switch (r.class)
+  switch (r->class)
     {
     case rvc_zero:
-      r.exp = 0;
+      exp = 0;
       break;
     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 ();
     }
 
-  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)
+  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];
+       *p++ = "0123456789abcdef"[(r->sig[i] >> j) & 15];
        if (--digits == 0)
          goto out;
       }
+
  out:
-  sprintf (p, "p%+d", r.exp);
+  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.  */
 
 void
-real_from_string (tr, str)
-     REAL_VALUE_TYPE *tr;
-     const char *str;
+real_from_string (REAL_VALUE_TYPE *r, const char *str)
 {
-  struct real_value *r = (struct real_value *) tr;
   int exp = 0;
+  bool sign = false;
 
   get_zero (r, 0);
 
   if (*str == '-')
     {
-      r->sign = 1;
+      sign = true;
       str++;
     }
   else if (*str == '+')
@@ -1666,6 +1795,11 @@ real_from_string (tr, str)
       if (*str == '.')
        {
          str++;
+         if (pos == SIGNIFICAND_BITS - 4)
+           {
+             while (*str == '0')
+               str++, exp -= 4;
+           }
          while (1)
            {
              d = hex_value (*str);
@@ -1682,12 +1816,12 @@ real_from_string (tr, str)
        }
       if (*str == 'p' || *str == 'P')
        {
-         int exp_neg = 0;
+         bool exp_neg = false;
 
          str++;
          if (*str == '-')
            {
-             exp_neg = 1;
+             exp_neg = true;
              str++;
            }
          else if (*str == '+')
@@ -1696,10 +1830,9 @@ real_from_string (tr, str)
          d = 0;
          while (ISDIGIT (*str))
            {
-             int t = d;
              d *= 10;
              d += *str - '0';
-             if (d < t)
+             if (d > MAX_EXP)
                {
                  /* Overflowed the exponent.  */
                  if (exp_neg)
@@ -1717,20 +1850,13 @@ real_from_string (tr, str)
 
       r->class = rvc_normal;
       r->exp = exp;
-      if (r->exp != exp)
-       {
-         if (exp < 0)
-           goto underflow;
-         else
-           goto overflow;
-       }
 
       normalize (r);
     }
   else
     {
       /* Decimal floating point.  */
-      const struct real_value *ten = ten_to_ptwo (0);
+      const REAL_VALUE_TYPE *ten = ten_to_ptwo (0);
       int d;
 
       while (*str == '0')
@@ -1745,6 +1871,11 @@ real_from_string (tr, str)
       if (*str == '.')
        {
          str++;
+         if (r->class == rvc_zero)
+           {
+             while (*str == '0')
+               str++, exp--;
+           }
          while (ISDIGIT (*str))
            {
              d = *str++ - '0';
@@ -1757,12 +1888,12 @@ real_from_string (tr, str)
 
       if (*str == 'e' || *str == 'E')
        {
-         int exp_neg = 0;
+         bool exp_neg = false;
 
          str++;
          if (*str == '-')
            {
-             exp_neg = 1;
+             exp_neg = true;
              str++;
            }
          else if (*str == '+')
@@ -1771,10 +1902,9 @@ real_from_string (tr, str)
          d = 0;
          while (ISDIGIT (*str))
            {
-             int t = d;
              d *= 10;
              d += *str - '0';
-             if (d < t)
+             if (d > MAX_EXP)
                {
                  /* Overflowed the exponent.  */
                  if (exp_neg)
@@ -1789,38 +1919,26 @@ real_from_string (tr, str)
          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;
   return;
 
  underflow:
-  get_zero (r, r->sign);
+  get_zero (r, sign);
   return;
 
  overflow:
-  get_inf (r, r->sign);
+  get_inf (r, sign);
   return;
 }
 
 /* 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;
 
@@ -1834,15 +1952,10 @@ real_from_string2 (s, mode)
 /* Initialize R from the integer pair HIGH+LOW.  */
 
 void
-real_from_integer (tr, mode, low, high, unsigned_p)
-     REAL_VALUE_TYPE *tr;
-     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)
 {
-  struct real_value *r = (struct real_value *) tr;
-
   if (low == 0 && high == 0)
     get_zero (r, 0);
   else
@@ -1882,16 +1995,15 @@ real_from_integer (tr, mode, low, high, unsigned_p)
     }
 
   if (mode != VOIDmode)
-    real_convert (tr, mode, tr);
+    real_convert (r, mode, r);
 }
 
-/* Returns 10**2**n.  */
+/* Returns 10**2**N.  */
 
-static const struct real_value *
-ten_to_ptwo (n)
-     int n;
+static const REAL_VALUE_TYPE *
+ten_to_ptwo (int n)
 {
-  static struct real_value tens[EXP_BITS];
+  static REAL_VALUE_TYPE tens[EXP_BITS];
 
   if (n < 0 || n >= EXP_BITS)
     abort ();
@@ -1906,11 +2018,11 @@ ten_to_ptwo (n)
          for (i = 0; i < n; ++i)
            t *= t;
 
-         real_from_integer ((REAL_VALUE_TYPE *) &tens[n], VOIDmode, t, 0, 1);
+         real_from_integer (&tens[n], VOIDmode, t, 0, 1);
        }
       else
        {
-         const struct real_value *t = ten_to_ptwo (n - 1);
+         const REAL_VALUE_TYPE *t = ten_to_ptwo (n - 1);
          do_multiply (&tens[n], t, t);
        }
     }
@@ -1918,30 +2030,70 @@ ten_to_ptwo (n)
   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 struct real_value *
-real_digit (n)
-     int n;
+static const REAL_VALUE_TYPE *
+real_digit (int n)
 {
-  static struct real_value num[10];
+  static REAL_VALUE_TYPE num[10];
 
   if (n < 0 || n > 9)
     abort ();
 
   if (n > 0 && num[n].class == rvc_zero)
-    real_from_integer ((REAL_VALUE_TYPE *) &num[n], VOIDmode, n, 0, 1);
+    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);
+}
+
 /* Fills R with +Inf.  */
 
 void
-real_inf (tr)
-     REAL_VALUE_TYPE *tr;
+real_inf (REAL_VALUE_TYPE *r)
 {
-  get_inf ((struct real_value *)tr, 0);
+  get_inf (r, 0);
 }
 
 /* Fills R with a NaN whose significand is described by STR.  If QUIET,
@@ -1950,16 +2102,12 @@ real_inf (tr)
    if the string was successfully parsed.  */
 
 bool
-real_nan (tr, str, quiet, mode)
-     REAL_VALUE_TYPE *tr;
-     const char *str;
-     int quiet;
-     enum machine_mode mode;
+real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet,
+         enum machine_mode mode)
 {
-  struct real_value *r = (struct real_value *) tr;
   const struct real_format *fmt;
 
-  fmt = fmt_for_mode[mode - QFmode];
+  fmt = REAL_MODE_FORMAT (mode);
   if (fmt == NULL)
     abort ();
 
@@ -1996,7 +2144,7 @@ real_nan (tr, str, quiet, mode)
 
       while ((d = hex_value (*str)) < base)
        {
-         struct real_value u;
+         REAL_VALUE_TYPE u;
 
          switch (base)
            {
@@ -2028,43 +2176,47 @@ real_nan (tr, str, quiet, mode)
 
       /* Shift the significand into place such that the bits
         are in the most significant bits for the format.  */
-      lshift_significand (r, r, SIGNIFICAND_BITS - fmt->p);
+      lshift_significand (r, r, SIGNIFICAND_BITS - fmt->pnan);
 
       /* Our MSB is always unset for NaNs.  */
       r->sig[SIGSZ-1] &= ~SIG_MSB;
 
       /* Force quiet or signalling NaN.  */
-      if (quiet)
-       r->sig[SIGSZ-1] |= SIG_MSB >> 1;
-      else
-       r->sig[SIGSZ-1] &= ~(SIG_MSB >> 1);
-
-      /* Force at least one bit of the significand set.  */
-      for (d = 0; d < SIGSZ; ++d)
-       if (r->sig[d])
-         break;
-      if (d == SIGSZ)
-       r->sig[SIGSZ-1] |= SIG_MSB >> 2;
-
-      /* Our intermediate format forces QNaNs to have MSB-1 set.
-        If the target format has QNaNs with the top bit unset,
-        mirror the output routines and invert the top two bits.  */
-      if (!fmt->qnan_msb_set)
-       r->sig[SIGSZ-1] ^= (SIG_MSB >> 1) | (SIG_MSB >> 2);
+      r->signalling = !quiet;
     }
 
   return true;
 }
 
-/* Fills R with 2**N.  */
+/* 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_2expN (tr, n)
-     REAL_VALUE_TYPE *tr;
-     int n;
+real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
 {
-  struct real_value *r = (struct real_value *) tr;
+  const struct real_format *fmt;
+  int np2;
+
+  fmt = REAL_MODE_FORMAT (mode);
+  if (fmt == NULL)
+    abort ();
+
+  r->class = rvc_normal;
+  r->sign = sign;
+  r->signalling = 0;
+  r->canonical = 0;
+  r->exp = fmt->emax * fmt->log2_b;
 
+  np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+  memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+  clear_significand_below (r, np2);
+}
+
+/* Fills R with 2**N.  */
+
+void
+real_2expN (REAL_VALUE_TYPE *r, int n)
+{
   memset (r, 0, sizeof (*r));
 
   n++;
@@ -2082,12 +2234,11 @@ real_2expN (tr, n)
 
 \f
 static void
-round_for_format (fmt, r)
-     const struct real_format *fmt;
-     struct real_value *r;
+round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
 {
   int p2, np2, i, w;
-  bool sticky, guard, lsb;
+  unsigned long sticky;
+  bool guard, lsb;
   int emin2m1, emax2;
 
   p2 = fmt->p * fmt->log2_b;
@@ -2111,14 +2262,6 @@ round_for_format (fmt, r)
 
     case rvc_nan:
       clear_significand_below (r, np2);
-
-      /* If we've cleared the entire significand, we need one bit
-        set for this to continue to be a NaN.  */
-      for (i = 0; i < SIGSZ; ++i)
-       if (r->sig[i])
-         break;
-      if (i == SIGSZ)
-       r->sig[SIGSZ-1] = SIG_MSB >> 2;
       return;
 
     case rvc_normal:
@@ -2136,7 +2279,7 @@ round_for_format (fmt, r)
       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;
        }
     }
@@ -2161,20 +2304,19 @@ round_for_format (fmt, r)
          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,
-     followed by one sticky bit, followed by stuff.  Fold non-zero
+     followed by one sticky bit, followed by stuff.  Fold nonzero
      stuff into the sticky bit.  */
 
   sticky = 0;
   for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
-    if (r->sig[i])
-      sticky = 1;
+    sticky |= r->sig[i];
   sticky |=
     r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
 
@@ -2184,7 +2326,7 @@ round_for_format (fmt, r)
   /* Round to even.  */
   if (guard && (sticky || lsb))
     {
-      struct real_value u;
+      REAL_VALUE_TYPE u;
       get_zero (&u, 0);
       set_significand_bit (&u, np2);
 
@@ -2203,7 +2345,7 @@ round_for_format (fmt, r)
              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;
@@ -2223,16 +2365,12 @@ round_for_format (fmt, r)
 /* Extend or truncate to a new mode.  */
 
 void
-real_convert (tr, mode, ta)
-     REAL_VALUE_TYPE *tr;
-     enum machine_mode mode;
-     const REAL_VALUE_TYPE *ta;
+real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
+             const REAL_VALUE_TYPE *a)
 {
-  struct real_value *r = (struct real_value *)tr;
-  const struct real_value *a = (const struct real_value *)ta;
   const struct real_format *fmt;
 
-  fmt = fmt_for_mode[mode - QFmode];
+  fmt = REAL_MODE_FORMAT (mode);
   if (fmt == NULL)
     abort ();
 
@@ -2247,9 +2385,7 @@ real_convert (tr, mode, ta)
 /* 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);
@@ -2259,38 +2395,29 @@ real_value_truncate (mode, a)
 /* Return true if truncating to MODE is exact.  */
 
 bool
-exact_real_truncate (mode, ta)
-     enum machine_mode mode;
-     const REAL_VALUE_TYPE *ta;
+exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
 {
   REAL_VALUE_TYPE t;
-  real_convert (&t, mode, ta);
-  return real_identical (&t, ta);
+  real_convert (&t, mode, a);
+  return real_identical (&t, a);
 }
 
-/* Write R to the target format of MODE.  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.
+/* 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 (buf, tr, mode)
-     long *buf;
-     const REAL_VALUE_TYPE *tr;
-     enum machine_mode mode;
+real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig,
+                   const struct real_format *fmt)
 {
-  struct real_value r;
-  const struct real_format *fmt;
+  REAL_VALUE_TYPE r;
   long buf1;
 
-  r = *(const struct real_value *) tr;
-
-  fmt = fmt_for_mode[mode - QFmode];
-  if (fmt == NULL)
-    abort ();
-
+  r = *r_orig;
   round_for_format (fmt, &r);
+
   if (!buf)
     buf = &buf1;
   (*fmt->encode) (fmt, buf, &r);
@@ -2298,59 +2425,121 @@ real_to_target (buf, tr, mode)
   return *buf;
 }
 
-/* Read R from the target format of MODE.  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.  */
+/* 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);
+  if (fmt == NULL)
+    abort ();
+
+  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 (tr, buf, mode)
-     REAL_VALUE_TYPE *tr;
-     const long *buf;
-     enum machine_mode mode;
+real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode)
 {
-  struct real_value *r = (struct real_value *) tr;
   const struct real_format *fmt;
 
-  fmt = fmt_for_mode[mode - QFmode];
+  fmt = REAL_MODE_FORMAT (mode);
   if (fmt == NULL)
     abort ();
 
   (*fmt->decode) (fmt, r, buf);
-}     
+}
 
 /* Return the number of bits in the significand for MODE.  */
 /* ??? Legacy.  Should get access to real_format directly.  */
 
 int
-significand_size (mode)
-     enum machine_mode mode;
+significand_size (enum machine_mode mode)
 {
   const struct real_format *fmt;
 
-  fmt = fmt_for_mode[mode - QFmode];
+  fmt = REAL_MODE_FORMAT (mode);
   if (fmt == NULL)
     return 0;
 
   return fmt->p * fmt->log2_b;
 }
+
+/* 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->class | (r->sign << 2);
+  switch (r->class)
+    {
+    case rvc_zero:
+    case rvc_inf:
+      return h;
+
+    case rvc_normal:
+      h |= r->exp << 3;
+      break;
+
+    case rvc_nan:
+      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 struct real_value *));
-static void decode_ieee_single PARAMS ((const struct real_format *,
-                                       struct real_value *, 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 struct real_value *r;
+encode_ieee_single (const struct real_format *fmt, long *buf,
+                   const REAL_VALUE_TYPE *r)
 {
   unsigned long image, sig, exp;
+  unsigned long sign = r->sign;
   bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
 
-  image = r->sign << 31;
+  image = sign << 31;
   sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
 
   switch (r->class)
@@ -2368,10 +2557,23 @@ encode_ieee_single (fmt, buf, r)
     case rvc_nan:
       if (fmt->has_nans)
        {
+         if (r->canonical)
+           sig = 0;
+         if (r->signalling == fmt->qnan_msb_set)
+           sig &= ~(1 << 22);
+         else
+           sig |= 1 << 22;
+         /* We overload qnan_msb_set here: it's only clear for
+            mips_ieee_single, which wants all mantissa bits but the
+            quiet/signalling one set in canonical NaNs (at least
+            Quiet ones).  */
+         if (r->canonical && !fmt->qnan_msb_set)
+           sig |= (1 << 22) - 1;
+         else if (sig == 0)
+           sig = 1 << 21;
+
          image |= 255 << 23;
          image |= sig;
-         if (!fmt->qnan_msb_set)
-           image ^= 1 << 23 | 1 << 22;
        }
       else
        image |= 0x7fffffff;
@@ -2388,16 +2590,17 @@ encode_ieee_single (fmt, buf, r)
       image |= exp << 23;
       image |= sig;
       break;
+
+    default:
+      abort ();
     }
 
   buf[0] = image;
 }
 
 static void
-decode_ieee_single (fmt, r, buf)
-     const struct real_format *fmt;
-     struct real_value *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;
@@ -2426,8 +2629,8 @@ decode_ieee_single (fmt, r, buf)
        {
          r->class = rvc_nan;
          r->sign = sign;
-         if (!fmt->qnan_msb_set)
-           image ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
+         r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+                          ^ fmt->qnan_msb_set);
          r->sig[SIGSZ-1] = image;
        }
       else
@@ -2445,15 +2648,17 @@ decode_ieee_single (fmt, r, buf)
     }
 }
 
-const struct real_format ieee_single = 
+const struct real_format ieee_single_format =
   {
     encode_ieee_single,
     decode_ieee_single,
     2,
     1,
     24,
+    24,
     -125,
     128,
+    31,
     true,
     true,
     true,
@@ -2461,19 +2666,35 @@ const struct real_format ieee_single =
     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 struct real_value *));
-static void decode_ieee_double PARAMS ((const struct real_format *,
-                                       struct real_value *, 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 struct real_value *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;
@@ -2513,10 +2734,26 @@ encode_ieee_double (fmt, buf, r)
     case rvc_nan:
       if (fmt->has_nans)
        {
+         if (r->canonical)
+           sig_hi = sig_lo = 0;
+         if (r->signalling == fmt->qnan_msb_set)
+           sig_hi &= ~(1 << 19);
+         else
+           sig_hi |= 1 << 19;
+         /* We overload qnan_msb_set here: it's only clear for
+            mips_ieee_single, which wants all mantissa bits but the
+            quiet/signalling one set in canonical NaNs (at least
+            Quiet ones).  */
+         if (r->canonical && !fmt->qnan_msb_set)
+           {
+             sig_hi |= (1 << 19) - 1;
+             sig_lo = 0xffffffff;
+           }
+         else if (sig_hi == 0 && sig_lo == 0)
+           sig_hi = 1 << 18;
+
          image_hi |= 2047 << 20;
          image_hi |= sig_hi;
-         if (!fmt->qnan_msb_set)
-           image_hi ^= 1 << 19 | 1 << 18;
          image_lo = sig_lo;
        }
       else
@@ -2538,6 +2775,9 @@ encode_ieee_double (fmt, buf, r)
       image_hi |= sig_hi;
       image_lo = sig_lo;
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -2547,10 +2787,8 @@ encode_ieee_double (fmt, buf, r)
 }
 
 static void
-decode_ieee_double (fmt, r, buf)
-     const struct real_format *fmt;
-     struct real_value *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;
@@ -2603,6 +2841,7 @@ decode_ieee_double (fmt, r, buf)
        {
          r->class = rvc_nan;
          r->sign = sign;
+         r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set;
          if (HOST_BITS_PER_LONG == 32)
            {
              r->sig[SIGSZ-1] = image_hi;
@@ -2610,9 +2849,6 @@ decode_ieee_double (fmt, r, buf)
            }
          else
            r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
-
-         if (!fmt->qnan_msb_set)
-           r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
        }
       else
        {
@@ -2635,15 +2871,17 @@ decode_ieee_double (fmt, r, buf)
     }
 }
 
-const struct real_format ieee_double = 
+const struct real_format ieee_double_format =
   {
     encode_ieee_double,
     decode_ieee_double,
     2,
     1,
     53,
+    53,
     -1021,
     1024,
+    63,
     true,
     true,
     true,
@@ -2651,28 +2889,42 @@ const struct real_format ieee_double =
     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 struct real_value *));
-static void decode_ieee_extended PARAMS ((const struct real_format *,
-                                         struct real_value *, 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 struct real_value *));
-static void decode_ieee_extended_128 PARAMS ((const struct real_format *,
-                                             struct real_value *,
-                                             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 struct real_value *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;
@@ -2717,8 +2969,12 @@ encode_ieee_extended (fmt, buf, r)
              sig_hi = sig_lo >> 31 >> 1;
              sig_lo &= 0xffffffff;
            }
-         if (!fmt->qnan_msb_set)
-           sig_hi ^= 1 << 30 | 1 << 29;
+         if (r->signalling == fmt->qnan_msb_set)
+           sig_hi &= ~(1 << 30);
+         else
+           sig_hi |= 1 << 30;
+         if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
+           sig_hi = 1 << 29;
 
          /* Intel requires the explicit integer bit to be set, otherwise
             it considers the value a "pseudo-nan".  Motorola docs say it
@@ -2738,11 +2994,11 @@ encode_ieee_extended (fmt, buf, r)
 
        /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
           whereas the intermediate representation is 0.F x 2**exp.
-          Which means we're off by one. 
+          Which means we're off by one.
 
           Except for Motorola, which consider exp=0 and explicit
           integer bit set to continue to be normalized.  In theory
-          this descrepency has been taken care of by the difference
+          this discrepancy has been taken care of by the difference
           in fmt->emin in round_for_format.  */
 
        if (denormal)
@@ -2768,6 +3024,9 @@ encode_ieee_extended (fmt, buf, r)
          }
       }
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -2777,20 +3036,16 @@ encode_ieee_extended (fmt, buf, r)
 }
 
 static void
-encode_ieee_extended_128 (fmt, buf, r)
-     const struct real_format *fmt;
-     long *buf;
-     const struct real_value *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;
-     struct real_value *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;
@@ -2846,6 +3101,7 @@ decode_ieee_extended (fmt, r, buf)
        {
          r->class = rvc_nan;
          r->sign = sign;
+         r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
          if (HOST_BITS_PER_LONG == 32)
            {
              r->sig[SIGSZ-1] = sig_hi;
@@ -2853,9 +3109,6 @@ decode_ieee_extended (fmt, r, buf)
            }
          else
            r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
-
-         if (!fmt->qnan_msb_set)
-           r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
        }
       else
        {
@@ -2879,23 +3132,23 @@ decode_ieee_extended (fmt, r, buf)
 }
 
 static void
-decode_ieee_extended_128 (fmt, r, buf)
-     const struct real_format *fmt;
-     struct real_value *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 = 
+const struct real_format ieee_extended_motorola_format =
   {
     encode_ieee_extended,
     decode_ieee_extended,
     2,
     1,
     64,
+    64,
     -16382,
     16384,
+    95,
     true,
     true,
     true,
@@ -2903,15 +3156,17 @@ const struct real_format ieee_extended_motorola =
     true
   };
 
-const struct real_format ieee_extended_intel_96 = 
+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,
@@ -2919,15 +3174,117 @@ const struct real_format ieee_extended_intel_96 =
     true
   };
 
-const struct real_format ieee_extended_intel_128 = 
+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,
+    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
+   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
+   ignored.  Zeroes, Infinities, and NaNs are set in both doubles
+   due to precedent.  */
+
+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, v;
+  const struct real_format *base_fmt;
+
+  base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
+
+  /* u = IEEE double precision portion of significand.  */
+  u = *r;
+  round_for_format (base_fmt, &u);
+  encode_ieee_double (base_fmt, &buf[0], &u);
+
+  if (r->class == rvc_normal)
+    {
+      do_add (&v, r, &u, 1);
+      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.class != rvc_zero && u.class != rvc_inf && u.class != 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,
+    1,
+    53 + 53,
+    53,
+    -1021 + 53,
+    1024,
+    -1,
     true,
     true,
     true,
@@ -2935,23 +3292,39 @@ const struct real_format ieee_extended_intel_128 =
     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 struct real_value *));
-static void decode_ieee_quad PARAMS ((const struct real_format *,
-                                     struct real_value *, 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 struct real_value *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;
-  struct real_value u;
+  REAL_VALUE_TYPE u;
 
   image3 = r->sign << 31;
   image2 = 0;
@@ -2982,7 +3355,12 @@ encode_ieee_quad (fmt, buf, r)
        {
          image3 |= 32767 << 16;
 
-         if (HOST_BITS_PER_LONG == 32)
+         if (r->canonical)
+           {
+             /* Don't use bits from the significand.  The
+                initialization above is right.  */
+           }
+         else if (HOST_BITS_PER_LONG == 32)
            {
              image0 = u.sig[0];
              image1 = u.sig[1];
@@ -2998,9 +3376,21 @@ encode_ieee_quad (fmt, buf, r)
              image0 &= 0xffffffff;
              image2 &= 0xffffffff;
            }
-
-         if (!fmt->qnan_msb_set)
-           image3 ^= 1 << 15 | 1 << 14;
+         if (r->signalling == fmt->qnan_msb_set)
+           image3 &= ~0x8000;
+         else
+           image3 |= 0x8000;
+         /* We overload qnan_msb_set here: it's only clear for
+            mips_ieee_single, which wants all mantissa bits but the
+            quiet/signalling one set in canonical NaNs (at least
+            Quiet ones).  */
+         if (r->canonical && !fmt->qnan_msb_set)
+           {
+             image3 |= 0x7fff;
+             image2 = image1 = image0 = 0xffffffff;
+           }
+         else if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
+           image3 |= 0x4000;
        }
       else
        {
@@ -3038,6 +3428,9 @@ encode_ieee_quad (fmt, buf, r)
          image2 &= 0xffffffff;
        }
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -3057,10 +3450,8 @@ encode_ieee_quad (fmt, buf, r)
 }
 
 static void
-decode_ieee_quad (fmt, r, buf)
-     const struct real_format *fmt;
-     struct real_value *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;
@@ -3122,6 +3513,7 @@ decode_ieee_quad (fmt, r, buf)
        {
          r->class = rvc_nan;
          r->sign = sign;
+         r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
 
          if (HOST_BITS_PER_LONG == 32)
            {
@@ -3136,9 +3528,6 @@ decode_ieee_quad (fmt, r, buf)
              r->sig[1] = (image3 << 31 << 1) | image2;
            }
          lshift_significand (r, r, SIGNIFICAND_BITS - 113);
-
-         if (!fmt->qnan_msb_set)
-           r->sig[SIGSZ-1] ^= (SIG_MSB >> 1 | SIG_MSB >> 2);
        }
       else
        {
@@ -3169,15 +3558,17 @@ decode_ieee_quad (fmt, r, buf)
     }
 }
 
-const struct real_format ieee_quad = 
+const struct real_format ieee_quad_format =
   {
     encode_ieee_quad,
     decode_ieee_quad,
     2,
     1,
     113,
-    -16382,
+    113,
+    -16381,
     16384,
+    127,
     true,
     true,
     true,
@@ -3185,27 +3576,50 @@ const struct real_format ieee_quad =
     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
-/* The VAX floating point formats.  */
-
-static void encode_vax_f PARAMS ((const struct real_format *fmt,
-                                 long *, const struct real_value *));
-static void decode_vax_f PARAMS ((const struct real_format *,
-                                 struct real_value *, const long *));
-static void encode_vax_d PARAMS ((const struct real_format *fmt,
-                                 long *, const struct real_value *));
-static void decode_vax_d PARAMS ((const struct real_format *,
-                                 struct real_value *, const long *));
-static void encode_vax_g PARAMS ((const struct real_format *fmt,
-                                 long *, const struct real_value *));
-static void decode_vax_g PARAMS ((const struct real_format *,
-                                 struct real_value *, const long *));
+/* 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 (fmt, buf, r)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     long *buf;
-     const struct real_value *r;
+encode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+             const REAL_VALUE_TYPE *r)
 {
   unsigned long sign, exp, sig, image;
 
@@ -3231,16 +3645,17 @@ encode_vax_f (fmt, buf, r)
       image |= exp << 7;
       image |= sig >> 16;
       break;
+
+    default:
+      abort ();
     }
 
   buf[0] = image;
 }
 
 static void
-decode_vax_f (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3259,10 +3674,8 @@ decode_vax_f (fmt, r, buf)
 }
 
 static void
-encode_vax_d (fmt, buf, r)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     long *buf;
-     const struct real_value *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;
 
@@ -3303,6 +3716,9 @@ encode_vax_d (fmt, buf, r)
       image0 |= sign;
       image0 |= (r->exp + 128) << 7;
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -3312,10 +3728,8 @@ encode_vax_d (fmt, buf, r)
 }
 
 static void
-decode_vax_d (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3327,7 +3741,7 @@ decode_vax_d (fmt, r, buf)
   image0 &= 0xffffffff;
   image1 &= 0xffffffff;
 
-  exp = (image0 >> 7) & 0x7f;
+  exp = (image0 >> 7) & 0xff;
 
   memset (r, 0, sizeof (*r));
 
@@ -3360,10 +3774,8 @@ decode_vax_d (fmt, r, buf)
 }
 
 static void
-encode_vax_g (fmt, buf, r)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     long *buf;
-     const struct real_value *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;
 
@@ -3404,6 +3816,9 @@ encode_vax_g (fmt, buf, r)
       image0 |= sign;
       image0 |= (r->exp + 1024) << 4;
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -3413,10 +3828,8 @@ encode_vax_g (fmt, buf, r)
 }
 
 static void
-decode_vax_g (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3460,15 +3873,17 @@ decode_vax_g (fmt, r, buf)
     }
 }
 
-const struct real_format vax_f_format = 
+const struct real_format vax_f_format =
   {
     encode_vax_f,
     decode_vax_f,
     2,
     1,
     24,
+    24,
     -127,
     127,
+    15,
     false,
     false,
     false,
@@ -3476,15 +3891,17 @@ const struct real_format vax_f_format =
     false
   };
 
-const struct real_format vax_d_format = 
+const struct real_format vax_d_format =
   {
     encode_vax_d,
     decode_vax_d,
     2,
     1,
     56,
+    56,
     -127,
     127,
+    15,
     false,
     false,
     false,
@@ -3492,44 +3909,43 @@ const struct real_format vax_d_format =
     false
   };
 
-const struct real_format vax_g_format = 
+const struct real_format vax_g_format =
   {
     encode_vax_g,
     decode_vax_g,
     2,
     1,
     53,
+    53,
     -1023,
     1023,
+    15,
     false,
     false,
     false,
     false,
     false
   };
-
 \f
-/* The IBM S/390 floating point formats.  A good reference for these can
-   be found in chapter 9 of "ESA/390 Principles of Operation", IBM document
-   number SA22-7201-01.  An on-line version can be found here:
+/* A good reference for these can be found in chapter 9 of
+   "ESA/390 Principles of Operation", IBM document number SA22-7201-01.
+   An on-line version can be found here:
 
    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 struct real_value *));
-static void decode_i370_single PARAMS ((const struct real_format *,
-                                       struct real_value *, const long *));
-static void encode_i370_double PARAMS ((const struct real_format *fmt,
-                                       long *, const struct real_value *));
-static void decode_i370_double PARAMS ((const struct real_format *,
-                                       struct real_value *, 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 struct real_value *r;
+encode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+                   long *buf, const REAL_VALUE_TYPE *r)
 {
   unsigned long sign, exp, sig, image;
 
@@ -3551,16 +3967,17 @@ encode_i370_single (fmt, buf, r)
       exp = ((r->exp / 4) + 64) << 24;
       image = sign | exp | sig;
       break;
+
+    default:
+      abort ();
     }
 
   buf[0] = image;
 }
 
 static void
-decode_i370_single (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3582,10 +3999,8 @@ decode_i370_single (fmt, r, buf)
 }
 
 static void
-encode_i370_double (fmt, buf, r)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     long *buf;
-     const struct real_value *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;
 
@@ -3621,6 +4036,9 @@ encode_i370_double (fmt, buf, r)
       exp = ((r->exp / 4) + 64) << 24;
       image_hi |= sign | exp;
       break;
+
+    default:
+      abort ();
     }
 
   if (FLOAT_WORDS_BIG_ENDIAN)
@@ -3630,10 +4048,8 @@ encode_i370_double (fmt, buf, r)
 }
 
 static void
-decode_i370_double (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3668,15 +4084,17 @@ decode_i370_double (fmt, r, buf)
     }
 }
 
-const struct real_format i370_single =
+const struct real_format i370_single_format =
   {
     encode_i370_single,
     decode_i370_single,
     16,
     4,
     6,
+    6,
     -64,
     63,
+    31,
     false,
     false,
     false, /* ??? The encoding does allow for "unnormals".  */
@@ -3684,42 +4102,58 @@ const struct real_format i370_single =
     false
   };
 
-const struct real_format i370_double =
+const struct real_format i370_double_format =
   {
     encode_i370_double,
     decode_i370_double,
     16,
     4,
     14,
+    14,
     -64,
     63,
+    63,
     false,
     false,
     false, /* ??? The encoding does allow for "unnormals".  */
     false, /* ??? The encoding does allow for "unnormals".  */
     false
   };
-
 \f
-/* TMS320C[34]x twos complement floating point format.  */
+/* The "twos-complement" c4x format is officially defined as
+
+       x = s(~s).f * 2**e
+
+   This is rather misleading.  One must remember that F is signed.
+   A better description would be
+
+       x = -1**s * ((s + 1 + .f) * 2**e
+
+   So if we have a (4 bit) fraction of .1000 with a sign bit of 1,
+   that's -1 * (1+1+(-.5)) == -1.5.  I think.
 
-static void encode_c4x_single PARAMS ((const struct real_format *fmt,
-                                      long *, const struct real_value *));
-static void decode_c4x_single PARAMS ((const struct real_format *,
-                                      struct real_value *, const long *));
-static void encode_c4x_extended PARAMS ((const struct real_format *fmt,
-                                        long *, const struct real_value *));
-static void decode_c4x_extended PARAMS ((const struct real_format *,
-                                        struct real_value *, const long *));
+   The constructions here are taken from Tables 5-1 and 5-2 of the
+   TMS320C4x User's Guide wherein step-by-step instructions for
+   conversion from IEEE are presented.  That's close enough to our
+   internal representation so as to make things easy.
+
+   See http://www-s.ti.com/sc/psheets/spru063c/spru063c.pdf  */
+
+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 struct real_value *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:
@@ -3745,6 +4179,9 @@ encode_c4x_single (fmt, buf, r)
          sig |= 0x800000;
        }
       break;
+
+    default:
+      abort ();
     }
 
   image = ((exp & 0xff) << 24) | (sig & 0xffffff);
@@ -3752,10 +4189,8 @@ encode_c4x_single (fmt, buf, r)
 }
 
 static void
-decode_c4x_single (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3787,13 +4222,11 @@ decode_c4x_single (fmt, r, buf)
 }
 
 static void
-encode_c4x_extended (fmt, buf, r)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     long *buf;
-     const struct real_value *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:
@@ -3824,6 +4257,9 @@ encode_c4x_extended (fmt, buf, r)
          sig |= 0x80000000;
        }
       break;
+
+    default:
+      abort ();
     }
 
   exp = (exp & 0xff) << 24;
@@ -3836,10 +4272,8 @@ encode_c4x_extended (fmt, buf, r)
 }
 
 static void
-decode_c4x_extended (fmt, r, buf)
-     const struct real_format *fmt ATTRIBUTE_UNUSED;
-     struct real_value *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;
@@ -3876,15 +4310,17 @@ decode_c4x_extended (fmt, r, buf)
     }
 }
 
-const struct real_format c4x_single = 
+const struct real_format c4x_single_format =
   {
     encode_c4x_single,
     decode_c4x_single,
     2,
     1,
     24,
+    24,
     -126,
     128,
+    -1,
     false,
     false,
     false,
@@ -3892,15 +4328,17 @@ const struct real_format c4x_single =
     false
   };
 
-const struct real_format c4x_extended = 
+const struct real_format c4x_extended_format =
   {
     encode_c4x_extended,
     decode_c4x_extended,
     2,
     1,
     32,
+    32,
     -126,
     128,
+    -1,
     false,
     false,
     false,
@@ -3909,103 +4347,233 @@ const struct real_format c4x_extended =
   };
 
 \f
-/* Initialize things at start of compilation.  */
+/* 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 const struct real_format * format_for_size PARAMS ((int));
+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 const struct real_format *
-format_for_size (size)
-     int size;
+static void
+encode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+                const REAL_VALUE_TYPE *r)
 {
-#ifndef TARGET_G_FORMAT
-#define TARGET_G_FORMAT 0
-#endif
+  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));
+}
 
-  switch (TARGET_FLOAT_FORMAT)
+const struct real_format real_internal_format =
+  {
+    encode_internal,
+    decode_internal,
+    2,
+    1,
+    SIGNIFICAND_BITS - 2,
+    SIGNIFICAND_BITS - 2,
+    -MAX_EXP,
+    MAX_EXP,
+    -1,
+    true,
+    true,
+    false,
+    true,
+    true
+  };
+\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))
     {
-    case IEEE_FLOAT_FORMAT:
-      switch (size)
-       {
-       case 32:
-         return &ieee_single;
+      *r = *x;
+      return false;
+    }
 
-       case 64:
-         return &ieee_double;
+  /* Negative arguments return NaN.  */
+  if (real_isneg (x))
+    {
+      get_canonical_qnan (r, 0);
+      return false;
+    }
 
-       case 96:
-         if (!INTEL_EXTENDED_IEEE_FORMAT)
-           return &ieee_extended_motorola;
-         else
-           return &ieee_extended_intel_96;
+  /* Infinity and NaN return themselves.  */
+  if (real_isinf (x) || real_isnan (x))
+    {
+      *r = *x;
+      return false;
+    }
 
-       case 128:
-         if (!INTEL_EXTENDED_IEEE_FORMAT)
-           return &ieee_quad;
-         else
-           return &ieee_extended_intel_128;
-       }
-      break;
+  if (!init)
+    {
+      do_add (&halfthree, &dconst1, &dconsthalf, 0);
+      init = true;
+    }
 
-    case VAX_FLOAT_FORMAT:
-      switch (size)
-       {
-       case 32:
-         return &vax_f_format;
+  /* Initial guess for reciprocal sqrt, i.  */
+  exp = real_exponent (x);
+  real_ldexp (&i, &dconst1, -exp/2);
 
-       case 64:
-         if (TARGET_G_FORMAT)
-           return &vax_g_format;
-         else
-           return &vax_d_format;
-       }
-      break;
+  /* 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;
 
-    case IBM_FLOAT_FORMAT:
-      switch (size)
-       {
-       case 32:
-         return &i370_single;
-       case 64:
-         return &i370_double;
-       }
-      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;
 
-    case C4X_FLOAT_FORMAT:
-      switch (size)
+  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)
        {
-       case 32:
-         return &c4x_single;
-       case 64:
-         return &c4x_extended;
+         inexact |= do_multiply (&t, &t, &t);
+         if (n & bit)
+           inexact |= do_multiply (&t, &t, x);
        }
-      break;
+      else if (n & bit)
+       init = true;
+      bit >>= 1;
     }
 
-  abort ();
+  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
-init_real_once ()
+real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode,
+           const REAL_VALUE_TYPE *x)
 {
-  int i;
+  do_fix_trunc (r, x);
+  if (mode != VOIDmode)
+    real_convert (r, mode, r);
+}
 
-  /* Set up the mode->format table.  */
-  for (i = 0; i < 3; ++i)
-    {
-      enum machine_mode mode;
-      int size;
+/* Round X to the largest integer not greater in value, i.e. round
+   down, placing the result in R in mode MODE.  */
 
-      if (i == 0)
-       size = FLOAT_TYPE_SIZE;
-      else if (i == 1)
-       size = DOUBLE_TYPE_SIZE;
-      else
-       size = LONG_DOUBLE_TYPE_SIZE;
+void
+real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
+           const REAL_VALUE_TYPE *x)
+{
+  REAL_VALUE_TYPE t;
 
-      mode = mode_for_size (size, MODE_FLOAT, 0);
-      if (mode == BLKmode)
-       abort ();
+  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);
+}
 
-      fmt_for_mode[mode - QFmode] = format_for_size (size);
-    }
+/* 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);
 }
+
+/* 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);
+}
+