OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / real.c
index 68cb71b..c5a16a8 100644 (file)
@@ -1,6 +1,6 @@
 /* real.c - software floating point emulation.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2000, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Stephen L. Moshier (moshier@world.std.com).
    Re-written by Richard Henderson <rth@redhat.com>
 
@@ -8,7 +8,7 @@
 
    GCC is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License as published by the Free
-   Software Foundation; either version 2, or (at your option) any later
+   Software Foundation; either version 3, or (at your option) any later
    version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -17,9 +17,8 @@
    for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
    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.  */
+   layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits.  */
 
 
 /* Used to classify two numbers simultaneously.  */
@@ -1168,6 +1162,14 @@ real_isnan (const REAL_VALUE_TYPE *r)
   return (r->cl == rvc_nan);
 }
 
+/* Determine whether a floating-point value X is finite.  */
+
+bool
+real_isfinite (const REAL_VALUE_TYPE *r)
+{
+  return (r->cl != rvc_nan) && (r->cl != rvc_inf);
+}
+
 /* Determine whether a floating-point value X is negative.  */
 
 bool
@@ -1264,6 +1266,35 @@ exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
   *r = u;
   return true;
 }
+
+/* Return true if arithmetic on values in IMODE that were promoted
+   from values in TMODE is equivalent to direct arithmetic on values
+   in TMODE.  */
+
+bool
+real_can_shorten_arithmetic (enum machine_mode imode, enum machine_mode tmode)
+{
+  const struct real_format *tfmt, *ifmt;
+  tfmt = REAL_MODE_FORMAT (tmode);
+  ifmt = REAL_MODE_FORMAT (imode);
+  /* These conditions are conservative rather than trying to catch the
+     exact boundary conditions; the main case to allow is IEEE float
+     and double.  */
+  return (ifmt->b == tfmt->b
+         && ifmt->p > 2 * tfmt->p
+         && ifmt->emin < 2 * tfmt->emin - tfmt->p - 2
+         && ifmt->emin < tfmt->emin - tfmt->emax - tfmt->p - 2
+         && ifmt->emax > 2 * tfmt->emax + 2
+         && ifmt->emax > tfmt->emax - tfmt->emin + tfmt->p + 2
+         && ifmt->round_towards_zero == tfmt->round_towards_zero
+         && (ifmt->has_sign_dependent_rounding
+             == tfmt->has_sign_dependent_rounding)
+         && ifmt->has_nans >= tfmt->has_nans
+         && ifmt->has_inf >= tfmt->has_inf
+         && ifmt->has_signed_zero >= tfmt->has_signed_zero
+         && !MODE_COMPOSITE_P (tmode)
+         && !MODE_COMPOSITE_P (imode));
+}
 \f
 /* Render R as an integer.  */
 
@@ -1441,20 +1472,30 @@ rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den)
 /* 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.  */
+   zeros.  If MODE is VOIDmode, round to nearest value.  Otherwise, round
+   to a string that, when parsed back in mode MODE, yields the same value.  */
 
 #define M_LOG10_2      0.30102999566398119521
 
 void
-real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
-                size_t digits, int crop_trailing_zeros)
+real_to_decimal_for_mode (char *str, const REAL_VALUE_TYPE *r_orig,
+                         size_t buf_size, size_t digits,
+                         int crop_trailing_zeros, enum machine_mode mode)
 {
+  const struct real_format *fmt = NULL;
   const REAL_VALUE_TYPE *one, *ten;
   REAL_VALUE_TYPE r, pten, u, v;
   int dec_exp, cmp_one, digit;
   size_t max_digits;
   char *p, *first, *last;
   bool sign;
+  bool round_up;
+
+  if (mode != VOIDmode)
+   {
+     fmt = REAL_MODE_FORMAT (mode);
+     gcc_assert (fmt);
+   }
 
   r = *r_orig;
   switch (r.cl)
@@ -1469,7 +1510,8 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
       return;
     case rvc_nan:
       /* ??? Print the significand as well, if not canonical?  */
-      strcpy (str, (r.sign ? "-NaN" : "+NaN"));
+      sprintf (str, "%c%cNaN", (r_orig->sign ? '-' : '+'),
+              (r_orig->signalling ? 'S' : 'Q'));
       return;
     default:
       gcc_unreachable ();
@@ -1669,17 +1711,31 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
   digit = rtd_divmod (&r, &pten);
 
   /* Round the result.  */
-  if (digit == 5)
+  if (fmt && fmt->round_towards_zero)
     {
-      /* Round to nearest.  If R is nonzero there are additional
-        nonzero digits to be extracted.  */
+      /* If the format uses round towards zero when parsing the string
+        back in, we need to always round away from zero here.  */
       if (cmp_significand_0 (&r))
        digit++;
-      /* Round to even.  */
-      else if ((p[-1] - '0') & 1)
-       digit++;
+      round_up = digit > 0;
+    }
+  else
+    {
+      if (digit == 5)
+       {
+         /* Round to nearest.  If R is nonzero there are additional
+            nonzero digits to be extracted.  */
+         if (cmp_significand_0 (&r))
+           digit++;
+         /* Round to even.  */
+         else if ((p[-1] - '0') & 1)
+           digit++;
+       }
+
+      round_up = digit > 5;
     }
-  if (digit > 5)
+
+  if (round_up)
     {
       while (p > first)
        {
@@ -1713,6 +1769,26 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
 
   /* Append the exponent.  */
   sprintf (last, "e%+d", dec_exp);
+
+#ifdef ENABLE_CHECKING
+  /* Verify that we can read the original value back in.  */
+  if (mode != VOIDmode)
+    {
+      real_from_string (&r, str);
+      real_convert (&r, mode, &r);
+      gcc_assert (real_identical (&r, r_orig));
+    }
+#endif
+}
+
+/* Likewise, except always uses round-to-nearest.  */
+
+void
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+                size_t digits, int crop_trailing_zeros)
+{
+  real_to_decimal_for_mode (str, r_orig, buf_size,
+                           digits, crop_trailing_zeros, VOIDmode);
 }
 
 /* Render R as a hexadecimal floating point constant.  Emit DIGITS
@@ -1741,7 +1817,8 @@ real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
       return;
     case rvc_nan:
       /* ??? Print the significand as well, if not canonical?  */
-      strcpy (str, (r->sign ? "-NaN" : "+NaN"));
+      sprintf (str, "%c%cNaN", (r->sign ? '-' : '+'),
+              (r->signalling ? 'S' : 'Q'));
       return;
     default:
       gcc_unreachable ();
@@ -1791,9 +1868,10 @@ real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
 }
 
 /* Initialize R from a decimal or hexadecimal string.  The string is
-   assumed to have been syntax checked already.  */
+   assumed to have been syntax checked already.  Return -1 if the
+   value underflows, +1 if overflows, and 0 otherwise. */
 
