OSDN Git Service

* real.h (ieee_extended_intel_96_round_53_format): New.
[pf3gnuchains/gcc-fork.git] / gcc / real.c
index a197af9..b491d88 100644 (file)
-/* real.c - implementation of REAL_ARITHMETIC, REAL_VALUE_ATOF,
-   and support for XFmode IEEE extended real floating point arithmetic.
-   Copyright (C) 1993, 94-99, 2000 Free Software Foundation, Inc.
+/* real.c - software floating point emulation.
+   Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Stephen L. Moshier (moshier@world.std.com).
+   Re-written by Richard Henderson  <rth@redhat.com>
 
-This file is part of GNU CC.
+   This file is part of GCC.
 
-GNU CC 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 version.
+   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
+   version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
 
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   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, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #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"
 
-/* To enable support of XFmode extended real floating point, define
-LONG_DOUBLE_TYPE_SIZE 96 in the tm.h file (m68k.h or i386.h).
-
-To support cross compilation between IEEE, VAX and IBM floating
-point formats, define REAL_ARITHMETIC in the tm.h file.
-
-In either case the machine files (tm.h) must not contain any code
-that tries to use host floating point arithmetic to convert
-REAL_VALUE_TYPEs from `double' to `float', pass them to fprintf,
-etc.  In cross-compile situations a REAL_VALUE_TYPE may not
-be intelligible to the host computer's native arithmetic.
-
-The emulator defaults to the host's floating point format so that
-its decimal conversion functions can be used if desired (see
-real.h).
-
-The first part of this file interfaces gcc to a floating point
-arithmetic suite that was not written with gcc in mind.  Avoid
-changing the low-level arithmetic routines unless you have suitable
-test programs available.  A special version of the PARANOIA floating
-point arithmetic tester, modified for this purpose, can be found on
-usc.edu: /pub/C-numanal/ieeetest.zoo.  Other tests, and libraries of
-XFmode and TFmode transcendental functions, can be obtained by ftp from
-netlib.att.com: netlib/cephes.   */
+/* The floating point model used internally is not exactly IEEE 754
+   compliant, and close to the description in the ISO C standard,
+   section 5.2.4.2.2 Characteristics of floating types.
+
+   Specifically
+
+       x = s * b^e * \sum_{k=1}^p f_k * b^{-k}
+
+       where
+               s = sign (+- 1)
+               b = base or radix, here always 2
+               e = exponent
+               p = precision (the number of base-b digits in the significand)
+               f_k = the digits of the significand.
+
+   We differ from typical IEEE 754 encodings in that the entire
+   significand is fractional.  Normalized significands are in the
+   range [0.5, 1.0).
+
+   A requirement of the model is that P be larger than than the 
+   largest supported target floating-point type by at least 2 bits.
+   This gives us proper rounding when we truncate to the target type.
+   In addition, E must be large enough to hold the smallest supported
+   denormal number in a normalized form.
+
+   Both of these requirements are easily satisfied.  The largest target
+   significand is 113 bits; we store at least 160.  The smallest
+   denormal number fits in 17 exponent bits; we store 29.
+
+   Note that the decimal string conversion routines are sensitive to 
+   rounding error.  Since the raw arithmetic routines do not themselves
+   have guard digits or rounding, the computation of 10**exp can
+   accumulate more than a few digits of error.  The previous incarnation
+   of real.c successfully used a 144 bit fraction; given the current
+   layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits.
+
+   Target floating point models that use base 16 instead of base 2
+   (i.e. IBM 370), are handled during round_for_format, in which we
+   canonicalize the exponent to be a multiple of 4 (log2(16)), and
+   adjust the significand to match.  */
+
+
+/* Used to classify two numbers simultaneously.  */
+#define CLASS2(A, B)  ((A) << 2 | (B))
+
+#if HOST_BITS_PER_LONG != 64 && HOST_BITS_PER_LONG != 32
+ #error "Some constant folding done by hand to avoid shift count warnings"
+#endif
+
+static void get_zero PARAMS ((REAL_VALUE_TYPE *, int));
+static void get_canonical_qnan PARAMS ((REAL_VALUE_TYPE *, int));
+static void get_canonical_snan PARAMS ((REAL_VALUE_TYPE *, int));
+static void get_inf PARAMS ((REAL_VALUE_TYPE *, int));
+static bool sticky_rshift_significand PARAMS ((REAL_VALUE_TYPE *,
+                                              const REAL_VALUE_TYPE *,
+                                              unsigned int));
+static void rshift_significand PARAMS ((REAL_VALUE_TYPE *,
+                                       const REAL_VALUE_TYPE *,
+                                       unsigned int));
+static void lshift_significand PARAMS ((REAL_VALUE_TYPE *,
+                                       const REAL_VALUE_TYPE *,
+                                       unsigned int));
+static void lshift_significand_1 PARAMS ((REAL_VALUE_TYPE *,
+                                         const REAL_VALUE_TYPE *));
+static bool add_significands PARAMS ((REAL_VALUE_TYPE *r,
+                                     const REAL_VALUE_TYPE *,
+                                     const REAL_VALUE_TYPE *));
+static bool sub_significands PARAMS ((REAL_VALUE_TYPE *,
+                                     const REAL_VALUE_TYPE *,
+                                     const REAL_VALUE_TYPE *, int));
+static void neg_significand PARAMS ((REAL_VALUE_TYPE *,
+                                    const REAL_VALUE_TYPE *));
+static int cmp_significands PARAMS ((const REAL_VALUE_TYPE *,
+                                    const REAL_VALUE_TYPE *));
+static int cmp_significand_0 PARAMS ((const REAL_VALUE_TYPE *));
+static void set_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
+static void clear_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
+static bool test_significand_bit PARAMS ((REAL_VALUE_TYPE *, unsigned int));
+static void clear_significand_below PARAMS ((REAL_VALUE_TYPE *,
+                                            unsigned int));
+static bool div_significands PARAMS ((REAL_VALUE_TYPE *,
+                                     const REAL_VALUE_TYPE *,
+                                     const REAL_VALUE_TYPE *));
+static void normalize PARAMS ((REAL_VALUE_TYPE *));
+
+static bool do_add PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+                           const REAL_VALUE_TYPE *, int));
+static bool do_multiply PARAMS ((REAL_VALUE_TYPE *,
+                                const REAL_VALUE_TYPE *,
+                                const REAL_VALUE_TYPE *));
+static bool do_divide PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+                              const REAL_VALUE_TYPE *));
+static int do_compare PARAMS ((const REAL_VALUE_TYPE *,
+                              const REAL_VALUE_TYPE *, int));
+static void do_fix_trunc PARAMS ((REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *));
+
+static unsigned long rtd_divmod PARAMS ((REAL_VALUE_TYPE *,
+                                        REAL_VALUE_TYPE *));
+
+static const REAL_VALUE_TYPE * ten_to_ptwo PARAMS ((int));
+static const REAL_VALUE_TYPE * ten_to_mptwo PARAMS ((int));
+static const REAL_VALUE_TYPE * real_digit PARAMS ((int));
+static void times_pten PARAMS ((REAL_VALUE_TYPE *, int));
+
+static void round_for_format PARAMS ((const struct real_format *,
+                                     REAL_VALUE_TYPE *));
 \f
-/* Type of computer arithmetic.
-   Only one of DEC, IBM, IEEE, C4X, or UNK should get defined.
-
-   `IEEE', when REAL_WORDS_BIG_ENDIAN is non-zero, refers generically
-   to big-endian IEEE floating-point data structure.  This definition
-   should work in SFmode `float' type and DFmode `double' type on
-   virtually all big-endian IEEE machines.  If LONG_DOUBLE_TYPE_SIZE
-   has been defined to be 96, then IEEE also invokes the particular
-   XFmode (`long double' type) data structure used by the Motorola
-   680x0 series processors.
-
-   `IEEE', when REAL_WORDS_BIG_ENDIAN is zero, refers generally to
-   little-endian IEEE machines. In this case, if LONG_DOUBLE_TYPE_SIZE
-   has been defined to be 96, then IEEE also invokes the particular
-   XFmode `long double' data structure used by the Intel 80x86 series
-   processors.
-
-   `DEC' refers specifically to the Digital Equipment Corp PDP-11
-   and VAX floating point data structure.  This model currently
-   supports no type wider than DFmode.
-
-   `IBM' refers specifically to the IBM System/370 and compatible
-   floating point data structure.  This model currently supports
-   no type wider than DFmode.  The IBM conversions were contributed by
-   frank@atom.ansto.gov.au (Frank Crawford).
-
-   `C4X' refers specifically to the floating point format used on
-   Texas Instruments TMS320C3x and TMS320C4x digital signal
-   processors.  This supports QFmode (32-bit float, double) and HFmode
-   (40-bit long double) where BITS_PER_BYTE is 32. Unlike IEEE
-   floats, C4x floats are not rounded to be even. The C4x conversions
-   were contributed by m.hayes@elec.canterbury.ac.nz (Michael Hayes) and
-   Haj.Ten.Brugge@net.HCC.nl (Herman ten Brugge).
-
-   If LONG_DOUBLE_TYPE_SIZE = 64 (the default, unless tm.h defines it)
-   then `long double' and `double' are both implemented, but they
-   both mean DFmode.  In this case, the software floating-point
-   support available here is activated by writing
-      #define REAL_ARITHMETIC
-   in tm.h.
-
-   The case LONG_DOUBLE_TYPE_SIZE = 128 activates TFmode support
-   and may deactivate XFmode since `long double' is used to refer
-   to both modes.
-
-   The macros FLOAT_WORDS_BIG_ENDIAN, HOST_FLOAT_WORDS_BIG_ENDIAN,
-   contributed by Richard Earnshaw <Richard.Earnshaw@cl.cam.ac.uk>,
-   separate the floating point unit's endian-ness from that of
-   the integer addressing.  This permits one to define a big-endian
-   FPU on a little-endian machine (e.g., ARM).  An extension to
-   BYTES_BIG_ENDIAN may be required for some machines in the future.
-   These optional macros may be defined in tm.h.  In real.h, they
-   default to WORDS_BIG_ENDIAN, etc., so there is no need to define
-   them for any normal host or target machine on which the floats
-   and the integers have the same endian-ness.   */
-
-
-/* The following converts gcc macros into the ones used by this file.  */
-
-/* REAL_ARITHMETIC defined means that macros in real.h are
-   defined to call emulator functions.  */
-#ifdef REAL_ARITHMETIC
-
-#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-/* PDP-11, Pro350, VAX: */
-#define DEC 1
-#else /* it's not VAX */
-#if TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT
-/* IBM System/370 style */
-#define IBM 1
-#else /* it's also not an IBM */
-#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
-/* TMS320C3x/C4x style */
-#define C4X 1
-#else /* it's also not a C4X */
-#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-#define IEEE
-#else /* it's not IEEE either */
-/* UNKnown arithmetic.  We don't support this and can't go on.  */
-unknown arithmetic type
-#define UNK 1
-#endif /* not IEEE */
-#endif /* not C4X */
-#endif /* not IBM */
-#endif /* not VAX */
-
-#define REAL_WORDS_BIG_ENDIAN FLOAT_WORDS_BIG_ENDIAN
-
-#else
-/* REAL_ARITHMETIC not defined means that the *host's* data
-   structure will be used.  It may differ by endian-ness from the
-   target machine's structure and will get its ends swapped
-   accordingly (but not here).  Probably only the decimal <-> binary
-   functions in this file will actually be used in this case.  */
-
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-#define DEC 1
-#else /* it's not VAX */
-#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
-/* IBM System/370 style */
-#define IBM 1
-#else /* it's also not an IBM */
-#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-#define IEEE
-#else /* it's not IEEE either */
-unknown arithmetic type
-#define UNK 1
-#endif /* not IEEE */
-#endif /* not IBM */
-#endif /* not VAX */
-
-#define REAL_WORDS_BIG_ENDIAN HOST_FLOAT_WORDS_BIG_ENDIAN
-
-#endif /* REAL_ARITHMETIC not defined */
-
-/* Define INFINITY for support of infinity.
-   Define NANS for support of Not-a-Number's (NaN's).  */
-#if !defined(DEC) && !defined(IBM) && !defined(C4X)
-#define INFINITY
-#define NANS
-#endif
+/* Initialize R with a positive zero.  */
 
-/* Support of NaNs requires support of infinity.  */
-#ifdef NANS
-#ifndef INFINITY
-#define INFINITY
-#endif
-#endif
-\f
-/* Find a host integer type that is at least 16 bits wide,
-   and another type at least twice whatever that size is.  */
-
-#if HOST_BITS_PER_CHAR >= 16
-#define EMUSHORT char
-#define EMUSHORT_SIZE HOST_BITS_PER_CHAR
-#define EMULONG_SIZE (2 * HOST_BITS_PER_CHAR)
-#else
-#if HOST_BITS_PER_SHORT >= 16
-#define EMUSHORT short
-#define EMUSHORT_SIZE HOST_BITS_PER_SHORT
-#define EMULONG_SIZE (2 * HOST_BITS_PER_SHORT)
-#else
-#if HOST_BITS_PER_INT >= 16
-#define EMUSHORT int
-#define EMUSHORT_SIZE HOST_BITS_PER_INT
-#define EMULONG_SIZE (2 * HOST_BITS_PER_INT)
-#else
-#if HOST_BITS_PER_LONG >= 16
-#define EMUSHORT long
-#define EMUSHORT_SIZE HOST_BITS_PER_LONG
-#define EMULONG_SIZE (2 * HOST_BITS_PER_LONG)
-#else
-/*  You will have to modify this program to have a smaller unit size.  */
-#define EMU_NON_COMPILE
-#endif
-#endif
-#endif
-#endif
+static inline void
+get_zero (r, sign)
+     REAL_VALUE_TYPE *r;
+     int sign;
+{
+  memset (r, 0, sizeof (*r));
+  r->sign = sign;
+}
 
-#if HOST_BITS_PER_SHORT >= EMULONG_SIZE
-#define EMULONG short
-#else
-#if HOST_BITS_PER_INT >= EMULONG_SIZE
-#define EMULONG int
-#else
-#if HOST_BITS_PER_LONG >= EMULONG_SIZE
-#define EMULONG long
-#else
-#if HOST_BITS_PER_LONGLONG >= EMULONG_SIZE
-#define EMULONG long long int
-#else
-/*  You will have to modify this program to have a smaller unit size.  */
-#define EMU_NON_COMPILE
-#endif
-#endif
-#endif
-#endif
+/* Initialize R with the canonical quiet NaN.  */
 
+static inline void
+get_canonical_qnan (r, sign)
+     REAL_VALUE_TYPE *r;
+     int sign;
+{
+  memset (r, 0, sizeof (*r));
+  r->class = rvc_nan;
+  r->sign = sign;
+  r->canonical = 1;
+}
 
-/* The host interface doesn't work if no 16-bit size exists.  */
-#if EMUSHORT_SIZE != 16
-#define EMU_NON_COMPILE
-#endif
+static inline void
+get_canonical_snan (r, sign)
+     REAL_VALUE_TYPE *r;
+     int sign;
+{
+  memset (r, 0, sizeof (*r));
+  r->class = rvc_nan;
+  r->sign = sign;
+  r->signalling = 1;
+  r->canonical = 1;
+}
+
+static inline void
+get_inf (r, sign)
+     REAL_VALUE_TYPE *r;
+     int sign;
+{
+  memset (r, 0, sizeof (*r));
+  r->class = rvc_inf;
+  r->sign = sign;
+}
 
-/* OK to continue compilation.  */
-#ifndef EMU_NON_COMPILE
-
-/* Construct macros to translate between REAL_VALUE_TYPE and e type.
-   In GET_REAL and PUT_REAL, r and e are pointers.
-   A REAL_VALUE_TYPE is guaranteed to occupy contiguous locations
-   in memory, with no holes.  */
-
-#if LONG_DOUBLE_TYPE_SIZE == 96
-/* Number of 16 bit words in external e type format */
-#define NE 6
-#define MAXDECEXP 4932
-#define MINDECEXP -4956
-#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
-#define PUT_REAL(e,r)                          \
-do {                                           \
-  if (2*NE < sizeof(*r))                       \
-    bzero((char *)r, sizeof(*r));              \
-  bcopy ((char *) e, (char *) r, 2*NE);                \
-} while (0)
-#else /* no XFmode */
-#if LONG_DOUBLE_TYPE_SIZE == 128
-#define NE 10
-#define MAXDECEXP 4932
-#define MINDECEXP -4977
-#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
-#define PUT_REAL(e,r)                          \
-do {                                           \
-  if (2*NE < sizeof(*r))                       \
-    bzero((char *)r, sizeof(*r));              \
-  bcopy ((char *) e, (char *) r, 2*NE);                \
-} while (0)
-#else
-#define NE 6
-#define MAXDECEXP 4932
-#define MINDECEXP -4956
-#ifdef REAL_ARITHMETIC
-/* Emulator uses target format internally
-   but host stores it in host endian-ness.  */
-
-#define GET_REAL(r,e)                                                  \
-do {                                                                   \
-     if (HOST_FLOAT_WORDS_BIG_ENDIAN == REAL_WORDS_BIG_ENDIAN)         \
-       e53toe ((unsigned EMUSHORT *) (r), (e));                                \
-     else                                                              \
-       {                                                               \
-        unsigned EMUSHORT w[4];                                        \
-         memcpy (&w[3], ((EMUSHORT *) r), sizeof (EMUSHORT));          \
-         memcpy (&w[2], ((EMUSHORT *) r) + 1, sizeof (EMUSHORT));      \
-         memcpy (&w[1], ((EMUSHORT *) r) + 2, sizeof (EMUSHORT));      \
-         memcpy (&w[0], ((EMUSHORT *) r) + 3, sizeof (EMUSHORT));      \
-        e53toe (w, (e));                                               \
-       }                                                               \
-   } while (0)
-
-#define PUT_REAL(e,r)                                                  \
-do {                                                                   \
-     if (HOST_FLOAT_WORDS_BIG_ENDIAN == REAL_WORDS_BIG_ENDIAN)         \
-       etoe53 ((e), (unsigned EMUSHORT *) (r));                                \
-     else                                                              \
-       {                                                               \
-        unsigned EMUSHORT w[4];                                        \
-        etoe53 ((e), w);                                               \
-         memcpy (((EMUSHORT *) r), &w[3], sizeof (EMUSHORT));          \
-         memcpy (((EMUSHORT *) r) + 1, &w[2], sizeof (EMUSHORT));      \
-         memcpy (((EMUSHORT *) r) + 2, &w[1], sizeof (EMUSHORT));      \
-         memcpy (((EMUSHORT *) r) + 3, &w[0], sizeof (EMUSHORT));      \
-       }                                                               \
-   } while (0)
-
-#else /* not REAL_ARITHMETIC */
-
-/* emulator uses host format */
-#define GET_REAL(r,e) e53toe ((unsigned EMUSHORT *) (r), (e))
-#define PUT_REAL(e,r) etoe53 ((e), (unsigned EMUSHORT *) (r))
-
-#endif /* not REAL_ARITHMETIC */
-#endif /* not TFmode */
-#endif /* not XFmode */
-
-
-/* Number of 16 bit words in internal format */
-#define NI (NE+3)
-
-/* Array offset to exponent */
-#define E 1
-
-/* Array offset to high guard word */
-#define M 2
-
-/* Number of bits of precision */
-#define NBITS ((NI-4)*16)
-
-/* Maximum number of decimal digits in ASCII conversion
- * = NBITS*log10(2)
- */
-#define NDEC (NBITS*8/27)
-
-/* The exponent of 1.0 */
-#define EXONE (0x3fff)
-
-extern int extra_warnings;
-extern unsigned EMUSHORT ezero[], ehalf[], eone[], etwo[];
-extern unsigned EMUSHORT elog2[], esqrt2[];
-
-static void endian     PARAMS ((unsigned EMUSHORT *, long *,
-                              enum machine_mode));
-static void eclear     PARAMS ((unsigned EMUSHORT *));
-static void emov       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void eabs       PARAMS ((unsigned EMUSHORT *));
-#endif
-static void eneg       PARAMS ((unsigned EMUSHORT *));
-static int eisneg      PARAMS ((unsigned EMUSHORT *));
-static int eisinf      PARAMS ((unsigned EMUSHORT *));
-static int eisnan      PARAMS ((unsigned EMUSHORT *));
-static void einfin     PARAMS ((unsigned EMUSHORT *));
-#ifdef NANS
-static void enan       PARAMS ((unsigned EMUSHORT *, int));
-static void einan      PARAMS ((unsigned EMUSHORT *));
-static int eiisnan     PARAMS ((unsigned EMUSHORT *));
-static int eiisneg     PARAMS ((unsigned EMUSHORT *));
-static void make_nan   PARAMS ((unsigned EMUSHORT *, int, enum machine_mode));
-#endif
-static void emovi      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void emovo      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void ecleaz     PARAMS ((unsigned EMUSHORT *));
-static void ecleazs    PARAMS ((unsigned EMUSHORT *));
-static void emovz      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void eiinfin    PARAMS ((unsigned EMUSHORT *));
-#endif
-#ifdef INFINITY
-static int eiisinf     PARAMS ((unsigned EMUSHORT *));
-#endif
-static int ecmpm       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void eshdn1     PARAMS ((unsigned EMUSHORT *));
-static void eshup1     PARAMS ((unsigned EMUSHORT *));
-static void eshdn8     PARAMS ((unsigned EMUSHORT *));
-static void eshup8     PARAMS ((unsigned EMUSHORT *));
-static void eshup6     PARAMS ((unsigned EMUSHORT *));
-static void eshdn6     PARAMS ((unsigned EMUSHORT *));
-static void eaddm      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));\f
-static void esubm      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void m16m       PARAMS ((unsigned int, unsigned short *,
-                              unsigned short *));
-static int edivm       PARAMS ((unsigned short *, unsigned short *));
-static int emulm       PARAMS ((unsigned short *, unsigned short *));
-static void emdnorm    PARAMS ((unsigned EMUSHORT *, int, int, EMULONG, int));
-static void esub       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-static void eadd       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-static void eadd1      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-static void ediv       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-static void emul       PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-static void e53toe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e64toe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e113toe    PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e24toe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe113    PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe113     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe64     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe64      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe53     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe53      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe24     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe24      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static int ecmp                PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void eround     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#endif
-static void ltoe       PARAMS ((HOST_WIDE_INT *, unsigned EMUSHORT *));
-static void ultoe      PARAMS ((unsigned HOST_WIDE_INT *, unsigned EMUSHORT *));
-static void eifrac     PARAMS ((unsigned EMUSHORT *, HOST_WIDE_INT *,
-                              unsigned EMUSHORT *));
-static void euifrac    PARAMS ((unsigned EMUSHORT *, unsigned HOST_WIDE_INT *,
-                              unsigned EMUSHORT *));
-static int eshift      PARAMS ((unsigned EMUSHORT *, int));
-static int enormlz     PARAMS ((unsigned EMUSHORT *));
-#if 0
-static void e24toasc   PARAMS ((unsigned EMUSHORT *, char *, int));
-static void e53toasc   PARAMS ((unsigned EMUSHORT *, char *, int));
-static void e64toasc   PARAMS ((unsigned EMUSHORT *, char *, int));
-static void e113toasc  PARAMS ((unsigned EMUSHORT *, char *, int));
-#endif /* 0 */
-static void etoasc     PARAMS ((unsigned EMUSHORT *, char *, int));
-static void asctoe24   PARAMS ((const char *, unsigned EMUSHORT *));
-static void asctoe53   PARAMS ((const char *, unsigned EMUSHORT *));
-static void asctoe64   PARAMS ((const char *, unsigned EMUSHORT *));
-static void asctoe113  PARAMS ((const char *, unsigned EMUSHORT *));
-static void asctoe     PARAMS ((const char *, unsigned EMUSHORT *));
-static void asctoeg    PARAMS ((const char *, unsigned EMUSHORT *, int));
-static void efloor     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void efrexp     PARAMS ((unsigned EMUSHORT *, int *,
-                              unsigned EMUSHORT *));
-#endif
-static void eldexp     PARAMS ((unsigned EMUSHORT *, int, unsigned EMUSHORT *));
-#if 0
-static void eremain    PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              unsigned EMUSHORT *));
-#endif
-static void eiremain   PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void mtherr     PARAMS ((const char *, int));
-#ifdef DEC
-static void dectoe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etodec     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void todec      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#endif
-#ifdef IBM
-static void ibmtoe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-static void etoibm     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-static void toibm      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-#endif
-#ifdef C4X
-static void c4xtoe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-static void etoc4x     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-static void toc4x      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *,
-                              enum machine_mode));
-#endif
-#if 0
-static void uditoe     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void ditoe      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoudi     PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etodi      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void esqrt      PARAMS ((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#endif
 \f
-/* Copy 32-bit numbers obtained from array containing 16-bit numbers,
-   swapping ends if required, into output array of longs.  The
-   result is normally passed to fprintf by the ASM_OUTPUT_ macros.   */
+/* Right-shift the significand of A by N bits; put the result in the
+   significand of R.  If any one bits are shifted out, return true.  */
 
-static void
-endian (e, x, mode)
-     unsigned EMUSHORT e[];
-     long x[];
-     enum machine_mode mode;
+static bool
+sticky_rshift_significand (r, a, n)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
+     unsigned int n;
 {
-  unsigned long th, t;
+  unsigned long sticky = 0;
+  unsigned int i, ofs = 0;
 
-  if (REAL_WORDS_BIG_ENDIAN)
+  if (n >= HOST_BITS_PER_LONG)
     {
-      switch (mode)
+      for (i = 0, ofs = n / HOST_BITS_PER_LONG; i < ofs; ++i)
+       sticky |= a->sig[i];
+      n &= HOST_BITS_PER_LONG - 1;
+    }
+
+  if (n != 0)
+    {
+      sticky |= a->sig[ofs] & (((unsigned long)1 << n) - 1);
+      for (i = 0; i < SIGSZ; ++i)
        {
-       case TFmode:
-         /* Swap halfwords in the fourth long.  */
-         th = (unsigned long) e[6] & 0xffff;
-         t = (unsigned long) e[7] & 0xffff;
-         t |= th << 16;
-         x[3] = (long) t;
-
-       case XFmode:
-         /* Swap halfwords in the third long.  */
-         th = (unsigned long) e[4] & 0xffff;
-         t = (unsigned long) e[5] & 0xffff;
-         t |= th << 16;
-         x[2] = (long) t;
-         /* fall into the double case */
-
-       case DFmode:
-         /* Swap halfwords in the second word.  */
-         th = (unsigned long) e[2] & 0xffff;
-         t = (unsigned long) e[3] & 0xffff;
-         t |= th << 16;
-         x[1] = (long) t;
-         /* fall into the float case */
-
-       case SFmode:
-       case HFmode:
-         /* Swap halfwords in the first word.  */
-         th = (unsigned long) e[0] & 0xffff;
-         t = (unsigned long) e[1] & 0xffff;
-         t |= th << 16;
-         x[0] = (long) t;
-         break;
-
-       default:
-         abort ();
+         r->sig[i]
+           = (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n)
+              | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1])
+                 << (HOST_BITS_PER_LONG - n)));
        }
     }
   else
     {
-      /* Pack the output array without swapping.  */
-
-      switch (mode)
-       {
-       case TFmode:
-         /* Pack the fourth long.  */
-         th = (unsigned long) e[7] & 0xffff;
-         t = (unsigned long) e[6] & 0xffff;
-         t |= th << 16;
-         x[3] = (long) t;
-
-       case XFmode:
-         /* Pack the third long.
-            Each element of the input REAL_VALUE_TYPE array has 16 useful bits
-            in it.  */
-         th = (unsigned long) e[5] & 0xffff;
-         t = (unsigned long) e[4] & 0xffff;
-         t |= th << 16;
-         x[2] = (long) t;
-         /* fall into the double case */
-
-       case DFmode:
-         /* Pack the second long */
-         th = (unsigned long) e[3] & 0xffff;
-         t = (unsigned long) e[2] & 0xffff;
-         t |= th << 16;
-         x[1] = (long) t;
-         /* fall into the float case */
-
-       case SFmode:
-       case HFmode:
-         /* Pack the first long */
-         th = (unsigned long) e[1] & 0xffff;
-         t = (unsigned long) e[0] & 0xffff;
-         t |= th << 16;
-         x[0] = (long) t;
-         break;
-
-       default:
-         abort ();
-       }
+      for (i = 0; ofs + i < SIGSZ; ++i)
+       r->sig[i] = a->sig[ofs + i];
+      for (; i < SIGSZ; ++i)
+       r->sig[i] = 0;
     }
-}
 
+  return sticky != 0;
+}
 
-/* This is the implementation of the REAL_ARITHMETIC macro.  */
+/* Right-shift the significand of A by N bits; put the result in the
+   significand of R.  */
 
-void
-earith (value, icode, r1, r2)
-     REAL_VALUE_TYPE *value;
-     int icode;
-     REAL_VALUE_TYPE *r1;
-     REAL_VALUE_TYPE *r2;
+static void
+rshift_significand (r, a, n)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
+     unsigned int n;
 {
-  unsigned EMUSHORT d1[NE], d2[NE], v[NE];
-  enum tree_code code;
-
-  GET_REAL (r1, d1);
-  GET_REAL (r2, d2);
-#ifdef NANS
-/*  Return NaN input back to the caller.  */
-  if (eisnan (d1))
+  unsigned int i, ofs = n / HOST_BITS_PER_LONG;
+
+  n &= HOST_BITS_PER_LONG - 1;
+  if (n != 0)
     {
-      PUT_REAL (d1, value);
-      return;
+      for (i = 0; i < SIGSZ; ++i)
+       {
+         r->sig[i]
+           = (((ofs + i >= SIGSZ ? 0 : a->sig[ofs + i]) >> n)
+              | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[ofs + i + 1])
+                 << (HOST_BITS_PER_LONG - n)));
+       }
     }
-  if (eisnan (d2))
+  else
     {
-      PUT_REAL (d2, value);
-      return;
+      for (i = 0; ofs + i < SIGSZ; ++i)
+       r->sig[i] = a->sig[ofs + i];
+      for (; i < SIGSZ; ++i)
+       r->sig[i] = 0;
     }
-#endif
-  code = (enum tree_code) icode;
-  switch (code)
+}
+
+/* Left-shift the significand of A by N bits; put the result in the
+   significand of R.  */
+
+static void
+lshift_significand (r, a, n)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
+     unsigned int n;
+{
+  unsigned int i, ofs = n / HOST_BITS_PER_LONG;
+
+  n &= HOST_BITS_PER_LONG - 1;
+  if (n == 0)
     {
-    case PLUS_EXPR:
-      eadd (d2, d1, v);
-      break;
+      for (i = 0; ofs + i < SIGSZ; ++i)
+       r->sig[SIGSZ-1-i] = a->sig[SIGSZ-1-i-ofs];
+      for (; i < SIGSZ; ++i)
+       r->sig[SIGSZ-1-i] = 0;
+    }
+  else
+    for (i = 0; i < SIGSZ; ++i)
+      {
+       r->sig[SIGSZ-1-i]
+         = (((ofs + i >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs]) << n)
+            | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs-1])
+               >> (HOST_BITS_PER_LONG - n)));
+      }
+}
 
-    case MINUS_EXPR:
-      esub (d2, d1, v);                /* d1 - d2 */
-      break;
+/* Likewise, but N is specialized to 1.  */
 
-    case MULT_EXPR:
-      emul (d2, d1, v);
-      break;
+static inline void
+lshift_significand_1 (r, a)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
+{
+  unsigned int i;
 
-    case RDIV_EXPR:
-#ifndef REAL_INFINITY
-      if (ecmp (d2, ezero) == 0)
+  for (i = SIGSZ - 1; i > 0; --i)
+    r->sig[i] = (a->sig[i] << 1) | (a->sig[i-1] >> (HOST_BITS_PER_LONG - 1));
+  r->sig[0] = a->sig[0] << 1;
+}
+
+/* Add the significands of A and B, placing the result in R.  Return
+   true if there was carry out of the most significant word.  */
+
+static inline bool
+add_significands (r, a, b)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
+{
+  bool carry = false;
+  int i;
+
+  for (i = 0; i < SIGSZ; ++i)
+    {
+      unsigned long ai = a->sig[i];
+      unsigned long ri = ai + b->sig[i];
+
+      if (carry)
        {
-#ifdef NANS
-       enan (v, eisneg (d1) ^ eisneg (d2));
-       break;
-#else
-       abort ();
-#endif
+         carry = ri < ai;
+         carry |= ++ri == 0;
        }
-#endif
-      ediv (d2, d1, v);        /* d1/d2 */
-      break;
-
-    case MIN_EXPR:             /* min (d1,d2) */
-      if (ecmp (d1, d2) < 0)
-       emov (d1, v);
       else
-       emov (d2, v);
-      break;
+       carry = ri < ai;
 
-    case MAX_EXPR:             /* max (d1,d2) */
-      if (ecmp (d1, d2) > 0)
-       emov (d1, v);
-      else
-       emov (d2, v);
-      break;
-    default:
-      emov (ezero, v);
-      break;
+      r->sig[i] = ri;
     }
-PUT_REAL (v, value);
-}
 
+  return carry;
+}
 
-/* Truncate REAL_VALUE_TYPE toward zero to signed HOST_WIDE_INT.
-   implements REAL_VALUE_RNDZINT (x) (etrunci (x)).  */
+/* 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.  */
 
-REAL_VALUE_TYPE
-etrunci (x)
-     REAL_VALUE_TYPE x;
+static inline bool
+sub_significands (r, a, b, carry)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
+     int carry;
 {
-  unsigned EMUSHORT f[NE], g[NE];
-  REAL_VALUE_TYPE r;
-  HOST_WIDE_INT l;
+  int i;
 
-  GET_REAL (&x, g);
-#ifdef NANS
-  if (eisnan (g))
-    return (x);
-#endif
-  eifrac (g, &l, f);
-  ltoe (&l, g);
-  PUT_REAL (g, &r);
-  return (r);
-}
+  for (i = 0; i < SIGSZ; ++i)
+    {
+      unsigned long ai = a->sig[i];
+      unsigned long ri = ai - b->sig[i];
+
+      if (carry)
+       {
+         carry = ri > ai;
+         carry |= ~--ri == 0;
+       }
+      else
+       carry = ri > ai;
 
+      r->sig[i] = ri;
+    }
 
-/* Truncate REAL_VALUE_TYPE toward zero to unsigned HOST_WIDE_INT;
-   implements REAL_VALUE_UNSIGNED_RNDZINT (x) (etruncui (x)).  */
+  return carry;
+}  
 
-REAL_VALUE_TYPE
-etruncui (x)
-     REAL_VALUE_TYPE x;
+/* Negate the significand A, placing the result in R.  */
+
+static inline void
+neg_significand (r, a)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
 {
-  unsigned EMUSHORT f[NE], g[NE];
-  REAL_VALUE_TYPE r;
-  unsigned HOST_WIDE_INT l;
+  bool carry = true;
+  int i;
 
-  GET_REAL (&x, g);
-#ifdef NANS
-  if (eisnan (g))
-    return (x);
-#endif
-  euifrac (g, &l, f);
-  ultoe (&l, g);
-  PUT_REAL (g, &r);
-  return (r);
-}
+  for (i = 0; i < SIGSZ; ++i)
+    {
+      unsigned long ri, ai = a->sig[i];
+
+      if (carry)
+       {
+         if (ai)
+           {
+             ri = -ai;
+             carry = false;
+           }
+         else
+           ri = ai;
+       }
+      else
+       ri = ~ai;
 
+      r->sig[i] = ri;
+    }
+}  
 
-/* This is the REAL_VALUE_ATOF function.  It converts a decimal or hexadecimal
-   string to binary, rounding off as indicated by the machine_mode argument.
-   Then it promotes the rounded value to REAL_VALUE_TYPE.  */
+/* Compare significands.  Return tri-state vs zero.  */
 
-REAL_VALUE_TYPE
-ereal_atof (s, t)
-     const char *s;
-     enum machine_mode t;
+static inline int 
+cmp_significands (a, b)
+     const REAL_VALUE_TYPE *a, *b;
 {
-  unsigned EMUSHORT tem[NE], e[NE];
-  REAL_VALUE_TYPE r;
+  int i;
 
-  switch (t)
+  for (i = SIGSZ - 1; i >= 0; --i)
     {
-#ifdef C4X
-    case QFmode:
-    case HFmode:
-      asctoe53 (s, tem);
-      e53toe (tem, e);
-      break;
-#else
-    case HFmode:
-#endif
+      unsigned long ai = a->sig[i];
+      unsigned long bi = b->sig[i];
 
-    case SFmode:
-      asctoe24 (s, tem);
-      e24toe (tem, e);
-      break;
+      if (ai > bi)
+       return 1;
+      if (ai < bi)
+       return -1;
+    }
 
-    case DFmode:
-      asctoe53 (s, tem);
-      e53toe (tem, e);
-      break;
+  return 0;
+}
 
-    case XFmode:
-      asctoe64 (s, tem);
-      e64toe (tem, e);
-      break;
+/* Return true if A is nonzero.  */
 
-    case TFmode:
-      asctoe113 (s, tem);
-      e113toe (tem, e);
-      break;
+static inline int 
+cmp_significand_0 (a)
+     const REAL_VALUE_TYPE *a;
+{
+  int i;
 
-    default:
-      asctoe (s, e);
-    }
-  PUT_REAL (e, &r);
-  return (r);
-}
+  for (i = SIGSZ - 1; i >= 0; --i)
+    if (a->sig[i])
+      return 1;
 
