diff options
author | Ulrich Weigand <uweigand@de.ibm.com> | 2008-08-19 16:37:13 +0000 |
---|---|---|
committer | Ulrich Weigand <uweigand@gcc.gnu.org> | 2008-08-19 16:37:13 +0000 |
commit | 38c29cbea3de335f5d0af1e2175285ab4c73815b (patch) | |
tree | c67fff0f7a950f385fe763c43912160fcfcd1aa9 | |
parent | 6157a1313a08463103b544ec8c6c3107b9bd2925 (diff) |
real.h (struct real_format): New member round_towards_zero.prereleases/gcc-4.3.2-rc1
ChangeLog:
* 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.
testsuite/ChangeLog:
* 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.
From-SVN: r139240
-rw-r--r-- | gcc/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/builtins.c | 42 | ||||
-rw-r--r-- | gcc/c-cppbuiltin.c | 5 | ||||
-rw-r--r-- | gcc/config/pdp11/pdp11.c | 2 | ||||
-rw-r--r-- | gcc/config/spu/float_disf.c | 30 | ||||
-rw-r--r-- | gcc/config/spu/float_unsdisf.c | 30 | ||||
-rw-r--r-- | gcc/config/spu/spu.md | 59 | ||||
-rw-r--r-- | gcc/config/spu/t-spu-elf | 7 | ||||
-rw-r--r-- | gcc/real.c | 119 | ||||
-rw-r--r-- | gcc/real.h | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/20031003-1.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/conversion.c | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/ieee/rbug.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/hex-round-1.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/hex-round-2.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/fp-int-convert-float.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/fp-int-convert-timode.c | 3 |
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 |