-void
+int
 real_from_string (REAL_VALUE_TYPE *r, const char *str)
 {
   int exp = 0;
@@ -1809,6 +1887,22 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str)
   else if (*str == '+')
     str++;
 
+  if (!strncmp (str, "QNaN", 4))
+    {
+      get_canonical_qnan (r, sign);
+      return 0;
+    }
+  else if (!strncmp (str, "SNaN", 4))
+    {
+      get_canonical_snan (r, sign);
+      return 0;
+    }
+  else if (!strncmp (str, "Inf", 3))
+    {
+      get_inf (r, sign);
+      return 0;
+    }
+
   if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
     {
       /* Hexadecimal floating point.  */
@@ -1865,7 +1959,7 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str)
 
       /* If the mantissa is zero, ignore the exponent.  */
       if (!cmp_significand_0 (r))
-       goto underflow;
+       goto is_a_zero;
 
       if (*str == 'p' || *str == 'P')
        {
@@ -1941,7 +2035,7 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str)
 
       /* If the mantissa is zero, ignore the exponent.  */
       if (r->cl == rvc_zero)
-       goto underflow;
+       goto is_a_zero;
 
       if (*str == 'e' || *str == 'E')
        {
@@ -1981,15 +2075,19 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str)
     }
 
   r->sign = sign;
-  return;
+  return 0;
+
+ is_a_zero:
+  get_zero (r, sign);
+  return 0;
 
  underflow:
   get_zero (r, sign);
-  return;
+  return -1;
 
  overflow:
   get_inf (r, sign);
-  return;
+  return 1;
 }
 
 /* Legacy.  Similar, but return the result directly.  */
@@ -2156,6 +2254,64 @@ times_pten (REAL_VALUE_TYPE *r, int exp)
     do_divide (r, r, &pten);
 }
 
+/* Returns the special REAL_VALUE_TYPE corresponding to 'e'.  */
+
+const REAL_VALUE_TYPE *
+dconst_e_ptr (void)
+{
+  static REAL_VALUE_TYPE value;
+
+  /* Initialize mathematical constants for constant folding builtins.
+     These constants need to be given to at least 160 bits precision.  */
+  if (value.cl == rvc_zero)
+    {
+      mpfr_t m;
+      mpfr_init2 (m, SIGNIFICAND_BITS);
+      mpfr_set_ui (m, 1, GMP_RNDN);
+      mpfr_exp (m, m, GMP_RNDN);
+      real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+      mpfr_clear (m);
+      
+    }
+  return &value;
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to 1/3.  */
+
+const REAL_VALUE_TYPE *
+dconst_third_ptr (void)
+{
+  static REAL_VALUE_TYPE value;
+
+  /* Initialize mathematical constants for constant folding builtins.
+     These constants need to be given to at least 160 bits precision.  */
+  if (value.cl == rvc_zero)
+    {
+      real_arithmetic (&value, RDIV_EXPR, &dconst1, real_digit (3));
+    }
+  return &value;
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to sqrt(2).  */
+
+const REAL_VALUE_TYPE *
+dconst_sqrt2_ptr (void)
+{
+  static REAL_VALUE_TYPE value;
+
+  /* Initialize mathematical constants for constant folding builtins.
+     These constants need to be given to at least 160 bits precision.  */
+  if (value.cl == rvc_zero)
+    {
+      mpfr_t m;
+      mpfr_init2 (m, SIGNIFICAND_BITS);
+      mpfr_sqrt_ui (m, 2, GMP_RNDN);
+      real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+      mpfr_clear (m);
+    }
+  return &value;
+}
+
 /* Fills R with +Inf.  */
 
 void
@@ -2277,18 +2433,27 @@ real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
     {
       r->cl = rvc_normal;
       r->sign = sign;
-      SET_REAL_EXP (r, fmt->emax * fmt->log2_b);
+      SET_REAL_EXP (r, fmt->emax);
 
-      np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+      np2 = SIGNIFICAND_BITS - fmt->p;
       memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
       clear_significand_below (r, np2);
+
+      if (fmt->pnan < fmt->p)
+       /* This is an IBM extended double format made up of two IEEE
+          doubles.  The value of the long double is the sum of the
+          values of the two parts.  The most significant part is
+          required to be the value of the long double rounded to the
+          nearest double.  Rounding means we need a slightly smaller
+          value for LDBL_MAX.  */
+       clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan - 1);
     }
 }
 
 /* Fills R with 2**N.  */
 
 void