+  return 0;
+}
 
-/* Expansion of REAL_NEGATE.  */
+/* Set bit N of the significand of R.  */
 
-REAL_VALUE_TYPE
-ereal_negate (x)
-     REAL_VALUE_TYPE x;
+static inline void
+set_significand_bit (r, n)
+     REAL_VALUE_TYPE *r;
+     unsigned int n;
 {
-  unsigned EMUSHORT e[NE];
-  REAL_VALUE_TYPE r;
+  r->sig[n / HOST_BITS_PER_LONG]
+    |= (unsigned long)1 << (n % HOST_BITS_PER_LONG);
+}
+
+/* Clear bit N of the significand of R.  */
 
-  GET_REAL (&x, e);
-  eneg (e);
-  PUT_REAL (e, &r);
-  return (r);
+static inline void
+clear_significand_bit (r, n)
+     REAL_VALUE_TYPE *r;
+     unsigned int n;
+{
+  r->sig[n / HOST_BITS_PER_LONG]
+    &= ~((unsigned long)1 << (n % HOST_BITS_PER_LONG));
 }
 
+/* Test bit N of the significand of R.  */
+
+static inline bool
+test_significand_bit (r, n)
+     REAL_VALUE_TYPE *r;
+     unsigned int n;
+{
+  /* ??? Compiler bug here if we return this expression directly.
+     The conversion to bool strips the "&1" and we wind up testing
+     e.g. 2 != 0 -> true.  Seen in gcc version 3.2 20020520.  */
+  int t = (r->sig[n / HOST_BITS_PER_LONG] >> (n % HOST_BITS_PER_LONG)) & 1;
+  return t;
+}
 
-/* Round real toward zero to HOST_WIDE_INT;
-   implements REAL_VALUE_FIX (x).  */
+/* Clear bits 0..N-1 of the significand of R.  */
 
-HOST_WIDE_INT
-efixi (x)
-     REAL_VALUE_TYPE x;
+static void
+clear_significand_below (r, n)
+     REAL_VALUE_TYPE *r;
+     unsigned int n;
 {
-  unsigned EMUSHORT f[NE], g[NE];
-  HOST_WIDE_INT l;
+  int i, w = n / HOST_BITS_PER_LONG;
 
-  GET_REAL (&x, f);
-#ifdef NANS
-  if (eisnan (f))
-    {
-      warning ("conversion from NaN to int");
-      return (-1);
-    }
-#endif
-  eifrac (f, &l, g);
-  return l;
+  for (i = 0; i < w; ++i)
+    r->sig[i] = 0;
+
+  r->sig[w] &= ~(((unsigned long)1 << (n % HOST_BITS_PER_LONG)) - 1);
 }
 
-/* Round real toward zero to unsigned HOST_WIDE_INT
-   implements  REAL_VALUE_UNSIGNED_FIX (x).
-   Negative input returns zero.  */
+/* Divide the significands of A and B, placing the result in R.  Return
+   true if the division was inexact.  */
 
-unsigned HOST_WIDE_INT
-efixui (x)
-     REAL_VALUE_TYPE x;
+static inline bool
+div_significands (r, a, b)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
 {
-  unsigned EMUSHORT f[NE], g[NE];
-  unsigned HOST_WIDE_INT l;
+  REAL_VALUE_TYPE u;
+  int i, bit = SIGNIFICAND_BITS - 1;
+  unsigned long msb, inexact;
 
-  GET_REAL (&x, f);
-#ifdef NANS
-  if (eisnan (f))
+  u = *a;
+  memset (r->sig, 0, sizeof (r->sig));
+
+  msb = 0;
+  goto start;
+  do
     {
-      warning ("conversion from NaN to unsigned int");
-      return (-1);
+      msb = u.sig[SIGSZ-1] & SIG_MSB;
+      lshift_significand_1 (&u, &u);
+    start:
+      if (msb || cmp_significands (&u, b) >= 0)
+       {
+         sub_significands (&u, &u, b, 0);
+         set_significand_bit (r, bit);
+       }
     }
-#endif
-  euifrac (f, &l, g);
-  return l;
-}
+  while (--bit >= 0);
 
+  for (i = 0, inexact = 0; i < SIGSZ; i++)
+    inexact |= u.sig[i];
 
-/* REAL_VALUE_FROM_INT macro.  */
+  return inexact != 0;
+}
 
-void
-ereal_from_int (d, i, j, mode)
-     REAL_VALUE_TYPE *d;
-     HOST_WIDE_INT i, j;
-     enum machine_mode mode;
+/* Adjust the exponent and significand of R such that the most
+   significant bit is set.  We underflow to zero and overflow to
+   infinity here, without denormals.  (The intermediate representation
+   exponent is large enough to handle target denormals normalized.)  */
+
+static void
+normalize (r)
+     REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT df[NE], dg[NE];
-  HOST_WIDE_INT low, high;
-  int sign;
+  int shift = 0, exp;
+  int i, j;
 
-  if (GET_MODE_CLASS (mode) != MODE_FLOAT)
-    abort ();
-  sign = 0;
-  low = i;
-  if ((high = j) < 0)
+  /* Find the first word that is nonzero.  */
+  for (i = SIGSZ - 1; i >= 0; i--)
+    if (r->sig[i] == 0)
+      shift += HOST_BITS_PER_LONG;
+    else
+      break;
+
+  /* Zero significand flushes to zero.  */
+  if (i < 0)
     {
-      sign = 1;
-      /* complement and add 1 */
-      high = ~high;
-      if (low)
-       low = -low;
-      else
-       high += 1;
+      r->class = rvc_zero;
+      r->exp = 0;
+      return;
     }
-  eldexp (eone, HOST_BITS_PER_WIDE_INT, df);
-  ultoe ((unsigned HOST_WIDE_INT *) &high, dg);
-  emul (dg, df, dg);
-  ultoe ((unsigned HOST_WIDE_INT *) &low, df);
-  eadd (df, dg, dg);
-  if (sign)
-    eneg (dg);
 
-  /* A REAL_VALUE_TYPE may not be wide enough to hold the two HOST_WIDE_INTS.
-     Avoid double-rounding errors later by rounding off now from the
-     extra-wide internal format to the requested precision.  */
-  switch (GET_MODE_BITSIZE (mode))
-    {
-    case 32:
-      etoe24 (dg, df);
-      e24toe (df, dg);
+  /* Find the first bit that is nonzero.  */
+  for (j = 0; ; j++)
+    if (r->sig[i] & ((unsigned long)1 << (HOST_BITS_PER_LONG - 1 - j)))
       break;
+  shift += j;
 
-    case 64:
-      etoe53 (dg, df);
-      e53toe (df, dg);
-      break;
+  if (shift > 0)
+    {
+      exp = r->exp - shift;
+      if (exp > MAX_EXP)
+       get_inf (r, r->sign);
+      else if (exp < -MAX_EXP)
+       get_zero (r, r->sign);
+      else
+       {
+         r->exp = exp;
+         lshift_significand (r, r, shift);
+       }
+    }
+}
+\f
+/* Calculate R = A + (SUBTRACT_P ? -B : B).  Return true if the
+   result may be inexact due to a loss of precision.  */
 
-    case 96:
-      etoe64 (dg, df);
-      e64toe (df, dg);
-      break;
+static bool
+do_add (r, a, b, subtract_p)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
+     int subtract_p;
+{
+  int dexp, sign, exp;
+  REAL_VALUE_TYPE t;
+  bool inexact = false;
+
+  /* Determine if we need to add or subtract.  */
+  sign = a->sign;
+  subtract_p = (sign ^ b->sign) ^ subtract_p;
+
+  switch (CLASS2 (a->class, b->class))
+    {
+    case CLASS2 (rvc_zero, rvc_zero):
+      /* -0 + -0 = -0, -0 - +0 = -0; all other cases yield +0.  */
+      get_zero (r, sign & !subtract_p);
+      return false;
+
+    case CLASS2 (rvc_zero, rvc_normal):
+    case CLASS2 (rvc_zero, rvc_inf):
+    case CLASS2 (rvc_zero, rvc_nan):
+      /* 0 + ANY = ANY.  */
+    case CLASS2 (rvc_normal, rvc_nan):
+    case CLASS2 (rvc_inf, rvc_nan):
+    case CLASS2 (rvc_nan, rvc_nan):
+      /* ANY + NaN = NaN.  */
+    case CLASS2 (rvc_normal, rvc_inf):
+      /* R + Inf = Inf.  */
+      *r = *b;
+      r->sign = sign ^ subtract_p;
+      return false;
+
+    case CLASS2 (rvc_normal, rvc_zero):
+    case CLASS2 (rvc_inf, rvc_zero):
+    case CLASS2 (rvc_nan, rvc_zero):
+      /* ANY + 0 = ANY.  */
+    case CLASS2 (rvc_nan, rvc_normal):
+    case CLASS2 (rvc_nan, rvc_inf):
+      /* NaN + ANY = NaN.  */
+    case CLASS2 (rvc_inf, rvc_normal):
+      /* Inf + R = Inf.  */
+      *r = *a;
+      return false;
+
+    case CLASS2 (rvc_inf, rvc_inf):
+      if (subtract_p)
+       /* Inf - Inf = NaN.  */
+       get_canonical_qnan (r, 0);
+      else
+       /* Inf + Inf = Inf.  */
+       *r = *a;
+      return false;
 
-    case 128:
-      etoe113 (dg, df);
-      e113toe (df, dg);
+    case CLASS2 (rvc_normal, rvc_normal):
       break;
 
     default:
       abort ();
-  }
-
-  PUT_REAL (dg, d);
-}
+    }
 
+  /* Swap the arguments such that A has the larger exponent.  */
+  dexp = a->exp - b->exp;
+  if (dexp < 0)
+    {
+      const REAL_VALUE_TYPE *t;
+      t = a, a = b, b = t;
+      dexp = -dexp;
+      sign ^= subtract_p;
+    }
+  exp = a->exp;
 
-/* REAL_VALUE_FROM_UNSIGNED_INT macro.   */
+  /* If the exponents are not identical, we need to shift the
+     significand of B down.  */
+  if (dexp > 0)
+    {
+      /* If the exponents are too far apart, the significands
+        do not overlap, which makes the subtraction a noop.  */
+      if (dexp >= SIGNIFICAND_BITS)
+       {
+         *r = *a;
+         r->sign = sign;
+         return true;
+       }
 
-void
-ereal_from_uint (d, i, j, mode)
-     REAL_VALUE_TYPE *d;
-     unsigned HOST_WIDE_INT i, j;
-     enum machine_mode mode;
-{
-  unsigned EMUSHORT df[NE], dg[NE];
-  unsigned HOST_WIDE_INT low, high;
+      inexact |= sticky_rshift_significand (&t, b, dexp);
+      b = &t;
+    }
 
-  if (GET_MODE_CLASS (mode) != MODE_FLOAT)
-    abort ();
-  low = i;
-  high = j;
-  eldexp (eone, HOST_BITS_PER_WIDE_INT, df);
-  ultoe (&high, dg);
-  emul (dg, df, dg);
-  ultoe (&low, df);
-  eadd (df, dg, dg);
-
-  /* A REAL_VALUE_TYPE may not be wide enough to hold the two HOST_WIDE_INTS.
-     Avoid double-rounding errors later by rounding off now from the
-     extra-wide internal format to the requested precision.  */
-  switch (GET_MODE_BITSIZE (mode))
+  if (subtract_p)
     {
-    case 32:
-      etoe24 (dg, df);
-      e24toe (df, dg);
-      break;
+      if (sub_significands (r, a, b, inexact))
+       {
+         /* We got a borrow out of the subtraction.  That means that
+            A and B had the same exponent, and B had the larger
+            significand.  We need to swap the sign and negate the
+            significand.  */
+         sign ^= 1;
+         neg_significand (r, r);
+       }
+    }
+  else
+    {
+      if (add_significands (r, a, b))
+       {
+         /* We got carry out of the addition.  This means we need to
+            shift the significand back down one bit and increase the
+            exponent.  */
+         inexact |= sticky_rshift_significand (r, r, 1);
+         r->sig[SIGSZ-1] |= SIG_MSB;
+         if (++exp > MAX_EXP)
+           {
+             get_inf (r, sign);
+             return true;
+           }
+       }
+    }
 
-    case 64:
-      etoe53 (dg, df);
-      e53toe (df, dg);
-      break;
+  r->class = rvc_normal;
+  r->sign = sign;
+  r->exp = exp;
 
-    case 96:
-      etoe64 (dg, df);
-      e64toe (df, dg);
-      break;
+  /* Re-normalize the result.  */
+  normalize (r);
+
+  /* Special case: if the subtraction results in zero, the result
+     is positive.  */
+  if (r->class == rvc_zero)
+    r->sign = 0;
+  else
+    r->sig[0] |= inexact;
+
+  return inexact;
+}
+
+/* Calculate R = A * B.  Return true if the result may be inexact.  */
 
-    case 128:
-      etoe113 (dg, df);
-      e113toe (df, dg);
+static bool
+do_multiply (r, a, b)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
+{
+  REAL_VALUE_TYPE u, t, *rr;
+  unsigned int i, j, k;
+  int sign = a->sign ^ b->sign;
+  bool inexact = false;
+
+  switch (CLASS2 (a->class, b->class))
+    {
+    case CLASS2 (rvc_zero, rvc_zero):
+    case CLASS2 (rvc_zero, rvc_normal):
+    case CLASS2 (rvc_normal, rvc_zero):
+      /* +-0 * ANY = 0 with appropriate sign.  */
+      get_zero (r, sign);
+      return false;
+
+    case CLASS2 (rvc_zero, rvc_nan):
+    case CLASS2 (rvc_normal, rvc_nan):
+    case CLASS2 (rvc_inf, rvc_nan):
+    case CLASS2 (rvc_nan, rvc_nan):
+      /* ANY * NaN = NaN.  */
+      *r = *b;
+      r->sign = sign;
+      return false;
+
+    case CLASS2 (rvc_nan, rvc_zero):
+    case CLASS2 (rvc_nan, rvc_normal):
+    case CLASS2 (rvc_nan, rvc_inf):
+      /* NaN * ANY = NaN.  */
+      *r = *a;
+      r->sign = sign;
+      return false;
+
+    case CLASS2 (rvc_zero, rvc_inf):
+    case CLASS2 (rvc_inf, rvc_zero):
+      /* 0 * Inf = NaN */
+      get_canonical_qnan (r, sign);
+      return false;
+
+    case CLASS2 (rvc_inf, rvc_inf):
+    case CLASS2 (rvc_normal, rvc_inf):
+    case CLASS2 (rvc_inf, rvc_normal):
+      /* Inf * Inf = Inf, R * Inf = Inf */
+      get_inf (r, sign);
+      return false;
+
+    case CLASS2 (rvc_normal, rvc_normal):
       break;
 
     default:
       abort ();
-  }
+    }
 
-  PUT_REAL (dg, d);
-}
+  if (r == a || r == b)
+    rr = &t;
+  else
+    rr = r;
+  get_zero (rr, 0);
 
+  /* Collect all the partial products.  Since we don't have sure access
+     to a widening multiply, we split each long into two half-words.
 
-/* REAL_VALUE_TO_INT macro.  */
+     Consider the long-hand form of a four half-word multiplication:
 
-void
-ereal_to_int (low, high, rr)
-     HOST_WIDE_INT *low, *high;
-     REAL_VALUE_TYPE rr;
-{
-  unsigned EMUSHORT d[NE], df[NE], dg[NE], dh[NE];
-  int s;
+                A  B  C  D
+             *  E  F  G  H
+            --------------
+               DE DF DG DH
+            CE CF CG CH
+         BE BF BG BH
+       AE AF AG AH
 
-  GET_REAL (&rr, d);
-#ifdef NANS
-  if (eisnan (d))
-    {
-      warning ("conversion from NaN to int");
-      *low = -1;
-      *high = -1;
-      return;
-    }
-#endif
-  /* convert positive value */
-  s = 0;
-  if (eisneg (d))
-    {
-      eneg (d);
-      s = 1;
-    }
-  eldexp (eone, HOST_BITS_PER_WIDE_INT, df);
-  ediv (df, d, dg);            /* dg = d / 2^32 is the high word */
-  euifrac (dg, (unsigned HOST_WIDE_INT *) high, dh);
-  emul (df, dh, dg);           /* fractional part is the low word */
-  euifrac (dg, (unsigned HOST_WIDE_INT *)low, dh);
-  if (s)
+     We construct partial products of the widened half-word products
+     that are known to not overlap, e.g. DF+DH.  Each such partial
+     product is given its proper exponent, which allows us to sum them
+     and obtain the finished product.  */
+
+  for (i = 0; i < SIGSZ * 2; ++i)
     {
-      /* complement and add 1 */
-      *high = ~(*high);
-      if (*low)
-       *low = -(*low);
+      unsigned long ai = a->sig[i / 2];
+      if (i & 1)
+       ai >>= HOST_BITS_PER_LONG / 2;
       else
-       *high += 1;
-    }
-}
+       ai &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1;
 
+      if (ai == 0)
+       continue;
 
-/* REAL_VALUE_LDEXP macro.  */
+      for (j = 0; j < 2; ++j)
+       {
+         int exp = (a->exp - (2*SIGSZ-1-i)*(HOST_BITS_PER_LONG/2)
+                    + (b->exp - (1-j)*(HOST_BITS_PER_LONG/2)));
 
-REAL_VALUE_TYPE
-ereal_ldexp (x, n)
-     REAL_VALUE_TYPE x;
-     int n;
-{
-  unsigned EMUSHORT e[NE], y[NE];
-  REAL_VALUE_TYPE r;
+         if (exp > MAX_EXP)
+           {
+             get_inf (r, sign);
+             return true;
+           }
+         if (exp < -MAX_EXP)
+           {
+             /* Would underflow to zero, which we shouldn't bother adding.  */
+             inexact = true;
+             continue;
+           }
 
-  GET_REAL (&x, e);
-#ifdef NANS
-  if (eisnan (e))
-    return (x);
-#endif
-  eldexp (e, n, y);
-  PUT_REAL (y, &r);
-  return (r);
-}
+         u.class = rvc_normal;
+         u.sign = 0;
+         u.exp = exp;
 
-/* These routines are conditionally compiled because functions
-   of the same names may be defined in fold-const.c.  */
+         for (k = j; k < SIGSZ * 2; k += 2)
+           {
+             unsigned long bi = b->sig[k / 2];
+             if (k & 1)
+               bi >>= HOST_BITS_PER_LONG / 2;
+             else
+               bi &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1;
 
-#ifdef REAL_ARITHMETIC
+             u.sig[k / 2] = ai * bi;
+           }
 
-/* Check for infinity in a REAL_VALUE_TYPE.  */
+         normalize (&u);
+         inexact |= do_add (rr, rr, &u, 0);
+       }
+    }
 
-int
-target_isinf (x)
-     REAL_VALUE_TYPE x ATTRIBUTE_UNUSED;
-{
-#ifdef INFINITY
-  unsigned EMUSHORT e[NE];
+  rr->sign = sign;
+  if (rr != r)
+    *r = t;
 
-  GET_REAL (&x, e);
-  return (eisinf (e));
-#else
-  return 0;
-#endif
+  return inexact;
 }
 
-/* Check whether a REAL_VALUE_TYPE item is a NaN.  */
+/* Calculate R = A / B.  Return true if the result may be inexact.  */
 
-int
-target_isnan (x)
-     REAL_VALUE_TYPE x ATTRIBUTE_UNUSED;
-{
-#ifdef NANS
-  unsigned EMUSHORT e[NE];
+static bool
+do_divide (r, a, b)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a, *b;
+{
+  int exp, sign = a->sign ^ b->sign;
+  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_inf):
+      /* Inf / Inf = NaN.  */
+      get_canonical_qnan (r, sign);
+      return false;
+
+    case CLASS2 (rvc_zero, rvc_normal):
+    case CLASS2 (rvc_zero, rvc_inf):
+      /* 0 / ANY = 0.  */
+    case CLASS2 (rvc_normal, rvc_inf):
+      /* R / Inf = 0.  */
+      get_zero (r, sign);
+      return false;
+
+    case CLASS2 (rvc_normal, rvc_zero):
+      /* R / 0 = Inf.  */
+    case CLASS2 (rvc_inf, rvc_zero):
+      /* Inf / 0 = Inf.  */
+      get_inf (r, sign);
+      return false;
+
+    case CLASS2 (rvc_zero, rvc_nan):
+    case CLASS2 (rvc_normal, rvc_nan):
+    case CLASS2 (rvc_inf, rvc_nan):
+    case CLASS2 (rvc_nan, rvc_nan):
+      /* ANY / NaN = NaN.  */
+      *r = *b;
+      r->sign = sign;
+      return false;
+
+    case CLASS2 (rvc_nan, rvc_zero):
+    case CLASS2 (rvc_nan, rvc_normal):
+    case CLASS2 (rvc_nan, rvc_inf):
+      /* NaN / ANY = NaN.  */
+      *r = *a;
+      r->sign = sign;
+      return false;
+
+    case CLASS2 (rvc_inf, rvc_normal):
+      /* Inf / R = Inf.  */
+      get_inf (r, sign);
+      return false;
+
+    case CLASS2 (rvc_normal, rvc_normal):
+      break;
 
-  GET_REAL (&x, e);
-  return (eisnan (e));
-#else
-  return (0);
-#endif
-}
+    default:
+      abort ();
+    }
 
+  if (r == a || r == b)
+    rr = &t;
+  else
+    rr = r;
 
-/* Check for a negative REAL_VALUE_TYPE number.
-   This just checks the sign bit, so that -0 counts as negative.  */
+  rr->class = rvc_normal;
+  rr->sign = sign;
 
-int
-target_negative (x)
-     REAL_VALUE_TYPE x;
-{
-  return ereal_isneg (x);
+  exp = a->exp - b->exp + 1;
+  if (exp > MAX_EXP)
+    {
+      get_inf (r, sign);
+      return true;
+    }
+  if (exp < -MAX_EXP)
+    {
+      get_zero (r, sign);
+      return true;
+    }
+  rr->exp = exp;
+
+  inexact = div_significands (rr, a, b);
+
+  /* Re-normalize the result.  */
+  normalize (rr);
+  rr->sig[0] |= inexact;
+
+  if (rr != r)
+    *r = t;
+
+  return inexact;
 }
 
-/* Expansion of REAL_VALUE_TRUNCATE.
-   The result is in floating point, rounded to nearest or even.  */
+/* Return a tri-state comparison of A vs B.  Return NAN_RESULT if
+   one of the two operands is a NaN.  */
 
-REAL_VALUE_TYPE
-real_value_truncate (mode, arg)
-     enum machine_mode mode;
-     REAL_VALUE_TYPE arg;
+static int
+do_compare (a, b, nan_result)
+     const REAL_VALUE_TYPE *a, *b;
+     int nan_result;
 {
-  unsigned EMUSHORT e[NE], t[NE];
-  REAL_VALUE_TYPE r;
+  int ret;
 
-  GET_REAL (&arg, e);
-#ifdef NANS
-  if (eisnan (e))
-    return (arg);
-#endif
-  eclear (t);
-  switch (mode)
+  switch (CLASS2 (a->class, b->class))
     {
-    case TFmode:
-      etoe113 (e, t);
-      e113toe (t, t);
-      break;
-
-    case XFmode:
-      etoe64 (e, t);
-      e64toe (t, t);
-      break;
+    case CLASS2 (rvc_zero, rvc_zero):
+      /* Sign of zero doesn't matter for compares.  */
+      return 0;
 
-    case DFmode:
-      etoe53 (e, t);
-      e53toe (t, t);
-      break;
+    case CLASS2 (rvc_inf, rvc_zero):
+    case CLASS2 (rvc_inf, rvc_normal):
+    case CLASS2 (rvc_normal, rvc_zero):
+      return (a->sign ? -1 : 1);
 
-    case SFmode:
-#ifndef C4X
-    case HFmode:
-#endif
-      etoe24 (e, t);
-      e24toe (t, t);
-      break;
+    case CLASS2 (rvc_inf, rvc_inf):
+      return -a->sign - -b->sign;
 
-#ifdef C4X
-    case HFmode:
-    case QFmode:
-      etoe53 (e, t);
-      e53toe (t, t);
-      break;
-#endif
+    case CLASS2 (rvc_zero, rvc_normal):
+    case CLASS2 (rvc_zero, rvc_inf):
+    case CLASS2 (rvc_normal, rvc_inf):
+      return (b->sign ? 1 : -1);
 
-    case SImode:
-      r = etrunci (arg);
-      return (r);
+    case CLASS2 (rvc_zero, rvc_nan):
+    case CLASS2 (rvc_normal, rvc_nan):
+    case CLASS2 (rvc_inf, rvc_nan):
+    case CLASS2 (rvc_nan, rvc_nan):
+    case CLASS2 (rvc_nan, rvc_zero):
+    case CLASS2 (rvc_nan, rvc_normal):
+    case CLASS2 (rvc_nan, rvc_inf):
+      return nan_result;
 
-    /* If an unsupported type was requested, presume that
-       the machine files know something useful to do with
-       the unmodified value.  */
+    case CLASS2 (rvc_normal, rvc_normal):
+      break;
 
     default:
-      return (arg);
+      abort ();
     }
-  PUT_REAL (t, &r);
-  return (r);
-}
 
-/* Try to change R into its exact multiplicative inverse in machine mode
-   MODE.  Return nonzero function value if successful.  */
+  if (a->sign != b->sign)
+    return -a->sign - -b->sign;
 
-int
-exact_real_inverse (mode, r)
-     enum machine_mode mode;
-     REAL_VALUE_TYPE *r;
-{
-  unsigned EMUSHORT e[NE], einv[NE];
-  REAL_VALUE_TYPE rinv;
-  int i;
+  if (a->exp > b->exp)
+    ret = 1;
+  else if (a->exp < b->exp)
+    ret = -1;
+  else
+    ret = cmp_significands (a, b);
 
-  GET_REAL (r, e);
+  return (a->sign ? -ret : ret);
+}
 
-  /* Test for input in range.  Don't transform IEEE special values.  */
-  if (eisinf (e) || eisnan (e) || (ecmp (e, ezero) == 0))
-    return 0;
+/* Return A truncated to an integral value toward zero.  */
 
-  /* Test for a power of 2: all significand bits zero except the MSB.
-     We are assuming the target has binary (or hex) arithmetic.  */
-  if (e[NE - 2] != 0x8000)
-    return 0;
+static void
+do_fix_trunc (r, a)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *a;
+{
+  *r = *a;
 
-  for (i = 0; i < NE - 2; i++)
+  switch (r->class)
     {
-      if (e[i] != 0)
-       return 0;
-    }
-
-  /* Compute the inverse and truncate it to the required mode.  */
-  ediv (e, eone, einv);
-  PUT_REAL (einv, &rinv);
-  rinv = real_value_truncate (mode, rinv);
-
-#ifdef CHECK_FLOAT_VALUE
-  /* This check is not redundant.  It may, for example, flush
-     a supposedly IEEE denormal value to zero.  */
-  i = 0;
-  if (CHECK_FLOAT_VALUE (mode, rinv, i))
-    return 0;
-#endif
-  GET_REAL (&rinv, einv);
+    case rvc_zero:
+    case rvc_inf:
+    case rvc_nan:
+      break;
 
-  /* Check the bits again, because the truncation might have
-     generated an arbitrary saturation value on overflow.  */
-  if (einv[NE - 2] != 0x8000)
-    return 0;
+    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;
 
-  for (i = 0; i < NE - 2; i++)
-    {
-      if (einv[i] != 0)
-       return 0;
+    default:
+      abort ();
     }
-
-  /* Fail if the computed inverse is out of range.  */
-  if (eisinf (einv) || eisnan (einv) || (ecmp (einv, ezero) == 0))
-    return 0;
-
-  /* Output the reciprocal and return success flag.  */
-  PUT_REAL (einv, r);
-  return 1;
 }
-#endif /* REAL_ARITHMETIC defined */
 
-/* Used for debugging--print the value of R in human-readable format
-   on stderr.  */
+/* Perform the binary or unary operation described by CODE.
+   For a unary operation, leave OP1 NULL.  */
 
 void
-debug_real (r)
-     REAL_VALUE_TYPE r;
+real_arithmetic (r, icode, op0, op1)
+     REAL_VALUE_TYPE *r;
+     int icode;
+     const REAL_VALUE_TYPE *op0, *op1;
 {
-  char dstr[30];
-
-  REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
-  fprintf (stderr, "%s", dstr);
-}
+  enum tree_code code = icode;
 
-\f
-/* The following routines convert REAL_VALUE_TYPE to the various floating
-   point formats that are meaningful to supported computers.
+  switch (code)
+    {
+    case PLUS_EXPR:
+      do_add (r, op0, op1, 0);
+      break;
 
-   The results are returned in 32-bit pieces, each piece stored in a `long'.
-   This is so they can be printed by statements like
+    case MINUS_EXPR:
+      do_add (r, op0, op1, 1);
+      break;
 
-      fprintf (file, "%lx, %lx", L[0],  L[1]);
+    case MULT_EXPR:
+      do_multiply (r, op0, op1);
+      break;
 
-   that will work on both narrow- and wide-word host computers.  */
+    case RDIV_EXPR:
+      do_divide (r, op0, op1);
+      break;
 
-/* Convert R to a 128-bit long double precision value.  The output array L
-   contains four 32-bit pieces of the result, in the order they would appear
-   in memory.  */
+    case MIN_EXPR:
+      if (op1->class == rvc_nan)
+       *r = *op1;
+      else if (do_compare (op0, op1, -1) < 0)
+       *r = *op0;
+      else
+       *r = *op1;
+      break;
 
-void
-etartdouble (r, l)
-     REAL_VALUE_TYPE r;
-     long l[];
-{
-  unsigned EMUSHORT e[NE];
+    case MAX_EXPR:
+      if (op1->class == rvc_nan)
+       *r = *op1;
+      else if (do_compare (op0, op1, 1) < 0)
+       *r = *op1;
+      else
+       *r = *op0;
+      break;
 
-  GET_REAL (&r, e);
-  etoe113 (e, e);
-  endian (e, l, TFmode);
-}
+    case NEGATE_EXPR:
+      *r = *op0;
+      r->sign ^= 1;
+      break;
 
-/* Convert R to a double extended precision value.  The output array L
-   contains three 32-bit pieces of the result, in the order they would
-   appear in memory.  */
+    case ABS_EXPR:
+      *r = *op0;
+      r->sign = 0;
+      break;
 
-void
-etarldouble (r, l)
-     REAL_VALUE_TYPE r;
-     long l[];
-{
-  unsigned EMUSHORT e[NE];
+    case FIX_TRUNC_EXPR:
+      do_fix_trunc (r, op0);
+      break;
 
-  GET_REAL (&r, e);
-  etoe64 (e, e);
-  endian (e, l, XFmode);
+    default:
+      abort ();
+    }
 }
 
-/* Convert R to a double precision value.  The output array L contains two
-   32-bit pieces of the result, in the order they would appear in memory.  */
+/* Legacy.  Similar, but return the result directly.  */
 
-void
-etardouble (r, l)
-     REAL_VALUE_TYPE r;
-     long l[];
+REAL_VALUE_TYPE
+real_arithmetic2 (icode, op0, op1)
+     int icode;
+     const REAL_VALUE_TYPE *op0, *op1;
 {
-  unsigned EMUSHORT e[NE];
-
-  GET_REAL (&r, e);
-  etoe53 (e, e);
-  endian (e, l, DFmode);
+  REAL_VALUE_TYPE r;
+  real_arithmetic (&r, icode, op0, op1);
+  return r;
 }
 
-/* Convert R to a single precision float value stored in the least-significant
-   bits of a `long'.  */
-
-long
-etarsingle (r)
-     REAL_VALUE_TYPE r;
+bool
+real_compare (icode, op0, op1)
+     int icode;
+     const REAL_VALUE_TYPE *op0, *op1;
 {
-  unsigned EMUSHORT e[NE];
-  long l;
-
-  GET_REAL (&r, e);
-  etoe24 (e, e);
-  endian (e, &l, SFmode);
-  return ((long) l);
-}
-
-/* Convert X to a decimal ASCII string S for output to an assembly
-   language file.  Note, there is no standard way to spell infinity or
-   a NaN, so these values may require special treatment in the tm.h
-   macros.  */
+  enum tree_code code = icode;
 
-void
-ereal_to_decimal (x, s)
-     REAL_VALUE_TYPE x;
-     char *s;
-{
-  unsigned EMUSHORT e[NE];
+  switch (code)
+    {
+    case LT_EXPR:
+      return do_compare (op0, op1, 1) < 0;
+    case LE_EXPR:
+      return do_compare (op0, op1, 1) <= 0;
+    case GT_EXPR:
+      return do_compare (op0, op1, -1) > 0;
+    case GE_EXPR:
+      return do_compare (op0, op1, -1) >= 0;
+    case EQ_EXPR:
+      return do_compare (op0, op1, -1) == 0;
+    case NE_EXPR:
+      return do_compare (op0, op1, -1) != 0;
+    case UNORDERED_EXPR:
+      return op0->class == rvc_nan || op1->class == rvc_nan;
+    case ORDERED_EXPR:
+      return op0->class != rvc_nan && op1->class != rvc_nan;
+    case UNLT_EXPR:
+      return do_compare (op0, op1, -1) < 0;
+    case UNLE_EXPR:
+      return do_compare (op0, op1, -1) <= 0;
+    case UNGT_EXPR:
+      return do_compare (op0, op1, 1) > 0;
+    case UNGE_EXPR:
+      return do_compare (op0, op1, 1) >= 0;
+    case UNEQ_EXPR:
+      return do_compare (op0, op1, 0) == 0;
 
-  GET_REAL (&x, e);
-  etoasc (e, s, 20);
+    default:
+      abort ();
+    }
 }
 
-/* Compare X and Y.  Return 1 if X > Y, 0 if X == Y, -1 if X < Y,
-   or -2 if either is a NaN.   */
+/* Return floor log2(R).  */
 
 int
