-/* real.c - implementation of REAL_ARITHMETIC, REAL_VALUE_ATOF,
- and support for XFmode IEEE extended real floating point arithmetic.
- Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+/* real.c - software floating point emulation.
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002,
+ 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Stephen L. Moshier (moshier@world.std.com).
+ Re-written by Richard Henderson <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 3, 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 COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
-#include "toplev.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. */
+#include "diagnostic-core.h"
+#include "real.h"
+#include "realmpfr.h"
+#include "tm_p.h"
+#include "dfp.h"
+
+/* The floating point model used internally is not exactly IEEE 754
+ compliant, and close to the description in the ISO C99 standard,
+ section 5.2.4.2.2 Characteristics of floating types.
+
+ Specifically
+
+ x = s * b^e * \sum_{k=1}^p f_k * b^{-k}
+
+ where
+ s = sign (+- 1)
+ b = base or radix, here always 2
+ e = exponent
+ p = precision (the number of base-b digits in the significand)
+ f_k = the digits of the significand.
+
+ We differ from typical IEEE 754 encodings in that the entire
+ significand is fractional. Normalized significands are in the
+ range [0.5, 1.0).
+
+ A requirement of the model is that P be larger than the largest
+ supported target floating-point type by at least 2 bits. This gives
+ us proper rounding when we truncate to the target type. In addition,
+ E must be large enough to hold the smallest supported denormal number
+ in a normalized form.
+
+ Both of these requirements are easily satisfied. The largest target
+ significand is 113 bits; we store at least 160. The smallest
+ denormal number fits in 17 exponent bits; we store 26.
+
+ Note that the decimal string conversion routines are sensitive to
+ rounding errors. Since the raw arithmetic routines do not themselves
+ have guard digits or rounding, the computation of 10**exp can
+ accumulate more than a few digits of error. The previous incarnation
+ of real.c successfully used a 144-bit fraction; given the current
+ layout of REAL_VALUE_TYPE we're forced to expand to at least 160 bits. */
+
+
+/* Used to classify two numbers simultaneously. */
+#define CLASS2(A, B) ((A) << 2 | (B))
+
+#if HOST_BITS_PER_LONG != 64 && HOST_BITS_PER_LONG != 32
+ #error "Some constant folding done by hand to avoid shift count warnings"
+#endif
+
+static void get_zero (REAL_VALUE_TYPE *, int);
+static void get_canonical_qnan (REAL_VALUE_TYPE *, int);
+static void get_canonical_snan (REAL_VALUE_TYPE *, int);
+static void get_inf (REAL_VALUE_TYPE *, int);
+static bool sticky_rshift_significand (REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, unsigned int);
+static void rshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ unsigned int);
+static void lshift_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ unsigned int);
+static void lshift_significand_1 (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static bool add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static bool sub_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, int);
+static void neg_significand (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static int cmp_significands (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+static int cmp_significand_0 (const REAL_VALUE_TYPE *);
+static void set_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static void clear_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static bool test_significand_bit (REAL_VALUE_TYPE *, unsigned int);
+static void clear_significand_below (REAL_VALUE_TYPE *, unsigned int);
+static bool div_significands (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static void normalize (REAL_VALUE_TYPE *);
+
+static bool do_add (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *, int);
+static bool do_multiply (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static bool do_divide (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *,
+ const REAL_VALUE_TYPE *);
+static int do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int);
+static void do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
+
+static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *);
+static void decimal_from_integer (REAL_VALUE_TYPE *);
+static void decimal_integer_string (char *, const REAL_VALUE_TYPE *,
+ size_t);
+
+static const REAL_VALUE_TYPE * ten_to_ptwo (int);
+static const REAL_VALUE_TYPE * ten_to_mptwo (int);
+static const REAL_VALUE_TYPE * real_digit (int);
+static void times_pten (REAL_VALUE_TYPE *, int);
+
+static void round_for_format (const struct real_format *, REAL_VALUE_TYPE *);
\f
-/* Type of computer arithmetic.
- Only one of DEC, IBM, IEEE, 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).
-
- 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 (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 (REAL_VALUE_TYPE *r, int sign)
+{
+ memset (r, 0, sizeof (*r));
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->canonical = 1;
+}
+static inline void
+get_canonical_snan (REAL_VALUE_TYPE *r, int sign)
+{
+ memset (r, 0, sizeof (*r));
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = 1;
+ r->canonical = 1;
+}
-/* 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_inf (REAL_VALUE_TYPE *r, int sign)
+{
+ memset (r, 0, sizeof (*r));
+ r->cl = 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) bcopy ((char *) e, (char *) r, 2*NE)
-#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) bcopy ((char *) e, (char *) r, 2*NE)
-#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]; \
- w[3] = ((EMUSHORT *) r)[0]; \
- w[2] = ((EMUSHORT *) r)[1]; \
- w[1] = ((EMUSHORT *) r)[2]; \
- w[0] = ((EMUSHORT *) r)[3]; \
- 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); \
- *((EMUSHORT *) r) = w[3]; \
- *((EMUSHORT *) r + 1) = w[2]; \
- *((EMUSHORT *) r + 2) = w[1]; \
- *((EMUSHORT *) r + 3) = w[0]; \
- } \
- } 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 PROTO((unsigned EMUSHORT *, long *,
- enum machine_mode));
-static void eclear PROTO((unsigned EMUSHORT *));
-static void emov PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void eabs PROTO((unsigned EMUSHORT *));
-#endif
-static void eneg PROTO((unsigned EMUSHORT *));
-static int eisneg PROTO((unsigned EMUSHORT *));
-static int eisinf PROTO((unsigned EMUSHORT *));
-static int eisnan PROTO((unsigned EMUSHORT *));
-static void einfin PROTO((unsigned EMUSHORT *));
-static void enan PROTO((unsigned EMUSHORT *, int));
-static void emovi PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void emovo PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void ecleaz PROTO((unsigned EMUSHORT *));
-static void ecleazs PROTO((unsigned EMUSHORT *));
-static void emovz PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void einan PROTO((unsigned EMUSHORT *));
-static int eiisnan PROTO((unsigned EMUSHORT *));
-static int eiisneg PROTO((unsigned EMUSHORT *));
-#if 0
-static void eiinfin PROTO((unsigned EMUSHORT *));
-#endif
-static int eiisinf PROTO((unsigned EMUSHORT *));
-static int ecmpm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void eshdn1 PROTO((unsigned EMUSHORT *));
-static void eshup1 PROTO((unsigned EMUSHORT *));
-static void eshdn8 PROTO((unsigned EMUSHORT *));
-static void eshup8 PROTO((unsigned EMUSHORT *));
-static void eshup6 PROTO((unsigned EMUSHORT *));
-static void eshdn6 PROTO((unsigned EMUSHORT *));
-static void eaddm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));\f
-static void esubm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void m16m PROTO((unsigned int, unsigned short *,
- unsigned short *));
-static int edivm PROTO((unsigned short *, unsigned short *));
-static int emulm PROTO((unsigned short *, unsigned short *));
-static void emdnorm PROTO((unsigned EMUSHORT *, int, int, EMULONG, int));
-static void esub PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-static void eadd PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-static void eadd1 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-static void ediv PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-static void emul PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-static void e53toe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e64toe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e113toe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void e24toe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe113 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe113 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe64 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe64 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe53 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe53 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoe24 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void toe24 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static int ecmp PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void eround PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#endif
-static void ltoe PROTO((HOST_WIDE_INT *, unsigned EMUSHORT *));
-static void ultoe PROTO((unsigned HOST_WIDE_INT *, unsigned EMUSHORT *));
-static void eifrac PROTO((unsigned EMUSHORT *, HOST_WIDE_INT *,
- unsigned EMUSHORT *));
-static void euifrac PROTO((unsigned EMUSHORT *, unsigned HOST_WIDE_INT *,
- unsigned EMUSHORT *));
-static int eshift PROTO((unsigned EMUSHORT *, int));
-static int enormlz PROTO((unsigned EMUSHORT *));
-#if 0
-static void e24toasc PROTO((unsigned EMUSHORT *, char *, int));
-static void e53toasc PROTO((unsigned EMUSHORT *, char *, int));
-static void e64toasc PROTO((unsigned EMUSHORT *, char *, int));
-static void e113toasc PROTO((unsigned EMUSHORT *, char *, int));
-#endif /* 0 */
-static void etoasc PROTO((unsigned EMUSHORT *, char *, int));
-static void asctoe24 PROTO((char *, unsigned EMUSHORT *));
-static void asctoe53 PROTO((char *, unsigned EMUSHORT *));
-static void asctoe64 PROTO((char *, unsigned EMUSHORT *));
-static void asctoe113 PROTO((char *, unsigned EMUSHORT *));
-static void asctoe PROTO((char *, unsigned EMUSHORT *));
-static void asctoeg PROTO((char *, unsigned EMUSHORT *, int));
-static void efloor PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#if 0
-static void efrexp PROTO((unsigned EMUSHORT *, int *,
- unsigned EMUSHORT *));
-#endif
-static void eldexp PROTO((unsigned EMUSHORT *, int, unsigned EMUSHORT *));
-#if 0
-static void eremain PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- unsigned EMUSHORT *));
-#endif
-static void eiremain PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void mtherr PROTO((char *, int));
-#ifdef DEC
-static void dectoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etodec PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void todec PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-#endif
-#ifdef IBM
-static void ibmtoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-static void etoibm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-static void toibm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-#endif
-#ifdef C4X
-static void c4xtoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-static void etoc4x PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-static void toc4x PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
- enum machine_mode));
-#endif
-static void make_nan PROTO((unsigned EMUSHORT *, int, enum machine_mode));
-#if 0
-static void uditoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void ditoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etoudi PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void etodi PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
-static void esqrt PROTO((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. */
-
-static void
-endian (e, x, mode)
- unsigned EMUSHORT e[];
- long x[];
- enum machine_mode mode;
+/* Right-shift the significand of A by N bits; put the result in the
+ significand of R. If any one bits are shifted out, return true. */
+
+static bool
+sticky_rshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ unsigned int n)
{
- unsigned long 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 (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))
- {
- PUT_REAL (d1, value);
- return;
- }
- if (eisnan (d2))
- {
- PUT_REAL (d2, value);
- return;
- }
-#endif
- code = (enum tree_code) icode;
- switch (code)
- {
- case PLUS_EXPR:
- eadd (d2, d1, v);
- break;
-
- case MINUS_EXPR:
- esub (d2, d1, v); /* d1 - d2 */
- break;
-
- case MULT_EXPR:
- emul (d2, d1, v);
- break;
+ unsigned int i, ofs = n / HOST_BITS_PER_LONG;
- case RDIV_EXPR:
-#ifndef REAL_INFINITY
- if (ecmp (d2, ezero) == 0)
+ n &= HOST_BITS_PER_LONG - 1;
+ if (n != 0)
+ {
+ for (i = 0; i < SIGSZ; ++i)
{
-#ifdef NANS
- enan (v, eisneg (d1) ^ eisneg (d2));
- break;
-#else
- abort ();
-#endif
+ 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)));
}
-#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;
-
- case MAX_EXPR: /* max (d1,d2) */
- if (ecmp (d1, d2) > 0)
- emov (d1, v);
- else
- emov (d2, v);
- break;
- default:
- emov (ezero, v);
- break;
}
-PUT_REAL (v, value);
+ else
+ {
+ for (i = 0; ofs + i < SIGSZ; ++i)
+ r->sig[i] = a->sig[ofs + i];
+ for (; i < SIGSZ; ++i)
+ r->sig[i] = 0;
+ }
}
+/* Left-shift the significand of A by N bits; put the result in the
+ significand of R. */
-/* Truncate REAL_VALUE_TYPE toward zero to signed HOST_WIDE_INT.
- implements REAL_VALUE_RNDZINT (x) (etrunci (x)). */
-
-REAL_VALUE_TYPE
-etrunci (x)
- REAL_VALUE_TYPE x;
+static void
+lshift_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ unsigned int n)
{
- unsigned EMUSHORT f[NE], g[NE];
- REAL_VALUE_TYPE r;
- HOST_WIDE_INT l;
+ unsigned int i, ofs = n / HOST_BITS_PER_LONG;
- 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);
+ n &= HOST_BITS_PER_LONG - 1;
+ if (n == 0)
+ {
+ for (i = 0; ofs + i < SIGSZ; ++i)
+ r->sig[SIGSZ-1-i] = a->sig[SIGSZ-1-i-ofs];
+ for (; i < SIGSZ; ++i)
+ r->sig[SIGSZ-1-i] = 0;
+ }
+ else
+ for (i = 0; i < SIGSZ; ++i)
+ {
+ r->sig[SIGSZ-1-i]
+ = (((ofs + i >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs]) << n)
+ | ((ofs + i + 1 >= SIGSZ ? 0 : a->sig[SIGSZ-1-i-ofs-1])
+ >> (HOST_BITS_PER_LONG - n)));
+ }
}
+/* Likewise, but N is specialized to 1. */
-/* Truncate REAL_VALUE_TYPE toward zero to unsigned HOST_WIDE_INT;
- implements REAL_VALUE_UNSIGNED_RNDZINT (x) (etruncui (x)). */
-
-REAL_VALUE_TYPE
-etruncui (x)
- REAL_VALUE_TYPE x;
+static inline void
+lshift_significand_1 (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
- unsigned EMUSHORT f[NE], g[NE];
- REAL_VALUE_TYPE r;
- unsigned HOST_WIDE_INT l;
+ unsigned 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 = 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. */
-/* This is the REAL_VALUE_ATOF function. It converts a decimal string to
- binary, rounding off as indicated by the machine_mode argument. Then it
- promotes the rounded value to REAL_VALUE_TYPE. */
-
-REAL_VALUE_TYPE
-ereal_atof (s, t)
- char *s;
- enum machine_mode t;
+static inline bool
+add_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
- unsigned EMUSHORT tem[NE], e[NE];
- REAL_VALUE_TYPE r;
+ bool carry = false;
+ int i;
- switch (t)
+ for (i = 0; i < SIGSZ; ++i)
{
- case HFmode:
- case SFmode:
- asctoe24 (s, tem);
- e24toe (tem, e);
- break;
-
- case DFmode:
- asctoe53 (s, tem);
- e53toe (tem, e);
- break;
-
- case XFmode:
- asctoe64 (s, tem);
- e64toe (tem, e);
- break;
+ unsigned long ai = a->sig[i];
+ unsigned long ri = ai + b->sig[i];
- case TFmode:
- asctoe113 (s, tem);
- e113toe (tem, e);
- break;
+ if (carry)
+ {
+ carry = ri < ai;
+ carry |= ++ri == 0;
+ }
+ else
+ carry = ri < ai;
- default:
- asctoe (s, e);
+ r->sig[i] = ri;
}
- PUT_REAL (e, &r);
- return (r);
-}
-
-
-/* Expansion of REAL_NEGATE. */
-
-REAL_VALUE_TYPE
-ereal_negate (x)
- REAL_VALUE_TYPE x;
-{
- unsigned EMUSHORT e[NE];
- REAL_VALUE_TYPE r;
- GET_REAL (&x, e);
- eneg (e);
- PUT_REAL (e, &r);
- return (r);
+ return carry;
}
+/* Subtract the significands of A and B, placing the result in R. CARRY is
+ true if there's a borrow incoming to the least significant word.
+ Return true if there was borrow out of the most significant word. */
-/* Round real toward zero to HOST_WIDE_INT;
- implements REAL_VALUE_FIX (x). */
-
-HOST_WIDE_INT
-efixi (x)
- REAL_VALUE_TYPE x;
+static inline bool
+sub_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b, int carry)
{
- unsigned EMUSHORT f[NE], g[NE];
- HOST_WIDE_INT l;
+ int i;
- GET_REAL (&x, f);
-#ifdef NANS
- if (eisnan (f))
+ for (i = 0; i < SIGSZ; ++i)
{
- warning ("conversion from NaN to int");
- return (-1);
- }
-#endif
- eifrac (f, &l, g);
- return l;
-}
+ unsigned long ai = a->sig[i];
+ unsigned long ri = ai - b->sig[i];
-/* Round real toward zero to unsigned HOST_WIDE_INT
- implements REAL_VALUE_UNSIGNED_FIX (x).
- Negative input returns zero. */
-
-unsigned HOST_WIDE_INT
-efixui (x)
- REAL_VALUE_TYPE x;
-{
- unsigned EMUSHORT f[NE], g[NE];
- unsigned HOST_WIDE_INT l;
+ if (carry)
+ {
+ carry = ri > ai;
+ carry |= ~--ri == 0;
+ }
+ else
+ carry = ri > ai;
- GET_REAL (&x, f);
-#ifdef NANS
- if (eisnan (f))
- {
- warning ("conversion from NaN to unsigned int");
- return (-1);
+ r->sig[i] = ri;
}
-#endif
- euifrac (f, &l, g);
- return l;
-}
+ return carry;
+}
-/* REAL_VALUE_FROM_INT macro. */
+/* Negate the significand A, placing the result in R. */
-void
-ereal_from_int (d, i, j, mode)
- REAL_VALUE_TYPE *d;
- HOST_WIDE_INT i, j;
- enum machine_mode mode;
+static inline void
+neg_significand (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
- unsigned EMUSHORT df[NE], dg[NE];
- HOST_WIDE_INT low, high;
- int sign;
+ bool carry = true;
+ int i;
- if (GET_MODE_CLASS (mode) != MODE_FLOAT)
- abort ();
- sign = 0;
- low = i;
- if ((high = j) < 0)
+ for (i = 0; i < SIGSZ; ++i)
{
- sign = 1;
- /* complement and add 1 */
- high = ~high;
- if (low)
- low = -low;
+ unsigned long ri, ai = a->sig[i];
+
+ if (carry)
+ {
+ if (ai)
+ {
+ ri = -ai;
+ carry = false;
+ }
+ else
+ ri = ai;
+ }
else
- high += 1;
- }
- 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);
+ ri = ~ai;
- /* 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);
- break;
+ r->sig[i] = ri;
+ }
+}
- case 64:
- etoe53 (dg, df);
- e53toe (df, dg);
- break;
+/* Compare significands. Return tri-state vs zero. */
- case 96:
- etoe64 (dg, df);
- e64toe (df, dg);
- break;
+static inline int
+cmp_significands (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
+{
+ int i;
- case 128:
- etoe113 (dg, df);
- e113toe (df, dg);
- break;
+ for (i = SIGSZ - 1; i >= 0; --i)
+ {
+ unsigned long ai = a->sig[i];
+ unsigned long bi = b->sig[i];
- default:
- abort ();
- }
+ if (ai > bi)
+ return 1;
+ if (ai < bi)
+ return -1;
+ }
- PUT_REAL (dg, d);
+ return 0;
}
+/* Return true if A is nonzero. */
-/* REAL_VALUE_FROM_UNSIGNED_INT macro. */
-
-void
-ereal_from_uint (d, i, j, mode)
- REAL_VALUE_TYPE *d;
- unsigned HOST_WIDE_INT i, j;
- enum machine_mode mode;
+static inline int
+cmp_significand_0 (const REAL_VALUE_TYPE *a)
{
- unsigned EMUSHORT df[NE], dg[NE];
- unsigned HOST_WIDE_INT low, high;
-
- 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))
- {
- case 32:
- etoe24 (dg, df);
- e24toe (df, dg);
- break;
-
- case 64:
- etoe53 (dg, df);
- e53toe (df, dg);
- break;
-
- case 96:
- etoe64 (dg, df);
- e64toe (df, dg);
- break;
-
- case 128:
- etoe113 (dg, df);
- e113toe (df, dg);
- break;
+ int i;
- default:
- abort ();
- }
+ for (i = SIGSZ - 1; i >= 0; --i)
+ if (a->sig[i])
+ return 1;
- PUT_REAL (dg, d);
+ return 0;
}
+/* Set bit N of the significand of R. */
-/* REAL_VALUE_TO_INT macro. */
-
-void
-ereal_to_int (low, high, rr)
- HOST_WIDE_INT *low, *high;
- REAL_VALUE_TYPE rr;
+static inline void
+set_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
- unsigned EMUSHORT d[NE], df[NE], dg[NE], dh[NE];
- int s;
-
- 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)
- {
- /* complement and add 1 */
- *high = ~(*high);
- if (*low)
- *low = -(*low);
- else
- *high += 1;
- }
+ r->sig[n / HOST_BITS_PER_LONG]
+ |= (unsigned long)1 << (n % HOST_BITS_PER_LONG);
}
+/* Clear bit N of the significand of R. */
-/* REAL_VALUE_LDEXP macro. */
-
-REAL_VALUE_TYPE
-ereal_ldexp (x, n)
- REAL_VALUE_TYPE x;
- int n;
+static inline void
+clear_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
{
- unsigned EMUSHORT e[NE], y[NE];
- REAL_VALUE_TYPE r;
-
- GET_REAL (&x, e);
-#ifdef NANS
- if (eisnan (e))
- return (x);
-#endif
- eldexp (e, n, y);
- PUT_REAL (y, &r);
- return (r);
+ r->sig[n / HOST_BITS_PER_LONG]
+ &= ~((unsigned long)1 << (n % HOST_BITS_PER_LONG));
}
-/* These routines are conditionally compiled because functions
- of the same names may be defined in fold-const.c. */
+/* Test bit N of the significand of R. */
-#ifdef REAL_ARITHMETIC
+static inline bool
+test_significand_bit (REAL_VALUE_TYPE *r, unsigned int n)
+{
+ /* ??? Compiler bug here if we return this expression directly.
+ The conversion to bool strips the "&1" and we wind up testing
+ e.g. 2 != 0 -> true. Seen in gcc version 3.2 20020520. */
+ int t = (r->sig[n / HOST_BITS_PER_LONG] >> (n % HOST_BITS_PER_LONG)) & 1;
+ return t;
+}
-/* Check for infinity in a REAL_VALUE_TYPE. */
+/* Clear bits 0..N-1 of the significand of R. */
-int
-target_isinf (x)
- REAL_VALUE_TYPE x;
+static void
+clear_significand_below (REAL_VALUE_TYPE *r, unsigned int n)
{
- unsigned EMUSHORT e[NE];
+ int i, w = n / HOST_BITS_PER_LONG;
-#ifdef INFINITY
- GET_REAL (&x, e);
- return (eisinf (e));
-#else
- return 0;
-#endif
+ for (i = 0; i < w; ++i)
+ r->sig[i] = 0;
+
+ r->sig[w] &= ~(((unsigned long)1 << (n % HOST_BITS_PER_LONG)) - 1);
}
-/* Check whether a REAL_VALUE_TYPE item is a NaN. */
+/* Divide the significands of A and B, placing the result in R. Return
+ true if the division was inexact. */
-int
-target_isnan (x)
- REAL_VALUE_TYPE x;
+static inline bool
+div_significands (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
{
- unsigned EMUSHORT e[NE];
+ REAL_VALUE_TYPE u;
+ int i, bit = SIGNIFICAND_BITS - 1;
+ unsigned long msb, inexact;
-#ifdef NANS
- GET_REAL (&x, e);
- return (eisnan (e));
-#else
- return (0);
-#endif
-}
+ u = *a;
+ memset (r->sig, 0, sizeof (r->sig));
+ msb = 0;
+ goto start;
+ do
+ {
+ msb = u.sig[SIGSZ-1] & SIG_MSB;
+ lshift_significand_1 (&u, &u);
+ start:
+ if (msb || cmp_significands (&u, b) >= 0)
+ {
+ sub_significands (&u, &u, b, 0);
+ set_significand_bit (r, bit);
+ }
+ }
+ while (--bit >= 0);
-/* Check for a negative REAL_VALUE_TYPE number.
- This just checks the sign bit, so that -0 counts as negative. */
+ for (i = 0, inexact = 0; i < SIGSZ; i++)
+ inexact |= u.sig[i];
-int
-target_negative (x)
- REAL_VALUE_TYPE x;
-{
- return ereal_isneg (x);
+ return inexact != 0;
}
-/* Expansion of REAL_VALUE_TRUNCATE.
- The result is in floating point, rounded to nearest or even. */
+/* 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.) */
-REAL_VALUE_TYPE
-real_value_truncate (mode, arg)
- enum machine_mode mode;
- REAL_VALUE_TYPE arg;
+static void
+normalize (REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT e[NE], t[NE];
- REAL_VALUE_TYPE r;
+ int shift = 0, exp;
+ int i, j;
- GET_REAL (&arg, e);
-#ifdef NANS
- if (eisnan (e))
- return (arg);
-#endif
- eclear (t);
- switch (mode)
- {
- case TFmode:
- etoe113 (e, t);
- e113toe (t, t);
- break;
+ if (r->decimal)
+ return;
- case XFmode:
- etoe64 (e, t);
- e64toe (t, t);
+ /* 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;
- case DFmode:
- etoe53 (e, t);
- e53toe (t, t);
- break;
+ /* Zero significand flushes to zero. */
+ if (i < 0)
+ {
+ r->cl = rvc_zero;
+ SET_REAL_EXP (r, 0);
+ return;
+ }
- case SFmode:
- case HFmode:
- etoe24 (e, t);
- e24toe (t, t);
+ /* 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 SImode:
- r = etrunci (arg);
- return (r);
-
- /* If an unsupported type was requested, presume that
- the machine files know something useful to do with
- the unmodified value. */
-
- default:
- return (arg);
+ if (shift > 0)
+ {
+ exp = REAL_EXP (r) - shift;
+ if (exp > MAX_EXP)
+ get_inf (r, r->sign);
+ else if (exp < -MAX_EXP)
+ get_zero (r, r->sign);
+ else
+ {
+ SET_REAL_EXP (r, exp);
+ lshift_significand (r, r, shift);
+ }
}
- PUT_REAL (t, &r);
- return (r);
}
+\f
+/* Calculate R = A + (SUBTRACT_P ? -B : B). Return true if the
+ result may be inexact due to a loss of precision. */
+
+static bool
+do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b, int subtract_p)
+{
+ int dexp, sign, exp;
+ REAL_VALUE_TYPE t;
+ bool inexact = false;
+
+ /* Determine if we need to add or subtract. */
+ sign = a->sign;
+ subtract_p = (sign ^ b->sign) ^ subtract_p;
+
+ switch (CLASS2 (a->cl, b->cl))
+ {
+ case CLASS2 (rvc_zero, rvc_zero):
+ /* -0 + -0 = -0, -0 - +0 = -0; all other cases yield +0. */
+ get_zero (r, sign & !subtract_p);
+ return false;
+
+ case CLASS2 (rvc_zero, rvc_normal):
+ case CLASS2 (rvc_zero, rvc_inf):
+ case CLASS2 (rvc_zero, rvc_nan):
+ /* 0 + ANY = ANY. */
+ case CLASS2 (rvc_normal, rvc_nan):
+ case CLASS2 (rvc_inf, rvc_nan):
+ case CLASS2 (rvc_nan, rvc_nan):
+ /* ANY + NaN = NaN. */
+ case CLASS2 (rvc_normal, rvc_inf):
+ /* R + Inf = Inf. */
+ *r = *b;
+ r->sign = sign ^ subtract_p;
+ return false;
+
+ case CLASS2 (rvc_normal, rvc_zero):
+ case CLASS2 (rvc_inf, rvc_zero):
+ case CLASS2 (rvc_nan, rvc_zero):
+ /* ANY + 0 = ANY. */
+ case CLASS2 (rvc_nan, rvc_normal):
+ case CLASS2 (rvc_nan, rvc_inf):
+ /* NaN + ANY = NaN. */
+ case CLASS2 (rvc_inf, rvc_normal):
+ /* Inf + R = Inf. */
+ *r = *a;
+ return false;
+
+ case CLASS2 (rvc_inf, rvc_inf):
+ if (subtract_p)
+ /* Inf - Inf = NaN. */
+ get_canonical_qnan (r, 0);
+ else
+ /* Inf + Inf = Inf. */
+ *r = *a;
+ return false;
-/* Try to change R into its exact multiplicative inverse in machine mode
- MODE. Return nonzero function value if successful. */
+ case CLASS2 (rvc_normal, rvc_normal):
+ break;
-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;
+ default:
+ gcc_unreachable ();
+ }
- GET_REAL (r, e);
+ /* Swap the arguments such that A has the larger exponent. */
+ dexp = REAL_EXP (a) - REAL_EXP (b);
+ if (dexp < 0)
+ {
+ const REAL_VALUE_TYPE *t;
+ t = a, a = b, b = t;
+ dexp = -dexp;
+ sign ^= subtract_p;
+ }
+ exp = REAL_EXP (a);
- /* Test for input in range. Don't transform IEEE special values. */
- if (eisinf (e) || eisnan (e) || (ecmp (e, ezero) == 0))
- return 0;
+ /* 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;
+ }
- /* 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;
+ inexact |= sticky_rshift_significand (&t, b, dexp);
+ b = &t;
+ }
- for (i = 0; i < NE - 2; i++)
+ if (subtract_p)
+ {
+ if (sub_significands (r, a, b, inexact))
+ {
+ /* We got a borrow out of the subtraction. That means that
+ A and B had the same exponent, and B had the larger
+ significand. We need to swap the sign and negate the
+ significand. */
+ sign ^= 1;
+ neg_significand (r, r);
+ }
+ }
+ else
{
- if (e[i] != 0)
- return 0;
+ 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;
+ }
+ }
}
- /* Compute the inverse and truncate it to the required mode. */
- ediv (e, eone, einv);
- PUT_REAL (einv, &rinv);
- rinv = real_value_truncate (mode, rinv);
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp);
+ /* Zero out the remaining fields. */
+ r->signalling = 0;
+ r->canonical = 0;
+ r->decimal = 0;
-#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);
+ /* Re-normalize the result. */
+ normalize (r);
- /* Check the bits again, because the truncation might have
- generated an arbitrary saturation value on overflow. */
- if (einv[NE - 2] != 0x8000)
- return 0;
+ /* Special case: if the subtraction results in zero, the result
+ is positive. */
+ if (r->cl == rvc_zero)
+ r->sign = 0;
+ else
+ r->sig[0] |= inexact;
+
+ return inexact;
+}
+
+/* Calculate R = A * B. Return true if the result may be inexact. */
+
+static bool
+do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
+{
+ REAL_VALUE_TYPE u, t, *rr;
+ unsigned int i, j, k;
+ int sign = a->sign ^ b->sign;
+ bool inexact = false;
+
+ switch (CLASS2 (a->cl, b->cl))
+ {
+ case CLASS2 (rvc_zero, rvc_zero):
+ case CLASS2 (rvc_zero, rvc_normal):
+ case CLASS2 (rvc_normal, rvc_zero):
+ /* +-0 * ANY = 0 with appropriate sign. */
+ get_zero (r, sign);
+ return false;
+
+ case CLASS2 (rvc_zero, rvc_nan):
+ case CLASS2 (rvc_normal, rvc_nan):
+ case CLASS2 (rvc_inf, rvc_nan):
+ case CLASS2 (rvc_nan, rvc_nan):
+ /* ANY * NaN = NaN. */
+ *r = *b;
+ r->sign = sign;
+ return false;
+
+ case CLASS2 (rvc_nan, rvc_zero):
+ case CLASS2 (rvc_nan, rvc_normal):
+ case CLASS2 (rvc_nan, rvc_inf):
+ /* NaN * ANY = NaN. */
+ *r = *a;
+ r->sign = sign;
+ return false;
+
+ case CLASS2 (rvc_zero, rvc_inf):
+ case CLASS2 (rvc_inf, rvc_zero):
+ /* 0 * Inf = NaN */
+ get_canonical_qnan (r, sign);
+ return false;
+
+ case CLASS2 (rvc_inf, rvc_inf):
+ case CLASS2 (rvc_normal, rvc_inf):
+ case CLASS2 (rvc_inf, rvc_normal):
+ /* Inf * Inf = Inf, R * Inf = Inf */
+ get_inf (r, sign);
+ return false;
+
+ case CLASS2 (rvc_normal, rvc_normal):
+ break;
- for (i = 0; i < NE - 2; i++)
- {
- if (einv[i] != 0)
- return 0;
+ default:
+ gcc_unreachable ();
}
- /* Fail if the computed inverse is out of range. */
- if (eisinf (einv) || eisnan (einv) || (ecmp (einv, ezero) == 0))
- return 0;
+ if (r == a || r == b)
+ rr = &t;
+ else
+ rr = r;
+ get_zero (rr, 0);
- /* Output the reciprocal and return success flag. */
- PUT_REAL (einv, r);
- return 1;
-}
-#endif /* REAL_ARITHMETIC defined */
+ /* Collect all the partial products. Since we don't have sure access
+ to a widening multiply, we split each long into two half-words.
-/* Used for debugging--print the value of R in human-readable format
- on stderr. */
+ Consider the long-hand form of a four half-word multiplication:
-void
-debug_real (r)
- REAL_VALUE_TYPE r;
-{
- char dstr[30];
+ A B C D
+ * E F G H
+ --------------
+ DE DF DG DH
+ CE CF CG CH
+ BE BF BG BH
+ AE AF AG AH
- REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
- fprintf (stderr, "%s", dstr);
-}
+ 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. */
-\f
-/* The following routines convert REAL_VALUE_TYPE to the various floating
- point formats that are meaningful to supported computers.
+ for (i = 0; i < SIGSZ * 2; ++i)
+ {
+ unsigned long ai = a->sig[i / 2];
+ if (i & 1)
+ ai >>= HOST_BITS_PER_LONG / 2;
+ else
+ ai &= ((unsigned long)1 << (HOST_BITS_PER_LONG / 2)) - 1;
- The results are returned in 32-bit pieces, each piece stored in a `long'.
- This is so they can be printed by statements like
-
- fprintf (file, "%lx, %lx", L[0], L[1]);
+ if (ai == 0)
+ continue;
- that will work on both narrow- and wide-word host computers. */
+ for (j = 0; j < 2; ++j)
+ {
+ int exp = (REAL_EXP (a) - (2*SIGSZ-1-i)*(HOST_BITS_PER_LONG/2)
+ + (REAL_EXP (b) - (1-j)*(HOST_BITS_PER_LONG/2)));
-/* 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. */
+ 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;
+ }
-void
-etartdouble (r, l)
- REAL_VALUE_TYPE r;
- long l[];
-{
- unsigned EMUSHORT e[NE];
+ memset (&u, 0, sizeof (u));
+ u.cl = rvc_normal;
+ SET_REAL_EXP (&u, exp);
- GET_REAL (&r, e);
- etoe113 (e, e);
- endian (e, l, TFmode);
-}
-
-/* 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. */
-
-void
-etarldouble (r, l)
- REAL_VALUE_TYPE r;
- long l[];
-{
- unsigned EMUSHORT e[NE];
-
- GET_REAL (&r, e);
- etoe64 (e, e);
- endian (e, l, XFmode);
-}
-
-/* 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. */
-
-void
-etardouble (r, l)
- REAL_VALUE_TYPE r;
- long l[];
-{
- unsigned EMUSHORT e[NE];
-
- GET_REAL (&r, e);
- etoe53 (e, e);
- endian (e, l, DFmode);
-}
-
-/* Convert R to a single precision float value stored in the least-significant
- bits of a `long'. */
+ 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;
-long
-etarsingle (r)
- REAL_VALUE_TYPE r;
-{
- unsigned EMUSHORT e[NE];
- long l;
+ u.sig[k / 2] = ai * bi;
+ }
- GET_REAL (&r, e);
- etoe24 (e, e);
- endian (e, &l, SFmode);
- return ((long) l);
-}
+ normalize (&u);
+ inexact |= do_add (rr, rr, &u, 0);
+ }
+ }
-/* 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. */
+ rr->sign = sign;
+ if (rr != r)
+ *r = t;
+
+ return inexact;
+}
+
+/* Calculate R = A / B. Return true if the result may be inexact. */
+
+static bool
+do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a,
+ const REAL_VALUE_TYPE *b)
+{
+ int exp, sign = a->sign ^ b->sign;
+ REAL_VALUE_TYPE t, *rr;
+ bool inexact;
+
+ switch (CLASS2 (a->cl, b->cl))
+ {
+ case CLASS2 (rvc_zero, rvc_zero):
+ /* 0 / 0 = NaN. */
+ case CLASS2 (rvc_inf, rvc_inf):
+ /* Inf / Inf = NaN. */
+ get_canonical_qnan (r, sign);
+ return false;
+
+ case CLASS2 (rvc_zero, rvc_normal):
+ case CLASS2 (rvc_zero, rvc_inf):
+ /* 0 / ANY = 0. */
+ case CLASS2 (rvc_normal, rvc_inf):
+ /* R / Inf = 0. */
+ get_zero (r, sign);
+ return false;
+
+ case CLASS2 (rvc_normal, rvc_zero):
+ /* R / 0 = Inf. */
+ case CLASS2 (rvc_inf, rvc_zero):
+ /* Inf / 0 = Inf. */
+ get_inf (r, sign);
+ return false;
+
+ case CLASS2 (rvc_zero, rvc_nan):
+ case CLASS2 (rvc_normal, rvc_nan):
+ case CLASS2 (rvc_inf, rvc_nan):
+ case CLASS2 (rvc_nan, rvc_nan):
+ /* ANY / NaN = NaN. */
+ *r = *b;
+ r->sign = sign;
+ return false;
+
+ case CLASS2 (rvc_nan, rvc_zero):
+ case CLASS2 (rvc_nan, rvc_normal):
+ case CLASS2 (rvc_nan, rvc_inf):
+ /* NaN / ANY = NaN. */
+ *r = *a;
+ r->sign = sign;
+ return false;
+
+ case CLASS2 (rvc_inf, rvc_normal):
+ /* Inf / R = Inf. */
+ get_inf (r, sign);
+ return false;
+
+ case CLASS2 (rvc_normal, rvc_normal):
+ break;
-void
-ereal_to_decimal (x, s)
- REAL_VALUE_TYPE x;
- char *s;
-{
- unsigned EMUSHORT e[NE];
+ default:
+ gcc_unreachable ();
+ }
- GET_REAL (&x, e);
- etoasc (e, s, 20);
-}
+ if (r == a || r == b)
+ rr = &t;
+ else
+ rr = r;
-/* Compare X and Y. Return 1 if X > Y, 0 if X == Y, -1 if X < Y,
- or -2 if either is a NaN. */
+ /* Make sure all fields in the result are initialized. */
+ get_zero (rr, 0);
+ rr->cl = rvc_normal;
+ rr->sign = sign;
-int
-ereal_cmp (x, y)
- REAL_VALUE_TYPE x, y;
-{
- unsigned EMUSHORT ex[NE], ey[NE];
+ exp = REAL_EXP (a) - REAL_EXP (b) + 1;
+ if (exp > MAX_EXP)
+ {
+ get_inf (r, sign);
+ return true;
+ }
+ if (exp < -MAX_EXP)
+ {
+ get_zero (r, sign);
+ return true;
+ }
+ SET_REAL_EXP (rr, exp);
- GET_REAL (&x, ex);
- GET_REAL (&y, ey);
- return (ecmp (ex, ey));
-}
+ inexact = div_significands (rr, a, b);
-/* Return 1 if the sign bit of X is set, else return 0. */
+ /* Re-normalize the result. */
+ normalize (rr);
+ rr->sig[0] |= inexact;
-int
-ereal_isneg (x)
- REAL_VALUE_TYPE x;
-{
- unsigned EMUSHORT ex[NE];
+ if (rr != r)
+ *r = t;
- GET_REAL (&x, ex);
- return (eisneg (ex));
+ return inexact;
}
-/* 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
-
- 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
+/* Return a tri-state comparison of A vs B. Return NAN_RESULT if
+ one of the two operands is a NaN. */
- 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
+static int
+do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b,
+ int nan_result)
+{
+ int ret;
+
+ switch (CLASS2 (a->cl, b->cl))
+ {
+ case CLASS2 (rvc_zero, rvc_zero):
+ /* Sign of zero doesn't matter for compares. */
+ return 0;
+
+ case CLASS2 (rvc_normal, rvc_zero):
+ /* Decimal float zero is special and uses rvc_normal, not rvc_zero. */
+ if (a->decimal)
+ return decimal_do_compare (a, b, nan_result);
+ /* Fall through. */
+ case CLASS2 (rvc_inf, rvc_zero):
+ case CLASS2 (rvc_inf, rvc_normal):
+ return (a->sign ? -1 : 1);
+
+ case CLASS2 (rvc_inf, rvc_inf):
+ return -a->sign - -b->sign;
+
+ case CLASS2 (rvc_zero, rvc_normal):
+ /* Decimal float zero is special and uses rvc_normal, not rvc_zero. */
+ if (b->decimal)
+ return decimal_do_compare (a, b, nan_result);
+ /* Fall through. */
+ case CLASS2 (rvc_zero, rvc_inf):
+ case CLASS2 (rvc_normal, rvc_inf):
+ return (b->sign ? 1 : -1);
+
+ case CLASS2 (rvc_zero, rvc_nan):
+ case CLASS2 (rvc_normal, rvc_nan):
+ case CLASS2 (rvc_inf, rvc_nan):
+ case CLASS2 (rvc_nan, rvc_nan):
+ case CLASS2 (rvc_nan, rvc_zero):
+ case CLASS2 (rvc_nan, rvc_normal):
+ case CLASS2 (rvc_nan, rvc_inf):
+ return nan_result;
+
+ case CLASS2 (rvc_normal, rvc_normal):
+ break;
-/* Control register for rounding precision.
- This can be set to 113 (if NE=10), 80 (if NE=6), 64, 56, 53, or 24 bits. */
+ default:
+ gcc_unreachable ();
+ }
-int rndprc = NBITS;
-extern int rndprc;
+ if (a->sign != b->sign)
+ return -a->sign - -b->sign;
-/* Clear out entire e-type number X. */
+ if (a->decimal || b->decimal)
+ return decimal_do_compare (a, b, nan_result);
-static void
-eclear (x)
- register unsigned EMUSHORT *x;
-{
- register int i;
+ if (REAL_EXP (a) > REAL_EXP (b))
+ ret = 1;
+ else if (REAL_EXP (a) < REAL_EXP (b))
+ ret = -1;
+ else
+ ret = cmp_significands (a, b);
- for (i = 0; i < NE; i++)
- *x++ = 0;
+ return (a->sign ? -ret : ret);
}
-/* Move e-type number from A to B. */
+/* Return A truncated to an integral value toward zero. */
-static void
-emov (a, b)
- register unsigned EMUSHORT *a, *b;
+static void
+do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a)
{
- register int i;
-
- for (i = 0; i < NE; i++)
- *b++ = *a++;
-}
+ *r = *a;
+ switch (r->cl)
+ {
+ case rvc_zero:
+ case rvc_inf:
+ case rvc_nan:
+ break;
-#if 0
-/* Absolute value of e-type X. */
+ case rvc_normal:
+ if (r->decimal)
+ {
+ decimal_do_fix_trunc (r, a);
+ return;
+ }
+ if (REAL_EXP (r) <= 0)
+ get_zero (r, r->sign);
+ else if (REAL_EXP (r) < SIGNIFICAND_BITS)
+ clear_significand_below (r, SIGNIFICAND_BITS - REAL_EXP (r));
+ break;
-static void
-eabs (x)
- unsigned EMUSHORT x[];
-{
- /* sign is top bit of last word of external format */
- x[NE - 1] &= 0x7fff;
+ default:
+ gcc_unreachable ();
+ }
}
-#endif /* 0 */
-/* Negate the e-type number X. */
+/* Perform the binary or unary operation described by CODE.
+ For a unary operation, leave OP1 NULL. This function returns
+ true if the result may be inexact due to loss of precision. */
-static void
-eneg (x)
- unsigned EMUSHORT x[];
+bool
+real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
{
+ enum tree_code code = (enum tree_code) icode;
- x[NE - 1] ^= 0x8000; /* Toggle the sign bit */
-}
+ if (op0->decimal || (op1 && op1->decimal))
+ return decimal_real_arithmetic (r, code, op0, op1);
-/* Return 1 if sign bit of e-type number X is nonzero, else zero. */
+ switch (code)
+ {
+ case PLUS_EXPR:
+ /* Clear any padding areas in *r if it isn't equal to one of the
+ operands so that we can later do bitwise comparisons later on. */
+ if (r != op0 && r != op1)
+ memset (r, '\0', sizeof (*r));
+ return do_add (r, op0, op1, 0);
-static int
-eisneg (x)
- unsigned EMUSHORT x[];
-{
+ case MINUS_EXPR:
+ if (r != op0 && r != op1)
+ memset (r, '\0', sizeof (*r));
+ return do_add (r, op0, op1, 1);
- if (x[NE - 1] & 0x8000)
- return (1);
- else
- return (0);
-}
+ case MULT_EXPR:
+ if (r != op0 && r != op1)
+ memset (r, '\0', sizeof (*r));
+ return do_multiply (r, op0, op1);
-/* Return 1 if e-type number X is infinity, else return zero. */
+ case RDIV_EXPR:
+ if (r != op0 && r != op1)
+ memset (r, '\0', sizeof (*r));
+ return do_divide (r, op0, op1);
+
+ case MIN_EXPR:
+ if (op1->cl == rvc_nan)
+ *r = *op1;
+ else if (do_compare (op0, op1, -1) < 0)
+ *r = *op0;
+ else
+ *r = *op1;
+ break;
-static int
-eisinf (x)
- unsigned EMUSHORT x[];
-{
+ case MAX_EXPR:
+ if (op1->cl == rvc_nan)
+ *r = *op1;
+ else if (do_compare (op0, op1, 1) < 0)
+ *r = *op1;
+ else
+ *r = *op0;
+ break;
-#ifdef NANS
- if (eisnan (x))
- return (0);
-#endif
- if ((x[NE - 1] & 0x7fff) == 0x7fff)
- return (1);
- else
- return (0);
-}
+ case NEGATE_EXPR:
+ *r = *op0;
+ r->sign ^= 1;
+ break;
-/* 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. */
+ case ABS_EXPR:
+ *r = *op0;
+ r->sign = 0;
+ break;
-static int
-eisnan (x)
- unsigned EMUSHORT x[];
-{
-#ifdef NANS
- int i;
+ case FIX_TRUNC_EXPR:
+ do_fix_trunc (r, op0);
+ break;
- /* 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);
+ default:
+ gcc_unreachable ();
}
-#endif
-
- return (0);
+ return false;
}
-/* Fill e-type number X with infinity pattern (IEEE)
- or largest possible number (non-IEEE). */
-
-static void
-einfin (x)
- register unsigned EMUSHORT *x;
+REAL_VALUE_TYPE
+real_value_negate (const REAL_VALUE_TYPE *op0)
{
- 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)
- {
- if (rndprc == 113)
- {
- *(x - 9) = 0;
- *(x - 8) = 0;
- }
- if (rndprc == 64)
- {
- *(x - 5) = 0;
- }
- if (rndprc == 53)
- {
- *(x - 4) = 0xf800;
- }
- else
- {
- *(x - 4) = 0;
- *(x - 3) = 0;
- *(x - 2) = 0xff00;
- }
- }
-#endif
+ REAL_VALUE_TYPE r;
+ real_arithmetic (&r, NEGATE_EXPR, op0, NULL);
+ return r;
}
-/* 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. */
-
-static void
-enan (x, sign)
- register unsigned EMUSHORT *x;
- int sign;
+REAL_VALUE_TYPE
+real_value_abs (const REAL_VALUE_TYPE *op0)
{
- register int i;
-
- for (i = 0; i < NE - 2; i++)
- *x++ = 0;
- *x++ = 0xc000;
- *x = (sign << 15) | 0x7fff;
+ REAL_VALUE_TYPE r;
+ real_arithmetic (&r, ABS_EXPR, op0, NULL);
+ return r;
}
-/* Move in an e-type number A, converting it to exploded e-type B. */
-
-static void
-emovi (a, b)
- unsigned EMUSHORT *a, *b;
+bool
+real_compare (int icode, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
{
- register unsigned EMUSHORT *p, *q;
- int i;
+ enum tree_code code = (enum tree_code) icode;
- 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)
+ switch (code)
{
-#ifdef NANS
- if (eisnan (a))
- {
- *q++ = 0;
- for (i = 3; i < NI; i++)
- *q++ = *p--;
- return;
- }
-#endif
+ case LT_EXPR:
+ return do_compare (op0, op1, 1) < 0;
+ case LE_EXPR:
+ return do_compare (op0, op1, 1) <= 0;
+ case GT_EXPR:
+ return do_compare (op0, op1, -1) > 0;
+ case GE_EXPR:
+ return do_compare (op0, op1, -1) >= 0;
+ case EQ_EXPR:
+ return do_compare (op0, op1, -1) == 0;
+ case NE_EXPR:
+ return do_compare (op0, op1, -1) != 0;
+ case UNORDERED_EXPR:
+ return op0->cl == rvc_nan || op1->cl == rvc_nan;
+ case ORDERED_EXPR:
+ return op0->cl != rvc_nan && op1->cl != rvc_nan;
+ case UNLT_EXPR:
+ return do_compare (op0, op1, -1) < 0;
+ case UNLE_EXPR:
+ return do_compare (op0, op1, -1) <= 0;
+ case UNGT_EXPR:
+ return do_compare (op0, op1, 1) > 0;
+ case UNGE_EXPR:
+ return do_compare (op0, op1, 1) >= 0;
+ case UNEQ_EXPR:
+ return do_compare (op0, op1, 0) == 0;
+ case LTGT_EXPR:
+ return do_compare (op0, op1, 0) != 0;
- for (i = 2; i < NI; i++)
- *q++ = 0;
- return;
+ default:
+ gcc_unreachable ();
}
-#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;
}
-/* Move out exploded e-type number A, converting it to e type B. */
+/* Return floor log2(R). */
-static void
-emovo (a, b)
- unsigned EMUSHORT *a, *b;
+int
+real_exponent (const REAL_VALUE_TYPE *r)
{
- 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)
+ switch (r->cl)
{
-#ifdef NANS
- if (eiisnan (a))
- {
- enan (b, eiisneg (a));
- return;
- }
-#endif
- einfin (b);
- return;
+ case rvc_zero:
+ return 0;
+ case rvc_inf:
+ case rvc_nan:
+ return (unsigned int)-1 >> 1;
+ case rvc_normal:
+ return REAL_EXP (r);
+ default:
+ gcc_unreachable ();
}
-#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. */
-
-static void
-ecleaz (xi)
- register unsigned EMUSHORT *xi;
-{
- register int i;
-
- for (i = 0; i < NI; i++)
- *xi++ = 0;
}
-/* Clear out exploded e-type XI, but don't touch the sign. */
+/* R = OP0 * 2**EXP. */
-static void
-ecleazs (xi)
- register unsigned EMUSHORT *xi;
+void
+real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, int exp)
{
- register int i;
-
- ++xi;
- for (i = 0; i < NI - 1; i++)
- *xi++ = 0;
-}
-
-/* Move exploded e-type number from A to B. */
+ *r = *op0;
+ switch (r->cl)
+ {
+ case rvc_zero:
+ case rvc_inf:
+ case rvc_nan:
+ break;
-static void
-emovz (a, b)
- register unsigned EMUSHORT *a, *b;
-{
- register int i;
+ case rvc_normal:
+ exp += REAL_EXP (op0);
+ if (exp > MAX_EXP)
+ get_inf (r, r->sign);
+ else if (exp < -MAX_EXP)
+ get_zero (r, r->sign);
+ else
+ SET_REAL_EXP (r, exp);
+ break;
- for (i = 0; i < NI - 1; i++)
- *b++ = *a++;
- /* clear low guard word */
- *b = 0;
+ default:
+ gcc_unreachable ();
+ }
}
-/* Generate exploded e-type NaN.
- The explicit pattern for this is maximum exponent and
- top two significant bits set. */
+/* Determine whether a floating-point value X is infinite. */
-static void
-einan (x)
- unsigned EMUSHORT x[];
+bool
+real_isinf (const REAL_VALUE_TYPE *r)
{
-
- ecleaz (x);
- x[E] = 0x7fff;
- x[M + 1] = 0xc000;
+ return (r->cl == rvc_inf);
}
-/* Return nonzero if exploded e-type X is a NaN. */
+/* Determine whether a floating-point value X is a NaN. */
-static int
-eiisnan (x)
- unsigned EMUSHORT x[];
+bool
+real_isnan (const REAL_VALUE_TYPE *r)
{
- int i;
-
- if ((x[E] & 0x7fff) == 0x7fff)
- {
- for (i = M + 1; i < NI; i++)
- {
- if (x[i] != 0)
- return (1);
- }
- }
- return (0);
+ return (r->cl == rvc_nan);
}
-/* Return nonzero if sign of exploded e-type X is nonzero. */
+/* Determine whether a floating-point value X is finite. */
-static int
-eiisneg (x)
- unsigned EMUSHORT x[];
+bool
+real_isfinite (const REAL_VALUE_TYPE *r)
{
-
- return x[0] != 0;
+ return (r->cl != rvc_nan) && (r->cl != rvc_inf);
}
-#if 0
-/* Fill exploded e-type X with infinity pattern.
- This has maximum exponent and significand all zeros. */
+/* Determine whether a floating-point value X is negative. */
-static void
-eiinfin (x)
- unsigned EMUSHORT x[];
+bool
+real_isneg (const REAL_VALUE_TYPE *r)
{
-
- ecleaz (x);
- x[E] = 0x7fff;
+ return r->sign;
}
-#endif /* 0 */
-/* Return nonzero if exploded e-type X is infinite. */
+/* Determine whether a floating-point value X is minus zero. */
-static int
-eiisinf (x)
- unsigned EMUSHORT x[];
+bool
+real_isnegzero (const REAL_VALUE_TYPE *r)
{
-
-#ifdef NANS
- if (eiisnan (x))
- return (0);
-#endif
- if ((x[E] & 0x7fff) == 0x7fff)
- return (1);
- return (0);
+ return r->sign && r->cl == rvc_zero;
}
+/* Compare two floating-point objects for bitwise identity. */
-/* Compare significands of numbers in internal exploded e-type format.
- Guard words are included in the comparison.
-
- Returns +1 if a > b
- 0 if a == b
- -1 if a < b */
-
-static int
-ecmpm (a, b)
- register unsigned EMUSHORT *a, *b;
+bool
+real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b)
{
int i;
- a += M; /* skip up to significand area */
- b += M;
- for (i = M; i < NI; i++)
+ if (a->cl != b->cl)
+ return false;
+ if (a->sign != b->sign)
+ return false;
+
+ switch (a->cl)
{
- if (*a++ != *b++)
- goto difrnt;
- }
- return (0);
+ case rvc_zero:
+ case rvc_inf:
+ return true;
- difrnt:
- if (*(--a) > *(--b))
- return (1);
- else
- return (-1);
-}
+ case rvc_normal:
+ if (a->decimal != b->decimal)
+ return false;
+ if (REAL_EXP (a) != REAL_EXP (b))
+ return false;
+ break;
-/* Shift significand of exploded e-type X down by 1 bit. */
+ 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;
-static void
-eshdn1 (x)
- register unsigned EMUSHORT *x;
-{
- register unsigned EMUSHORT bits;
- int i;
+ default:
+ gcc_unreachable ();
+ }
- x += M; /* point to significand area */
+ for (i = 0; i < SIGSZ; ++i)
+ if (a->sig[i] != b->sig[i])
+ return false;
- bits = 0;
- for (i = M; i < NI; i++)
- {
- if (*x & 1)
- bits |= 1;
- *x >>= 1;
- if (bits & 2)
- *x |= 0x8000;
- bits <<= 1;
- ++x;
- }
+ return true;
}
-/* Shift significand of exploded e-type X up by 1 bit. */
+/* Try to change R into its exact multiplicative inverse in machine
+ mode MODE. Return true if successful. */
-static void
-eshup1 (x)
- register unsigned EMUSHORT *x;
+bool
+exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
{
- register unsigned EMUSHORT bits;
+ const REAL_VALUE_TYPE *one = real_digit (1);
+ REAL_VALUE_TYPE u;
int i;
- x += NI - 1;
- bits = 0;
-
- for (i = M; i < NI; i++)
- {
- if (*x & 0x8000)
- bits |= 1;
- *x <<= 1;
- if (bits & 2)
- *x |= 1;
- bits <<= 1;
- --x;
- }
+ if (r->cl != rvc_normal)
+ return false;
+
+ /* Check for a power of two: all significand bits zero except the MSB. */
+ for (i = 0; i < SIGSZ-1; ++i)
+ if (r->sig[i] != 0)
+ return false;
+ if (r->sig[SIGSZ-1] != SIG_MSB)
+ return false;
+
+ /* Find the inverse and truncate to the required mode. */
+ do_divide (&u, one, r);
+ real_convert (&u, mode, &u);
+
+ /* The rounding may have overflowed. */
+ if (u.cl != rvc_normal)
+ return false;
+ for (i = 0; i < SIGSZ-1; ++i)
+ if (u.sig[i] != 0)
+ return false;
+ if (u.sig[SIGSZ-1] != SIG_MSB)
+ return false;
+
+ *r = u;
+ return true;
+}
+
+/* Return true if arithmetic on values in IMODE that were promoted
+ from values in TMODE is equivalent to direct arithmetic on values
+ in TMODE. */
+
+bool
+real_can_shorten_arithmetic (enum machine_mode imode, enum machine_mode tmode)
+{
+ const struct real_format *tfmt, *ifmt;
+ tfmt = REAL_MODE_FORMAT (tmode);
+ ifmt = REAL_MODE_FORMAT (imode);
+ /* These conditions are conservative rather than trying to catch the
+ exact boundary conditions; the main case to allow is IEEE float
+ and double. */
+ return (ifmt->b == tfmt->b
+ && ifmt->p > 2 * tfmt->p
+ && ifmt->emin < 2 * tfmt->emin - tfmt->p - 2
+ && ifmt->emin < tfmt->emin - tfmt->emax - tfmt->p - 2
+ && ifmt->emax > 2 * tfmt->emax + 2
+ && ifmt->emax > tfmt->emax - tfmt->emin + tfmt->p + 2
+ && ifmt->round_towards_zero == tfmt->round_towards_zero
+ && (ifmt->has_sign_dependent_rounding
+ == tfmt->has_sign_dependent_rounding)
+ && ifmt->has_nans >= tfmt->has_nans
+ && ifmt->has_inf >= tfmt->has_inf
+ && ifmt->has_signed_zero >= tfmt->has_signed_zero
+ && !MODE_COMPOSITE_P (tmode)
+ && !MODE_COMPOSITE_P (imode));
}
+\f
+/* Render R as an integer. */
+HOST_WIDE_INT
+real_to_integer (const REAL_VALUE_TYPE *r)
+{
+ unsigned HOST_WIDE_INT i;
+
+ switch (r->cl)
+ {
+ case rvc_zero:
+ underflow:
+ return 0;
+
+ case rvc_inf:
+ case rvc_nan:
+ overflow:
+ i = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+ if (!r->sign)
+ i--;
+ return i;
+
+ case rvc_normal:
+ if (r->decimal)
+ return decimal_real_to_integer (r);
+
+ if (REAL_EXP (r) <= 0)
+ goto underflow;
+ /* Only force overflow for unsigned overflow. Signed overflow is
+ undefined, so it doesn't matter what we return, and some callers
+ expect to be able to use this routine for both signed and
+ unsigned conversions. */
+ if (REAL_EXP (r) > HOST_BITS_PER_WIDE_INT)
+ goto overflow;
+
+ if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+ i = r->sig[SIGSZ-1];
+ else
+ {
+ gcc_assert (HOST_BITS_PER_WIDE_INT == 2 * HOST_BITS_PER_LONG);
+ i = r->sig[SIGSZ-1];
+ i = i << (HOST_BITS_PER_LONG - 1) << 1;
+ i |= r->sig[SIGSZ-2];
+ }
-/* Shift significand of exploded e-type X down by 8 bits. */
+ i >>= HOST_BITS_PER_WIDE_INT - REAL_EXP (r);
-static void
-eshdn8 (x)
- register unsigned EMUSHORT *x;
-{
- register unsigned EMUSHORT newbyt, oldbyt;
- int i;
+ if (r->sign)
+ i = -i;
+ return i;
- x += M;
- oldbyt = 0;
- for (i = M; i < NI; i++)
- {
- newbyt = *x << 8;
- *x >>= 8;
- *x |= oldbyt;
- oldbyt = newbyt;
- ++x;
+ default:
+ gcc_unreachable ();
}
}
-/* Shift significand of exploded e-type X up by 8 bits. */
+/* Likewise, but to an integer pair, HI+LOW. */
-static void
-eshup8 (x)
- register unsigned EMUSHORT *x;
+void
+real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh,
+ const REAL_VALUE_TYPE *r)
{
- int i;
- register unsigned EMUSHORT newbyt, oldbyt;
-
- x += NI - 1;
- oldbyt = 0;
+ REAL_VALUE_TYPE t;
+ HOST_WIDE_INT low, high;
+ int exp;
- for (i = M; i < NI; i++)
+ switch (r->cl)
{
- newbyt = *x >> 8;
- *x <<= 8;
- *x |= oldbyt;
- oldbyt = newbyt;
- --x;
- }
-}
+ case rvc_zero:
+ underflow:
+ low = high = 0;
+ break;
+
+ case rvc_inf:
+ case rvc_nan:
+ overflow:
+ high = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+ if (r->sign)
+ low = 0;
+ else
+ {
+ high--;
+ low = -1;
+ }
+ break;
-/* Shift significand of exploded e-type X up by 16 bits. */
+ case rvc_normal:
+ if (r->decimal)
+ {
+ decimal_real_to_integer2 (plow, phigh, r);
+ return;
+ }
-static void
-eshup6 (x)
- register unsigned EMUSHORT *x;
-{
- int i;
- register unsigned EMUSHORT *p;
+ exp = REAL_EXP (r);
+ if (exp <= 0)
+ goto underflow;
+ /* Only force overflow for unsigned overflow. Signed overflow is
+ undefined, so it doesn't matter what we return, and some callers
+ expect to be able to use this routine for both signed and
+ unsigned conversions. */
+ if (exp > 2*HOST_BITS_PER_WIDE_INT)
+ goto overflow;
+
+ rshift_significand (&t, r, 2*HOST_BITS_PER_WIDE_INT - exp);
+ if (HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG)
+ {
+ high = t.sig[SIGSZ-1];
+ low = t.sig[SIGSZ-2];
+ }
+ else
+ {
+ gcc_assert (HOST_BITS_PER_WIDE_INT == 2*HOST_BITS_PER_LONG);
+ high = t.sig[SIGSZ-1];
+ high = high << (HOST_BITS_PER_LONG - 1) << 1;
+ high |= t.sig[SIGSZ-2];
+
+ low = t.sig[SIGSZ-3];
+ low = low << (HOST_BITS_PER_LONG - 1) << 1;
+ low |= t.sig[SIGSZ-4];
+ }
- p = x + M;
- x += M + 1;
+ if (r->sign)
+ {
+ if (low == 0)
+ high = -high;
+ else
+ low = -low, high = ~high;
+ }
+ break;
- for (i = M; i < NI - 1; i++)
- *p++ = *x++;
+ default:
+ gcc_unreachable ();
+ }
- *p = 0;
+ *plow = low;
+ *phigh = high;
}
-/* Shift significand of exploded e-type X down by 16 bits. */
+/* 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
-eshdn6 (x)
- register unsigned EMUSHORT *x;
+static unsigned long
+rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den)
{
- int i;
- register unsigned EMUSHORT *p;
+ unsigned long q, msb;
+ int expn = REAL_EXP (num), expd = REAL_EXP (den);
- x += NI - 1;
- p = x + 1;
+ if (expn < expd)
+ return 0;
+
+ q = msb = 0;
+ goto start;
+ do
+ {
+ msb = num->sig[SIGSZ-1] & SIG_MSB;
+ q <<= 1;
+ lshift_significand_1 (num, num);
+ start:
+ if (msb || cmp_significands (num, den) >= 0)
+ {
+ sub_significands (num, num, den, 0);
+ q |= 1;
+ }
+ }
+ while (--expn >= expd);
- for (i = M; i < NI - 1; i++)
- *(--p) = *(--x);
+ SET_REAL_EXP (num, expd);
+ normalize (num);
- *(--p) = 0;
+ return q;
}
-/* Add significands of exploded e-type X and Y. X + Y replaces Y. */
+/* Render R as a decimal floating point constant. Emit DIGITS significant
+ digits in the result, bounded by BUF_SIZE. If DIGITS is 0, choose the
+ maximum for the representation. If CROP_TRAILING_ZEROS, strip trailing
+ zeros. If MODE is VOIDmode, round to nearest value. Otherwise, round
+ to a string that, when parsed back in mode MODE, yields the same value. */
-static void
-eaddm (x, y)
- unsigned EMUSHORT *x, *y;
-{
- register unsigned EMULONG a;
- int i;
- unsigned int carry;
+#define M_LOG10_2 0.30102999566398119521
- 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;
+void
+real_to_decimal_for_mode (char *str, const REAL_VALUE_TYPE *r_orig,
+ size_t buf_size, size_t digits,
+ int crop_trailing_zeros, enum machine_mode mode)
+{
+ const struct real_format *fmt = NULL;
+ const REAL_VALUE_TYPE *one, *ten;
+ REAL_VALUE_TYPE r, pten, u, v;
+ int dec_exp, cmp_one, digit;
+ size_t max_digits;
+ char *p, *first, *last;
+ bool sign;
+ bool round_up;
+
+ if (mode != VOIDmode)
+ {
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+ }
+
+ r = *r_orig;
+ switch (r.cl)
+ {
+ case rvc_zero:
+ strcpy (str, (r.sign ? "-0.0" : "0.0"));
+ return;
+ case rvc_normal:
+ break;
+ case rvc_inf:
+ strcpy (str, (r.sign ? "-Inf" : "+Inf"));
+ return;
+ case rvc_nan:
+ /* ??? Print the significand as well, if not canonical? */
+ sprintf (str, "%c%cNaN", (r_orig->sign ? '-' : '+'),
+ (r_orig->signalling ? 'S' : 'Q'));
+ return;
+ default:
+ gcc_unreachable ();
}
-}
-
-/* Subtract significands of exploded e-type X and Y. Y - X replaces Y. */
-
-static void
-esubm (x, y)
- unsigned EMUSHORT *x, *y;
-{
- unsigned EMULONG a;
- int i;
- unsigned int carry;
- x += NI - 1;
- y += NI - 1;
- carry = 0;
- for (i = M; i < NI; i++)
+ if (r.decimal)
{
- a = (unsigned EMULONG) (*y) - (unsigned EMULONG) (*x) - carry;
- if (a & 0x10000)
- carry = 1;
- else
- carry = 0;
- *y = (unsigned EMUSHORT) a;
- --x;
- --y;
+ decimal_real_to_decimal (str, &r, buf_size, digits, crop_trailing_zeros);
+ return;
}
-}
-
-static unsigned EMUSHORT equot[NI];
+ /* Bound the number of digits printed by the size of the representation. */
+ max_digits = SIGNIFICAND_BITS * M_LOG10_2;
+ if (digits == 0 || digits > max_digits)
+ digits = max_digits;
+ /* Estimate the decimal exponent, and compute the length of the string it
+ will print as. Be conservative and add one to account for possible
+ overflow or rounding error. */
+ dec_exp = REAL_EXP (&r) * M_LOG10_2;
+ for (max_digits = 1; dec_exp ; max_digits++)
+ dec_exp /= 10;
-#if 0
-/* Radix 2 shift-and-add versions of multiply and divide */
+ /* Bound the number of digits printed by the size of the output buffer. */
+ max_digits = buf_size - 1 - 1 - 2 - max_digits - 1;
+ gcc_assert (max_digits <= buf_size);
+ if (digits > max_digits)
+ digits = max_digits;
+ one = real_digit (1);
+ ten = ten_to_ptwo (0);
-/* Divide significands */
-
-int
-edivm (den, num)
- unsigned EMUSHORT den[], num[];
-{
- int i;
- register unsigned EMUSHORT *p, *q;
- unsigned EMUSHORT j;
+ sign = r.sign;
+ r.sign = 0;
- p = &equot[0];
- *p++ = num[0];
- *p++ = num[1];
+ dec_exp = 0;
+ pten = *one;
- for (i = M; i < NI; i++)
+ cmp_one = do_compare (&r, one, 0);
+ if (cmp_one > 0)
{
- *p++ = 0;
- }
+ int m;
- /* Use faster compare and subtraction if denominator has only 15 bits of
- significance. */
+ /* Number is greater than one. Convert significand to an integer
+ and strip trailing decimal zeros. */
- p = &den[M + 2];
- if (*p++ == 0)
- {
- for (i = M + 3; i < NI; i++)
- {
- if (*p++ != 0)
- goto fulldiv;
- }
- if ((den[M + 1] & 1) != 0)
- goto fulldiv;
- eshdn1 (num);
- eshdn1 (den);
+ u = r;
+ SET_REAL_EXP (&u, SIGNIFICAND_BITS - 1);
- p = &den[M + 1];
- q = &num[M + 1];
+ /* Largest M, such that 10**2**M fits within SIGNIFICAND_BITS. */
+ m = floor_log2 (max_digits);
- for (i = 0; i < NBITS + 2; i++)
+ /* 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
{
- if (*p <= *q)
- {
- *q -= *p;
- j = 1;
- }
- else
+ REAL_VALUE_TYPE t;
+
+ do_divide (&t, &u, ten_to_ptwo (m));
+ do_fix_trunc (&v, &t);
+ if (cmp_significands (&v, &t) == 0)
{
- j = 0;
+ u = t;
+ dec_exp += 1 << m;
}
- 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. */
+ while (--m >= 0);
- fulldiv:
+ /* Revert the scaling to integer that we performed earlier. */
+ SET_REAL_EXP (&u, REAL_EXP (&u) + REAL_EXP (&r)
+ - (SIGNIFICAND_BITS - 1));
+ r = u;
- p = &equot[NI - 2];
- for (i = 0; i < NBITS + 2; i++)
- {
- if (ecmpm (den, num) <= 0)
+ /* Find power of 10. Do this by dividing out 10**2**M when
+ this is larger than the current remainder. Fill PTEN with
+ the power of 10 that we compute. */
+ if (REAL_EXP (&r) > 0)
{
- esubm (den, num);
- j = 1; /* quotient bit = 1 */
+ m = floor_log2 ((int)(REAL_EXP (&r) * M_LOG10_2)) + 1;
+ do
+ {
+ const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m);
+ if (do_compare (&u, ptentwo, 0) >= 0)
+ {
+ do_divide (&u, &u, ptentwo);
+ do_multiply (&pten, &pten, ptentwo);
+ dec_exp += 1 << m;
+ }
+ }
+ while (--m >= 0);
}
else
- j = 0;
- eshup1 (equot);
- *p |= j;
- eshup1 (num);
+ /* 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;
- divdon:
+ /* Number is less than one. Pad significand with leading
+ decimal zeros. */
- eshdn1 (equot);
- eshdn1 (equot);
-
- /* 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);
-}
-
-
-/* Multiply significands */
-
-int
-emulm (a, b)
- unsigned EMUSHORT a[], b[];
-{
- 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);
- }
-
- for (i = 0; i < NI; i++)
- b[i] = equot[i];
-
- /* return flag for lost nonzero bits */
- return (j);
-}
-
-#else
-
-/* Radix 65536 versions of multiply and divide. */
-
-/* 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[];
-{
- register unsigned EMUSHORT *pp;
- register unsigned EMULONG carry;
- unsigned EMUSHORT *ps;
- unsigned EMUSHORT p[NI];
- unsigned EMULONG aa, m;
- int i;
-
- aa = a;
- pp = &p[NI-2];
- *pp++ = 0;
- *pp = 0;
- ps = &b[NI-1];
-
- for (i=M+1; i<NI; i++)
- {
- if (*ps == 0)
+ v = r;
+ while (1)
{
- --ps;
- --pp;
- *(pp-1) = 0;
- }
- else
- {
- 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;
- }
- }
- for (i=M; i<NI; i++)
- c[i] = p[i];
-}
-
-/* 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. */
+ /* Stop if we'd shift bits off the bottom. */
+ if (v.sig[0] & 7)
+ break;
-static int
-edivm (den, num)
- unsigned EMUSHORT den[], num[];
-{
- int i;
- register unsigned EMUSHORT *p;
- unsigned EMULONG tnum;
- unsigned EMUSHORT j, tdenm, tquot;
- unsigned EMUSHORT tprod[NI+1];
+ do_multiply (&u, &v, ten);
- p = &equot[0];
- *p++ = num[0];
- *p++ = num[1];
+ /* Stop if we're now >= 1. */
+ if (REAL_EXP (&u) > 0)
+ break;
- for (i=M; i<NI; i++)
- {
- *p++ = 0;
- }
- eshdn1 (num);
- tdenm = den[M+1];
- for (i=M; i<NI; i++)
- {
- /* Find trial quotient digit (the radix is 65536). */
- tnum = (((unsigned EMULONG) num[M]) << 16) + num[M+1];
+ v = u;
+ dec_exp -= 1;
+ }
+ r = v;
- /* Do not execute the divide instruction if it will overflow. */
- if ((tdenm * 0xffffL) < tnum)
- tquot = 0xffff;
- 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)
+ /* Find power of 10. Do this by multiplying in P=10**2**M when
+ the current remainder is smaller than 1/P. Fill PTEN with the
+ power of 10 that we compute. */
+ m = floor_log2 ((int)(-REAL_EXP (&r) * M_LOG10_2)) + 1;
+ do
{
- tquot -= 1;
- esubm (den, tprod);
- if (ecmpm (tprod, num) > 0)
+ const REAL_VALUE_TYPE *ptentwo = ten_to_ptwo (m);
+ const REAL_VALUE_TYPE *ptenmtwo = ten_to_mptwo (m);
+
+ if (do_compare (&v, ptenmtwo, 0) <= 0)
{
- tquot -= 1;
- esubm (den, tprod);
+ do_multiply (&v, &v, ptentwo);
+ do_multiply (&pten, &pten, ptentwo);
+ dec_exp -= 1 << m;
}
}
- 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);
-}
-
-/* Multiply significands of exploded e-type A and B, result in B. */
-
-static int
-emulm (a, b)
- unsigned EMUSHORT a[], b[];
-{
- unsigned EMUSHORT *p, *q;
- unsigned EMUSHORT pprod[NI];
- unsigned EMUSHORT j;
- int i;
+ while (--m >= 0);
- 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);
+ /* Invert the positive power of 10 that we've collected so far. */
+ do_divide (&pten, one, &pten);
}
- for (i=0; i<NI; i++)
- b[i] = equot[i];
-
- /* return flag for lost nonzero bits */
- return ((int)j);
-}
-#endif
+ p = str;
+ if (sign)
+ *p++ = '-';
+ first = p++;
+ /* At this point, PTEN should contain the nearest power of 10 smaller
+ than R, such that this division produces the first digit.
-/* 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.
-
- 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.
-
- Input RCNTRL is the rounding control. If it is nonzero, the
- returned value will be rounded to RNDPRC bits.
-
- 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. */
-
-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];
-
-static void
-emdnorm (s, lost, subflg, exp, rcntrl)
- unsigned EMUSHORT s[];
- int lost;
- int subflg;
- EMULONG exp;
- int rcntrl;
-{
- int i, j;
- unsigned EMUSHORT r;
+ 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. */
- /* Normalize */
- j = enormlz (s);
+ digit = rtd_divmod (&r, &pten);
- /* a blank significand could mean either zero or infinity. */
-#ifndef INFINITY
- if (j > NBITS)
+ /* Be prepared for error in that division via underflow ... */
+ if (digit == 0 && cmp_significand_0 (&r))
{
- ecleazs (s);
- return;
+ /* Multiply by 10 and try again. */
+ do_multiply (&r, &r, ten);
+ digit = rtd_divmod (&r, &pten);
+ dec_exp -= 1;
+ gcc_assert (digit != 0);
}
-#endif
- exp -= j;
-#ifndef INFINITY
- if (exp >= 32767L)
- goto overf;
-#else
- if ((j > NBITS) && (exp < 32767))
+
+ /* ... or overflow. */
+ if (digit == 10)
{
- ecleazs (s);
- return;
+ *p++ = '1';
+ if (--digits > 0)
+ *p++ = '0';
+ dec_exp += 1;
}
-#endif
- if (exp < 0L)
+ else
{
- if (exp > (EMULONG) (-NBITS - 1))
- {
- j = (int) exp;
- i = eshift (s, j);
- if (i)
- lost = 1;
- }
- else
- {
- ecleazs (s);
- return;
- }
+ gcc_assert (digit <= 10);
+ *p++ = digit + '0';
}
- /* 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)
+
+ /* Generate subsequent digits. */
+ while (--digits > 0)
{
- 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;
+ do_multiply (&r, &r, ten);
+ digit = rtd_divmod (&r, &pten);
+ *p++ = digit + '0';
}
+ last = p;
+
+ /* Generate one more digit with which to do rounding. */
+ do_multiply (&r, &r, ten);
+ digit = rtd_divmod (&r, &pten);
- /* 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)))
+ /* Round the result. */
+ if (fmt && fmt->round_towards_zero)
{
- lost |= s[NI - 1] & 1;
- eshdn1 (s);
+ /* If the format uses round towards zero when parsing the string
+ back in, we need to always round away from zero here. */
+ if (cmp_significand_0 (&r))
+ digit++;
+ round_up = digit > 0;
}
- /* Clear out all bits below the rounding bit,
- remembering in r if any were nonzero. */
- r = s[rw] & rmsk;
- if (rndprc < NBITS)
+ else
{
- i = rw + 1;
- while (i < NI)
+ if (digit == 5)
{
- if (s[i])
- r |= 1;
- s[i] = 0;
- ++i;
+ /* Round to nearest. If R is nonzero there are additional
+ nonzero digits to be extracted. */
+ if (cmp_significand_0 (&r))
+ digit++;
+ /* Round to even. */
+ else if ((p[-1] - '0') & 1)
+ digit++;
}
+
+ round_up = digit > 5;
}
- s[rw] &= ~rmsk;
- if ((r & rmbit) != 0)
+
+ if (round_up)
{
- if (r == rmbit)
+ while (p > first)
{
- if (lost == 0)
- { /* round to even */
- if ((s[re] & rebit) == 0)
- goto mddone;
- }
+ digit = *--p;
+ if (digit == '9')
+ *p = '0';
else
{
- if (subflg != 0)
- goto mddone;
+ *p = digit + 1;
+ break;
}
}
- 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))
+
+ /* 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)
{
- s[rw] &= ~rmsk;
- if (rndprc == 24)
- {
- s[5] = 0;
- s[6] = 0;
- }
+ first[1] = '1';
+ dec_exp++;
}
-#endif
- return;
}
- if (exp < 0)
- s[1] = 0;
- else
- s[1] = (unsigned EMUSHORT) exp;
-}
-/* Subtract. C = B - A, all e type numbers. */
+ /* Insert the decimal point. */
+ first[0] = first[1];
+ first[1] = '.';
-static int subflg = 0;
+ /* If requested, drop trailing zeros. Never crop past "1.0". */
+ if (crop_trailing_zeros)
+ while (last > first + 3 && last[-1] == '0')
+ last--;
-static void
-esub (a, b, c)
- unsigned EMUSHORT *a, *b, *c;
-{
+ /* Append the exponent. */
+ sprintf (last, "e%+d", dec_exp);
-#ifdef NANS
- if (eisnan (a))
+#ifdef ENABLE_CHECKING
+ /* Verify that we can read the original value back in. */
+ if (mode != VOIDmode)
{
- 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;
+ real_from_string (&r, str);
+ real_convert (&r, mode, &r);
+ gcc_assert (real_identical (&r, r_orig));
}
#endif
- subflg = 1;
- eadd1 (a, b, c);
}
-/* Add. C = A + B, all e type. */
+/* Likewise, except always uses round-to-nearest. */
+
+void
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
+{
+ real_to_decimal_for_mode (str, r_orig, buf_size,
+ digits, crop_trailing_zeros, VOIDmode);
+}
+
+/* Render R as a hexadecimal floating point constant. Emit DIGITS
+ significant digits in the result, bounded by BUF_SIZE. If DIGITS is 0,
+ choose the maximum for the representation. If CROP_TRAILING_ZEROS,
+ strip trailing zeros. */
-static void
-eadd (a, b, c)
- unsigned EMUSHORT *a, *b, *c;
+void
+real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
{
+ int i, j, exp = REAL_EXP (r);
+ char *p, *first;
+ char exp_buf[16];
+ size_t max_digits;
-#ifdef NANS
-/* NaN plus anything is a NaN. */
- if (eisnan (a))
+ switch (r->cl)
{
- emov (a, c);
+ case rvc_zero:
+ exp = 0;
+ break;
+ case rvc_normal:
+ break;
+ case rvc_inf:
+ strcpy (str, (r->sign ? "-Inf" : "+Inf"));
return;
- }
- if (eisnan (b))
- {
- emov (b, c);
+ case rvc_nan:
+ /* ??? Print the significand as well, if not canonical? */
+ sprintf (str, "%c%cNaN", (r->sign ? '-' : '+'),
+ (r->signalling ? 'S' : 'Q'));
return;
+ default:
+ gcc_unreachable ();
}
-/* Infinity minus infinity is a NaN.
- Test for adding infinities of opposite signs. */
- if (eisinf (a) && eisinf (b)
- && ((eisneg (a) ^ eisneg (b)) != 0))
+
+ if (r->decimal)
{
- mtherr ("esub", INVALID);
- enan (c, 0);
+ /* Hexadecimal format for decimal floats is not interesting. */
+ strcpy (str, "N/A");
return;
}
-#endif
- subflg = 0;
- eadd1 (a, b, c);
+
+ if (digits == 0)
+ digits = SIGNIFICAND_BITS / 4;
+
+ /* Bound the number of digits printed by the size of the output buffer. */
+
+ sprintf (exp_buf, "p%+d", exp);
+ max_digits = buf_size - strlen (exp_buf) - r->sign - 4 - 1;
+ gcc_assert (max_digits <= buf_size);
+ if (digits > max_digits)
+ digits = max_digits;
+
+ p = str;
+ if (r->sign)
+ *p++ = '-';
+ *p++ = '0';
+ *p++ = 'x';
+ *p++ = '0';
+ *p++ = '.';
+ first = p;
+
+ for (i = SIGSZ - 1; i >= 0; --i)
+ for (j = HOST_BITS_PER_LONG - 4; j >= 0; j -= 4)
+ {
+ *p++ = "0123456789abcdef"[(r->sig[i] >> j) & 15];
+ if (--digits == 0)
+ goto out;
+ }
+
+ out:
+ if (crop_trailing_zeros)
+ while (p > first + 1 && p[-1] == '0')
+ p--;
+
+ sprintf (p, "p%+d", exp);
}
-/* Arithmetic common to both addition and subtraction. */
+/* Initialize R from a decimal or hexadecimal string. The string is
+ assumed to have been syntax checked already. Return -1 if the
+ value underflows, +1 if overflows, and 0 otherwise. */
-static void
-eadd1 (a, b, c)
- unsigned EMUSHORT *a, *b, *c;
+int
+real_from_string (REAL_VALUE_TYPE *r, const char *str)
{
- unsigned EMUSHORT ai[NI], bi[NI], ci[NI];
- int i, lost, j, k;
- EMULONG lt, lta, ltb;
+ int exp = 0;
+ bool sign = false;
-#ifdef INFINITY
- if (eisinf (a))
+ get_zero (r, 0);
+
+ if (*str == '-')
{
- emov (a, c);
- if (subflg)
- eneg (c);
- return;
+ sign = true;
+ str++;
}
- if (eisinf (b))
+ else if (*str == '+')
+ str++;
+
+ if (!strncmp (str, "QNaN", 4))
{
- emov (b, c);
- return;
+ get_canonical_qnan (r, sign);
+ return 0;
}
-#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;
+ else if (!strncmp (str, "SNaN", 4))
+ {
+ get_canonical_snan (r, sign);
+ return 0;
}
- lost = 0;
- if (lt != 0L)
+ else if (!strncmp (str, "Inf", 3))
{
- if (lt < (EMULONG) (-NBITS - 1))
- goto done; /* answer same as larger addend */
- k = (int) lt;
- lost = eshift (ai, k); /* shift the smaller number down */
+ get_inf (r, sign);
+ return 0;
}
- else
+
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
{
- /* 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])
+ /* Hexadecimal floating point. */
+ int pos = SIGNIFICAND_BITS - 4, d;
+
+ str += 2;
+
+ while (*str == '0')
+ str++;
+ while (1)
+ {
+ d = hex_value (*str);
+ if (d == _hex_bad)
+ break;
+ if (pos >= 0)
{
- eclear (c);
- return;
+ r->sig[pos / HOST_BITS_PER_LONG]
+ |= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
+ pos -= 4;
}
- /* if same sign, result is double */
- /* double denormalized tiny number */
- if ((bi[E] == 0) && ((bi[3] & 0x8000) == 0))
+ else if (d)
+ /* Ensure correct rounding by setting last bit if there is
+ a subsequent nonzero digit. */
+ r->sig[0] |= 1;
+ exp += 4;
+ str++;
+ }
+ if (*str == '.')
+ {
+ str++;
+ if (pos == SIGNIFICAND_BITS - 4)
{
- eshup1 (bi);
- goto done;
+ while (*str == '0')
+ str++, exp -= 4;
}
- /* add 1 to exponent unless both are zero! */
- for (j = 1; j < NI - 1; j++)
+ while (1)
{
- if (bi[j] != 0)
+ d = hex_value (*str);
+ if (d == _hex_bad)
+ break;
+ if (pos >= 0)
{
- ltb += 1;
- if (ltb >= 0x7fff)
- {
- eclear (c);
- if (ai[0] != 0)
- eneg (c);
- einfin (c);
- return;
- }
- break;
+ r->sig[pos / HOST_BITS_PER_LONG]
+ |= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
+ pos -= 4;
}
+ else if (d)
+ /* Ensure correct rounding by setting last bit if there is
+ a subsequent nonzero digit. */
+ r->sig[0] |= 1;
+ str++;
}
- 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);
-}
+ /* If the mantissa is zero, ignore the exponent. */
+ if (!cmp_significand_0 (r))
+ goto is_a_zero;
-/* Divide: C = B/A, all e type. */
+ if (*str == 'p' || *str == 'P')
+ {
+ bool exp_neg = false;
-static void
-ediv (a, b, c)
- unsigned EMUSHORT *a, *b, *c;
-{
- unsigned EMUSHORT ai[NI], bi[NI];
- int i, sign;
- EMULONG lt, lta, ltb;
+ str++;
+ if (*str == '-')
+ {
+ exp_neg = true;
+ str++;
+ }
+ else if (*str == '+')
+ str++;
-/* 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);
+ 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;
-#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;
+ exp += d;
+ }
+
+ r->cl = rvc_normal;
+ SET_REAL_EXP (r, exp);
+
+ normalize (r);
}
-/* Anything else over infinity is zero. */
- if (eisinf (a))
+ else
{
- 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++)
+ /* Decimal floating point. */
+ const REAL_VALUE_TYPE *ten = ten_to_ptwo (0);
+ int d;
+
+ while (*str == '0')
+ str++;
+ while (ISDIGIT (*str))
+ {
+ d = *str++ - '0';
+ do_multiply (r, r, ten);
+ if (d)
+ do_add (r, r, real_digit (d), 0);
+ }
+ if (*str == '.')
{
- if (bi[i] != 0)
+ str++;
+ if (r->cl == rvc_zero)
+ {
+ while (*str == '0')
+ str++, exp--;
+ }
+ while (ISDIGIT (*str))
{
- ltb -= enormlz (bi);
- goto dnzro1;
+ d = *str++ - '0';
+ do_multiply (r, r, ten);
+ if (d)
+ do_add (r, r, real_digit (d), 0);
+ exp--;
}
}
- eclear (c);
- goto divsign;
- }
- dnzro1:
- if (ai[E] == 0)
- { /* possible divide by zero */
- for (i = 1; i < NI - 1; i++)
+ /* If the mantissa is zero, ignore the exponent. */
+ if (r->cl == rvc_zero)
+ goto is_a_zero;
+
+ if (*str == 'e' || *str == 'E')
{
- if (ai[i] != 0)
+ bool exp_neg = false;
+
+ str++;
+ if (*str == '-')
+ {
+ exp_neg = true;
+ str++;
+ }
+ else if (*str == '+')
+ str++;
+
+ d = 0;
+ while (ISDIGIT (*str))
{
- lta -= enormlz (ai);
- goto dnzro2;
+ 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;
}
-/* Divide by zero is not an invalid operation.
- It is a divide-by-zero operation! */
- einfin (c);
- mtherr ("ediv", SING);
- goto divsign;
+
+ if (exp)
+ times_pten (r, exp);
}
- dnzro2:
- i = edivm (ai, bi);
- /* calculate exponent */
- lt = ltb - lta + EXONE;
- emdnorm (bi, i, 0, lt, 64);
- emovo (bi, c);
+ r->sign = sign;
+ return 0;
- divsign:
+ is_a_zero:
+ get_zero (r, sign);
+ return 0;
- if (sign
-#ifndef IEEE
- && (ecmp (c, ezero) != 0)
-#endif
- )
- *(c+(NE-1)) |= 0x8000;
- else
- *(c+(NE-1)) &= ~0x8000;
+ underflow:
+ get_zero (r, sign);
+ return -1;
+
+ overflow:
+ get_inf (r, sign);
+ return 1;
}
-/* Multiply e-types A and B, return e-type product C. */
+/* Legacy. Similar, but return the result directly. */
-static void
-emul (a, b, c)
- unsigned EMUSHORT *a, *b, *c;
+REAL_VALUE_TYPE
+real_from_string2 (const char *s, enum machine_mode mode)
{
- unsigned EMUSHORT ai[NI], bi[NI];
- int i, j, sign;
- EMULONG lt, lta, ltb;
+ REAL_VALUE_TYPE r;
-/* 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);
+ real_from_string (&r, s);
+ if (mode != VOIDmode)
+ real_convert (&r, mode, &r);
-#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)
+ return r;
+}
+
+/* Initialize R from string S and desired MODE. */
+
+void
+real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode)
+{
+ if (DECIMAL_FLOAT_MODE_P (mode))
+ decimal_real_from_string (r, s);
+ else
+ real_from_string (r, s);
+
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Initialize R from the integer pair HIGH+LOW. */
+
+void
+real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ unsigned HOST_WIDE_INT low, HOST_WIDE_INT high,
+ int unsigned_p)
+{
+ if (low == 0 && high == 0)
+ get_zero (r, 0);
+ else
{
- for (i = 1; i < NI - 1; i++)
+ memset (r, 0, sizeof (*r));
+ r->cl = rvc_normal;
+ r->sign = high < 0 && !unsigned_p;
+ SET_REAL_EXP (r, 2 * HOST_BITS_PER_WIDE_INT);
+
+ if (r->sign)
{
- if (ai[i] != 0)
- {
- lta -= enormlz (ai);
- goto mnzer1;
- }
+ high = ~high;
+ if (low == 0)
+ high += 1;
+ else
+ low = -low;
}
- eclear (c);
- goto mulsign;
- }
- mnzer1:
- if (bi[E] == 0)
- {
- for (i = 1; i < NI - 1; i++)
+ if (HOST_BITS_PER_LONG == HOST_BITS_PER_WIDE_INT)
{
- if (bi[i] != 0)
- {
- ltb -= enormlz (bi);
- goto mnzer2;
- }
+ r->sig[SIGSZ-1] = high;
+ r->sig[SIGSZ-2] = low;
+ }
+ else
+ {
+ gcc_assert (HOST_BITS_PER_LONG*2 == HOST_BITS_PER_WIDE_INT);
+ r->sig[SIGSZ-1] = high >> (HOST_BITS_PER_LONG - 1) >> 1;
+ r->sig[SIGSZ-2] = high;
+ r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
+ r->sig[SIGSZ-4] = low;
}
- 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:
+ normalize (r);
+ }
- if (sign
-#ifndef IEEE
- && (ecmp (c, ezero) != 0)
-#endif
- )
- *(c+(NE-1)) |= 0x8000;
- else
- *(c+(NE-1)) &= ~0x8000;
+ if (DECIMAL_FLOAT_MODE_P (mode))
+ decimal_from_integer (r);
+ else if (mode != VOIDmode)
+ real_convert (r, mode, r);
}
-/* Convert double precision PE to e-type Y. */
+/* Render R, an integral value, as a floating point constant with no
+ specified exponent. */
static void
-e53toe (pe, y)
- unsigned EMUSHORT *pe, *y;
+decimal_integer_string (char *str, const REAL_VALUE_TYPE *r_orig,
+ size_t buf_size)
{
-#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. */
+ int dec_exp, digit, digits;
+ REAL_VALUE_TYPE r, pten;
+ char *p;
+ bool sign;
- 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)
+ r = *r_orig;
+
+ if (r.cl == rvc_zero)
{
- *p++ = *(--e);
- *p++ = *(--e);
- *p++ = *(--e);
+ strcpy (str, "0.");
+ return;
}
- else
+
+ sign = r.sign;
+ r.sign = 0;
+
+ dec_exp = REAL_EXP (&r) * M_LOG10_2;
+ digits = dec_exp + 1;
+ gcc_assert ((digits + 2) < (int)buf_size);
+
+ pten = *real_digit (1);
+ times_pten (&pten, dec_exp);
+
+ p = str;
+ if (sign)
+ *p++ = '-';
+
+ digit = rtd_divmod (&r, &pten);
+ gcc_assert (digit >= 0 && digit <= 9);
+ *p++ = digit + '0';
+ while (--digits > 0)
{
- ++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);
+ times_pten (&r, 1);
+ digit = rtd_divmod (&r, &pten);
+ *p++ = digit + '0';
}
- emovo (yy, y);
-#endif /* not C4X */
-#endif /* not IBM */
-#endif /* not DEC */
+ *p++ = '.';
+ *p++ = '\0';
}
-/* Convert double extended precision float PE to e type Y. */
+/* Convert a real with an integral value to decimal float. */
-static void
-e64toe (pe, y)
- unsigned EMUSHORT *pe, *y;
+static void
+decimal_from_integer (REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT yy[NI];
- unsigned EMUSHORT *e, *p, *q;
- int i;
+ char str[256];
- 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)
- {
- for (i = 0; i < 5; i++)
- *p++ = *e++;
+ decimal_integer_string (str, r, sizeof (str) - 1);
+ decimal_real_from_string (r, str);
+}
- /* 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];
+/* Returns 10**2**N. */
- emovi(yy, temp);
- eshup1(temp);
- emovo(temp,y);
- return;
- }
- }
- 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)
+static const REAL_VALUE_TYPE *
+ten_to_ptwo (int n)
+{
+ static REAL_VALUE_TYPE tens[EXP_BITS];
+
+ gcc_assert (n >= 0);
+ gcc_assert (n < EXP_BITS);
+
+ if (tens[n].cl == rvc_zero)
{
-#ifdef NANS
- if (! REAL_WORDS_BIG_ENDIAN)
+ if (n < (HOST_BITS_PER_WIDE_INT == 64 ? 5 : 4))
{
- 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;
- }
- }
+ HOST_WIDE_INT t = 10;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ t *= t;
+
+ real_from_integer (&tens[n], VOIDmode, t, 0, 1);
}
else
{
-#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 */
+ const REAL_VALUE_TYPE *t = ten_to_ptwo (n - 1);
+ do_multiply (&tens[n], t, t);
}
-#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++;
+
+ return &tens[n];
}
-/* Convert 128-bit long double precision float PE to e type Y. */
+/* Returns 10**(-2**N). */
-static void
-e113toe (pe, y)
- unsigned EMUSHORT *pe, *y;
+static const REAL_VALUE_TYPE *
+ten_to_mptwo (int n)
{
- 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)
+ static REAL_VALUE_TYPE tens[EXP_BITS];
+
+ gcc_assert (n >= 0);
+ gcc_assert (n < EXP_BITS);
+
+ if (tens[n].cl == rvc_zero)
+ do_divide (&tens[n], real_digit (1), ten_to_ptwo (n));
+
+ return &tens[n];
+}
+
+/* Returns N. */
+
+static const REAL_VALUE_TYPE *
+real_digit (int n)
+{
+ static REAL_VALUE_TYPE num[10];
+
+ gcc_assert (n >= 0);
+ gcc_assert (n <= 9);
+
+ if (n > 0 && num[n].cl == rvc_zero)
+ real_from_integer (&num[n], VOIDmode, n, 0, 1);
+
+ return &num[n];
+}
+
+/* Multiply R by 10**EXP. */
+
+static void
+times_pten (REAL_VALUE_TYPE *r, int exp)
+{
+ REAL_VALUE_TYPE pten, *rr;
+ bool negative = (exp < 0);
+ int i;
+
+ if (negative)
{
- for (i = 0; i < 7; i++)
- *p++ = *(--e);
+ exp = -exp;
+ pten = *real_digit (1);
+ rr = &pten;
}
else
+ rr = r;
+
+ for (i = 0; exp > 0; ++i, exp >>= 1)
+ if (exp & 1)
+ do_multiply (rr, rr, ten_to_ptwo (i));
+
+ if (negative)
+ do_divide (r, r, &pten);
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to 'e'. */
+
+const REAL_VALUE_TYPE *
+dconst_e_ptr (void)
+{
+ static REAL_VALUE_TYPE value;
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ if (value.cl == rvc_zero)
{
- ++e;
- for (i = 0; i < 7; i++)
- *p++ = *e++;
+ mpfr_t m;
+ mpfr_init2 (m, SIGNIFICAND_BITS);
+ mpfr_set_ui (m, 1, GMP_RNDN);
+ mpfr_exp (m, m, GMP_RNDN);
+ real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+ mpfr_clear (m);
+
}
-#endif
-/* If denormal, remove the implied bit; else shift down 1. */
- if (r == 0)
+ return &value;
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to 1/3. */
+
+const REAL_VALUE_TYPE *
+dconst_third_ptr (void)
+{
+ static REAL_VALUE_TYPE value;
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ if (value.cl == rvc_zero)
{
- yy[M] = 0;
+ real_arithmetic (&value, RDIV_EXPR, &dconst1, real_digit (3));
}
- else
+ return &value;
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to sqrt(2). */
+
+const REAL_VALUE_TYPE *
+dconst_sqrt2_ptr (void)
+{
+ static REAL_VALUE_TYPE value;
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ if (value.cl == rvc_zero)
{
- yy[M] = 1;
- eshift (yy, -1);
+ mpfr_t m;
+ mpfr_init2 (m, SIGNIFICAND_BITS);
+ mpfr_sqrt_ui (m, 2, GMP_RNDN);
+ real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+ mpfr_clear (m);
}
- emovo (yy, y);
+ return &value;
}
-/* Convert single precision float PE to e type Y. */
+/* Fills R with +Inf. */
-static void
-e24toe (pe, y)
- unsigned EMUSHORT *pe, *y;
+void
+real_inf (REAL_VALUE_TYPE *r)
{
-#ifdef IBM
+ get_inf (r, 0);
+}
- ibmtoe (pe, y, SFmode);
+/* 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. */
-#else
+bool
+real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet,
+ enum machine_mode mode)
+{
+ const struct real_format *fmt;
-#ifdef C4X
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
- c4xtoe (pe, y, QFmode);
+ if (*str == 0)
+ {
+ if (quiet)
+ get_canonical_qnan (r, 0);
+ else
+ get_canonical_snan (r, 0);
+ }
+ else
+ {
+ int base = 10, d;
-#else
+ memset (r, 0, sizeof (*r));
+ r->cl = rvc_nan;
- register unsigned EMUSHORT r;
- register unsigned EMUSHORT *e, *p;
- unsigned EMUSHORT yy[NI];
- int denorm, k;
+ /* Parse akin to strtol into the significand of R. */
- 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)
+ while (ISSPACE (*str))
+ str++;
+ if (*str == '-')
+ str++;
+ else if (*str == '+')
+ str++;
+ if (*str == '0')
{
- if (((pe[0] & 0x7f) != 0) || (pe[1] != 0))
+ str++;
+ if (*str == 'x' || *str == 'X')
{
- enan (y, yy[0] != 0);
- return;
+ base = 16;
+ str++;
}
+ else
+ base = 8;
}
- else
+
+ while ((d = hex_value (*str)) < base)
{
- if (((pe[1] & 0x7f) != 0) || (pe[0] != 0))
+ REAL_VALUE_TYPE u;
+
+ switch (base)
{
- enan (y, yy[0] != 0);
- return;
+ case 8:
+ lshift_significand (r, r, 3);
+ break;
+ case 16:
+ lshift_significand (r, r, 4);
+ break;
+ case 10:
+ lshift_significand_1 (&u, r);
+ lshift_significand (r, r, 3);
+ add_significands (r, r, &u);
+ break;
+ default:
+ gcc_unreachable ();
}
+
+ get_zero (&u, 0);
+ u.sig[0] = d;
+ add_significands (r, r, &u);
+
+ str++;
}
-#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. */
+ /* Must have consumed the entire string for success. */
+ if (*str != 0)
+ return false;
-static void
-etoe113 (x, e)
- unsigned EMUSHORT *x, *e;
-{
- unsigned EMUSHORT xi[NI];
- EMULONG exp;
- int rndsav;
+ /* 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);
-#ifdef NANS
- if (eisnan (x))
- {
- make_nan (e, eisneg (x), TFmode);
- return;
+ /* Our MSB is always unset for NaNs. */
+ r->sig[SIGSZ-1] &= ~SIG_MSB;
+
+ /* Force quiet or signalling NaN. */
+ r->signalling = !quiet;
}
-#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;
- nonorm:
- toe113 (xi, e);
+
+ return true;
}
-/* Convert exploded e-type X, that has already been rounded to
- 113-bit precision, to IEEE 128-bit long double format Y. */
+/* 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
-toe113 (a, b)
- unsigned EMUSHORT *a, *b;
+void
+real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
{
- register unsigned EMUSHORT *p, *q;
- unsigned EMUSHORT i;
+ const struct real_format *fmt;
+ int np2;
-#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 */
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+ memset (r, 0, sizeof (*r));
- /* 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++;
- }
+ if (fmt->b == 10)
+ decimal_real_maxval (r, sign, mode);
else
{
- for (i = 0; i < 7; i++)
- *q-- = *p++;
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, fmt->emax);
+
+ np2 = SIGNIFICAND_BITS - fmt->p;
+ memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+ clear_significand_below (r, np2);
+
+ if (fmt->pnan < fmt->p)
+ /* This is an IBM extended double format made up of two IEEE
+ doubles. The value of the long double is the sum of the
+ values of the two parts. The most significant part is
+ required to be the value of the long double rounded to the
+ nearest double. Rounding means we need a slightly smaller
+ value for LDBL_MAX. */
+ clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan - 1);
}
}
-/* Convert e-type X to IEEE double extended format E. */
+/* Fills R with 2**N. */
-static void
-etoe64 (x, e)
- unsigned EMUSHORT *x, *e;
+void
+real_2expN (REAL_VALUE_TYPE *r, int n, enum machine_mode fmode)
{
- unsigned EMUSHORT xi[NI];
- EMULONG exp;
- int rndsav;
+ memset (r, 0, sizeof (*r));
-#ifdef NANS
- if (eisnan (x))
+ n++;
+ if (n > MAX_EXP)
+ r->cl = rvc_inf;
+ else if (n < -MAX_EXP)
+ ;
+ else
{
- make_nan (e, eisneg (x), XFmode);
- return;
+ r->cl = rvc_normal;
+ SET_REAL_EXP (r, n);
+ r->sig[SIGSZ-1] = SIG_MSB;
}
-#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;
- nonorm:
- toe64 (xi, e);
+ if (DECIMAL_FLOAT_MODE_P (fmode))
+ decimal_real_convert (r, fmode, r);
}
-/* Convert exploded e-type X, that has already been rounded to
- 64-bit precision, to IEEE double extended format Y. */
-
-static void
-toe64 (a, b)
- unsigned EMUSHORT *a, *b;
+\f
+static void
+round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
{
- register unsigned EMUSHORT *p, *q;
- unsigned EMUSHORT i;
+ int p2, np2, i, w;
+ int emin2m1, emax2;
+ bool round_up = false;
-#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
+ if (r->decimal)
{
- 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
+ if (fmt->b == 10)
+ {
+ decimal_round_for_format (fmt, r);
+ return;
+ }
+ /* FIXME. We can come here via fp_easy_constant
+ (e.g. -O0 on '_Decimal32 x = 1.0 + 2.0dd'), but have not
+ investigated whether this convert needs to be here, or
+ something else is missing. */
+ decimal_real_convert (r, DFmode, r);
}
-#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)
+ p2 = fmt->p;
+ emin2m1 = fmt->emin - 1;
+ emax2 = fmt->emax;
+
+ np2 = SIGNIFICAND_BITS - p2;
+ switch (r->cl)
{
-#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
+ underflow:
+ get_zero (r, r->sign);
+ case rvc_zero:
+ if (!fmt->has_signed_zero)
+ r->sign = 0;
+ return;
+
+ overflow:
+ get_inf (r, r->sign);
+ case rvc_inf:
+ return;
+
+ case rvc_nan:
+ clear_significand_below (r, np2);
+ return;
+
+ case rvc_normal:
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
+
+ /* Check the range of the exponent. If we're out of range,
+ either underflow or overflow. */
+ if (REAL_EXP (r) > emax2)
+ goto overflow;
+ else if (REAL_EXP (r) <= emin2m1)
{
- if (i)
- *q-- = *p++ | 0x8000;
+ int diff;
+
+ if (!fmt->has_denorm)
+ {
+ /* Don't underflow completely until we've had a chance to round. */
+ if (REAL_EXP (r) < emin2m1)
+ goto underflow;
+ }
else
- *q-- = *p++;
+ {
+ diff = emin2m1 - REAL_EXP (r) + 1;
+ if (diff > p2)
+ goto underflow;
+
+ /* De-normalize the significand. */
+ r->sig[0] |= sticky_rshift_significand (r, r, diff);
+ SET_REAL_EXP (r, REAL_EXP (r) + diff);
+ }
}
-#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)
+
+ if (!fmt->round_towards_zero)
{
- for (i = 0; i < 4; i++)
- *q++ = *p++;
+ /* There are P2 true significand bits, followed by one guard bit,
+ followed by one sticky bit, followed by stuff. Fold nonzero
+ stuff into the sticky bit. */
+ unsigned long sticky;
+ bool guard, lsb;
+
+ sticky = 0;
+ for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
+ sticky |= r->sig[i];
+ sticky |= r->sig[w]
+ & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
+
+ guard = test_significand_bit (r, np2 - 1);
+ lsb = test_significand_bit (r, np2);
+
+ /* Round to even. */
+ round_up = guard && (sticky || lsb);
}
- else
+
+ if (round_up)
{
-#ifdef INFINITY
- if (eiisinf (a))
+ REAL_VALUE_TYPE u;
+ get_zero (&u, 0);
+ set_significand_bit (&u, np2);
+
+ if (add_significands (r, r, &u))
{
- /* Intel long double infinity significand. */
- *q-- = 0x8000;
- *q-- = 0;
- *q-- = 0;
- *q = 0;
- return;
+ /* Overflow. Means the significand had been all ones, and
+ is now all zeros. Need to increase the exponent, and
+ possibly re-normalize it. */
+ SET_REAL_EXP (r, REAL_EXP (r) + 1);
+ if (REAL_EXP (r) > emax2)
+ goto overflow;
+ r->sig[SIGSZ-1] = SIG_MSB;
}
-#endif
- for (i = 0; i < 4; i++)
- *q-- = *p++;
}
-#endif
-}
-/* e type to double precision. */
+ /* Catch underflow that we deferred until after rounding. */
+ if (REAL_EXP (r) <= emin2m1)
+ goto underflow;
-#ifdef DEC
-/* Convert e-type X to DEC-format double E. */
-
-static void
-etoe53 (x, e)
- unsigned EMUSHORT *x, *e;
-{
- etodec (x, e); /* see etodec.c */
+ /* Clear out trailing garbage. */
+ clear_significand_below (r, np2);
}
-/* Convert exploded e-type X, that has already been rounded to
- 56-bit double precision, to DEC double Y. */
+/* Extend or truncate to a new mode. */
-static void
-toe53 (x, y)
- unsigned EMUSHORT *x, *y;
+void
+real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *a)
{
- todec (x, y);
-}
+ const struct real_format *fmt;
-#else
-#ifdef IBM
-/* Convert e-type X to IBM 370-format double E. */
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
-static void
-etoe53 (x, e)
- unsigned EMUSHORT *x, *e;
-{
- etoibm (x, e, DFmode);
-}
+ *r = *a;
-/* Convert exploded e-type X, that has already been rounded to
- 56-bit precision, to IBM 370 double Y. */
+ if (a->decimal || fmt->b == 10)
+ decimal_real_convert (r, mode, a);
-static void
-toe53 (x, y)
- unsigned EMUSHORT *x, *y;
-{
- toibm (x, y, DFmode);
+ round_for_format (fmt, r);
+
+ /* round_for_format de-normalizes denormals. Undo just that part. */
+ if (r->cl == rvc_normal)
+ normalize (r);
}
-#else /* it's neither DEC nor IBM */
-#ifdef C4X
-/* Convert e-type X to C4X-format double E. */
+/* Legacy. Likewise, except return the struct directly. */
-static void
-etoe53 (x, e)
- unsigned EMUSHORT *x, *e;
+REAL_VALUE_TYPE
+real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a)
{
- etoc4x (x, e, HFmode);
+ REAL_VALUE_TYPE r;
+ real_convert (&r, mode, &a);
+ return r;
}
-/* Convert exploded e-type X, that has already been rounded to
- 56-bit precision, to IBM 370 double Y. */
+/* Return true if truncating to MODE is exact. */
-static void
-toe53 (x, y)
- unsigned EMUSHORT *x, *y;
+bool
+exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
{
- toc4x (x, y, HFmode);
+ const struct real_format *fmt;
+ REAL_VALUE_TYPE t;
+ int emin2m1;
+
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+
+ /* Don't allow conversion to denormals. */
+ emin2m1 = fmt->emin - 1;
+ if (REAL_EXP (a) <= emin2m1)
+ return false;
+
+ /* After conversion to the new mode, the value must be identical. */
+ real_convert (&t, mode, a);
+ return real_identical (&t, a);
}
-#else /* it's neither DEC nor IBM nor C4X */
+/* 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 double E. */
+ Legacy: return word 0 for implementing REAL_VALUE_TO_TARGET_SINGLE. */
-static void
-etoe53 (x, e)
- unsigned EMUSHORT *x, *e;
+long
+real_to_target_fmt (long *buf, const REAL_VALUE_TYPE *r_orig,
+ const struct real_format *fmt)
{
- unsigned EMUSHORT xi[NI];
- EMULONG exp;
- int rndsav;
+ REAL_VALUE_TYPE r;
+ long buf1;
-#ifdef NANS
- if (eisnan (x))
- {
- make_nan (e, eisneg (x), DFmode);
- return;
- }
-#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;
- nonorm:
- toe53 (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
- 53-bit precision, to IEEE double Y. */
+/* Similar, but look up the format from MODE. */
-static void
-toe53 (x, y)
- unsigned EMUSHORT *x, *y;
+long
+real_to_target (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), DFmode);
- return;
- }
-#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 */
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
- i = *p++;
- if (i >= (unsigned int) 2047)
- {
- /* Saturate at largest number less than infinity. */
-#ifdef INFINITY
- *y |= 0x7ff0;
- if (! REAL_WORDS_BIG_ENDIAN)
- {
- *(--y) = 0;
- *(--y) = 0;
- *(--y) = 0;
- }
- else
- {
- ++y;
- *y++ = 0;
- *y++ = 0;
- *y++ = 0;
- }
-#else
- *y |= (unsigned EMUSHORT) 0x7fef;
- if (! REAL_WORDS_BIG_ENDIAN)
- {
- *(--y) = 0xffff;
- *(--y) = 0xffff;
- *(--y) = 0xffff;
- }
- else
- {
- ++y;
- *y++ = 0xffff;
- *y++ = 0xffff;
- *y++ = 0xffff;
- }
-#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++;
- }
+ return real_to_target_fmt (buf, r, fmt);
}
-#endif /* not C4X */
-#endif /* not IBM */
-#endif /* not DEC */
-
-
-
-/* e type to single precision. */
-
-#ifdef IBM
-/* Convert e-type X to IBM 370 float E. */
+/* 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 void
-etoe24 (x, e)
- unsigned EMUSHORT *x, *e;
+void
+real_from_target_fmt (REAL_VALUE_TYPE *r, const long *buf,
+ const struct real_format *fmt)
{
- etoibm (x, e, SFmode);
+ (*fmt->decode) (fmt, r, buf);
}
-/* Convert exploded e-type X, that has already been rounded to
- float precision, to IBM 370 float Y. */
+/* Similar, but look up the format from MODE. */
-static void
-toe24 (x, y)
- unsigned EMUSHORT *x, *y;
+void
+real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode)
{
- toibm (x, y, SFmode);
-}
+ const struct real_format *fmt;
-#else
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
-#ifdef C4X
-/* Convert e-type X to C4X float E. */
-
-static void
-etoe24 (x, e)
- unsigned EMUSHORT *x, *e;
-{
- etoc4x (x, e, QFmode);
+ (*fmt->decode) (fmt, r, buf);
}
-/* Convert exploded e-type X, that has already been rounded to
- float precision, to IBM 370 float Y. */
+/* Return the number of bits of the largest binary value that the
+ significand of MODE will hold. */
+/* ??? Legacy. Should get access to real_format directly. */
-static void
-toe24 (x, y)
- unsigned EMUSHORT *x, *y;
+int
+significand_size (enum machine_mode mode)
{
- toc4x (x, y, QFmode);
-}
-
-#else
-
-/* Convert e-type X to IEEE float E. DEC float is the same as IEEE float. */
+ const struct real_format *fmt;
-static void
-etoe24 (x, e)
- unsigned EMUSHORT *x, *e;
-{
- EMULONG exp;
- unsigned EMUSHORT xi[NI];
- int rndsav;
+ fmt = REAL_MODE_FORMAT (mode);
+ if (fmt == NULL)
+ return 0;
-#ifdef NANS
- if (eisnan (x))
+ if (fmt->b == 10)
{
- make_nan (e, eisneg (x), SFmode);
- return;
+ /* Return the size in bits of the largest binary value that can be
+ held by the decimal coefficient for this mode. This is one more
+ than the number of bits required to hold the largest coefficient
+ of this mode. */
+ double log2_10 = 3.3219281;
+ return fmt->p * log2_10;
}
-#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;
- nonorm:
- toe24 (xi, e);
+ return fmt->p;
}
-/* Convert exploded e-type X, that has already been rounded to
- float precision, to IEEE float 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
-toe24 (x, y)
- unsigned EMUSHORT *x, *y;
+unsigned int
+real_hash (const REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT i;
- unsigned EMUSHORT *p;
+ unsigned int h;
+ size_t i;
-#ifdef NANS
- if (eiisnan (x))
+ h = r->cl | (r->sign << 2);
+ switch (r->cl)
{
- 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 */
-
- 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
-}
-#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. */
-
-static int
-ecmp (a, b)
- unsigned EMUSHORT *a, *b;
-{
- 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);
-
- return (0); /* equality */
-
- diff:
-
- if (*(--p) > *(--q))
- return (msign); /* p is bigger */
- else
- return (-msign); /* p is littler */
-}
-
-#if 0
-/* Find e-type nearest integer to X, as floor (X + 0.5). */
-
-static void
-eround (x, y)
- unsigned EMUSHORT *x, *y;
-{
- eadd (ehalf, x, y);
- efloor (y, y);
-}
-#endif /* 0 */
+ case rvc_zero:
+ case rvc_inf:
+ return h;
-/* Convert HOST_WIDE_INT LP to e type Y. */
+ case rvc_normal:
+ h |= REAL_EXP (r) << 3;
+ break;
-static void
-ltoe (lp, y)
- HOST_WIDE_INT *lp;
- unsigned EMUSHORT *y;
-{
- unsigned EMUSHORT yi[NI];
- unsigned HOST_WIDE_INT ll;
- int k;
+ case rvc_nan:
+ if (r->signalling)
+ h ^= (unsigned int)-1;
+ if (r->canonical)
+ return h;
+ break;
- 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
- {
- ll = (unsigned HOST_WIDE_INT) (*lp);
+ default:
+ gcc_unreachable ();
}
- /* 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
-
- 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 */
-}
-/* Convert unsigned HOST_WIDE_INT LP to e type Y. */
-
-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
-
- 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 */
-}
-
-
-/* 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
-eifrac (x, i, frac)
- unsigned EMUSHORT *x;
- HOST_WIDE_INT *i;
- unsigned EMUSHORT *frac;
-{
- unsigned EMUSHORT xi[NI];
- int j, k;
- unsigned HOST_WIDE_INT ll;
-
- 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))
- {
- /* long integer overflow: output large integer
- and correct fraction */
- if (xi[0])
- *i = ((unsigned HOST_WIDE_INT) 1) << (HOST_BITS_PER_WIDE_INT - 1);
- else
- {
-#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];
- }
- while ((k -= 16) > 0);
- *i = ll;
- if (xi[0])
- *i = -(*i);
- }
- else
+ if (sizeof(unsigned long) > sizeof(unsigned int))
+ for (i = 0; i < SIGSZ; ++i)
{
- /* shift not more than 16 bits */
- eshift (xi, k);
- *i = (HOST_WIDE_INT) xi[M] & 0xffff;
- if (xi[0])
- *i = -(*i);
+ unsigned long s = r->sig[i];
+ h ^= s ^ (s >> (HOST_BITS_PER_LONG / 2));
}
- xi[0] = 0;
- xi[E] = EXONE - 1;
- xi[M] = 0;
- if ((k = enormlz (xi)) > NBITS)
- ecleaz (xi);
else
- xi[E] -= (unsigned EMUSHORT) k;
+ for (i = 0; i < SIGSZ; ++i)
+ h ^= r->sig[i];
- emovo (xi, frac);
+ return h;
}
+\f
+/* IEEE single-precision format. */
+static void encode_ieee_single (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_single (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-/* 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. */
-
-static void
-euifrac (x, i, frac)
- unsigned EMUSHORT *x;
- unsigned HOST_WIDE_INT *i;
- unsigned EMUSHORT *frac;
+static void
+encode_ieee_single (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- unsigned HOST_WIDE_INT ll;
- unsigned EMUSHORT xi[NI];
- int j, k;
+ unsigned long image, sig, exp;
+ unsigned long sign = r->sign;
+ 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 argument is fraction */
- *i = 0L;
- emovo (xi, frac);
- return;
- }
- if (k > HOST_BITS_PER_WIDE_INT)
- {
- /* 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");
- }
- else if (k > 16)
+ image = sign << 31;
+ sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
+
+ switch (r->cl)
{
- /* 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
+ 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)
{
- eshup6 (xi);
- ll = (ll << 16) | xi[M];
+ if (r->canonical)
+ sig = (fmt->canonical_nan_lsbs_set ? (1 << 22) - 1 : 0);
+ if (r->signalling == fmt->qnan_msb_set)
+ sig &= ~(1 << 22);
+ else
+ sig |= 1 << 22;
+ if (sig == 0)
+ sig = 1 << 21;
+
+ image |= 255 << 23;
+ image |= sig;
}
- while ((k -= 16) > 0);
- *i = ll;
- }
- else
- {
- /* shift not more than 16 bits */
- eshift (xi, k);
- *i = (HOST_WIDE_INT) xi[M] & 0xffff;
- }
+ else
+ image |= 0x7fffffff;
+ break;
- if (xi[0]) /* A negative value yields unsigned integer 0. */
- *i = 0L;
+ case rvc_normal:
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one. */
+ if (denormal)
+ exp = 0;
+ else
+ exp = REAL_EXP (r) + 127 - 1;
+ image |= exp << 23;
+ image |= sig;
+ break;
- xi[0] = 0;
- xi[E] = EXONE - 1;
- xi[M] = 0;
- if ((k = enormlz (xi)) > NBITS)
- ecleaz (xi);
- else
- xi[E] -= (unsigned EMUSHORT) k;
+ default:
+ gcc_unreachable ();
+ }
- emovo (xi, frac);
+ buf[0] = image;
}
-/* Shift the significand of exploded e-type X up or down by SC bits. */
-
-static int
-eshift (x, sc)
- unsigned EMUSHORT *x;
- int sc;
+static void
+decode_ieee_single (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- unsigned EMUSHORT lost;
- unsigned EMUSHORT *p;
+ unsigned long image = buf[0] & 0xffffffff;
+ bool sign = (image >> 31) & 1;
+ int exp = (image >> 23) & 0xff;
- if (sc == 0)
- return (0);
+ memset (r, 0, sizeof (*r));
+ image <<= HOST_BITS_PER_LONG - 24;
+ image &= ~SIG_MSB;
- lost = 0;
- p = x + NI - 1;
-
- if (sc < 0)
+ if (exp == 0)
{
- sc = -sc;
- while (sc >= 16)
- {
- lost |= *p; /* remember lost bits */
- eshdn6 (x);
- sc -= 16;
- }
-
- while (sc >= 8)
- {
- lost |= *p & 0xff;
- eshdn8 (x);
- sc -= 8;
- }
-
- while (sc > 0)
+ if (image && fmt->has_denorm)
{
- lost |= *p & 1;
- eshdn1 (x);
- sc -= 1;
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, -126);
+ r->sig[SIGSZ-1] = image << 1;
+ normalize (r);
}
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
}
- else
+ else if (exp == 255 && (fmt->has_nans || fmt->has_inf))
{
- while (sc >= 16)
- {
- eshup6 (x);
- sc -= 16;
- }
-
- while (sc >= 8)
- {
- eshup8 (x);
- sc -= 8;
- }
-
- while (sc > 0)
+ if (image)
{
- eshup1 (x);
- sc -= 1;
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+ ^ fmt->qnan_msb_set);
+ r->sig[SIGSZ-1] = image;
}
- }
- if (lost)
- lost = 1;
- return ((int) lost);
-}
-
-/* Shift normalize the significand area of exploded e-type X.
- Return the shift count (up = positive). */
-
-static int
-enormlz (x)
- unsigned EMUSHORT x[];
-{
- 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;
-
- /* 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)
- {
- eshup1 (x);
- sc += 1;
- if (sc > NBITS)
+ else
{
- mtherr ("enormlz", UNDERFLOW);
- return (sc);
+ r->cl = rvc_inf;
+ r->sign = sign;
}
}
- return (sc);
-
- /* Normalize by shifting down out of the high guard word
- of the significand */
- normdn:
-
- if (*p & 0xff00)
- {
- eshdn8 (x);
- sc -= 8;
- }
- while (*p != 0)
+ else
{
- eshdn1 (x);
- sc -= 1;
-
- if (sc < -NBITS)
- {
- mtherr ("enormlz", OVERFLOW);
- return (sc);
- }
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp - 127 + 1);
+ r->sig[SIGSZ-1] = image | SIG_MSB;
}
- return (sc);
-}
-
-/* Powers of ten used in decimal <-> binary conversions. */
-
-#define NTEN 12
-#define MAXP 4096
-
-#if LONG_DOUBLE_TYPE_SIZE == 128
-static unsigned EMUSHORT etens[NTEN + 1][NE] =
-{
- {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 */
-};
-
-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 */
-};
-
-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
-
-#if 0
-/* Convert float value X to ASCII string STRING with NDIG digits after
- the decimal point. */
-
-static void
-e24toasc (x, string, ndigs)
- unsigned EMUSHORT x[];
- char *string;
- int ndigs;
-{
- unsigned EMUSHORT w[NI];
-
- e24toe (x, w);
- etoasc (w, string, ndigs);
-}
-
-/* Convert double value X to ASCII string STRING with NDIG digits after
- the decimal point. */
-
-static void
-e53toasc (x, string, ndigs)
- unsigned EMUSHORT x[];
- char *string;
- int ndigs;
-{
- unsigned EMUSHORT w[NI];
-
- e53toe (x, w);
- etoasc (w, string, ndigs);
}
-/* Convert double extended value X to ASCII string STRING with NDIG digits
- after the decimal point. */
-
-static void
-e64toasc (x, string, ndigs)
- unsigned EMUSHORT x[];
- char *string;
- int ndigs;
-{
- unsigned EMUSHORT w[NI];
-
- e64toe (x, w);
- etoasc (w, string, ndigs);
-}
+const struct real_format ieee_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 24,
+ 24,
+ -125,
+ 128,
+ 31,
+ 31,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+const struct real_format mips_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 24,
+ 24,
+ -125,
+ 128,
+ 31,
+ 31,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ true
+ };
+
+const struct real_format motorola_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 24,
+ 24,
+ -125,
+ 128,
+ 31,
+ 31,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+
+/* SPU Single Precision (Extended-Range Mode) format is the same as IEEE
+ single precision with the following differences:
+ - Infinities are not supported. Instead MAX_FLOAT or MIN_FLOAT
+ are generated.
+ - NaNs are not supported.
+ - The range of non-zero numbers in binary is
+ (001)[1.]000...000 to (255)[1.]111...111.
+ - Denormals can be represented, but are treated as +0.0 when
+ used as an operand and are never generated as a result.
+ - -0.0 can be represented, but a zero result is always +0.0.
+ - the only supported rounding mode is trunction (towards zero). */
+const struct real_format spu_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 24,
+ 24,
+ -125,
+ 129,
+ 31,
+ 31,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false
+ };
+\f
+/* IEEE double-precision format. */
-/* Convert 128-bit long double value X to ASCII string STRING with NDIG digits
- after the decimal point. */
+static void encode_ieee_double (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_double (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-static void
-e113toasc (x, string, ndigs)
- unsigned EMUSHORT x[];
- char *string;
- int ndigs;
+static void
+encode_ieee_double (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT w[NI];
-
- e113toe (x, w);
- etoasc (w, string, ndigs);
-}
-#endif /* 0 */
+ unsigned long image_lo, image_hi, sig_lo, sig_hi, exp;
+ bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
-/* Convert e-type X to ASCII string STRING with NDIGS digits after
- the decimal point. */
+ image_hi = r->sign << 31;
+ image_lo = 0;
-static char wstring[80]; /* working storage for ASCII output */
-
-static void
-etoasc (x, string, ndigs)
- unsigned EMUSHORT x[];
- char *string;
- int ndigs;
-{
- 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)
+ if (HOST_BITS_PER_LONG == 64)
{
- sign = 0xffff;
- y[NE - 1] &= 0x7fff;
+ sig_hi = r->sig[SIGSZ-1];
+ sig_lo = (sig_hi >> (64 - 53)) & 0xffffffff;
+ sig_hi = (sig_hi >> (64 - 53 + 1) >> 31) & 0xfffff;
}
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 */
+ 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;
}
- tnzro:
- /* Test for infinity. */
- if (y[NE - 1] == 0x7fff)
+ switch (r->cl)
{
- 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 (i == -2)
- abort ();
-
- 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;
+ case rvc_zero:
+ break;
- 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 (ecmp (p, u) <= 0)
- {
- ediv (p, u, u);
- emul (p, t, t);
- expon += (int) m;
- }
- m >>= 1;
- if (m == 0)
- break;
- p += NE;
- }
- }
- else
- { /* Number is less than 1.0 */
- /* Pad significand with trailing decimal zeros. */
- if (y[NE - 1] == 0)
+ case rvc_inf:
+ if (fmt->has_inf)
+ image_hi |= 2047 << 20;
+ else
{
- while ((y[NE - 2] & 0x8000) == 0)
- {
- emul (ten, y, y);
- expon -= 1;
- }
+ image_hi |= 0x7fffffff;
+ image_lo = 0xffffffff;
}
- else
+ break;
+
+ case rvc_nan:
+ if (fmt->has_nans)
{
- emovi (y, w);
- for (i = 0; i < NDEC + 1; i++)
+ if (r->canonical)
{
- 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)
+ if (fmt->canonical_nan_lsbs_set)
{
- eshdn1 (u);
- u[1] += 1;
+ sig_hi = (1 << 19) - 1;
+ sig_lo = 0xffffffff;
+ }
+ else
+ {
+ sig_hi = 0;
+ sig_lo = 0;
}
- 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;
- }
- 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)
- {
- emovo (y, t);
- if (ecmp (t, ezero) != 0)
- goto roun; /* round to nearest */
- if ((*(s - 1) & 1) == 0)
- goto doexp; /* round to even */
- }
- /* 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;
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 19);
+ else
+ sig_hi |= 1 << 19;
+ if (sig_hi == 0 && sig_lo == 0)
+ sig_hi = 1 << 18;
+
+ image_hi |= 2047 << 20;
+ image_hi |= sig_hi;
+ image_lo = sig_lo;
}
- /* Round up and carry out from less significant digits */
- k += 1;
- *s = (char) k;
- if (k > '9')
+ else
{
- *s = '0';
- goto roun;
+ image_hi |= 0x7fffffff;
+ image_lo = 0xffffffff;
}
- }
- 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)
- char *s;
- unsigned EMUSHORT *y;
-{
- asctoeg (s, y, 24);
-}
+ break;
+ case rvc_normal:
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one. */
+ if (denormal)
+ exp = 0;
+ else
+ exp = REAL_EXP (r) + 1023 - 1;
+ image_hi |= exp << 20;
+ image_hi |= sig_hi;
+ image_lo = sig_lo;
+ break;
-/* Convert ASCII string S to double precision value Y. */
+ default:
+ gcc_unreachable ();
+ }
-static void
-asctoe53 (s, y)
- char *s;
- unsigned EMUSHORT *y;
-{
-#if defined(DEC) || defined(IBM)
- asctoeg (s, y, 56);
-#else
-#if defined(C4X)
- asctoeg (s, y, 32);
-#else
- asctoeg (s, y, 53);
-#endif
-#endif
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ buf[0] = image_hi, buf[1] = image_lo;
+ else
+ buf[0] = image_lo, buf[1] = image_hi;
}
-
-/* Convert ASCII string S to double extended value Y. */
-
-static void
-asctoe64 (s, y)
- char *s;
- unsigned EMUSHORT *y;
+static void
+decode_ieee_double (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- asctoeg (s, y, 64);
-}
+ unsigned long image_hi, image_lo;
+ bool sign;
+ int exp;
-/* Convert ASCII string S to 128-bit long double Y. */
-
-static void
-asctoe113 (s, y)
- char *s;
- unsigned EMUSHORT *y;
-{
- asctoeg (s, y, 113);
-}
+ 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;
-/* Convert ASCII string S to e type Y. */
+ sign = (image_hi >> 31) & 1;
+ exp = (image_hi >> 20) & 0x7ff;
-static void
-asctoe (s, y)
- char *s;
- unsigned EMUSHORT *y;
-{
- asctoeg (s, y, NBITS);
-}
+ memset (r, 0, sizeof (*r));
-/* Convert ASCII string SS to e type Y, with a specified rounding precision
- of OPREC bits. */
+ image_hi <<= 32 - 21;
+ image_hi |= image_lo >> 21;
+ image_hi &= 0x7fffffff;
+ image_lo <<= 32 - 21;
-static void
-asctoeg (ss, y, oprec)
- char *ss;
- unsigned EMUSHORT *y;
- int oprec;
-{
- 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;
-
- /* Copy the input string. */
- lstr = (char *) alloca (strlen (ss) + 1);
- s = ss;
- while (*s == ' ') /* skip leading spaces */
- ++s;
- sp = lstr;
- while ((*sp++ = *s++) != '\0')
- ;
- s = lstr;
-
- 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:
- k = *s - '0';
- if ((k >= 0) && (k <= 9))
+ if (exp == 0)
{
- /* 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))
- {
- sp = s;
- while ((*sp >= '0') && (*sp <= '9'))
- ++sp;
- /* Check for syntax error */
- c = *sp & 0x7f;
- if ((c != 'e') && (c != 'E') && (c != '\0')
- && (c != '\n') && (c != '\r') && (c != ' ')
- && (c != ','))
- goto error;
- --sp;
- while (*sp == '0')
- *sp-- = 'z';
- trail = 1;
- if (*s == 'z')
- goto donchr;
- }
-
- /* 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)
+ if ((image_hi || image_lo) && fmt->has_denorm)
{
- 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);
- ecleaz (xt);
- xt[NI - 2] = (unsigned EMUSHORT) k;
- eaddm (xt, yy);
- }
- else
- {
- /* Mark any lost non-zero digit. */
- lost |= k;
- /* Count lost digits before the decimal point. */
- if (decflg == 0)
- nexp -= 1;
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, -1022);
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ image_hi = (image_hi << 1) | (image_lo >> 31);
+ image_lo <<= 1;
+ r->sig[SIGSZ-1] = image_hi;
+ r->sig[SIGSZ-2] = image_lo;
+ }
+ else
+ {
+ image_hi = (image_hi << 31 << 2) | (image_lo << 1);
+ r->sig[SIGSZ-1] = image_hi;
+ }
+ normalize (r);
}
- prec += 1;
- goto donchr;
- }
-
- switch (*s)
- {
- case 'z':
- break;
- case 'E':
- case 'e':
- 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;
- 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;
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
}
- if (*s == '+')
- ++s;
- while ((*s >= '0') && (*s <= '9'))
+ else if (exp == 2047 && (fmt->has_nans || fmt->has_inf))
{
- exp *= 10;
- exp += *s++ - '0';
- if (exp > -(MINDECEXP))
+ if (image_hi || image_lo)
{
- if (esign < 0)
- goto zero;
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = ((image_hi >> 30) & 1) ^ fmt->qnan_msb_set;
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ r->sig[SIGSZ-1] = image_hi;
+ r->sig[SIGSZ-2] = image_lo;
+ }
else
- goto infinite;
+ r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo;
}
- }
- if (esign < 0)
- exp = -exp;
- if (exp > MAXDECEXP)
- {
- infinite:
- ecleaz (yy);
- yy[E] = 0x7fff; /* infinity */
- goto aexit;
- }
- if (exp < MINDECEXP)
- {
- zero:
- ecleaz (yy);
- goto aexit;
- }
-
- daldone:
- nexp = exp - nexp;
- /* Pad trailing zeros to minimize power of 10, per IEEE spec. */
- while ((nexp > 0) && (yy[2] == 0))
- {
- emovz (yy, xt);
- eshup1 (xt);
- eshup1 (xt);
- eaddm (yy, xt);
- eshup1 (xt);
- if (xt[2] != 0)
- break;
- nexp -= 1;
- emovz (xt, yy);
- }
- if ((k = enormlz (yy)) > NBITS)
- {
- ecleaz (yy);
- goto aexit;
- }
- lexp = (EXONE - 1 + NBITS) - k;
- emdnorm (yy, lost, 0, lexp, 64);
-
- /* Convert to external format:
-
- 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. */
-
- lexp = yy[E];
- if (nexp == 0)
- {
- k = 0;
- goto expdon;
- }
- esign = 1;
- if (nexp < 0)
- {
- nexp = -nexp;
- esign = -1;
- if (nexp > 4096)
+ else
{
- /* Punt. Can't handle this without 2 divides. */
- emovi (etens[0], tt);
- lexp -= tt[E];
- k = edivm (tt, yy);
- lexp += EXONE;
- nexp -= 4096;
+ r->cl = rvc_inf;
+ r->sign = sign;
}
}
- p = &etens[NTEN][0];
- emov (eone, xt);
- exp = 1;
- do
- {
- if (exp & nexp)
- emul (p, xt, xt);
- p -= NE;
- exp = exp + exp;
- }
- while (exp <= MAXP);
-
- emovi (xt, tt);
- if (esign < 0)
- {
- lexp -= tt[E];
- k = edivm (tt, yy);
- lexp += EXONE;
- }
else
{
- lexp += tt[E];
- k = emulm (tt, yy);
- lexp -= EXONE - 1;
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp - 1023 + 1);
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ r->sig[SIGSZ-1] = image_hi | SIG_MSB;
+ r->sig[SIGSZ-2] = image_lo;
+ }
+ else
+ r->sig[SIGSZ-1] = (image_hi << 31 << 1) | image_lo | SIG_MSB;
}
+}
- 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, k, 0, lexp, 64);
+const struct real_format ieee_double_format =
+ {
+ encode_ieee_double,
+ decode_ieee_double,
+ 2,
+ 53,
+ 53,
+ -1021,
+ 1024,
+ 63,
+ 63,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+const struct real_format mips_double_format =
+ {
+ encode_ieee_double,
+ decode_ieee_double,
+ 2,
+ 53,
+ 53,
+ -1021,
+ 1024,
+ 63,
+ 63,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ true
+ };
+
+const struct real_format motorola_double_format =
+ {
+ encode_ieee_double,
+ decode_ieee_double,
+ 2,
+ 53,
+ 53,
+ -1021,
+ 1024,
+ 63,
+ 63,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+\f
+/* IEEE extended real format. This comes in three flavors: Intel's as
+ a 12 byte image, Intel's as a 16 byte image, and Motorola's. Intel
+ 12- and 16-byte images may be big- or little endian; Motorola's is
+ always big endian. */
+
+/* Helper subroutine which converts from the internal format to the
+ 12-byte little-endian Intel format. Functions below adjust this
+ for the other possible formats. */
+static void
+encode_ieee_extended (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ unsigned long image_hi, sig_hi, sig_lo;
+ bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
- aexit:
+ image_hi = r->sign << 15;
+ sig_hi = sig_lo = 0;
- rndprc = rndsav;
- yy[0] = nsign;
- switch (oprec)
+ switch (r->cl)
{
-#ifdef DEC
- case 56:
- todec (yy, y); /* see etodec.c */
- break;
-#endif
-#ifdef IBM
- case 56:
- toibm (yy, y, DFmode);
+ case rvc_zero:
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);
+ case rvc_inf:
+ if (fmt->has_inf)
+ {
+ image_hi |= 32767;
+
+ /* Intel requires the explicit integer bit to be set, otherwise
+ it considers the value a "pseudo-infinity". Motorola docs
+ say it doesn't care. */
+ sig_hi = 0x80000000;
+ }
+ else
+ {
+ image_hi |= 32767;
+ sig_lo = sig_hi = 0xffffffff;
+ }
break;
- case NBITS:
- emovo (yy, y);
+
+ case rvc_nan:
+ if (fmt->has_nans)
+ {
+ image_hi |= 32767;
+ if (r->canonical)
+ {
+ if (fmt->canonical_nan_lsbs_set)
+ {
+ sig_hi = (1 << 30) - 1;
+ sig_lo = 0xffffffff;
+ }
+ }
+ else if (HOST_BITS_PER_LONG == 32)
+ {
+ sig_hi = r->sig[SIGSZ-1];
+ sig_lo = r->sig[SIGSZ-2];
+ }
+ else
+ {
+ sig_lo = r->sig[SIGSZ-1];
+ sig_hi = sig_lo >> 31 >> 1;
+ sig_lo &= 0xffffffff;
+ }
+ if (r->signalling == fmt->qnan_msb_set)
+ sig_hi &= ~(1 << 30);
+ else
+ sig_hi |= 1 << 30;
+ if ((sig_hi & 0x7fffffff) == 0 && sig_lo == 0)
+ sig_hi = 1 << 29;
+
+ /* Intel requires the explicit integer bit to be set, otherwise
+ it considers the value a "pseudo-nan". Motorola docs say it
+ doesn't care. */
+ sig_hi |= 0x80000000;
+ }
+ else
+ {
+ image_hi |= 32767;
+ sig_lo = sig_hi = 0xffffffff;
+ }
break;
- }
-}
+ case rvc_normal:
+ {
+ int exp = REAL_EXP (r);
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one.
-/* Return Y = largest integer not greater than X (truncated toward minus
- infinity). */
+ 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. */
-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;
+ if (denormal)
+ exp = 0;
+ else
+ {
+ exp += 16383 - 1;
+ gcc_assert (exp >= 0);
+ }
+ image_hi |= exp;
+
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ sig_hi = r->sig[SIGSZ-1];
+ sig_lo = r->sig[SIGSZ-2];
+ }
+ else
+ {
+ sig_lo = r->sig[SIGSZ-1];
+ sig_hi = sig_lo >> 31 >> 1;
+ sig_lo &= 0xffffffff;
+ }
+ }
+ break;
- p = &y[0];
- while (e >= 16)
- {
- *p++ = 0;
- e -= 16;
+ default:
+ gcc_unreachable ();
}
- /* clear the remaining bits */
- *p &= bmask[e];
- /* truncate negatives toward minus infinity */
- isitneg:
- if ((unsigned EMUSHORT) expon & (unsigned EMUSHORT) 0x8000)
- {
- for (i = 0; i < NE - 1; i++)
- {
- if (f[i] != y[i])
- {
- esub (eone, y, y);
- break;
- }
- }
- }
+ buf[0] = sig_lo, buf[1] = sig_hi, buf[2] = image_hi;
}
-
-#if 0
-/* Return S and EXP such that S * 2^EXP = X and .5 <= S < 1.
- For example, 1.1 = 0.55 * 2^1. */
-
-static void
-efrexp (x, exp, s)
- unsigned EMUSHORT x[];
- int *exp;
- unsigned EMUSHORT s[];
+/* Convert from the internal format to the 12-byte Motorola format
+ for an IEEE extended real. */
+static void
+encode_ieee_extended_motorola (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT xi[NI];
- EMULONG li;
+ long intermed[3];
+ encode_ieee_extended (fmt, intermed, r);
- emovi (x, xi);
- /* Handle denormalized numbers properly using long integer exponent. */
- li = (EMULONG) ((EMUSHORT) xi[1]);
+ /* Motorola chips are assumed always to be big-endian. Also, the
+ padding in a Motorola extended real goes between the exponent and
+ the mantissa. At this point the mantissa is entirely within
+ elements 0 and 1 of intermed, and the exponent entirely within
+ element 2, so all we have to do is swap the order around, and
+ shift element 2 left 16 bits. */
+ buf[0] = intermed[2] << 16;
+ buf[1] = intermed[1];
+ buf[2] = intermed[0];
+}
- if (li == 0)
+/* Convert from the internal format to the 12-byte Intel format for
+ an IEEE extended real. */
+static void
+encode_ieee_extended_intel_96 (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ if (FLOAT_WORDS_BIG_ENDIAN)
{
- li -= enormlz (xi);
+ /* All the padding in an Intel-format extended real goes at the high
+ end, which in this case is after the mantissa, not the exponent.
+ Therefore we must shift everything down 16 bits. */
+ long intermed[3];
+ encode_ieee_extended (fmt, intermed, r);
+ buf[0] = ((intermed[2] << 16) | ((unsigned long)(intermed[1] & 0xFFFF0000) >> 16));
+ buf[1] = ((intermed[1] << 16) | ((unsigned long)(intermed[0] & 0xFFFF0000) >> 16));
+ buf[2] = (intermed[0] << 16);
}
- xi[1] = 0x3ffe;
- emovo (xi, s);
- *exp = (int) (li - 0x3ffe);
+ else
+ /* encode_ieee_extended produces what we want directly. */
+ encode_ieee_extended (fmt, buf, r);
}
-#endif
-
-/* Return e type Y = X * 2^PWR2. */
-static void
-eldexp (x, pwr2, y)
- unsigned EMUSHORT x[];
- int pwr2;
- unsigned EMUSHORT y[];
+/* Convert from the internal format to the 16-byte Intel format for
+ an IEEE extended real. */
+static void
+encode_ieee_extended_intel_128 (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT xi[NI];
- EMULONG li;
- int i;
-
- emovi (x, xi);
- li = xi[1];
- li += pwr2;
- i = 0;
- emdnorm (xi, i, i, li, 64);
- emovo (xi, y);
+ /* All the padding in an Intel-format extended real goes at the high end. */
+ encode_ieee_extended_intel_96 (fmt, buf, r);
+ buf[3] = 0;
}
+/* As above, we have a helper function which converts from 12-byte
+ little-endian Intel format to internal format. Functions below
+ adjust for the other possible formats. */
+static void
+decode_ieee_extended (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
+{
+ unsigned long image_hi, sig_hi, sig_lo;
+ bool sign;
+ int exp;
-#if 0
-/* C = remainder after dividing B by A, all e type values.
- Least significant integer quotient bits left in EQUOT. */
+ sig_lo = buf[0], sig_hi = buf[1], image_hi = buf[2];
+ sig_lo &= 0xffffffff;
+ sig_hi &= 0xffffffff;
+ image_hi &= 0xffffffff;
-static void
-eremain (a, b, c)
- unsigned EMUSHORT a[], b[], c[];
-{
- unsigned EMUSHORT den[NI], num[NI];
+ sign = (image_hi >> 15) & 1;
+ exp = image_hi & 0x7fff;
-#ifdef NANS
- if (eisinf (b)
- || (ecmp (a, ezero) == 0)
- || eisnan (a)
- || eisnan (b))
+ memset (r, 0, sizeof (*r));
+
+ if (exp == 0)
{
- enan (c, 0);
- return;
+ if ((sig_hi || sig_lo) && fmt->has_denorm)
+ {
+ r->cl = rvc_normal;
+ r->sign = sign;
+
+ /* When the IEEE format contains a hidden bit, we know that
+ it's zero at this point, and so shift up the significand
+ and decrease the exponent to match. In this case, Motorola
+ defines the explicit integer bit to be valid, so we don't
+ know whether the msb is set or not. */
+ SET_REAL_EXP (r, fmt->emin);
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ r->sig[SIGSZ-1] = sig_hi;
+ r->sig[SIGSZ-2] = sig_lo;
+ }
+ else
+ r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
+
+ normalize (r);
+ }
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
}
-#endif
- if (ecmp (a, ezero) == 0)
+ else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
{
- mtherr ("eremain", SING);
- eclear (c);
- return;
+ /* See above re "pseudo-infinities" and "pseudo-nans".
+ Short summary is that the MSB will likely always be
+ set, and that we don't care about it. */
+ sig_hi &= 0x7fffffff;
+
+ if (sig_hi || sig_lo)
+ {
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = ((sig_hi >> 30) & 1) ^ fmt->qnan_msb_set;
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ r->sig[SIGSZ-1] = sig_hi;
+ r->sig[SIGSZ-2] = sig_lo;
+ }
+ else
+ r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
+ }
+ else
+ {
+ r->cl = rvc_inf;
+ r->sign = sign;
+ }
}
- 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[];
-{
- EMULONG ld, ln;
- unsigned EMUSHORT j;
-
- ld = den[E];
- ld -= enormlz (den);
- ln = num[E];
- ln -= enormlz (num);
- ecleaz (equot);
- while (ln >= ld)
{
- if (ecmpm (den, num) <= 0)
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp - 16383 + 1);
+ if (HOST_BITS_PER_LONG == 32)
{
- esubm (den, num);
- j = 1;
+ r->sig[SIGSZ-1] = sig_hi;
+ r->sig[SIGSZ-2] = sig_lo;
}
else
- j = 0;
- eshup1 (equot);
- equot[NI - 1] |= j;
- eshup1 (num);
- ln -= 1;
+ r->sig[SIGSZ-1] = (sig_hi << 31 << 1) | sig_lo;
}
- emdnorm (num, 0, 0, ln, 0);
}
-/* Report an error condition CODE encountered in function NAME.
- CODE is one of the following:
-
- 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. */
-
-#define NMSGS 8
-static char *ermsg[NMSGS] =
-{
- "unknown", /* error code 0 */
- "domain", /* error code 1 */
- "singularity", /* et seq. */
- "overflow",
- "underflow",
- "total loss of precision",
- "partial loss of precision",
- "invalid operation"
-};
-
-int merror = 0;
-extern int merror;
-
-static void
-mtherr (name, code)
- char *name;
- int code;
+/* Convert from the internal format to the 12-byte Motorola format
+ for an IEEE extended real. */
+static void
+decode_ieee_extended_motorola (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- char errstr[80];
-
- /* 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 ((code <= 0) || (code >= NMSGS))
- code = 0;
- sprintf (errstr, " %s %s error", name, ermsg[code]);
- if (extra_warnings)
- warning (errstr);
- /* Set global error message word */
- merror = code + 1;
-}
+ long intermed[3];
-#ifdef DEC
-/* Convert DEC double precision D to e type E. */
+ /* Motorola chips are assumed always to be big-endian. Also, the
+ padding in a Motorola extended real goes between the exponent and
+ the mantissa; remove it. */
+ intermed[0] = buf[2];
+ intermed[1] = buf[1];
+ intermed[2] = (unsigned long)buf[0] >> 16;
-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);
+ decode_ieee_extended (fmt, r, intermed);
}
-/* Convert e type X to DEC double precision D. */
+/* Convert from the internal format to the 12-byte Intel format for
+ an IEEE extended real. */
+static void
+decode_ieee_extended_intel_96 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
+{
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ {
+ /* All the padding in an Intel-format extended real goes at the high
+ end, which in this case is after the mantissa, not the exponent.
+ Therefore we must shift everything up 16 bits. */
+ long intermed[3];
+
+ intermed[0] = (((unsigned long)buf[2] >> 16) | (buf[1] << 16));
+ intermed[1] = (((unsigned long)buf[1] >> 16) | (buf[0] << 16));
+ intermed[2] = ((unsigned long)buf[0] >> 16);
+
+ decode_ieee_extended (fmt, r, intermed);
+ }
+ else
+ /* decode_ieee_extended produces what we want directly. */
+ decode_ieee_extended (fmt, r, buf);
+}
-static void
-etodec (x, d)
- unsigned EMUSHORT *x, *d;
+/* Convert from the internal format to the 16-byte Intel format for
+ an IEEE extended real. */
+static void
+decode_ieee_extended_intel_128 (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- 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);
+ /* All the padding in an Intel-format extended real goes at the high end. */
+ decode_ieee_extended_intel_96 (fmt, r, buf);
}
-/* Convert exploded e-type X, that has already been rounded to
- 56-bit precision, to DEC format double Y. */
+const struct real_format ieee_extended_motorola_format =
+ {
+ encode_ieee_extended_motorola,
+ decode_ieee_extended_motorola,
+ 2,
+ 64,
+ 64,
+ -16382,
+ 16384,
+ 95,
+ 95,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+
+const struct real_format ieee_extended_intel_96_format =
+ {
+ encode_ieee_extended_intel_96,
+ decode_ieee_extended_intel_96,
+ 2,
+ 64,
+ 64,
+ -16381,
+ 16384,
+ 79,
+ 79,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+const struct real_format ieee_extended_intel_128_format =
+ {
+ encode_ieee_extended_intel_128,
+ decode_ieee_extended_intel_128,
+ 2,
+ 64,
+ 64,
+ -16381,
+ 16384,
+ 79,
+ 79,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+/* The following caters to i386 systems that set the rounding precision
+ to 53 bits instead of 64, e.g. FreeBSD. */
+const struct real_format ieee_extended_intel_96_round_53_format =
+ {
+ encode_ieee_extended_intel_96,
+ decode_ieee_extended_intel_96,
+ 2,
+ 53,
+ 53,
+ -16381,
+ 16384,
+ 79,
+ 79,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+\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
+ +0.0 or -0.0 for Infinity and don't-care for NaN. */
+
+static void encode_ibm_extended (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ibm_extended (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-static void
-todec (x, y)
- unsigned EMUSHORT *x, *y;
+static void
+encode_ibm_extended (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- unsigned EMUSHORT i;
- unsigned EMUSHORT *p;
-
- p = x;
- *y = 0;
- if (*p++)
- *y = 0100000;
- i = *p++;
- if (i == 0)
+ REAL_VALUE_TYPE u, normr, v;
+ const struct real_format *base_fmt;
+
+ base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
+
+ /* Renormalize R before doing any arithmetic on it. */
+ normr = *r;
+ if (normr.cl == rvc_normal)
+ normalize (&normr);
+
+ /* u = IEEE double precision portion of significand. */
+ u = normr;
+ round_for_format (base_fmt, &u);
+ encode_ieee_double (base_fmt, &buf[0], &u);
+
+ if (u.cl == rvc_normal)
{
- *y++ = 0;
- *y++ = 0;
- *y++ = 0;
- *y++ = 0;
- return;
+ do_add (&v, &normr, &u, 1);
+ /* Call round_for_format since we might need to denormalize. */
+ round_for_format (base_fmt, &v);
+ encode_ieee_double (base_fmt, &buf[2], &v);
}
- if (i > 0377)
+ else
{
- *y++ |= 077777;
- *y++ = 0xffff;
- *y++ = 0xffff;
- *y++ = 0xffff;
-#ifdef ERANGE
- errno = ERANGE;
-#endif
- return;
+ /* Inf, NaN, 0 are all representable as doubles, so the
+ least-significant part can be 0.0. */
+ buf[2] = 0;
+ buf[3] = 0;
}
- 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. */
-static void
-ibmtoe (d, e, mode)
- unsigned EMUSHORT *d;
- unsigned EMUSHORT *e;
- enum machine_mode mode;
+static void
+decode_ibm_extended (const struct real_format *fmt ATTRIBUTE_UNUSED, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- unsigned EMUSHORT y[NI];
- register unsigned EMUSHORT r, *p;
- int rndsav;
-
- 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 */
+ REAL_VALUE_TYPE u, v;
+ const struct real_format *base_fmt;
+
+ base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
+ decode_ieee_double (base_fmt, &u, &buf[0]);
+
+ if (u.cl != rvc_zero && u.cl != rvc_inf && u.cl != rvc_nan)
{
- *p++ = *d++; /* fill in the rest of our mantissa */
- *p++ = *d++;
+ decode_ieee_double (base_fmt, &v, &buf[2]);
+ do_add (r, &u, &v, 0);
}
- *p = *d;
-
- if (y[M] == 0 && y[M+1] == 0 && y[M+2] == 0 && y[M+3] == 0)
- y[0] = y[E] = 0;
else
- y[E] -= 5 + enormlz (y); /* now normalise the mantissa */
- /* handle change in RADIX */
- emovo (y, e);
+ *r = u;
}
+const struct real_format ibm_extended_format =
+ {
+ encode_ibm_extended,
+ decode_ibm_extended,
+ 2,
+ 53 + 53,
+ 53,
+ -1021 + 53,
+ 1024,
+ 127,
+ -1,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+const struct real_format mips_extended_format =
+ {
+ encode_ibm_extended,
+ decode_ibm_extended,
+ 2,
+ 53 + 53,
+ 53,
+ -1021 + 53,
+ 1024,
+ 127,
+ -1,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ true
+ };
+\f
+/* IEEE quad precision format. */
-/* Convert e type to IBM single/double precision. */
+static void encode_ieee_quad (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_quad (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-static void
-etoibm (x, d, mode)
- unsigned EMUSHORT *x, *d;
- enum machine_mode mode;
+static void
+encode_ieee_quad (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- 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);
-}
+ unsigned long image3, image2, image1, image0, exp;
+ bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
+ REAL_VALUE_TYPE u;
-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)
- {
- *y++ = 0;
- *y++ = 0;
- }
- return;
- }
- r = i & 0x3;
- i >>= 2;
- if (i > 0x7f)
+ image3 = r->sign << 31;
+ image2 = 0;
+ image1 = 0;
+ image0 = 0;
+
+ rshift_significand (&u, r, SIGNIFICAND_BITS - 113);
+
+ switch (r->cl)
{
- *y++ |= 0x7fff;
- *y++ = 0xffff;
- if (mode != SFmode)
+ case rvc_zero:
+ break;
+
+ case rvc_inf:
+ if (fmt->has_inf)
+ image3 |= 32767 << 16;
+ else
{
- *y++ = 0xffff;
- *y++ = 0xffff;
+ image3 |= 0x7fffffff;
+ image2 = 0xffffffff;
+ image1 = 0xffffffff;
+ image0 = 0xffffffff;
}
-#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. */
+ break;
-static void
-c4xtoe (d, e, mode)
- unsigned EMUSHORT *d;
- unsigned EMUSHORT *e;
- enum machine_mode mode;
-{
- unsigned EMUSHORT y[NI];
- int r;
- int rndsav;
- int isnegative;
- int size;
- int i;
- int carry;
+ case rvc_nan:
+ if (fmt->has_nans)
+ {
+ image3 |= 32767 << 16;
- /* Short-circuit the zero case. */
- if ((d[0] == 0x8000)
- && (d[1] == 0x0000)
- && ((mode == QFmode) || ((d[2] == 0x0000) && (d[3] == 0x0000))))
- {
- e[0] = 0;
- e[1] = 0;
- e[2] = 0;
- e[3] = 0;
- e[4] = 0;
- e[5] = 0;
- return;
- }
+ if (r->canonical)
+ {
+ if (fmt->canonical_nan_lsbs_set)
+ {
+ image3 |= 0x7fff;
+ image2 = image1 = image0 = 0xffffffff;
+ }
+ }
+ else if (HOST_BITS_PER_LONG == 32)
+ {
+ image0 = u.sig[0];
+ image1 = u.sig[1];
+ image2 = u.sig[2];
+ image3 |= u.sig[3] & 0xffff;
+ }
+ else
+ {
+ image0 = u.sig[0];
+ image1 = image0 >> 31 >> 1;
+ image2 = u.sig[1];
+ image3 |= (image2 >> 31 >> 1) & 0xffff;
+ image0 &= 0xffffffff;
+ image2 &= 0xffffffff;
+ }
+ if (r->signalling == fmt->qnan_msb_set)
+ image3 &= ~0x8000;
+ else
+ image3 |= 0x8000;
+ if (((image3 & 0xffff) | image2 | image1 | image0) == 0)
+ image3 |= 0x4000;
+ }
+ else
+ {
+ image3 |= 0x7fffffff;
+ image2 = 0xffffffff;
+ image1 = 0xffffffff;
+ image0 = 0xffffffff;
+ }
+ break;
- 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;
- }
-
- r >>= 8; /* Shift exponent word down 8 bits. */
- if (r & 0x80) /* Make the exponent negative if it is. */
- {
- r = r | (~0 & ~0xff);
- }
+ case rvc_normal:
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one. */
+ if (denormal)
+ exp = 0;
+ else
+ exp = REAL_EXP (r) + 16383 - 1;
+ image3 |= exp << 16;
- if (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))
+ if (HOST_BITS_PER_LONG == 32)
{
- /* We overflowed into the next word, carry is the same. */
- y[i] = carry ? 0x0000 : 0xffff;
+ image0 = u.sig[0];
+ image1 = u.sig[1];
+ image2 = u.sig[2];
+ image3 |= u.sig[3] & 0xffff;
}
- else
+ else
{
- /* No overflow, just invert and add carry. */
- y[i] = ((~y[i]) + carry) & 0xffff;
- carry = 0;
+ image0 = u.sig[0];
+ image1 = image0 >> 31 >> 1;
+ image2 = u.sig[1];
+ image3 |= (image2 >> 31 >> 1) & 0xffff;
+ image0 &= 0xffffffff;
+ image2 &= 0xffffffff;
}
- }
-
- 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);
-}
+ break;
+ default:
+ gcc_unreachable ();
+ }
-/* Convert e type to C4X single/double precision. */
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ {
+ buf[0] = image3;
+ buf[1] = image2;
+ buf[2] = image1;
+ buf[3] = image0;
+ }
+ else
+ {
+ buf[0] = image0;
+ buf[1] = image1;
+ buf[2] = image2;
+ buf[3] = image3;
+ }
+}
-static void
-etoc4x (x, d, mode)
- unsigned EMUSHORT *x, *d;
- enum machine_mode mode;
+static void
+decode_ieee_quad (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
{
- unsigned EMUSHORT xi[NI];
- EMULONG exp;
- int rndsav;
+ unsigned long image3, image2, image1, image0;
+ bool sign;
+ int exp;
- emovi (x, xi);
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ {
+ image3 = buf[0];
+ image2 = buf[1];
+ image1 = buf[2];
+ image0 = buf[3];
+ }
+ else
+ {
+ image0 = buf[0];
+ image1 = buf[1];
+ image2 = buf[2];
+ image3 = buf[3];
+ }
+ image0 &= 0xffffffff;
+ image1 &= 0xffffffff;
+ image2 &= 0xffffffff;
- /* Adjust exponent for offsets. */
- exp = (EMULONG) xi[E] - (EXONE - 0x7f);
+ sign = (image3 >> 31) & 1;
+ exp = (image3 >> 16) & 0x7fff;
+ image3 &= 0xffff;
- /* 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);
-}
+ memset (r, 0, sizeof (*r));
-static void
-toc4x (x, y, mode)
- unsigned EMUSHORT *x, *y;
- enum machine_mode mode;
-{
- int i;
- int r;
- 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))))
+ if (exp == 0)
{
- /* We have a zero. Put it into the output and return. */
- *y++ = 0x8000;
- *y++ = 0x0000;
- if (mode != QFmode)
- {
- *y++ = 0x0000;
- *y++ = 0x0000;
- }
- return;
+ if ((image3 | image2 | image1 | image0) && fmt->has_denorm)
+ {
+ r->cl = rvc_normal;
+ r->sign = sign;
+
+ SET_REAL_EXP (r, -16382 + (SIGNIFICAND_BITS - 112));
+ if (HOST_BITS_PER_LONG == 32)
+ {
+ r->sig[0] = image0;
+ r->sig[1] = image1;
+ r->sig[2] = image2;
+ r->sig[3] = image3;
+ }
+ else
+ {
+ r->sig[0] = (image1 << 31 << 1) | image0;
+ r->sig[1] = (image3 << 31 << 1) | image2;
+ }
+
+ normalize (r);
+ }
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
}
-
- *y = 0;
-
- /* Negative number require a two's complement conversion of the
- mantissa. */
- if (x[0])
+ else if (exp == 32767 && (fmt->has_nans || fmt->has_inf))
{
- *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 (image3 | image2 | image1 | image0)
{
- if (x[v] == 0x0000)
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = ((image3 >> 15) & 1) ^ fmt->qnan_msb_set;
+
+ if (HOST_BITS_PER_LONG == 32)
{
- x[v] = carry ? 0x0000 : 0xffff;
+ r->sig[0] = image0;
+ r->sig[1] = image1;
+ r->sig[2] = image2;
+ r->sig[3] = image3;
}
else
{
- x[v] = ((~x[v]) + carry) & 0xffff;
- carry = 0;
+ r->sig[0] = (image1 << 31 << 1) | image0;
+ r->sig[1] = (image3 << 31 << 1) | image2;
}
- v--;
+ lshift_significand (r, r, SIGNIFICAND_BITS - 113);
}
-
- /* 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)
+ else
{
- /* 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--;
+ r->cl = rvc_inf;
+ r->sign = sign;
}
}
else
{
- i = ((int) x[1]) - 0x7f;
- }
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp - 16383 + 1);
- if ((i < -128) || (i > 127))
- {
- y[0] |= 0xff7f;
- y[1] = 0xffff;
- if (mode != QFmode)
+ if (HOST_BITS_PER_LONG == 32)
{
- y[2] = 0xffff;
- y[3] = 0xffff;
+ r->sig[0] = image0;
+ r->sig[1] = image1;
+ r->sig[2] = image2;
+ r->sig[3] = image3;
}
-#ifdef ERANGE
- errno = ERANGE;
-#endif
- return;
+ 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;
}
-
- y[0] |= ((i & 0xff) << 8);
-
- eshift (x, 8);
-
- y[0] |= x[M] & 0x7f;
- y[1] = x[M + 1];
- if (mode != QFmode)
+}
+
+const struct real_format ieee_quad_format =
+ {
+ encode_ieee_quad,
+ decode_ieee_quad,
+ 2,
+ 113,
+ 113,
+ -16381,
+ 16384,
+ 127,
+ 127,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+const struct real_format mips_quad_format =
+ {
+ encode_ieee_quad,
+ decode_ieee_quad,
+ 2,
+ 113,
+ 113,
+ -16381,
+ 16384,
+ 127,
+ 127,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ true
+ };
+\f
+/* Descriptions of VAX floating point formats can be found beginning at
+
+ http://h71000.www7.hp.com/doc/73FINAL/4515/4515pro_013.html#f_floating_point_format
+
+ The thing to remember is that they're almost IEEE, except for word
+ order, exponent bias, and the lack of infinities, nans, and denormals.
+
+ We don't implement the H_floating format here, simply because neither
+ the VAX or Alpha ports use it. */
+
+static void encode_vax_f (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_f (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_vax_d (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_d (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+static void encode_vax_g (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_vax_g (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
+
+static void
+encode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ unsigned long sign, exp, sig, image;
+
+ sign = r->sign << 15;
+
+ switch (r->cl)
{
- y[2] = x[M + 2];
- y[3] = x[M + 3];
+ case rvc_zero:
+ image = 0;
+ break;
+
+ case rvc_inf:
+ case rvc_nan:
+ image = 0xffff7fff | sign;
+ break;
+
+ case rvc_normal:
+ sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
+ exp = REAL_EXP (r) + 128;
+
+ image = (sig << 16) & 0xffff0000;
+ image |= sign;
+ image |= exp << 7;
+ image |= sig >> 16;
+ break;
+
+ default:
+ gcc_unreachable ();
}
+
+ buf[0] = image;
}
-#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
+static void
+decode_vax_f (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
+{
+ unsigned long image = buf[0] & 0xffffffff;
+ int exp = (image >> 7) & 0xff;
-#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
+ memset (r, 0, sizeof (*r));
-#ifdef SFMODE_NAN
-SFMODE_NAN;
-#else
-#ifdef IEEE
-unsigned EMUSHORT SFbignan[2] = {0x7fff, 0xffff};
-unsigned EMUSHORT SFlittlenan[2] = {0, 0xffc0};
-#endif
-#endif
+ if (exp != 0)
+ {
+ r->cl = rvc_normal;
+ r->sign = (image >> 15) & 1;
+ SET_REAL_EXP (r, exp - 128);
+ image = ((image & 0x7f) << 16) | ((image >> 16) & 0xffff);
+ r->sig[SIGSZ-1] = (image << (HOST_BITS_PER_LONG - 24)) | SIG_MSB;
+ }
+}
static void
-make_nan (nan, sign, mode)
- unsigned EMUSHORT *nan;
- int sign;
- enum machine_mode mode;
+encode_vax_d (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- int n;
- unsigned EMUSHORT *p;
+ unsigned long image0, image1, sign = r->sign << 15;
- switch (mode)
+ switch (r->cl)
{
-/* 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;
+ case rvc_zero:
+ image0 = image1 = 0;
break;
- case XFmode:
- n = 6;
- if (REAL_WORDS_BIG_ENDIAN)
- p = XFbignan;
- else
- p = XFlittlenan;
+ case rvc_inf:
+ case rvc_nan:
+ image0 = 0xffff7fff | sign;
+ image1 = 0xffffffff;
break;
- case DFmode:
- n = 4;
- if (REAL_WORDS_BIG_ENDIAN)
- p = DFbignan;
+ case rvc_normal:
+ /* Extract the significand into straight hi:lo. */
+ if (HOST_BITS_PER_LONG == 64)
+ {
+ image0 = r->sig[SIGSZ-1];
+ image1 = (image0 >> (64 - 56)) & 0xffffffff;
+ image0 = (image0 >> (64 - 56 + 1) >> 31) & 0x7fffff;
+ }
else
- p = DFlittlenan;
- break;
+ {
+ image0 = r->sig[SIGSZ-1];
+ image1 = r->sig[SIGSZ-2];
+ image1 = (image0 << 24) | (image1 >> 8);
+ image0 = (image0 >> 8) & 0xffffff;
+ }
- case SFmode:
- case HFmode:
- n = 2;
- if (REAL_WORDS_BIG_ENDIAN)
- p = SFbignan;
- else
- p = SFlittlenan;
+ /* Rearrange the half-words of the significand to match the
+ external format. */
+ image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff007f;
+ image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
+
+ /* Add the sign and exponent. */
+ image0 |= sign;
+ image0 |= (REAL_EXP (r) + 128) << 7;
break;
-#endif
default:
- abort ();
+ gcc_unreachable ();
}
- if (REAL_WORDS_BIG_ENDIAN)
- *nan++ = (sign << 15) | *p++;
- while (--n != 0)
- *nan++ = *p++;
- if (! REAL_WORDS_BIG_ENDIAN)
- *nan = (sign << 15) | *p;
-}
-/* This is the inverse of the function `etarsingle' invoked by
- REAL_VALUE_TO_TARGET_SINGLE. */
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ buf[0] = image1, buf[1] = image0;
+ else
+ buf[0] = image0, buf[1] = image1;
+}
-REAL_VALUE_TYPE
-ereal_unto_float (f)
- long f;
+static void
+decode_vax_d (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 image0, image1;
+ 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;
- }
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ image1 = buf[0], image0 = buf[1];
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;
-}
-
+ image0 = buf[0], image1 = buf[1];
+ image0 &= 0xffffffff;
+ image1 &= 0xffffffff;
-/* This is the inverse of the function `etardouble' invoked by
- REAL_VALUE_TO_TARGET_DOUBLE. */
+ exp = (image0 >> 7) & 0xff;
-REAL_VALUE_TYPE
-ereal_unto_double (d)
- long 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)
- {
- 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
+ if (exp != 0)
{
- /* 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;
-}
+ r->cl = rvc_normal;
+ r->sign = (image0 >> 15) & 1;
+ SET_REAL_EXP (r, exp - 128);
+ /* Rearrange the half-words of the external format into
+ proper ascending order. */
+ image0 = ((image0 & 0x7f) << 16) | ((image0 >> 16) & 0xffff);
+ image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
-/* 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. */
+ if (HOST_BITS_PER_LONG == 64)
+ {
+ image0 = (image0 << 31 << 1) | image1;
+ image0 <<= 64 - 56;
+ image0 |= SIG_MSB;
+ r->sig[SIGSZ-1] = image0;
+ }
+ else
+ {
+ r->sig[SIGSZ-1] = image0;
+ r->sig[SIGSZ-2] = image1;
+ lshift_significand (r, r, 2*HOST_BITS_PER_LONG - 56);
+ r->sig[SIGSZ-1] |= SIG_MSB;
+ }
+ }
+}
-REAL_VALUE_TYPE
-ereal_from_float (f)
- HOST_WIDE_INT f;
+static void
+encode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
{
- REAL_VALUE_TYPE r;
- unsigned EMUSHORT s[2];
- unsigned EMUSHORT e[NE];
+ unsigned long image0, image1, sign = r->sign << 15;
- /* 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
+ switch (r->cl)
{
- 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;
-}
+ case rvc_zero:
+ image0 = image1 = 0;
+ break;
+ case rvc_inf:
+ case rvc_nan:
+ image0 = 0xffff7fff | sign;
+ image1 = 0xffffffff;
+ break;
-/* 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.
+ case rvc_normal:
+ /* Extract the significand into straight hi:lo. */
+ if (HOST_BITS_PER_LONG == 64)
+ {
+ image0 = r->sig[SIGSZ-1];
+ image1 = (image0 >> (64 - 53)) & 0xffffffff;
+ image0 = (image0 >> (64 - 53 + 1) >> 31) & 0xfffff;
+ }
+ else
+ {
+ image0 = r->sig[SIGSZ-1];
+ image1 = r->sig[SIGSZ-2];
+ image1 = (image0 << 21) | (image1 >> 11);
+ image0 = (image0 >> 11) & 0xfffff;
+ }
- 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. */
+ /* Rearrange the half-words of the significand to match the
+ external format. */
+ image0 = ((image0 << 16) | (image0 >> 16)) & 0xffff000f;
+ image1 = ((image1 << 16) | (image1 >> 16)) & 0xffffffff;
-REAL_VALUE_TYPE
-ereal_from_double (d)
- HOST_WIDE_INT d[];
-{
- REAL_VALUE_TYPE r;
- unsigned EMUSHORT s[4];
- unsigned EMUSHORT e[NE];
+ /* Add the sign and exponent. */
+ image0 |= sign;
+ image0 |= (REAL_EXP (r) + 1024) << 4;
+ break;
- /* 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];
-#if HOST_BITS_PER_WIDE_INT == 32
- 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[2] = (unsigned EMUSHORT) (d[0] >> 48);
- s[3] = (unsigned EMUSHORT) (d[0] >> 32);
-#endif
+ default:
+ gcc_unreachable ();
}
+
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ buf[0] = image1, buf[1] = image0;
else
- {
- /* 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
- }
- /* Convert target double to E-type. */
- e53toe (s, e);
- /* Output E-type to REAL_VALUE_TYPE. */
- PUT_REAL (e, &r);
- return r;
+ buf[0] = image0, buf[1] = image1;
}
-
-#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. */
-
static void
-uditoe (di, e)
- unsigned EMUSHORT *di; /* Address of the 64-bit int. */
- unsigned EMUSHORT *e;
+decode_vax_g (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
{
- unsigned EMUSHORT yi[NI];
- int k;
+ unsigned long image0, image1;
+ int exp;
- ecleaz (yi);
- if (WORDS_BIG_ENDIAN)
- {
- for (k = M; k < M + 4; k++)
- yi[k] = *di++;
- }
+ if (FLOAT_WORDS_BIG_ENDIAN)
+ image1 = buf[0], image0 = buf[1];
else
+ image0 = buf[0], image1 = buf[1];
+ image0 &= 0xffffffff;
+ image1 &= 0xffffffff;
+
+ exp = (image0 >> 4) & 0x7ff;
+
+ memset (r, 0, sizeof (*r));
+
+ if (exp != 0)
{
- for (k = M + 3; k >= M; k--)
- yi[k] = *di++;
+ r->cl = rvc_normal;
+ r->sign = (image0 >> 15) & 1;
+ SET_REAL_EXP (r, exp - 1024);
+
+ /* Rearrange the half-words of the external format into
+ proper ascending order. */
+ image0 = ((image0 & 0xf) << 16) | ((image0 >> 16) & 0xffff);
+ image1 = ((image1 & 0xffff) << 16) | ((image1 >> 16) & 0xffff);
+
+ if (HOST_BITS_PER_LONG == 64)
+ {
+ image0 = (image0 << 31 << 1) | image1;
+ image0 <<= 64 - 53;
+ image0 |= SIG_MSB;
+ r->sig[SIGSZ-1] = image0;
+ }
+ else
+ {
+ r->sig[SIGSZ-1] = image0;
+ r->sig[SIGSZ-2] = image1;
+ lshift_significand (r, r, 64 - 53);
+ r->sig[SIGSZ-1] |= SIG_MSB;
+ }
}
- 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);
}
-/* Convert target computer signed 64-bit integer to e-type. */
+const struct real_format vax_f_format =
+ {
+ encode_vax_f,
+ decode_vax_f,
+ 2,
+ 24,
+ 24,
+ -127,
+ 127,
+ 15,
+ 15,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ };
+
+const struct real_format vax_d_format =
+ {
+ encode_vax_d,
+ decode_vax_d,
+ 2,
+ 56,
+ 56,
+ -127,
+ 127,
+ 15,
+ 15,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ };
+
+const struct real_format vax_g_format =
+ {
+ encode_vax_g,
+ decode_vax_g,
+ 2,
+ 53,
+ 53,
+ -1023,
+ 1023,
+ 15,
+ 15,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false
+ };
+\f
+/* Encode real R into a single precision DFP value in BUF. */
+static void
+encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal32 (fmt, buf, r);
+}
+/* Decode a single precision DFP value in BUF into a real R. */
static void
-ditoe (di, e)
- unsigned EMUSHORT *di; /* Address of the 64-bit int. */
- unsigned EMUSHORT *e;
+decode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
{
- unsigned EMULONG acc;
- unsigned EMUSHORT yi[NI];
- unsigned EMUSHORT carry;
- int k, sign;
+ decode_decimal32 (fmt, r, buf);
+}
- 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--)
- {
- acc = (unsigned EMULONG) (~yi[k] & 0xffff) + carry;
- yi[k] = acc;
- carry = 0;
- if (acc & 0x10000)
- carry = 1;
- }
- }
- 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);
+/* Encode real R into a double precision DFP value in BUF. */
+static void
+encode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal64 (fmt, buf, r);
}
+/* Decode a double precision DFP value in BUF into a real R. */
+static void
+decode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
+{
+ decode_decimal64 (fmt, r, buf);
+}
-/* Convert e-type to unsigned 64-bit int. */
+/* Encode real R into a quad precision DFP value in BUF. */
+static void
+encode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal128 (fmt, buf, r);
+}
-static void
-etoudi (x, i)
- unsigned EMUSHORT *x;
- unsigned EMUSHORT *i;
+/* Decode a quad precision DFP value in BUF into a real R. */
+static void
+decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
{
- unsigned EMUSHORT xi[NI];
- int j, k;
+ decode_decimal128 (fmt, r, buf);
+}
- 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)
+/* Single precision decimal floating point (IEEE 754). */
+const struct real_format decimal_single_format =
+ {
+ encode_decimal_single,
+ decode_decimal_single,
+ 10,
+ 7,
+ 7,
+ -94,
+ 97,
+ 31,
+ 31,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+/* Double precision decimal floating point (IEEE 754). */
+const struct real_format decimal_double_format =
+ {
+ encode_decimal_double,
+ decode_decimal_double,
+ 10,
+ 16,
+ 16,
+ -382,
+ 385,
+ 63,
+ 63,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+/* Quad precision decimal floating point (IEEE 754). */
+const struct real_format decimal_quad_format =
+ {
+ encode_decimal_quad,
+ decode_decimal_quad,
+ 10,
+ 34,
+ 34,
+ -6142,
+ 6145,
+ 127,
+ 127,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+\f
+/* Encode half-precision floats. This routine is used both for the IEEE
+ ARM alternative encodings. */
+static void
+encode_ieee_half (const struct real_format *fmt, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ unsigned long image, sig, exp;
+ unsigned long sign = r->sign;
+ bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
+
+ image = sign << 15;
+ sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 11)) & 0x3ff;
+
+ switch (r->cl)
{
- /* 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];
+ case rvc_zero:
+ break;
+
+ case rvc_inf:
+ if (fmt->has_inf)
+ image |= 31 << 10;
else
+ image |= 0x7fff;
+ break;
+
+ case rvc_nan:
+ if (fmt->has_nans)
{
- i += 3;
- *i-- = xi[M];
- }
- k -= j;
- do
- {
- eshup6 (xi);
- if (WORDS_BIG_ENDIAN)
- *i++ = xi[M];
+ if (r->canonical)
+ sig = (fmt->canonical_nan_lsbs_set ? (1 << 9) - 1 : 0);
+ if (r->signalling == fmt->qnan_msb_set)
+ sig &= ~(1 << 9);
else
- *i-- = xi[M];
- }
- while ((k -= 16) > 0);
- }
- else
- {
- /* shift not more than 16 bits */
- eshift (xi, k);
-
-noshift:
+ sig |= 1 << 9;
+ if (sig == 0)
+ sig = 1 << 8;
- if (WORDS_BIG_ENDIAN)
- {
- i += 3;
- *i-- = xi[M];
- *i-- = 0;
- *i-- = 0;
- *i = 0;
+ image |= 31 << 10;
+ image |= sig;
}
else
- {
- *i++ = xi[M];
- *i++ = 0;
- *i++ = 0;
- *i = 0;
- }
+ image |= 0x3ff;
+ break;
+
+ case rvc_normal:
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one. */
+ if (denormal)
+ exp = 0;
+ else
+ exp = REAL_EXP (r) + 15 - 1;
+ image |= exp << 10;
+ image |= sig;
+ break;
+
+ default:
+ gcc_unreachable ();
}
+
+ buf[0] = image;
}
+/* Decode half-precision floats. This routine is used both for the IEEE
+ ARM alternative encodings. */
+static void
+decode_ieee_half (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+ const long *buf)
+{
+ unsigned long image = buf[0] & 0xffff;
+ bool sign = (image >> 15) & 1;
+ int exp = (image >> 10) & 0x1f;
-/* Convert e-type to signed 64-bit int. */
+ memset (r, 0, sizeof (*r));
+ image <<= HOST_BITS_PER_LONG - 11;
+ image &= ~SIG_MSB;
-static void
-etodi (x, i)
- unsigned EMUSHORT *x;
- unsigned EMUSHORT *i;
-{
- 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)
+ if (exp == 0)
{
- /* 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
+ if (image && fmt->has_denorm)
{
- eshup6 (xi);
- if (WORDS_BIG_ENDIAN)
- *i++ = xi[M];
- else
- *i-- = xi[M];
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, -14);
+ r->sig[SIGSZ-1] = image << 1;
+ normalize (r);
}
- while ((k -= 16) > 0);
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
}
- else
+ else if (exp == 31 && (fmt->has_nans || fmt->has_inf))
{
- /* shift not more than 16 bits */
- eshift (xi, k);
-
- if (WORDS_BIG_ENDIAN)
+ if (image)
{
- i += 3;
- *i = xi[M];
- *i-- = 0;
- *i-- = 0;
- *i = 0;
+ r->cl = rvc_nan;
+ r->sign = sign;
+ r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+ ^ fmt->qnan_msb_set);
+ r->sig[SIGSZ-1] = image;
}
else
{
- *i++ = xi[M];
- *i++ = 0;
- *i++ = 0;
- *i = 0;
+ r->cl = rvc_inf;
+ r->sign = sign;
}
}
- /* Negate if negative */
- if (xi[0])
+ else
{
- carry = 0;
- if (WORDS_BIG_ENDIAN)
- isave += 3;
- for (k = 0; k < 4; k++)
- {
- acc = (unsigned EMULONG) (~(*isave) & 0xffff) + carry;
- if (WORDS_BIG_ENDIAN)
- *isave-- = acc;
- else
- *isave++ = acc;
- carry = 0;
- if (acc & 0x10000)
- carry = 1;
- }
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, exp - 15 + 1);
+ r->sig[SIGSZ-1] = image | SIG_MSB;
}
}
+/* Half-precision format, as specified in IEEE 754R. */
+const struct real_format ieee_half_format =
+ {
+ encode_ieee_half,
+ decode_ieee_half,
+ 2,
+ 11,
+ 11,
+ -13,
+ 16,
+ 15,
+ 15,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+/* ARM's alternative half-precision format, similar to IEEE but with
+ no reserved exponent value for NaNs and infinities; rather, it just
+ extends the range of exponents by one. */
+const struct real_format arm_half_format =
+ {
+ encode_ieee_half,
+ decode_ieee_half,
+ 2,
+ 11,
+ 11,
+ -13,
+ 17,
+ 15,
+ 15,
+ false,
+ true,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false
+ };
+\f
+/* A synthetic "format" for internal arithmetic. It's the size of the
+ internal significand minus the two bits needed for proper rounding.
+ The encode and decode routines exist only to satisfy our paranoia
+ harness. */
+
+static void encode_internal (const struct real_format *fmt,
+ long *, const REAL_VALUE_TYPE *);
+static void decode_internal (const struct real_format *,
+ REAL_VALUE_TYPE *, const long *);
-/* Longhand square root routine. */
+static void
+encode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED, long *buf,
+ const REAL_VALUE_TYPE *r)
+{
+ memcpy (buf, r, sizeof (*r));
+}
+static void
+decode_internal (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r, const long *buf)
+{
+ memcpy (r, buf, sizeof (*r));
+}
-static int esqinited = 0;
-static unsigned short sqrndbit[NI];
+const struct real_format real_internal_format =
+ {
+ encode_internal,
+ decode_internal,
+ 2,
+ SIGNIFICAND_BITS - 2,
+ SIGNIFICAND_BITS - 2,
+ -MAX_EXP,
+ MAX_EXP,
+ -1,
+ -1,
+ false,
+ false,
+ true,
+ true,
+ false,
+ true,
+ true,
+ false
+ };
+\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. */
-static void
-esqrt (x, y)
- unsigned EMUSHORT *x, *y;
+bool
+real_sqrt (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;
+ get_canonical_qnan (r, 0);
+ return false;
}
-#ifdef INFINITY
- if (eisinf (x))
+ /* Infinity and NaN return themselves. */
+ if (!real_isfinite (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)
+ {
+ do_add (&halfthree, &dconst1, &dconsthalf, 0);
+ init = true;
+ }
+
+ /* Initial guess for reciprocal sqrt, i. */
+ exp = real_exponent (x);
+ real_ldexp (&i, &dconst1, -exp/2);
+
+ /* Newton's iteration for reciprocal sqrt, i. */
+ for (iter = 0; iter < 16; iter++)
{
- if (m > 0)
- exp += 1;
- eshdn1 (xx);
+ /* 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;
}
- ecleaz (sq);
- ecleaz (num);
- n = 8; /* get 8 bits of result per inner loop */
- nlups = rndprc;
- j = 0;
+ /* Final iteration: r = i*x + 0.5*i*x*(1.0 - i*(i*x)). */
+ do_multiply (&t, x, &i);
+ do_multiply (&h, &t, &i);
+ do_add (&i, &dconst1, &h, 1);
+ do_multiply (&h, &t, &i);
+ do_multiply (&i, &dconsthalf, &h);
+ do_add (&h, &t, &i, 0);
+
+ /* ??? We need a Tuckerman test to get the last bit. */
+
+ real_convert (r, mode, &h);
+ return true;
+}
+
+/* Calculate X raised to the integer exponent N in mode MODE and store
+ the result in R. Return true if the result may be inexact due to
+ loss of precision. The algorithm is the classic "left-to-right binary
+ method" described in section 4.6.3 of Donald Knuth's "Seminumerical
+ Algorithms", "The Art of Computer Programming", Volume 2. */
+
+bool
+real_powi (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x, HOST_WIDE_INT n)
+{
+ unsigned HOST_WIDE_INT bit;
+ REAL_VALUE_TYPE t;
+ bool inexact = false;
+ bool init = false;
+ bool neg;
+ int i;
+
+ if (n == 0)
+ {
+ *r = dconst1;
+ return false;
+ }
+ else if (n < 0)
+ {
+ /* Don't worry about overflow, from now on n is unsigned. */
+ neg = true;
+ n = -n;
+ }
+ else
+ neg = false;
- while (nlups > 0)
+ t = *x;
+ bit = (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1);
+ for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
{
- /* 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++)
+ if (init)
{
- /* 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;
- }
+ inexact |= do_multiply (&t, &t, &t);
+ if (n & bit)
+ inexact |= do_multiply (&t, &t, x);
}
- nlups -= n;
- j += 1;
+ else if (n & bit)
+ init = true;
+ bit >>= 1;
}
- /* Adjust for extra, roundoff loop done. */
- exp += (NBITS - 1) - rndprc;
+ if (neg)
+ inexact |= do_divide (&t, &dconst1, &t);
+
+ real_convert (r, mode, &t);
+ return inexact;
+}
- /* Sticky bit = 1 if the remainder is nonzero. */
- k = 0;
- for (i = 3; i < NI; i++)
- k |= (int) num[i];
+/* Round X to the nearest integer not larger in absolute value, i.e.
+ towards zero, placing the result in R in mode MODE. */
- /* Renormalize and round off. */
- emdnorm (sq, k, 0, exp, 64);
- emovo (sq, y);
+void
+real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_fix_trunc (r, x);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
}
-#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;
+/* Round X to the largest integer not greater in value, i.e. round
+ down, placing the result in R in mode MODE. */
+
+void
+real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
{
+ REAL_VALUE_TYPE t;
-/* Don't test the modes, but their sizes, lest this
- code won't work for BITS_PER_UNIT != 8 . */
+ do_fix_trunc (&t, x);
+ if (! real_identical (&t, x) && x->sign)
+ do_add (&t, &t, &dconstm1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, &t);
+ else
+ *r = t;
+}
-switch (GET_MODE_BITSIZE (mode))
- {
- case 32:
-
-#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
- return 56;
-#endif
+/* Round X to the smallest integer not less then argument, i.e. round
+ up, placing the result in R in mode MODE. */
- 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
+void
+real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ REAL_VALUE_TYPE t;
+
+ do_fix_trunc (&t, x);
+ if (! real_identical (&t, x) && ! x->sign)
+ do_add (&t, &t, &dconst1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, &t);
+ else
+ *r = t;
+}
- case 96:
- return 64;
- case 128:
- return 113;
+/* Round X to the nearest integer, but round halfway cases away from
+ zero. */
- default:
- abort ();
- }
+void
+real_round (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_add (r, x, &dconsthalf, x->sign);
+ do_fix_trunc (r, r);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
+/* Set the sign of R to the sign of X. */
+
+void
+real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x)
+{
+ r->sign = x->sign;
+}
+
+/* Check whether the real constant value given is an integer. */
+
+bool
+real_isinteger (const REAL_VALUE_TYPE *c, enum machine_mode mode)
+{
+ REAL_VALUE_TYPE cint;
+
+ real_trunc (&cint, mode, c);
+ return real_identical (c, &cint);
+}
+
+/* Write into BUF the maximum representable finite floating-point
+ number, (1 - b**-p) * b**emax for a given FP format FMT as a hex
+ float string. LEN is the size of BUF, and the buffer must be large
+ enough to contain the resulting string. */
+
+void
+get_max_float (const struct real_format *fmt, char *buf, size_t len)
+{
+ int i, n;
+ char *p;
+
+ strcpy (buf, "0x0.");
+ n = fmt->p;
+ for (i = 0, p = buf + 4; i + 3 < n; i += 4)
+ *p++ = 'f';
+ if (i < n)
+ *p++ = "08ce"[n - i];
+ sprintf (p, "p%d", fmt->emax);
+ if (fmt->pnan < fmt->p)
+ {
+ /* This is an IBM extended double format made up of two IEEE
+ doubles. The value of the long double is the sum of the
+ values of the two parts. The most significant part is
+ required to be the value of the long double rounded to the
+ nearest double. Rounding means we need a slightly smaller
+ value for LDBL_MAX. */
+ buf[4 + fmt->pnan / 4] = "7bde"[fmt->pnan % 4];
+ }
+
+ gcc_assert (strlen (buf) < len);
}