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]

Patch to rework IEEE floating point checks


This patch replaces conditions of the form:

	TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
	&& !flag_unsafe_math_optimizations

with macros that check for particular properties.

There's several motivations:

1) Support targets that use a variation of IEEE, such as IEEE without
   NaNs, or IEEE without signed zeros.

2) Allow the format to vary with mode.  A target might have a
   non-compliant single precision FPU, but use a more compliant
   emulation library for double precision.

3) Document what exactly makes each transformation right or wrong,
   which should make things easier to maintain.  At the moment, most
   checks just say "not valid for IEEE" with no explanation why.
   And to show that there has been some confusion here, if x and y
   are IEEE floats, the tree level optimises "x + -y" into "x - y",
   but the RTL level doesn't.

4) Make it possible to add options like -fignore-signed-zeros,
   or whatever, as suboptions of -funsafe-math-optimizations.
   (More options might not be universally popular, though. ;-)

The patch introduces new macros:

	MODE_HAS_NANS
	MODE_HAS_INFINITIES
	MODE_HAS_SIGNED_ZEROS
	MODE_HAS_SIGN_DEPENDENT_ROUNDING

to describe the properties of a mode.  It also adds variants
with s/MODE_HAS/HONOR/, which are true if the optimizer has to
take account of these properties.

I did wonder about using the target structure instead of defining
the MODE_HAS_... macros.  But this stuff really applies to the
TARGET_FLOAT_FORMAT macro, so I think using macros make more sense.

Other changes:

1) The unordered comparison builtins now use the MODE_HAS_NANS macro
   to decide whether an unordered comparison is needed.  I split the
   code out into a separate function and fixed a nit:

	float f;
	__builtin_isgreater (f, 0)

   complains that 0 is not a real when unordered comparisons are needed,
   but promotes 0 to a real when they aren't needed (ie., when the format
   isn't IEEE).  In fact, the function accepts any comparable input when
   the float format is not IEEE.  The patch makes the interface the same,
   requiring the common type of the two arguments to be a real.

   (This wasn't entirely optional, btw, since the function has to find
   out the common type in order to find out the mode.)

2) reversed_comparison_code_parts() now searches for the real comparison
   mode before checking for NaNs.

3) I took the IEEE check out of reverse_condition_maybe_unordered().  The
   only target-independent caller seems to be r_comparison_code_parts()
   (just mentioned).  Some backends call it too, but they all know
   they're IEEE anyway.

Bootstrapped and regression tested on i686-pc-linux-gnu.  Does it
look OK?

Richard


	* defaults.h (MODE_HAS_NANS, MODE_HAS_INFINITIES): New.
	(MODE_HAS_SIGNED_ZEROS, MODE_HAS_SIGN_DEPENDENT_ROUNDING): New.
	* flags.h (HONOR_NANS, HONOR_INFINITIES, HONOR_SIGNED_ZEROS): New.
	(HONOR_SIGN_DEPENDENT_ROUNDING): New.
	* builtins.c (expand_builtin_mathfn): Use HONOR_NANS.
	* c-common.c (truthvalue_conversion): Reduce x - y != 0 to x != y
	unless x and y could be infinite.
	(expand_unordered_cmp): New, mostly split from expand_tree_builtin.
	Check that the common type of both arguments is a real, even for
	targets without unordered comparisons.  Allow an integer argument
	to be compared against a real.
	(expand_tree_builtin): Use expand_unordered_cmp.
	* combine.c (combine_simplify_rtx): Use the new HONOR_... macros.
	* cse.c (fold_rtx): Likewise.  Fix indentation.
	* fold-const.c (fold): Use the new HONOR_... macros.
	* ifcvt.c (noce_try_minmax): And here.
	* jump.c (reversed_comparison_code_parts): After searching for
	the true comparison mode, use HONOR_NANS to decide whether it
	can be safely reversed.
	(reverse_condition_maybe_unordered): Remove IEEE check.
	* simplify-rtx.c (simplify_binary_operation): Use the new macros
	to decide which simplifications are valid.  Allow the following
	simplifications for IEEE: (-a + b) to (b - a), (a + -b) to (a - b),
	and (a - -b) to (a + b).
	(simplify_relational_operation): Use HONOR_NANS.
	* doc/tm.texi: Document the MODE_HAS_... macros.

	* gcc.dg/unordered-1.c: New test.

Index: defaults.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/defaults.h,v
retrieving revision 1.64
diff -c -p -d -r1.64 defaults.h
*** defaults.h	2001/12/17 16:46:09	1.64
--- defaults.h	2002/02/28 16:56:18
*************** You Lose!  You must define PREFERRED_DEB
*** 457,460 ****
--- 457,479 ----
  #define MODE_BASE_REG_CLASS(MODE) BASE_REG_CLASS
  #endif
  