-ereal_cmp (x, y)
-     REAL_VALUE_TYPE x, y;
-{
-  unsigned EMUSHORT ex[NE], ey[NE];
-
-  GET_REAL (&x, ex);
-  GET_REAL (&y, ey);
-  return (ecmp (ex, ey));
+real_exponent (r)
+     const REAL_VALUE_TYPE *r;
+{
+  switch (r->class)
+    {
+    case rvc_zero:
+      return 0;
+    case rvc_inf:
+    case rvc_nan:
+      return (unsigned int)-1 >> 1;
+    case rvc_normal:
+      return r->exp;
+    default:
+      abort ();
+    }
 }
 
-/*  Return 1 if the sign bit of X is set, else return 0.  */
+/* R = OP0 * 2**EXP.  */
 
-int
-ereal_isneg (x)
-     REAL_VALUE_TYPE x;
+void
+real_ldexp (r, op0, exp)
+     REAL_VALUE_TYPE *r;
+     const REAL_VALUE_TYPE *op0;
+     int exp;
 {
-  unsigned EMUSHORT ex[NE];
-
-  GET_REAL (&x, ex);
-  return (eisneg (ex));
-}
-
-/* End of REAL_ARITHMETIC interface */
-\f
-/*
-  Extended precision IEEE binary floating point arithmetic routines
-
-  Numbers are stored in C language as arrays of 16-bit unsigned
-  short integers.  The arguments of the routines are pointers to
-  the arrays.
-
-  External e type data structure, similar to Intel 8087 chip
-  temporary real format but possibly with a larger significand:
-
-       NE-1 significand words  (least significant word first,
-                                most significant bit is normally set)
-       exponent                (value = EXONE for 1.0,
-                               top bit is the sign)
-
-
-  Internal exploded e-type data structure of a number (a "word" is 16 bits):
-
-  ei[0]        sign word       (0 for positive, 0xffff for negative)
-  ei[1]        biased exponent (value = EXONE for the number 1.0)
-  ei[2]        high guard word (always zero after normalization)
-  ei[3]
-  to ei[NI-2]  significand     (NI-4 significand words,
-                                most significant word first,
-                                most significant bit is set)
-  ei[NI-1]     low guard word  (0x8000 bit is rounding place)
-
-
-
-               Routines for external format e-type numbers
+  *r = *op0;
+  switch (r->class)
+    {
+    case rvc_zero:
+    case rvc_inf:
+    case rvc_nan:
+      break;
 
-       asctoe (string, e)      ASCII string to extended double e type
-       asctoe64 (string, &d)   ASCII string to long double
-       asctoe53 (string, &d)   ASCII string to double
-       asctoe24 (string, &f)   ASCII string to single
-       asctoeg (string, e, prec) ASCII string to specified precision
-       e24toe (&f, e)          IEEE single precision to e type
-       e53toe (&d, e)          IEEE double precision to e type
-       e64toe (&d, e)          IEEE long double precision to e type
-       e113toe (&d, e)         128-bit long double precision to e type
-#if 0
-       eabs (e)                        absolute value
-#endif
-       eadd (a, b, c)          c = b + a
-       eclear (e)              e = 0
-       ecmp (a, b)             Returns 1 if a > b, 0 if a == b,
-                               -1 if a < b, -2 if either a or b is a NaN.
-       ediv (a, b, c)          c = b / a
-       efloor (a, b)           truncate to integer, toward -infinity
-       efrexp (a, exp, s)      extract exponent and significand
-       eifrac (e, &l, frac)    e to HOST_WIDE_INT and e type fraction
-       euifrac (e, &l, frac)   e to unsigned HOST_WIDE_INT and e type fraction
-       einfin (e)              set e to infinity, leaving its sign alone
-       eldexp (a, n, b)        multiply by 2**n
-       emov (a, b)             b = a
-       emul (a, b, c)          c = b * a
-       eneg (e)                        e = -e
-#if 0
-       eround (a, b)           b = nearest integer value to a
-#endif
-       esub (a, b, c)          c = b - a
-#if 0
-       e24toasc (&f, str, n)   single to ASCII string, n digits after decimal
-       e53toasc (&d, str, n)   double to ASCII string, n digits after decimal
-       e64toasc (&d, str, n)   80-bit long double to ASCII string
-       e113toasc (&d, str, n)  128-bit long double to ASCII string
-#endif
-       etoasc (e, str, n)      e to ASCII string, n digits after decimal
-       etoe24 (e, &f)          convert e type to IEEE single precision
-       etoe53 (e, &d)          convert e type to IEEE double precision
-       etoe64 (e, &d)          convert e type to IEEE long double precision
-       ltoe (&l, e)            HOST_WIDE_INT to e type
-       ultoe (&l, e)           unsigned HOST_WIDE_INT to e type
-       eisneg (e)              1 if sign bit of e != 0, else 0
-       eisinf (e)              1 if e has maximum exponent (non-IEEE)
-                               or is infinite (IEEE)
-        eisnan (e)              1 if e is a NaN
-
-
-               Routines for internal format exploded e-type numbers
-
-       eaddm (ai, bi)          add significands, bi = bi + ai
-       ecleaz (ei)             ei = 0
-       ecleazs (ei)            set ei = 0 but leave its sign alone
-       ecmpm (ai, bi)          compare significands, return 1, 0, or -1
-       edivm (ai, bi)          divide  significands, bi = bi / ai
-       emdnorm (ai,l,s,exp)    normalize and round off
-       emovi (a, ai)           convert external a to internal ai
-       emovo (ai, a)           convert internal ai to external a
-       emovz (ai, bi)          bi = ai, low guard word of bi = 0
-       emulm (ai, bi)          multiply significands, bi = bi * ai
-       enormlz (ei)            left-justify the significand
-       eshdn1 (ai)             shift significand and guards down 1 bit
-       eshdn8 (ai)             shift down 8 bits
-       eshdn6 (ai)             shift down 16 bits
-       eshift (ai, n)          shift ai n bits up (or down if n < 0)
-       eshup1 (ai)             shift significand and guards up 1 bit
-       eshup8 (ai)             shift up 8 bits
-       eshup6 (ai)             shift up 16 bits
-       esubm (ai, bi)          subtract significands, bi = bi - ai
-        eiisinf (ai)            1 if infinite
-        eiisnan (ai)            1 if a NaN
-       eiisneg (ai)            1 if sign bit of ai != 0, else 0
-        einan (ai)              set ai = NaN
-#if 0
-        eiinfin (ai)            set ai = infinity
-#endif
+    case rvc_normal:
+      exp += op0->exp;
+      if (exp > MAX_EXP)
+       get_inf (r, r->sign);
+      else if (exp < -MAX_EXP)
+       get_zero (r, r->sign);
+      else
+       r->exp = exp;
+      break;
 
-  The result is always normalized and rounded to NI-4 word precision
-  after each arithmetic operation.
-
-  Exception flags are NOT fully supported.
-
-  Signaling NaN's are NOT supported; they are treated the same
-  as quiet NaN's.
-
-  Define INFINITY for support of infinity; otherwise a
-  saturation arithmetic is implemented.
-
-  Define NANS for support of Not-a-Number items; otherwise the
-  arithmetic will never produce a NaN output, and might be confused
-  by a NaN input.
-  If NaN's are supported, the output of `ecmp (a,b)' is -2 if
-  either a or b is a NaN. This means asking `if (ecmp (a,b) < 0)'
-  may not be legitimate. Use `if (ecmp (a,b) == -1)' for `less than'
-  if in doubt.
-
-  Denormals are always supported here where appropriate (e.g., not
-  for conversion to DEC numbers).  */
-
-/* Definitions for error codes that are passed to the common error handling
-   routine mtherr.
-
-   For Digital Equipment PDP-11 and VAX computers, certain
-  IBM systems, and others that use numbers with a 56-bit
-  significand, the symbol DEC should be defined.  In this
-  mode, most floating point constants are given as arrays
-  of octal integers to eliminate decimal to binary conversion
-  errors that might be introduced by the compiler.
-
-  For computers, such as IBM PC, that follow the IEEE
-  Standard for Binary Floating Point Arithmetic (ANSI/IEEE
-  Std 754-1985), the symbol IEEE should be defined.
-  These numbers have 53-bit significands.  In this mode, constants
-  are provided as arrays of hexadecimal 16 bit integers.
-  The endian-ness of generated values is controlled by
-  REAL_WORDS_BIG_ENDIAN.
-
-  To accommodate other types of computer arithmetic, all
-  constants are also provided in a normal decimal radix
-  which one can hope are correctly converted to a suitable
-  format by the available C language compiler.  To invoke
-  this mode, the symbol UNK is defined.
-
-  An important difference among these modes is a predefined
-  set of machine arithmetic constants for each.  The numbers
-  MACHEP (the machine roundoff error), MAXNUM (largest number
-  represented), and several other parameters are preset by
-  the configuration symbol.  Check the file const.c to
-  ensure that these values are correct for your computer.
-
-  For ANSI C compatibility, define ANSIC equal to 1.  Currently
-  this affects only the atan2 function and others that use it.  */
-
-/* Constant definitions for math error conditions.  */
-
-#define DOMAIN         1       /* argument domain error */
-#define SING           2       /* argument singularity */
-#define OVERFLOW       3       /* overflow range error */
-#define UNDERFLOW      4       /* underflow range error */
-#define TLOSS          5       /* total loss of precision */
-#define PLOSS          6       /* partial loss of precision */
-#define INVALID                7       /* NaN-producing operation */
-
-/*  e type constants used by high precision check routines */
-
-#if LONG_DOUBLE_TYPE_SIZE == 128
-/* 0.0 */
-unsigned EMUSHORT ezero[NE] =
- {0x0000, 0x0000, 0x0000, 0x0000,
-  0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,};
-extern unsigned EMUSHORT ezero[];
-
-/* 5.0E-1 */
-unsigned EMUSHORT ehalf[NE] =
- {0x0000, 0x0000, 0x0000, 0x0000,
-  0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x3ffe,};
-extern unsigned EMUSHORT ehalf[];
-
-/* 1.0E0 */
-unsigned EMUSHORT eone[NE] =
- {0x0000, 0x0000, 0x0000, 0x0000,
-  0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x3fff,};
-extern unsigned EMUSHORT eone[];
-
-/* 2.0E0 */
-unsigned EMUSHORT etwo[NE] =
- {0x0000, 0x0000, 0x0000, 0x0000,
-  0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x4000,};
-extern unsigned EMUSHORT etwo[];
-
-/* 3.2E1 */
-unsigned EMUSHORT e32[NE] =
- {0x0000, 0x0000, 0x0000, 0x0000,
-  0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x4004,};
-extern unsigned EMUSHORT e32[];
-
-/* 6.93147180559945309417232121458176568075500134360255E-1 */
-unsigned EMUSHORT elog2[NE] =
- {0x40f3, 0xf6af, 0x03f2, 0xb398,
-  0xc9e3, 0x79ab, 0150717, 0013767, 0130562, 0x3ffe,};
-extern unsigned EMUSHORT elog2[];
-
-/* 1.41421356237309504880168872420969807856967187537695E0 */
-unsigned EMUSHORT esqrt2[NE] =
- {0x1d6f, 0xbe9f, 0x754a, 0x89b3,
-  0x597d, 0x6484, 0174736, 0171463, 0132404, 0x3fff,};
-extern unsigned EMUSHORT esqrt2[];
-
-/* 3.14159265358979323846264338327950288419716939937511E0 */
-unsigned EMUSHORT epi[NE] =
- {0x2902, 0x1cd1, 0x80dc, 0x628b,
-  0xc4c6, 0xc234, 0020550, 0155242, 0144417, 0040000,};
-extern unsigned EMUSHORT epi[];
-
-#else
-/* LONG_DOUBLE_TYPE_SIZE is other than 128 */
-unsigned EMUSHORT ezero[NE] =
- {0, 0000000, 0000000, 0000000, 0000000, 0000000,};
-unsigned EMUSHORT ehalf[NE] =
- {0, 0000000, 0000000, 0000000, 0100000, 0x3ffe,};
-unsigned EMUSHORT eone[NE] =
- {0, 0000000, 0000000, 0000000, 0100000, 0x3fff,};
-unsigned EMUSHORT etwo[NE] =
- {0, 0000000, 0000000, 0000000, 0100000, 0040000,};
-unsigned EMUSHORT e32[NE] =
- {0, 0000000, 0000000, 0000000, 0100000, 0040004,};
-unsigned EMUSHORT elog2[NE] =
- {0xc9e4, 0x79ab, 0150717, 0013767, 0130562, 0x3ffe,};
-unsigned EMUSHORT esqrt2[NE] =
- {0x597e, 0x6484, 0174736, 0171463, 0132404, 0x3fff,};
-unsigned EMUSHORT epi[NE] =
- {0xc4c6, 0xc234, 0020550, 0155242, 0144417, 0040000,};
-#endif
+    default:
+      abort ();
+    }
+}
 
-/* Control register for rounding precision.
-   This can be set to 113 (if NE=10), 80 (if NE=6), 64, 56, 53, or 24 bits.  */
+/* Determine whether a floating-point value X is infinite.  */
 
-int rndprc = NBITS;
-extern int rndprc;
+bool
+real_isinf (r)
+     const REAL_VALUE_TYPE *r;
+{
+  return (r->class == rvc_inf);
+}
 
-/*  Clear out entire e-type number X.  */
+/* Determine whether a floating-point value X is a NaN.  */
 
-static void
-eclear (x)
-     register unsigned EMUSHORT *x;
+bool
+real_isnan (r)
+     const REAL_VALUE_TYPE *r;
 {
-  register int i;
-
-  for (i = 0; i < NE; i++)
-    *x++ = 0;
+  return (r->class == rvc_nan);
 }
 
-/* Move e-type number from A to B.  */
+/* Determine whether a floating-point value X is negative.  */
 
-static void
-emov (a, b)
-     register unsigned EMUSHORT *a, *b;
+bool
+real_isneg (r)
+     const REAL_VALUE_TYPE *r;
 {
-  register int i;
-
-  for (i = 0; i < NE; i++)
-    *b++ = *a++;
+  return r->sign;
 }
 
+/* Determine whether a floating-point value X is minus zero.  */
 
-#if 0
-/* Absolute value of e-type X.  */
-
-static void
-eabs (x)
-     unsigned EMUSHORT x[];
+bool
+real_isnegzero (r)
+     const REAL_VALUE_TYPE *r;
 {
-  /* sign is top bit of last word of external format */
-  x[NE - 1] &= 0x7fff;
+  return r->sign && r->class == rvc_zero;
 }
-#endif /* 0 */
 
-/* Negate the e-type number X.  */
+/* Compare two floating-point objects for bitwise identity.  */
 
-static void
-eneg (x)
-     unsigned EMUSHORT x[];
+bool
+real_identical (a, b)
+     const REAL_VALUE_TYPE *a, *b;
 {
+  int i;
 
-  x[NE - 1] ^= 0x8000;         /* Toggle the sign bit */
-}
+  if (a->class != b->class)
+    return false;
+  if (a->sign != b->sign)
+    return false;
 
-/* Return 1 if sign bit of e-type number X is nonzero, else zero.  */
+  switch (a->class)
+    {
+    case rvc_zero:
+    case rvc_inf:
+      return true;
 
-static int
-eisneg (x)
-     unsigned EMUSHORT x[];
-{
+    case rvc_normal:
+      if (a->exp != b->exp)
+       return false;
+      break;
 
-  if (x[NE - 1] & 0x8000)
-    return (1);
-  else
-    return (0);
-}
+    case rvc_nan:
+      if (a->signalling != b->signalling)
+       return false;
+      /* The significand is ignored for canonical NaNs.  */
+      if (a->canonical || b->canonical)
+       return a->canonical == b->canonical;
+      break;
 
-/* Return 1 if e-type number X is infinity, else return zero.  */
+    default:
+      abort ();
+    }
 
-static int
-eisinf (x)
-     unsigned EMUSHORT x[];
-{
+  for (i = 0; i < SIGSZ; ++i)
+    if (a->sig[i] != b->sig[i])
+      return false;
 
-#ifdef NANS
-  if (eisnan (x))
-    return (0);
-#endif
-  if ((x[NE - 1] & 0x7fff) == 0x7fff)
-    return (1);
-  else
-    return (0);
+  return true;
 }
 
-/* Check if e-type number is not a number.  The bit pattern is one that we
-   defined, so we know for sure how to detect it.  */
+/* Try to change R into its exact multiplicative inverse in machine
+   mode MODE.  Return true if successful.  */
 
-static int
-eisnan (x)
-     unsigned EMUSHORT x[] ATTRIBUTE_UNUSED;
+bool
+exact_real_inverse (mode, r)
+     enum machine_mode mode;
+     REAL_VALUE_TYPE *r;
 {
-#ifdef NANS
+  const REAL_VALUE_TYPE *one = real_digit (1);
+  REAL_VALUE_TYPE u;
   int i;
+  
+  if (r->class != rvc_normal)
+    return false;
+
+  /* Check for a power of two: all significand bits zero except the MSB.  */
+  for (i = 0; i < SIGSZ-1; ++i)
+    if (r->sig[i] != 0)
+      return false;
+  if (r->sig[SIGSZ-1] != SIG_MSB)
+    return false;
+
+  /* Find the inverse and truncate to the required mode.  */
+  do_divide (&u, one, r);
+  real_convert (&u, mode, &u);
+  
+  /* The rounding may have overflowed.  */
+  if (u.class != rvc_normal)
+    return false;
+  for (i = 0; i < SIGSZ-1; ++i)
+    if (u.sig[i] != 0)
+      return false;
+  if (u.sig[SIGSZ-1] != SIG_MSB)
+    return false;
+
+  *r = u;
+  return true;
+}
+\f
+/* Render R as an integer.  */
 
-  /* NaN has maximum exponent */
-  if ((x[NE - 1] & 0x7fff) != 0x7fff)
-    return (0);
-  /* ... and non-zero significand field.  */
-  for (i = 0; i < NE - 1; i++)
-    {
-      if (*x++ != 0)
-        return (1);
-    }
-#endif
+HOST_WIDE_INT
+real_to_integer (r)
+     const REAL_VALUE_TYPE *r;
+{
+  unsigned HOST_WIDE_INT i;
+
+  switch (r->class)
+    {
+    case rvc_zero:
+    underflow:
+      return 0;
+
+    case rvc_inf:
+    case rvc_nan:
+    overflow:
+      i = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+      if (!r->sign)
+       i--;
+      return i;
+
+    case rvc_normal:
+      if (r->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;
+
+      if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+       i = r->sig[SIGSZ-1];
+      else if (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG)
+       {
+         i = r->sig[SIGSZ-1];
+         i = i << (HOST_BITS_PER_LONG - 1) << 1;
+         i |= r->sig[SIGSZ-2];
+       }
+      else
+       abort ();
+
+      i >>= HOST_BITS_PER_WIDE_INT - r->exp;
+
+      if (r->sign)
+       i = -i;
+      return i;
 
-  return (0);
+    default:
+      abort ();
+    }
 }
 
-/*  Fill e-type number X with infinity pattern (IEEE)
-    or largest possible number (non-IEEE).  */
+/* Likewise, but to an integer pair, HI+LOW.  */
 
-static void
-einfin (x)
-     register unsigned EMUSHORT *x;
+void
+real_to_integer2 (plow, phigh, r)
+     HOST_WIDE_INT *plow, *phigh;
+     const REAL_VALUE_TYPE *r;
 {
-  register int i;
-
-#ifdef INFINITY
-  for (i = 0; i < NE - 1; i++)
-    *x++ = 0;
-  *x |= 32767;
-#else
-  for (i = 0; i < NE - 1; i++)
-    *x++ = 0xffff;
-  *x |= 32766;
-  if (rndprc < NBITS)
+  REAL_VALUE_TYPE t;
+  HOST_WIDE_INT low, high;
+  int exp;
+
+  switch (r->class)
     {
-      if (rndprc == 113)
+    case rvc_zero:
+    underflow:
+      low = high = 0;
+      break;
+
+    case rvc_inf:
+    case rvc_nan:
+    overflow:
+      high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+      if (r->sign)
+       low = 0;
+      else
        {
-         *(x - 9) = 0;
-         *(x - 8) = 0;
+         high--;
+         low = -1;
        }
-      if (rndprc == 64)
+      break;
+
+    case rvc_normal:
+      exp = r->exp;
+      if (exp <= 0)
+       goto underflow;
+      /* Only force overflow for unsigned overflow.  Signed overflow is
+        undefined, so it doesn't matter what we return, and some callers
+        expect to be able to use this routine for both signed and 
+        unsigned conversions.  */
+      if (exp > 2*HOST_BITS_PER_WIDE_INT)
+       goto overflow;
+
+      rshift_significand (&t, r, 2*HOST_BITS_PER_WIDE_INT - exp);
+      if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
        {
-         *(x - 5) = 0;
+         high = t.sig[SIGSZ-1];
+         low = t.sig[SIGSZ-2];
        }
-      if (rndprc == 53)
+      else if (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG)
        {
-         *(x - 4) = 0xf800;
+         high = t.sig[SIGSZ-1];
+         high = high << (HOST_BITS_PER_LONG - 1) << 1;
+         high |= t.sig[SIGSZ-2];
+
+         low = t.sig[SIGSZ-3];
+         low = low << (HOST_BITS_PER_LONG - 1) << 1;
+         low |= t.sig[SIGSZ-4];
        }
       else
-       {
-         *(x - 4) = 0;
-         *(x - 3) = 0;
-         *(x - 2) = 0xff00;
-       }
-    }
-#endif
-}
-
-/* Output an e-type NaN.
-   This generates Intel's quiet NaN pattern for extended real.
-   The exponent is 7fff, the leading mantissa word is c000.  */
-
-#ifdef NANS
-static void
-enan (x, sign)
-     register unsigned EMUSHORT *x;
-     int sign;
-{
-  register int i;
-
-  for (i = 0; i < NE - 2; i++)
-    *x++ = 0;
-  *x++ = 0xc000;
-  *x = (sign << 15) | 0x7fff;
-}
-#endif /* NANS */
-
-/* Move in an e-type number A, converting it to exploded e-type B.  */
-
-static void
-emovi (a, b)
-     unsigned EMUSHORT *a, *b;
-{
-  register unsigned EMUSHORT *p, *q;
-  int i;
+       abort ();
 
-  q = b;
-  p = a + (NE - 1);            /* point to last word of external number */
-  /* get the sign bit */
-  if (*p & 0x8000)
-    *q++ = 0xffff;
-  else
-    *q++ = 0;
-  /* get the exponent */
-  *q = *p--;
-  *q++ &= 0x7fff;              /* delete the sign bit */
-#ifdef INFINITY
-  if ((*(q - 1) & 0x7fff) == 0x7fff)
-    {
-#ifdef NANS
-      if (eisnan (a))
+      if (r->sign)
        {
-         *q++ = 0;
-         for (i = 3; i < NI; i++)
-           *q++ = *p--;
-         return;
+         if (low == 0)
+           high = -high;
+         else
+           low = -low, high = ~high;
        }
-#endif
+      break;
 
-      for (i = 2; i < NI; i++)
-       *q++ = 0;
-      return;
+    default:
+      abort ();
     }
-#endif
 
-  /* clear high guard word */
-  *q++ = 0;
-  /* move in the significand */
-  for (i = 0; i < NE - 1; i++)
-    *q++ = *p--;
-  /* clear low guard word */
-  *q = 0;
+  *plow = low;
+  *phigh = high;
 }
 
-/* Move out exploded e-type number A, converting it to e type B.  */
+/* 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 void
-emovo (a, b)
-     unsigned EMUSHORT *a, *b;
+static unsigned long
+rtd_divmod (num, den)
+     REAL_VALUE_TYPE *num, *den;
 {
-  register unsigned EMUSHORT *p, *q;
-  unsigned EMUSHORT i;
-  int j;
-
-  p = a;
-  q = b + (NE - 1);            /* point to output exponent */
-  /* combine sign and exponent */
-  i = *p++;
-  if (i)
-    *q-- = *p++ | 0x8000;
-  else
-    *q-- = *p++;
-#ifdef INFINITY
-  if (*(p - 1) == 0x7fff)
+  unsigned long q, msb;
+  int expn = num->exp, expd = den->exp;
+
+  if (expn < expd)
+    return 0;
+
+  q = msb = 0;
+  goto start;
+  do
     {
-#ifdef NANS
-      if (eiisnan (a))
+      msb = num->sig[SIGSZ-1] & SIG_MSB;
+      q <<= 1;
+      lshift_significand_1 (num, num);
+    start:
+      if (msb || cmp_significands (num, den) >= 0)
        {
-         enan (b, eiisneg (a));
-         return;
+         sub_significands (num, num, den, 0);
+         q |= 1;
        }
-#endif
-      einfin (b);
-       return;
     }
-#endif
-  /* skip over guard word */
-  ++p;
-  /* move the significand */
-  for (j = 0; j < NE - 1; j++)
-    *q-- = *p++;
-}
-
-/* Clear out exploded e-type number XI.  */
+  while (--expn >= expd);
 
-static void
-ecleaz (xi)
-     register unsigned EMUSHORT *xi;
-{
-  register int i;
+  num->exp = expd;
+  normalize (num);
 
-  for (i = 0; i < NI; i++)
-    *xi++ = 0;
+  return q;
 }
 
-/* Clear out exploded e-type XI, but don't touch the sign.  */
+/* 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.  */
 
