summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog32
-rw-r--r--gcc/builtins.c42
-rw-r--r--gcc/c-cppbuiltin.c5
-rw-r--r--gcc/config/pdp11/pdp11.c2
-rw-r--r--gcc/config/spu/float_disf.c30
-rw-r--r--gcc/config/spu/float_unsdisf.c30
-rw-r--r--gcc/config/spu/spu.md59
-rw-r--r--gcc/config/spu/t-spu-elf7
-rw-r--r--gcc/real.c119
-rw-r--r--gcc/real.h8
-rw-r--r--gcc/testsuite/ChangeLog13
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20031003-1.c6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/conversion.c12
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c6
-rw-r--r--gcc/testsuite/gcc.dg/hex-round-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/hex-round-2.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c1
-rw-r--r--gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c3
18 files changed, 333 insertions, 44 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 80a0a87c6fa..28b13ccbe9b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,35 @@
+2008-08-19 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * real.h (struct real_format): New member round_towards_zero.
+ * real.c (round_for_format): Respect fmt->round_towards_zero.
+ (ieee_single_format, mips_single_format, motorola_single_format,
+ spu_single_format, ieee_double_format, mips_double_format,
+ motorola_double_format, ieee_extended_motorola_format,
+ ieee_extended_intel_96_format, ieee_extended_intel_128_format,
+ ieee_extended_intel_96_round_53_format, ibm_extended_format,
+ mips_extended_format, ieee_quad_format, mips_quad_format,
+ vax_f_format, vax_d_format, vax_g_format): Initialize it.
+ * config/pdp11/pdp11.c (pdp11_f_format, pdp11_d_format): Likewise.
+
+ * builtins.s (do_mpfr_arg1): Consider round_towards_zero member of
+ real_format to choose rounding mode when calling MPFR functions.
+ (do_mpfr_arg2, do_mpfr_arg3, do_mpfr_sincos): Likewise.
+ (do_mpfr_bessel_n, do_mpfr_remquo, do_mpfr_lgamma_r): Likewise.
+
+ * real.h (real_to_decimal_for_mode): Add prototype.
+ * real.c (real_to_decimal_for_mode): Renames old real_to_decimal.
+ Respect target rounding mode when generating decimal representation.
+ (real_to_decimal): New stub for backwards compatibility.
+ * c-cppbuiltin.c (builtin_define_with_hex_fp_value): Use
+ real_to_decimal_for_mode instead of real_to_decimal.
+
+ * config/spu/spu.md ("floatdisf2", "floatunsdisf2"): New.
+
+ * config/spu/float_disf.c: New file.
+ * config/spu/float_unsdisf.c: New file.
+ * config/spu/t-elf (LIB2FUNCS_STATIC_EXTRA): Add them.
+ (LIB2FUNCS_EXCLUDE): Define.
+
2008-08-19 Jakub Jelinek <jakub@redhat.com>
PR debug/37156
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 66d55733fe7..d61651e7728 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -12688,14 +12688,16 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
&& (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
&& (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
int inexact;
mpfr_t m;
mpfr_init2 (m, prec);
mpfr_from_real (m, ra, GMP_RNDN);
mpfr_clear_flags ();
- inexact = func (m, m, GMP_RNDN);
+ inexact = func (m, m, rnd);
result = do_mpfr_ckconv (m, type, inexact);
mpfr_clear (m);
}
@@ -12730,7 +12732,9 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
if (real_isfinite (ra1) && real_isfinite (ra2))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
int inexact;
mpfr_t m1, m2;
@@ -12738,7 +12742,7 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
mpfr_from_real (m1, ra1, GMP_RNDN);
mpfr_from_real (m2, ra2, GMP_RNDN);
mpfr_clear_flags ();
- inexact = func (m1, m1, m2, GMP_RNDN);
+ inexact = func (m1, m1, m2, rnd);
result = do_mpfr_ckconv (m1, type, inexact);
mpfr_clears (m1, m2, NULL);
}
@@ -12776,7 +12780,9 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
if (real_isfinite (ra1) && real_isfinite (ra2) && real_isfinite (ra3))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
int inexact;
mpfr_t m1, m2, m3;
@@ -12785,7 +12791,7 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
mpfr_from_real (m2, ra2, GMP_RNDN);
mpfr_from_real (m3, ra3, GMP_RNDN);
mpfr_clear_flags ();
- inexact = func (m1, m1, m2, m3, GMP_RNDN);
+ inexact = func (m1, m1, m2, m3, rnd);
result = do_mpfr_ckconv (m1, type, inexact);
mpfr_clears (m1, m2, m3, NULL);
}
@@ -12819,7 +12825,9 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
if (real_isfinite (ra))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
tree result_s, result_c;
int inexact;
mpfr_t m, ms, mc;
@@ -12827,7 +12835,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
mpfr_inits2 (prec, m, ms, mc, NULL);
mpfr_from_real (m, ra, GMP_RNDN);
mpfr_clear_flags ();
- inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN);
+ inexact = mpfr_sin_cos (ms, mc, m, rnd);
result_s = do_mpfr_ckconv (ms, type, inexact);
result_c = do_mpfr_ckconv (mc, type, inexact);
mpfr_clears (m, ms, mc, NULL);
@@ -12892,14 +12900,16 @@ do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
&& real_isfinite (ra)
&& (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min)))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
int inexact;
mpfr_t m;
mpfr_init2 (m, prec);
mpfr_from_real (m, ra, GMP_RNDN);
mpfr_clear_flags ();
- inexact = func (m, n, m, GMP_RNDN);
+ inexact = func (m, n, m, rnd);
result = do_mpfr_ckconv (m, type, inexact);
mpfr_clear (m);
}
@@ -12933,7 +12943,9 @@ do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
if (real_isfinite (ra0) && real_isfinite (ra1))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
tree result_rem;
long integer_quo;
mpfr_t m0, m1;
@@ -12942,7 +12954,7 @@ do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
mpfr_from_real (m0, ra0, GMP_RNDN);
mpfr_from_real (m1, ra1, GMP_RNDN);
mpfr_clear_flags ();
- mpfr_remquo (m0, &integer_quo, m0, m1, GMP_RNDN);
+ mpfr_remquo (m0, &integer_quo, m0, m1, rnd);
/* Remquo is independent of the rounding mode, so pass
inexact=0 to do_mpfr_ckconv(). */
result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
@@ -13010,7 +13022,9 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
&& ra->cl != rvc_zero
&& !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type))))
{
- const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
+ const int prec = fmt->p;
+ const mp_rnd_t rnd = fmt->round_towards_zero? GMP_RNDZ : GMP_RNDN;
int inexact, sg;
mpfr_t m;
tree result_lg;
@@ -13018,7 +13032,7 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
mpfr_init2 (m, prec);
mpfr_from_real (m, ra, GMP_RNDN);
mpfr_clear_flags ();
- inexact = mpfr_lgamma (m, &sg, m, GMP_RNDN);
+ inexact = mpfr_lgamma (m, &sg, m, rnd);
result_lg = do_mpfr_ckconv (m, type, inexact);
mpfr_clear (m);
if (result_lg)
diff --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c
index 86c3f9cfff2..cd53ae7a729 100644
--- a/gcc/c-cppbuiltin.c
+++ b/gcc/c-cppbuiltin.c
@@ -837,7 +837,7 @@ builtin_define_with_int_value (const char *macro, HOST_WIDE_INT value)
/* Pass an object-like macro a hexadecimal floating-point value. */
static void
builtin_define_with_hex_fp_value (const char *macro,
- tree type ATTRIBUTE_UNUSED, int digits,
+ tree type, int digits,
const char *hex_str,
const char *fp_suffix,
const char *fp_cast)
@@ -856,7 +856,8 @@ builtin_define_with_hex_fp_value (const char *macro,
then print it back out as decimal. */
real_from_string (&real, hex_str);
- real_to_decimal (dec_str, &real, sizeof (dec_str), digits, 0);
+ real_to_decimal_for_mode (dec_str, &real, sizeof (dec_str), digits, 0,
+ TYPE_MODE (type));
/* Assemble the macro in the following fashion
macro = fp_cast [dec_str fp_suffix] */
diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c
index ba649eac60f..2de1938550d 100644
--- a/gcc/config/pdp11/pdp11.c
+++ b/gcc/config/pdp11/pdp11.c
@@ -78,6 +78,7 @@ const struct real_format pdp11_f_format =
false,
false,
false,
+ false,
false
};
@@ -97,6 +98,7 @@ const struct real_format pdp11_d_format =
false,
false,
false,
+ false,
false
};
diff --git a/gcc/config/spu/float_disf.c b/gcc/config/spu/float_disf.c
new file mode 100644
index 00000000000..d8f3eb47615
--- /dev/null
+++ b/gcc/config/spu/float_disf.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This file 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 of the License, or (at your option)
+ any later version.
+
+ This file 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 this file; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. The exception does not
+ however invalidate any other reasons why the executable file might be covered
+ by the GNU General Public License. */
+
+float __floatdisf (long long x)
+{
+ /* The SPU back-end now generates inline code for this conversion.
+ This file is solely used to provide the __floatdisf functions
+ for objects generated with prior versions of GCC. */
+ return x;
+}
diff --git a/gcc/config/spu/float_unsdisf.c b/gcc/config/spu/float_unsdisf.c
new file mode 100644
index 00000000000..0f16b963e2f
--- /dev/null
+++ b/gcc/config/spu/float_unsdisf.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+
+ This file 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 of the License, or (at your option)
+ any later version.
+
+ This file 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 this file; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. The exception does not
+ however invalidate any other reasons why the executable file might be covered
+ by the GNU General Public License. */
+
+float __floatundisf (unsigned long long x)
+{
+ /* The SPU back-end now generates inline code for this conversion.
+ This file is solely used to provide the __floatundisf function
+ for objects generated with prior versions of GCC. */
+ return x;
+}
diff --git a/gcc/config/spu/spu.md b/gcc/config/spu/spu.md
index 83a44be6f11..b316b9d4516 100644
--- a/gcc/config/spu/spu.md
+++ b/gcc/config/spu/spu.md
@@ -661,6 +661,65 @@
"frds\t%0,%1"
[(set_attr "type" "fpd")])
+(define_expand "floatdisf2"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (float:SF (match_operand:DI 1 "register_operand" "")))]
+ ""
+ {
+ rtx c0 = gen_reg_rtx (SImode);
+ rtx r0 = gen_reg_rtx (DImode);
+ rtx r1 = gen_reg_rtx (SFmode);
+ rtx r2 = gen_reg_rtx (SImode);
+ rtx setneg = gen_reg_rtx (SImode);
+ rtx isneg = gen_reg_rtx (SImode);
+ rtx neg = gen_reg_rtx (DImode);
+ rtx mask = gen_reg_rtx (DImode);
+
+ emit_move_insn (c0, GEN_INT (-0x80000000ll));
+
+ emit_insn (gen_negdi2 (neg, operands[1]));
+ emit_insn (gen_cgt_di_m1 (isneg, operands[1]));
+ emit_insn (gen_extend_compare (mask, isneg));
+ emit_insn (gen_selb (r0, neg, operands[1], mask));
+ emit_insn (gen_andc_si (setneg, c0, isneg));
+
+ emit_insn (gen_floatunsdisf2 (r1, r0));
+
+ emit_insn (gen_iorsi3 (r2, gen_rtx_SUBREG (SImode, r1, 0), setneg));
+ emit_move_insn (operands[0], gen_rtx_SUBREG (SFmode, r2, 0));
+ DONE;
+ })
+
+(define_insn_and_split "floatunsdisf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unsigned_float:SF (match_operand:DI 1 "register_operand" "r")))
+ (clobber (match_scratch:SF 2 "=r"))
+ (clobber (match_scratch:SF 3 "=r"))
+ (clobber (match_scratch:SF 4 "=r"))]
+ ""
+ "#"
+ "reload_completed"
+ [(set (match_dup:SF 0)
+ (unsigned_float:SF (match_dup:DI 1)))]
+ {
+ rtx op1_v4si = gen_rtx_REG (V4SImode, REGNO (operands[1]));
+ rtx op2_v4sf = gen_rtx_REG (V4SFmode, REGNO (operands[2]));
+ rtx op2_ti = gen_rtx_REG (TImode, REGNO (operands[2]));
+ rtx op3_ti = gen_rtx_REG (TImode, REGNO (operands[3]));
+
+ REAL_VALUE_TYPE scale;
+ real_2expN (&scale, 32, SFmode);
+
+ emit_insn (gen_floatunsv4siv4sf2 (op2_v4sf, op1_v4si));
+ emit_insn (gen_shlqby_ti (op3_ti, op2_ti, GEN_INT (4)));
+
+ emit_move_insn (operands[4],
+ CONST_DOUBLE_FROM_REAL_VALUE (scale, SFmode));
+ emit_insn (gen_fma_sf (operands[0],
+ operands[2], operands[4], operands[3]));
+ DONE;
+ })
+
;; Do (double)(operands[1]+0x80000000u)-(double)0x80000000
(define_expand "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "")
diff --git a/gcc/config/spu/t-spu-elf b/gcc/config/spu/t-spu-elf
index 0a3947d9017..017f09d1fb6 100644
--- a/gcc/config/spu/t-spu-elf
+++ b/gcc/config/spu/t-spu-elf
@@ -21,8 +21,15 @@ CROSS_LIBGCC1 =
TARGET_LIBGCC2_CFLAGS = -fPIC -mwarn-reloc -D__IN_LIBGCC2
+# We exclude those because the libgcc2.c default versions do not support
+# the SPU single-precision format (round towards zero). We provide our
+# own versions below.
+LIB2FUNCS_EXCLUDE = _floatdisf _floatundisf
+
LIB2FUNCS_STATIC_EXTRA = $(srcdir)/config/spu/float_unssidf.c \
$(srcdir)/config/spu/float_unsdidf.c \
+ $(srcdir)/config/spu/float_unsdisf.c \
+ $(srcdir)/config/spu/float_disf.c \
$(srcdir)/config/spu/mfc_tag_table.c \
$(srcdir)/config/spu/mfc_tag_reserve.c \
$(srcdir)/config/spu/mfc_tag_release.c \
diff --git a/gcc/real.c b/gcc/real.c
index 4488795fcf0..2077953556f 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -1443,20 +1443,30 @@ rtd_divmod (REAL_VALUE_TYPE *num, REAL_VALUE_TYPE *den)
/* Render R as a decimal floating point constant. Emit DIGITS significant
digits in the result, bounded by BUF_SIZE. If DIGITS is 0, choose the
maximum for the representation. If CROP_TRAILING_ZEROS, strip trailing
- zeros. */
+ zeros. If MODE is VOIDmode, round to nearest value. Otherwise, round
+ to a string that, when parsed back in mode MODE, yields the same value. */
#define M_LOG10_2 0.30102999566398119521
void
-real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
- size_t digits, int crop_trailing_zeros)
+real_to_decimal_for_mode (char *str, const REAL_VALUE_TYPE *r_orig,
+ size_t buf_size, size_t digits,
+ int crop_trailing_zeros, enum machine_mode mode)
{
+ const struct real_format *fmt = NULL;
const REAL_VALUE_TYPE *one, *ten;
REAL_VALUE_TYPE r, pten, u, v;
int dec_exp, cmp_one, digit;
size_t max_digits;
char *p, *first, *last;
bool sign;
+ bool round_up;
+
+ if (mode != VOIDmode)
+ {
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+ }
r = *r_orig;
switch (r.cl)
@@ -1671,17 +1681,31 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
digit = rtd_divmod (&r, &pten);
/* Round the result. */
- if (digit == 5)
+ if (fmt && fmt->round_towards_zero)
{
- /* Round to nearest. If R is nonzero there are additional
- nonzero digits to be extracted. */
+ /* If the format uses round towards zero when parsing the string
+ back in, we need to always round away from zero here. */
if (cmp_significand_0 (&r))
digit++;
- /* Round to even. */
- else if ((p[-1] - '0') & 1)
- digit++;
+ round_up = digit > 0;
}
- if (digit > 5)
+ else
+ {
+ if (digit == 5)
+ {
+ /* Round to nearest. If R is nonzero there are additional
+ nonzero digits to be extracted. */
+ if (cmp_significand_0 (&r))
+ digit++;
+ /* Round to even. */
+ else if ((p[-1] - '0') & 1)
+ digit++;
+ }
+
+ round_up = digit > 5;
+ }
+
+ if (round_up)
{
while (p > first)
{
@@ -1715,6 +1739,26 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
/* Append the exponent. */
sprintf (last, "e%+d", dec_exp);
+
+#ifdef ENABLE_CHECKING
+ /* Verify that we can read the original value back in. */
+ if (mode != VOIDmode)
+ {
+ real_from_string (&r, str);
+ real_convert (&r, mode, &r);
+ gcc_assert (real_identical (&r, r_orig));
+ }
+#endif
+}
+
+/* Likewise, except always uses round-to-nearest. */
+
+void
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
+{
+ real_to_decimal_for_mode (str, r_orig, buf_size,
+ digits, crop_trailing_zeros, VOIDmode);
}
/* Render R as a hexadecimal floating point constant. Emit DIGITS
@@ -2328,9 +2372,8 @@ static void
round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
{
int p2, np2, i, w;
- unsigned long sticky;
- bool guard, lsb;
int emin2m1, emax2;
+ bool round_up = false;
if (r->decimal)
{
@@ -2402,21 +2445,28 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
}
}
- /* There are P2 true significand bits, followed by one guard bit,
- followed by one sticky bit, followed by stuff. Fold nonzero
- stuff into the sticky bit. */
+ if (!fmt->round_towards_zero)
+ {
+ /* There are P2 true significand bits, followed by one guard bit,
+ followed by one sticky bit, followed by stuff. Fold nonzero
+ stuff into the sticky bit. */
+ unsigned long sticky;
+ bool guard, lsb;
+
+ sticky = 0;
+ for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
+ sticky |= r->sig[i];
+ sticky |= r->sig[w]
+ & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
- sticky = 0;
- for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
- sticky |= r->sig[i];
- sticky |=
- r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
+ guard = test_significand_bit (r, np2 - 1);
+ lsb = test_significand_bit (r, np2);
- guard = test_significand_bit (r, np2 - 1);
- lsb = test_significand_bit (r, np2);
+ /* Round to even. */
+ round_up = guard && (sticky || lsb);
+ }
- /* Round to even. */
- if (guard && (sticky || lsb))
+ if (round_up)
{
REAL_VALUE_TYPE u;
get_zero (&u, 0);
@@ -2756,6 +2806,7 @@ const struct real_format ieee_single_format =
128,
31,
31,
+ false,
true,
true,
true,
@@ -2775,6 +2826,7 @@ const struct real_format mips_single_format =
128,
31,
31,
+ false,
true,
true,
true,
@@ -2794,6 +2846,7 @@ const struct real_format motorola_single_format =
128,
31,
31,
+ false,
true,
true,
true,
@@ -2824,6 +2877,7 @@ const struct real_format spu_single_format =
129,
31,
31,
+ true,
false,
false,
true,
@@ -3031,6 +3085,7 @@ const struct real_format ieee_double_format =
1024,
63,
63,
+ false,
true,
true,
true,
@@ -3050,6 +3105,7 @@ const struct real_format mips_double_format =
1024,
63,
63,
+ false,
true,
true,
true,
@@ -3069,6 +3125,7 @@ const struct real_format motorola_double_format =
1024,
63,
63,
+ false,
true,
true,
true,
@@ -3406,6 +3463,7 @@ const struct real_format ieee_extended_motorola_format =
16384,
95,
95,
+ false,
true,
true,
true,
@@ -3425,6 +3483,7 @@ const struct real_format ieee_extended_intel_96_format =
16384,
79,
79,
+ false,
true,
true,
true,
@@ -3444,6 +3503,7 @@ const struct real_format ieee_extended_intel_128_format =
16384,
79,
79,
+ false,
true,
true,
true,
@@ -3465,6 +3525,7 @@ const struct real_format ieee_extended_intel_96_round_53_format =
16384,
79,
79,
+ false,
true,
true,
true,
@@ -3551,6 +3612,7 @@ const struct real_format ibm_extended_format =
1024,
127,
-1,
+ false,
true,
true,
true,
@@ -3570,6 +3632,7 @@ const struct real_format mips_extended_format =
1024,
127,
-1,
+ false,
true,
true,
true,
@@ -3831,6 +3894,7 @@ const struct real_format ieee_quad_format =
16384,
127,
127,
+ false,
true,
true,
true,
@@ -3850,6 +3914,7 @@ const struct real_format mips_quad_format =
16384,
127,
127,
+ false,
true,
true,
true,
@@ -4172,6 +4237,7 @@ const struct real_format vax_d_format =
false,
false,
false,
+ false,
false
};
@@ -4191,6 +4257,7 @@ const struct real_format vax_g_format =
false,
false,
false,
+ false,
false
};
@@ -4260,6 +4327,7 @@ const struct real_format decimal_single_format =
96,
31,
31,
+ false,
true,
true,
true,
@@ -4280,6 +4348,7 @@ const struct real_format decimal_double_format =
384,
63,
63,
+ false,
true,
true,
true,
@@ -4300,6 +4369,7 @@ const struct real_format decimal_quad_format =
6144,
127,
127,
+ false,
true,
true,
true,
@@ -4343,6 +4413,7 @@ const struct real_format real_internal_format =
MAX_EXP,
-1,
-1,
+ false,
true,
true,
false,
diff --git a/gcc/real.h b/gcc/real.h
index 2850c7a05e3..381ac5ef213 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -147,6 +147,9 @@ struct real_format
or -1 for a complex encoding. */
int signbit_rw;
+ /* Default rounding mode for operations on this format. */
+ bool round_towards_zero;
+
/* Properties of the format. */
bool has_nans;
bool has_inf;
@@ -216,6 +219,11 @@ extern bool exact_real_truncate (enum machine_mode, const REAL_VALUE_TYPE *);
extern void real_to_decimal (char *, const REAL_VALUE_TYPE *, size_t,
size_t, int);
+/* Render R as a decimal floating point constant, rounded so as to be
+ parsed back to the same value when interpreted in mode MODE. */
+extern void real_to_decimal_for_mode (char *, const REAL_VALUE_TYPE *, size_t,
+ size_t, int, enum machine_mode);
+
/* Render R as a hexadecimal floating point constant. */
extern void real_to_hexadecimal (char *, const REAL_VALUE_TYPE *,
size_t, size_t, int);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1d8a0750f45..206bdb6f6fc 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,16 @@
+2008-08-19 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ * gcc.c-torture/execute/20031003-1.c (main): Update test to
+ accommodate SPU single-precision rounding mode.
+ * gcc.c-torture/execute/conversion.c (test_float_to_integer,
+ test_float_to_longlong_integer): Likewise.
+ * gcc.c-torture/execute/ieee/rbug.c (main): Likewise.
+ * gcc.dg/hex-round-1.c: Skip test on SPU.
+ * gcc.dg/hex-round-2.c: Likewise.
+
+ * gcc.dg/torture/fp-int-convert-float.c: Reenable test on SPU.
+ * gcc.dg/torture/fp-int-convert-timode.c: Reenable "float" test on SPU.
+
2008-08-19 Jakub Jelinek <jakub@redhat.com>
PR debug/37156
diff --git a/gcc/testsuite/gcc.c-torture/execute/20031003-1.c b/gcc/testsuite/gcc.c-torture/execute/20031003-1.c
index 5d39d799e50..5d172e7e604 100644
--- a/gcc/testsuite/gcc.c-torture/execute/20031003-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/20031003-1.c
@@ -19,9 +19,15 @@ int main()
#if INT_MAX == 2147483647
if (f1() != 2147483647)
abort ();
+#ifdef __SPU__
+ /* SPU float rounds towards zero. */
+ if (f2() != 0x7fffff80)
+ abort ();
+#else
if (f2() != 2147483647)
abort ();
#endif
+#endif
return 0;
}
diff --git a/gcc/testsuite/gcc.c-torture/execute/conversion.c b/gcc/testsuite/gcc.c-torture/execute/conversion.c
index 9e62acfd2ad..82d681acfe6 100644
--- a/gcc/testsuite/gcc.c-torture/execute/conversion.c
+++ b/gcc/testsuite/gcc.c-torture/execute/conversion.c
@@ -284,9 +284,15 @@ test_float_to_integer()
abort();
if (f2u(1.99) != 1)
abort();
+#ifdef __SPU__
+ /* SPU float rounds towards zero. */
+ if (f2u((float) ((~0U) >> 1)) != 0x7fffff80)
+ abort();
+#else
if (f2u((float) ((~0U) >> 1)) != (~0U) >> 1 && /* 0x7fffffff */
f2u((float) ((~0U) >> 1)) != ((~0U) >> 1) + 1)
abort();
+#endif
if (f2u((float) ~((~0U) >> 1)) != ~((~0U) >> 1)) /* 0x80000000 */
abort();
@@ -439,9 +445,15 @@ test_float_to_longlong_integer()
abort();
if (f2ull(1.99) != 1LL)
abort();
+#ifdef __SPU__
+ /* SPU float rounds towards zero. */
+ if (f2ull((float) ((~0ULL) >> 1)) != 0x7fffff8000000000ULL)
+ abort();
+#else
if (f2ull((float) ((~0ULL) >> 1)) != (~0ULL) >> 1 && /* 0x7fffffff */
f2ull((float) ((~0ULL) >> 1)) != ((~0ULL) >> 1) + 1)
abort();
+#endif
if (f2ull((float) ~((~0ULL) >> 1)) != ~((~0ULL) >> 1)) /* 0x80000000 */
abort();
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c b/gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c
index ce13d7e9eed..1586bd7d43b 100644
--- a/gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c
@@ -41,8 +41,14 @@ main ()
k = 0x8234508000000001ULL;
x = s (k);
k = (unsigned long long) x;
+#ifdef __SPU__
+ /* SPU float rounds towards zero. */
+ if (k != 0x8234500000000000ULL)
+ abort ();
+#else
if (k != 0x8234510000000000ULL)
abort ();
+#endif
exit (0);
}
diff --git a/gcc/testsuite/gcc.dg/hex-round-1.c b/gcc/testsuite/gcc.dg/hex-round-1.c
index 3276ad46378..e1283cae37b 100644
--- a/gcc/testsuite/gcc.dg/hex-round-1.c
+++ b/gcc/testsuite/gcc.dg/hex-round-1.c
@@ -1,6 +1,7 @@
/* Test for hexadecimal float rounding: bug 21720. */
/* { dg-do link } */
/* { dg-options "-O -std=gnu99" } */
+/* { dg-skip-if "SPU float rounds towards zero" { spu-*-* } } */
#include <float.h>
diff --git a/gcc/testsuite/gcc.dg/hex-round-2.c b/gcc/testsuite/gcc.dg/hex-round-2.c
index ba9b8bf3d02..af49536abac 100644
--- a/gcc/testsuite/gcc.dg/hex-round-2.c
+++ b/gcc/testsuite/gcc.dg/hex-round-2.c
@@ -2,6 +2,7 @@
in number. */
/* { dg-do link } */
/* { dg-options "-O -std=gnu99" } */
+/* { dg-skip-if "SPU float rounds towards zero" { spu-*-* } } */
#include <float.h>
diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c
index 737282c275b..320544696e2 100644
--- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c
+++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c
@@ -3,7 +3,6 @@
/* Skipped for MIPS16 targets because of PR 35232 */
/* { dg-do run { target { { ! mips*-*-* } || nomips16 } } } */
/* { dg-options "" } */
-/* { dg-skip-if "Round to zero" { spu-*-* } } */
#include <float.h>
#include "fp-int-convert.h"
diff --git a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c
index faeae6050d1..2b27153044c 100644
--- a/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c
+++ b/gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c
@@ -9,10 +9,7 @@
int
main (void)
{
-#ifndef __SPU__
- /* Single-precision floating point on SPU always rounds to zero. */
TEST_I_F(TItype, UTItype, float, FLT_MANT_DIG);
-#endif
TEST_I_F(TItype, UTItype, double, DBL_MANT_DIG);
/* Disable the long double tests when using IBM Extended Doubles.
They have variable precision, but constants calculated by gcc's