+ #ifndef MODE_HAS_NANS
+ #define MODE_HAS_NANS(MODE) \
+   (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+ #endif
+ 
+ #ifndef MODE_HAS_INFINITIES
+ #define MODE_HAS_INFINITIES(MODE) MODE_HAS_NANS (MODE)
+ #endif
+ 
+ #ifndef MODE_HAS_SIGNED_ZEROS
+ #define MODE_HAS_SIGNED_ZEROS(MODE) \
+   (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+ #endif
+ 
+ #ifndef MODE_HAS_SIGN_DEPENDENT_ROUNDING
+ #define MODE_HAS_SIGN_DEPENDENT_ROUNDING(MODE) \
+   (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+ #endif
+ 
  #endif  /* ! GCC_DEFAULTS_H */
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.76
diff -c -p -d -r1.76 flags.h
*** flags.h	2002/01/10 18:51:14	1.76
--- flags.h	2002/02/28 16:56:18
*************** extern int flag_detailed_statistics;
*** 636,639 ****
--- 636,663 ----
  /* Nonzero means enable synchronous exceptions for non-call instructions.  */
  extern int flag_non_call_exceptions;
  
+ /* True if the given mode has a NaN representation and the treatment of
+    NaN operands is important.  Certain optimizations, such as folding
+    x * 0 into x, are not correct for NaN operands, and are normally
+    disabled for modes with NaNs.  The user can ask for them to be
+    done anyway using the -funsafe-math-optimizations switch.  */
+ #define HONOR_NANS(MODE) \
+   (MODE_HAS_NANS (MODE) && !flag_unsafe_math_optimizations)
+ 
+ /* As for HONOR_NANS, but true if the mode can represent infinity and
+    the treatment of infinite values is important.  */
+ #define HONOR_INFINITIES(MODE) \
+   (MODE_HAS_INFINITIES (MODE) && !flag_unsafe_math_optimizations)
+ 
+ /* Like HONOR_NANS, but true if the given mode distinguishes between
+    postive and negative zero, and the sign of zero is important.  */
+ #define HONOR_SIGNED_ZEROS(MODE) \
+   (MODE_HAS_SIGNED_ZEROS (MODE) && !flag_unsafe_math_optimizations)
+ 
+ /* Like HONOR_NANS, but true if given mode supports sign-dependent rounding,
+    and the rounding mode is important.  If this macro is true for the mode
+    of -(x - y), the expression can't be optimized to (y - x).  */
+ #define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \
+   (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && !flag_unsafe_math_optimizations)
+ 
  #endif /* ! GCC_FLAGS_H */
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.142
diff -c -p -d -r1.142 builtins.c
*** builtins.c	2002/01/26 14:47:12	1.142
--- builtins.c	2002/02/28 16:56:18
*************** expand_builtin_mathfn (exp, target, subt
*** 1470,1475 ****
--- 1470,1476 ----
    rtx op0, insns;
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
+   enum machine_mode argmode;
  
    if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_mathfn (exp, target, subt
*** 1518,1525 ****
  
    /* Compute into TARGET.
       Set TARGET to wherever the result comes back.  */
!   target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
! 			builtin_optab, op0, target, 0);
  
    /* If we were unable to expand via the builtin, stop the
       sequence (without outputting the insns) and return 0, causing
--- 1519,1526 ----
  
    /* Compute into TARGET.
       Set TARGET to wherever the result comes back.  */
!   argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
!   target = expand_unop (argmode, builtin_optab, op0, target, 0);
  
    /* If we were unable to expand via the builtin, stop the
       sequence (without outputting the insns) and return 0, causing
*************** expand_builtin_mathfn (exp, target, subt
*** 1530,1546 ****
        return 0;
      }
  
!   /* If errno must be maintained and if we are not allowing unsafe
!      math optimizations, check the result.  */
  
!   if (flag_errno_math && ! flag_unsafe_math_optimizations)
      {
        rtx lab1;
- 
-       /* Don't define the builtin FP instructions
- 	 if your machine is not IEEE.  */
-       if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
- 	abort ();
  
        lab1 = gen_label_rtx ();
  
--- 1531,1541 ----
        return 0;
      }
  
!   /* If errno must be maintained, we must set it to EDOM for NaN results.  */
  
!   if (flag_errno_math && HONOR_NANS (argmode))
      {
        rtx lab1;
  
        lab1 = gen_label_rtx ();
  
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.294
diff -c -p -d -r1.294 c-common.c
*** c-common.c	2002/02/22 00:08:59	1.294
--- c-common.c	2002/02/28 16:56:18
*************** truthvalue_conversion (expr)
*** 2203,2212 ****
        break;
  
      case MINUS_EXPR:
!       /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
! 	 this case.  */
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
! 	  && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
  	break;
        /* fall through...  */
      case BIT_XOR_EXPR:
--- 2203,2213 ----
        break;
  
      case MINUS_EXPR:
!       /* Perhaps reduce (x - y) != 0 to (x != y).  The expressions
! 	 aren't guaranteed to the be same for modes that can represent
! 	 infinity, since if x and y are both +infinity, or both
! 	 -infinity, then x - y is not a number.  */
!       if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0)))))
  	break;
        /* fall through...  */
      case BIT_XOR_EXPR:
*************** strip_array_types (type)
*** 3072,3077 ****
--- 3073,3153 ----
    return type;
  }
  