-static void
-ecleazs (xi)
-     register unsigned EMUSHORT *xi;
-{
-  register int i;
+#define M_LOG10_2      0.30102999566398119521
 
-  ++xi;
-  for (i = 0; i < NI - 1; i++)
-    *xi++ = 0;
-}
+void
+real_to_decimal (str, r_orig, buf_size, digits, crop_trailing_zeros)
+     char *str;
+     const REAL_VALUE_TYPE *r_orig;
+     size_t buf_size, digits;
+     int crop_trailing_zeros;
+{
+  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 = *r_orig;
+  switch (r.class)
+    {
+    case rvc_zero:
+      strcpy (str, (r.sign ? "-0.0" : "0.0"));
+      return;
+    case rvc_normal:
+      break;
+    case rvc_inf:
+      strcpy (str, (r.sign ? "-Inf" : "+Inf"));
+      return;
+    case rvc_nan:
+      /* ??? Print the significand as well, if not canonical?  */
+      strcpy (str, (r.sign ? "-NaN" : "+NaN"));
+      return;
+    default:
+      abort ();
+    }
 
-/* Move exploded e-type number from A to B.  */
+  /* Bound the number of digits printed by the size of the representation.  */
+  max_digits = SIGNIFICAND_BITS * M_LOG10_2;
+  if (digits == 0 || digits > max_digits)
+    digits = max_digits;
 
-static void
-emovz (a, b)
-     register unsigned EMUSHORT *a, *b;
-{
-  register int i;
+  /* 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;
 
-  for (i = 0; i < NI - 1; i++)
-    *b++ = *a++;
-  /* clear low guard word */
-  *b = 0;
-}
+  /* 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;
 
-/* Generate exploded e-type NaN.
-   The explicit pattern for this is maximum exponent and
-   top two significant bits set.  */
+  one = real_digit (1);
+  ten = ten_to_ptwo (0);
 
-#ifdef NANS
-static void
-einan (x)
-     unsigned EMUSHORT x[];
-{
+  sign = r.sign;
+  r.sign = 0;
 
-  ecleaz (x);
-  x[E] = 0x7fff;
-  x[M + 1] = 0xc000;
-}
-#endif /* NANS */
+  dec_exp = 0;
+  pten = *one;
 
-/* Return nonzero if exploded e-type X is a NaN.  */
+  cmp_one = do_compare (&r, one, 0);
+  if (cmp_one > 0)
+    {
+      int m;
 
-#ifdef NANS
-static int
-eiisnan (x)
-     unsigned EMUSHORT x[];
-{
-  int i;
+      /* Number is greater than one.  Convert significand to an integer
+        and strip trailing decimal zeros.  */
 
-  if ((x[E] & 0x7fff) == 0x7fff)
-    {
-      for (i = M + 1; i < NI; i++)
-       {
-         if (x[i] != 0)
-           return (1);
-       }
-    }
-  return (0);
-}
-#endif /* NANS */
+      u = r;
+      u.exp = SIGNIFICAND_BITS - 1;
 
-/* Return nonzero if sign of exploded e-type X is nonzero.  */
+      /* Largest M, such that 10**2**M fits within SIGNIFICAND_BITS.  */
+      m = floor_log2 (max_digits);
 
-#ifdef NANS
-static int
-eiisneg (x)
-     unsigned EMUSHORT x[];
-{
+      /* 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;
 
-  return x[0] != 0;
-}
-#endif /* NANS */
+         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);
 
-#if 0
-/* Fill exploded e-type X with infinity pattern.
-   This has maximum exponent and significand all zeros.  */
+      /* Revert the scaling to integer that we performed earlier.  */
+      u.exp += r.exp - (SIGNIFICAND_BITS - 1);
+      r = u;
 
-static void
-eiinfin (x)
-     unsigned EMUSHORT x[];
-{
+      /* 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;
+    }
+  if (cmp_one < 0)
+    {
+      int m;
 
-  ecleaz (x);
-  x[E] = 0x7fff;
-}
-#endif /* 0 */
+      /* Number is less than one.  Pad significand with leading
+        decimal zeros.  */
 
-/* Return nonzero if exploded e-type X is infinite.  */
+      v = r;
+      while (1)
+       {
+         /* Stop if we'd shift bits off the bottom.  */
+         if (v.sig[0] & 7)
+           break;
 
-#ifdef INFINITY
-static int
-eiisinf (x)
-     unsigned EMUSHORT x[];
-{
+         do_multiply (&u, &v, ten);
 
-#ifdef NANS
-  if (eiisnan (x))
-    return (0);
-#endif
-  if ((x[E] & 0x7fff) == 0x7fff)
-    return (1);
-  return (0);
-}
-#endif /* INFINITY */
+         /* Stop if we're now >= 1.  */
+         if (u.exp > 0)
+           break;
 
-/* Compare significands of numbers in internal exploded e-type format.
-   Guard words are included in the comparison.
+         v = u;
+         dec_exp -= 1;
+       }
+      r = v;
 
-   Returns     +1 if a > b
-                0 if a == b
-               -1 if a < b   */
+      /* 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);
 
-static int
-ecmpm (a, b)
-     register unsigned EMUSHORT *a, *b;
-{
-  int i;
+         if (do_compare (&v, ptenmtwo, 0) <= 0)
+           {
+             do_multiply (&v, &v, ptentwo);
+             do_multiply (&pten, &pten, ptentwo);
+             dec_exp -= 1 << m;
+           }
+       }
+      while (--m >= 0);
 
-  a += M;                      /* skip up to significand area */
-  b += M;
-  for (i = M; i < NI; i++)
-    {
-      if (*a++ != *b++)
-       goto difrnt;
+      /* Invert the positive power of 10 that we've collected so far.  */
+      do_divide (&pten, one, &pten);
     }
-  return (0);
 
- difrnt:
-  if (*(--a) > *(--b))
-    return (1);
-  else
-    return (-1);
-}
+  p = str;
+  if (sign)
+    *p++ = '-';
+  first = p++;
 
-/* Shift significand of exploded e-type X down by 1 bit.  */
+  /* At this point, PTEN should contain the nearest power of 10 smaller
+     than R, such that this division produces the first digit.
 
-static void
-eshdn1 (x)
-     register unsigned EMUSHORT *x;
-{
-  register unsigned EMUSHORT bits;
-  int i;
+     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.  */
 
-  x += M;                      /* point to significand area */
+  digit = rtd_divmod (&r, &pten);
 
-  bits = 0;
-  for (i = M; i < NI; i++)
+  /* Be prepared for error in that division via underflow ...  */
+  if (digit == 0 && cmp_significand_0 (&r))
     {
-      if (*x & 1)
-       bits |= 1;
-      *x >>= 1;
-      if (bits & 2)
-       *x |= 0x8000;
-      bits <<= 1;
-      ++x;
+      /* Multiply by 10 and try again.  */
+      do_multiply (&r, &r, ten);
+      digit = rtd_divmod (&r, &pten);
+      dec_exp -= 1;
+      if (digit == 0)
+       abort ();
     }
-}
-
-/* Shift significand of exploded e-type X up by 1 bit.  */
-
-static void
-eshup1 (x)
-     register unsigned EMUSHORT *x;
-{
-  register unsigned EMUSHORT bits;
-  int i;
-
-  x += NI - 1;
-  bits = 0;
 
-  for (i = M; i < NI; i++)
+  /* ... or overflow.  */
+  if (digit == 10)
     {
-      if (*x & 0x8000)
-       bits |= 1;
-      *x <<= 1;
-      if (bits & 2)
-       *x |= 1;
-      bits <<= 1;
-      --x;
+      *p++ = '1';
+      if (--digits > 0)
+       *p++ = '0';
+      dec_exp += 1;
     }
-}
-
-
-/* Shift significand of exploded e-type X down by 8 bits.  */
-
-static void
-eshdn8 (x)
-     register unsigned EMUSHORT *x;
-{
-  register unsigned EMUSHORT newbyt, oldbyt;
-  int i;
+  else if (digit > 10)
+    abort ();
+  else
+    *p++ = digit + '0';
 
-  x += M;
-  oldbyt = 0;
-  for (i = M; i < NI; i++)
+  /* Generate subsequent digits.  */
+  while (--digits > 0)
     {
-      newbyt = *x << 8;
-      *x >>= 8;
-      *x |= oldbyt;
-      oldbyt = newbyt;
-      ++x;
+      do_multiply (&r, &r, ten);
+      digit = rtd_divmod (&r, &pten);
+      *p++ = digit + '0';
     }
-}
-
-/* Shift significand of exploded e-type X up by 8 bits.  */
+  last = p;
 
-static void
-eshup8 (x)
-     register unsigned EMUSHORT *x;
-{
-  int i;
-  register unsigned EMUSHORT newbyt, oldbyt;
-
-  x += NI - 1;
-  oldbyt = 0;
+  /* Generate one more digit with which to do rounding.  */
+  do_multiply (&r, &r, ten);
+  digit = rtd_divmod (&r, &pten);
 
-  for (i = M; i < NI; i++)
+  /* Round the result.  */
+  if (digit == 5)
     {
-      newbyt = *x >> 8;
-      *x <<= 8;
-      *x |= oldbyt;
-      oldbyt = newbyt;
-      --x;
+      /* 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++;
     }
-}
-
-/* Shift significand of exploded e-type X up by 16 bits.  */
-
-static void
-eshup6 (x)
-     register unsigned EMUSHORT *x;
-{
-  int i;
-  register unsigned EMUSHORT *p;
+  if (digit > 5)
+    {
+      while (p > first)
+       {
+         digit = *--p;
+         if (digit == '9')
+           *p = '0';
+         else
+           {
+             *p = digit + 1;
+             break;
+           }
+       }
 
-  p = x + M;
-  x += M + 1;
+      /* 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] = '.';
 
-  for (i = M; i < NI - 1; i++)
-    *p++ = *x++;
+  /* If requested, drop trailing zeros.  Never crop past "1.0".  */
+  if (crop_trailing_zeros)
+    while (last > first + 3 && last[-1] == '0')
+      last--;
 
-  *p = 0;
+  /* Append the exponent.  */
+  sprintf (last, "e%+d", dec_exp);
 }
 
-/* Shift significand of exploded e-type X down by 16 bits.  */
+/* Render R as a hexadecimal floating point constant.  Emit DIGITS
+   significant digits in the result, bounded by BUF_SIZE.  If DIGITS is 0,
+   choose the maximum for the representation.  If CROP_TRAILING_ZEROS,
+   strip trailing zeros.  */
 
-static void
-eshdn6 (x)
-     register unsigned EMUSHORT *x;
+void
+real_to_hexadecimal (str, r, buf_size, digits, crop_trailing_zeros)
+     char *str;
+     const REAL_VALUE_TYPE *r;
+     size_t buf_size, digits;
+     int crop_trailing_zeros;
 {
-  int i;
-  register unsigned EMUSHORT *p;
+  int i, j, exp = r->exp;
+  char *p, *first;
+  char exp_buf[16];
+  size_t max_digits;
 
-  x += NI - 1;
-  p = x + 1;
+  switch (r->class)
+    {
+    case rvc_zero:
+      exp = 0;
+      break;
+    case rvc_normal:
+      break;
+    case rvc_inf:
+      strcpy (str, (r->sign ? "-Inf" : "+Inf"));
+      return;
+    case rvc_nan:
+      /* ??? Print the significand as well, if not canonical?  */
+      strcpy (str, (r->sign ? "-NaN" : "+NaN"));
+      return;
+    default:
+      abort ();
+    }
 
-  for (i = M; i < NI - 1; i++)
-    *(--p) = *(--x);
+  if (digits == 0)
+    digits = SIGNIFICAND_BITS / 4;
 
-  *(--p) = 0;
-}
+  /* Bound the number of digits printed by the size of the output buffer.  */
 
-/* Add significands of exploded e-type X and Y.  X + Y replaces Y.  */
+  sprintf (exp_buf, "p%+d", exp);
+  max_digits = buf_size - strlen (exp_buf) - r->sign - 4 - 1;
+  if (max_digits > buf_size)
+    abort ();
+  if (digits > max_digits)
+    digits = max_digits;
+
+  p = str;
+  if (r->sign)
+    *p++ = '-';
+  *p++ = '0';
+  *p++ = 'x';
+  *p++ = '0';
+  *p++ = '.';
+  first = p;
+
+  for (i = SIGSZ - 1; i >= 0; --i)
+    for (j = HOST_BITS_PER_LONG - 4; j >= 0; j -= 4)
+      {
+       *p++ = "0123456789abcdef"[(r->sig[i] >> j) & 15];
+       if (--digits == 0)
+         goto out;
+      }
 
-static void
-eaddm (x, y)
-     unsigned EMUSHORT *x, *y;
-{
-  register unsigned EMULONG a;
-  int i;
-  unsigned int carry;
+ out:
+  if (crop_trailing_zeros)
+    while (p > first + 1 && p[-1] == '0')
+      p--;
 
-  x += NI - 1;
-  y += NI - 1;
-  carry = 0;
-  for (i = M; i < NI; i++)
-    {
-      a = (unsigned EMULONG) (*x) + (unsigned EMULONG) (*y) + carry;
-      if (a & 0x10000)
-       carry = 1;
-      else
-       carry = 0;
-      *y = (unsigned EMUSHORT) a;
-      --x;
-      --y;
-    }
+  sprintf (p, "p%+d", exp);
 }
 
-/* Subtract significands of exploded e-type X and Y.  Y - X replaces Y.  */
+/* Initialize R from a decimal or hexadecimal string.  The string is
+   assumed to have been syntax checked already.  */
 
-static void
-esubm (x, y)
-     unsigned EMUSHORT *x, *y;
+void
+real_from_string (r, str)
+     REAL_VALUE_TYPE *r;
+     const char *str;
 {
-  unsigned EMULONG a;
-  int i;
-  unsigned int carry;
+  int exp = 0;
+  bool sign = false;
+
+  get_zero (r, 0);
 
-  x += NI - 1;
-  y += NI - 1;
-  carry = 0;
-  for (i = M; i < NI; i++)
+  if (*str == '-')
     {
-      a = (unsigned EMULONG) (*y) - (unsigned EMULONG) (*x) - carry;
-      if (a & 0x10000)
-       carry = 1;
-      else
-       carry = 0;
-      *y = (unsigned EMUSHORT) a;
-      --x;
-      --y;
+      sign = true;
+      str++;
     }
-}
+  else if (*str == '+')
+    str++;
 
+  if (str[0] == '0' && str[1] == 'x')
+    {
+      /* Hexadecimal floating point.  */
+      int pos = SIGNIFICAND_BITS - 4, d;
 
-static unsigned EMUSHORT equot[NI];
-
+      str += 2;
 
-#if 0
-/* Radix 2 shift-and-add versions of multiply and divide  */
+      while (*str == '0')
+       str++;
+      while (1)
+       {
+         d = hex_value (*str);
+         if (d == _hex_bad)
+           break;
+         if (pos >= 0)
+           {
+             r->sig[pos / HOST_BITS_PER_LONG]
+               |= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
+             pos -= 4;
+           }
+         exp += 4;
+         str++;
+       }
+      if (*str == '.')
+       {
+         str++;
+         if (pos == SIGNIFICAND_BITS - 4)
+           {
+             while (*str == '0')
+               str++, exp -= 4;
+           }
+         while (1)
+           {
+             d = hex_value (*str);
+             if (d == _hex_bad)
+               break;
+             if (pos >= 0)
+               {
+                 r->sig[pos / HOST_BITS_PER_LONG]
+                   |= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
+                 pos -= 4;
+               }
+             str++;
+           }
+       }
+      if (*str == 'p' || *str == 'P')
+       {
+         bool exp_neg = false;
 
+         str++;
+         if (*str == '-')
+           {
+             exp_neg = true;
+             str++;
+           }
+         else if (*str == '+')
+           str++;
 
-/* Divide significands */
+         d = 0;
+         while (ISDIGIT (*str))
+           {
+             d *= 10;
+             d += *str - '0';
+             if (d > MAX_EXP)
+               {
+                 /* Overflowed the exponent.  */
+                 if (exp_neg)
+                   goto underflow;
+                 else
+                   goto overflow;
+               }
+             str++;
+           }
+         if (exp_neg)
+           d = -d;
 
-int
-edivm (den, num)
-     unsigned EMUSHORT den[], num[];
-{
-  int i;
-  register unsigned EMUSHORT *p, *q;
-  unsigned EMUSHORT j;
+         exp += d;
+       }
 
-  p = &equot[0];
-  *p++ = num[0];
-  *p++ = num[1];
+      r->class = rvc_normal;
+      r->exp = exp;
 
-  for (i = M; i < NI; i++)
-    {
-      *p++ = 0;
+      normalize (r);
     }
-
-  /* Use faster compare and subtraction if denominator has only 15 bits of
-     significance.  */
-
-  p = &den[M + 2];
-  if (*p++ == 0)
+  else
     {
-      for (i = M + 3; i < NI; i++)
+      /* Decimal floating point.  */
+      const REAL_VALUE_TYPE *ten = ten_to_ptwo (0);
+      int d;
+
+      while (*str == '0')
+       str++;
+      while (ISDIGIT (*str))
        {
-         if (*p++ != 0)
-           goto fulldiv;
+         d = *str++ - '0';
+         do_multiply (r, r, ten);
+         if (d)
+           do_add (r, r, real_digit (d), 0);
        }
-      if ((den[M + 1] & 1) != 0)
-       goto fulldiv;
-      eshdn1 (num);
-      eshdn1 (den);
-
-      p = &den[M + 1];
-      q = &num[M + 1];
-
-      for (i = 0; i < NBITS + 2; i++)
+      if (*str == '.')
        {
-         if (*p <= *q)
+         str++;
+         if (r->class == rvc_zero)
            {
-             *q -= *p;
-             j = 1;
+             while (*str == '0')
+               str++, exp--;
            }
-         else
+         while (ISDIGIT (*str))
            {
-             j = 0;
+             d = *str++ - '0';
+             do_multiply (r, r, ten);
+             if (d)
+               do_add (r, r, real_digit (d), 0);
+             exp--;
            }
-         eshup1 (equot);
-         equot[NI - 2] |= j;
-         eshup1 (num);
        }
-      goto divdon;
-    }
 
-  /* The number of quotient bits to calculate is NBITS + 1 scaling guard
-     bit + 1 roundoff bit.  */
-
- fulldiv:
-
-  p = &equot[NI - 2];
-  for (i = 0; i < NBITS + 2; i++)
-    {
-      if (ecmpm (den, num) <= 0)
+      if (*str == 'e' || *str == 'E')
        {
-         esubm (den, num);
-         j = 1;                /* quotient bit = 1 */
-       }
-      else
-       j = 0;
-      eshup1 (equot);
-      *p |= j;
-      eshup1 (num);
-    }
+         bool exp_neg = false;
 
- divdon:
+         str++;
+         if (*str == '-')
+           {
+             exp_neg = true;
+             str++;
+           }
+         else if (*str == '+')
+           str++;
 
-  eshdn1 (equot);
-  eshdn1 (equot);
+         d = 0;
+         while (ISDIGIT (*str))
+           {
+             d *= 10;
+             d += *str - '0';
+             if (d > MAX_EXP)
+               {
+                 /* Overflowed the exponent.  */
+                 if (exp_neg)
+                   goto underflow;
+                 else
+                   goto overflow;
+               }
+             str++;
+           }
+         if (exp_neg)
+           d = -d;
+         exp += d;
+       }
 
-  /* test for nonzero remainder after roundoff bit */
-  p = &num[M];
-  j = 0;
-  for (i = M; i < NI; i++)
-    {
-      j |= *p++;
+      if (exp)
+       times_pten (r, exp);
     }
-  if (j)
-    j = 1;
 
+  r->sign = sign;
+  return;
 
-  for (i = 0; i < NI; i++)
-    num[i] = equot[i];
-  return ((int) j);
-}
+ underflow:
+  get_zero (r, sign);
+  return;
 
+ overflow:
+  get_inf (r, sign);
+  return;
+}
 
-/* Multiply significands */
+/* Legacy.  Similar, but return the result directly.  */
 
-int
-emulm (a, b)
-     unsigned EMUSHORT a[], b[];
+REAL_VALUE_TYPE
+real_from_string2 (s, mode)
+     const char *s;
+     enum machine_mode mode;
 {
-  unsigned EMUSHORT *p, *q;
-  int i, j, k;
-
-  equot[0] = b[0];
-  equot[1] = b[1];
-  for (i = M; i < NI; i++)
-    equot[i] = 0;
-
-  p = &a[NI - 2];
-  k = NBITS;
-  while (*p == 0)              /* significand is not supposed to be zero */
-    {
-      eshdn6 (a);
-      k -= 16;
-    }
-  if ((*p & 0xff) == 0)
-    {
-      eshdn8 (a);
-      k -= 8;
-    }
-
-  q = &equot[NI - 1];
-  j = 0;
-  for (i = 0; i < k; i++)
-    {
-      if (*p & 1)
-       eaddm (b, equot);
-      /* remember if there were any nonzero bits shifted out */
-      if (*q & 1)
-       j |= 1;
-      eshdn1 (a);
-      eshdn1 (equot);
-    }
+  REAL_VALUE_TYPE r;
 
-  for (i = 0; i < NI; i++)
-    b[i] = equot[i];
+  real_from_string (&r, s);
+  if (mode != VOIDmode)
+    real_convert (&r, mode, &r);
 
-  /* return flag for lost nonzero bits */
-  return (j);
+  return r;
 }
 
-#else
-
-/* Radix 65536 versions of multiply and divide.  */
+/* Initialize R from the integer pair HIGH+LOW.  */
 
-/* Multiply significand of e-type number B
-   by 16-bit quantity A, return e-type result to C.  */
-
-static void
-m16m (a, b, c)
-     unsigned int a;
-     unsigned EMUSHORT b[], c[];
+void
+real_from_integer (r, mode, low, high, unsigned_p)
+     REAL_VALUE_TYPE *r;
+     enum machine_mode mode;
+     unsigned HOST_WIDE_INT low;
+     HOST_WIDE_INT high;
+     int unsigned_p;
 {
-  register unsigned EMUSHORT *pp;
-  register unsigned EMULONG carry;
-  unsigned EMUSHORT *ps;
-  unsigned EMUSHORT p[NI];
-  unsigned EMULONG aa, m;
-  int i;
+  if (low == 0 && high == 0)
+    get_zero (r, 0);
+  else
+    {
+      r->class = rvc_normal;
+      r->sign = high < 0 && !unsigned_p;
+      r->exp = 2 * HOST_BITS_PER_WIDE_INT;
 
-  aa = a;
-  pp = &p[NI-2];
-  *pp++ = 0;
-  *pp = 0;
-  ps = &b[NI-1];
+      if (r->sign)
+       {
+         high = ~high;
+         if (low == 0)
+           high += 1;
+         else
+           low = -low;
+       }
 
-  for (i=M+1; i<NI; i++)
-    {
-      if (*ps == 0)
+      if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
        {
-         --ps;
-         --pp;
-         *(pp-1) = 0;
+         r->sig[SIGSZ-1] = high;
+         r->sig[SIGSZ-2] = low;
+         memset (r->sig, 0, sizeof(long)*(SIGSZ-2));
        }
-      else
+      else if (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT)
        {
-         m = (unsigned EMULONG) aa * *ps--;
-         carry = (m & 0xffff) + *pp;
-         *pp-- = (unsigned EMUSHORT)carry;
-         carry = (carry >> 16) + (m >> 16) + *pp;
-         *pp = (unsigned EMUSHORT)carry;
-         *(pp-1) = carry >> 16;
+         r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1;
+         r->sig[SIGSZ-2] = high;
+         r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
+         r->sig[SIGSZ-4] = low;
+         if (SIGSZ > 4)
+           memset (r->sig, 0, sizeof(long)*(SIGSZ-4));
        }
+      else
+       abort ();
+
+      normalize (r);
     }
-  for (i=M; i<NI; i++)
-    c[i] = p[i];
+
+  if (mode != VOIDmode)
+    real_convert (r, mode, r);
 }
 
-/* Divide significands of exploded e-types NUM / DEN.  Neither the
-   numerator NUM nor the denominator DEN is permitted to have its high guard
-   word nonzero.  */
+/* Returns 10**2**N.  */
 
-static int
-edivm (den, num)
-     unsigned EMUSHORT den[], num[];
+static const REAL_VALUE_TYPE *
+ten_to_ptwo (n)
+     int n;
 {
-  int i;
-  register unsigned EMUSHORT *p;
-  unsigned EMULONG tnum;
-  unsigned EMUSHORT j, tdenm, tquot;
-  unsigned EMUSHORT tprod[NI+1];
+  static REAL_VALUE_TYPE tens[EXP_BITS];
 
-  p = &equot[0];
-  *p++ = num[0];
-  *p++ = num[1];
+  if (n < 0 || n >= EXP_BITS)
+    abort ();
 
-  for (i=M; i<NI; i++)
-    {
-      *p++ = 0;
-    }
-  eshdn1 (num);
-  tdenm = den[M+1];
-  for (i=M; i<NI; i++)
+  if (tens[n].class == rvc_zero)
     {
-      /* Find trial quotient digit (the radix is 65536).  */
-      tnum = (((unsigned EMULONG) num[M]) << 16) + num[M+1];
+      if (n < (HOST_BITS_PER_WIDE_INT == 64 ? 5 : 4))
+       {
+         HOST_WIDE_INT t = 10;
+         int i;
 
-      /* Do not execute the divide instruction if it will overflow.  */
-      if ((tdenm * (unsigned long)0xffff) < tnum)
-       tquot = 0xffff;
+         for (i = 0; i < n; ++i)
+           t *= t;
+
+         real_from_integer (&tens[n], VOIDmode, t, 0, 1);
+       }
       else
-       tquot = tnum / tdenm;
-      /* Multiply denominator by trial quotient digit.  */
-      m16m ((unsigned int)tquot, den, tprod);
-      /* The quotient digit may have been overestimated.  */
-      if (ecmpm (tprod, num) > 0)
        {
-         tquot -= 1;
-         esubm (den, tprod);
-         if (ecmpm (tprod, num) > 0)
-           {
-             tquot -= 1;
-             esubm (den, tprod);
-           }
+         const REAL_VALUE_TYPE *t = ten_to_ptwo (n - 1);
+         do_multiply (&tens[n], t, t);
        }
-      esubm (tprod, num);
-      equot[i] = tquot;
-      eshup6(num);
     }
-  /* test for nonzero remainder after roundoff bit */
-  p = &num[M];
-  j = 0;
-  for (i=M; i<NI; i++)
-    {
-      j |= *p++;
-    }
-  if (j)
-    j = 1;
 
-  for (i=0; i<NI; i++)
-    num[i] = equot[i];
-
-  return ((int)j);
+  return &tens[n];
 }
 
-/* Multiply significands of exploded e-type A and B, result in B.  */
+/* Returns 10**(-2**N).  */
 
-static int
-emulm (a, b)
-     unsigned EMUSHORT a[], b[];
+static const REAL_VALUE_TYPE *
+ten_to_mptwo (n)
+     int n;
 {
-  unsigned EMUSHORT *p, *q;
-  unsigned EMUSHORT pprod[NI];
-  unsigned EMUSHORT j;
-  int i;
+  static REAL_VALUE_TYPE tens[EXP_BITS];
 
-  equot[0] = b[0];
-  equot[1] = b[1];
-  for (i=M; i<NI; i++)
-    equot[i] = 0;
-
-  j = 0;
-  p = &a[NI-1];
-  q = &equot[NI-1];
-  for (i=M+1; i<NI; i++)
-    {
-      if (*p == 0)
-       {
-         --p;
-       }
-      else
-       {
-         m16m ((unsigned int) *p--, b, pprod);
-         eaddm(pprod, equot);
-       }
-      j |= *q;
-      eshdn6(equot);
-    }
+  if (n < 0 || n >= EXP_BITS)
+    abort ();
 
-  for (i=0; i<NI; i++)
-    b[i] = equot[i];
+  if (tens[n].class == rvc_zero)
+    do_divide (&tens[n], real_digit (1), ten_to_ptwo (n));
 
-  /* return flag for lost nonzero bits */
-  return ((int)j);
+  return &tens[n];
 }
-#endif
 
+/* Returns N.  */
 
-/* Normalize and round off.
-
-  The internal format number to be rounded is S.
-  Input LOST is 0 if the value is exact.  This is the so-called sticky bit.
-
-  Input SUBFLG indicates whether the number was obtained
-  by a subtraction operation.  In that case if LOST is nonzero
-  then the number is slightly smaller than indicated.
+static const REAL_VALUE_TYPE *
+real_digit (n)
+     int n;
+{
+  static REAL_VALUE_TYPE num[10];
 
-  Input EXP is the biased exponent, which may be negative.
-  the exponent field of S is ignored but is replaced by
-  EXP as adjusted by normalization and rounding.
+  if (n < 0 || n > 9)
+    abort ();
 
-  Input RCNTRL is the rounding control.  If it is nonzero, the
-  returned value will be rounded to RNDPRC bits.
+  if (n > 0 && num[n].class == rvc_zero)
+    real_from_integer (&num[n], VOIDmode, n, 0, 1);
 
-  For future reference:  In order for emdnorm to round off denormal
-   significands at the right point, the input exponent must be
-   adjusted to be the actual value it would have after conversion to
-   the final floating point type.  This adjustment has been
-   implemented for all type conversions (etoe53, etc.) and decimal
-   conversions, but not for the arithmetic functions (eadd, etc.).
-   Data types having standard 15-bit exponents are not affected by
-   this, but SFmode and DFmode are affected. For example, ediv with
-   rndprc = 24 will not round correctly to 24-bit precision if the
-   result is denormal.   */
+  return &num[n];
+}
 
-static int rlast = -1;
-static int rw = 0;
-static unsigned EMUSHORT rmsk = 0;
-static unsigned EMUSHORT rmbit = 0;
-static unsigned EMUSHORT rebit = 0;
-static int re = 0;
-static unsigned EMUSHORT rbit[NI];
+/* Multiply R by 10**EXP.  */
 
 static void
-emdnorm (s, lost, subflg, exp, rcntrl)
-     unsigned EMUSHORT s[];
-     int lost;
-     int subflg;
-     EMULONG exp;
-     int rcntrl;
+times_pten (r, exp)
+     REAL_VALUE_TYPE *r;
+     int exp;
 {
-  int i, j;
-  unsigned EMUSHORT r;
-
-  /* Normalize */
-  j = enormlz (s);
-
-  /* a blank significand could mean either zero or infinity.  */
-#ifndef INFINITY
-  if (j > NBITS)
-    {
-      ecleazs (s);
-      return;
-    }
-#endif
-  exp -= j;
-#ifndef INFINITY
-  if (exp >= 32767L)
-    goto overf;
-#else
-  if ((j > NBITS) && (exp < 32767))
-    {
-      ecleazs (s);
-      return;
-    }
-#endif
-  if (exp < 0L)
-    {
-      if (exp > (EMULONG) (-NBITS - 1))
-       {
-         j = (int) exp;
-         i = eshift (s, j);
-         if (i)
-           lost = 1;
-       }
-      else
-       {
-         ecleazs (s);
-         return;
-       }
-    }
-  /* Round off, unless told not to by rcntrl.  */
-  if (rcntrl == 0)
-    goto mdfin;
-  /* Set up rounding parameters if the control register changed.  */
-  if (rndprc != rlast)
-    {
-      ecleaz (rbit);
-      switch (rndprc)
-       {
-       default:
-       case NBITS:
-         rw = NI - 1;          /* low guard word */
-         rmsk = 0xffff;
-         rmbit = 0x8000;
-         re = rw - 1;
-         rebit = 1;
-         break;
-
-       case 113:
-         rw = 10;
-         rmsk = 0x7fff;
-         rmbit = 0x4000;
-         rebit = 0x8000;
-         re = rw;
-         break;
-
-       case 64:
-         rw = 7;
-         rmsk = 0xffff;
-         rmbit = 0x8000;
-         re = rw - 1;
-         rebit = 1;
-         break;
-
-         /* For DEC or IBM arithmetic */
-       case 56:
-         rw = 6;
-         rmsk = 0xff;
-         rmbit = 0x80;
-         rebit = 0x100;
-         re = rw;
-         break;
-
-       case 53:
-         rw = 6;
-         rmsk = 0x7ff;
-         rmbit = 0x0400;
-         rebit = 0x800;
-         re = rw;
-         break;
-
-         /* For C4x arithmetic */
-       case 32:
-         rw = 5;
-         rmsk = 0xffff;
-         rmbit = 0x8000;
-         rebit = 1;
-         re = rw - 1;
-         break;
-
-       case 24:
-         rw = 4;
-         rmsk = 0xff;
-         rmbit = 0x80;
-         rebit = 0x100;
-         re = rw;
-         break;
-       }
-      rbit[re] = rebit;
-      rlast = rndprc;
-    }
-
-  /* Shift down 1 temporarily if the data structure has an implied
-     most significant bit and the number is denormal.
-     Intel long double denormals also lose one bit of precision.  */
-  if ((exp <= 0) && (rndprc != NBITS)
-      && ((rndprc != 64) || ((rndprc == 64) && ! REAL_WORDS_BIG_ENDIAN)))
-    {
-      lost |= s[NI - 1] & 1;
-      eshdn1 (s);
-    }
-  /* Clear out all bits below the rounding bit,
-     remembering in r if any were nonzero.  */
-  r = s[rw] & rmsk;
-  if (rndprc < NBITS)
-    {
-      i = rw + 1;
-      while (i < NI)
-       {
-         if (s[i])
-           r |= 1;
-         s[i] = 0;
-         ++i;
-       }
-    }
-  s[rw] &= ~rmsk;
-  if ((r & rmbit) != 0)
-    {
-#ifndef C4X
-      if (r == rmbit)
-       {
-         if (lost == 0)
-           {                   /* round to even */
-             if ((s[re] & rebit) == 0)
-               goto mddone;
-           }
-         else
-           {
-             if (subflg != 0)
-               goto mddone;
-           }
-       }
-#endif
-      eaddm (rbit, s);
-    }
- mddone:
-/* Undo the temporary shift for denormal values.  */
-  if ((exp <= 0) && (rndprc != NBITS)
-      && ((rndprc != 64) || ((rndprc == 64) && ! REAL_WORDS_BIG_ENDIAN)))
-    {
-      eshup1 (s);
-    }
-  if (s[2] != 0)
-    {                          /* overflow on roundoff */
-      eshdn1 (s);
-      exp += 1;
-    }
- mdfin:
-  s[NI - 1] = 0;
-  if (exp >= 32767L)
-    {
-#ifndef INFINITY
-    overf:
-#endif
-#ifdef INFINITY
-      s[1] = 32767;
-      for (i = 2; i < NI - 1; i++)
-       s[i] = 0;
-      if (extra_warnings)
-       warning ("floating point overflow");
-#else
-      s[1] = 32766;
-      s[2] = 0;
-      for (i = M + 1; i < NI - 1; i++)
-       s[i] = 0xffff;
-      s[NI - 1] = 0;
-      if ((rndprc < 64) || (rndprc == 113))
-       {
-         s[rw] &= ~rmsk;
-         if (rndprc == 24)
-           {
-             s[5] = 0;
-             s[6] = 0;
-           }
-       }
-#endif
-      return;
-    }
-  if (exp < 0)
-    s[1] = 0;
-  else
-    s[1] = (unsigned EMUSHORT) exp;
-}
-
-/*  Subtract.  C = B - A, all e type numbers.  */
-
-static int subflg = 0;
-
-static void
-esub (a, b, c)
-     unsigned EMUSHORT *a, *b, *c;
-{
-
-#ifdef NANS
-  if (eisnan (a))
-    {
-      emov (a, c);
-      return;
-    }
-  if (eisnan (b))
-    {
-      emov (b, c);
-      return;
-    }
-/* Infinity minus infinity is a NaN.
-   Test for subtracting infinities of the same sign.  */
-  if (eisinf (a) && eisinf (b)
-      && ((eisneg (a) ^ eisneg (b)) == 0))
-    {
-      mtherr ("esub", INVALID);
-      enan (c, 0);
-      return;
-    }
-#endif
-  subflg = 1;
-  eadd1 (a, b, c);
-}
-
-/* Add.  C = A + B, all e type.  */
-
-static void
-eadd (a, b, c)
-     unsigned EMUSHORT *a, *b, *c;
-{
-
-#ifdef NANS
-/* NaN plus anything is a NaN.  */
-  if (eisnan (a))
-    {
-      emov (a, c);
-      return;
-    }
-  if (eisnan (b))
-    {
-      emov (b, c);
-      return;
-    }
-/* Infinity minus infinity is a NaN.
-   Test for adding infinities of opposite signs.  */
-  if (eisinf (a) && eisinf (b)
-      && ((eisneg (a) ^ eisneg (b)) != 0))
-    {
-      mtherr ("esub", INVALID);
-      enan (c, 0);
-      return;
-    }
-#endif
-  subflg = 0;
-  eadd1 (a, b, c);
-}
-
-/* Arithmetic common to both addition and subtraction.  */
-
-static void
-eadd1 (a, b, c)
-     unsigned EMUSHORT *a, *b, *c;
-{
-  unsigned EMUSHORT ai[NI], bi[NI], ci[NI];
-  int i, lost, j, k;
-  EMULONG lt, lta, ltb;
-
-#ifdef INFINITY
-  if (eisinf (a))
-    {
-      emov (a, c);
-      if (subflg)
-       eneg (c);
-      return;
-    }
-  if (eisinf (b))
-    {
-      emov (b, c);
-      return;
-    }
-#endif
-  emovi (a, ai);
-  emovi (b, bi);
-  if (subflg)
-    ai[0] = ~ai[0];
-
-  /* compare exponents */
-  lta = ai[E];
-  ltb = bi[E];
-  lt = lta - ltb;
-  if (lt > 0L)
-    {                          /* put the larger number in bi */
-      emovz (bi, ci);
-      emovz (ai, bi);
-      emovz (ci, ai);
-      ltb = bi[E];
-      lt = -lt;
-    }
-  lost = 0;
-  if (lt != 0L)
-    {
-      if (lt < (EMULONG) (-NBITS - 1))
-       goto done;              /* answer same as larger addend */
-      k = (int) lt;
-      lost = eshift (ai, k);   /* shift the smaller number down */
-    }
-  else
-    {
-      /* exponents were the same, so must compare significands */
-      i = ecmpm (ai, bi);
-      if (i == 0)
-       {                       /* the numbers are identical in magnitude */
-         /* if different signs, result is zero */
-         if (ai[0] != bi[0])
-           {
-             eclear (c);
-             return;
-           }
-         /* if same sign, result is double */
-         /* double denormalized tiny number */
-         if ((bi[E] == 0) && ((bi[3] & 0x8000) == 0))
-           {
-             eshup1 (bi);
-             goto done;
-           }
-         /* add 1 to exponent unless both are zero! */
-         for (j = 1; j < NI - 1; j++)
-           {
-             if (bi[j] != 0)
-               {
-                 ltb += 1;
-                 if (ltb >= 0x7fff)
-                   {
-                     eclear (c);
-                     if (ai[0] != 0)
-                       eneg (c);
-                     einfin (c);
-                     return;
-                   }
-                 break;
-               }
-           }
-         bi[E] = (unsigned EMUSHORT) ltb;
-         goto done;
-       }
-      if (i > 0)
-       {                       /* put the larger number in bi */
-         emovz (bi, ci);
-         emovz (ai, bi);
-         emovz (ci, ai);
-       }
-    }
-  if (ai[0] == bi[0])
-    {
-      eaddm (ai, bi);
-      subflg = 0;
-    }
-  else
-    {
-      esubm (ai, bi);
-      subflg = 1;
-    }
-  emdnorm (bi, lost, subflg, ltb, 64);
-
- done:
-  emovo (bi, c);
-}
-
-/* Divide: C = B/A, all e type.  */
-
-static void
-ediv (a, b, c)
-     unsigned EMUSHORT *a, *b, *c;
-{
-  unsigned EMUSHORT ai[NI], bi[NI];
-  int i, sign;
-  EMULONG lt, lta, ltb;
-
-/* IEEE says if result is not a NaN, the sign is "-" if and only if
-   operands have opposite signs -- but flush -0 to 0 later if not IEEE.  */
-  sign = eisneg(a) ^ eisneg(b);
-
-#ifdef NANS
-/* Return any NaN input.  */
-  if (eisnan (a))
-    {
-    emov (a, c);
-    return;
-    }
-  if (eisnan (b))
-    {
-    emov (b, c);
-    return;
-    }
-/* Zero over zero, or infinity over infinity, is a NaN.  */
-  if (((ecmp (a, ezero) == 0) && (ecmp (b, ezero) == 0))
-      || (eisinf (a) && eisinf (b)))
-    {
-    mtherr ("ediv", INVALID);
-    enan (c, sign);
-    return;
-    }
-#endif
-/* Infinity over anything else is infinity.  */
-#ifdef INFINITY
-  if (eisinf (b))
-    {
-      einfin (c);
-      goto divsign;
-    }
-/* Anything else over infinity is zero.  */
-  if (eisinf (a))
-    {
-      eclear (c);
-      goto divsign;
-    }
-#endif
-  emovi (a, ai);
-  emovi (b, bi);
-  lta = ai[E];
-  ltb = bi[E];
-  if (bi[E] == 0)
-    {                          /* See if numerator is zero.  */
-      for (i = 1; i < NI - 1; i++)
-       {
-         if (bi[i] != 0)
-           {
-             ltb -= enormlz (bi);
-             goto dnzro1;
-           }
-       }
-      eclear (c);
-      goto divsign;
-    }
- dnzro1:
-
-  if (ai[E] == 0)
-    {                          /* possible divide by zero */
-      for (i = 1; i < NI - 1; i++)
-       {
-         if (ai[i] != 0)
-           {
-             lta -= enormlz (ai);
-             goto dnzro2;
-           }
-       }
-/* Divide by zero is not an invalid operation.
-   It is a divide-by-zero operation!   */
-      einfin (c);
-      mtherr ("ediv", SING);
-      goto divsign;
-    }
- dnzro2:
-
-  i = edivm (ai, bi);
-  /* calculate exponent */
-  lt = ltb - lta + EXONE;
-  emdnorm (bi, i, 0, lt, 64);
-  emovo (bi, c);
-
- divsign:
-
-  if (sign
-#ifndef IEEE
-      && (ecmp (c, ezero) != 0)
-#endif
-      )
-     *(c+(NE-1)) |= 0x8000;
-  else
-     *(c+(NE-1)) &= ~0x8000;
-}
-
-/* Multiply e-types A and B, return e-type product C.   */
-
-static void
-emul (a, b, c)
-     unsigned EMUSHORT *a, *b, *c;
-{
-  unsigned EMUSHORT ai[NI], bi[NI];
-  int i, j, sign;
-  EMULONG lt, lta, ltb;
-
-/* IEEE says if result is not a NaN, the sign is "-" if and only if
-   operands have opposite signs -- but flush -0 to 0 later if not IEEE.  */
-  sign = eisneg(a) ^ eisneg(b);
-
-#ifdef NANS
-/* NaN times anything is the same NaN.  */
-  if (eisnan (a))
-    {
-    emov (a, c);
-    return;
-    }
-  if (eisnan (b))
-    {
-    emov (b, c);
-    return;
-    }
-/* Zero times infinity is a NaN.  */
-  if ((eisinf (a) && (ecmp (b, ezero) == 0))
-      || (eisinf (b) && (ecmp (a, ezero) == 0)))
-    {
-    mtherr ("emul", INVALID);
-    enan (c, sign);
-    return;
-    }
-#endif
-/* Infinity times anything else is infinity.  */
-#ifdef INFINITY
-  if (eisinf (a) || eisinf (b))
-    {
-      einfin (c);
-      goto mulsign;
-    }
-#endif
-  emovi (a, ai);
-  emovi (b, bi);
-  lta = ai[E];
-  ltb = bi[E];
-  if (ai[E] == 0)
-    {
-      for (i = 1; i < NI - 1; i++)
-       {
-         if (ai[i] != 0)
-           {
-             lta -= enormlz (ai);
-             goto mnzer1;
-           }
-       }
-      eclear (c);
-      goto mulsign;
-    }
- mnzer1:
-
-  if (bi[E] == 0)
-    {
-      for (i = 1; i < NI - 1; i++)
-       {
-         if (bi[i] != 0)
-           {
-             ltb -= enormlz (bi);
-             goto mnzer2;
-           }
-       }
-      eclear (c);
-      goto mulsign;
-    }
- mnzer2:
-
-  /* Multiply significands */
-  j = emulm (ai, bi);
-  /* calculate exponent */
-  lt = lta + ltb - (EXONE - 1);
-  emdnorm (bi, j, 0, lt, 64);
-  emovo (bi, c);
-
- mulsign:
-
-  if (sign
-#ifndef IEEE
-      && (ecmp (c, ezero) != 0)
-#endif
-      )
-     *(c+(NE-1)) |= 0x8000;
-  else
-     *(c+(NE-1)) &= ~0x8000;
-}
-
-/* Convert double precision PE to e-type Y.  */
-
-static void
-e53toe (pe, y)
-     unsigned EMUSHORT *pe, *y;
-{
-#ifdef DEC
-
-  dectoe (pe, y);
-
-#else
-#ifdef IBM
-
-  ibmtoe (pe, y, DFmode);
-
-#else
-#ifdef C4X
-
-  c4xtoe (pe, y, HFmode);
-
-#else
-  register unsigned EMUSHORT r;
-  register unsigned EMUSHORT *e, *p;
-  unsigned EMUSHORT yy[NI];
-  int denorm, k;
-
-  e = pe;
-  denorm = 0;                  /* flag if denormalized number */
-  ecleaz (yy);
-  if (! REAL_WORDS_BIG_ENDIAN)
-    e += 3;
-  r = *e;
-  yy[0] = 0;
-  if (r & 0x8000)
-    yy[0] = 0xffff;
-  yy[M] = (r & 0x0f) | 0x10;
-  r &= ~0x800f;                        /* strip sign and 4 significand bits */
-#ifdef INFINITY
-  if (r == 0x7ff0)
-    {
-#ifdef NANS
-      if (! REAL_WORDS_BIG_ENDIAN)
-       {
-         if (((pe[3] & 0xf) != 0) || (pe[2] != 0)
-             || (pe[1] != 0) || (pe[0] != 0))
-           {
-             enan (y, yy[0] != 0);
-             return;
-           }
-       }
-      else
-       {
-         if (((pe[0] & 0xf) != 0) || (pe[1] != 0)
-             || (pe[2] != 0) || (pe[3] != 0))
-           {
-             enan (y, yy[0] != 0);
-             return;
-           }
-       }
-#endif  /* NANS */
-      eclear (y);
-      einfin (y);
-      if (yy[0])
-       eneg (y);
-      return;
-    }
-#endif  /* INFINITY */
-  r >>= 4;
-  /* If zero exponent, then the significand is denormalized.
-     So take back the understood high significand bit.  */
-
-  if (r == 0)
-    {
-      denorm = 1;
-      yy[M] &= ~0x10;
-    }
-  r += EXONE - 01777;
-  yy[E] = r;
-  p = &yy[M + 1];
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    {
-      *p++ = *(--e);
-      *p++ = *(--e);
-      *p++ = *(--e);
-    }
-  else
-    {
-      ++e;
-      *p++ = *e++;
-      *p++ = *e++;
-      *p++ = *e++;
-    }
-#endif
-  eshift (yy, -5);
-  if (denorm)
-    {
-       /* If zero exponent, then normalize the significand.  */
-      if ((k = enormlz (yy)) > NBITS)
-       ecleazs (yy);
-      else
-       yy[E] -= (unsigned EMUSHORT) (k - 1);
-    }
-  emovo (yy, y);
-#endif /* not C4X */
-#endif /* not IBM */
-#endif /* not DEC */
-}
-
-/* Convert double extended precision float PE to e type Y.  */
-
-static void
-e64toe (pe, y)
-     unsigned EMUSHORT *pe, *y;
-{
-  unsigned EMUSHORT yy[NI];
-  unsigned EMUSHORT *e, *p, *q;
+  REAL_VALUE_TYPE pten, *rr;
+  bool negative = (exp < 0);
   int i;
 
-  e = pe;
-  p = yy;
-  for (i = 0; i < NE - 5; i++)
-    *p++ = 0;
-/* This precision is not ordinarily supported on DEC or IBM.  */
-#ifdef DEC
-  for (i = 0; i < 5; i++)
-    *p++ = *e++;
-#endif
-#ifdef IBM
-  p = &yy[0] + (NE - 1);
-  *p-- = *e++;
-  ++e;
-  for (i = 0; i < 5; i++)
-    *p-- = *e++;
-#endif
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
+  if (negative)
     {
-      for (i = 0; i < 5; i++)
-       *p++ = *e++;
-
-      /* For denormal long double Intel format, shift significand up one
-        -- but only if the top significand bit is zero.  A top bit of 1
-        is "pseudodenormal" when the exponent is zero.  */
-      if((yy[NE-1] & 0x7fff) == 0 && (yy[NE-2] & 0x8000) == 0)
-       {
-         unsigned EMUSHORT temp[NI];
-
-         emovi(yy, temp);
-         eshup1(temp);
-         emovo(temp,y);
-         return;
-       }
+      exp = -exp;
+      pten = *real_digit (1);
+      rr = &pten;
     }
   else
-    {
-      p = &yy[0] + (NE - 1);
-#ifdef ARM_EXTENDED_IEEE_FORMAT
-      /* For ARMs, the exponent is in the lowest 15 bits of the word.  */
-      *p-- = (e[0] & 0x8000) | (e[1] & 0x7ffff);
-      e += 2;
-#else
-      *p-- = *e++;
-      ++e;
-#endif
-      for (i = 0; i < 4; i++)
-       *p-- = *e++;
-    }
-#endif
-#ifdef INFINITY
-  /* Point to the exponent field and check max exponent cases.  */
-  p = &yy[NE - 1];
-  if ((*p & 0x7fff) == 0x7fff)
-    {
-#ifdef NANS
-      if (! REAL_WORDS_BIG_ENDIAN)
-       {
-         for (i = 0; i < 4; i++)
-           {
-             if ((i != 3 && pe[i] != 0)
-                 /* Anything but 0x8000 here, including 0, is a NaN.  */
-                 || (i == 3 && pe[i] != 0x8000))
-               {
-                 enan (y, (*p & 0x8000) != 0);
-                 return;
-               }
-           }
-       }
-      else
-       {
-#ifdef ARM_EXTENDED_IEEE_FORMAT
-         for (i = 2; i <= 5; i++)
-           {
-             if (pe[i] != 0)
-               {
-                 enan (y, (*p & 0x8000) != 0);
-                 return;
-               }
-           }
-#else /* not ARM */
-         /* In Motorola extended precision format, the most significant
-            bit of an infinity mantissa could be either 1 or 0.  It is
-            the lower order bits that tell whether the value is a NaN.  */
-         if ((pe[2] & 0x7fff) != 0)
-           goto bigend_nan;
-
-         for (i = 3; i <= 5; i++)
-           {
-             if (pe[i] != 0)
-               {
-bigend_nan:
-                 enan (y, (*p & 0x8000) != 0);
-                 return;
-               }
-           }
-#endif /* not ARM */
-       }
-#endif /* NANS */
-      eclear (y);
-      einfin (y);
-      if (*p & 0x8000)
-       eneg (y);
-      return;
-    }
-#endif  /* INFINITY */
-  p = yy;
-  q = y;
-  for (i = 0; i < NE; i++)
-    *q++ = *p++;
-}
+    rr = r;
 
-/* Convert 128-bit long double precision float PE to e type Y.  */
+  for (i = 0; exp > 0; ++i, exp >>= 1)
+    if (exp & 1)
+      do_multiply (rr, rr, ten_to_ptwo (i));
 
-static void
-e113toe (pe, y)
-     unsigned EMUSHORT *pe, *y;
-{
-  register unsigned EMUSHORT r;
-  unsigned EMUSHORT *e, *p;
-  unsigned EMUSHORT yy[NI];
-  int denorm, i;
-
-  e = pe;
-  denorm = 0;
-  ecleaz (yy);
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    e += 7;
-#endif
-  r = *e;
-  yy[0] = 0;
-  if (r & 0x8000)
-    yy[0] = 0xffff;
-  r &= 0x7fff;
-#ifdef INFINITY
-  if (r == 0x7fff)
-    {
-#ifdef NANS
-      if (! REAL_WORDS_BIG_ENDIAN)
-       {
-         for (i = 0; i < 7; i++)
-           {
-             if (pe[i] != 0)
-               {
-                 enan (y, yy[0] != 0);
-                 return;
-               }
-           }
-       }
-      else
-       {
-         for (i = 1; i < 8; i++)
-           {
-             if (pe[i] != 0)
-               {
-                 enan (y, yy[0] != 0);
-                 return;
-               }
-           }
-       }
-#endif /* NANS */
-      eclear (y);
-      einfin (y);
-      if (yy[0])
-       eneg (y);
-      return;
-    }
-#endif  /* INFINITY */
-  yy[E] = r;
-  p = &yy[M + 1];
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    {
-      for (i = 0; i < 7; i++)
-       *p++ = *(--e);
-    }
-  else
-    {
-      ++e;
-      for (i = 0; i < 7; i++)
-       *p++ = *e++;
-    }
-#endif
-/* If denormal, remove the implied bit; else shift down 1.  */
-  if (r == 0)
-    {
-      yy[M] = 0;
-    }
-  else
-    {
-      yy[M] = 1;
-      eshift (yy, -1);
-    }
-  emovo (yy, y);
+  if (negative)
+    do_divide (r, r, &pten);
 }
 
-/* Convert single precision float PE to e type Y.  */
-
-static void
-e24toe (pe, y)
-     unsigned EMUSHORT *pe, *y;
-{
-#ifdef IBM
-
-  ibmtoe (pe, y, SFmode);
+/* Fills R with +Inf.  */
 
-#else
-
-#ifdef C4X
-
-  c4xtoe (pe, y, QFmode);
-
-#else
-
-  register unsigned EMUSHORT r;
-  register unsigned EMUSHORT *e, *p;
-  unsigned EMUSHORT yy[NI];
-  int denorm, k;
-
-  e = pe;
-  denorm = 0;                  /* flag if denormalized number */
-  ecleaz (yy);
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    e += 1;
-#endif
-#ifdef DEC
-  e += 1;
-#endif
-  r = *e;
-  yy[0] = 0;
-  if (r & 0x8000)
-    yy[0] = 0xffff;
-  yy[M] = (r & 0x7f) | 0200;
-  r &= ~0x807f;                        /* strip sign and 7 significand bits */
-#ifdef INFINITY
-  if (r == 0x7f80)
-    {
-#ifdef NANS
-      if (REAL_WORDS_BIG_ENDIAN)
-       {
-         if (((pe[0] & 0x7f) != 0) || (pe[1] != 0))
-           {
-             enan (y, yy[0] != 0);
-             return;
-           }
-       }
-      else
-       {
-         if (((pe[1] & 0x7f) != 0) || (pe[0] != 0))
-           {
-             enan (y, yy[0] != 0);
-             return;
-           }
-       }
-#endif  /* NANS */
-      eclear (y);
-      einfin (y);
-      if (yy[0])
-       eneg (y);
-      return;
-    }
-#endif  /* INFINITY */
-  r >>= 7;
-  /* If zero exponent, then the significand is denormalized.
-     So take back the understood high significand bit.  */
-  if (r == 0)
-    {
-      denorm = 1;
-      yy[M] &= ~0200;
-    }
-  r += EXONE - 0177;
-  yy[E] = r;
-  p = &yy[M + 1];
-#ifdef DEC
-  *p++ = *(--e);
-#endif
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    *p++ = *(--e);
-  else
-    {
-      ++e;
-      *p++ = *e++;
-    }
-#endif
-  eshift (yy, -8);
-  if (denorm)
-    {                          /* if zero exponent, then normalize the significand */
-      if ((k = enormlz (yy)) > NBITS)
-       ecleazs (yy);
-      else
-       yy[E] -= (unsigned EMUSHORT) (k - 1);
-    }
-  emovo (yy, y);
-#endif /* not C4X */
-#endif /* not IBM */
-}
-
-/* Convert e-type X to IEEE 128-bit long double format E.  */
-
-static void
-etoe113 (x, e)
-     unsigned EMUSHORT *x, *e;
-{
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
-
-#ifdef NANS
-  if (eisnan (x))
-    {
-      make_nan (e, eisneg (x), TFmode);
-      return;
-    }
-#endif
-  emovi (x, xi);
-  exp = (EMULONG) xi[E];
-#ifdef INFINITY
-  if (eisinf (x))
-    goto nonorm;
-#endif
-  /* round off to nearest or even */
-  rndsav = rndprc;
-  rndprc = 113;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-#ifdef INFINITY
- nonorm:
-#endif
-  toe113 (xi, e);
-}
-
-/* Convert exploded e-type X, that has already been rounded to
-   113-bit precision, to IEEE 128-bit long double format Y.  */
-
-static void
-toe113 (a, b)
-     unsigned EMUSHORT *a, *b;
-{
-  register unsigned EMUSHORT *p, *q;
-  unsigned EMUSHORT i;
-
-#ifdef NANS
-  if (eiisnan (a))
-    {
-      make_nan (b, eiisneg (a), TFmode);
-      return;
-    }
-#endif
-  p = a;
-  if (REAL_WORDS_BIG_ENDIAN)
-    q = b;
-  else
-    q = b + 7;                 /* point to output exponent */
-
-  /* If not denormal, delete the implied bit.  */
-  if (a[E] != 0)
-    {
-      eshup1 (a);
-    }
-  /* combine sign and exponent */
-  i = *p++;
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      if (i)
-       *q++ = *p++ | 0x8000;
-      else
-       *q++ = *p++;
-    }
-  else
-    {
-      if (i)
-       *q-- = *p++ | 0x8000;
-      else
-       *q-- = *p++;
-    }
-  /* skip over guard word */
-  ++p;
-  /* move the significand */
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      for (i = 0; i < 7; i++)
-       *q++ = *p++;
-    }
-  else
-    {
-      for (i = 0; i < 7; i++)
-       *q-- = *p++;
-    }
-}
-
-/* Convert e-type X to IEEE double extended format E.  */
-
-static void
-etoe64 (x, e)
-     unsigned EMUSHORT *x, *e;
+void
+real_inf (r)
+     REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
-
-#ifdef NANS
-  if (eisnan (x))
-    {
-      make_nan (e, eisneg (x), XFmode);
-      return;
-    }
-#endif
-  emovi (x, xi);
-  /* adjust exponent for offset */
-  exp = (EMULONG) xi[E];
-#ifdef INFINITY
-  if (eisinf (x))
-    goto nonorm;
-#endif
-  /* round off to nearest or even */
-  rndsav = rndprc;
-  rndprc = 64;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-#ifdef INFINITY
- nonorm:
-#endif
-  toe64 (xi, e);
+  get_inf (r, 0);
 }
 
-/* Convert exploded e-type X, that has already been rounded to
-   64-bit precision, to IEEE double extended format Y.  */
+/* Fills R with a NaN whose significand is described by STR.  If QUIET,
+   we force a QNaN, else we force an SNaN.  The string, if not empty,
+   is parsed as a number and placed in the significand.  Return true
+   if the string was successfully parsed.  */
 
-static void
-toe64 (a, b)
-     unsigned EMUSHORT *a, *b;
-{
-  register unsigned EMUSHORT *p, *q;
-  unsigned EMUSHORT i;
-
-#ifdef NANS
-  if (eiisnan (a))
-    {
-      make_nan (b, eiisneg (a), XFmode);
-      return;
-    }
-#endif
-  /* Shift denormal long double Intel format significand down one bit.  */
-  if ((a[E] == 0) && ! REAL_WORDS_BIG_ENDIAN)
-    eshdn1 (a);
-  p = a;
-#ifdef IBM
-  q = b;
-#endif
-#ifdef DEC
-  q = b + 4;
-#endif
-#ifdef IEEE
-  if (REAL_WORDS_BIG_ENDIAN)
-    q = b;
-  else
-    {
-      q = b + 4;                       /* point to output exponent */
-#if LONG_DOUBLE_TYPE_SIZE == 96
-      /* Clear the last two bytes of 12-byte Intel format */
-      *(q+1) = 0;
-#endif
-    }
-#endif
-
-  /* combine sign and exponent */
-  i = *p++;
-#ifdef IBM
-  if (i)
-    *q++ = *p++ | 0x8000;
-  else
-    *q++ = *p++;
-  *q++ = 0;
-#endif
-#ifdef DEC
-  if (i)
-    *q-- = *p++ | 0x8000;
-  else
-    *q-- = *p++;
-#endif
-#ifdef IEEE
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-#ifdef ARM_EXTENDED_IEEE_FORMAT
-      /* The exponent is in the lowest 15 bits of the first word.  */
-      *q++ = i ? 0x8000 : 0;
-      *q++ = *p++;
-#else
-      if (i)
-       *q++ = *p++ | 0x8000;
-      else
-       *q++ = *p++;
-      *q++ = 0;
-#endif
-    }
-  else
+bool
+real_nan (r, str, quiet, mode)
+     REAL_VALUE_TYPE *r;
+     const char *str;
+     int quiet;
+     enum machine_mode mode;
+{
+  const struct real_format *fmt;
+
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
+
+  if (*str == 0)
     {
-      if (i)
-       *q-- = *p++ | 0x8000;
+      if (quiet)
+       get_canonical_qnan (r, 0);
       else
-       *q-- = *p++;
-    }
-#endif
-  /* skip over guard word */
-  ++p;
-  /* move the significand */
-#ifdef IBM
-  for (i = 0; i < 4; i++)
-    *q++ = *p++;
-#endif
-#ifdef DEC
-  for (i = 0; i < 4; i++)
-    *q-- = *p++;
-#endif
-#ifdef IEEE
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      for (i = 0; i < 4; i++)
-       *q++ = *p++;
+       get_canonical_snan (r, 0);
     }
   else
     {
-#ifdef INFINITY
-      if (eiisinf (a))
+      int base = 10, d;
+      bool neg = false;
+
+      memset (r, 0, sizeof (*r));
+      r->class = rvc_nan;
+
+      /* Parse akin to strtol into the significand of R.  */
+
+      while (ISSPACE (*str))
+       str++;
+      if (*str == '-')
+       str++, neg = true;
+      else if (*str == '+')
+       str++;
+      if (*str == '0')
        {
-         /* Intel long double infinity significand.  */
-         *q-- = 0x8000;
-         *q-- = 0;
-         *q-- = 0;
-         *q = 0;
-         return;
+         if (*++str == 'x')
+           str++, base = 16;
+         else
+           base = 8;
        }
-#endif
-      for (i = 0; i < 4; i++)
-       *q-- = *p++;
-    }
-#endif
-}
 
