defaults.h (MODE_HAS_NANS, [...]): New.
authorRichard Sandiford <rsandifo@redhat.com>
Thu, 7 Mar 2002 11:37:16 +0000 (11:37 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 7 Mar 2002 11:37:16 +0000 (11:37 +0000)
* 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_real_zero_addition_p): New.
(fold): Use it, and the new HONOR_... macros.
* ifcvt.c (noce_try_minmax): Use the new HONOR_... macros.
* 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.

From-SVN: r50401

12 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/c-common.c
gcc/combine.c
gcc/cse.c
gcc/defaults.h
gcc/doc/tm.texi
gcc/flags.h
gcc/fold-const.c
gcc/ifcvt.c
gcc/jump.c
gcc/simplify-rtx.c

index 6def6705e0bc1f48fea09435230669c080e31ffd..2940fceffa308f5abe142d5644cc3a1f5864c4cd 100644 (file)
@@ -1,3 +1,33 @@
+2002-03-07  Richard Sandiford  <rsandifo@redhat.com>
+
+       * 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_real_zero_addition_p): New.
+       (fold): Use it, and the new HONOR_... macros.
+       * ifcvt.c (noce_try_minmax): Use the new HONOR_... macros.
+       * 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.
+
 2002-03-07  Richard Earnshaw  <rearnsha@arm.com>
 
        * combine.c (simplify_comparison): If simplifying a logical shift
index e3adb05feeb1f3d3094c1469486368d708aa2cde..c4aebd3a801ab1950dad6087cc4b1f93e6fdba92 100644 (file)
@@ -1470,6 +1470,7 @@ expand_builtin_mathfn (exp, target, subtarget)
   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;
@@ -1518,8 +1519,8 @@ expand_builtin_mathfn (exp, target, subtarget)
 
   /* 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);
+  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
@@ -1530,18 +1531,12 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* If errno must be maintained and if we are not allowing unsafe
-     math optimizations, check the result.  */
+  /* If errno must be maintained, we must set it to EDOM for NaN results.  */
 
-  if (flag_errno_math && ! flag_unsafe_math_optimizations)
+  if (flag_errno_math && HONOR_NANS (argmode))
     {
       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 ();
 
       /* Test the result; if it is NaN, set errno=EDOM because
index ed67bb05b9109cc54e429e1011d637d76ae6475f..7fad4b304f228e76ac1b90b7160902e3164a745b 100644 (file)
@@ -2202,10 +2202,15 @@ truthvalue_conversion (expr)
       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)
+      /* 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.
+
+        Note that this transformation is safe when x or y is NaN.
+        (x - y) is then NaN, and both (x - y) != 0 and x != y will
+        be false.  */
+      if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0)))))
        break;
       /* fall through...  */
     case BIT_XOR_EXPR:
@@ -3051,6 +3056,81 @@ strip_array_types (type)
   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.  */
@@ -3063,8 +3143,6 @@ tree
 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;
 
@@ -3103,72 +3181,22 @@ expand_tree_builtin (function, params, coerced_params)
       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;
+      return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
 
     case BUILT_IN_ISGREATEREQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNLT_EXPR;
-      else
-       code = LT_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
 
     case BUILT_IN_ISLESS:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGE_EXPR;
-      else
-       code = GE_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
 
     case BUILT_IN_ISLESSEQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGT_EXPR;
-      else
-       code = GT_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
 
     case BUILT_IN_ISLESSGREATER:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNEQ_EXPR;
-      else
-       code = EQ_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
 
     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;
+      return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
 
     default:
       break;
index a155555c5fcbb1b3fca23907e1f43e354e6ea47d..c9a67033dc8601bcdca4894de4cb40c9af4a365e 100644 (file)
@@ -3978,12 +3978,14 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       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).  */
+      /* (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
-         && (! FLOAT_MODE_P (mode)
-             /* x-y != -(y-x) with IEEE floating point.  */
-             || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-             || flag_unsafe_math_optimizations))
+         && !HONOR_SIGNED_ZEROS (mode)
+         && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
        return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
                           XEXP (XEXP (x, 0), 0));
 
