This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Support Cell SPU floating point


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 */



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]