-/* e type to double precision.  */
+      while ((d = hex_value (*str)) < base)
+       {
+         REAL_VALUE_TYPE u;
 
-#ifdef DEC
-/* Convert e-type X to DEC-format double E.  */
+         switch (base)
+           {
+           case 8:
+             lshift_significand (r, r, 3);
+             break;
+           case 16:
+             lshift_significand (r, r, 4);
+             break;
+           case 10:
+             lshift_significand_1 (&u, r);
+             lshift_significand (r, r, 3);
+             add_significands (r, r, &u);
+             break;
+           default:
+             abort ();
+           }
 
-static void
-etoe53 (x, e)
-     unsigned EMUSHORT *x, *e;
-{
-  etodec (x, e);               /* see etodec.c */
-}
+         get_zero (&u, 0);
+         u.sig[0] = d;
+         add_significands (r, r, &u);
 
-/* Convert exploded e-type X, that has already been rounded to
-   56-bit double precision, to DEC double Y.  */
+         str++;
+       }
 
-static void
-toe53 (x, y)
-     unsigned EMUSHORT *x, *y;
-{
-  todec (x, y);
-}
+      /* Must have consumed the entire string for success.  */
+      if (*str != 0)
+       return false;
 
-#else
-#ifdef IBM
-/* Convert e-type X to IBM 370-format double E.  */
+      /* Shift the significand into place such that the bits
+        are in the most significant bits for the format.  */
+      lshift_significand (r, r, SIGNIFICAND_BITS - fmt->pnan);
 
-static void
-etoe53 (x, e)
-     unsigned EMUSHORT *x, *e;
-{
-  etoibm (x, e, DFmode);
-}
+      /* Our MSB is always unset for NaNs.  */
+      r->sig[SIGSZ-1] &= ~SIG_MSB;
 
-/* Convert exploded e-type X, that has already been rounded to
-   56-bit precision, to IBM 370 double Y.  */
+      /* Force quiet or signalling NaN.  */
+      r->signalling = !quiet;
+    }
 
-static void
-toe53 (x, y)
-     unsigned EMUSHORT *x, *y;
-{
-  toibm (x, y, DFmode);
+  return true;
 }
 
-#else /* it's neither DEC nor IBM */
-#ifdef C4X
-/* Convert e-type X to C4X-format long double E.  */
+/* Fills R with the largest finite value representable in mode MODE.
+   If SIGN is nonzero, R is set to the most negative finite value.  */
 
-static void
-etoe53 (x, e)
-     unsigned EMUSHORT *x, *e;
+void
+real_maxval (r, sign, mode)
+     REAL_VALUE_TYPE *r;
+     int sign;
+     enum machine_mode mode;
 {
-  etoc4x (x, e, HFmode);
-}
+  const struct real_format *fmt;
+  int np2;
 
-/* Convert exploded e-type X, that has already been rounded to
-   56-bit precision, to IBM 370 double Y.  */
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
 
-static void
-toe53 (x, y)
-     unsigned EMUSHORT *x, *y;
-{
-  toc4x (x, y, HFmode);
-}
+  r->class = rvc_normal;
+  r->sign = sign;
+  r->signalling = 0;
+  r->canonical = 0;
+  r->exp = fmt->emax * fmt->log2_b;
 
-#else  /* it's neither DEC nor IBM nor C4X */
+  np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+  memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+  clear_significand_below (r, np2);
+}
 
-/* Convert e-type X to IEEE double E.  */
+/* Fills R with 2**N.  */
 
-static void
-etoe53 (x, e)
-     unsigned EMUSHORT *x, *e;
+void
+real_2expN (r, n)
+     REAL_VALUE_TYPE *r;
+     int n;
 {
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
+  memset (r, 0, sizeof (*r));
 
-#ifdef NANS
-  if (eisnan (x))
+  n++;
+  if (n > MAX_EXP)
+    r->class = rvc_inf;
+  else if (n < -MAX_EXP)
+    ;
+  else
     {
-      make_nan (e, eisneg (x), DFmode);
-      return;
+      r->class = rvc_normal;
+      r->exp = n;
+      r->sig[SIGSZ-1] = SIG_MSB;
     }
-#endif
-  emovi (x, xi);
-  /* adjust exponent for offsets */
-  exp = (EMULONG) xi[E] - (EXONE - 0x3ff);
-#ifdef INFINITY
-  if (eisinf (x))
-    goto nonorm;
-#endif
-  /* round off to nearest or even */
-  rndsav = rndprc;
-  rndprc = 53;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-#ifdef INFINITY
- nonorm:
-#endif
-  toe53 (xi, e);
 }
 
-/* Convert exploded e-type X, that has already been rounded to
-   53-bit precision, to IEEE double Y.  */
-
+\f
 static void
-toe53 (x, y)
-     unsigned EMUSHORT *x, *y;
+round_for_format (fmt, r)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT i;
-  unsigned EMUSHORT *p;
+  int p2, np2, i, w;
+  unsigned long sticky;
+  bool guard, lsb;
+  int emin2m1, emax2;
 
-#ifdef NANS
-  if (eiisnan (x))
+  p2 = fmt->p * fmt->log2_b;
+  emin2m1 = (fmt->emin - 1) * fmt->log2_b;
+  emax2 = fmt->emax * fmt->log2_b;
+
+  np2 = SIGNIFICAND_BITS - p2;
+  switch (r->class)
     {
-      make_nan (y, eiisneg (x), DFmode);
+    underflow:
+      get_zero (r, r->sign);
+    case rvc_zero:
+      if (!fmt->has_signed_zero)
+       r->sign = 0;
+      return;
+
+    overflow:
+      get_inf (r, r->sign);
+    case rvc_inf:
+      return;
+
+    case rvc_nan:
+      clear_significand_below (r, np2);
       return;
+
+    case rvc_normal:
+      break;
+
+    default:
+      abort ();
     }
-#endif
-  p = &x[0];
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    y += 3;
-#endif
-  *y = 0;                      /* output high order */
-  if (*p++)
-    *y = 0x8000;               /* output sign bit */
 
-  i = *p++;
-  if (i >= (unsigned int) 2047)
+  /* If we're not base2, normalize the exponent to a multiple of
+     the true base.  */
+  if (fmt->log2_b != 1)
     {
-      /* Saturate at largest number less than infinity.  */
-#ifdef INFINITY
-      *y |= 0x7ff0;
-      if (! REAL_WORDS_BIG_ENDIAN)
-       {
-         *(--y) = 0;
-         *(--y) = 0;
-         *(--y) = 0;
-       }
-      else
+      int shift = r->exp & (fmt->log2_b - 1);
+      if (shift)
        {
-         ++y;
-         *y++ = 0;
-         *y++ = 0;
-         *y++ = 0;
+         shift = fmt->log2_b - shift;
+         r->sig[0] |= sticky_rshift_significand (r, r, shift);
+         r->exp += shift;
        }
-#else
-      *y |= (unsigned EMUSHORT) 0x7fef;
-      if (! REAL_WORDS_BIG_ENDIAN)
+    }
+
+  /* Check the range of the exponent.  If we're out of range,
+     either underflow or overflow.  */
+  if (r->exp > emax2)
+    goto overflow;
+  else if (r->exp <= emin2m1)
+    {
+      int diff;
+
+      if (!fmt->has_denorm)
        {
-         *(--y) = 0xffff;
-         *(--y) = 0xffff;
-         *(--y) = 0xffff;
+         /* Don't underflow completely until we've had a chance to round.  */
+         if (r->exp < emin2m1)
+           goto underflow;
        }
       else
        {
-         ++y;
-         *y++ = 0xffff;
-         *y++ = 0xffff;
-         *y++ = 0xffff;
+         diff = emin2m1 - r->exp + 1;
+         if (diff > p2)
+           goto underflow;
+
+         /* De-normalize the significand.  */
+         r->sig[0] |= sticky_rshift_significand (r, r, diff);
+         r->exp += diff;
        }
-#endif
-      return;
-    }
-  if (i == 0)
-    {
-      eshift (x, 4);
-    }
-  else
-    {
-      i <<= 4;
-      eshift (x, 5);
-    }
-  i |= *p++ & (unsigned EMUSHORT) 0x0f;        /* *p = xi[M] */
-  *y |= (unsigned EMUSHORT) i; /* high order output already has sign bit set */
-  if (! REAL_WORDS_BIG_ENDIAN)
-    {
-      *(--y) = *p++;
-      *(--y) = *p++;
-      *(--y) = *p;
-    }
-  else
-    {
-      ++y;
-      *y++ = *p++;
-      *y++ = *p++;
-      *y++ = *p++;
     }
-}
 
-#endif /* not C4X */
-#endif /* not IBM */
-#endif /* not DEC */
+  /* 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.  */
+
+  sticky = 0;
+  for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
+    sticky |= r->sig[i];
+  sticky |=
+    r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
 
+  guard = test_significand_bit (r, np2 - 1);
+  lsb = test_significand_bit (r, np2);
 
+  /* Round to even.  */
+  if (guard && (sticky || lsb))
+    {
+      REAL_VALUE_TYPE u;
+      get_zero (&u, 0);
+      set_significand_bit (&u, np2);
 
-/* e type to single precision.  */
+      if (add_significands (r, r, &u))
+       {
+         /* Overflow.  Means the significand had been all ones, and
+            is now all zeros.  Need to increase the exponent, and
+            possibly re-normalize it.  */
+         if (++r->exp > emax2)
+           goto overflow;
+         r->sig[SIGSZ-1] = SIG_MSB;
+
+         if (fmt->log2_b != 1)
+           {
+             int shift = r->exp & (fmt->log2_b - 1);
+             if (shift)
+               {
+                 shift = fmt->log2_b - shift;
+                 rshift_significand (r, r, shift);
+                 r->exp += shift;
+                 if (r->exp > emax2)
+                   goto overflow;
+               }
+           }
+       }
+    }
 
-#ifdef IBM
-/* Convert e-type X to IBM 370 float E.  */
+  /* Catch underflow that we deferred until after rounding.  */
+  if (r->exp <= emin2m1)
+    goto underflow;
 
-static void
-etoe24 (x, e)
-     unsigned EMUSHORT *x, *e;
-{
-  etoibm (x, e, SFmode);
+  /* Clear out trailing garbage.  */
+  clear_significand_below (r, np2);
 }
 
-/* Convert exploded e-type X, that has already been rounded to
-   float precision, to IBM 370 float Y.  */
+/* Extend or truncate to a new mode.  */
 
-static void
-toe24 (x, y)
-     unsigned EMUSHORT *x, *y;
+void
+real_convert (r, mode, a)
+     REAL_VALUE_TYPE *r;
+     enum machine_mode mode;
+     const REAL_VALUE_TYPE *a;
 {
-  toibm (x, y, SFmode);
-}
+  const struct real_format *fmt;
+
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
+
+  *r = *a;
+  round_for_format (fmt, r);
 
-#else
+  /* round_for_format de-normalizes denormals.  Undo just that part.  */
+  if (r->class == rvc_normal)
+    normalize (r);
+}
 
-#ifdef C4X
-/* Convert e-type X to C4X float E.  */
+/* Legacy.  Likewise, except return the struct directly.  */
 
-static void
-etoe24 (x, e)
-     unsigned EMUSHORT *x, *e;
+REAL_VALUE_TYPE
+real_value_truncate (mode, a)
+     enum machine_mode mode;
+     REAL_VALUE_TYPE a;
 {
-  etoc4x (x, e, QFmode);
+  REAL_VALUE_TYPE r;
+  real_convert (&r, mode, &a);
+  return r;
 }
 
-/* Convert exploded e-type X, that has already been rounded to
-   float precision, to IBM 370 float Y.  */
+/* Return true if truncating to MODE is exact.  */
 
-static void
-toe24 (x, y)
-     unsigned EMUSHORT *x, *y;
+bool
+exact_real_truncate (mode, a)
+     enum machine_mode mode;
+     const REAL_VALUE_TYPE *a;
 {
-  toc4x (x, y, QFmode);
+  REAL_VALUE_TYPE t;
+  real_convert (&t, mode, a);
+  return real_identical (&t, a);
 }
 
-#else
+/* 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.
 
-/* Convert e-type X to IEEE float E.  DEC float is the same as IEEE float.  */
+   Legacy: return word 0 for implementing REAL_VALUE_TO_TARGET_SINGLE.  */
 
-static void
-etoe24 (x, e)
-     unsigned EMUSHORT *x, *e;
+long
+real_to_target_fmt (buf, r_orig, fmt)
+     long *buf;
+     const REAL_VALUE_TYPE *r_orig;
+     const struct real_format *fmt;
 {
-  EMULONG exp;
-  unsigned EMUSHORT xi[NI];
-  int rndsav;
+  REAL_VALUE_TYPE r;
+  long buf1;
 
-#ifdef NANS
-  if (eisnan (x))
-    {
-      make_nan (e, eisneg (x), SFmode);
-      return;
-    }
-#endif
-  emovi (x, xi);
-  /* adjust exponent for offsets */
-  exp = (EMULONG) xi[E] - (EXONE - 0177);
-#ifdef INFINITY
-  if (eisinf (x))
-    goto nonorm;
-#endif
-  /* round off to nearest or even */
-  rndsav = rndprc;
-  rndprc = 24;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-#ifdef INFINITY
- nonorm:
-#endif
-  toe24 (xi, e);
+  r = *r_orig;
+  round_for_format (fmt, &r);
+
+  if (!buf)
+    buf = &buf1;
+  (*fmt->encode) (fmt, buf, &r);
+
+  return *buf;
 }
 
-/* Convert exploded e-type X, that has already been rounded to
-   float precision, to IEEE float Y.  */
+/* Similar, but look up the format from MODE.  */
 
-static void
-toe24 (x, y)
-     unsigned EMUSHORT *x, *y;
+long
+real_to_target (buf, r, mode)
+     long *buf;
+     const REAL_VALUE_TYPE *r;
+     enum machine_mode mode;
 {
-  unsigned EMUSHORT i;
-  unsigned EMUSHORT *p;
+  const struct real_format *fmt;
 
-#ifdef NANS
-  if (eiisnan (x))
-    {
-      make_nan (y, eiisneg (x), SFmode);
-      return;
-    }
-#endif
-  p = &x[0];
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    y += 1;
-#endif
-#ifdef DEC
-  y += 1;
-#endif
-  *y = 0;                      /* output high order */
-  if (*p++)
-    *y = 0x8000;               /* output sign bit */
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
 
-  i = *p++;
-/* Handle overflow cases.  */
-  if (i >= 255)
-    {
-#ifdef INFINITY
-      *y |= (unsigned EMUSHORT) 0x7f80;
-#ifdef DEC
-      *(--y) = 0;
-#endif
-#ifdef IEEE
-      if (! REAL_WORDS_BIG_ENDIAN)
-       *(--y) = 0;
-      else
-       {
-         ++y;
-         *y = 0;
-       }
-#endif
-#else  /* no INFINITY */
-      *y |= (unsigned EMUSHORT) 0x7f7f;
-#ifdef DEC
-      *(--y) = 0xffff;
-#endif
-#ifdef IEEE
-      if (! REAL_WORDS_BIG_ENDIAN)
-       *(--y) = 0xffff;
-      else
-       {
-         ++y;
-         *y = 0xffff;
-       }
-#endif
-#ifdef ERANGE
-      errno = ERANGE;
-#endif
-#endif  /* no INFINITY */
-      return;
-    }
-  if (i == 0)
-    {
-      eshift (x, 7);
-    }
-  else
-    {
-      i <<= 7;
-      eshift (x, 8);
-    }
-  i |= *p++ & (unsigned EMUSHORT) 0x7f;        /* *p = xi[M] */
-  /* High order output already has sign bit set.  */
-  *y |= i;
-#ifdef DEC
-  *(--y) = *p;
-#endif
-#ifdef IEEE
-  if (! REAL_WORDS_BIG_ENDIAN)
-    *(--y) = *p;
-  else
-    {
-      ++y;
-      *y = *p;
-    }
-#endif
+  return real_to_target_fmt (buf, r, fmt);
 }
-#endif  /* not C4X */
-#endif  /* not IBM */
 
-/* Compare two e type numbers.
-   Return +1 if a > b
-           0 if a == b
-          -1 if a < b
-          -2 if either a or b is a NaN.  */
+/* 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.  */
 
-static int
-ecmp (a, b)
-     unsigned EMUSHORT *a, *b;
+void
+real_from_target_fmt (r, buf, fmt)
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+     const struct real_format *fmt;
 {
-  unsigned EMUSHORT ai[NI], bi[NI];
-  register unsigned EMUSHORT *p, *q;
-  register int i;
-  int msign;
-
-#ifdef NANS
-  if (eisnan (a)  || eisnan (b))
-      return (-2);
-#endif
-  emovi (a, ai);
-  p = ai;
-  emovi (b, bi);
-  q = bi;
-
-  if (*p != *q)
-    {                          /* the signs are different */
-      /* -0 equals + 0 */
-      for (i = 1; i < NI - 1; i++)
-       {
-         if (ai[i] != 0)
-           goto nzro;
-         if (bi[i] != 0)
-           goto nzro;
-       }
-      return (0);
-    nzro:
-      if (*p == 0)
-       return (1);
-      else
-       return (-1);
-    }
-  /* both are the same sign */
-  if (*p == 0)
-    msign = 1;
-  else
-    msign = -1;
-  i = NI - 1;
-  do
-    {
-      if (*p++ != *q++)
-       {
-         goto diff;
-       }
-    }
-  while (--i > 0);
+  (*fmt->decode) (fmt, r, buf);
+}     
+
+/* Similar, but look up the format from MODE.  */
 
-  return (0);                  /* equality */
+void
+real_from_target (r, buf, mode)
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+     enum machine_mode mode;
+{
+  const struct real_format *fmt;
 
- diff:
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    abort ();
 
-  if (*(--p) > *(--q))
-    return (msign);            /* p is bigger */
-  else
-    return (-msign);           /* p is littler */
-}
+  (*fmt->decode) (fmt, r, buf);
+}     
 
-#if 0
-/* Find e-type nearest integer to X, as floor (X + 0.5).  */
+/* Return the number of bits in the significand for MODE.  */
+/* ??? Legacy.  Should get access to real_format directly.  */
 
-static void
-eround (x, y)
-     unsigned EMUSHORT *x, *y;
+int
+significand_size (mode)
+     enum machine_mode mode;
 {
-  eadd (ehalf, x, y);
-  efloor (y, y);
+  const struct real_format *fmt;
+
+  fmt = real_format_for_mode[mode - QFmode];
+  if (fmt == NULL)
+    return 0;
+
+  return fmt->p * fmt->log2_b;
 }
-#endif /* 0 */
 
-/* Convert HOST_WIDE_INT LP to e type Y.  */
+/* 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.  */
 
-static void
-ltoe (lp, y)
-     HOST_WIDE_INT *lp;
-     unsigned EMUSHORT *y;
+unsigned int
+real_hash (r)
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT yi[NI];
-  unsigned HOST_WIDE_INT ll;
-  int k;
+  unsigned int h;
+  size_t i;
 
-  ecleaz (yi);
-  if (*lp < 0)
-    {
-      /* make it positive */
-      ll = (unsigned HOST_WIDE_INT) (-(*lp));
-      yi[0] = 0xffff;          /* put correct sign in the e type number */
-    }
-  else
+  h = r->class | (r->sign << 2);
+  switch (r->class)
     {
-      ll = (unsigned HOST_WIDE_INT) (*lp);
-    }
-  /* move the long integer to yi significand area */
-#if HOST_BITS_PER_WIDE_INT == 64
-  yi[M] = (unsigned EMUSHORT) (ll >> 48);
-  yi[M + 1] = (unsigned EMUSHORT) (ll >> 32);
-  yi[M + 2] = (unsigned EMUSHORT) (ll >> 16);
-  yi[M + 3] = (unsigned EMUSHORT) ll;
-  yi[E] = EXONE + 47;          /* exponent if normalize shift count were 0 */
-#else
-  yi[M] = (unsigned EMUSHORT) (ll >> 16);
-  yi[M + 1] = (unsigned EMUSHORT) ll;
-  yi[E] = EXONE + 15;          /* exponent if normalize shift count were 0 */
-#endif
+    case rvc_zero:
+    case rvc_inf:
+      return h;
 
-  if ((k = enormlz (yi)) > NBITS)/* normalize the significand */
-    ecleaz (yi);               /* it was zero */
-  else
-    yi[E] -= (unsigned EMUSHORT) k;/* subtract shift count from exponent */
-  emovo (yi, y);               /* output the answer */
-}
+    case rvc_normal:
+      h |= r->exp << 3;
+      break;
 
-/* Convert unsigned HOST_WIDE_INT LP to e type Y.  */
+    case rvc_nan:
+      if (r->signalling)
+       h ^= (unsigned int)-1;
+      if (r->canonical)
+       return h;
+      break;
 
-static void
-ultoe (lp, y)
-     unsigned HOST_WIDE_INT *lp;
-     unsigned EMUSHORT *y;
-{
-  unsigned EMUSHORT yi[NI];
-  unsigned HOST_WIDE_INT ll;
-  int k;
-
-  ecleaz (yi);
-  ll = *lp;
-
-  /* move the long integer to ayi significand area */
-#if HOST_BITS_PER_WIDE_INT == 64
-  yi[M] = (unsigned EMUSHORT) (ll >> 48);
-  yi[M + 1] = (unsigned EMUSHORT) (ll >> 32);
-  yi[M + 2] = (unsigned EMUSHORT) (ll >> 16);
-  yi[M + 3] = (unsigned EMUSHORT) ll;
-  yi[E] = EXONE + 47;          /* exponent if normalize shift count were 0 */
-#else
-  yi[M] = (unsigned EMUSHORT) (ll >> 16);
-  yi[M + 1] = (unsigned EMUSHORT) ll;
-  yi[E] = EXONE + 15;          /* exponent if normalize shift count were 0 */
-#endif
+    default:
+      abort ();
+    }
 
-  if ((k = enormlz (yi)) > NBITS)/* normalize the significand */
-    ecleaz (yi);               /* it was zero */
+  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
-    yi[E] -= (unsigned EMUSHORT) k;  /* subtract shift count from exponent */
-  emovo (yi, y);               /* output the answer */
-}
+    for (i = 0; i < SIGSZ; ++i)
+      h ^= r->sig[i];
 
+  return h;
+}
+\f
+/* IEEE single-precision format.  */
 
-/* Find signed HOST_WIDE_INT integer I and floating point fractional
-   part FRAC of e-type (packed internal format) floating point input X.
-   The integer output I has the sign of the input, except that
-   positive overflow is permitted if FIXUNS_TRUNC_LIKE_FIX_TRUNC.
-   The output e-type fraction FRAC is the positive fractional
-   part of abs (X).  */
+static void encode_ieee_single PARAMS ((const struct real_format *fmt,
+                                       long *, const REAL_VALUE_TYPE *));
+static void decode_ieee_single PARAMS ((const struct real_format *,
+                                       REAL_VALUE_TYPE *, const long *));
 
 static void
-eifrac (x, i, frac)
-     unsigned EMUSHORT *x;
-     HOST_WIDE_INT *i;
-     unsigned EMUSHORT *frac;
+encode_ieee_single (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT xi[NI];
-  int j, k;
-  unsigned HOST_WIDE_INT ll;
+  unsigned long image, sig, exp;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
 
-  emovi (x, xi);
-  k = (int) xi[E] - (EXONE - 1);
-  if (k <= 0)
-    {
-      /* if exponent <= 0, integer = 0 and real output is fraction */
-      *i = 0L;
-      emovo (xi, frac);
-      return;
-    }
-  if (k > (HOST_BITS_PER_WIDE_INT - 1))
+  image = r->sign << 31;
+  sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
+
+  switch (r->class)
     {
-      /* long integer overflow: output large integer
-        and correct fraction  */
-      if (xi[0])
-       *i = ((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1);
+    case rvc_zero:
+      break;
+
+    case rvc_inf:
+      if (fmt->has_inf)
+       image |= 255 << 23;
       else
+       image |= 0x7fffffff;
+      break;
+
+    case rvc_nan:
+      if (fmt->has_nans)
        {
-#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
-         /* In this case, let it overflow and convert as if unsigned.  */
-         euifrac (x, &ll, frac);
-         *i = (HOST_WIDE_INT) ll;
-         return;
-#else
-         /* In other cases, return the largest positive integer.  */
-         *i = (((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1)) - 1;
-#endif
-       }
-      eshift (xi, k);
-      if (extra_warnings)
-       warning ("overflow on truncation to integer");
-    }
-  else if (k > 16)
-    {
-      /* Shift more than 16 bits: first shift up k-16 mod 16,
-        then shift up by 16's.  */
-      j = k - ((k >> 4) << 4);
-      eshift (xi, j);
-      ll = xi[M];
-      k -= j;
-      do
-       {
-         eshup6 (xi);
-         ll = (ll << 16) | xi[M];
+         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;
        }
-      while ((k -= 16) > 0);
-      *i = ll;
-      if (xi[0])
-       *i = -(*i);
-    }
-  else
-      {
-        /* shift not more than 16 bits */
-          eshift (xi, k);
-        *i = (HOST_WIDE_INT) xi[M] & 0xffff;
-        if (xi[0])
-         *i = -(*i);
-      }
-  xi[0] = 0;
-  xi[E] = EXONE - 1;
-  xi[M] = 0;
-  if ((k = enormlz (xi)) > NBITS)
-    ecleaz (xi);
-  else
-    xi[E] -= (unsigned EMUSHORT) k;
+      else
+       image |= 0x7fffffff;
+      break;
 
-  emovo (xi, frac);
-}
+    case rvc_normal:
+      /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+        whereas the intermediate representation is 0.F x 2**exp.
+        Which means we're off by one.  */
+      if (denormal)
+       exp = 0;
+      else
+      exp = r->exp + 127 - 1;
+      image |= exp << 23;
+      image |= sig;
+      break;
 
+    default:
+      abort ();
+    }
 
-/* Find unsigned HOST_WIDE_INT integer I and floating point fractional part
-   FRAC of e-type X.  A negative input yields integer output = 0 but
-   correct fraction.  */
+  buf[0] = image;
+}
 
 static void
-euifrac (x, i, frac)
-     unsigned EMUSHORT *x;
-     unsigned HOST_WIDE_INT *i;
-     unsigned EMUSHORT *frac;
+decode_ieee_single (fmt, r, buf)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  unsigned HOST_WIDE_INT ll;
-  unsigned EMUSHORT xi[NI];
-  int j, k;
+  unsigned long image = buf[0] & 0xffffffff;
+  bool sign = (image >> 31) & 1;
+  int exp = (image >> 23) & 0xff;
 
-  emovi (x, xi);
-  k = (int) xi[E] - (EXONE - 1);
-  if (k <= 0)
-    {
-      /* if exponent <= 0, integer = 0 and argument is fraction */
-      *i = 0L;
-      emovo (xi, frac);
-      return;
-    }
-  if (k > HOST_BITS_PER_WIDE_INT)
+  memset (r, 0, sizeof (*r));
+  image <<= HOST_BITS_PER_LONG - 24;
+  image &= ~SIG_MSB;
+
+  if (exp == 0)
     {
-      /* Long integer overflow: output large integer
-        and correct fraction.
-        Note, the BSD microvax compiler says that ~(0UL)
-        is a syntax error.  */
-      *i = ~(0L);
-      eshift (xi, k);
-      if (extra_warnings)
-       warning ("overflow on truncation to unsigned integer");
+      if (image && fmt->has_denorm)
+       {
+         r->class = rvc_normal;
+         r->sign = sign;
+         r->exp = -126;
+         r->sig[SIGSZ-1] = image << 1;
+         normalize (r);
+       }
+      else if (fmt->has_signed_zero)
+       r->sign = sign;
     }