-real_2expN (REAL_VALUE_TYPE *r, int n)
+real_2expN (REAL_VALUE_TYPE *r, int n, enum machine_mode fmode)
 {
   memset (r, 0, sizeof (*r));
 
@@ -2303,6 +2468,8 @@ real_2expN (REAL_VALUE_TYPE *r, int n)
       SET_REAL_EXP (r, n);
       r->sig[SIGSZ-1] = SIG_MSB;
     }
+  if (DECIMAL_FLOAT_MODE_P (fmode))
+    decimal_real_convert (r, fmode, r);
 }
 
 \f
@@ -2310,9 +2477,8 @@ static void
 round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
 {
   int p2, np2, i, w;
-  unsigned long sticky;
-  bool guard, lsb;
   int emin2m1, emax2;
+  bool round_up = false;
 
   if (r->decimal)
     {
@@ -2328,9 +2494,9 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
       decimal_real_convert (r, DFmode, r);
     }
 
-  p2 = fmt->p * fmt->log2_b;
-  emin2m1 = (fmt->emin - 1) * fmt->log2_b;
-  emax2 = fmt->emax * fmt->log2_b;
+  p2 = fmt->p;
+  emin2m1 = fmt->emin - 1;
+  emax2 = fmt->emax;
 
   np2 = SIGNIFICAND_BITS - p2;
   switch (r->cl)
@@ -2358,22 +2524,6 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
       gcc_unreachable ();
     }
 
-  /* If we're not base2, normalize the exponent to a multiple of
-     the true base.  */
-  if (fmt->log2_b != 1)
-    {
-      int shift;
-
-      gcc_assert (fmt->b != 10);
-      shift = REAL_EXP (r) & (fmt->log2_b - 1);
-      if (shift)
-       {
-         shift = fmt->log2_b - shift;
-         r->sig[0] |= sticky_rshift_significand (r, r, shift);
-         SET_REAL_EXP (r, REAL_EXP (r) + shift);
-       }
-    }
-
   /* Check the range of the exponent.  If we're out of range,
      either underflow or overflow.  */
   if (REAL_EXP (r) > emax2)
@@ -2400,21 +2550,28 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
        }
     }
 
-  /* There are P2 true significand bits, followed by one guard bit,
-     followed by one sticky bit, followed by stuff.  Fold nonzero
-     stuff into the sticky bit.  */
+  if (!fmt->round_towards_zero)
+    {
+      /* There are P2 true significand bits, followed by one guard bit,
+         followed by one sticky bit, followed by stuff.  Fold nonzero
+         stuff into the sticky bit.  */
+      unsigned long sticky;
+      bool guard, lsb;
+
+      sticky = 0;
+      for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
+       sticky |= r->sig[i];
+      sticky |= r->sig[w]
+               & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
 
-  sticky = 0;
-  for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
-    sticky |= r->sig[i];
-  sticky |=
-    r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
+      guard = test_significand_bit (r, np2 - 1);
+      lsb = test_significand_bit (r, np2);
 
-  guard = test_significand_bit (r, np2 - 1);
-  lsb = test_significand_bit (r, np2);
+      /* Round to even.  */
+      round_up = guard && (sticky || lsb);
+    }
 
-  /* Round to even.  */
-  if (guard && (sticky || lsb))
+  if (round_up)
     {
       REAL_VALUE_TYPE u;
       get_zero (&u, 0);
@@ -2429,19 +2586,6 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
          if (REAL_EXP (r) > emax2)
            goto overflow;
          r->sig[SIGSZ-1] = SIG_MSB;
-
-         if (fmt->log2_b != 1)
-           {
-             int shift = REAL_EXP (r) & (fmt->log2_b - 1);
-             if (shift)
-               {
-                 shift = fmt->log2_b - shift;
-                 rshift_significand (r, r, shift);
-                 SET_REAL_EXP (r, REAL_EXP (r) + shift);
-                 if (REAL_EXP (r) > emax2)
-                   goto overflow;
-               }
-           }
        }
     }
 