+ static tree expand_unordered_cmp PARAMS ((tree, tree, enum tree_code,
+ 					  enum tree_code));
+ 
+ /* Expand a call to an unordered comparison function such as
+    __builtin_isgreater().  FUNCTION is the function's declaration and
+    PARAMS a list of the values passed.  For __builtin_isunordered(),
+    UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR.  In
+    other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes
+    that give the opposite of the desired result.  UNORDERED_CODE is
+    used for modes that can hold NaNs and ORDERED_CODE is used for the
+    rest.  */
+ 
+ static tree
+ expand_unordered_cmp (function, params, unordered_code, ordered_code)
+      tree function, params;
+      enum tree_code unordered_code, ordered_code;
+ {
+   tree arg0, arg1, type;
+   enum tree_code code0, code1;
+ 
+   /* Check that we have exactly two arguments.  */
+   if (params == 0 || TREE_CHAIN (params) == 0)
+     {
+       error ("too few arguments to function `%s'",
+ 	     IDENTIFIER_POINTER (DECL_NAME (function)));
+       return error_mark_node;
+     }
+   else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
+     {
+       error ("too many arguments to function `%s'",
+ 	     IDENTIFIER_POINTER (DECL_NAME (function)));
+       return error_mark_node;
+     }
+ 
+   arg0 = TREE_VALUE (params);
+   arg1 = TREE_VALUE (TREE_CHAIN (params));
+ 
+   code0 = TREE_CODE (TREE_TYPE (arg0));
+   code1 = TREE_CODE (TREE_TYPE (arg1));
+ 
+   /* Make sure that the arguments have a common type of REAL.  */
+   type = 0;
+   if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+       && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+     type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+ 
+   if (type == 0 || TREE_CODE (type) != REAL_TYPE)
+     {
+       error ("non-floating-point argument to function `%s'",
+ 	     IDENTIFIER_POINTER (DECL_NAME (function)));
+       return error_mark_node;
+     }
+ 
+   if (unordered_code == UNORDERED_EXPR)
+     {
+       if (MODE_HAS_NANS (TYPE_MODE (type)))
+ 	return build_binary_op (unordered_code,
+ 				convert (type, arg0),
+ 				convert (type, arg1),
+ 				0);
+       else
+ 	return integer_zero_node;
+     }
+ 
+   return build_unary_op (TRUTH_NOT_EXPR,
+ 			 build_binary_op (MODE_HAS_NANS (TYPE_MODE (type))
+ 					  ? unordered_code
+ 					  : ordered_code,
+ 					  convert (type, arg0),
+ 					  convert (type, arg1),
+ 					  0),
+ 			 0);
+ }
+ 
+ 
  /* Recognize certain built-in functions so we can make tree-codes
     other than CALL_EXPR.  We do this when it enables fold-const.c
     to do something useful.  */
*************** tree
*** 3084,3091 ****
  expand_tree_builtin (function, params, coerced_params)
       tree function, params, coerced_params;
  {
-   enum tree_code code;
- 
    if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
      return NULL_TREE;
  
--- 3160,3165 ----
*************** expand_tree_builtin (function, params, c
*** 3124,3195 ****
        return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
  
      case BUILT_IN_ISGREATER:
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
! 	code = UNLE_EXPR;
!       else
! 	code = LE_EXPR;
!       goto unordered_cmp;
  
      case BUILT_IN_ISGREATEREQUAL:
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
! 	code = UNLT_EXPR;
!       else
! 	code = LT_EXPR;
!       goto unordered_cmp;
  
      case BUILT_IN_ISLESS:
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
! 	code = UNGE_EXPR;
!       else
! 	code = GE_EXPR;
!       goto unordered_cmp;
  
      case BUILT_IN_ISLESSEQUAL:
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
! 	code = UNGT_EXPR;
!       else
! 	code = GT_EXPR;
!       goto unordered_cmp;
  
      case BUILT_IN_ISLESSGREATER:
!       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
! 	code = UNEQ_EXPR;
!       else
! 	code = EQ_EXPR;
!       goto unordered_cmp;
  
      case BUILT_IN_ISUNORDERED:
!       if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
! 	return integer_zero_node;
!       code = UNORDERED_EXPR;
!       goto unordered_cmp;
! 
!     unordered_cmp:
!       {
! 	tree arg0, arg1;
! 
! 	if (params == 0
! 	    || TREE_CHAIN (params) == 0)
! 	  {
! 	    error ("too few arguments to function `%s'",
! 		   IDENTIFIER_POINTER (DECL_NAME (function)));
! 	    return error_mark_node;
! 	  }
! 	else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
! 	  {
! 	    error ("too many arguments to function `%s'",
! 		   IDENTIFIER_POINTER (DECL_NAME (function)));
! 	    return error_mark_node;
! 	  }
! 
! 	arg0 = TREE_VALUE (params);
! 	arg1 = TREE_VALUE (TREE_CHAIN (params));
! 	arg0 = build_binary_op (code, arg0, arg1, 0);
! 	if (code != UNORDERED_EXPR)
! 	  arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0);
! 	return arg0;
!       }
!       break;
  
      default:
        break;
--- 3198,3219 ----
        return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
  
      case BUILT_IN_ISGREATER:
!       return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
  
      case BUILT_IN_ISGREATEREQUAL:
!       return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
  
      case BUILT_IN_ISLESS:
!       return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
  
      case BUILT_IN_ISLESSEQUAL:
!       return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
  
      case BUILT_IN_ISLESSGREATER:
!       return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
  
      case BUILT_IN_ISUNORDERED:
!       return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
  
      default:
        break;
Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.267
diff -c -p -d -r1.267 combine.c
*** combine.c	2002/02/20 23:15:00	1.267
--- combine.c	2002/02/28 16:56:19
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3978,3989 ****
        if (GET_CODE (XEXP (x, 0)) == NOT)
  	return plus_constant (XEXP (XEXP (x, 0), 0), 1);
  
!       /* (neg (minus X Y)) can become (minus Y X).  */
        if (GET_CODE (XEXP (x, 0)) == MINUS
! 	  && (! FLOAT_MODE_P (mode)
! 	      /* x-y != -(y-x) with IEEE floating point.  */
! 	      || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	      || flag_unsafe_math_optimizations))
  	return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
  			   XEXP (XEXP (x, 0), 0));
  
--- 3978,3991 ----
        if (GET_CODE (XEXP (x, 0)) == NOT)
  	return plus_constant (XEXP (XEXP (x, 0), 0), 1);
  
!       /* (neg (minus X Y)) can become (minus Y X).  This transformation
! 	 isn't safe for modes with signed zeros, since if X and Y are
! 	 both +0, (minus Y X) is the same as (minus X Y).  If the rounding
! 	 mode is towards +infinity (or -infinity) then the two expressions
! 	 will be rounded differently.  */
        if (GET_CODE (XEXP (x, 0)) == MINUS
! 	  && !HONOR_SIGNED_ZEROS (mode)
! 	  && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
  	return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
  			   XEXP (XEXP (x, 0), 0));
  
