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


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]