@@ -2499,7 +2643,7 @@ exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
   gcc_assert (fmt);
 
   /* Don't allow conversion to denormals.  */
-  emin2m1 = (fmt->emin - 1) * fmt->log2_b;
+  emin2m1 = fmt->emin - 1;
   if (REAL_EXP (a) <= emin2m1)
     return false;
 
@@ -2590,7 +2734,7 @@ significand_size (enum machine_mode mode)
       double log2_10 = 3.3219281;
       return fmt->p * log2_10;
     }
-  return fmt->p * fmt->log2_b;
+  return fmt->p;
 }
 
 /* Return a hash value for the given real value.  */
@@ -2672,18 +2816,12 @@ encode_ieee_single (const struct real_format *fmt, long *buf,
       if (fmt->has_nans)
        {
          if (r->canonical)
-           sig = 0;
+           sig = (fmt->canonical_nan_lsbs_set ? (1 << 22) - 1 : 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)
+         if (sig == 0)
            sig = 1 << 21;
 
          image |= 255 << 23;
@@ -2767,18 +2905,20 @@ const struct real_format ieee_single_format =
     encode_ieee_single,
     decode_ieee_single,
     2,
-    1,
     24,
     24,
     -125,
     128,
     31,
     31,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 const struct real_format mips_single_format =
@@ -2786,20 +2926,74 @@ const struct real_format mips_single_format =
     encode_ieee_single,
     decode_ieee_single,
     2,
-    1,
     24,
     24,
     -125,
     128,
     31,
     31,
+    false,
     true,
     true,
     true,
     true,
-    false
+    true,
+    false,
+    true
+  };
+
+const struct real_format motorola_single_format =
+  {
+    encode_ieee_single,
+    decode_ieee_single,
+    2,
+    24,
+    24,
+    -125,
+    128,
+    31,
+    31,
+    false,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true
   };
 
+/*  SPU Single Precision (Extended-Range Mode) format is the same as IEEE
+    single precision with the following differences:
+      - Infinities are not supported.  Instead MAX_FLOAT or MIN_FLOAT
+       are generated.
+      - NaNs are not supported.
+      - The range of non-zero numbers in binary is
+       (001)[1.]000...000 to (255)[1.]111...111.
+      - Denormals can be represented, but are treated as +0.0 when
+       used as an operand and are never generated as a result.
+      - -0.0 can be represented, but a zero result is always +0.0.
+      - the only supported rounding mode is trunction (towards zero).  */
+const struct real_format spu_single_format =
+  {
+    encode_ieee_single,
+    decode_ieee_single,
+    2,
+    24,
+    24,
+    -125,
+    129,
+    31,
+    31,
+    true,
+    false,
+    false,
+    false,
+    true,
+    true,
+    false,
+    false
+  };
 \f
 /* IEEE double-precision format.  */
 
@@ -2851,21 +3045,23 @@ encode_ieee_double (const struct real_format *fmt, long *buf,
       if (fmt->has_nans)
        {
          if (r->canonical)
-           sig_hi = sig_lo = 0;
+           {
+             if (fmt->canonical_nan_lsbs_set)
+               {
+                 sig_hi = (1 << 19) - 1;
+                 sig_lo = 0xffffffff;
+               }
+             else
+               {
+                 sig_hi = 0;
+                 sig_lo = 0;
+               }
+           }
          if (r->signalling == fmt->qnan_msb_set)
            sig_hi &= ~(1 << 19);
          else
            sig_hi |= 1 << 19;
-         /* 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)
+         if (sig_hi == 0 && sig_lo == 0)
            sig_hi = 1 << 18;
 
          image_hi |= 2047 << 20;
@@ -2992,18 +3188,20 @@ const struct real_format ieee_double_format =
     encode_ieee_double,
     decode_ieee_double,
     2,
-    1,
     53,
     53,
     -1021,
     1024,
     63,
     63,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 const struct real_format mips_double_format =
@@ -3011,20 +3209,42 @@ const struct real_format mips_double_format =
     encode_ieee_double,
     decode_ieee_double,
     2,
-    1,
     53,
     53,
     -1021,
     1024,
     63,
     63,
+    false,
     true,
     true,
     true,
     true,
-    false
+    true,
+    false,
+    true
   };
 
+const struct real_format motorola_double_format =
+  {
+    encode_ieee_double,
+    decode_ieee_double,
+    2,
+    53,
+    53,
+    -1021,
+    1024,
+    63,
+    63,
+    false,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
 \f
 /* IEEE extended real format.  This comes in three flavors: Intel's as
    a 12 byte image, Intel's as a 16 byte image, and Motorola's.  Intel
@@ -3070,7 +3290,15 @@ encode_ieee_extended (const struct real_format *fmt, long *buf,
       if (fmt->has_nans)
        {
          image_hi |= 32767;
-         if (HOST_BITS_PER_LONG == 32)
+         if (r->canonical)
+           {
+             if (fmt->canonical_nan_lsbs_set)
+               {
+                 sig_hi = (1 << 30) - 1;
+                 sig_lo = 0xffffffff;
+               }
+           }
+         else if (HOST_BITS_PER_LONG == 32)
            {
              sig_hi = r->sig[SIGSZ-1];
              sig_lo = r->sig[SIGSZ-2];
@@ -3341,13 +3569,15 @@ const struct real_format ieee_extended_motorola_format =
     encode_ieee_extended_motorola,
     decode_ieee_extended_motorola,
     2,
-    1,
     64,
     64,
     -16382,
     16384,
     95,
     95,
+    false,
+    true,
+    true,
     true,
     true,
     true,
@@ -3360,18 +3590,20 @@ const struct real_format ieee_extended_intel_96_format =
     encode_ieee_extended_intel_96,
     decode_ieee_extended_intel_96,
     2,
-    1,
     64,
     64,
     -16381,
     16384,
     79,
     79,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 const struct real_format ieee_extended_intel_128_format =
@@ -3379,18 +3611,20 @@ const struct real_format ieee_extended_intel_128_format =
     encode_ieee_extended_intel_128,
     decode_ieee_extended_intel_128,
     2,
-    1,
     64,
     64,
     -16381,
     16384,
     79,
     79,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 /* The following caters to i386 systems that set the rounding precision
@@ -3400,18 +3634,20 @@ const struct real_format ieee_extended_intel_96_round_53_format =
     encode_ieee_extended_intel_96,
     decode_ieee_extended_intel_96,
     2,
-    1,
     53,
     53,
     -16381,
     16384,
     79,
     79,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 \f
 /* IBM 128-bit extended precision format: a pair of IEEE double precision
@@ -3436,7 +3672,7 @@ encode_ibm_extended (const struct real_format *fmt, long *buf,
 
   base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
 
-  /* Renormlize R before doing any arithmetic on it.  */
+  /* Renormalize R before doing any arithmetic on it.  */
   normr = *r;
   if (normr.cl == rvc_normal)
     normalize (&normr);
@@ -3486,18 +3722,20 @@ const struct real_format ibm_extended_format =
     encode_ibm_extended,
     decode_ibm_extended,
     2,
-    1,
     53 + 53,
     53,
     -1021 + 53,
     1024,
     127,
     -1,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 const struct real_format mips_extended_format =
@@ -3505,18 +3743,20 @@ const struct real_format mips_extended_format =
     encode_ibm_extended,
     decode_ibm_extended,
     2,
-    1,
     53 + 53,
     53,
     -1021 + 53,
     1024,
     127,
     -1,
+    false,
     true,
     true,
     true,
     true,
-    false
+    true,
+    false,
+    true
   };
 
 \f
@@ -3566,8 +3806,11 @@ encode_ieee_quad (const struct real_format *fmt, long *buf,
 
          if (r->canonical)
            {
-             /* Don't use bits from the significand.  The
-                initialization above is right.  */
+             if (fmt->canonical_nan_lsbs_set)
+               {
+                 image3 |= 0x7fff;
+                 image2 = image1 = image0 = 0xffffffff;
+               }
            }
          else if (HOST_BITS_PER_LONG == 32)
            {
@@ -3589,16 +3832,7 @@ encode_ieee_quad (const struct real_format *fmt, long *buf,
            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)
+         if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
            image3 |= 0x4000;
        }
       else
@@ -3772,18 +4006,20 @@ const struct real_format ieee_quad_format =
     encode_ieee_quad,
     decode_ieee_quad,
     2,
-    1,
     113,
     113,
     -16381,
     16384,
     127,
     127,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
 const struct real_format mips_quad_format =
@@ -3791,18 +4027,20 @@ const struct real_format mips_quad_format =
     encode_ieee_quad,
     decode_ieee_quad,
     2,
-    1,
     113,
     113,
     -16381,
     16384,
     127,
     127,
+    false,
     true,
     true,
     true,
     true,
-    false
+    true,
+    false,
+    true
   };
 \f
 /* Descriptions of VAX floating point formats can be found beginning at
@@ -4089,7 +4327,6 @@ const struct real_format vax_f_format =
     encode_vax_f,
     decode_vax_f,
     2,
-    1,
     24,
     24,
     -127,
@@ -4100,6 +4337,9 @@ const struct real_format vax_f_format =
     false,
     false,
     false,
+    false,
+    false,
+    false,
     false
   };
 
@@ -4108,7 +4348,6 @@ const struct real_format vax_d_format =
     encode_vax_d,
     decode_vax_d,
     2,
-    1,
     56,
     56,
     -127,
@@ -4119,6 +4358,9 @@ const struct real_format vax_d_format =
     false,
     false,
     false,
+    false,
+    false,
+    false,
     false
   };
 
@@ -4127,7 +4369,6 @@ const struct real_format vax_g_format =
     encode_vax_g,
     decode_vax_g,
     2,
-    1,
     53,
     53,
     -1023,
@@ -4138,212 +4379,20 @@ const struct real_format vax_g_format =
     false,
     false,
     false,
+    false,
+    false,
+    false,
     false
   };
 \f
-/* 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 (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 *);
-
+/* Encode real R into a single precision DFP value in BUF.  */
 static void
-encode_i370_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
-                   long *buf, const REAL_VALUE_TYPE *r)
+encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+                       long *buf ATTRIBUTE_UNUSED, 
+                      const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
 {
-  unsigned long sign, exp, sig, image;
-
-  sign = r->sign << 31;
-
-  switch (r->cl)
-    {
-    case rvc_zero:
-      image = 0;
-      break;
-
-    case rvc_inf:
-    case rvc_nan:
-      image = 0x7fffffff | sign;
-      break;
-
-    case rvc_normal:
-      sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0xffffff;
-      exp = ((REAL_EXP (r) / 4) + 64) << 24;
-      image = sign | exp | sig;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  buf[0] = image;
-}
-
-static void
-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;
-
-  sign = (image >> 31) & 1;
-  exp = (image >> 24) & 0x7f;
-  sig = image & 0xffffff;
-
-  memset (r, 0, sizeof (*r));
-
-  if (exp || sig)
-    {
-      r->cl = rvc_normal;
-      r->sign = sign;
-      SET_REAL_EXP (r, (exp - 64) * 4);
-      r->sig[SIGSZ-1] = sig << (HOST_BITS_PER_LONG - 24);
-      normalize (r);
-    }
-}
-
-static void
-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;
-
-  sign = r->sign << 31;
-
-  switch (r->cl)
-    {
-    case rvc_zero:
-      image_hi = image_lo = 0;
-      break;
-
-    case rvc_inf:
-    case rvc_nan:
-      image_hi = 0x7fffffff | sign;
-      image_lo = 0xffffffff;
-      break;
-
-    case rvc_normal:
-      if (HOST_BITS_PER_LONG == 64)
-       {
-         image_hi = r->sig[SIGSZ-1];
-         image_lo = (image_hi >> (64 - 56)) & 0xffffffff;
-         image_hi = (image_hi >> (64 - 56 + 1) >> 31) & 0xffffff;
-       }
-      else
-       {
-         image_hi = r->sig[SIGSZ-1];
-         image_lo = r->sig[SIGSZ-2];
-         image_lo = (image_lo >> 8) | (image_hi << 24);
-         image_hi >>= 8;
-       }
-
-      exp = ((REAL_EXP (r) / 4) + 64) << 24;
-      image_hi |= sign | exp;
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  if (FLOAT_WORDS_BIG_ENDIAN)
-    buf[0] = image_hi, buf[1] = image_lo;
-  else
-    buf[0] = image_lo, buf[1] = image_hi;
-}
-
-static void
-decode_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;
-
-  if (FLOAT_WORDS_BIG_ENDIAN)
-    image_hi = buf[0], image_lo = buf[1];
-  else
-    image_lo = buf[0], image_hi = buf[1];
-
-  sign = (image_hi >> 31) & 1;
-  exp = (image_hi >> 24) & 0x7f;
-  image_hi &= 0xffffff;
-  image_lo &= 0xffffffff;
-
-  memset (r, 0, sizeof (*r));
-
-  if (exp || image_hi || image_lo)
-    {
-      r->cl = rvc_normal;
-      r->sign = sign;
-      SET_REAL_EXP (r, (exp - 64) * 4 + (SIGNIFICAND_BITS - 56));
-
-      if (HOST_BITS_PER_LONG == 32)
-       {
-         r->sig[0] = image_lo;
-         r->sig[1] = image_hi;
-       }
-      else
-       r->sig[0] = image_lo | (image_hi << 31 << 1);
-
-      normalize (r);
-    }
-}
-
-const struct real_format i370_single_format =
-  {
-    encode_i370_single,
-    decode_i370_single,
-    16,
-    4,
-    6,
-    6,
-    -64,
-    63,
-    31,
-    31,
-    false,
-    false,
-    false, /* ??? The encoding does allow for "unnormals".  */
-    false, /* ??? The encoding does allow for "unnormals".  */
-    false
-  };
-
-const struct real_format i370_double_format =
-  {
-    encode_i370_double,
-    decode_i370_double,
-    16,
-    4,
-    14,
-    14,
-    -64,
-    63,
-    63,
-    63,
-    false,
-    false,
-    false, /* ??? The encoding does allow for "unnormals".  */
-    false, /* ??? The encoding does allow for "unnormals".  */
-    false
-  };
-\f
-/* Encode real R into a single precision DFP value in BUF.  */
-static void
-encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
-                       long *buf ATTRIBUTE_UNUSED, 
-                      const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
-{
-  encode_decimal32 (fmt, buf, r);
-}
+  encode_decimal32 (fmt, buf, r);
+}
 
 /* Decode a single precision DFP value in BUF into a real R.  */
 static void 
