/* real.c - software floating point emulation.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2002, 2003 Free Software Foundation, Inc.
+ 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
Contributed by Stephen L. Moshier (moshier@world.std.com).
Re-written by Richard Henderson <rth@redhat.com>
else
rr = r;
+ /* Make sure all fields in the result are initialized. */
+ get_zero (rr, 0);
rr->class = rvc_normal;
rr->sign = sign;
{
const struct real_format *fmt;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
abort ();
const struct real_format *fmt;
int np2;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
abort ();
{
const struct real_format *fmt;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
abort ();
{
const struct real_format *fmt;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
abort ();
{
const struct real_format *fmt;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
abort ();
{
const struct real_format *fmt;
- fmt = real_format_for_mode[mode - QFmode];
+ fmt = REAL_MODE_FORMAT (mode);
if (fmt == NULL)
return 0;
const REAL_VALUE_TYPE *r)
{
unsigned long image, sig, exp;
+ unsigned long sign = r->sign;
bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
- image = r->sign << 31;
+ image = sign << 31;
sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 24)) & 0x7fffff;
switch (r->class)
base_fmt = fmt->qnan_msb_set ? &ieee_double_format : &mips_double_format;
- switch (r->class)
- {
- case rvc_zero:
- /* Both doubles have sign bit set. */
- buf[0] = FLOAT_WORDS_BIG_ENDIAN ? r->sign << 31 : 0;
- buf[1] = FLOAT_WORDS_BIG_ENDIAN ? 0 : r->sign << 31;
- buf[2] = buf[0];
- buf[3] = buf[1];
- break;
-
- case rvc_inf:
- case rvc_nan:
- /* Both doubles set to Inf / NaN. */
- encode_ieee_double (base_fmt, &buf[0], r);
- buf[2] = buf[0];
- buf[3] = buf[1];
- return;
-
- case rvc_normal:
- /* u = IEEE double precision portion of significand. */
- u = *r;
- clear_significand_below (&u, SIGNIFICAND_BITS - 53);
-
- normalize (&u);
- /* If the upper double is zero, we have a denormal double, so
- move it to the first double and leave the second as zero. */
- if (u.class == rvc_zero)
- {
- v = u;
- u = *r;
- normalize (&u);
- }
- else
- {
- /* v = remainder containing additional 53 bits of significand. */
- do_add (&v, r, &u, 1);
- round_for_format (base_fmt, &v);
- }
-
- round_for_format (base_fmt, &u);
+ /* u = IEEE double precision portion of significand. */
+ u = *r;
+ round_for_format (base_fmt, &u);
+ encode_ieee_double (base_fmt, &buf[0], &u);
- encode_ieee_double (base_fmt, &buf[0], &u);
+ if (r->class == rvc_normal)
+ {
+ do_add (&v, r, &u, 1);
+ round_for_format (base_fmt, &v);
encode_ieee_double (base_fmt, &buf[2], &v);
- break;
-
- default:
- abort ();
+ }
+ else
+ {
+ /* Inf, NaN, 0 are all representable as doubles, so the
+ least-significant part can be 0.0. */
+ buf[2] = 0;
+ buf[3] = 0;
}
}
true
};
\f
-/* Set up default mode to format mapping for IEEE. Everyone else has
- to set these values in OVERRIDE_OPTIONS. */
-
-const struct real_format *real_format_for_mode[TFmode - QFmode + 1] =
-{
- NULL, /* QFmode */
- NULL, /* HFmode */
- NULL, /* TQFmode */
- &ieee_single_format, /* SFmode */
- &ieee_double_format, /* DFmode */
-
- /* We explicitly don't handle XFmode. There are two formats,
- pretty much equally common. Choose one in OVERRIDE_OPTIONS. */
- NULL, /* XFmode */
- &ieee_quad_format /* TFmode */
-};
-
-\f
/* Calculate the square root of X in mode MODE, and store the result
in R. Return TRUE if the operation does not raise an exception.
For details see "High Precision Division and Square Root",
real_floor (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
- do_fix_trunc (r, x);
- if (! real_identical (r, x) && r->sign)
- do_add (r, r, &dconstm1, 0);
+ REAL_VALUE_TYPE t;
+
+ 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, r);
+ real_convert (r, mode, &t);
}
/* Round X to the smallest integer not less then argument, i.e. round
real_ceil (REAL_VALUE_TYPE *r, enum machine_mode mode,
const REAL_VALUE_TYPE *x)
{
- do_fix_trunc (r, x);
- if (! real_identical (r, x) && ! r->sign)
- do_add (r, r, &dconst1, 0);
+ REAL_VALUE_TYPE t;
+
+ do_fix_trunc (&t, x);
+ if (! real_identical (&t, x) && ! x->sign)
+ do_add (&t, &t, &dconst1, 0);
+ if (mode != VOIDmode)
+ real_convert (r, mode, &t);
+}
+
+/* Round X to the nearest integer, but round halfway cases away from
+ zero. */
+
+void
+real_round (REAL_VALUE_TYPE *r, enum machine_mode mode,
+ const REAL_VALUE_TYPE *x)
+{
+ do_add (r, x, &dconsthalf, x->sign);
+ do_fix_trunc (r, r);
if (mode != VOIDmode)
real_convert (r, mode, r);
}
+