-  else if (k > 16)
+  else if (exp == 255 && (fmt->has_nans || fmt->has_inf))
     {
-      /* Shift more than 16 bits: first shift up k-16 mod 16,
-        then shift up by 16's.  */
-      j = k - ((k >> 4) << 4);
-      eshift (xi, j);
-      ll = xi[M];
-      k -= j;
-      do
+      if (image)
+       {
+         r->class = rvc_nan;
+         r->sign = sign;
+         r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+                          ^ fmt->qnan_msb_set);
+         r->sig[SIGSZ-1] = image;
+       }
+      else
        {
-         eshup6 (xi);
-         ll = (ll << 16) | xi[M];
+         r->class = rvc_inf;
+         r->sign = sign;
        }
-      while ((k -= 16) > 0);
-      *i = ll;
     }
   else
     {
-      /* shift not more than 16 bits */
-      eshift (xi, k);
-      *i = (HOST_WIDE_INT) xi[M] & 0xffff;
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = exp - 127 + 1;
+      r->sig[SIGSZ-1] = image | SIG_MSB;
     }
+}
 
-  if (xi[0])  /* A negative value yields unsigned integer 0.  */
-    *i = 0L;
-
-  xi[0] = 0;
-  xi[E] = EXONE - 1;
-  xi[M] = 0;
-  if ((k = enormlz (xi)) > NBITS)
-    ecleaz (xi);
-  else
-    xi[E] -= (unsigned EMUSHORT) k;
+const struct real_format ieee_single_format = 
+  {
+    encode_ieee_single,
+    decode_ieee_single,
+    2,
+    1,
+    24,
+    24,
+    -125,
+    128,
+    31,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
+
+const struct real_format mips_single_format = 
+  {
+    encode_ieee_single,
+    decode_ieee_single,
+    2,
+    1,
+    24,
+    24,
+    -125,
+    128,
+    31,
+    true,
+    true,
+    true,
+    true,
+    false
+  };
 
-  emovo (xi, frac);
-}
+\f
+/* IEEE double-precision format.  */
 
-/* Shift the significand of exploded e-type X up or down by SC bits.  */
+static void encode_ieee_double PARAMS ((const struct real_format *fmt,
+                                       long *, const REAL_VALUE_TYPE *));
+static void decode_ieee_double PARAMS ((const struct real_format *,
+                                       REAL_VALUE_TYPE *, const long *));
 
-static int
-eshift (x, sc)
-     unsigned EMUSHORT *x;
-     int sc;
+static void
+encode_ieee_double (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT lost;
-  unsigned EMUSHORT *p;
+  unsigned long image_lo, image_hi, sig_lo, sig_hi, exp;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
 
-  if (sc == 0)
-    return (0);
+  image_hi = r->sign << 31;
+  image_lo = 0;
 
-  lost = 0;
-  p = x + NI - 1;
+  if (HOST_BITS_PER_LONG == 64)
+    {
+      sig_hi = r->sig[SIGSZ-1];
+      sig_lo = (sig_hi >> (64 - 53)) & 0xffffffff;
+      sig_hi = (sig_hi >> (64 - 53 + 1) >> 31) & 0xfffff;
+    }
+  else
+    {
+      sig_hi = r->sig[SIGSZ-1];
+      sig_lo = r->sig[SIGSZ-2];
+      sig_lo = (sig_hi << 21) | (sig_lo >> 11);
+      sig_hi = (sig_hi >> 11) & 0xfffff;
+    }
 
-  if (sc < 0)
+  switch (r->class)
     {
-      sc = -sc;
-      while (sc >= 16)
-       {
-         lost |= *p;           /* remember lost bits */
-         eshdn6 (x);
-         sc -= 16;
-       }
+    case rvc_zero:
+      break;
 
-      while (sc >= 8)
+    case rvc_inf:
+      if (fmt->has_inf)
+       image_hi |= 2047 << 20;
+      else
        {
-         lost |= *p & 0xff;
-         eshdn8 (x);
-         sc -= 8;
+         image_hi |= 0x7fffffff;
+         image_lo = 0xffffffff;
        }
+      break;
 
-      while (sc > 0)
+    case rvc_nan:
+      if (fmt->has_nans)
        {
-         lost |= *p & 1;
-         eshdn1 (x);
-         sc -= 1;
+         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;
+         image_lo = sig_lo;
        }
-    }
-  else
-    {
-      while (sc >= 16)
+      else
        {
-         eshup6 (x);
-         sc -= 16;
+         image_hi |= 0x7fffffff;
+         image_lo = 0xffffffff;
        }
+      break;
 
-      while (sc >= 8)
-       {
-         eshup8 (x);
-         sc -= 8;
-       }
+    case rvc_normal:
+      /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+        whereas the intermediate representation is 0.F x 2**exp.
+        Which means we're off by one.  */
+      if (denormal)
+       exp = 0;
+      else
+       exp = r->exp + 1023 - 1;
+      image_hi |= exp << 20;
+      image_hi |= sig_hi;
+      image_lo = sig_lo;
+      break;
 
-      while (sc > 0)
-       {
-         eshup1 (x);
-         sc -= 1;
-       }
+    default:
+      abort ();
     }
-  if (lost)
-    lost = 1;
-  return ((int) lost);
-}
 
-/* Shift normalize the significand area of exploded e-type X.
-   Return the shift count (up = positive).  */
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = image_hi, buf[1] = image_lo;
+  else
+    buf[0] = image_lo, buf[1] = image_hi;
+}
 
-static int
-enormlz (x)
-     unsigned EMUSHORT x[];
+static void
+decode_ieee_double (fmt, r, buf)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  register unsigned EMUSHORT *p;
-  int sc;
-
-  sc = 0;
-  p = &x[M];
-  if (*p != 0)
-    goto normdn;
-  ++p;
-  if (*p & 0x8000)
-    return (0);                        /* already normalized */
-  while (*p == 0)
-    {
-      eshup6 (x);
-      sc += 16;
+  unsigned long image_hi, image_lo;
+  bool sign;
+  int exp;
 
-      /* With guard word, there are NBITS+16 bits available.
-       Return true if all are zero.  */
-      if (sc > NBITS)
-       return (sc);
-    }
-  /* see if high byte is zero */
-  while ((*p & 0xff00) == 0)
-    {
-      eshup8 (x);
-      sc += 8;
-    }
-  /* now shift 1 bit at a time */
-  while ((*p & 0x8000) == 0)
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    image_hi = buf[0], image_lo = buf[1];
+  else
+    image_lo = buf[0], image_hi = buf[1];
+  image_lo &= 0xffffffff;
+  image_hi &= 0xffffffff;
+
+  sign = (image_hi >> 31) & 1;
+  exp = (image_hi >> 20) & 0x7ff;
+
+  memset (r, 0, sizeof (*r));
+
+  image_hi <<= 32 - 21;
+  image_hi |= image_lo >> 21;
+  image_hi &= 0x7fffffff;
+  image_lo <<= 32 - 21;
+
+  if (exp == 0)
     {
-      eshup1 (x);
-      sc += 1;
-      if (sc > NBITS)
+      if ((image_hi || image_lo) && fmt->has_denorm)
        {
-         mtherr ("enormlz", UNDERFLOW);
-         return (sc);
+         r->class = rvc_normal;
+         r->sign = sign;
+         r->exp = -1022;
+         if (HOST_BITS_PER_LONG == 32)
+           {
+             image_hi = (image_hi << 1) | (image_lo >> 31);
+             image_lo <<= 1;
+             r->sig[SIGSZ-1] = image_hi;
+             r->sig[SIGSZ-2] = image_lo;
+           }
+         else
+           {
+             image_hi = (image_hi << 31 << 2) | (image_lo << 1);
+             r->sig[SIGSZ-1] = image_hi;
+           }
+         normalize (r);
        }
+      else if (fmt->has_signed_zero)
+       r->sign = sign;
     }
-  return (sc);
-
-  /* Normalize by shifting down out of the high guard word
-     of the significand */
- normdn:
-
-  if (*p & 0xff00)
+  else if (exp == 2047 && (fmt->has_nans || fmt->has_inf))
     {
-      eshdn8 (x);
-      sc -= 8;
+      if (image_hi || image_lo)
+       {
+         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;
+             r->sig[SIGSZ-2] = image_lo;
+           }
+         else
+           r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
+       }
+      else
+       {
+         r->class = rvc_inf;
+         r->sign = sign;
+       }
     }
-  while (*p != 0)
+  else
     {
-      eshdn1 (x);
-      sc -= 1;
-
-      if (sc < -NBITS)
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = exp - 1023 + 1;
+      if (HOST_BITS_PER_LONG == 32)
        {
-         mtherr ("enormlz", OVERFLOW);
-         return (sc);
+         r->sig[SIGSZ-1] = image_hi | SIG_MSB;
+         r->sig[SIGSZ-2] = image_lo;
        }
+      else
+       r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo | SIG_MSB;
     }
-  return (sc);
 }
 
-/* Powers of ten used in decimal <-> binary conversions.  */
+const struct real_format ieee_double_format = 
+  {
+    encode_ieee_double,
+    decode_ieee_double,
+    2,
+    1,
+    53,
+    53,
+    -1021,
+    1024,
+    63,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
+
+const struct real_format mips_double_format = 
+  {
+    encode_ieee_double,
+    decode_ieee_double,
+    2,
+    1,
+    53,
+    53,
+    -1021,
+    1024,
+    63,
+    true,
+    true,
+    true,
+    true,
+    false
+  };
 
-#define NTEN 12
-#define MAXP 4096
+\f
+/* IEEE extended double precision format.  This comes in three
+   flavors: Intel's as a 12 byte image, Intel's as a 16 byte image,
+   and Motorola's.  */
+
+static void encode_ieee_extended PARAMS ((const struct real_format *fmt,
+                                         long *, const REAL_VALUE_TYPE *));
+static void decode_ieee_extended PARAMS ((const struct real_format *,
+                                         REAL_VALUE_TYPE *, const long *));
+
+static void encode_ieee_extended_128 PARAMS ((const struct real_format *fmt,
+                                             long *,
+                                             const REAL_VALUE_TYPE *));
+static void decode_ieee_extended_128 PARAMS ((const struct real_format *,
+                                             REAL_VALUE_TYPE *,
+                                             const long *));
 
-#if LONG_DOUBLE_TYPE_SIZE == 128
-static unsigned EMUSHORT etens[NTEN + 1][NE] =
+static void
+encode_ieee_extended (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  {0x6576, 0x4a92, 0x804a, 0x153f,
-   0xc94c, 0x979a, 0x8a20, 0x5202, 0xc460, 0x7525,},   /* 10**4096 */
-  {0x6a32, 0xce52, 0x329a, 0x28ce,
-   0xa74d, 0x5de4, 0xc53d, 0x3b5d, 0x9e8b, 0x5a92,},   /* 10**2048 */
-  {0x526c, 0x50ce, 0xf18b, 0x3d28,
-   0x650d, 0x0c17, 0x8175, 0x7586, 0xc976, 0x4d48,},
-  {0x9c66, 0x58f8, 0xbc50, 0x5c54,
-   0xcc65, 0x91c6, 0xa60e, 0xa0ae, 0xe319, 0x46a3,},
-  {0x851e, 0xeab7, 0x98fe, 0x901b,
-   0xddbb, 0xde8d, 0x9df9, 0xebfb, 0xaa7e, 0x4351,},
-  {0x0235, 0x0137, 0x36b1, 0x336c,
-   0xc66f, 0x8cdf, 0x80e9, 0x47c9, 0x93ba, 0x41a8,},
-  {0x50f8, 0x25fb, 0xc76b, 0x6b71,
-   0x3cbf, 0xa6d5, 0xffcf, 0x1f49, 0xc278, 0x40d3,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0xf020, 0xb59d, 0x2b70, 0xada8, 0x9dc5, 0x4069,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0x0000, 0x0000, 0x0400, 0xc9bf, 0x8e1b, 0x4034,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0x0000, 0x0000, 0x0000, 0x2000, 0xbebc, 0x4019,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0x0000, 0x0000, 0x0000, 0x0000, 0x9c40, 0x400c,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0x0000, 0x0000, 0x0000, 0x0000, 0xc800, 0x4005,},
-  {0x0000, 0x0000, 0x0000, 0x0000,
-   0x0000, 0x0000, 0x0000, 0x0000, 0xa000, 0x4002,},   /* 10**1 */
-};
+  unsigned long image_hi, sig_hi, sig_lo;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
 
-static unsigned EMUSHORT emtens[NTEN + 1][NE] =
-{
-  {0x2030, 0xcffc, 0xa1c3, 0x8123,
-   0x2de3, 0x9fde, 0xd2ce, 0x04c8, 0xa6dd, 0x0ad8,},   /* 10**-4096 */
-  {0x8264, 0xd2cb, 0xf2ea, 0x12d4,
-   0x4925, 0x2de4, 0x3436, 0x534f, 0xceae, 0x256b,},   /* 10**-2048 */
-  {0xf53f, 0xf698, 0x6bd3, 0x0158,
-   0x87a6, 0xc0bd, 0xda57, 0x82a5, 0xa2a6, 0x32b5,},
-  {0xe731, 0x04d4, 0xe3f2, 0xd332,
-   0x7132, 0xd21c, 0xdb23, 0xee32, 0x9049, 0x395a,},
-  {0xa23e, 0x5308, 0xfefb, 0x1155,
-   0xfa91, 0x1939, 0x637a, 0x4325, 0xc031, 0x3cac,},
-  {0xe26d, 0xdbde, 0xd05d, 0xb3f6,
-   0xac7c, 0xe4a0, 0x64bc, 0x467c, 0xddd0, 0x3e55,},
-  {0x2a20, 0x6224, 0x47b3, 0x98d7,
-   0x3f23, 0xe9a5, 0xa539, 0xea27, 0xa87f, 0x3f2a,},
-  {0x0b5b, 0x4af2, 0xa581, 0x18ed,
-   0x67de, 0x94ba, 0x4539, 0x1ead, 0xcfb1, 0x3f94,},
-  {0xbf71, 0xa9b3, 0x7989, 0xbe68,
-   0x4c2e, 0xe15b, 0xc44d, 0x94be, 0xe695, 0x3fc9,},
-  {0x3d4d, 0x7c3d, 0x36ba, 0x0d2b,
-   0xfdc2, 0xcefc, 0x8461, 0x7711, 0xabcc, 0x3fe4,},
-  {0xc155, 0xa4a8, 0x404e, 0x6113,
-   0xd3c3, 0x652b, 0xe219, 0x1758, 0xd1b7, 0x3ff1,},
-  {0xd70a, 0x70a3, 0x0a3d, 0xa3d7,
-   0x3d70, 0xd70a, 0x70a3, 0x0a3d, 0xa3d7, 0x3ff8,},
-  {0xcccd, 0xcccc, 0xcccc, 0xcccc,
-   0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3ffb,},   /* 10**-1 */
-};
-#else
-/* LONG_DOUBLE_TYPE_SIZE is other than 128 */
-static unsigned EMUSHORT etens[NTEN + 1][NE] =
-{
-  {0xc94c, 0x979a, 0x8a20, 0x5202, 0xc460, 0x7525,},   /* 10**4096 */
-  {0xa74d, 0x5de4, 0xc53d, 0x3b5d, 0x9e8b, 0x5a92,},   /* 10**2048 */
-  {0x650d, 0x0c17, 0x8175, 0x7586, 0xc976, 0x4d48,},
-  {0xcc65, 0x91c6, 0xa60e, 0xa0ae, 0xe319, 0x46a3,},
-  {0xddbc, 0xde8d, 0x9df9, 0xebfb, 0xaa7e, 0x4351,},
-  {0xc66f, 0x8cdf, 0x80e9, 0x47c9, 0x93ba, 0x41a8,},
-  {0x3cbf, 0xa6d5, 0xffcf, 0x1f49, 0xc278, 0x40d3,},
-  {0xf020, 0xb59d, 0x2b70, 0xada8, 0x9dc5, 0x4069,},
-  {0x0000, 0x0000, 0x0400, 0xc9bf, 0x8e1b, 0x4034,},
-  {0x0000, 0x0000, 0x0000, 0x2000, 0xbebc, 0x4019,},
-  {0x0000, 0x0000, 0x0000, 0x0000, 0x9c40, 0x400c,},
-  {0x0000, 0x0000, 0x0000, 0x0000, 0xc800, 0x4005,},
-  {0x0000, 0x0000, 0x0000, 0x0000, 0xa000, 0x4002,},   /* 10**1 */
-};
+  image_hi = r->sign << 15;
+  sig_hi = sig_lo = 0;
 
-static unsigned EMUSHORT emtens[NTEN + 1][NE] =
-{
-  {0x2de4, 0x9fde, 0xd2ce, 0x04c8, 0xa6dd, 0x0ad8,},   /* 10**-4096 */
-  {0x4925, 0x2de4, 0x3436, 0x534f, 0xceae, 0x256b,},   /* 10**-2048 */
-  {0x87a6, 0xc0bd, 0xda57, 0x82a5, 0xa2a6, 0x32b5,},
-  {0x7133, 0xd21c, 0xdb23, 0xee32, 0x9049, 0x395a,},
-  {0xfa91, 0x1939, 0x637a, 0x4325, 0xc031, 0x3cac,},
-  {0xac7d, 0xe4a0, 0x64bc, 0x467c, 0xddd0, 0x3e55,},
-  {0x3f24, 0xe9a5, 0xa539, 0xea27, 0xa87f, 0x3f2a,},
-  {0x67de, 0x94ba, 0x4539, 0x1ead, 0xcfb1, 0x3f94,},
-  {0x4c2f, 0xe15b, 0xc44d, 0x94be, 0xe695, 0x3fc9,},
-  {0xfdc2, 0xcefc, 0x8461, 0x7711, 0xabcc, 0x3fe4,},
-  {0xd3c3, 0x652b, 0xe219, 0x1758, 0xd1b7, 0x3ff1,},
-  {0x3d71, 0xd70a, 0x70a3, 0x0a3d, 0xa3d7, 0x3ff8,},
-  {0xcccd, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3ffb,},   /* 10**-1 */
-};
-#endif
+  switch (r->class)
+    {
+    case rvc_zero:
+      break;
 
-#if 0
-/* Convert float value X to ASCII string STRING with NDIG digits after
-   the decimal point.  */
+    case rvc_inf:
+      if (fmt->has_inf)
+       {
+         image_hi |= 32767;
 
-static void
-e24toasc (x, string, ndigs)
-     unsigned EMUSHORT x[];
-     char *string;
-     int ndigs;
-{
-  unsigned EMUSHORT w[NI];
+         /* Intel requires the explicit integer bit to be set, otherwise
+            it considers the value a "pseudo-infinity".  Motorola docs
+            say it doesn't care.  */
+         sig_hi = 0x80000000;
+       }
+      else
+       {
+         image_hi |= 32767;
+         sig_lo = sig_hi = 0xffffffff;
+       }
+      break;
 
-  e24toe (x, w);
-  etoasc (w, string, ndigs);
-}
+    case rvc_nan:
+      if (fmt->has_nans)
+       {
+         image_hi |= 32767;
+         if (HOST_BITS_PER_LONG == 32)
+           {
+             sig_hi = r->sig[SIGSZ-1];
+             sig_lo = r->sig[SIGSZ-2];
+           }
+         else
+           {
+             sig_lo = r->sig[SIGSZ-1];
+             sig_hi = sig_lo >> 31 >> 1;
+             sig_lo &= 0xffffffff;
+           }
+         if (r->signalling == fmt->qnan_msb_set)
+           sig_hi &= ~(1 << 30);
+         else
+           sig_hi |= 1 << 30;
+         if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
+           sig_hi = 1 << 29;
+
+         /* Intel requires the explicit integer bit to be set, otherwise
+            it considers the value a "pseudo-nan".  Motorola docs say it
+            doesn't care.  */
+         sig_hi |= 0x80000000;
+       }
+      else
+       {
+         image_hi |= 32767;
+         sig_lo = sig_hi = 0xffffffff;
+       }
+      break;
 
-/* Convert double value X to ASCII string STRING with NDIG digits after
-   the decimal point.  */
+    case rvc_normal:
+      {
+       int exp = r->exp;
 
-static void
-e53toasc (x, string, ndigs)
-     unsigned EMUSHORT x[];
-     char *string;
-     int ndigs;
-{
-  unsigned EMUSHORT w[NI];
+       /* 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. 
 
-  e53toe (x, w);
-  etoasc (w, string, ndigs);
-}
+          Except for Motorola, which consider exp=0 and explicit
+          integer bit set to continue to be normalized.  In theory
+          this discrepancy has been taken care of by the difference
+          in fmt->emin in round_for_format.  */
 
-/* Convert double extended value X to ASCII string STRING with NDIG digits
-   after the decimal point.  */
+       if (denormal)
+         exp = 0;
+       else
+         {
+           exp += 16383 - 1;
+           if (exp < 0)
+             abort ();
+         }
+       image_hi |= exp;
+
+       if (HOST_BITS_PER_LONG == 32)
+         {
+           sig_hi = r->sig[SIGSZ-1];
+           sig_lo = r->sig[SIGSZ-2];
+         }
+       else
+         {
+           sig_lo = r->sig[SIGSZ-1];
+           sig_hi = sig_lo >> 31 >> 1;
+           sig_lo &= 0xffffffff;
+         }
+      }
+      break;
 
-static void
-e64toasc (x, string, ndigs)
-     unsigned EMUSHORT x[];
-     char *string;
-     int ndigs;
-{
-  unsigned EMUSHORT w[NI];
+    default:
+      abort ();
+    }
 
-  e64toe (x, w);
-  etoasc (w, string, ndigs);
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = image_hi << 16, buf[1] = sig_hi, buf[2] = sig_lo;
+  else
+    buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi;
 }
 
-/* Convert 128-bit long double value X to ASCII string STRING with NDIG digits
-   after the decimal point.  */
-
 static void
-e113toasc (x, string, ndigs)
-     unsigned EMUSHORT x[];
-     char *string;
-     int ndigs;
+encode_ieee_extended_128 (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT w[NI];
-
-  e113toe (x, w);
-  etoasc (w, string, ndigs);
+  buf[3 * !FLOAT_WORDS_BIG_ENDIAN] = 0;
+  encode_ieee_extended (fmt, buf+!!FLOAT_WORDS_BIG_ENDIAN, r);
 }
-#endif /* 0 */
-
-/* Convert e-type X to ASCII string STRING with NDIGS digits after
-   the decimal point.  */
-
-static char wstring[80];       /* working storage for ASCII output */
 
 static void
-etoasc (x, string, ndigs)
-     unsigned EMUSHORT x[];
-     char *string;
-     int ndigs;
+decode_ieee_extended (fmt, r, buf)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  EMUSHORT digit;
-  unsigned EMUSHORT y[NI], t[NI], u[NI], w[NI];
-  unsigned EMUSHORT *p, *r, *ten;
-  unsigned EMUSHORT sign;
-  int i, j, k, expon, rndsav;
-  char *s, *ss;
-  unsigned EMUSHORT m;
-
-
-  rndsav = rndprc;
-  ss = string;
-  s = wstring;
-  *ss = '\0';
-  *s = '\0';
-#ifdef NANS
-  if (eisnan (x))
-    {
-      sprintf (wstring, " NaN ");
-      goto bxit;
-    }
-#endif
-  rndprc = NBITS;              /* set to full precision */
-  emov (x, y);                 /* retain external format */
-  if (y[NE - 1] & 0x8000)
-    {
-      sign = 0xffff;
-      y[NE - 1] &= 0x7fff;
-    }
-  else
-    {
-      sign = 0;
-    }
-  expon = 0;
-  ten = &etens[NTEN][0];
-  emov (eone, t);
-  /* Test for zero exponent */
-  if (y[NE - 1] == 0)
-    {
-      for (k = 0; k < NE - 1; k++)
-       {
-         if (y[k] != 0)
-           goto tnzro;         /* denormalized number */
-       }
-      goto isone;              /* valid all zeros */
-    }
- tnzro:
+  unsigned long image_hi, sig_hi, sig_lo;
+  bool sign;
+  int exp;
 
-  /* Test for infinity.  */
-  if (y[NE - 1] == 0x7fff)
-    {
-      if (sign)
-       sprintf (wstring, " -Infinity ");
-      else
-       sprintf (wstring, " Infinity ");
-      goto bxit;
-    }
-
-  /* Test for exponent nonzero but significand denormalized.
-   * This is an error condition.
-   */
-  if ((y[NE - 1] != 0) && ((y[NE - 2] & 0x8000) == 0))
-    {
-      mtherr ("etoasc", DOMAIN);
-      sprintf (wstring, "NaN");
-      goto bxit;
-    }
-
-  /* Compare to 1.0 */
-  i = ecmp (eone, y);
-  if (i == 0)
-    goto isone;
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    image_hi = buf[0] >> 16, sig_hi = buf[1], sig_lo = buf[2];
+  else
+    sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2];
+  sig_lo &= 0xffffffff;
+  sig_hi &= 0xffffffff;
+  image_hi &= 0xffffffff;
 
-  if (i == -2)
-    abort ();
+  sign = (image_hi >> 15) & 1;
+  exp = image_hi & 0x7fff;
 
-  if (i < 0)
-    {                          /* Number is greater than 1 */
-      /* Convert significand to an integer and strip trailing decimal zeros.  */
-      emov (y, u);
-      u[NE - 1] = EXONE + NBITS - 1;
+  memset (r, 0, sizeof (*r));
 
-      p = &etens[NTEN - 4][0];
-      m = 16;
-      do
-       {
-         ediv (p, u, t);
-         efloor (t, w);
-         for (j = 0; j < NE - 1; j++)
-           {
-             if (t[j] != w[j])
-               goto noint;
-           }
-         emov (t, u);
-         expon += (int) m;
-       noint:
-         p += NE;
-         m >>= 1;
-       }
-      while (m != 0);
-
-      /* Rescale from integer significand */
-      u[NE - 1] += y[NE - 1] - (unsigned int) (EXONE + NBITS - 1);
-      emov (u, y);
-      /* Find power of 10 */
-      emov (eone, t);
-      m = MAXP;
-      p = &etens[0][0];
-      /* An unordered compare result shouldn't happen here.  */
-      while (ecmp (ten, u) <= 0)
+  if (exp == 0)
+    {
+      if ((sig_hi || sig_lo) && fmt->has_denorm)
        {
-         if (ecmp (p, u) <= 0)
+         r->class = rvc_normal;
+         r->sign = sign;
+
+         /* When the IEEE format contains a hidden bit, we know that
+            it's zero at this point, and so shift up the significand
+            and decrease the exponent to match.  In this case, Motorola
+            defines the explicit integer bit to be valid, so we don't
+            know whether the msb is set or not.  */
+         r->exp = fmt->emin;
+         if (HOST_BITS_PER_LONG == 32)
            {
-             ediv (p, u, u);
-             emul (p, t, t);
-             expon += (int) m;
+             r->sig[SIGSZ-1] = sig_hi;
+             r->sig[SIGSZ-2] = sig_lo;
            }
-         m >>= 1;
-         if (m == 0)
-           break;
-         p += NE;
+         else
+           r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
+
+         normalize (r);
        }
+      else if (fmt->has_signed_zero)
+       r->sign = sign;
     }
-  else
-    {                          /* Number is less than 1.0 */
-      /* Pad significand with trailing decimal zeros.  */
-      if (y[NE - 1] == 0)
+  else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
+    {
+      /* See above re "pseudo-infinities" and "pseudo-nans".
+        Short summary is that the MSB will likely always be
+        set, and that we don't care about it.  */
+      sig_hi &= 0x7fffffff;
+
+      if (sig_hi || sig_lo)
        {
-         while ((y[NE - 2] & 0x8000) == 0)
+         r->class = rvc_nan;
+         r->sign = sign;
+         r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
+         if (HOST_BITS_PER_LONG == 32)
            {
-             emul (ten, y, y);
-             expon -= 1;
+             r->sig[SIGSZ-1] = sig_hi;
+             r->sig[SIGSZ-2] = sig_lo;
            }
+         else
+           r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
        }
       else
        {
-         emovi (y, w);
-         for (i = 0; i < NDEC + 1; i++)
-           {
-             if ((w[NI - 1] & 0x7) != 0)
-               break;
-             /* multiply by 10 */
-             emovz (w, u);
-             eshdn1 (u);
-             eshdn1 (u);
-             eaddm (w, u);
-             u[1] += 3;
-             while (u[2] != 0)
-               {
-                 eshdn1 (u);
-                 u[1] += 1;
-               }
-             if (u[NI - 1] != 0)
-               break;
-             if (eone[NE - 1] <= u[1])
-               break;
-             emovz (u, w);
-             expon -= 1;
-           }
-         emovo (w, y);
-       }
-      k = -MAXP;
-      p = &emtens[0][0];
-      r = &etens[0][0];
-      emov (y, w);
-      emov (eone, t);
-      while (ecmp (eone, w) > 0)
-       {
-         if (ecmp (p, w) >= 0)
-           {
-             emul (r, w, w);
-             emul (r, t, t);
-             expon += k;
-           }
-         k /= 2;
-         if (k == 0)
-           break;
-         p += NE;
-         r += NE;
-       }
-      ediv (t, eone, t);
-    }
- isone:
-  /* Find the first (leading) digit.  */
-  emovi (t, w);
-  emovz (w, t);
-  emovi (y, w);
-  emovz (w, y);
-  eiremain (t, y);
-  digit = equot[NI - 1];
-  while ((digit == 0) && (ecmp (y, ezero) != 0))
-    {
-      eshup1 (y);
-      emovz (y, u);
-      eshup1 (u);
-      eshup1 (u);
-      eaddm (u, y);
-      eiremain (t, y);
-      digit = equot[NI - 1];
-      expon -= 1;
-    }
-  s = wstring;
-  if (sign)
-    *s++ = '-';
-  else
-    *s++ = ' ';
-  /* Examine number of digits requested by caller.  */
-  if (ndigs < 0)
-    ndigs = 0;
-  if (ndigs > NDEC)
-    ndigs = NDEC;
-  if (digit == 10)
-    {
-      *s++ = '1';
-      *s++ = '.';
-      if (ndigs > 0)
-       {
-         *s++ = '0';
-         ndigs -= 1;
+         r->class = rvc_inf;
+         r->sign = sign;
        }
-      expon += 1;
     }
   else
     {
-      *s++ = (char)digit + '0';
-      *s++ = '.';
-    }
-  /* Generate digits after the decimal point.  */
-  for (k = 0; k <= ndigs; k++)
-    {
-      /* multiply current number by 10, without normalizing */
-      eshup1 (y);
-      emovz (y, u);
-      eshup1 (u);
-      eshup1 (u);
-      eaddm (u, y);
-      eiremain (t, y);
-      *s++ = (char) equot[NI - 1] + '0';
-    }
-  digit = equot[NI - 1];
-  --s;
-  ss = s;
-  /* round off the ASCII string */
-  if (digit > 4)
-    {
-      /* Test for critical rounding case in ASCII output.  */
-      if (digit == 5)
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = exp - 16383 + 1;
+      if (HOST_BITS_PER_LONG == 32)
        {
-         emovo (y, t);
-         if (ecmp (t, ezero) != 0)
-           goto roun;          /* round to nearest */
-#ifndef C4X
-         if ((*(s - 1) & 1) == 0)
-           goto doexp;         /* round to even */
-#endif
-       }
-      /* Round up and propagate carry-outs */
-    roun:
-      --s;
-      k = *s & 0x7f;
-      /* Carry out to most significant digit? */
-      if (k == '.')
-       {
-         --s;
-         k = *s;
-         k += 1;
-         *s = (char) k;
-         /* Most significant digit carries to 10? */
-         if (k > '9')
-           {
-             expon += 1;
-             *s = '1';
-           }
-         goto doexp;
-       }
-      /* Round up and carry out from less significant digits */
-      k += 1;
-      *s = (char) k;
-      if (k > '9')
-       {
-         *s = '0';
-         goto roun;
+         r->sig[SIGSZ-1] = sig_hi;
+         r->sig[SIGSZ-2] = sig_lo;
        }
+      else
+       r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
     }
- doexp:
-  /*
-     if (expon >= 0)
-     sprintf (ss, "e+%d", expon);
-     else
-     sprintf (ss, "e%d", expon);
-     */
-  sprintf (ss, "e%d", expon);
- bxit:
-  rndprc = rndsav;
-  /* copy out the working string */
-  s = string;
-  ss = wstring;
-  while (*ss == ' ')           /* strip possible leading space */
-    ++ss;
-  while ((*s++ = *ss++) != '\0')
-    ;
 }
 
-
-/* Convert ASCII string to floating point.
-
-   Numeric input is a free format decimal number of any length, with
-   or without decimal point.  Entering E after the number followed by an
-   integer number causes the second number to be interpreted as a power of
-   10 to be multiplied by the first number (i.e., "scientific" notation).  */
-
-/* Convert ASCII string S to single precision float value Y.  */
-
 static void
-asctoe24 (s, y)
-     const char *s;
-     unsigned EMUSHORT *y;
+decode_ieee_extended_128 (fmt, r, buf)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  asctoeg (s, y, 24);
+  decode_ieee_extended (fmt, r, buf+!!FLOAT_WORDS_BIG_ENDIAN);
 }
 
-
-/* Convert ASCII string S to double precision value Y.  */
+const struct real_format ieee_extended_motorola_format = 
+  {
+    encode_ieee_extended,
+    decode_ieee_extended,
+    2,
+    1,
+    64,
+    64,
+    -16382,
+    16384,
+    95,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
+
+const struct real_format ieee_extended_intel_96_format = 
+  {
+    encode_ieee_extended,
+    decode_ieee_extended,
+    2,
+    1,
+    64,
+    64,
+    -16381,
+    16384,
+    79,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
+
+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 PARAMS ((const struct real_format *fmt,
+                                        long *, const REAL_VALUE_TYPE *));
+static void decode_ibm_extended PARAMS ((const struct real_format *,
+                                        REAL_VALUE_TYPE *, const long *));
 
 static void
-asctoe53 (s, y)
-     const char *s;
-     unsigned EMUSHORT *y;
+encode_ibm_extended (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-#if defined(DEC) || defined(IBM)
-  asctoeg (s, y, 56);
-#else
-#if defined(C4X)
-  asctoeg (s, y, 32);
-#else
-  asctoeg (s, y, 53);
-#endif
-#endif
-}
+  REAL_VALUE_TYPE u, v;
+  const struct real_format *base_fmt;
 
+  base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
 
-/* Convert ASCII string S to double extended value Y.  */
+  switch (r->class)
+    {
+    case rvc_zero:
+      /* Both doubles have sign bit set.  */
+      buf[0] = FLOAT_WORDS_BIG_ENDIAN ? r->sign << 31 : 0;
+      buf[1] = FLOAT_WORDS_BIG_ENDIAN ? 0 : r->sign << 31;
+      buf[2] = buf[0];
+      buf[3] = buf[1];
+      break;
 
-static void
-asctoe64 (s, y)
-     const char *s;
-     unsigned EMUSHORT *y;
-{
-  asctoeg (s, y, 64);
-}
+    case rvc_inf:
+    case rvc_nan:
+      /* Both doubles set to Inf / NaN.  */
+      encode_ieee_double (base_fmt, &buf[0], r);
+      buf[2] = buf[0];
+      buf[3] = buf[1];
+      return;
+      
+    case rvc_normal:
+      /* u = IEEE double precision portion of significand.  */
+      u = *r;
+      clear_significand_below (&u, SIGNIFICAND_BITS - 53);
+
+      normalize (&u);
+      /* If the upper double is zero, we have a denormal double, so
+        move it to the first double and leave the second as zero.  */
+      if (u.class == rvc_zero)
+       {
+         v = u;
+         u = *r;
+         normalize (&u);
+       }
+      else
+       {
+         /* v = remainder containing additional 53 bits of significand.  */
+         do_add (&v, r, &u, 1);
+         round_for_format (base_fmt, &v);
+       }
 
-/* Convert ASCII string S to 128-bit long double Y.  */
+      round_for_format (base_fmt, &u);
 
-static void
-asctoe113 (s, y)
-     const char *s;
-     unsigned EMUSHORT *y;
-{
-  asctoeg (s, y, 113);
-}
+      encode_ieee_double (base_fmt, &buf[0], &u);
+      encode_ieee_double (base_fmt, &buf[2], &v);
+      break;
 
-/* Convert ASCII string S to e type Y.  */
+    default:
+      abort ();
+    }
+}
 
 static void
-asctoe (s, y)
-     const char *s;
-     unsigned EMUSHORT *y;
+decode_ibm_extended (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  asctoeg (s, y, NBITS);
+  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;
 }
 
-/* Convert ASCII string SS to e type Y, with a specified rounding precision
-   of OPREC bits.  BASE is 16 for C9X hexadecimal floating constants.  */
+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,
+    true,
+    true
+  };
+
+const struct real_format mips_extended_format = 
+  {
+    encode_ibm_extended,
+    decode_ibm_extended,
+    2,
+    1,
+    53 + 53,
+    53,
+    -1021 + 53,
+    1024,
+    -1,
+    true,
+    true,
+    true,
+    true,
+    false
+  };
+
+\f
+/* IEEE quad precision format.  */
+
+static void encode_ieee_quad PARAMS ((const struct real_format *fmt,
+                                     long *, const REAL_VALUE_TYPE *));
+static void decode_ieee_quad PARAMS ((const struct real_format *,
+                                     REAL_VALUE_TYPE *, const long *));
 
 static void
-asctoeg (ss, y, oprec)
-     const char *ss;
-     unsigned EMUSHORT *y;
-     int oprec;
+encode_ieee_quad (fmt, buf, r)
+     const struct real_format *fmt;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT yy[NI], xt[NI], tt[NI];
-  int esign, decflg, sgnflg, nexp, exp, prec, lost;
-  int k, trail, c, rndsav;
-  EMULONG lexp;
-  unsigned EMUSHORT nsign, *p;
-  char *sp, *s, *lstr;
-  int base = 10;
-
-  /* Copy the input string.  */
-  lstr = (char *) alloca (strlen (ss) + 1);
-
-  while (*ss == ' ')           /* skip leading spaces */
-    ++ss;
-
-  sp = lstr;
-  while ((*sp++ = *ss++) != '\0')
-    ;
-  s = lstr;
+  unsigned long image3, image2, image1, image0, exp;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
+  REAL_VALUE_TYPE u;
 
-  if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
-    {
-      base = 16;
-      s += 2;
-    }
+  image3 = r->sign << 31;
+  image2 = 0;
+  image1 = 0;
+  image0 = 0;
 
-  rndsav = rndprc;
-  rndprc = NBITS;              /* Set to full precision */
-  lost = 0;
-  nsign = 0;
-  decflg = 0;
-  sgnflg = 0;
-  nexp = 0;
-  exp = 0;
-  prec = 0;
-  ecleaz (yy);
-  trail = 0;
-
- nxtcom:
-  if (*s >= '0' && *s <= '9')
-    k = *s - '0';
-  else if (*s >= 'a')
-    k = 10 + *s - 'a';
-  else
-    k = 10 + *s - 'A';
-  if ((k >= 0) && (k < base))
+  rshift_significand (&u, r, SIGNIFICAND_BITS - 113);
+
+  switch (r->class)
     {
-      /* Ignore leading zeros */
-      if ((prec == 0) && (decflg == 0) && (k == 0))
-       goto donchr;
-      /* Identify and strip trailing zeros after the decimal point.  */
-      if ((trail == 0) && (decflg != 0))
+    case rvc_zero:
+      break;
+
+    case rvc_inf:
+      if (fmt->has_inf)
+       image3 |= 32767 << 16;
+      else
        {
-         sp = s;
-         while ((*sp >= '0' && *sp <= '9')
-                || (base == 16 && ((*sp >= 'a' && *sp <= 'f')
-                                   || (*sp >= 'A' && *sp <= 'F'))))
-           ++sp;
-         /* Check for syntax error */
-         c = *sp & 0x7f;
-         if ((base != 10 || ((c != 'e') && (c != 'E')))
-             && (base != 16 || ((c != 'p') && (c != 'P')))
-             && (c != '\0')
-             && (c != '\n') && (c != '\r') && (c != ' ')
-             && (c != ','))
-           goto error;
-         --sp;
-         while (*sp == '0')
-           *sp-- = 'z';
-         trail = 1;
-         if (*s == 'z')
-           goto donchr;
+         image3 |= 0x7fffffff;
+         image2 = 0xffffffff;
+         image1 = 0xffffffff;
+         image0 = 0xffffffff;
        }
+      break;
 
-      /* If enough digits were given to more than fill up the yy register,
-        continuing until overflow into the high guard word yy[2]
-        guarantees that there will be a roundoff bit at the top
-        of the low guard word after normalization.  */
-
-      if (yy[2] == 0)
+    case rvc_nan:
+      if (fmt->has_nans)
        {
-         if (base == 16)
+         image3 |= 32767 << 16;
+
+         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];
+             image2 = u.sig[2];
+             image3 |= u.sig[3] & 0xffff;
+           }
+         else
            {
-             if (decflg)
-               nexp += 4;      /* count digits after decimal point */
-
-             eshup1 (yy);      /* multiply current number by 16 */
-             eshup1 (yy);
-             eshup1 (yy);
-             eshup1 (yy);
+             image0 = u.sig[0];
+             image1 = image0 >> 31 >> 1;
+             image2 = u.sig[1];
+             image3 |= (image2 >> 31 >> 1) & 0xffff;
+             image0 &= 0xffffffff;
+             image2 &= 0xffffffff;
            }
+         if (r->signalling == fmt->qnan_msb_set)
+           image3 &= ~0x8000;
          else
+           image3 |= 0x8000;
+         /* 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)
            {
-             if (decflg)
-               nexp += 1;              /* count digits after decimal point */
-
-             eshup1 (yy);              /* multiply current number by 10 */
-             emovz (yy, xt);
-             eshup1 (xt);
-             eshup1 (xt);
-             eaddm (xt, yy);
+             image3 |= 0x7fff;
+             image2 = image1 = image0 = 0xffffffff;
            }