@@ -4390,294 +4439,71 @@ decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
   decode_decimal128 (fmt, r, buf);
 }
 
-/* Single precision decimal floating point (IEEE 754R). */
+/* Single precision decimal floating point (IEEE 754). */
 const struct real_format decimal_single_format =
   {
     encode_decimal_single,
     decode_decimal_single,
     10, 
-    1,  /* log10 */
     7,
     7,
     -95,
     96,
     31,
     31,
+    false,
+    true,
     true,
     true,
     true,
     true, 
-    true
+    true,
+    false
   };
 
-/* Double precision decimal floating point (IEEE 754R). */
+/* Double precision decimal floating point (IEEE 754). */
 const struct real_format decimal_double_format =
   {
     encode_decimal_double,
     decode_decimal_double,
     10,
-    1,  /* log10 */
     16,
     16,
     -383,
     384,
     63,
     63,
+    false,
     true,
     true,
     true,
     true,
-    true
+    true,
+    true,
+    false
   };
 
-/* Quad precision decimal floating point (IEEE 754R). */
+/* Quad precision decimal floating point (IEEE 754). */
 const struct real_format decimal_quad_format =
   {
     encode_decimal_quad,
     decode_decimal_quad,
     10,
-    1,  /* log10 */
     34,
     34,
     -6143,
     6144,
     127,
     127,
+    false,
+    true,
     true,
     true,
     true, 
     true, 
-    true
-  };
-\f
-/* 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.
-
-   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 (const struct real_format *fmt ATTRIBUTE_UNUSED,
-                  long *buf, const REAL_VALUE_TYPE *r)
-{
-  unsigned long image, exp, sig;
-
-  switch (r->cl)
-    {
-    case rvc_zero:
-      exp = -128;
-      sig = 0;
-      break;
-
-    case rvc_inf:
-    case rvc_nan:
-      exp = 127;
-      sig = 0x800000 - r->sign;
-      break;
-
-    case rvc_normal:
-      exp = REAL_EXP (r) - 1;
-      sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
-      if (r->sign)
-       {
-         if (sig)
-           sig = -sig;
-         else
-           exp--;
-         sig |= 0x800000;
-       }
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  image = ((exp & 0xff) << 24) | (sig & 0xffffff);
-  buf[0] = image;
-}
-
-static void
-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;
-  int exp, sf;
-
-  exp = (((image >> 24) & 0xff) ^ 0x80) - 0x80;
-  sf = ((image & 0xffffff) ^ 0x800000) - 0x800000;
-
-  memset (r, 0, sizeof (*r));
-
-  if (exp != -128)
-    {
-      r->cl = rvc_normal;
-
-      sig = sf & 0x7fffff;
-      if (sf < 0)
-       {
-         r->sign = 1;
-         if (sig)
-           sig = -sig;
-         else
-           exp++;
-       }
-      sig = (sig << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
-
-      SET_REAL_EXP (r, exp + 1);
-      r->sig[SIGSZ-1] = sig;
-    }
-}
-
-static void
-encode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
-                    long *buf, const REAL_VALUE_TYPE *r)
-{
-  unsigned long exp, sig;
-
-  switch (r->cl)
-    {
-    case rvc_zero:
-      exp = -128;
-      sig = 0;
-      break;
-
-    case rvc_inf:
-    case rvc_nan:
-      exp = 127;
-      sig = 0x80000000 - r->sign;
-      break;
-
-    case rvc_normal:
-      exp = REAL_EXP (r) - 1;
-
-      sig = r->sig[SIGSZ-1];
-      if (HOST_BITS_PER_LONG == 64)
-       sig = sig >> 1 >> 31;
-      sig &= 0x7fffffff;
-
-      if (r->sign)
-       {
-         if (sig)
-           sig = -sig;
-         else
-           exp--;
-         sig |= 0x80000000;
-       }
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  exp = (exp & 0xff) << 24;
-  sig &= 0xffffffff;
-
-  if (FLOAT_WORDS_BIG_ENDIAN)
-    buf[0] = exp, buf[1] = sig;
-  else
-    buf[0] = sig, buf[0] = exp;
-}
-
-static void
-decode_c4x_extended (const struct real_format *fmt ATTRIBUTE_UNUSED,
-                    REAL_VALUE_TYPE *r, const long *buf)
-{
-  unsigned long sig;
-  int exp, sf;
-
-  if (FLOAT_WORDS_BIG_ENDIAN)
-    exp = buf[0], sf = buf[1];
-  else
-    sf = buf[0], exp = buf[1];
-
-  exp = (((exp >> 24) & 0xff) & 0x80) - 0x80;
-  sf = ((sf & 0xffffffff) ^ 0x80000000) - 0x80000000;
-
-  memset (r, 0, sizeof (*r));
-
-  if (exp != -128)
-    {
-      r->cl = rvc_normal;
-
-      sig = sf & 0x7fffffff;
-      if (sf < 0)
-       {
-         r->sign = 1;
-         if (sig)
-           sig = -sig;
-         else
-           exp++;
-       }
-      if (HOST_BITS_PER_LONG == 64)
-       sig = sig << 1 << 31;
-      sig |= SIG_MSB;
-
-      SET_REAL_EXP (r, exp + 1);
-      r->sig[SIGSZ-1] = sig;
-    }
-}
-
-const struct real_format c4x_single_format =
-  {
-    encode_c4x_single,
-    decode_c4x_single,
-    2,
-    1,
-    24,
-    24,
-    -126,
-    128,
-    23,
-    -1,
-    false,
-    false,
-    false,
-    false,
-    false
-  };
-
-const struct real_format c4x_extended_format =
-  {
-    encode_c4x_extended,
-    decode_c4x_extended,
-    2,
-    1,
-    32,
-    32,
-    -126,
-    128,
-    31,
-    -1,
-    false,
-    false,
-    false,
-    false,
+    true,
     false
   };
-
 \f
 /* A synthetic "format" for internal arithmetic.  It's the size of the
    internal significand minus the two bits needed for proper rounding.
@@ -4708,18 +4534,20 @@ const struct real_format real_internal_format =
     encode_internal,
     decode_internal,
     2,
-    1,
     SIGNIFICAND_BITS - 2,
     SIGNIFICAND_BITS - 2,
     -MAX_EXP,
     MAX_EXP,
     -1,
     -1,
+    false,
+    false,
     true,
     true,
     false,
     true,
-    true
+    true,
+    false
   };
 \f
 /* Calculate the square root of X in mode MODE, and store the result
@@ -4752,7 +4580,7 @@ real_sqrt (REAL_VALUE_TYPE *r, enum machine_mode mode,
     }
 
   /* Infinity and NaN return themselves.  */