*************** combine_simplify_rtx (x, op0_mode, last,
*** 4145,4154 ****
        if (XEXP (x, 1) == const0_rtx)
  	return XEXP (x, 0);
  
!       /* In IEEE floating point, x-0 is not the same as x.  */
!       if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	   || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
! 	   || flag_unsafe_math_optimizations)
  	  && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
  	return XEXP (x, 0);
        break;
--- 4147,4157 ----
        if (XEXP (x, 1) == const0_rtx)
  	return XEXP (x, 0);
  
!       /* x - 0 is the same as x unless x's mode has signed zeros and
! 	 allows rounding towards -ve infinity.  Under those conditions,
! 	 0 - 0 is -0.  */
!       if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
! 	    && HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
  	  && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
  	return XEXP (x, 0);
        break;
Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.218
diff -c -p -d -r1.218 cse.c
*** cse.c	2002/02/19 02:53:23	1.218
--- cse.c	2002/02/28 16:56:20
*************** fold_rtx (x, insn)
*** 3980,3998 ****
  					& HASH_MASK), mode_arg0))
  		      && p0->first_same_value == p1->first_same_value))
  		{
! 		   /* Sadly two equal NaNs are not equivalent.  */
! 		   if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 		       || ! FLOAT_MODE_P (mode_arg0) 
! 		       || flag_unsafe_math_optimizations)
! 		      return ((code == EQ || code == LE || code == GE
! 			       || code == LEU || code == GEU || code == UNEQ
! 			       || code == UNLE || code == UNGE || code == ORDERED)
! 			      ? true_rtx : false_rtx);
! 		   /* Take care for the FP compares we can resolve.  */
! 		   if (code == UNEQ || code == UNLE || code == UNGE)
! 		     return true_rtx;
! 		   if (code == LTGT || code == LT || code == GT)
! 		     return false_rtx;
  		}
  
  	      /* If FOLDED_ARG0 is a register, see if the comparison we are
--- 3980,3997 ----
  					& HASH_MASK), mode_arg0))
  		      && p0->first_same_value == p1->first_same_value))
  		{
! 		  /* Sadly two equal NaNs are not equivalent.  */
! 		  if (!HONOR_NANS (mode_arg0))
! 		    return ((code == EQ || code == LE || code == GE
! 			     || code == LEU || code == GEU || code == UNEQ
! 			     || code == UNLE || code == UNGE
! 			     || code == ORDERED)
! 			    ? true_rtx : false_rtx);
! 		  /* Take care for the FP compares we can resolve.  */
! 		  if (code == UNEQ || code == UNLE || code == UNGE)
! 		    return true_rtx;
! 		  if (code == LTGT || code == LT || code == GT)
! 		    return false_rtx;
  		}
  
  	      /* If FOLDED_ARG0 is a register, see if the comparison we are
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.185
diff -c -p -d -r1.185 fold-const.c
*** fold-const.c	2002/02/22 11:50:47	1.185
--- fold-const.c	2002/02/28 16:56:20
*************** fold (expr)
*** 5588,5596 ****
  				    same));
  	    }
  	}
!       /* In IEEE floating point, x+0 may not equal x.  */
!       else if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 		|| flag_unsafe_math_optimizations)
  	       && real_zerop (arg1))
  	return non_lvalue (convert (type, arg0));
        /* x+(-0) equals x, even for IEEE.  */
--- 5588,5599 ----
  				    same));
  	    }
  	}
!       /* Maybe fold x + 0 to x.  The expressions are equivalent when x is
! 	 NaN, infinite, or non-zero and finite.  They aren't equivalent
! 	 when x is zero and its mode has signed zeros, unless the rounding
! 	 mode is towards -ve infinity.  In other rounding modes, (-0) + 0
! 	 is 0.  */
!       else if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
  	       && real_zerop (arg1))
  	return non_lvalue (convert (type, arg0));
        /* x+(-0) equals x, even for IEEE.  */
*************** fold (expr)
*** 5754,5769 ****
  				TREE_OPERAND (arg0, 1)));
  	}
  
!       else if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	       || flag_unsafe_math_optimizations)
! 	{
! 	  /* Except with IEEE floating point, 0-x equals -x.  */
! 	  if (! wins && real_zerop (arg0))
! 	    return negate_expr (convert (type, arg1));
! 	  /* Except with IEEE floating point, x-0 equals x.  */
! 	  if (real_zerop (arg1))
! 	    return non_lvalue (convert (type, arg0));
! 	}
  
        /* Fold &x - &x.  This can happen from &x.foo - &x.
  	 This is unsafe for certain floats even in non-IEEE formats.
--- 5757,5778 ----
  				TREE_OPERAND (arg0, 1)));
  	}
  
!       /* Maybe fold 0 - x to -x.  This transformation is valid if x is
! 	 NaN, infinite, or non-zero and finite.  It isn't valid for
! 	 modes with signed zeros, unless the rounding mode is towards
! 	 -0.  In other cases, 0 - 0 is 0, not -0.  */
!       else if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1)))
! 	       && !wins
! 	       && real_zerop (arg0))
! 	return negate_expr (convert (type, arg1));
! 
!       /* x - 0 is the same as x, unless the mode has signed zeros and
! 	 can round towards -ve infinity.  Under those conditions,
! 	 0 - 0 is -0.  */
!       else if (!(HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (TREE_TYPE (arg0)))
! 		 && HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0))))
! 	       && real_zerop (arg1))
! 	return non_lvalue (convert (type, arg0));
  
        /* Fold &x - &x.  This can happen from &x.foo - &x.
  	 This is unsafe for certain floats even in non-IEEE formats.
*************** fold (expr)
*** 5808,5816 ****
  	}
        else
  	{
! 	  /* x*0 is 0, except for IEEE floating point.  */
! 	  if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	       || flag_unsafe_math_optimizations)
  	      && real_zerop (arg1))
  	    return omit_one_operand (type, arg1, arg0);
  	  /* In IEEE floating point, x*1 is not equivalent to x for snans.
--- 5817,5828 ----
  	}
        else
  	{
! 	  /* Maybe fold x * 0 to 0.  The expressions aren't the same
! 	     when x is NaN, since x * 0 is also NaN.  Nor are they the
! 	     same in modes with signed zeros, since multiplying a
! 	     negative value by 0 gives -0, not +0.  */
! 	  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
! 	      && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg0)))
  	      && real_zerop (arg1))
  	    return omit_one_operand (type, arg1, arg0);
  	  /* In IEEE floating point, x*1 is not equivalent to x for snans.
*************** fold (expr)
*** 7097,7119 ****
  
        /* If we have A op B ? A : C, we may be able to convert this to a
  	 simpler expression, depending on the operation and the values
! 	 of B and C.  IEEE floating point prevents this though,
! 	 because A or B might be -0.0 or a NaN.  */
  
        if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
