This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Support Cell SPU floating point
- From: trevor_smigiel at playstation dot sony dot com
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Cc: Andrew_Pinski at PlayStation dot Sony dot Com, Ulrich Weigand <uweigand at de dot ibm dot com>, Russell_Olsen at playstation dot sony dot com, Richard Guenther <richard dot guenther at gmail dot com>, Ian Lance Taylor <iant at google dot com>, Mark Mitchell <mark at codesourcery dot com>
- Date: Thu, 25 Oct 2007 11:15:14 -0700
- Subject: Re: [PATCH] Support Cell SPU floating point
- References: <20070829001149.GF1923@playstation.sony.com> <20070906192435.GT1923@playstation.sony.com>
Are there any further comments on this patch?
If not, is it ok for mainline?
Trevor
* Trevor Smigiel <Trevor_Smigiel@playstation.sony.com> [2007-09-06 12:24]:
> Here is a new version of the patch which addresses the issues raised.
> Changes from the previous patch are:
>
> - rename STANDARD_DENORMS to HONOR_NONIEEE_DENORMS
> - move checking of new macros (like DENORM_OPERANDS_ARE_ZERO) from
> const-fold.c and simplify-rtx.c to real.c, in the new routines
> real_arithmetic_fold, real_compare_fold, and real_convert_fold.
> - use a mode argument to ROUND_TOWARDS_ZERO instead of a size argument.
> - add FLO_mode to fp-bit.h
>
> Trevor
>
> in gcc/
>
> 2007-09-06 Trevor Smigiel <Trevor_Smigiel@playstation.sony.com>
>
> * doc/tm.texi (DENORM_OPERANDS_ARE_ZERO, DENORM_RESULTS_ARE_ZERO,
> ZERO_RESULTS_ARE_POSITVE, REAL_CONVERT_AS_IEEE): Document new macros.
> (ROUND_TOWARDS_ZERO): Document new mode argument.
> * flags.h (HONOR_NONIEEE_DENORMS): Define.
> * defaults.h (ROUND_TOWARDS_ZERO): Add size argument.
> (MODE_HAS_SIGN_DEPENDENT_ROUNDING): Pass size to ROUND_TOWARDS_ZERO.
> (DENORM_OPERANDS_ARE_ZERO, DENORM_RESULTS_ARE_ZERO,
> ZERO_RESULTS_ARE_POSITVE, REAL_CONVERT_AS_IEEE): Define.
> * fold-const.c (const_binop): Call real_arithmetic_fold.
> (fold_relational_const): Call real_compare_fold.
> (fold_convert_const_real_from_real): Call real_convert_fold.
> (fold_real_zero_addition_p): Return false when HONOR_NONIEEE_DENORMS
> is true.
> (fold_binary): Don't allow certain optimizations when
> HONOR_NONIEEE_DENORMS is true.
> * real.c (real_is_denorm, real_convert_ieee, real_arithmetic_fold,
> real_compare_fold, real_convert_fold): Define.
> (round_for_format): Handle round_towards_zero field.
> (ieee_single_format, mips_single_format, motorola_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, decimal_single_format,
> decimal_double_format, decimal_quad_format, c4x_single_format,
> c4x_extended_format, real_internal_format): Initialize
> round_towards_zero field.
> (spu_extended_format): Define new real format.
> * real.h (real_format): Add round_towards_zero field.
> (real_arithmetic_fold, real_compare_fold, real_convert_fold,
> spu_extended_format): Declare.
> * simplify-rtx.c (simplify_const_unary_operation): Call
> real_convert_fold for FLOAT_EXTEND when REAL_CONVERT_AS_IEEE is
> true.
> (simplify_binary_operation_1): Don't allow certain optimizations when
> HONOR_NONIEEE_DENORMS is true.
> (simplify_const_binary_operation): Call real_arithmetic_fold.
> (simplify_const_relational_operation): Call real_compare_fold.
> * c-common.c (c_common_truthvalue_conversion): Call real_compare_fold.
> * config/spu/spu.c (spu_override_options): Initialize
> REAL_MODE_FORMAT for SFmode.
> * config/spu/spu.h (ROUND_TOWARDS_ZERO, DENORM_OPERANDS_ARE_ZERO,
> DENORM_RESULTS_ARE_ZERO, ZERO_RESULTS_ARE_POSITVE,
> REAL_CONVERT_AS_IEEE, LARGEST_EXPONENT_IS_NORMAL): Define.
> (MODE_HAS_NANS, MODE_HAS_INFINITIES,
> MODE_HAS_SIGN_DEPENDENT_ROUNDING): Delete.
> * config/fp-bit.h (FLO_mode): Define.
> * config/fp-bit.c: Include insn-modes.h.
> (pack_d, _fpmul_parts, _fpdiv_parts): Pass FLO_mode as argument to
> ROUND_TOWARDS_ZERO.
>
> in gcc/testsuite/
>
> 2007-09-06 Trevor Smigiel <Trevor_Smigiel@playstation.sony.com>
> * gcc.c-torture/execute/ieee/fold.c: Add.
>
> * Trevor Smigiel <Trevor_Smigiel@playstation.sony.com> [2007-08-28 17:11]:
> > This patch does three things:
> >
> > 1) Add Cell SPU extended single precision format to real.c
> > 2) Define macros for constant folding of denormalized numbers
> > 3) Define macros to prevent certain optimizations on denorms
> >
> > The latter 2 parts are necessary to get proper constant folding and
> > optimization on SPU which does not fully support IEEE floats. A comment
> > in real.c describes the differences:
> >
> > /* 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)
> >
> > SPU Double Precision format is the same as IEEE with the following
> > differences:
> > - denorms can be generated as a result, but are treated as zero
> > when used as an operand
> >
> > When converting between float and double, Infinity and NaN patterns
> > are honored. For example, 0x7f800000 will convert to
> > 0x7ff0000000000000, not 0x47f0000000000000; and 0x7ff0000000000000
> > converts to 0x7f800000, not 0x7fffffff. */
> >
> > A couple of debatable choices are: (of course, it is all debatable)
> >
> > - the name STANDARD_DENORM. Its purpose is to prevent optimization,
> > perhaps it would be better named as SAFE_FOR_DENORM, as in "this
> > optimization is safe even if an operand is a denorm." There could be a
> > similar macro for negative zero, but handling denorms handles all the -0
> > cases too. In fact, our internal implementation uses only
> > SAFE_FOR_MINUS_ZERO.
> >
> > - converting denorms to zero in const-fold.c and simplify-rtx.c. It
> > could be done in real.c as part of the format. The arithmetic in real.c
> > is modeless, and I didn't think it was appropriate to add mode arguments
> > to most of the functions or to the REAL_VALUE structure. Compiler
> > internal computations might not want real.c to operate in a format
> > specific manner. The advantage of doing it in real.c is that it is
> > only done in one place. In our internal implementation, we did pass a
> > mode argument to most functions in real.c.
> >
> > The patch was bootstrapped on x86 by Andrew and had no new failures.
> >
> > The testsuite results on SPU do change quite a bit, as expected. Some
> > failures become passes, and some passes become failures. These do need
> > to be handled, and I hope to get some help doing so after the basic
> > patch is accepted.
> >
> > Trevor
> >
> Index: gcc/doc/tm.texi
> ===================================================================
> *** gcc/doc/tm.texi (revision 128153)
> --- gcc/doc/tm.texi (working copy)
> *************** The default definition of this macro is
> *** 1423,1435 ****
> a floating-point mode and the target format is IEEE@.
> @end defmac
>
> ! @defmac ROUND_TOWARDS_ZERO
> ! If defined, this macro should be true if the prevailing rounding
> ! mode is towards zero. A true value has the following effects:
>
> @itemize @bullet
> @item
> ! @code{MODE_HAS_SIGN_DEPENDENT_ROUNDING} will be false for all modes.
>
> @item
> @file{libgcc.a}'s floating-point emulator will round towards zero
> --- 1423,1468 ----
> a floating-point mode and the target format is IEEE@.
> @end defmac
>
> ! @defmac DENORM_OPERANDS_ARE_ZERO (@var{mode})
> ! If defined, this macro should be true for @var{mode} if a denormalized
> ! number should be converted to zero before constant folding an operation.
> !
> ! The default definition of this macro is false for all modes.
> ! @end defmac
> !
> ! @defmac DENORM_RESULTS_ARE_ZERO (@var{mode})
> ! If defined, this macro should be true for @var{mode} if the results of
> ! a constant folded operation is a denormalized number which should be
> ! converted to zero.
> !
> ! The default definition of this macro is false for all modes.
> ! @end defmac
> !
> ! @defmac ZERO_RESULTS_ARE_POSITVE (@var{mode})
> ! If defined, this macro should be true for @var{mode} if the results of a
> ! constant folded operation is negative zero and should be converted to
> ! positive zero.
> !
> ! The default definition of this macro is false for all modes.
> ! @end defmac
> !
> ! @defmac REAL_CONVERT_AS_IEEE (@var{to_mode}, @var{from_mode})
> ! If defined, this macro should be true for @var{to_mode} and
> ! @var{from_mode} if a conversion between the two modes should be done as
> ! if the target format for the modes were IEEE.
> !
> ! The default definition of this macro is false for all modes.
> ! @end defmac
> !
> ! @defmac ROUND_TOWARDS_ZERO (@var{mode})
> ! If defined, this macro should be true for @var{mode} if the rounding
> ! mode should be round towards zero. A true value for @var{mode} has the
> ! following effects:
>
> @itemize @bullet
> @item
> ! @code{MODE_HAS_SIGN_DEPENDENT_ROUNDING} will be false for
> ! @var{mode}.
>
> @item
> @file{libgcc.a}'s floating-point emulator will round towards zero
> Index: gcc/flags.h
> ===================================================================
> *** gcc/flags.h (revision 128153)
> --- gcc/flags.h (working copy)
> *************** extern bool flag_instrument_functions_ex
> *** 311,316 ****
> --- 311,320 ----
> #define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \
> (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && flag_rounding_math)
>
> + /* True when the given mode fully supports denormalized numbers. */
> + #define HONOR_NONIEEE_DENORMS(MODE) \
> + (!DENORM_OPERANDS_ARE_ZERO (MODE) && !DENORM_RESULTS_ARE_ZERO (MODE))
> +
> /* True if overflow wraps around for the given integral type. That
> is, TYPE_MAX + 1 == TYPE_MIN. */
> #define TYPE_OVERFLOW_WRAPS(TYPE) \
> Index: gcc/defaults.h
> ===================================================================
> *** gcc/defaults.h (revision 128153)
> --- gcc/defaults.h (working copy)
> *************** along with GCC; see the file COPYING3.
> *** 666,672 ****
> #endif
>
> #ifndef ROUND_TOWARDS_ZERO
> ! #define ROUND_TOWARDS_ZERO 0
> #endif
>
> #ifndef MODE_HAS_NANS
> --- 666,688 ----
> #endif
>
> #ifndef ROUND_TOWARDS_ZERO
> ! #define ROUND_TOWARDS_ZERO(MODE) 0
> ! #endif
> !
> ! #ifndef DENORM_OPERANDS_ARE_ZERO
> ! #define DENORM_OPERANDS_ARE_ZERO(MODE) 0
> ! #endif
> !
> ! #ifndef DENORM_RESULTS_ARE_ZERO
> ! #define DENORM_RESULTS_ARE_ZERO(MODE) 0
> ! #endif
> !
> ! #ifndef ZERO_RESULTS_ARE_POSITIVE
> ! #define ZERO_RESULTS_ARE_POSITIVE(MODE) 0
> ! #endif
> !
> ! #ifndef REAL_CONVERT_AS_IEEE
> ! #define REAL_CONVERT_AS_IEEE(TO_MODE,FROM_MODE) 0
> #endif
>
> #ifndef MODE_HAS_NANS
> *************** along with GCC; see the file COPYING3.
> *** 692,698 ****
> #define MODE_HAS_SIGN_DEPENDENT_ROUNDING(MODE) \
> (FLOAT_MODE_P (MODE) \
> && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT \
> ! && !ROUND_TOWARDS_ZERO)
> #endif
>
> #ifndef FLOAT_LIB_COMPARE_RETURNS_BOOL
> --- 708,714 ----
> #define MODE_HAS_SIGN_DEPENDENT_ROUNDING(MODE) \
> (FLOAT_MODE_P (MODE) \
> && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT \
> ! && !ROUND_TOWARDS_ZERO (MODE))
> #endif
>
> #ifndef FLOAT_LIB_COMPARE_RETURNS_BOOL
> Index: gcc/builtins.c
> ===================================================================
> *** gcc/builtins.c (revision 128153)
> --- gcc/builtins.c (working copy)
> *************** fold_builtin_abs (tree arg, tree type)
> *** 9291,9297 ****
> static tree
> fold_builtin_fmin_fmax (tree arg0, tree arg1, tree type, bool max)
> {
> ! if (validate_arg (arg0, REAL_TYPE) && validate_arg (arg1, REAL_TYPE))
> {
> /* Calculate the result when the argument is a constant. */
> tree res = do_mpfr_arg2 (arg0, arg1, type, (max ? mpfr_max : mpfr_min));
> --- 9291,9298 ----
> static tree
> fold_builtin_fmin_fmax (tree arg0, tree arg1, tree type, bool max)
> {
> ! if (validate_arg (arg0, REAL_TYPE) && validate_arg (arg1, REAL_TYPE)
> ! && !HONOR_NONIEEE_DENORMS (TYPE_MODE (type)))
> {
> /* Calculate the result when the argument is a constant. */
> tree res = do_mpfr_arg2 (arg0, arg1, type, (max ? mpfr_max : mpfr_min));
> Index: gcc/fold-const.c
> ===================================================================
> *** gcc/fold-const.c (revision 128153)
> --- gcc/fold-const.c (working copy)
> *************** const_binop (enum tree_code code, tree a
> *** 1868,1874 ****
> else if (REAL_VALUE_ISNAN (d2))
> return arg2;
>
> ! inexact = real_arithmetic (&value, code, &d1, &d2);
> real_convert (&result, mode, &value);
>
> /* Don't constant fold this floating point operation if
> --- 1868,1874 ----
> else if (REAL_VALUE_ISNAN (d2))
> return arg2;
>
> ! inexact = real_arithmetic_fold (&value, code, &d1, &d2, mode);
> real_convert (&result, mode, &value);
>
> /* Don't constant fold this floating point operation if
> *************** fold_convert_const_real_from_real (tree
> *** 2271,2277 ****
> REAL_VALUE_TYPE value;
> tree t;
>
> ! real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
> t = build_real (type, value);
>
> TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
> --- 2271,2278 ----
> REAL_VALUE_TYPE value;
> tree t;
>
> ! real_convert_fold (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1),
> ! TYPE_MODE (TREE_TYPE (arg1)));
> t = build_real (type, value);
>
> TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
> *************** fold_real_zero_addition_p (const_tree ty
> *** 6476,6481 ****
> --- 6477,6486 ----
> if (!real_zerop (addend))
> return false;
>
> + /* Don't allow the fold with non-standard denorms. */
> + if (HONOR_NONIEEE_DENORMS (TYPE_MODE (type)))
> + return false;
> +
> /* Don't allow the fold with -fsignaling-nans. */
> if (HONOR_SNANS (TYPE_MODE (type)))
> return false;
> *************** fold_binary (enum tree_code code, tree t
> *** 10296,10306 ****
> --- 10301,10313 ----
> return omit_one_operand (type, arg1, arg0);
> /* In IEEE floating point, x*1 is not equivalent to x for snans. */
> if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
> + && !HONOR_NONIEEE_DENORMS (TYPE_MODE (TREE_TYPE (arg0)))
> && real_onep (arg1))
> return non_lvalue (fold_convert (type, arg0));
>
> /* Transform x * -1.0 into -x. */
> if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
> + && !HONOR_NONIEEE_DENORMS (TYPE_MODE (TREE_TYPE (arg0)))
> && real_minus_onep (arg1))
> return fold_convert (type, negate_expr (arg0));
>
> *************** fold_binary (enum tree_code code, tree t
> *** 10928,10933 ****
> --- 10935,10941 ----
> if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg0))
> && ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
> && ! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg0)))
> + && ! HONOR_NONIEEE_DENORMS (TYPE_MODE (TREE_TYPE (arg0)))
> && operand_equal_p (arg0, arg1, 0))
> {
> tree r = build_real (TREE_TYPE (arg0), dconst1);
> *************** fold_binary (enum tree_code code, tree t
> *** 10961,10971 ****
> --- 10969,10981 ----
>
> /* In IEEE floating point, x/1 is not equivalent to x for snans. */
> if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
> + && !HONOR_NONIEEE_DENORMS (TYPE_MODE (TREE_TYPE (arg0)))
> && real_onep (arg1))
> return non_lvalue (fold_convert (type, arg0));
>
> /* In IEEE floating point, x/-1 is not equivalent to -x for snans. */
> if (!HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
> + && !HONOR_NONIEEE_DENORMS (TYPE_MODE (TREE_TYPE (arg0)))
> && real_minus_onep (arg1))
> return non_lvalue (fold_convert (type, negate_expr (arg0)));
>
> *************** fold_relational_const (enum tree_code co
> *** 14561,14566 ****
> --- 14571,14577 ----
>
> if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST)
> {
> + bool result;
> const REAL_VALUE_TYPE *c0 = TREE_REAL_CST_PTR (op0);
> const REAL_VALUE_TYPE *c1 = TREE_REAL_CST_PTR (op1);
>
> *************** fold_relational_const (enum tree_code co
> *** 14601,14607 ****
> return constant_boolean_node (result, type);
> }
>
> ! return constant_boolean_node (real_compare (code, c0, c1), type);
> }
>
> if (TREE_CODE (op0) == FIXED_CST && TREE_CODE (op1) == FIXED_CST)
> --- 14612,14619 ----
> return constant_boolean_node (result, type);
> }
>
> ! result = real_compare_fold (code, c0, c1, TYPE_MODE (TREE_TYPE (op0)));
> ! return constant_boolean_node (result, type);
> }
>
> if (TREE_CODE (op0) == FIXED_CST && TREE_CODE (op1) == FIXED_CST)
> Index: gcc/real.c
> ===================================================================
> *** gcc/real.c (revision 128153)
> --- gcc/real.c (working copy)
> *************** static bool do_divide (REAL_VALUE_TYPE *
> *** 109,114 ****
> --- 109,116 ----
> 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 bool real_isdenorm (enum machine_mode, const REAL_VALUE_TYPE *);
> +
> static unsigned long rtd_divmod (REAL_VALUE_TYPE *, REAL_VALUE_TYPE *);
>
> static const REAL_VALUE_TYPE * ten_to_ptwo (int);
> *************** real_arithmetic (REAL_VALUE_TYPE *r, int
> *** 1046,1051 ****
> --- 1048,1079 ----
> return false;
> }
>
> + bool
> + real_arithmetic_fold (REAL_VALUE_TYPE *r, int icode,
> + const REAL_VALUE_TYPE *op0, const REAL_VALUE_TYPE *op1,
> + enum machine_mode mode)
> + {
> + bool inexact;
> +
> + /* Some formats accept denorms but treat them as zero. */
> + if (DENORM_OPERANDS_ARE_ZERO (mode))
> + {
> + if (real_isdenorm (mode, op0))
> + op0 = &dconst0;
> + if (real_isdenorm (mode, op1))
> + op1 = &dconst0;
> + }
> +
> + inexact = real_arithmetic (r, icode, op0, op1);
> +
> + /* Some formats always generate +0.0 for denorms and -0.0. */
> + if ((DENORM_RESULTS_ARE_ZERO (mode) && real_isdenorm (mode, r))
> + || (ZERO_RESULTS_ARE_POSITIVE (mode) && real_isnegzero (r)))
> + *r = dconst0;
> +
> + return inexact;
> + }
> +
> /* Legacy. Similar, but return the result directly. */
>
> REAL_VALUE_TYPE
> *************** real_compare (int icode, const REAL_VALU
> *** 1099,1104 ****
> --- 1127,1148 ----
> }
> }
>
> + bool
> + real_compare_fold (int icode, const REAL_VALUE_TYPE *op0,
> + const REAL_VALUE_TYPE *op1, enum machine_mode mode)
> + {
> + /* Some formats accept denorms but treat them as zero. */
> + if (DENORM_OPERANDS_ARE_ZERO (mode))
> + {
> + if (real_isdenorm (mode, op0))
> + op0 = &dconst0;
> + if (real_isdenorm (mode, op1))
> + op1 = &dconst0;
> + }
> +
> + return real_compare (icode, op0, op1);
> + }
> +
> /* Return floor log2(R). */
>
> int
> *************** real_isnegzero (const REAL_VALUE_TYPE *r
> *** 1186,1191 ****
> --- 1230,1244 ----
> return r->sign && r->cl == rvc_zero;
> }
>
> + /* Determine whether a floating-point value X is a denorm for MODE. */
> +
> + static bool
> + real_isdenorm (enum machine_mode mode, const REAL_VALUE_TYPE * r)
> + {
> + const struct real_format *fmt = REAL_MODE_FORMAT (mode);
> + return fmt->has_denorm && r->cl == rvc_normal && REAL_EXP (r) < fmt->emin;
> + }
> +
> /* Compare two floating-point objects for bitwise identity. */
>
> bool
> *************** round_for_format (const struct real_form
> *** 2400,2440 ****
> }
> }
>
> ! /* 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. */
> !
> ! 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. */
> ! if (guard && (sticky || lsb))
> ! {
> ! REAL_VALUE_TYPE u;
> ! get_zero (&u, 0);
> ! set_significand_bit (&u, np2);
>
> ! if (add_significands (r, r, &u))
> {
> ! /* 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;
> }
> - }
>
> ! /* Catch underflow that we deferred until after rounding. */
> ! if (REAL_EXP (r) <= emin2m1)
> ! goto underflow;
>
> /* Clear out trailing garbage. */
> clear_significand_below (r, np2);
> --- 2453,2499 ----
> }
> }
>
> ! 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. */
> !
> ! 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. */
> ! if (guard && (sticky || lsb))
> {
> ! REAL_VALUE_TYPE u;
> ! get_zero (&u, 0);
> ! set_significand_bit (&u, np2);
> !
> ! if (add_significands (r, r, &u))
> ! {
> ! /* 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;
> ! }
> }
>
> ! /* Catch underflow that we deferred until after rounding. */
> ! if (REAL_EXP (r) <= emin2m1)
> ! goto underflow;
> !
> ! }
>
> /* Clear out trailing garbage. */
> clear_significand_below (r, np2);
> *************** real_convert (REAL_VALUE_TYPE *r, enum m
> *** 2463,2468 ****
> --- 2522,2588 ----
> normalize (r);
> }
>
> + /* Do a real conversion as if A and R were IEEE numbers. The result is
> + returned as a native number. For example, the bit representation of
> + an IEEE infinity might be a normal number in the native format. In
> + that case the result is a REAL_VALUE_TYPE that corresponds to the
> + native value. */
> + static void
> + real_convert_ieee (REAL_VALUE_TYPE * r, enum machine_mode mode,
> + const REAL_VALUE_TYPE * a, enum machine_mode fmode)
> + {
> + long buf[6];
> + const struct real_format *fmt;
> + const struct real_format *from_fmt;
> + const struct real_format *ieee_fmt;
> +
> + fmt = REAL_MODE_FORMAT (mode);
> + from_fmt = REAL_MODE_FORMAT (fmode);
> + gcc_assert (fmt && from_fmt);
> +
> + *r = *a;
> +
> + ieee_fmt = (fmode == SFmode) ? &ieee_single_format : &ieee_double_format;
> +
> + /* Convert to an IEEE representation. */
> + if (from_fmt != ieee_fmt)
> + {
> + from_fmt->encode (from_fmt, buf, r);
> + ieee_fmt->decode (ieee_fmt, r, buf);
> + }
> +
> + /* Do the conversion as IEEE. */
> + ieee_fmt = (mode == SFmode) ? &ieee_single_format : &ieee_double_format;
> + round_for_format (ieee_fmt, r);
> + if (r->cl == rvc_normal)
> + normalize (r);
> +
> + /* Convert to native representation. */
> + if (fmt != ieee_fmt)
> + {
> + ieee_fmt->encode (ieee_fmt, buf, r);
> + fmt->decode (fmt, r, buf);
> + }
> + }
> +
> + void
> + real_convert_fold (REAL_VALUE_TYPE *r, enum machine_mode to_mode,
> + const REAL_VALUE_TYPE *a, enum machine_mode from_mode)
> + {
> + if (DENORM_OPERANDS_ARE_ZERO (from_mode) && real_isdenorm (from_mode, r))
> + a = &dconst0;
> +
> + /* Even though the native format does not represent IEEE exactly,
> + treat the bit representation as if it were IEEE when converting. */
> + if (REAL_CONVERT_AS_IEEE (to_mode, from_mode))
> + real_convert_ieee (r, to_mode, a, from_mode);
> + else
> + real_convert (r, to_mode, a);
> +
> + if (DENORM_RESULTS_ARE_ZERO (to_mode) && real_isdenorm (to_mode, r))
> + *r = dconst0;
> + }
> +
> /* Legacy. Likewise, except return the struct directly. */
>
> REAL_VALUE_TYPE
> *************** const struct real_format ieee_single_for
> *** 2759,2764 ****
> --- 2879,2885 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format mips_single_for
> *** 2778,2784 ****
> true,
> true,
> false,
> ! true
> };
>
> const struct real_format motorola_single_format =
> --- 2899,2906 ----
> true,
> true,
> false,
> ! true,
> ! false
> };
>
> const struct real_format motorola_single_format =
> *************** const struct real_format motorola_single
> *** 2797,2803 ****
> true,
> true,
> true,
> ! true
> };
>
> /* IEEE double-precision format. */
> --- 2919,2926 ----
> true,
> true,
> true,
> ! true,
> ! false
> };
>
> /* IEEE double-precision format. */
> *************** const struct real_format ieee_double_for
> *** 3004,3009 ****
> --- 3127,3133 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format mips_double_for
> *** 3023,3029 ****
> true,
> true,
> false,
> ! true
> };
>
> const struct real_format motorola_double_format =
> --- 3147,3154 ----
> true,
> true,
> false,
> ! true,
> ! false
> };
>
> const struct real_format motorola_double_format =
> *************** const struct real_format motorola_double
> *** 3042,3048 ****
> true,
> true,
> true,
> ! true
> };
>
> /* IEEE extended real format. This comes in three flavors: Intel's as
> --- 3167,3174 ----
> true,
> true,
> true,
> ! true,
> ! false
> };
>
> /* IEEE extended real format. This comes in three flavors: Intel's as
> *************** const struct real_format ieee_extended_m
> *** 3379,3385 ****
> true,
> true,
> true,
> ! true
> };
>
> const struct real_format ieee_extended_intel_96_format =
> --- 3505,3512 ----
> true,
> true,
> true,
> ! true,
> ! false
> };
>
> const struct real_format ieee_extended_intel_96_format =
> *************** const struct real_format ieee_extended_i
> *** 3398,3403 ****
> --- 3525,3531 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format ieee_extended_i
> *** 3417,3422 ****
> --- 3545,3551 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format ieee_extended_i
> *** 3438,3443 ****
> --- 3567,3573 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format ibm_extended_fo
> *** 3524,3529 ****
> --- 3654,3660 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format mips_extended_f
> *** 3543,3549 ****
> true,
> true,
> false,
> ! true
> };
>
>
> --- 3674,3681 ----
> true,
> true,
> false,
> ! true,
> ! false
> };
>
>
> *************** const struct real_format ieee_quad_forma
> *** 3804,3809 ****
> --- 3936,3942 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format mips_quad_forma
> *** 3823,3829 ****
> true,
> true,
> false,
> ! true
> };
>
> /* Descriptions of VAX floating point formats can be found beginning at
> --- 3956,3963 ----
> true,
> true,
> false,
> ! true,
> ! false
> };
>
> /* Descriptions of VAX floating point formats can be found beginning at
> *************** const struct real_format vax_f_format =
> *** 4121,4126 ****
> --- 4255,4261 ----
> false,
> false,
> false,
> + false,
> false
> };
>
> *************** const struct real_format vax_d_format =
> *** 4140,4145 ****
> --- 4275,4281 ----
> false,
> false,
> false,
> + false,
> false
> };
>
> *************** const struct real_format vax_g_format =
> *** 4159,4164 ****
> --- 4295,4301 ----
> false,
> false,
> false,
> + false,
> false
> };
>
> *************** const struct real_format decimal_single_
> *** 4233,4238 ****
> --- 4370,4376 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format decimal_double_
> *** 4253,4258 ****
> --- 4391,4397 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format decimal_quad_fo
> *** 4273,4278 ****
> --- 4412,4418 ----
> true,
> true,
> true,
> + false,
> false
> };
>
> *************** const struct real_format c4x_single_form
> *** 4482,4487 ****
> --- 4622,4628 ----
> false,
> false,
> false,
> + false,
> false
> };
>
> *************** const struct real_format c4x_extended_fo
> *** 4501,4510 ****
> --- 4642,4693 ----
> false,
> false,
> false,
> + false,
> false
> };
>
>
> + /* 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)
> +
> + SPU Double Precision format is the same as IEEE with the following
> + differences:
> + - denorms can be generated as a result, but are treated as zero
> + when used as an operand
> +
> + When converting between float and double, Infinity and NaN patterns
> + are honored. For example, 0x7f800000 will convert to
> + 0x7ff0000000000000, not 0x47f0000000000000; and 0x7ff0000000000000
> + converts to 0x7f800000, not 0x7fffffff. */
> + const struct real_format spu_extended_format =
> + {
> + encode_ieee_single,
> + decode_ieee_single,
> + 2,
> + 24,
> + 24,
> + -125,
> + 129,
> + 31,
> + 31,
> + false,
> + false,
> + true,
> + true,
> + false,
> + false,
> + true,
> + };
> +
> /* 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
> *************** const struct real_format real_internal_f
> *** 4545,4550 ****
> --- 4728,4734 ----
> false,
> true,
> true,
> + false,
> false
> };
>
> Index: gcc/real.h
> ===================================================================
> *** gcc/real.h (revision 128153)
> --- gcc/real.h (working copy)
> *************** struct real_format
> *** 152,157 ****
> --- 152,158 ----
> bool has_signed_zero;
> bool qnan_msb_set;
> bool canonical_nan_lsbs_set;
> + bool round_towards_zero;
> };
>
>
> *************** extern const struct real_format *
> *** 182,190 ****
> --- 183,199 ----
> extern bool real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
> const REAL_VALUE_TYPE *);
>
> + /* Binary or unary arithmetic on tree_code when folding. */
> + extern bool real_arithmetic_fold (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
> + const REAL_VALUE_TYPE *, enum machine_mode);
> +
> /* Compare reals by tree_code. */
> extern bool real_compare (int, const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
>
> + /* Compare reals by tree_code when folding */
> + extern bool real_compare_fold (int, const REAL_VALUE_TYPE *,
> + const REAL_VALUE_TYPE *, enum machine_mode);
> +
> /* Determine whether a floating-point value X is infinite. */
> extern bool real_isinf (const REAL_VALUE_TYPE *);
>
> *************** extern bool real_identical (const REAL_V
> *** 207,212 ****
> --- 216,225 ----
> extern void real_convert (REAL_VALUE_TYPE *, enum machine_mode,
> const REAL_VALUE_TYPE *);
>
> + /* Extend or truncate to a new mode when folding. */
> + extern void real_convert_fold (REAL_VALUE_TYPE *, enum machine_mode,
> + const REAL_VALUE_TYPE *, enum machine_mode);
> +
> /* Return true if truncating to NEW is exact. */
> extern bool exact_real_truncate (enum machine_mode, const REAL_VALUE_TYPE *);
>
> *************** extern const struct real_format vax_d_fo
> *** 273,278 ****
> --- 286,292 ----
> extern const struct real_format vax_g_format;
> extern const struct real_format c4x_single_format;
> extern const struct real_format c4x_extended_format;
> + extern const struct real_format spu_extended_format;
> extern const struct real_format real_internal_format;
> extern const struct real_format decimal_single_format;
> extern const struct real_format decimal_double_format;
> Index: gcc/testsuite/gcc.c-torture/execute/ieee/fold.c
> ===================================================================
> *** gcc/testsuite/gcc.c-torture/execute/ieee/fold.c (revision 0)
> --- gcc/testsuite/gcc.c-torture/execute/ieee/fold.c (revision 0)
> ***************
> *** 0 ****
> --- 1,201 ----
> + /* Test that a folded operation computes the same value as a non-folded
> + operation. Specifically with values that are denorms.
> + The constants used are valid for IEEE formats. */
> +
> + #include <stdio.h>
> + extern void abort(void);
> + extern void exit(int);
> +
> +
> + union u {
> + float f;
> + unsigned int i;
> + double d;
> + unsigned long long l;
> + };
> +
> + static const double d_smallest_norm = 0x1p-1022;
> + static const double d_max_denorm = 0x0.8p-1022;
> + static const double d_smallest_denorm = 0x0.0000000000001p-1022;
> +
> + static const float smallest_norm = 1.1754943508222875079687365372222456778186655567720875215087517062784172594547271728515625e-38f;
> + static const float max_denorm = 5.8774717541114375398436826861112283890933277838604376075437585313920862972736358642578125e-39f;
> + static const float smallest_denorm = 1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45f;
> +
> + static const double pinfd = +1.0 / 0.0;
> + static const double pinf = +1.0 / 0.0;
> +
> + volatile union u a, b;
> +
> + int failed;
> +
> + #define TEST_OP(A,B,OP) \
> + do { \
> + union u u, v; \
> + a.f = A; \
> + b.f = B; \
> + u.f = A OP B; \
> + v.f = a.f OP b.f; \
> + if (u.i != v.i) \
> + { \
> + printf( #A #OP #B " = %08x " #OP " %08x = const %08x = volatile %08x\n", a.i, b.i, u.i, v.i ); \
> + failed++; \
> + } \
> + } while (0);
> +
> + #define TEST_OPD(A,B,OP) \
> + do { \
> + union u u, v; \
> + a.d = A; \
> + b.d = B; \
> + u.d = A OP B; \
> + v.d = a.d OP b.d; \
> + if (u.l != v.l) \
> + { \
> + printf( #A #OP #B " = %016llx " #OP " %016llx = const %016llx = volatile %016llx\n", a.l, b.l, u.l, v.l ); \
> + failed++; \
> + } \
> + } while (0);
> +
> + #define TEST_FTOD(A) \
> + do { \
> + union u u, v; \
> + a.f = A; \
> + u.d = A; \
> + v.d = a.f; \
> + if (u.l != v.l) \
> + { \
> + printf( "(double)" #A " = %08x = const %016llx = volatile %016llx\n", a.i, u.l, v.l ); \
> + failed++; \
> + } \
> + } while (0);
> +
> + #define TEST_DTOF(A) \
> + do { \
> + union u u, v; \
> + a.d = A; \
> + u.f = A; \
> + v.f = a.d; \
> + if (u.i != v.i) \
> + { \
> + printf( "(float)" #A " = %016llx = const %08x = volatile %08x\n", a.l, u.i, v.i ); \
> + failed++; \
> + } \
> + } while (0);
> +
> + #define TEST_FUNC(A,OP) \
> + do { \
> + union u u, v; \
> + a.f = A; \
> + u.f = OP (A); \
> + v.f = OP (a.f); \
> + if (u.i != v.i) \
> + { \
> + printf( #OP "(" #A ") = " #OP " (%08x) = const %08x = volatile %08x\n", a.i, u.i, v.i ); \
> + failed++; \
> + } \
> + } while (0);
> +
> + int
> + main()
> + {
> + union u u;
> + /* Check constant strings are represented exactly. */
> + u.f = smallest_norm;
> + if (u.i != 0x00800000)
> + {
> + printf("00800000 %08x\n", u.i);
> + failed++;
> + }
> + u.f = max_denorm;
> + if (u.i != 0x00400000)
> + {
> + printf("00400000 %08x\n", u.i);
> + failed++;
> + }
> + u.f = smallest_denorm;
> + if (u.i != 0x00000001)
> + {
> + printf("00000001 %08x\n", u.i);
> + failed++;
> + }
> +
> + TEST_OP(smallest_denorm, max_denorm, +);
> + TEST_OP(smallest_norm, max_denorm, +);
> + TEST_OP(smallest_norm, smallest_denorm, +);
> +
> + TEST_OP(max_denorm, 2.0f, *);
> + TEST_OP(max_denorm, 0.25f, *);
> + TEST_OP(smallest_norm, 2.0f, *);
> + TEST_OP(smallest_norm, 0.25f, *);
> +
> + TEST_OP(max_denorm, 4.0f, /);
> + TEST_OP(max_denorm, 0.5f, /);
> + TEST_OP(smallest_norm, 4.0f, /);
> +
> + TEST_OP(smallest_norm, 0.5f, /);
> +
> + TEST_OP(smallest_denorm, max_denorm, <);
> + TEST_OP(smallest_norm, max_denorm, <);
> + TEST_OP(smallest_norm, smallest_denorm, <);
> + TEST_OP(smallest_denorm, max_denorm, >);
> + TEST_OP(smallest_norm, max_denorm, >);
> + TEST_OP(smallest_norm, smallest_denorm, >);
> + TEST_OP(smallest_denorm, max_denorm, ==);
> + TEST_OP(smallest_norm, max_denorm, ==);
> + TEST_OP(smallest_norm, smallest_denorm, ==);
> +
> + TEST_OP(pinf, pinf, !=);
> + TEST_OP(pinf, pinf, ==);
> +
> + TEST_OPD(d_smallest_denorm, d_max_denorm, +);
> + TEST_OPD(d_smallest_norm, d_max_denorm, +);
> + TEST_OPD(d_smallest_norm, d_smallest_denorm, +);
> +
> + TEST_OPD(d_max_denorm, 2.0, *);
> + TEST_OPD(d_max_denorm, 0.25, *);
> + TEST_OPD(d_smallest_norm, 2.0, *);
> + TEST_OPD(d_smallest_norm, 0.25, *);
> +
> + TEST_OPD(d_max_denorm, 4.0, /);
> + TEST_OPD(d_max_denorm, 0.5, /);
> + TEST_OPD(d_smallest_norm, 4.0, /);
> +
> + TEST_OPD(d_smallest_norm, 0.5, /);
> +
> + TEST_OPD(d_smallest_denorm, d_max_denorm, <);
> + TEST_OPD(d_smallest_norm, d_max_denorm, <);
> + TEST_OPD(d_smallest_norm, d_smallest_denorm, <);
> + TEST_OPD(d_smallest_denorm, d_max_denorm, >);
> + TEST_OPD(d_smallest_norm, d_max_denorm, >);
> + TEST_OPD(d_smallest_norm, d_smallest_denorm, >);
> + TEST_OPD(d_smallest_denorm, d_max_denorm, ==);
> + TEST_OPD(d_smallest_norm, d_max_denorm, ==);
> + TEST_OPD(d_smallest_norm, d_smallest_denorm, ==);
> +
> + TEST_OPD(pinfd, pinfd, !=);
> + TEST_OPD(pinfd, pinfd, ==);
> + TEST_OPD(pinfd, pinf, ==);
> +
> + TEST_FUNC(smallest_norm, __builtin_sqrtf);
> +
> + TEST_FUNC(smallest_denorm, __builtin_sqrtf);
> + TEST_FUNC(max_denorm, __builtin_sqrtf);
> + TEST_FUNC(4.0f, __builtin_sqrtf);
> + TEST_FUNC(2.0f, __builtin_sqrtf);
> + TEST_FUNC(0.5f, __builtin_sqrtf);
> +
> + TEST_FTOD(smallest_norm);
> + TEST_FTOD(smallest_denorm);
> + TEST_FTOD(max_denorm);
> + TEST_FTOD(-0.0f);
> +
> + TEST_DTOF(d_smallest_norm);
> + TEST_DTOF(d_smallest_denorm);
> + TEST_DTOF(d_max_denorm);
> + TEST_DTOF(-0.0);
> +
> + if (failed > 0)
> + abort();
> + exit(0);
> + }
> Index: gcc/simplify-rtx.c
> ===================================================================
> *** gcc/simplify-rtx.c (revision 128153)
> --- gcc/simplify-rtx.c (working copy)
> *************** simplify_const_unary_operation (enum rtx
> *** 1334,1339 ****
> --- 1334,1341 ----
> d = real_value_truncate (mode, d);
> break;
> case FLOAT_EXTEND:
> + if (REAL_CONVERT_AS_IEEE (mode, GET_MODE (op)))
> + real_convert_fold (&d, mode, &d, GET_MODE (op));
> /* All this does is change the mode. */
> break;
> case FIX:
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 1793,1798 ****
> --- 1795,1801 ----
> 0 - 0 is -0. */
> if (!(HONOR_SIGNED_ZEROS (mode)
> && HONOR_SIGN_DEPENDENT_ROUNDING (mode))
> + && !HONOR_NONIEEE_DENORMS (mode)
> && trueop1 == CONST0_RTX (mode))
> return op0;
>
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 1961,1967 ****
> break;
>
> case MULT:
> ! if (trueop1 == constm1_rtx)
> return simplify_gen_unary (NEG, mode, op0, mode);
>
> /* Maybe simplify x * 0 to 0. The reduction is not valid if
> --- 1964,1971 ----
> break;
>
> case MULT:
> ! if (trueop1 == constm1_rtx
> ! && !HONOR_NONIEEE_DENORMS (mode))
> return simplify_gen_unary (NEG, mode, op0, mode);
>
> /* Maybe simplify x * 0 to 0. The reduction is not valid if
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 1970,1975 ****
> --- 1974,1980 ----
> number by 0 will give -0, not 0. */
> if (!HONOR_NANS (mode)
> && !HONOR_SIGNED_ZEROS (mode)
> + && !HONOR_NONIEEE_DENORMS (mode)
> && trueop1 == CONST0_RTX (mode)
> && ! side_effects_p (op0))
> return op1;
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 1977,1982 ****
> --- 1982,1988 ----
> /* In IEEE floating point, x*1 is not equivalent to x for
> signalling NaNs. */
> if (!HONOR_SNANS (mode)
> + && !HONOR_NONIEEE_DENORMS (mode)
> && trueop1 == CONST1_RTX (mode))
> return op0;
>
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 2013,2018 ****
> --- 2019,2025 ----
> return simplify_gen_binary (PLUS, mode, op0, copy_rtx (op0));
>
> if (!HONOR_SNANS (mode)
> + && !HONOR_NONIEEE_DENORMS (mode)
> && REAL_VALUES_EQUAL (d, dconstm1))
> return simplify_gen_unary (NEG, mode, op0, mode);
> }
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 2465,2470 ****
> --- 2472,2478 ----
> return op0;
> /* x/1.0 is x. */
> if (trueop1 == CONST1_RTX (mode)
> + && !HONOR_NONIEEE_DENORMS (mode)
> && !HONOR_SNANS (mode))
> return op0;
>
> *************** simplify_binary_operation_1 (enum rtx_co
> *** 2476,2481 ****
> --- 2484,2490 ----
>
> /* x/-1.0 is -x. */
> if (REAL_VALUES_EQUAL (d, dconstm1)
> + && !HONOR_NONIEEE_DENORMS (mode)
> && !HONOR_SNANS (mode))
> return simplify_gen_unary (NEG, mode, op0, mode);
>
> *************** simplify_const_binary_operation (enum rt
> *** 3034,3041 ****
> /* Inf * 0 = NaN plus exception. */
> return 0;
>
> ! inexact = real_arithmetic (&value, rtx_to_tree_code (code),
> ! &f0, &f1);
> real_convert (&result, mode, &value);
>
> /* Don't constant fold this floating point operation if
> --- 3043,3050 ----
> /* Inf * 0 = NaN plus exception. */
> return 0;
>
> ! inexact = real_arithmetic_fold (&value, rtx_to_tree_code (code),
> ! &f0, &f1, mode);
> real_convert (&result, mode, &value);
>
> /* Don't constant fold this floating point operation if
> *************** simplify_const_relational_operation (enu
> *** 4060,4068 ****
> return 0;
> }
>
> ! equal = REAL_VALUES_EQUAL (d0, d1);
> ! op0lt = op0ltu = REAL_VALUES_LESS (d0, d1);
> ! op1lt = op1ltu = REAL_VALUES_LESS (d1, d0);
> }
>
> /* Otherwise, see if the operands are both integers. */
> --- 4069,4079 ----
> return 0;
> }
>
> ! equal = real_compare_fold (EQ_EXPR, &d0, &d1, GET_MODE (trueop0));
> ! op0lt = op0ltu = real_compare_fold (LT_EXPR, &d0, &d1,
> ! GET_MODE (trueop0));
> ! op1lt = op1ltu = real_compare_fold (LT_EXPR, &d1, &d0,
> ! GET_MODE (trueop0));
> }
>
> /* Otherwise, see if the operands are both integers. */
> Index: gcc/c-common.c
> ===================================================================
> *** gcc/c-common.c (revision 128153)
> --- gcc/c-common.c (working copy)
> *************** c_common_truthvalue_conversion (tree exp
> *** 2956,2962 ****
> : truthvalue_true_node;
>
> case REAL_CST:
> ! return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
> ? truthvalue_true_node
> : truthvalue_false_node;
>
> --- 2956,2963 ----
> : truthvalue_true_node;
>
> case REAL_CST:
> ! return real_compare_fold (NE_EXPR, &TREE_REAL_CST (expr), &dconst0,
> ! TYPE_MODE (TREE_TYPE (expr)))
> ? truthvalue_true_node
> : truthvalue_false_node;
>
> Index: gcc/config/spu/spu.c
> ===================================================================
> *** gcc/config/spu/spu.c (revision 128153)
> --- gcc/config/spu/spu.c (working copy)
> *************** spu_override_options (void)
> *** 342,347 ****
> --- 342,348 ----
> else
> error ("Unknown architecture '%s'", &spu_tune_string[0]);
> }
> + REAL_MODE_FORMAT (SFmode) = &spu_extended_format;
> }
>
> /* Handle an attribute requiring a FUNCTION_DECL; arguments as in
> Index: gcc/config/spu/spu.h
> ===================================================================
> *** gcc/config/spu/spu.h (revision 128153)
> --- gcc/config/spu/spu.h (working copy)
> *************** extern GTY(()) int spu_tune;
> *** 124,156 ****
>
> #define STACK_SIZE_MODE SImode
>
> ! /* #define TARGET_FLOAT_FORMAT SPU_FLOAT_FORMAT */
>
> ! #ifndef MODE_HAS_NANS
> ! #define MODE_HAS_NANS(MODE) \
> ! (FLOAT_MODE_P (MODE) \
> ! && MODE != SFmode \
> ! && !LARGEST_EXPONENT_IS_NORMAL (GET_MODE_BITSIZE (MODE)))
> ! #endif
> !
> ! #ifndef MODE_HAS_INFINITIES
> ! #define MODE_HAS_INFINITIES(MODE) \
> ! (FLOAT_MODE_P (MODE) \
> ! && MODE != SFmode \
> ! && !LARGEST_EXPONENT_IS_NORMAL (GET_MODE_BITSIZE (MODE)))
> ! #endif
> !
> ! #ifndef MODE_HAS_SIGN_DEPENDENT_ROUNDING
> ! #define MODE_HAS_SIGN_DEPENDENT_ROUNDING(MODE) \
> ! (FLOAT_MODE_P (MODE) \
> ! && MODE != SFmode \
> ! && !ROUND_TOWARDS_ZERO)
> ! #endif
>
> ! #define ROUND_TOWARDS_ZERO 1
>
> ! /* This is certainly true. Should it be defined? (It wasn't before.) */
> ! /* #define LARGEST_EXPONENT_IS_NORMAL(size) (size != 32) */
>
>
> /* Type Layout */
> --- 124,140 ----
>
> #define STACK_SIZE_MODE SImode
>
> ! #define ROUND_TOWARDS_ZERO(MODE) ((MODE) == SFmode)
>
> ! #define LARGEST_EXPONENT_IS_NORMAL(SIZE) ((SIZE) == 32)
> !
> ! #define DENORM_OPERANDS_ARE_ZERO(MODE) 1
> !
> ! #define DENORM_RESULTS_ARE_ZERO(MODE) ((MODE) == SFmode)
>
> ! #define ZERO_RESULTS_ARE_POSITIVE(MODE) ((MODE) == SFmode)
>
> ! #define REAL_CONVERT_AS_IEEE(TO_MODE,FROM_MODE) ((TO_MODE) != (FROM_MODE))
>
>
> /* Type Layout */
> Index: gcc/config/fp-bit.c
> ===================================================================
> *** gcc/config/fp-bit.c (revision 128153)
> --- gcc/config/fp-bit.c (working copy)
> *************** Software Foundation, 51 Franklin Street,
> *** 42,47 ****
> --- 42,48 ----
> #include "tconfig.h"
> #include "coretypes.h"
> #include "tm.h"
> + #include "insn-modes.h"
> #include "config/fp-bit.h"
>
> /* The following macros can be defined to change the behavior of this file:
> *************** pack_d ( fp_number_type * src)
> *** 301,307 ****
> else
> {
> exp = src->normal_exp + EXPBIAS;
> ! if (!ROUND_TOWARDS_ZERO)
> {
> /* IF the gard bits are the all zero, but the first, then we're
> half way between two numbers, choose the one which makes the
> --- 302,308 ----
> else
> {
> exp = src->normal_exp + EXPBIAS;
> ! if (!ROUND_TOWARDS_ZERO (TFO_mode))
> {
> /* IF the gard bits are the all zero, but the first, then we're
> half way between two numbers, choose the one which makes the
> *************** _fpmul_parts ( fp_number_type * a,
> *** 915,921 ****
> low <<= 1;
> }
>
> ! if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
> {
> if (high & (1 << NGARDS))
> {
> --- 916,922 ----
> low <<= 1;
> }
>
> ! if (!ROUND_TOWARDS_ZERO (TFO_mode) && (high & GARDMASK) == GARDMSB)
> {
> if (high & (1 << NGARDS))
> {
> *************** _fpdiv_parts (fp_number_type * a,
> *** 1035,1041 ****
> numerator *= 2;
> }
>
> ! if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
> {
> if (quotient & (1 << NGARDS))
> {
> --- 1036,1042 ----
> numerator *= 2;
> }
>
> ! if (!ROUND_TOWARDS_ZERO (TFO_mode) && (quotient & GARDMASK) == GARDMSB)
> {
> if (quotient & (1 << NGARDS))
> {
> Index: gcc/config/fp-bit.h
> ===================================================================
> *** gcc/config/fp-bit.h (revision 128153)
> --- gcc/config/fp-bit.h (working copy)
> *************** typedef unsigned int UTItype __attribute
> *** 175,180 ****
> --- 175,181 ----
> typedef UDItype halffractype;
> typedef USItype qrtrfractype;
> #define qrtrfractype qrtrfractype
> + #define TFO_mode TFmode
> typedef TFtype FLO_type;
> typedef TItype intfrac;
> #elif defined FLOAT
> *************** typedef unsigned int UTItype __attribute
> *** 195,200 ****
> --- 196,202 ----
> # define __fpcmp_parts __fpcmp_parts_f
> typedef USItype fractype;
> typedef UHItype halffractype;
> + #define TFO_mode SFmode
> typedef SFtype FLO_type;
> typedef SItype intfrac;
>
> *************** typedef unsigned int UTItype __attribute
> *** 218,223 ****
> --- 220,226 ----
> # define __fpcmp_parts __fpcmp_parts_d
> typedef UDItype fractype;
> typedef USItype halffractype;
> + #define TFO_mode DFmode
> typedef DFtype FLO_type;
> typedef DItype intfrac;
> #endif /* FLOAT */