-  if (real_isinf (x) || real_isnan (x))
+  if (!real_isfinite (x))
     {
       *r = *x;
       return false;
@@ -4923,30 +4751,61 @@ real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x)
 }
 
 /* Convert from REAL_VALUE_TYPE to MPFR.  The caller is responsible
-   for initializing and clearing the MPFR parmeter.  */
+   for initializing and clearing the MPFR parameter.  */
 
 void
-mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r)
+mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r, mp_rnd_t rndmode)
 {
   /* We use a string as an intermediate type.  */
   char buf[128];
+  int ret;
 
+  /* Take care of Infinity and NaN.  */
+  if (r->cl == rvc_inf)
+    {
+      mpfr_set_inf (m, r->sign == 1 ? -1 : 1);
+      return;
+    }
+  
+  if (r->cl == rvc_nan)
+    {
+      mpfr_set_nan (m);
+      return;
+    }
+  
   real_to_hexadecimal (buf, r, sizeof (buf), 0, 1);
   /* mpfr_set_str() parses hexadecimal floats from strings in the same
      format that GCC will output them.  Nothing extra is needed.  */
-  gcc_assert (mpfr_set_str (m, buf, 16, GMP_RNDN) == 0);
+  ret = mpfr_set_str (m, buf, 16, rndmode);
+  gcc_assert (ret == 0);
 }
 