- 	  && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- 	      || ! FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 0)))
- 	      || flag_unsafe_math_optimizations)
  	  && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
! 					     arg1, TREE_OPERAND (arg0, 1)))
  	{
  	  tree arg2 = TREE_OPERAND (t, 2);
  	  enum tree_code comp_code = TREE_CODE (arg0);
  
  	  STRIP_NOPS (arg2);
  
! 	  /* If we have A op 0 ? A : -A, this is A, -A, abs (A), or -abs (A),
! 	     depending on the comparison operation.  */
  	  if ((FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 1)))
  	       ? real_zerop (TREE_OPERAND (arg0, 1))
  	       : integer_zerop (TREE_OPERAND (arg0, 1)))
--- 7109,7146 ----
  
        /* If we have A op B ? A : C, we may be able to convert this to a
  	 simpler expression, depending on the operation and the values
! 	 of B and C.  Signed zeros prevent all of these transformations,
! 	 for reasons given above each one.  */
  
        if (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
  	  && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0),
! 					     arg1, TREE_OPERAND (arg0, 1))
! 	  && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
  	{
  	  tree arg2 = TREE_OPERAND (t, 2);
  	  enum tree_code comp_code = TREE_CODE (arg0);
  
  	  STRIP_NOPS (arg2);
  
! 	  /* If we have A op 0 ? A : -A, consider applying the following
! 	     transformations:
! 
! 	     A == 0? A : -A    same as -A
! 	     A != 0? A : -A    same as A
! 	     A >= 0? A : -A    same as abs (A)
! 	     A > 0?  A : -A    same as abs (A)
! 	     A <= 0? A : -A    same as -abs (A)
! 	     A < 0?  A : -A    same as -abs (A)
! 
! 	     None of these transformations work for modes with signed
! 	     zeros.  If A is +/-0, the first two transformations will
! 	     change the sign of the result (from +0 to -0, or vice
! 	     versa).  The last four will fix the sign of the result,
! 	     even though the original expressions could be positive or
! 	     negative, depending on the sign of A.
! 
! 	     Note that all these transformations are correct if A is
! 	     NaN, since the two alternatives (A and -A) are also NaNs.  */
  	  if ((FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg0, 1)))
  	       ? real_zerop (TREE_OPERAND (arg0, 1))
  	       : integer_zerop (TREE_OPERAND (arg0, 1)))
*************** fold (expr)
*** 7128,7134 ****
  			      negate_expr
  			      (convert (TREE_TYPE (TREE_OPERAND (t, 1)),
  					arg1))));
- 
  	      case NE_EXPR:
  		return pedantic_non_lvalue (convert (type, arg1));
  	      case GE_EXPR:
--- 7155,7160 ----
*************** fold (expr)
*** 7151,7158 ****
  		abort ();
  	      }
  
! 	  /* If this is A != 0 ? A : 0, this is simply A.  For ==, it is
! 	     always zero.  */
  
  	  if (integer_zerop (TREE_OPERAND (arg0, 1)) && integer_zerop (arg2))
  	    {
--- 7177,7186 ----
  		abort ();
  	      }
  
! 	  /* A != 0 ? A : 0 is simply A, unless A is -0.  Likewise
! 	     A == 0 ? A : 0 is always 0 unless A is -0.  Note that
! 	     both transformations are correct when A is NaN: A != 0
! 	     is then true, and A == 0 is false.  */
  
  	  if (integer_zerop (TREE_OPERAND (arg0, 1)) && integer_zerop (arg2))
  	    {
*************** fold (expr)
*** 7162,7170 ****
  		return pedantic_non_lvalue (convert (type, integer_zero_node));
  	    }
  
! 	  /* If this is A op B ? A : B, this is either A, B, min (A, B),
! 	     or max (A, B), depending on the operation.  */
  
  	  if (operand_equal_for_comparison_p (TREE_OPERAND (arg0, 1),
  					      arg2, TREE_OPERAND (arg0, 0)))
  	    {
--- 7190,7221 ----
  		return pedantic_non_lvalue (convert (type, integer_zero_node));
  	    }
  