-         /* Insert the current digit.  */
-         ecleaz (xt);
-         xt[NI - 2] = (unsigned EMUSHORT) k;
-         eaddm (xt, yy);
+         else if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
+           image3 |= 0x4000;
        }
       else
        {
-         /* Mark any lost non-zero digit.  */
-         lost |= k;
-         /* Count lost digits before the decimal point.  */
-         if (decflg == 0)
-           {
-             if (base == 10)
-               nexp -= 1;
-             else
-               nexp -= 4;
-           }
+         image3 |= 0x7fffffff;
+         image2 = 0xffffffff;
+         image1 = 0xffffffff;
+         image0 = 0xffffffff;
        }
-      prec += 1;
-      goto donchr;
-    }
-
-  switch (*s)
-    {
-    case 'z':
-      break;
-    case 'E':
-    case 'e':
-    case 'P':
-    case 'p':
-      goto expnt;
-    case '.':                  /* decimal point */
-      if (decflg)
-       goto error;
-      ++decflg;
       break;
-    case '-':
-      nsign = 0xffff;
-      if (sgnflg)
-       goto error;
-      ++sgnflg;
-      break;
-    case '+':
-      if (sgnflg)
-       goto error;
-      ++sgnflg;
+
+    case rvc_normal:
+      /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+        whereas the intermediate representation is 0.F x 2**exp.
+        Which means we're off by one.  */
+      if (denormal)
+       exp = 0;
+      else
+       exp = r->exp + 16383 - 1;
+      image3 |= exp << 16;
+
+      if (HOST_BITS_PER_LONG == 32)
+       {
+         image0 = u.sig[0];
+         image1 = u.sig[1];
+         image2 = u.sig[2];
+         image3 |= u.sig[3] & 0xffff;
+       }
+      else
+       {
+         image0 = u.sig[0];
+         image1 = image0 >> 31 >> 1;
+         image2 = u.sig[1];
+         image3 |= (image2 >> 31 >> 1) & 0xffff;
+         image0 &= 0xffffffff;
+         image2 &= 0xffffffff;
+       }
       break;
-    case ',':
-    case ' ':
-    case '\0':
-    case '\n':
-    case '\r':
-      goto daldone;
-    case 'i':
-    case 'I':
-      goto infinite;
+
     default:
-    error:
-#ifdef NANS
-      einan (yy);
-#else
-      mtherr ("asctoe", DOMAIN);
-      eclear (yy);
-#endif
-      goto aexit;
-    }
- donchr:
-  ++s;
-  goto nxtcom;
-
-  /* Exponent interpretation */
- expnt:
-  /* 0.0eXXX is zero, regardless of XXX.  Check for the 0.0. */
-  for (k = 0; k < NI; k++)
-    {
-      if (yy[k] != 0)
-       goto read_expnt;
-    }
-  goto aexit;
-
-read_expnt:
-  esign = 1;
-  exp = 0;
-  ++s;
-  /* check for + or - */
-  if (*s == '-')
-    {
-      esign = -1;
-      ++s;
-    }
-  if (*s == '+')
-    ++s;
-  while ((*s >= '0') && (*s <= '9'))
-    {
-      exp *= 10;
-      exp += *s++ - '0';
-      if (exp > 999999)
-       break;
+      abort ();
     }
-  if (esign < 0)
-    exp = -exp;
-  if ((exp > MAXDECEXP) && (base == 10))
+
+  if (FLOAT_WORDS_BIG_ENDIAN)
     {
- infinite:
-      ecleaz (yy);
-      yy[E] = 0x7fff;          /* infinity */
-      goto aexit;
+      buf[0] = image3;
+      buf[1] = image2;
+      buf[2] = image1;
+      buf[3] = image0;
     }
-  if ((exp < MINDECEXP) && (base == 10))
+  else
     {
- zero:
-      ecleaz (yy);
-      goto aexit;
+      buf[0] = image0;
+      buf[1] = image1;
+      buf[2] = image2;
+      buf[3] = image3;
     }
+}
 
- daldone:
-  if (base == 16)
-    {
-      /* Base 16 hexadecimal floating constant.  */
-      if ((k = enormlz (yy)) > NBITS)
-       {
-         ecleaz (yy);
-         goto aexit;
-       }
-      /* Adjust the exponent.  NEXP is the number of hex digits,
-         EXP is a power of 2.  */
-      lexp = (EXONE - 1 + NBITS) - k + yy[E] + exp - nexp;
-      if (lexp > 0x7fff)
-       goto infinite;
-      if (lexp < 0)
-       goto zero;
-      yy[E] = lexp;
-      goto expdon;
-    }
+static void
+decode_ieee_quad (fmt, r, buf)
+     const struct real_format *fmt;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+{
+  unsigned long image3, image2, image1, image0;
+  bool sign;
+  int exp;
 
-  nexp = exp - nexp;
-  /* Pad trailing zeros to minimize power of 10, per IEEE spec.  */
-  while ((nexp > 0) && (yy[2] == 0))
+  if (FLOAT_WORDS_BIG_ENDIAN)
     {
-      emovz (yy, xt);
-      eshup1 (xt);
-      eshup1 (xt);
-      eaddm (yy, xt);
-      eshup1 (xt);
-      if (xt[2] != 0)
-       break;
-      nexp -= 1;
-      emovz (xt, yy);
+      image3 = buf[0];
+      image2 = buf[1];
+      image1 = buf[2];
+      image0 = buf[3];
     }
-  if ((k = enormlz (yy)) > NBITS)
+  else
     {
-      ecleaz (yy);
-      goto aexit;
+      image0 = buf[0];
+      image1 = buf[1];
+      image2 = buf[2];
+      image3 = buf[3];
     }
-  lexp = (EXONE - 1 + NBITS) - k;
-  emdnorm (yy, lost, 0, lexp, 64);
-  lost = 0;
+  image0 &= 0xffffffff;
+  image1 &= 0xffffffff;
+  image2 &= 0xffffffff;
 
-  /* Convert to external format:
+  sign = (image3 >> 31) & 1;
+  exp = (image3 >> 16) & 0x7fff;
+  image3 &= 0xffff;
 
-     Multiply by 10**nexp.  If precision is 64 bits,
-     the maximum relative error incurred in forming 10**n
-     for 0 <= n <= 324 is 8.2e-20, at 10**180.
-     For 0 <= n <= 999, the peak relative error is 1.4e-19 at 10**947.
-     For 0 >= n >= -999, it is -1.55e-19 at 10**-435.  */
+  memset (r, 0, sizeof (*r));
 
-  lexp = yy[E];
-  if (nexp == 0)
-    {
-      k = 0;
-      goto expdon;
-    }
-  esign = 1;
-  if (nexp < 0)
+  if (exp == 0)
     {
-      nexp = -nexp;
-      esign = -1;
-      if (nexp > 4096)
+      if ((image3 | image2 | image1 | image0) && fmt->has_denorm)
        {
-         /* Punt.  Can't handle this without 2 divides.  */
-         emovi (etens[0], tt);
-         lexp -= tt[E];
-         k = edivm (tt, yy);
-         lexp += EXONE;
-         nexp -= 4096;
+         r->class = rvc_normal;
+         r->sign = sign;
+
+         r->exp = -16382 + (SIGNIFICAND_BITS - 112);
+         if (HOST_BITS_PER_LONG == 32)
+           {
+             r->sig[0] = image0;
+             r->sig[1] = image1;
+             r->sig[2] = image2;
+             r->sig[3] = image3;
+           }
+         else
+           {
+             r->sig[0] = (image1 << 31 << 1) | image0;
+             r->sig[1] = (image3 << 31 << 1) | image2;
+           }
+
+         normalize (r);
        }
+      else if (fmt->has_signed_zero)
+       r->sign = sign;
     }
-  p = &etens[NTEN][0];
-  emov (eone, xt);
-  exp = 1;
-  do
+  else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
     {
-      if (exp & nexp)
-       emul (p, xt, xt);
-      p -= NE;
-      exp = exp + exp;
-    }
-  while (exp <= MAXP);
+      if (image3 | image2 | image1 | image0)
+       {
+         r->class = rvc_nan;
+         r->sign = sign;
+         r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
 
-  emovi (xt, tt);
-  if (esign < 0)
-    {
-      lexp -= tt[E];
-      k = edivm (tt, yy);
-      lexp += EXONE;
+         if (HOST_BITS_PER_LONG == 32)
+           {
+             r->sig[0] = image0;
+             r->sig[1] = image1;
+             r->sig[2] = image2;
+             r->sig[3] = image3;
+           }
+         else
+           {
+             r->sig[0] = (image1 << 31 << 1) | image0;
+             r->sig[1] = (image3 << 31 << 1) | image2;
+           }
+         lshift_significand (r, r, SIGNIFICAND_BITS - 113);
+       }
+      else
+       {
+         r->class = rvc_inf;
+         r->sign = sign;
+       }
     }
   else
     {
-      lexp += tt[E];
-      k = emulm (tt, yy);
-      lexp -= EXONE - 1;
-    }
-  lost = k;
-
- expdon:
-
-  /* Round and convert directly to the destination type */
-  if (oprec == 53)
-    lexp -= EXONE - 0x3ff;
-#ifdef C4X
-  else if (oprec == 24 || oprec == 32)
-    lexp -= (EXONE - 0x7f);
-#else
-#ifdef IBM
-  else if (oprec == 24 || oprec == 56)
-    lexp -= EXONE - (0x41 << 2);
-#else
-  else if (oprec == 24)
-    lexp -= EXONE - 0177;
-#endif /* IBM */
-#endif /* C4X */
-#ifdef DEC
-  else if (oprec == 56)
-    lexp -= EXONE - 0201;
-#endif
-  rndprc = oprec;
-  emdnorm (yy, lost, 0, lexp, 64);
-
- aexit:
-
-  rndprc = rndsav;
-  yy[0] = nsign;
-  switch (oprec)
-    {
-#ifdef DEC
-    case 56:
-      todec (yy, y);           /* see etodec.c */
-      break;
-#endif
-#ifdef IBM
-    case 56:
-      toibm (yy, y, DFmode);
-      break;
-#endif
-#ifdef C4X
-    case 32:
-      toc4x (yy, y, HFmode);
-      break;
-#endif
-
-    case 53:
-      toe53 (yy, y);
-      break;
-    case 24:
-      toe24 (yy, y);
-      break;
-    case 64:
-      toe64 (yy, y);
-      break;
-    case 113:
-      toe113 (yy, y);
-      break;
-    case NBITS:
-      emovo (yy, y);
-      break;
-    }
-}
-
-
-
-/* Return Y = largest integer not greater than X (truncated toward minus
-   infinity).  */
-
-static unsigned EMUSHORT bmask[] =
-{
-  0xffff,
-  0xfffe,
-  0xfffc,
-  0xfff8,
-  0xfff0,
-  0xffe0,
-  0xffc0,
-  0xff80,
-  0xff00,
-  0xfe00,
-  0xfc00,
-  0xf800,
-  0xf000,
-  0xe000,
-  0xc000,
-  0x8000,
-  0x0000,
-};
-
-static void
-efloor (x, y)
-     unsigned EMUSHORT x[], y[];
-{
-  register unsigned EMUSHORT *p;
-  int e, expon, i;
-  unsigned EMUSHORT f[NE];
-
-  emov (x, f);                 /* leave in external format */
-  expon = (int) f[NE - 1];
-  e = (expon & 0x7fff) - (EXONE - 1);
-  if (e <= 0)
-    {
-      eclear (y);
-      goto isitneg;
-    }
-  /* number of bits to clear out */
-  e = NBITS - e;
-  emov (f, y);
-  if (e <= 0)
-    return;
-
-  p = &y[0];
-  while (e >= 16)
-    {
-      *p++ = 0;
-      e -= 16;
-    }
-  /* clear the remaining bits */
-  *p &= bmask[e];
-  /* truncate negatives toward minus infinity */
- isitneg:
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = exp - 16383 + 1;
 
-  if ((unsigned EMUSHORT) expon & (unsigned EMUSHORT) 0x8000)
-    {
-      for (i = 0; i < NE - 1; i++)
+      if (HOST_BITS_PER_LONG == 32)
        {
-         if (f[i] != y[i])
-           {
-             esub (eone, y, y);
-             break;
-           }
+         r->sig[0] = image0;
+         r->sig[1] = image1;
+         r->sig[2] = image2;
+         r->sig[3] = image3;
+       }
+      else
+       {
+         r->sig[0] = (image1 << 31 << 1) | image0;
+         r->sig[1] = (image3 << 31 << 1) | image2;
        }
+      lshift_significand (r, r, SIGNIFICAND_BITS - 113);
+      r->sig[SIGSZ-1] |= SIG_MSB;
     }
 }
 
-
-#if 0
-/* Return S and EXP such that  S * 2^EXP = X and .5 <= S < 1.
-   For example, 1.1 = 0.55 * 2^1.  */
+const struct real_format ieee_quad_format = 
+  {
+    encode_ieee_quad,
+    decode_ieee_quad,
+    2,
+    1,
+    113,
+    113,
+    -16381,
+    16384,
+    127,
+    true,
+    true,
+    true,
+    true,
+    true
+  };
+
+const struct real_format mips_quad_format = 
+  {
+    encode_ieee_quad,
+    decode_ieee_quad,
+    2,
+    1,
+    113,
+    113,
+    -16381,
+    16384,
+    127,
+    true,
+    true,
+    true,
+    true,
+    false
+  };
+\f
+/* Descriptions of VAX floating point formats can be found beginning at
+
+   http://www.openvms.compaq.com:8000/73final/4515/4515pro_013.html#f_floating_point_format
+
+   The thing to remember is that they're almost IEEE, except for word
+   order, exponent bias, and the lack of infinities, nans, and denormals.
+
+   We don't implement the H_floating format here, simply because neither
+   the VAX or Alpha ports use it.  */
+   
+static void encode_vax_f PARAMS ((const struct real_format *fmt,
+                                 long *, const REAL_VALUE_TYPE *));
+static void decode_vax_f PARAMS ((const struct real_format *,
+                                 REAL_VALUE_TYPE *, const long *));
+static void encode_vax_d PARAMS ((const struct real_format *fmt,
+                                 long *, const REAL_VALUE_TYPE *));
+static void decode_vax_d PARAMS ((const struct real_format *,
+                                 REAL_VALUE_TYPE *, const long *));
+static void encode_vax_g PARAMS ((const struct real_format *fmt,
+                                 long *, const REAL_VALUE_TYPE *));
+static void decode_vax_g PARAMS ((const struct real_format *,
+                                 REAL_VALUE_TYPE *, const long *));
 
 static void
-efrexp (x, exp, s)
-     unsigned EMUSHORT x[];
-     int *exp;
-     unsigned EMUSHORT s[];
+encode_vax_f (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT xi[NI];
-  EMULONG li;
+  unsigned long sign, exp, sig, image;
 
-  emovi (x, xi);
-  /*  Handle denormalized numbers properly using long integer exponent.  */
-  li = (EMULONG) ((EMUSHORT) xi[1]);
+  sign = r->sign << 15;
 
-  if (li == 0)
+  switch (r->class)
     {
-      li -= enormlz (xi);
-    }
-  xi[1] = 0x3ffe;
-  emovo (xi, s);
-  *exp = (int) (li - 0x3ffe);
-}
-#endif
+    case rvc_zero:
+      image = 0;
+      break;
 
-/* Return e type Y = X * 2^PWR2.  */
+    case rvc_inf:
+    case rvc_nan:
+      image = 0xffff7fff | sign;
+      break;
 
-static void
-eldexp (x, pwr2, y)
-     unsigned EMUSHORT x[];
-     int pwr2;
-     unsigned EMUSHORT y[];
-{
-  unsigned EMUSHORT xi[NI];
-  EMULONG li;
-  int i;
+    case rvc_normal:
+      sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
+      exp = r->exp + 128;
 
-  emovi (x, xi);
-  li = xi[1];
-  li += pwr2;
-  i = 0;
-  emdnorm (xi, i, i, li, 64);
-  emovo (xi, y);
-}
+      image = (sig << 16) & 0xffff0000;
+      image |= sign;
+      image |= exp << 7;
+      image |= sig >> 16;
+      break;
 
+    default:
+      abort ();
+    }
 
-#if 0
-/* C = remainder after dividing B by A, all e type values.
-   Least significant integer quotient bits left in EQUOT.  */
+  buf[0] = image;
+}
 
 static void
-eremain (a, b, c)
-     unsigned EMUSHORT a[], b[], c[];
+decode_vax_f (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  unsigned EMUSHORT den[NI], num[NI];
+  unsigned long image = buf[0] & 0xffffffff;
+  int exp = (image >> 7) & 0xff;
 
-#ifdef NANS
-  if (eisinf (b)
-      || (ecmp (a, ezero) == 0)
-      || eisnan (a)
-      || eisnan (b))
-    {
-      enan (c, 0);
-      return;
-    }
-#endif
-  if (ecmp (a, ezero) == 0)
+  memset (r, 0, sizeof (*r));
+
+  if (exp != 0)
     {
-      mtherr ("eremain", SING);
-      eclear (c);
-      return;
+      r->class = rvc_normal;
+      r->sign = (image >> 15) & 1;
+      r->exp = exp - 128;
+
+      image = ((image & 0x7f) << 16) | ((image >> 16) & 0xffff);
+      r->sig[SIGSZ-1] = (image << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
     }
-  emovi (a, den);
-  emovi (b, num);
-  eiremain (den, num);
-  /* Sign of remainder = sign of quotient */
-  if (a[0] == b[0])
-    num[0] = 0;
-  else
-    num[0] = 0xffff;
-  emovo (num, c);
 }
-#endif
-
-/*  Return quotient of exploded e-types NUM / DEN in EQUOT,
-    remainder in NUM.  */
 
 static void
-eiremain (den, num)
-     unsigned EMUSHORT den[], num[];
+encode_vax_d (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  EMULONG ld, ln;
-  unsigned EMUSHORT j;
-
-  ld = den[E];
-  ld -= enormlz (den);
-  ln = num[E];
-  ln -= enormlz (num);
-  ecleaz (equot);
-  while (ln >= ld)
+  unsigned long image0, image1, sign = r->sign << 15;
+
+  switch (r->class)
     {
-      if (ecmpm (den, num) <= 0)
+    case rvc_zero:
+      image0 = image1 = 0;
+      break;
+
+    case rvc_inf:
+    case rvc_nan:
+      image0 = 0xffff7fff | sign;
+      image1 = 0xffffffff;
+      break;
+
+    case rvc_normal:
+      /* Extract the significand into straight hi:lo.  */
+      if (HOST_BITS_PER_LONG == 64)
        {
-         esubm (den, num);
-         j = 1;
+         image0 = r->sig[SIGSZ-1];
+         image1 = (image0 >> (64 - 56)) & 0xffffffff;
+         image0 = (image0 >> (64 - 56 + 1) >> 31) & 0x7fffff;
        }
       else
-         j = 0;
-      eshup1 (equot);
-      equot[NI - 1] |= j;
-      eshup1 (num);
-      ln -= 1;
-    }
-  emdnorm (num, 0, 0, ln, 0);
-}
-
-/* Report an error condition CODE encountered in function NAME.
-
-    Mnemonic        Value          Significance
-
-     DOMAIN            1       argument domain error
-     SING              2       function singularity
-     OVERFLOW          3       overflow range error
-     UNDERFLOW         4       underflow range error
-     TLOSS             5       total loss of precision
-     PLOSS             6       partial loss of precision
-     INVALID           7       NaN - producing operation
-     EDOM             33       Unix domain error code
-     ERANGE           34       Unix range error code
-
-   The order of appearance of the following messages is bound to the
-   error codes defined above.  */
-
-int merror = 0;
-extern int merror;
-
-static void
-mtherr (name, code)
-     const char *name;
-     int code;
-{
-  /* The string passed by the calling program is supposed to be the
-     name of the function in which the error occurred.
-     The code argument selects which error message string will be printed.  */
-
-  if (strcmp (name, "esub") == 0)
-    name = "subtraction";
-  else if (strcmp (name, "ediv") == 0)
-    name = "division";
-  else if (strcmp (name, "emul") == 0)
-    name = "multiplication";
-  else if (strcmp (name, "enormlz") == 0)
-    name = "normalization";
-  else if (strcmp (name, "etoasc") == 0)
-    name = "conversion to text";
-  else if (strcmp (name, "asctoe") == 0)
-    name = "parsing";
-  else if (strcmp (name, "eremain") == 0)
-    name = "modulus";
-  else if (strcmp (name, "esqrt") == 0)
-    name = "square root";
-  if (extra_warnings)
-    {
-      switch (code)
        {
-       case DOMAIN:    warning ("%s: argument domain error"    , name); break;
-       case SING:      warning ("%s: function singularity"     , name); break;
-       case OVERFLOW:  warning ("%s: overflow range error"     , name); break;
-       case UNDERFLOW: warning ("%s: underflow range error"    , name); break;
-       case TLOSS:     warning ("%s: total loss of precision"  , name); break;
-       case PLOSS:     warning ("%s: partial loss of precision", name); break;
-       case INVALID:   warning ("%s: NaN - producing operation", name); break;
-       default:        abort ();
+         image0 = r->sig[SIGSZ-1];
+         image1 = r->sig[SIGSZ-2];
+         image1 = (image0 << 24) | (image1 >> 8);
+         image0 = (image0 >> 8) & 0xffffff;
        }
-    }
-
-  /* Set global error message word */
-  merror = code + 1;
-}
-
-#ifdef DEC
-/* Convert DEC double precision D to e type E.  */
-
-static void
-dectoe (d, e)
-     unsigned EMUSHORT *d;
-     unsigned EMUSHORT *e;
-{
-  unsigned EMUSHORT y[NI];
-  register unsigned EMUSHORT r, *p;
-
-  ecleaz (y);                  /* start with a zero */
-  p = y;                       /* point to our number */
-  r = *d;                      /* get DEC exponent word */
-  if (*d & (unsigned int) 0x8000)
-    *p = 0xffff;               /* fill in our sign */
-  ++p;                         /* bump pointer to our exponent word */
-  r &= 0x7fff;                 /* strip the sign bit */
-  if (r == 0)                  /* answer = 0 if high order DEC word = 0 */
-    goto done;
-
-
-  r >>= 7;                     /* shift exponent word down 7 bits */
-  r += EXONE - 0201;           /* subtract DEC exponent offset */
-  /* add our e type exponent offset */
-  *p++ = r;                    /* to form our exponent */
-
-  r = *d++;                    /* now do the high order mantissa */
-  r &= 0177;                   /* strip off the DEC exponent and sign bits */
-  r |= 0200;                   /* the DEC understood high order mantissa bit */
-  *p++ = r;                    /* put result in our high guard word */
-
-  *p++ = *d++;                 /* fill in the rest of our mantissa */
-  *p++ = *d++;
-  *p = *d;
-
-  eshdn8 (y);                  /* shift our mantissa down 8 bits */
- done:
-  emovo (y, e);
-}
-
-/* Convert e type X to DEC double precision D.  */
 
-static void
-etodec (x, d)
-     unsigned EMUSHORT *x, *d;
-{
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
-
-  emovi (x, xi);
-  /* Adjust exponent for offsets.  */
-  exp = (EMULONG) xi[E] - (EXONE - 0201);
-  /* Round off to nearest or even.  */
-  rndsav = rndprc;
-  rndprc = 56;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-  todec (xi, d);
-}
+      /* Rearrange the half-words of the significand to match the
+        external format.  */
+      image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff007f;
+      image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
 
-/* Convert exploded e-type X, that has already been rounded to
-   56-bit precision, to DEC format double Y.  */
+      /* Add the sign and exponent.  */
+      image0 |= sign;
+      image0 |= (r->exp + 128) << 7;
+      break;
 
-static void
-todec (x, y)
-     unsigned EMUSHORT *x, *y;
-{
-  unsigned EMUSHORT i;
-  unsigned EMUSHORT *p;
-
-  p = x;
-  *y = 0;
-  if (*p++)
-    *y = 0100000;
-  i = *p++;
-  if (i == 0)
-    {
-      *y++ = 0;
-      *y++ = 0;
-      *y++ = 0;
-      *y++ = 0;
-      return;
-    }
-  if (i > 0377)
-    {
-      *y++ |= 077777;
-      *y++ = 0xffff;
-      *y++ = 0xffff;
-      *y++ = 0xffff;
-#ifdef ERANGE
-      errno = ERANGE;
-#endif
-      return;
+    default:
+      abort ();
     }
-  i &= 0377;
-  i <<= 7;
-  eshup8 (x);
-  x[M] &= 0177;
-  i |= x[M];
-  *y++ |= i;
-  *y++ = x[M + 1];
-  *y++ = x[M + 2];
-  *y++ = x[M + 3];
-}
-#endif /* DEC */
 
-#ifdef IBM
-/* Convert IBM single/double precision to e type.  */
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = image1, buf[1] = image0;
+  else
+    buf[0] = image0, buf[1] = image1;
+}
 
 static void
-ibmtoe (d, e, mode)
-     unsigned EMUSHORT *d;
-     unsigned EMUSHORT *e;
-     enum machine_mode mode;
+decode_vax_d (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  unsigned EMUSHORT y[NI];
-  register unsigned EMUSHORT r, *p;
-
-  ecleaz (y);                  /* start with a zero */
-  p = y;                       /* point to our number */
-  r = *d;                      /* get IBM exponent word */
-  if (*d & (unsigned int) 0x8000)
-    *p = 0xffff;               /* fill in our sign */
-  ++p;                         /* bump pointer to our exponent word */
-  r &= 0x7f00;                 /* strip the sign bit */
-  r >>= 6;                     /* shift exponent word down 6 bits */
-                               /* in fact shift by 8 right and 2 left */
-  r += EXONE - (0x41 << 2);    /* subtract IBM exponent offset */
-                               /* add our e type exponent offset */
-  *p++ = r;                    /* to form our exponent */
-
-  *p++ = *d++ & 0xff;          /* now do the high order mantissa */
-                               /* strip off the IBM exponent and sign bits */
-  if (mode != SFmode)          /* there are only 2 words in SFmode */
-    {
-      *p++ = *d++;             /* fill in the rest of our mantissa */
-      *p++ = *d++;
-    }
-  *p = *d;
+  unsigned long image0, image1;
+  int exp;
 
-  if (y[M] == 0 && y[M+1] == 0 && y[M+2] == 0 && y[M+3] == 0)
-    y[0] = y[E] = 0;
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    image1 = buf[0], image0 = buf[1];
   else
-    y[E] -= 5 + enormlz (y);   /* now normalise the mantissa */
-                             /* handle change in RADIX */
-  emovo (y, e);
-}
+    image0 = buf[0], image1 = buf[1];
+  image0 &= 0xffffffff;
+  image1 &= 0xffffffff;
 
+  exp = (image0 >> 7) & 0x7f;
 
+  memset (r, 0, sizeof (*r));
 
-/* Convert e type to IBM single/double precision.  */
+  if (exp != 0)
+    {
+      r->class = rvc_normal;
+      r->sign = (image0 >> 15) & 1;
+      r->exp = exp - 128;
 
-static void
-etoibm (x, d, mode)
-     unsigned EMUSHORT *x, *d;
-     enum machine_mode mode;
-{
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
-
-  emovi (x, xi);
-  exp = (EMULONG) xi[E] - (EXONE - (0x41 << 2));       /* adjust exponent for offsets */
-                                                       /* round off to nearest or even */
-  rndsav = rndprc;
-  rndprc = 56;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-  toibm (xi, d, mode);
-}
+      /* Rearrange the half-words of the external format into
+        proper ascending order.  */
+      image0 = ((image0 & 0x7f) << 16) | ((image0 >> 16) & 0xffff);
+      image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
 
-static void
-toibm (x, y, mode)
-     unsigned EMUSHORT *x, *y;
-     enum machine_mode mode;
-{
-  unsigned EMUSHORT i;
-  unsigned EMUSHORT *p;
-  int r;
-
-  p = x;
-  *y = 0;
-  if (*p++)
-    *y = 0x8000;
-  i = *p++;
-  if (i == 0)
-    {
-      *y++ = 0;
-      *y++ = 0;
-      if (mode != SFmode)
+      if (HOST_BITS_PER_LONG == 64)
        {
-         *y++ = 0;
-         *y++ = 0;
+         image0 = (image0 << 31 << 1) | image1;
+         image0 <<= 64 - 56;
+         image0 |= SIG_MSB;
+         r->sig[SIGSZ-1] = image0;
        }
-      return;
-    }
-  r = i & 0x3;
-  i >>= 2;
-  if (i > 0x7f)
-    {
-      *y++ |= 0x7fff;
-      *y++ = 0xffff;
-      if (mode != SFmode)
+      else
        {
-         *y++ = 0xffff;
-         *y++ = 0xffff;
+         r->sig[SIGSZ-1] = image0;
+         r->sig[SIGSZ-2] = image1;
+         lshift_significand (r, r, 2*HOST_BITS_PER_LONG - 56);
+         r->sig[SIGSZ-1] |= SIG_MSB;
        }
-#ifdef ERANGE
-      errno = ERANGE;
-#endif
-      return;
-    }
-  i &= 0x7f;
-  *y |= (i << 8);
-  eshift (x, r + 5);
-  *y++ |= x[M];
-  *y++ = x[M + 1];
-  if (mode != SFmode)
-    {
-      *y++ = x[M + 2];
-      *y++ = x[M + 3];
     }
 }
-#endif /* IBM */
-
-
-#ifdef C4X
-/* Convert C4X single/double precision to e type.  */
 
 static void
-c4xtoe (d, e, mode)
-     unsigned EMUSHORT *d;
-     unsigned EMUSHORT *e;
-     enum machine_mode mode;
+encode_vax_g (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  unsigned EMUSHORT y[NI];
-  int r;
-  int isnegative;
-  int size;
-  int i;
-  int carry;
+  unsigned long image0, image1, sign = r->sign << 15;
 
-  /* Short-circuit the zero case. */
-  if ((d[0] == 0x8000)
-      && (d[1] == 0x0000)
-      && ((mode == QFmode) || ((d[2] == 0x0000) && (d[3] == 0x0000))))
+  switch (r->class)
     {
-      e[0] = 0;
-      e[1] = 0;
-      e[2] = 0;
-      e[3] = 0;
-      e[4] = 0;
-      e[5] = 0;
-      return;
-    }
-
-  ecleaz (y);                  /* start with a zero */
-  r = d[0];                    /* get sign/exponent part */
-  if (r & (unsigned int) 0x0080)
-  {
-     y[0] = 0xffff;            /* fill in our sign */
-     isnegative = TRUE;
-  }
-  else
-  {
-     isnegative = FALSE;
-  }
+    case rvc_zero:
+      image0 = image1 = 0;
+      break;
 
-  r >>= 8;                     /* Shift exponent word down 8 bits.  */
-  if (r & 0x80)                        /* Make the exponent negative if it is. */
-  {
-     r = r | (~0 & ~0xff);
-  }
+    case rvc_inf:
+    case rvc_nan:
+      image0 = 0xffff7fff | sign;
+      image1 = 0xffffffff;
+      break;
 
-  if (isnegative)
-  {
-     /* Now do the high order mantissa.  We don't "or" on the high bit
-       because it is 2 (not 1) and is handled a little differently
-       below.  */
-     y[M] = d[0] & 0x7f;
-
-     y[M+1] = d[1];
-     if (mode != QFmode)       /* There are only 2 words in QFmode.  */
-     {
-       y[M+2] = d[2];          /* Fill in the rest of our mantissa.  */
-       y[M+3] = d[3];
-       size = 4;
-     }
-     else
-     {
-       size = 2;
-     }
-     eshift(y, -8);
-
-     /* Now do the two's complement on the data.  */
-
-     carry = 1;        /* Initially add 1 for the two's complement. */
-     for (i=size + M; i > M; i--)
-     {
-       if (carry && (y[i] == 0x0000))
+    case rvc_normal:
+      /* Extract the significand into straight hi:lo.  */
+      if (HOST_BITS_PER_LONG == 64)
        {
-          /* We overflowed into the next word, carry is the same.  */
-          y[i] = carry ? 0x0000 : 0xffff;
+         image0 = r->sig[SIGSZ-1];
+         image1 = (image0 >> (64 - 53)) & 0xffffffff;
+         image0 = (image0 >> (64 - 53 + 1) >> 31) & 0xfffff;
        }
-       else
+      else
        {
-          /* No overflow, just invert and add carry.  */
-          y[i] = ((~y[i]) + carry) & 0xffff;
-          carry = 0;
+         image0 = r->sig[SIGSZ-1];
+         image1 = r->sig[SIGSZ-2];
+         image1 = (image0 << 21) | (image1 >> 11);
+         image0 = (image0 >> 11) & 0xfffff;
        }
-     }
-
-     if (carry)
-     {
-       eshift(y, -1);
-       y[M+1] |= 0x8000;
-       r++;
-     }
-     y[1] = r + EXONE;
-  }
-  else
-  {
-    /* Add our e type exponent offset to form our exponent.  */
-     r += EXONE;
-     y[1] = r;
-
-     /* Now do the high order mantissa strip off the exponent and sign
-       bits and add the high 1 bit.  */
-     y[M] = (d[0] & 0x7f) | 0x80;
-
-     y[M+1] = d[1];
-     if (mode != QFmode)       /* There are only 2 words in QFmode.  */
-     {
-       y[M+2] = d[2];          /* Fill in the rest of our mantissa.  */
-       y[M+3] = d[3];
-     }
-     eshift(y, -8);
-  }
-
-  emovo (y, e);
-}
-
-
-/* Convert e type to C4X single/double precision.  */
 
-static void
-etoc4x (x, d, mode)
-     unsigned EMUSHORT *x, *d;
-     enum machine_mode mode;
-{
-  unsigned EMUSHORT xi[NI];
-  EMULONG exp;
-  int rndsav;
+      /* Rearrange the half-words of the significand to match the
+        external format.  */
+      image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff000f;
+      image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
 
-  emovi (x, xi);
+      /* Add the sign and exponent.  */
+      image0 |= sign;
+      image0 |= (r->exp + 1024) << 4;
+      break;
 
-  /* Adjust exponent for offsets. */
-  exp = (EMULONG) xi[E] - (EXONE - 0x7f);
+    default:
+      abort ();
+    }
 
-  /* Round off to nearest or even. */
-  rndsav = rndprc;
-  rndprc = mode == QFmode ? 24 : 32;
-  emdnorm (xi, 0, 0, exp, 64);
-  rndprc = rndsav;
-  toc4x (xi, d, mode);
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = image1, buf[1] = image0;
+  else
+    buf[0] = image0, buf[1] = image1;
 }
 
 static void