-/* Convert from MPFR to REAL_VALUE_TYPE.  */
+/* Convert from MPFR to REAL_VALUE_TYPE, for a given type TYPE and rounding
+   mode RNDMODE.  TYPE is only relevant if M is a NaN.  */
 
 void
-real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m)
+real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m, tree type, mp_rnd_t rndmode)
 {
   /* We use a string as an intermediate type.  */
   char buf[128], *rstr;
   mp_exp_t exp;
 
-  rstr = mpfr_get_str (NULL, &exp, 16, 0, m, GMP_RNDN);
+  /* Take care of Infinity and NaN.  */
+  if (mpfr_inf_p (m))
+    {
+      real_inf (r);
+      if (mpfr_sgn (m) < 0)
+       *r = REAL_VALUE_NEGATE (*r);
+      return;
+    }
+
+  if (mpfr_nan_p (m))
+    {
+      real_nan (r, "", 1, TYPE_MODE (type));
+      return;
+    }
+
+  rstr = mpfr_get_str (NULL, &exp, 16, 0, m, rndmode);
 
   /* The additional 12 chars add space for the sprintf below.  This
      leaves 6 digits for the exponent which is supposedly enough.  */
@@ -4966,3 +4825,46 @@ real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m)
   
   real_from_string (r, buf);
 }