! 	  /* Try some transformations of A op B ? A : B.
  
+ 	     A == B? A : B    same as B
+ 	     A != B? A : B    same as A
+ 	     A >= B? A : B    same as max (A, B)
+ 	     A > B?  A : B    same as max (B, A)
+ 	     A <= B? A : B    same as min (A, B)
+ 	     A < B?  A : B    same as min (B, A)
+ 
+ 	     As above, these transformations don't work in the presence
+ 	     of signed zeros.  For example, if A and B are zeros of
+ 	     opposite sign, the first two transformations will change
+ 	     the sign of the result.  In the last four, the original
+ 	     expressions give different results for (A=+0, B=-0) and
+ 	     (A=-0, B=+0), but the transformed expressions do not.
+ 
+ 	     The first two transformations are correct if either A or B
+ 	     is a NaN.  In the first transformation, the condition will
+ 	     be false, and B will indeed be chosen.  In the case of the
+ 	     second transformation, the condition A != B will be true,
+ 	     and A will be chosen.
+ 
+ 	     The conversions to max() and min() are not correct if B is
+ 	     a number and A is not.  The conditions in the original
+ 	     expressions will be false, so all four give B.  The min()
+ 	     and max() versions would give a NaN instead.  */
  	  if (operand_equal_for_comparison_p (TREE_OPERAND (arg0, 1),
  					      arg2, TREE_OPERAND (arg0, 0)))
  	    {
*************** fold (expr)
*** 7188,7208 ****
  		     operand which will be used if they are equal first
  		     so that we can convert this back to the
  		     corresponding COND_EXPR.  */
! 		  return pedantic_non_lvalue
! 		    (convert (type, fold (build (MIN_EXPR, comp_type,
! 						 (comp_code == LE_EXPR
! 						  ? comp_op0 : comp_op1),
! 						 (comp_code == LE_EXPR
! 						  ? comp_op1 : comp_op0)))));
  		  break;
  		case GE_EXPR:
  		case GT_EXPR:
! 		  return pedantic_non_lvalue
! 		    (convert (type, fold (build (MAX_EXPR, comp_type,
! 						 (comp_code == GE_EXPR
! 						  ? comp_op0 : comp_op1),
! 						 (comp_code == GE_EXPR
! 						  ? comp_op1 : comp_op0)))));
  		  break;
  		default:
  		  abort ();
--- 7239,7261 ----
  		     operand which will be used if they are equal first
  		     so that we can convert this back to the
  		     corresponding COND_EXPR.  */
! 		  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
! 		    return pedantic_non_lvalue
! 		      (convert (type, fold (build (MIN_EXPR, comp_type,
! 						   (comp_code == LE_EXPR
! 						    ? comp_op0 : comp_op1),
! 						   (comp_code == LE_EXPR
! 						    ? comp_op1 : comp_op0)))));
  		  break;
  		case GE_EXPR:
  		case GT_EXPR:
! 		  if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))))
! 		    return pedantic_non_lvalue
! 		      (convert (type, fold (build (MAX_EXPR, comp_type,
! 						   (comp_code == GE_EXPR
! 						    ? comp_op0 : comp_op1),
! 						   (comp_code == GE_EXPR
! 						    ? comp_op1 : comp_op0)))));
  		  break;
  		default:
  		  abort ();
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.78
diff -c -p -d -r1.78 ifcvt.c
*** ifcvt.c	2002/01/31 11:07:14	1.78
--- ifcvt.c	2002/02/28 16:56:20
*************** noce_try_minmax (if_info)
*** 1297,1308 ****
    if (no_new_pseudos)
      return FALSE;
  
!   /* ??? Reject FP modes since we don't know how 0 vs -0 or NaNs
!      will be resolved with an SMIN/SMAX.  It wouldn't be too hard
       to get the target to tell us...  */
!   if (FLOAT_MODE_P (GET_MODE (if_info->x))
!       && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
!       && ! flag_unsafe_math_optimizations)
      return FALSE;
  
    cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
--- 1297,1307 ----
    if (no_new_pseudos)
      return FALSE;
  
!   /* ??? Reject modes with NaNs or signed zeros since we don't know how
!      they will be resolved with an SMIN/SMAX.  It wouldn't be too hard
       to get the target to tell us...  */
!   if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))
!       || HONOR_NANS (GET_MODE (if_info->x)))
      return FALSE;
  
    cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
Index: jump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/jump.c,v
retrieving revision 1.205
diff -c -p -d -r1.205 jump.c
*** jump.c	2002/02/21 22:47:58	1.205
--- jump.c	2002/02/28 16:56:21
*************** reversed_comparison_code_parts (code, ar
*** 704,714 ****
        break;
      }
  
-   /* In case we give up IEEE compatibility, all comparisons are reversible.  */
-   if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-       || flag_unsafe_math_optimizations)
-     return reverse_condition (code);
- 
    if (GET_MODE_CLASS (mode) == MODE_CC
  #ifdef HAVE_cc0
        || arg0 == cc0_rtx
--- 704,709 ----
*************** reversed_comparison_code_parts (code, ar
*** 757,767 ****
  	}
      }
  
!   /* An integer condition.  */
    if (GET_CODE (arg0) == CONST_INT
        || (GET_MODE (arg0) != VOIDmode
  	  && GET_MODE_CLASS (mode) != MODE_CC
! 	  && ! FLOAT_MODE_P (mode)))
      return reverse_condition (code);
  
    return UNKNOWN;
--- 752,763 ----
  	}
      }
  
!   /* Test for an integer condition, or a floating-point comparison
!      in which NaNs can be ignored.  */
    if (GET_CODE (arg0) == CONST_INT
        || (GET_MODE (arg0) != VOIDmode
  	  && GET_MODE_CLASS (mode) != MODE_CC
! 	  && !HONOR_NANS (mode)))
      return reverse_condition (code);
  
    return UNKNOWN;