-toc4x (x, y, mode)
-     unsigned EMUSHORT *x, *y;
-     enum machine_mode mode;
+decode_vax_g (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  int i;
-  int v;
-  int carry;
-
-  /* Short-circuit the zero case */
-  if ((x[0] == 0)      /* Zero exponent and sign */
-      && (x[1] == 0)
-      && (x[M] == 0)   /* The rest is for zero mantissa */
-      && (x[M+1] == 0)
-      /* Only check for double if necessary */
-      && ((mode == QFmode) || ((x[M+2] == 0) && (x[M+3] == 0))))
-    {
-      /* We have a zero.  Put it into the output and return. */
-      *y++ = 0x8000;
-      *y++ = 0x0000;
-      if (mode != QFmode)
-        {
-          *y++ = 0x0000;
-          *y++ = 0x0000;
-        }
-      return;
-    }
-
-  *y = 0;
-
-  /* Negative number require a two's complement conversion of the
-     mantissa. */
-  if (x[0])
-    {
-      *y = 0x0080;
-
-      i = ((int) x[1]) - 0x7f;
-
-      /* Now add 1 to the inverted data to do the two's complement. */
-      if (mode != QFmode)
-       v = 4 + M;
-      else
-       v = 2 + M;
-      carry = 1;
-      while (v > M)
-       {
-         if (x[v] == 0x0000)
-           {
-             x[v] = carry ? 0x0000 : 0xffff;
-           }
-         else
-           {
-             x[v] = ((~x[v]) + carry) & 0xffff;
-             carry = 0;
-           }
-         v--;
-       }
-
-      /* The following is a special case.  The C4X negative float requires
-        a zero in the high bit (because the format is (2 - x) x 2^m), so
-        if a one is in that bit, we have to shift left one to get rid
-        of it.  This only occurs if the number is -1 x 2^m. */
-      if (x[M+1] & 0x8000)
-       {
-         /* This is the case of -1 x 2^m, we have to rid ourselves of the
-            high sign bit and shift the exponent. */
-         eshift(x, 1);
-         i--;
-       }
-    }
-  else
-    {
-      i = ((int) x[1]) - 0x7f;
-    }
+  unsigned long image0, image1;
+  int exp;
 
-  if ((i < -128) || (i > 127))
-    {
-      y[0] |= 0xff7f;
-      y[1] = 0xffff;
-      if (mode != QFmode)
-       {
-         y[2] = 0xffff;
-         y[3] = 0xffff;
-       }
-#ifdef ERANGE
-      errno = ERANGE;
-#endif
-      return;
-    }
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    image1 = buf[0], image0 = buf[1];
+  else
+    image0 = buf[0], image1 = buf[1];
+  image0 &= 0xffffffff;
+  image1 &= 0xffffffff;
 
-  y[0] |= ((i & 0xff) << 8);
+  exp = (image0 >> 4) & 0x7ff;
 
-  eshift (x, 8);
+  memset (r, 0, sizeof (*r));
 
-  y[0] |= x[M] & 0x7f;
-  y[1] = x[M + 1];
-  if (mode != QFmode)
+  if (exp != 0)
     {
-      y[2] = x[M + 2];
-      y[3] = x[M + 3];
-    }
-}
-#endif /* C4X */
-
-/* Output a binary NaN bit pattern in the target machine's format.  */
-
-/* If special NaN bit patterns are required, define them in tm.h
-   as arrays of unsigned 16-bit shorts.  Otherwise, use the default
-   patterns here.  */
-#ifdef TFMODE_NAN
-TFMODE_NAN;
-#else
-#ifdef IEEE
-unsigned EMUSHORT TFbignan[8] =
- {0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
-unsigned EMUSHORT TFlittlenan[8] = {0, 0, 0, 0, 0, 0, 0x8000, 0xffff};
-#endif
-#endif
-
-#ifdef XFMODE_NAN
-XFMODE_NAN;
-#else
-#ifdef IEEE
-unsigned EMUSHORT XFbignan[6] =
- {0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
-unsigned EMUSHORT XFlittlenan[6] = {0, 0, 0, 0xc000, 0xffff, 0};
-#endif
-#endif
+      r->class = rvc_normal;
+      r->sign = (image0 >> 15) & 1;
+      r->exp = exp - 1024;
 
-#ifdef DFMODE_NAN
-DFMODE_NAN;
-#else
-#ifdef IEEE
-unsigned EMUSHORT DFbignan[4] = {0x7fff, 0xffff, 0xffff, 0xffff};
-unsigned EMUSHORT DFlittlenan[4] = {0, 0, 0, 0xfff8};
-#endif
-#endif
+      /* Rearrange the half-words of the external format into
+        proper ascending order.  */
+      image0 = ((image0 & 0xf) << 16) | ((image0 >> 16) & 0xffff);
+      image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
 
-#ifdef SFMODE_NAN
-SFMODE_NAN;
-#else
-#ifdef IEEE
-unsigned EMUSHORT SFbignan[2] = {0x7fff, 0xffff};
-unsigned EMUSHORT SFlittlenan[2] = {0, 0xffc0};
-#endif
-#endif
+      if (HOST_BITS_PER_LONG == 64)
+       {
+         image0 = (image0 << 31 << 1) | image1;
+         image0 <<= 64 - 53;
+         image0 |= SIG_MSB;
+         r->sig[SIGSZ-1] = image0;
+       }
+      else
+       {
+         r->sig[SIGSZ-1] = image0;
+         r->sig[SIGSZ-2] = image1;
+         lshift_significand (r, r, 64 - 53);
+         r->sig[SIGSZ-1] |= SIG_MSB;
+       }
+    }
+}
 
+const struct real_format vax_f_format = 
+  {
+    encode_vax_f,
+    decode_vax_f,
+    2,
+    1,
+    24,
+    24,
+    -127,
+    127,
+    15,
+    false,
+    false,
+    false,
+    false,
+    false
+  };
+
+const struct real_format vax_d_format = 
+  {
+    encode_vax_d,
+    decode_vax_d,
+    2,
+    1,
+    56,
+    56,
+    -127,
+    127,
+    15,
+    false,
+    false,
+    false,
+    false,
+    false
+  };
+
+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
+/* 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 REAL_VALUE_TYPE *));
+static void decode_i370_single PARAMS ((const struct real_format *,
+                                       REAL_VALUE_TYPE *, const long *));
+static void encode_i370_double PARAMS ((const struct real_format *fmt,
+                                       long *, const REAL_VALUE_TYPE *));
+static void decode_i370_double PARAMS ((const struct real_format *,
+                                       REAL_VALUE_TYPE *, const long *));
 
-#ifdef NANS
 static void
-make_nan (nan, sign, mode)
-     unsigned EMUSHORT *nan;
-     int sign;
-     enum machine_mode mode;
+encode_i370_single (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  int n;
-  unsigned EMUSHORT *p;
+  unsigned long sign, exp, sig, image;
 
-  switch (mode)
-    {
-/* Possibly the `reserved operand' patterns on a VAX can be
-   used like NaN's, but probably not in the same way as IEEE.  */
-#if !defined(DEC) && !defined(IBM) && !defined(C4X)
-    case TFmode:
-      n = 8;
-      if (REAL_WORDS_BIG_ENDIAN)
-       p = TFbignan;
-      else
-       p = TFlittlenan;
-      break;
+  sign = r->sign << 31;
 
-    case XFmode:
-      n = 6;
-      if (REAL_WORDS_BIG_ENDIAN)
-       p = XFbignan;
-      else
-       p = XFlittlenan;
+  switch (r->class)
+    {
+    case rvc_zero:
+      image = 0;
       break;
 
-    case DFmode:
-      n = 4;
-      if (REAL_WORDS_BIG_ENDIAN)
-       p = DFbignan;
-      else
-       p = DFlittlenan;
+    case rvc_inf:
+    case rvc_nan:
+      image = 0x7fffffff | sign;
       break;
 
-    case SFmode:
-    case HFmode:
-      n = 2;
-      if (REAL_WORDS_BIG_ENDIAN)
-       p = SFbignan;
-      else
-       p = SFlittlenan;
+    case rvc_normal:
+      sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0xffffff;
+      exp = ((r->exp / 4) + 64) << 24;
+      image = sign | exp | sig;
       break;
-#endif
 
     default:
       abort ();
     }
-  if (REAL_WORDS_BIG_ENDIAN)
-    *nan++ = (sign << 15) | (*p++ & 0x7fff);
-  while (--n != 0)
-    *nan++ = *p++;
-  if (! REAL_WORDS_BIG_ENDIAN)
-    *nan = (sign << 15) | (*p & 0x7fff);
-}
-#endif /* NANS */
 
-/* This is the inverse of the function `etarsingle' invoked by
-   REAL_VALUE_TO_TARGET_SINGLE.  */
+  buf[0] = image;
+}
 
-REAL_VALUE_TYPE
-ereal_unto_float (f)
-     long f;
+static void
+decode_i370_single (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  REAL_VALUE_TYPE r;
-  unsigned EMUSHORT s[2];
-  unsigned EMUSHORT e[NE];
+  unsigned long sign, sig, image = buf[0];
+  int exp;
 
-  /* Convert 32 bit integer to array of 16 bit pieces in target machine order.
-   This is the inverse operation to what the function `endian' does.  */
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      s[0] = (unsigned EMUSHORT) (f >> 16);
-      s[1] = (unsigned EMUSHORT) f;
-    }
-  else
+  sign = (image >> 31) & 1;
+  exp = (image >> 24) & 0x7f;
+  sig = image & 0xffffff;
+
+  memset (r, 0, sizeof (*r));
+
+  if (exp || sig)
     {
-      s[0] = (unsigned EMUSHORT) f;
-      s[1] = (unsigned EMUSHORT) (f >> 16);
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = (exp - 64) * 4;
+      r->sig[SIGSZ-1] = sig << (HOST_BITS_PER_LONG - 24);
+      normalize (r);
     }
-  /* Convert and promote the target float to E-type. */
-  e24toe (s, e);
-  /* Output E-type to REAL_VALUE_TYPE. */
-  PUT_REAL (e, &r);
-  return r;
 }
 
-
-/* This is the inverse of the function `etardouble' invoked by
-   REAL_VALUE_TO_TARGET_DOUBLE.  */
-
-REAL_VALUE_TYPE
-ereal_unto_double (d)
-     long d[];
+static void
+encode_i370_double (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
 {
-  REAL_VALUE_TYPE r;
-  unsigned EMUSHORT s[4];
-  unsigned EMUSHORT e[NE];
+  unsigned long sign, exp, image_hi, image_lo;
 
-  /* Convert array of HOST_WIDE_INT to equivalent array of 16-bit pieces.  */
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      s[0] = (unsigned EMUSHORT) (d[0] >> 16);
-      s[1] = (unsigned EMUSHORT) d[0];
-      s[2] = (unsigned EMUSHORT) (d[1] >> 16);
-      s[3] = (unsigned EMUSHORT) d[1];
-    }
-  else
+  sign = r->sign << 31;
+
+  switch (r->class)
     {
-      /* Target float words are little-endian.  */
-      s[0] = (unsigned EMUSHORT) d[0];
-      s[1] = (unsigned EMUSHORT) (d[0] >> 16);
-      s[2] = (unsigned EMUSHORT) d[1];
-      s[3] = (unsigned EMUSHORT) (d[1] >> 16);
-    }
-  /* Convert target double to E-type. */
-  e53toe (s, e);
-  /* Output E-type to REAL_VALUE_TYPE. */
-  PUT_REAL (e, &r);
-  return r;
-}
+    case rvc_zero:
+      image_hi = image_lo = 0;
+      break;
 
+    case rvc_inf:
+    case rvc_nan:
+      image_hi = 0x7fffffff | sign;
+      image_lo = 0xffffffff;
+      break;
 
-/* Convert an SFmode target `float' value to a REAL_VALUE_TYPE.
-   This is somewhat like ereal_unto_float, but the input types
-   for these are different.  */
+    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;
+       }
 
-REAL_VALUE_TYPE
-ereal_from_float (f)
-     HOST_WIDE_INT f;
-{
-  REAL_VALUE_TYPE r;
-  unsigned EMUSHORT s[2];
-  unsigned EMUSHORT e[NE];
+      exp = ((r->exp / 4) + 64) << 24;
+      image_hi |= sign | exp;
+      break;
 
-  /* Convert 32 bit integer to array of 16 bit pieces in target machine order.
-   This is the inverse operation to what the function `endian' does.  */
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-      s[0] = (unsigned EMUSHORT) (f >> 16);
-      s[1] = (unsigned EMUSHORT) f;
+    default:
+      abort ();
     }
+
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = image_hi, buf[1] = image_lo;
   else
-    {
-      s[0] = (unsigned EMUSHORT) f;
-      s[1] = (unsigned EMUSHORT) (f >> 16);
-    }
-  /* Convert and promote the target float to E-type.  */
-  e24toe (s, e);
-  /* Output E-type to REAL_VALUE_TYPE.  */
-  PUT_REAL (e, &r);
-  return r;
+    buf[0] = image_lo, buf[1] = image_hi;
 }
 
+static void
+decode_i370_double (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+{
+  unsigned long sign, image_hi, image_lo;
+  int exp;
 
-/* Convert a DFmode target `double' value to a REAL_VALUE_TYPE.
-   This is somewhat like ereal_unto_double, but the input types
-   for these are different.
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    image_hi = buf[0], image_lo = buf[1];
+  else
+    image_lo = buf[0], image_hi = buf[1];
 
-   The DFmode is stored as an array of HOST_WIDE_INT in the target's
-   data format, with no holes in the bit packing.  The first element
-   of the input array holds the bits that would come first in the
-   target computer's memory.  */
+  sign = (image_hi >> 31) & 1;
+  exp = (image_hi >> 24) & 0x7f;
+  image_hi &= 0xffffff;
+  image_lo &= 0xffffffff;
 
-REAL_VALUE_TYPE
-ereal_from_double (d)
-     HOST_WIDE_INT d[];
-{
-  REAL_VALUE_TYPE r;
-  unsigned EMUSHORT s[4];
-  unsigned EMUSHORT e[NE];
+  memset (r, 0, sizeof (*r));
 
-  /* Convert array of HOST_WIDE_INT to equivalent array of 16-bit pieces.  */
-  if (REAL_WORDS_BIG_ENDIAN)
-    {
-#if HOST_BITS_PER_WIDE_INT == 32
-      s[0] = (unsigned EMUSHORT) (d[0] >> 16);
-      s[1] = (unsigned EMUSHORT) d[0];
-      s[2] = (unsigned EMUSHORT) (d[1] >> 16);
-      s[3] = (unsigned EMUSHORT) d[1];
-#else
-      /* In this case the entire target double is contained in the
-        first array element.  The second element of the input is
-        ignored.  */
-      s[0] = (unsigned EMUSHORT) (d[0] >> 48);
-      s[1] = (unsigned EMUSHORT) (d[0] >> 32);
-      s[2] = (unsigned EMUSHORT) (d[0] >> 16);
-      s[3] = (unsigned EMUSHORT) d[0];
-#endif
-    }
-  else
+  if (exp || image_hi || image_lo)
     {
-      /* Target float words are little-endian.  */
-      s[0] = (unsigned EMUSHORT) d[0];
-      s[1] = (unsigned EMUSHORT) (d[0] >> 16);
-#if HOST_BITS_PER_WIDE_INT == 32
-      s[2] = (unsigned EMUSHORT) d[1];
-      s[3] = (unsigned EMUSHORT) (d[1] >> 16);
-#else
-      s[2] = (unsigned EMUSHORT) (d[0] >> 32);
-      s[3] = (unsigned EMUSHORT) (d[0] >> 48);
-#endif
+      r->class = rvc_normal;
+      r->sign = sign;
+      r->exp = (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);
     }
-  /* Convert target double to E-type.  */
-  e53toe (s, e);
-  /* Output E-type to REAL_VALUE_TYPE.  */
-  PUT_REAL (e, &r);
-  return r;
 }
 
+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".  */
+    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,
+    false,
+    false,
+    false, /* ??? The encoding does allow for "unnormals".  */
+    false, /* ??? The encoding does allow for "unnormals".  */
+    false
+  };
+\f
+/* The "twos-complement" c4x format is officially defined as
+
+       x = s(~s).f * 2**e
 
-#if 0
-/* Convert target computer unsigned 64-bit integer to e-type.
-   The endian-ness of DImode follows the convention for integers,
-   so we use WORDS_BIG_ENDIAN here, not REAL_WORDS_BIG_ENDIAN.  */
+   This is rather misleading.  One must remember that F is signed.
+   A better description would be
 
-static void
-uditoe (di, e)
-     unsigned EMUSHORT *di;  /* Address of the 64-bit int.  */
-     unsigned EMUSHORT *e;
-{
-  unsigned EMUSHORT yi[NI];
-  int k;
+       x = -1**s * ((s + 1 + .f) * 2**e
 
-  ecleaz (yi);
-  if (WORDS_BIG_ENDIAN)
-    {
-      for (k = M; k < M + 4; k++)
-       yi[k] = *di++;
-    }
-  else
-    {
-      for (k = M + 3; k >= M; k--)
-       yi[k] = *di++;
-    }
-  yi[E] = EXONE + 47;  /* exponent if normalize shift count were 0 */
-  if ((k = enormlz (yi)) > NBITS)/* normalize the significand */
-    ecleaz (yi);               /* it was zero */
-  else
-    yi[E] -= (unsigned EMUSHORT) k;/* subtract shift count from exponent */
-  emovo (yi, 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  */
 
-/* Convert target computer signed 64-bit integer to e-type.  */
+static void encode_c4x_single PARAMS ((const struct real_format *fmt,
+                                      long *, const REAL_VALUE_TYPE *));
+static void decode_c4x_single PARAMS ((const struct real_format *,
+                                      REAL_VALUE_TYPE *, const long *));
+static void encode_c4x_extended PARAMS ((const struct real_format *fmt,
+                                        long *, const REAL_VALUE_TYPE *));
+static void decode_c4x_extended PARAMS ((const struct real_format *,
+                                        REAL_VALUE_TYPE *, const long *));
 
 static void
-ditoe (di, e)
-     unsigned EMUSHORT *di;  /* Address of the 64-bit int.  */
-     unsigned EMUSHORT *e;
-{
-  unsigned EMULONG acc;
-  unsigned EMUSHORT yi[NI];
-  unsigned EMUSHORT carry;
-  int k, sign;
+encode_c4x_single (fmt, buf, r)
+     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:
+      exp = -128;
+      sig = 0;
+      break;
 
-  ecleaz (yi);
-  if (WORDS_BIG_ENDIAN)
-    {
-      for (k = M; k < M + 4; k++)
-       yi[k] = *di++;
-    }
-  else
-    {
-      for (k = M + 3; k >= M; k--)
-       yi[k] = *di++;
-    }
-  /* Take absolute value */
-  sign = 0;
-  if (yi[M] & 0x8000)
-    {
-      sign = 1;
-      carry = 0;
-      for (k = M + 3; k >= M; k--)
+    case rvc_inf:
+    case rvc_nan:
+      exp = 127;
+      sig = 0x800000 - r->sign;
+      break;
+
+    case rvc_normal:
+      exp = r->exp - 1;
+      sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
+      if (r->sign)
        {
-         acc = (unsigned EMULONG) (~yi[k] & 0xffff) + carry;
-         yi[k] = acc;
-         carry = 0;
-         if (acc & 0x10000)
-           carry = 1;
+         if (sig)
+           sig = -sig;
+         else
+           exp--;
+         sig |= 0x800000;
        }
-    }
-  yi[E] = EXONE + 47;  /* exponent if normalize shift count were 0 */
-  if ((k = enormlz (yi)) > NBITS)/* normalize the significand */
-    ecleaz (yi);               /* it was zero */
-  else
-    yi[E] -= (unsigned EMUSHORT) k;/* subtract shift count from exponent */
-  emovo (yi, e);
-  if (sign)
-       eneg (e);
-}
+      break;
 
+    default:
+      abort ();
+    }
 
-/* Convert e-type to unsigned 64-bit int.  */
+  image = ((exp & 0xff) << 24) | (sig & 0xffffff);
+  buf[0] = image;
+}
 
 static void
-etoudi (x, i)
-     unsigned EMUSHORT *x;
-     unsigned EMUSHORT *i;
+decode_c4x_single (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  unsigned EMUSHORT xi[NI];
-  int j, k;
+  unsigned long image = buf[0];
+  unsigned long sig;
+  int exp, sf;
 
-  emovi (x, xi);
-  if (xi[0])
-    {
-      xi[M] = 0;
-      goto noshift;
-    }
-  k = (int) xi[E] - (EXONE - 1);
-  if (k <= 0)
-    {
-      for (j = 0; j < 4; j++)
-       *i++ = 0;
-      return;
-    }
-  if (k > 64)
-    {
-      for (j = 0; j < 4; j++)
-       *i++ = 0xffff;
-      if (extra_warnings)
-       warning ("overflow on truncation to integer");
-      return;
-    }
-  if (k > 16)
+  exp = (((image >> 24) & 0xff) ^ 0x80) - 0x80;
+  sf = ((image & 0xffffff) ^ 0x800000) - 0x800000;
+
+  memset (r, 0, sizeof (*r));
+
+  if (exp != -128)
     {
-      /* Shift more than 16 bits: first shift up k-16 mod 16,
-        then shift up by 16's.  */
-      j = k - ((k >> 4) << 4);
-      if (j == 0)
-       j = 16;
-      eshift (xi, j);
-      if (WORDS_BIG_ENDIAN)
-       *i++ = xi[M];
-      else
-       {
-         i += 3;
-         *i-- = xi[M];
-       }
-      k -= j;
-      do
+      r->class = rvc_normal;
+
+      sig = sf & 0x7fffff;
+      if (sf < 0)
        {
-         eshup6 (xi);
-         if (WORDS_BIG_ENDIAN)
-           *i++ = xi[M];
+         r->sign = 1;
+         if (sig)
+           sig = -sig;
          else
-           *i-- = xi[M];
+           exp++;
        }
-      while ((k -= 16) > 0);
+      sig = (sig << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
+
+      r->exp = exp + 1;
+      r->sig[SIGSZ-1] = sig;
     }
-  else
-    {
-        /* shift not more than 16 bits */
-      eshift (xi, k);
+}
 
-noshift:
+static void
+encode_c4x_extended (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
+{
+  unsigned long exp, sig;
+  
+  switch (r->class)
+    {
+    case rvc_zero:
+      exp = -128;
+      sig = 0;
+      break;
 
-      if (WORDS_BIG_ENDIAN)
-       {
-         i += 3;
-         *i-- = xi[M];
-         *i-- = 0;
-         *i-- = 0;
-         *i = 0;
-       }
-      else
+    case rvc_inf:
+    case rvc_nan:
+      exp = 127;
+      sig = 0x80000000 - r->sign;
+      break;
+
+    case rvc_normal:
+      exp = r->exp - 1;
+
+      sig = r->sig[SIGSZ-1];
+      if (HOST_BITS_PER_LONG == 64)
+       sig = sig >> 1 >> 31;
+      sig &= 0x7fffffff;
+
+      if (r->sign)
        {
-         *i++ = xi[M];
-         *i++ = 0;
-         *i++ = 0;
-         *i = 0;
+         if (sig)
+           sig = -sig;
+         else
+           exp--;
+         sig |= 0x80000000;
        }
+      break;
+
+    default:
+      abort ();
     }
-}
 
+  exp = (exp & 0xff) << 24;
+  sig &= 0xffffffff;
 
-/* Convert e-type to signed 64-bit int.  */
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    buf[0] = exp, buf[1] = sig;
+  else
+    buf[0] = sig, buf[0] = exp;
+}
 
 static void
-etodi (x, i)
-     unsigned EMUSHORT *x;
-     unsigned EMUSHORT *i;
+decode_c4x_extended (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
 {
-  unsigned EMULONG acc;
-  unsigned EMUSHORT xi[NI];
-  unsigned EMUSHORT carry;
-  unsigned EMUSHORT *isave;
-  int j, k;
-
-  emovi (x, xi);
-  k = (int) xi[E] - (EXONE - 1);
-  if (k <= 0)
-    {
-      for (j = 0; j < 4; j++)
-       *i++ = 0;
-      return;
-    }
-  if (k > 64)
-    {
-      for (j = 0; j < 4; j++)
-       *i++ = 0xffff;
-      if (extra_warnings)
-       warning ("overflow on truncation to integer");
-      return;
-    }
-  isave = i;
-  if (k > 16)
-    {
-      /* Shift more than 16 bits: first shift up k-16 mod 16,
-        then shift up by 16's.  */
-      j = k - ((k >> 4) << 4);
-      if (j == 0)
-       j = 16;
-      eshift (xi, j);
-      if (WORDS_BIG_ENDIAN)
-       *i++ = xi[M];
-      else
-       {
-         i += 3;
-         *i-- = xi[M];
-       }
-      k -= j;
-      do
-       {
-         eshup6 (xi);
-         if (WORDS_BIG_ENDIAN)
-           *i++ = xi[M];
-         else
-           *i-- = xi[M];
-       }
-      while ((k -= 16) > 0);
-    }
+  unsigned long sig;
+  int exp, sf;
+
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    exp = buf[0], sf = buf[1];
   else
-    {
-        /* shift not more than 16 bits */
-      eshift (xi, k);
+    sf = buf[0], exp = buf[1];
 
-      if (WORDS_BIG_ENDIAN)
-       {
-         i += 3;
-         *i = xi[M];
-         *i-- = 0;
-         *i-- = 0;
-         *i = 0;
-       }
-      else
-       {
-         *i++ = xi[M];
-         *i++ = 0;
-         *i++ = 0;
-         *i = 0;
-       }
-    }
-  /* Negate if negative */
-  if (xi[0])
+  exp = (((exp >> 24) & 0xff) & 0x80) - 0x80;
+  sf = ((sf & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+  memset (r, 0, sizeof (*r));
+
+  if (exp != -128)
     {
-      carry = 0;
-      if (WORDS_BIG_ENDIAN)
-       isave += 3;
-      for (k = 0; k < 4; k++)
+      r->class = rvc_normal;
+
+      sig = sf & 0x7fffffff;
+      if (sf < 0)
        {
-         acc = (unsigned EMULONG) (~(*isave) & 0xffff) + carry;
-         if (WORDS_BIG_ENDIAN)
-           *isave-- = acc;
+         r->sign = 1;
+         if (sig)
+           sig = -sig;
          else
-           *isave++ = acc;
-         carry = 0;
-         if (acc & 0x10000)
-           carry = 1;
+           exp++;
        }
+      if (HOST_BITS_PER_LONG == 64)
+       sig = sig << 1 << 31;
+      sig |= SIG_MSB;
+
+      r->exp = 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,
+    -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,
+    -1,
+    false,
+    false,
+    false,
+    false,
+    false
+  };
 
-/* Longhand square root routine.  */
+\f
+/* A synthetic "format" for internal arithmetic.  It's the size of the
+   internal significand minus the two bits needed for proper rounding.
+   The encode and decode routines exist only to satisfy our paranoia
+   harness.  */
 
+static void encode_internal PARAMS ((const struct real_format *fmt,
+                                    long *, const REAL_VALUE_TYPE *));
+static void decode_internal PARAMS ((const struct real_format *,
+                                    REAL_VALUE_TYPE *, const long *));
 
-static int esqinited = 0;
-static unsigned short sqrndbit[NI];
+static void
+encode_internal (fmt, buf, r)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     long *buf;
+     const REAL_VALUE_TYPE *r;
+{
+  memcpy (buf, r, sizeof (*r));
+}
 
 static void
-esqrt (x, y)
-     unsigned EMUSHORT *x, *y;
+decode_internal (fmt, r, buf)
+     const struct real_format *fmt ATTRIBUTE_UNUSED;
+     REAL_VALUE_TYPE *r;
+     const long *buf;
+{
+  memcpy (r, buf, sizeof (*r));
+}
+
+const struct real_format real_internal_format = 
+  {
+    encode_internal,
+    decode_internal,
+    2,
+    1,
+    SIGNIFICAND_BITS - 2,
+    SIGNIFICAND_BITS - 2,
+    -MAX_EXP,
+    MAX_EXP,
+    -1,
+    true,
+    true,
+    false,
+    true,
+    true 
+  };
+\f
+/* Set up default mode to format mapping for IEEE.  Everyone else has
+   to set these values in OVERRIDE_OPTIONS.  */
+
+const struct real_format *real_format_for_mode[TFmode - QFmode + 1] =
+{
+  NULL,                                /* QFmode */
+  NULL,                                /* HFmode */
+  NULL,                                /* TQFmode */
+  &ieee_single_format,         /* SFmode */
+  &ieee_double_format,         /* DFmode */
+
+  /* We explicitly don't handle XFmode.  There are two formats,
+     pretty much equally common.  Choose one in OVERRIDE_OPTIONS.  */
+  NULL,                                /* XFmode */
+  &ieee_quad_format            /* TFmode */
+};
+
+\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 (r, mode, x)
+     REAL_VALUE_TYPE *r;
+     enum machine_mode mode;
+     const REAL_VALUE_TYPE *x;
 {
-  unsigned EMUSHORT temp[NI], num[NI], sq[NI], xx[NI];
-  EMULONG m, exp;
-  int i, j, k, n, nlups;
+  static REAL_VALUE_TYPE halfthree;
+  static bool init = false;
+  REAL_VALUE_TYPE h, t, i;
+  int iter, exp;
 
-  if (esqinited == 0)
+  /* sqrt(-0.0) is -0.0.  */
+  if (real_isnegzero (x))
     {
-      ecleaz (sqrndbit);
-      sqrndbit[NI - 2] = 1;
-      esqinited = 1;
+      *r = *x;
+      return false;
     }
-  /* Check for arg <= 0 */
-  i = ecmp (x, ezero);
-  if (i <= 0)
+
+  /* Negative arguments return NaN.  */
+  if (real_isneg (x))
     {
-      if (i == -1)
-       {
-         mtherr ("esqrt", DOMAIN);
-         eclear (y);
-       }
-      else
-       emov (x, y);
-      return;
+      /* Mode is ignored for canonical NaN.  */
+      real_nan (r, "", 1, SFmode);
+      return false;
     }
 
-#ifdef INFINITY
-  if (eisinf (x))
+  /* Infinity and NaN return themselves.  */
+  if (real_isinf (x) || real_isnan (x))
     {
-      eclear (y);
-      einfin (y);
-      return;
+      *r = *x;
+      return false;
     }
-#endif
-  /* Bring in the arg and renormalize if it is denormal.  */
-  emovi (x, xx);
-  m = (EMULONG) xx[1];         /* local long word exponent */
-  if (m == 0)
-    m -= enormlz (xx);
-
-  /* Divide exponent by 2 */
-  m -= 0x3ffe;
-  exp = (unsigned short) ((m / 2) + 0x3ffe);
-
-  /* Adjust if exponent odd */
-  if ((m & 1) != 0)
+
+  if (!init)
     {
-      if (m > 0)
-       exp += 1;
-      eshdn1 (xx);
+      do_add (&halfthree, &dconst1, &dconsthalf, 0);
+      init = true;
     }
 
-  ecleaz (sq);
-  ecleaz (num);
-  n = 8;                       /* get 8 bits of result per inner loop */
-  nlups = rndprc;
-  j = 0;
+  /* Initial guess for reciprocal sqrt, i.  */
+  exp = real_exponent (x);
+  real_ldexp (&i, &dconst1, -exp/2);
 
-  while (nlups > 0)
+  /* Newton's iteration for reciprocal sqrt, i.  */
+  for (iter = 0; iter < 16; iter++)
     {
-      /* bring in next word of arg */
-      if (j < NE)
-       num[NI - 1] = xx[j + 3];
-      /* Do additional bit on last outer loop, for roundoff.  */
-      if (nlups <= 8)
-       n = nlups + 1;
-      for (i = 0; i < n; i++)
-       {
-         /* Next 2 bits of arg */
-         eshup1 (num);
-         eshup1 (num);
-         /* Shift up answer */
-         eshup1 (sq);
-         /* Make trial divisor */
-         for (k = 0; k < NI; k++)
-           temp[k] = sq[k];
-         eshup1 (temp);
-         eaddm (sqrndbit, temp);
-         /* Subtract and insert answer bit if it goes in */
-         if (ecmpm (temp, num) <= 0)
-           {
-             esubm (temp, num);
-             sq[NI - 2] |= 1;
-           }
-       }
-      nlups -= n;
-      j += 1;
+      /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x).  */
+      do_multiply (&t, x, &i);
+      do_multiply (&h, &t, &i);
+      do_multiply (&t, &h, &dconsthalf);
+      do_add (&h, &halfthree, &t, 1);
+      do_multiply (&t, &i, &h);
+
+      /* Check for early convergence.  */
+      if (iter >= 6 && real_identical (&i, &t))
+       break;
+
+      /* ??? Unroll loop to avoid copying.  */
+      i = t;
     }
 
-  /* Adjust for extra, roundoff loop done.  */
-  exp += (NBITS - 1) - rndprc;
+  /* 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);
 
-  /* Sticky bit = 1 if the remainder is nonzero.  */
-  k = 0;
-  for (i = 3; i < NI; i++)
-    k |= (int) num[i];
+  /* ??? We need a Tuckerman test to get the last bit.  */
 
-  /* Renormalize and round off.  */
-  emdnorm (sq, k, 0, exp, 64);
-  emovo (sq, y);
+  real_convert (r, mode, &h);
+  return true;
 }
-#endif
-#endif /* EMU_NON_COMPILE not defined */
-\f
-/* Return the binary precision of the significand for a given
-   floating point mode.  The mode can hold an integer value
-   that many bits wide, without losing any bits.  */
-
-int
-significand_size (mode)
-     enum machine_mode mode;
-{
 
-/* Don't test the modes, but their sizes, lest this
-   code won't work for BITS_PER_UNIT != 8 .  */
+/* 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.  */
 
-switch (GET_MODE_BITSIZE (mode))
-  {
-  case 32:
+bool
+real_powi (r, mode, x, n)
+     REAL_VALUE_TYPE *r;
+     enum machine_mode mode;
+     const REAL_VALUE_TYPE *x;
+     HOST_WIDE_INT n;
+{
+  unsigned HOST_WIDE_INT bit;
+  REAL_VALUE_TYPE t;
+  bool inexact = false;
+  bool init = false;
+  bool neg;
+  int i;
 
-#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
-    return 56;
-#endif
+  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;
 
-    return 24;
-
-  case 64:
-#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-    return 53;
-#else
-#if TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT
-    return 56;
-#else
-#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-    return 56;
-#else
-#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
-    return 56;
-#else
-    abort ();
-#endif
-#endif
-#endif
-#endif
+  t = *x;
+  bit = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+  for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
+    {
+      if (init)
+       {
+         inexact |= do_multiply (&t, &t, &t);
+         if (n & bit)
+           inexact |= do_multiply (&t, &t, x);
+       }
+      else if (n & bit)
+       init = true;
+      bit >>= 1;
+    }
 
-  case 96:
-    return 64;
-  case 128:
-    return 113;
+  if (neg)
+    inexact |= do_divide (&t, &dconst1, &t);
 
-  default:
-    abort ();
-  }
+  real_convert (r, mode, &t);
+  return inexact;
 }
+