@@ -4145,10 +4147,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       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)
+      /* x - 0 is the same as x unless x's mode has signed zeros and
+        allows rounding towards -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 7a05dad03077c4bb391caa6012862826abb1ebd4..1fe4752d8a0f414f3aa2531eb82aeed355bcc076 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -3981,19 +3981,18 @@ fold_rtx (x, insn)
                                        & 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;
+                 /* 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 fe467404a68f2e9a1b621cd0551a3ed0a3d932e8..5142ee7b471017e3b65457e99d2b8969f74a5904 100644 (file)
@@ -465,4 +465,24 @@ You Lose!  You must define PREFERRED_DEBUGGING_TYPE!
 #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) \
+  (FLOAT_MODE_P (MODE) && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
+#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 8d1a3188074c99a3c7a198b535242a81e2351e28..344c711f57caa5f0bd085d7afc3a001f1bd045e5 100644 (file)
@@ -1336,6 +1336,55 @@ defined for them.
 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
+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 is true when @var{mode}
+is a floating-point mode and the target format is IEEE@.
+
+@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 @minus{}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 @minus{}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})
index 2c69497fb7dd38e6a32266d4bca5b1b44c387e10..3b0ee2fc947fad27996d229229e6ab35cc85e1aa 100644 (file)
@@ -633,4 +633,27 @@ extern int flag_non_call_exceptions;
 /* Nonzero means put zero initialized data in the bss section.  */
 extern int flag_zero_initialized_in_bss;
 
+/* 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.  */
+#define HONOR_SIGN_DEPENDENT_ROUNDING(MODE) \
+  (MODE_HAS_SIGN_DEPENDENT_ROUNDING (MODE) && !flag_unsafe_math_optimizations)
+
 #endif /* ! GCC_FLAGS_H */
index aee10565e9a9e81575646f3869c2ad0547c7c842..feb3e5f72fdca6df406510e298eaccfd1a655893 100644 (file)
@@ -105,6 +105,7 @@ static tree constant_boolean_node PARAMS ((int, tree));
 static int count_cond          PARAMS ((tree, int));
 static tree fold_binary_op_with_conditional_arg 
   PARAMS ((enum tree_code, tree, tree, tree, int));
+static bool fold_real_zero_addition_p  PARAMS ((tree, tree, int));
                                                         
 #ifndef BRANCH_COST
 #define BRANCH_COST 1
@@ -4372,6 +4373,43 @@ fold_binary_op_with_conditional_arg (code, type, cond, arg, cond_first_p)
 }
 
 \f
+/* Subroutine of fold() that checks for the addition of +/- 0.0.
+
+   If !NEGATE, return true if ADDEND is +/-0.0 and, for all X of type
+   TYPE, X + ADDEND is the same as X.  If NEGATE, return true if X -
+   ADDEND is the same as X.
+
+   X + 0 and X - 0 both give X when X is NaN, infinite, or non-zero
+   and finite.  The problematic cases are when X is zero, and its mode
+   has signed zeros.  In the case of rounding towards -infinity,
+   X - 0 is not the same as X because 0 - 0 is -0.  In other rounding
+   modes, X + 0 is not the same as X because -0 + 0 is 0.  */
+
+static bool
+fold_real_zero_addition_p (type, addend, negate)
+     tree type, addend;
+     int negate;
+{
+  if (!real_zerop (addend))
+    return false;
+
+  /* Allow the fold if zeros aren't signed, or their sign isn't important.  */
+  if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type)))
+    return true;
+
+  /* Treat x + -0 as x - 0 and x - -0 as x + 0.  */
+  if (TREE_CODE (addend) == REAL_CST
+      && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (addend)))
+    negate = !negate;
+
+  /* The mode has signed zeros, and we have to honor their sign.
+     In this situation, there is only one case we can return true for.
+     X - 0 is the same as X unless rounding towards -infinity is
+     supported.  */
+  return negate && !HONOR_SIGN_DEPENDENT_ROUNDING (TYPE_MODE (type));
+}
+
+
 /* Perform constant folding and related simplification of EXPR.
    The related simplifications include x*1 => x, x*0 => 0, etc.,
    and application of the associative law.
@@ -5001,16 +5039,15 @@ fold (expr)
                                    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.  */
-      else if (TREE_CODE (arg1) == REAL_CST
-              && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
+
+      /* See if ARG1 is zero and X + ARG1 reduces to X.  */
+      else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0))
        return non_lvalue (convert (type, arg0));
 
+      /* Likewise if the operands are reversed.  */
+      else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+       return non_lvalue (convert (type, arg1));
+
      bit_rotate:
       /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
         is a rotate of A by C1 bits.  */
@@ -5163,16 +5200,15 @@ fold (expr)
                                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));