*************** enum rtx_code
*** 840,849 ****
  reverse_condition_maybe_unordered (code)
       enum rtx_code code;
  {
-   /* Non-IEEE formats don't have unordered conditions.  */
-   if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
-     return reverse_condition (code);
- 
    switch (code)
      {
      case EQ:
--- 836,841 ----
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.94
diff -c -p -d -r1.94 simplify-rtx.c
*** simplify-rtx.c	2002/02/21 23:06:15	1.94
--- simplify-rtx.c	2002/02/28 16:56:21
*************** simplify_binary_operation (code, mode, o
*** 1045,1060 ****
        switch (code)
  	{
  	case PLUS:
! 	  /* In IEEE floating point, x+0 is not the same as x.  Similarly
! 	     for the other optimizations below.  */
! 	  if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
! 	      && FLOAT_MODE_P (mode) && ! flag_unsafe_math_optimizations)
! 	    break;
! 
! 	  if (trueop1 == CONST0_RTX (mode))
  	    return op0;
  
! 	  /* ((-a) + b) -> (b - a) and similarly for (a + (-b)) */
  	  if (GET_CODE (op0) == NEG)
  	    return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
  	  else if (GET_CODE (op1) == NEG)
--- 1045,1059 ----
        switch (code)
  	{
  	case PLUS:
! 	  /* Maybe simplify x + 0 to x.  The two expressions are equivalent
! 	     when x is NaN, infinite, or finite and non-zero.  They aren't
! 	     when x is -0 and the rounding mode is not towards -ve infinity,
! 	     since (-0) + 0 is then 0.  */
! 	  if (!HONOR_SIGNED_ZEROS (mode) && trueop1 == CONST0_RTX (mode))
  	    return op0;
  
! 	  /* ((-a) + b) -> (b - a) and similarly for (a + (-b)).  These
! 	     transformations are safe even for IEEE.  */
  	  if (GET_CODE (op0) == NEG)
  	    return simplify_gen_binary (MINUS, mode, op1, XEXP (op0, 0));
  	  else if (GET_CODE (op1) == NEG)
*************** simplify_binary_operation (code, mode, o
*** 1186,1197 ****
  	  break;	      
  
  	case MINUS:
- 	  /* None of these optimizations can be done for IEEE
- 	     floating point.  */
- 	  if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
- 	      && FLOAT_MODE_P (mode) && ! flag_unsafe_math_optimizations)
- 	    break;
- 
  	  /* We can't assume x-x is 0 even with non-IEEE floating point,
  	     but since it is zero except in very strange circumstances, we
  	     will treat it as zero with -funsafe-math-optimizations.  */
--- 1185,1190 ----
*************** simplify_binary_operation (code, mode, o
*** 1200,1215 ****
  	      && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
  	    return CONST0_RTX (mode);
  
! 	  /* Change subtraction from zero into negation.  */
! 	  if (trueop0 == CONST0_RTX (mode))
  	    return gen_rtx_NEG (mode, op1);
  
  	  /* (-1 - a) is ~a.  */
  	  if (trueop0 == constm1_rtx)
  	    return gen_rtx_NOT (mode, op1);
  
! 	  /* Subtracting 0 has no effect.  */
! 	  if (trueop1 == CONST0_RTX (mode))
  	    return op0;
  
  	  /* See if this is something like X * C - X or vice versa or
--- 1193,1215 ----
  	      && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
  	    return CONST0_RTX (mode);
  
! 	  /* Change subtraction from zero into negation.  (0 - x) is the
! 	     same as -x when x is NaN, infinite, or finite and non-zero.
! 	     But if the mode has signed zeros, and does not round towards
! 	     -ve infinity, then 0 - 0 is 0, not -0.  */
! 	  if (!HONOR_SIGNED_ZEROS (mode) && trueop0 == CONST0_RTX (mode))
  	    return gen_rtx_NEG (mode, op1);
  
  	  /* (-1 - a) is ~a.  */
  	  if (trueop0 == constm1_rtx)
  	    return gen_rtx_NOT (mode, op1);
  
! 	  /* Subtracting 0 has no effect unless the mode has signed zeros
! 	     and supports rounding towards -ve infinity.  In such a case,
! 	     0 - 0 is -0.  */
! 	  if (!(HONOR_SIGNED_ZEROS (mode)
! 		&& HONOR_SIGN_DEPENDENT_ROUNDING (mode))
! 	      && trueop1 == CONST0_RTX (mode))
  	    return op0;
  
  	  /* See if this is something like X * C - X or vice versa or
*************** simplify_binary_operation (code, mode, o
*** 1266,1272 ****
  		}
  	    }
  
! 	  /* (a - (-b)) -> (a + b).  */
  	  if (GET_CODE (op1) == NEG)
  	    return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
  
--- 1266,1272 ----
  		}
  	    }
  
! 	  /* (a - (-b)) -> (a + b).  True even for IEEE.  */
  	  if (GET_CODE (op1) == NEG)
  	    return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
  
*************** simplify_binary_operation (code, mode, o
*** 1312,1320 ****
  	      return tem ? tem : gen_rtx_NEG (mode, op0);
  	    }
  
! 	  /* In IEEE floating point, x*0 is not always 0.  */
! 	  if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	       || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
  	      && trueop1 == CONST0_RTX (mode)
  	      && ! side_effects_p (op0))
  	    return op1;
--- 1312,1323 ----
  	      return tem ? tem : gen_rtx_NEG (mode, op0);
  	    }
  
! 	  /* Maybe simplify x * 0 to 0.  The reduction is not valid if
! 	     x is NaN, since x * 0 is then also NaN.  Nor is it valid
! 	     when the mode has signed zeros, since multiplying a negative
! 	     number by 0 will give -0, not 0.  */
! 	  if (!HONOR_NANS (mode)
! 	      && !HONOR_SIGNED_ZEROS (mode)
  	      && trueop1 == CONST0_RTX (mode)
  	      && ! side_effects_p (op0))
  	    return op1;
*************** simplify_binary_operation (code, mode, o
*** 1425,1433 ****
  		return op0;
  	    }
  
! 	  /* In IEEE floating point, 0/x is not always 0.  */
! 	  if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	       || ! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
  	      && trueop0 == CONST0_RTX (mode)
  	      && ! side_effects_p (op1))
  	    return op0;