+
+/* Check whether the real constant value given is an integer.  */
+
+bool
+real_isinteger (const REAL_VALUE_TYPE *c, enum machine_mode mode)
+{
+  REAL_VALUE_TYPE cint;
+
+  real_trunc (&cint, mode, c);
+  return real_identical (c, &cint);
+}
+
+/* Write into BUF the maximum representable finite floating-point
+   number, (1 - b**-p) * b**emax for a given FP format FMT as a hex
+   float string.  LEN is the size of BUF, and the buffer must be large
+   enough to contain the resulting string.  */
+
+void
+get_max_float (const struct real_format *fmt, char *buf, size_t len)
+{
+  int i, n;
+  char *p;
+
+  strcpy (buf, "0x0.");
+  n = fmt->p;
+  for (i = 0, p = buf + 4; i + 3 < n; i += 4)
+    *p++ = 'f';
+  if (i < n)
+    *p++ = "08ce"[n - i];
+  sprintf (p, "p%d", fmt->emax);
+  if (fmt->pnan < fmt->p)
+    {
+      /* This is an IBM extended double format made up of two IEEE
+        doubles.  The value of the long double is the sum of the
+        values of the two parts.  The most significant part is
+        required to be the value of the long double rounded to the
+        nearest double.  Rounding means we need a slightly smaller
+        value for LDBL_MAX.  */
+      buf[4 + fmt->pnan / 4] = "7bde"[fmt->pnan % 4];
+    }
+
+  gcc_assert (strlen (buf) < len);
+}