-       }
+      /* See if ARG1 is zero and X - ARG1 reduces to X.  */
+      else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 1))
+       return non_lvalue (convert (type, arg0));
+
+      /* (ARG0 - ARG1) is the same as (-ARG1 + ARG0).  So check whether
+        ARG0 is zero and X + ARG0 reduces to X, since that would mean
+        (-ARG1 + ARG0) reduces to -ARG1.  */
+      else if (!wins && fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0))
+       return negate_expr (convert (type, arg1));
 
       /* Fold &x - &x.  This can happen from &x.foo - &x.
         This is unsafe for certain floats even in non-IEEE formats.
@@ -5217,9 +5253,12 @@ fold (expr)
        }
       else
        {
-         /* x*0 is 0, except for IEEE floating point.  */
-         if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-              || flag_unsafe_math_optimizations)
+         /* 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.
@@ -6504,23 +6543,38 @@ fold (expr)
 
       /* 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.  */
+        of B and C.  Signed zeros prevent all of these transformations,
+        for reasons given above each one.  */
 
       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)))
+                                            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, this is A, -A, abs (A), or -abs (A),
-            depending on the comparison operation.  */
+         /* 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)))
@@ -6535,7 +6589,6 @@ fold (expr)
                              negate_expr
                              (convert (TREE_TYPE (TREE_OPERAND (t, 1)),
                                        arg1))));
-
              case NE_EXPR:
                return pedantic_non_lvalue (convert (type, arg1));
              case GE_EXPR:
@@ -6558,8 +6611,10 @@ fold (expr)
                abort ();
              }
 
-         /* If this is A != 0 ? A : 0, this is simply A.  For ==, it is
-            always zero.  */
+         /* 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))
            {
@@ -6569,9 +6624,32 @@ fold (expr)
                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.  */
-
+         /* 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)))
            {
@@ -6595,21 +6673,23 @@ fold (expr)
                     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)))));
+                 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:
-                 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)))));
+                 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 038b8c5d5fffb4239e049752af8434295ae0d5db..7a450bc97a99a17678ed6e2567cfc8ed701f2829 100644 (file)
@@ -1295,12 +1295,11 @@ noce_try_minmax (if_info)
   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
+  /* ??? 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 (FLOAT_MODE_P (GET_MODE (if_info->x))
-      && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-      && ! flag_unsafe_math_optimizations)
+  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 7d01a55f3ba2e5bee9d68d6c3d8b877999d593a2..86b3a94276965b6b63fd8c158ebd0b5fea2705d1 100644 (file)
@@ -704,11 +704,6 @@ reversed_comparison_code_parts (code, arg0, arg1, insn)
       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
@@ -757,11 +752,12 @@ reversed_comparison_code_parts (code, arg0, arg1, insn)
        }
     }
 
-  /* An integer condition.  */
+  /* 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
-         && ! FLOAT_MODE_P (mode)))
+         && !HONOR_NANS (mode)))
     return reverse_condition (code);
 
   return UNKNOWN;
@@ -840,10 +836,6 @@ enum rtx_code
 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:
index b50a3392f7b19470b91e73c59631b911b4db4571..88ca32b5b2440248da71630b24916b26af64ff21 100644 (file)
@@ -981,16 +981,15 @@ simplify_binary_operation (code, mode, op0, op1)
       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))
+         /* 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 -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)) */
+         /* ((-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)
@@ -1122,12 +1121,6 @@ simplify_binary_operation (code, mode, op0, op1)
          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.  */
@@ -1136,16 +1129,23 @@ simplify_binary_operation (code, mode, op0, op1)
              && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations))
            return CONST0_RTX (mode);
 
-         /* Change subtraction from zero into negation.  */
-         if (trueop0 == 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
+            -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.  */
-         if (trueop1 == CONST0_RTX (mode))
+         /* Subtracting 0 has no effect unless the mode has signed zeros
+            and supports rounding towards -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
@@ -1202,7 +1202,7 @@ simplify_binary_operation (code, mode, op0, op1)
                }
            }
 
-         /* (a - (-b)) -> (a + b).  */
+         /* (a - (-b)) -> (a + b).  True even for IEEE.  */
          if (GET_CODE (op1) == NEG)
            return simplify_gen_binary (PLUS, mode, op0, XEXP (op1, 0));
 
@@ -1248,9 +1248,12 @@ simplify_binary_operation (code, mode, op0, op1)
              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)
+         /* 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;
@@ -1361,9 +1364,12 @@ simplify_binary_operation (code, mode, op0, op1)
                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)
+         /* 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;
@@ -2018,12 +2024,9 @@ simplify_relational_operation (code, mode, op0, op1)
   if (flag_unsafe_math_optimizations && code == UNORDERED)
     return const0_rtx;
 
-  /* For non-IEEE floating-point, if the two operands are equal, we know the
+  /* For modes without NaNs, 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))
+  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