--- 1428,1439 ----
  		return op0;
  	    }
  
! 	  /* Maybe change 0 / x to 0.  This transformation isn't safe for
! 	     modes with NaNs, since 0 / 0 will then be NaN rather than 0.
! 	     Nor is it safe for modes with signed zeros, since dividing
! 	     0 by a negative number gives -0, not 0.  */
! 	  if (!HONOR_NANS (mode)
! 	      && !HONOR_SIGNED_ZEROS (mode)
  	      && trueop0 == CONST0_RTX (mode)
  	      && ! side_effects_p (op1))
  	    return op0;
*************** simplify_relational_operation (code, mod
*** 2092,2103 ****
    if (flag_unsafe_math_optimizations && code == UNORDERED)
      return const0_rtx;
  
!   /* For non-IEEE floating-point, if the two operands are equal, we know the
       result.  */
!   if (rtx_equal_p (trueop0, trueop1)
!       && (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
! 	  || ! FLOAT_MODE_P (GET_MODE (trueop0)) 
! 	  || flag_unsafe_math_optimizations))
      equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
  
    /* If the operands are floating-point constants, see if we can fold
--- 2098,2106 ----
    if (flag_unsafe_math_optimizations && code == UNORDERED)
      return const0_rtx;
  
!   /* For modes without NaNs, if the two operands are equal, we know the
       result.  */
!   if (!HONOR_NANS (GET_MODE (trueop0)) && rtx_equal_p (trueop0, trueop1))
      equal = 1, op0lt = 0, op0ltu = 0, op1lt = 0, op1ltu = 0;
  
    /* If the operands are floating-point constants, see if we can fold
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.102
diff -c -p -d -r1.102 tm.texi
*** doc/tm.texi	2002/02/23 12:59:09	1.102
--- doc/tm.texi	2002/02/28 16:56:22
*************** defined for them.
*** 1335,1340 ****
--- 1335,1388 ----
  The ordering of the component words of floating point values stored in
  memory is controlled by @code{FLOAT_WORDS_BIG_ENDIAN}.
  
+ @findex MODE_HAS_NANS
+ @item MODE_HAS_NANS (@var{mode})
+ When defined, this macro should be true if @var{mode} has a NaN
+ representation.  The compiler assumes that NaNs are not equal to
+ anything (including themselves) and that addition, subtraction,
+ multiplication and division all return NaNs when one operand is
+ a NaN.
+ 
+ By default, this macro is true if @var{mode} is a floating-point
+ mode and the target floating-point format is IEEE@.
+ 
+ @findex MODE_HAS_INFINITIES
+ @item MODE_HAS_INFINITIES (@var{mode})
+ This macro should be true if @var{mode} can represent infinity.  At
+ present, the compiler uses this macro to decide whether @samp{x - x}
+ is always defined.  By default, the macro shadows @code{MODE_HAS_NANS}.
+ 
+ @findex MODE_HAS_SIGNED_ZEROS
+ @item MODE_HAS_SIGNED_ZEROS (@var{mode})
+ True if @var{mode} distinguishes between positive and negative zero.
+ The rules are expected to follow the IEEE standard:
+ 
+ @itemize @bullet
+ @item
+ @samp{x + x} has the same sign as @samp{x}.
+ 
+ @item
+ If the sum of two values with opposite sign is zero, the result is
+ positive for all rounding modes expect towards -infinity, for which
+ it is negative.
+ 
+ @item
+ The sign of a product or quotient is negative when exactly one
+ of the operands is negative.
+ @end itemize
+ 
+ The default definition is true if @var{mode} is a floating-point
+ mode and the target format is IEEE@.
+ 
+ @findex MODE_HAS_SIGN_DEPENDENT_ROUNDING
+ @item MODE_HAS_SIGN_DEPENDENT_ROUNDING (@var{mode})
+ If defined, this macro should be true for @var{mode} if it has at
+ least one rounding mode in which @samp{x} and @samp{-x} can be
+ rounded to numbers of different magnitude.  Two such modes are
+ towards -infinity and towards +infinity.
+ 
+ The default definition of this macro is true if @var{mode} is
+ a floating-point mode and the target format is IEEE.
  @end table
  
  @deftypefn {Target Hook} bool TARGET_MS_BITFIELD_LAYOUT_P (tree @var{record_type})
*** /dev/null	Tue Nov 14 21:44:43 2000
--- testsuite/gcc.dg/unordered-1.c	Wed Feb 27 16:37:17 2002
***************
*** 0 ****
--- 1,18 ----
+ /* { dg-do compile } */
+ 
+ void bar (int);
+ 
+ void foo (int i, float f)
+ {
+   bar (__builtin_isgreater (i, i));	/* { dg-error "non-floating-point" } */
+   bar (__builtin_isgreater (f, i));
+   bar (__builtin_isgreater (i, f));
+   bar (__builtin_isgreater (f, 2));
+   bar (__builtin_isgreater (f, 2.0f));
+   bar (__builtin_isgreater (f, 2.0));
+   bar (__builtin_isgreater (2, f));
+   bar (__builtin_isgreater (2.0f, f));
+   bar (__builtin_isgreater (2.0, f));
+   bar (__builtin_isgreater (&f, i));	/* { dg-error "non-floating-point" } */
+   bar (__builtin_isgreater (f, &i));	/* { dg-error "non-floating-point" } */
+ }


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