/* real.c - software floating point emulation.
- Copyright (C) 1993-2014 Free Software Foundation, Inc.
+ Copyright (C) 1993-2015 Free Software Foundation, Inc.
Contributed by Stephen L. Moshier (moshier@world.std.com).
Re-written by Richard Henderson <rth@redhat.com>
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
#include "diagnostic-core.h"
-#include "real.h"
#include "realmpfr.h"
#include "tm_p.h"
#include "dfp.h"
-#include "wide-int.h"
+#include "rtl.h"
+#include "options.h"
/* The floating point model used internally is not exactly IEEE 754
compliant, and close to the description in the ISO C99 standard,
mode MODE. Return true if successful. */
bool
-exact_real_inverse (enum machine_mode mode, REAL_VALUE_TYPE *r)
+exact_real_inverse (machine_mode mode, REAL_VALUE_TYPE *r)
{
const REAL_VALUE_TYPE *one = real_digit (1);
REAL_VALUE_TYPE u;
in TMODE. */
bool
-real_can_shorten_arithmetic (enum machine_mode imode, enum machine_mode tmode)
+real_can_shorten_arithmetic (machine_mode imode, machine_mode tmode)
{
const struct real_format *tfmt, *ifmt;
tfmt = REAL_MODE_FORMAT (tmode);
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)
+ int crop_trailing_zeros, machine_mode mode)
{
const struct real_format *fmt = NULL;
const REAL_VALUE_TYPE *one, *ten;
because the hex digits used in real_from_mpfr did not
start with a digit 8 to f, but the exponent bounds above
should have avoided underflow or overflow. */
- gcc_assert (r->cl = rvc_normal);
+ gcc_assert (r->cl == rvc_normal);
/* Set a sticky bit if mpfr_strtofr was inexact. */
r->sig[0] |= inexact;
+ mpfr_clear (m);
}
}
/* Legacy. Similar, but return the result directly. */
REAL_VALUE_TYPE
-real_from_string2 (const char *s, enum machine_mode mode)
+real_from_string2 (const char *s, machine_mode mode)
{
REAL_VALUE_TYPE r;
/* Initialize R from string S and desired MODE. */
void
-real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode)
+real_from_string3 (REAL_VALUE_TYPE *r, const char *s, machine_mode mode)
{
if (DECIMAL_FLOAT_MODE_P (mode))
decimal_real_from_string (r, s);
/* Initialize R from the wide_int VAL_IN. The MODE is not VOIDmode,*/
void
-real_from_integer (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_from_integer (REAL_VALUE_TYPE *r, machine_mode mode,
const wide_int_ref &val_in, signop sgn)
{
if (val_in == 0)
bool
real_nan (REAL_VALUE_TYPE *r, const char *str, int quiet,
- enum machine_mode mode)
+ machine_mode mode)
{
const struct real_format *fmt;
If SIGN is nonzero, R is set to the most negative finite value. */
void
-real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode)
+real_maxval (REAL_VALUE_TYPE *r, int sign, machine_mode mode)
{
const struct real_format *fmt;
int np2;
/* Fills R with 2**N. */
void
-real_2expN (REAL_VALUE_TYPE *r, int n, enum machine_mode fmode)
+real_2expN (REAL_VALUE_TYPE *r, int n, machine_mode fmode)
{
memset (r, 0, sizeof (*r));
/* Extend or truncate to a new mode. */
void
-real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_convert (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *a)
{
const struct real_format *fmt;
/* Legacy. Likewise, except return the struct directly. */
REAL_VALUE_TYPE
-real_value_truncate (enum machine_mode mode, REAL_VALUE_TYPE a)
+real_value_truncate (machine_mode mode, REAL_VALUE_TYPE a)
{
REAL_VALUE_TYPE r;
real_convert (&r, mode, &a);
/* Return true if truncating to MODE is exact. */
bool
-exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
+exact_real_truncate (machine_mode mode, const REAL_VALUE_TYPE *a)
{
const struct real_format *fmt;
REAL_VALUE_TYPE t;
/* Similar, but look up the format from MODE. */
long
-real_to_target (long *buf, const REAL_VALUE_TYPE *r, enum machine_mode mode)
+real_to_target (long *buf, const REAL_VALUE_TYPE *r, machine_mode mode)
{
const struct real_format *fmt;
/* Similar, but look up the format from MODE. */
void
-real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode)
+real_from_target (REAL_VALUE_TYPE *r, const long *buf, machine_mode mode)
{
const struct real_format *fmt;
/* ??? Legacy. Should get access to real_format directly. */
int
-significand_size (enum machine_mode mode)
+significand_size (machine_mode mode)
{
const struct real_format *fmt;
true,
true,
true,
- false
+ false,
+ "ieee_single"
};
const struct real_format mips_single_format =
true,
true,
false,
- true
+ true,
+ "mips_single"
};
const struct real_format motorola_single_format =
true,
true,
true,
- true
+ true,
+ "motorola_single"
};
/* SPU Single Precision (Extended-Range Mode) format is the same as IEEE
true,
true,
false,
- false
+ false,
+ "spu_single"
};
\f
/* IEEE double-precision format. */
true,
true,
true,
- false
+ false,
+ "ieee_double"
};
const struct real_format mips_double_format =
true,
true,
false,
- true
+ true,
+ "mips_double"
};
const struct real_format motorola_double_format =
true,
true,
true,
- true
+ true,
+ "motorola_double"
};
\f
/* IEEE extended real format. This comes in three flavors: Intel's as
long intermed[3];
encode_ieee_extended (fmt, intermed, r);
+ if (r->cl == rvc_inf)
+ /* For infinity clear the explicit integer bit again, so that the
+ format matches the canonical infinity generated by the FPU. */
+ intermed[1] = 0;
+
/* 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
true,
true,
true,
- true
+ true,
+ "ieee_extended_motorola"
};
const struct real_format ieee_extended_intel_96_format =
true,
true,
true,
- false
+ false,
+ "ieee_extended_intel_96"
};
const struct real_format ieee_extended_intel_128_format =
true,
true,
true,
- false
+ false,
+ "ieee_extended_intel_128"
};
/* The following caters to i386 systems that set the rounding precision
true,
true,
true,
- false
+ false,
+ "ieee_extended_intel_96_round_53"
};
\f
/* IBM 128-bit extended precision format: a pair of IEEE double precision
true,
true,
true,
- false
+ false,
+ "ibm_extended"
};
const struct real_format mips_extended_format =
true,
true,
false,
- true
+ true,
+ "mips_extended"
};
\f
true,
true,
true,
- false
+ false,
+ "ieee_quad"
};
const struct real_format mips_quad_format =
true,
true,
false,
- true
+ true,
+ "mips_quad"
};
\f
/* Descriptions of VAX floating point formats can be found beginning at
false,
false,
false,
- false
+ false,
+ "vax_f"
};
const struct real_format vax_d_format =
false,
false,
false,
- false
+ false,
+ "vax_d"
};
const struct real_format vax_g_format =
false,
false,
false,
- false
+ false,
+ "vax_g"
};
\f
/* Encode real R into a single precision DFP value in BUF. */
true,
true,
true,
- false
+ false,
+ "decimal_single"
};
/* Double precision decimal floating point (IEEE 754). */
true,
true,
true,
- false
+ false,
+ "decimal_double"
};
/* Quad precision decimal floating point (IEEE 754). */
true,
true,
true,
- false
+ false,
+ "decimal_quad"
};
\f
/* Encode half-precision floats. This routine is used both for the IEEE
true,
true,
true,
- false
+ false,
+ "ieee_half"
};
/* ARM's alternative half-precision format, similar to IEEE but with
true,
true,
false,
- false
+ false,
+ "arm_half"
};
\f
/* A synthetic "format" for internal arithmetic. It's the size of the
false,
true,
true,
- false
+ false,
+ "real_internal"
};
\f
/* Calculate X raised to the integer exponent N in mode MODE and store
Algorithms", "The Art of Computer Programming", Volume 2. */
bool
-real_powi (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_powi (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *x, HOST_WIDE_INT n)
{
unsigned HOST_WIDE_INT bit;
towards zero, placing the result in R in mode MODE. */
void
-real_trunc (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_trunc (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *x)
{
do_fix_trunc (r, x);
down, placing the result in R in mode MODE. */
void
-real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_floor (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *x)
{
REAL_VALUE_TYPE t;
up, placing the result in R in mode MODE. */
void
-real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_ceil (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *x)
{
REAL_VALUE_TYPE t;
zero. */
void
-real_round (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_round (REAL_VALUE_TYPE *r, machine_mode mode,
const REAL_VALUE_TYPE *x)
{
do_add (r, x, &dconsthalf, 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_isinteger (const REAL_VALUE_TYPE *c, machine_mode mode)
{
REAL_VALUE_TYPE cint;
gcc_assert (strlen (buf) < len);
}
+
+/* True if mode M has a NaN representation and
+ the treatment of NaN operands is important. */
+
+bool
+HONOR_NANS (machine_mode m)
+{
+ return MODE_HAS_NANS (m) && !flag_finite_math_only;
+}
+
+bool
+HONOR_NANS (const_tree t)
+{
+ return HONOR_NANS (element_mode (t));
+}
+
+bool
+HONOR_NANS (const_rtx x)
+{
+ return HONOR_NANS (GET_MODE (x));
+}
+
+/* Like HONOR_NANs, but true if we honor signaling NaNs (or sNaNs). */
+
+bool
+HONOR_SNANS (machine_mode m)
+{
+ return flag_signaling_nans && HONOR_NANS (m);
+}
+
+bool
+HONOR_SNANS (const_tree t)
+{
+ return HONOR_SNANS (element_mode (t));
+}
+
+bool
+HONOR_SNANS (const_rtx x)
+{
+ return HONOR_SNANS (GET_MODE (x));
+}
+
+/* As for HONOR_NANS, but true if the mode can represent infinity and
+ the treatment of infinite values is important. */
+
+bool
+HONOR_INFINITIES (machine_mode m)
+{
+ return MODE_HAS_INFINITIES (m) && !flag_finite_math_only;
+}
+
+bool
+HONOR_INFINITIES (const_tree t)
+{
+ return HONOR_INFINITIES (element_mode (t));
+}
+
+bool
+HONOR_INFINITIES (const_rtx x)
+{
+ return HONOR_INFINITIES (GET_MODE (x));
+}
+
+/* Like HONOR_NANS, but true if the given mode distinguishes between
+ positive and negative zero, and the sign of zero is important. */
+
+bool
+HONOR_SIGNED_ZEROS (machine_mode m)
+{
+ return MODE_HAS_SIGNED_ZEROS (m) && flag_signed_zeros;
+}
+
+bool
+HONOR_SIGNED_ZEROS (const_tree t)
+{
+ return HONOR_SIGNED_ZEROS (element_mode (t));
+}
+
+bool
+HONOR_SIGNED_ZEROS (const_rtx x)
+{
+ return HONOR_SIGNED_ZEROS (GET_MODE (x));
+}
+
+/* Like HONOR_NANS, but true if given mode supports sign-dependent rounding,
+ and the rounding mode is important. */
+
+bool
+HONOR_SIGN_DEPENDENT_ROUNDING (machine_mode m)
+{
+ return MODE_HAS_SIGN_DEPENDENT_ROUNDING (m) && flag_rounding_math;
+}
+
+bool
+HONOR_SIGN_DEPENDENT_ROUNDING (const_tree t)
+{
+ return HONOR_SIGN_DEPENDENT_ROUNDING (element_mode (t));
+}
+
+bool
+HONOR_SIGN_DEPENDENT_ROUNDING (const_rtx x)
+{
+ return HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (x));
+}