This series of patches fix PR61441.
authorSujoy Saraswati <sujoy.saraswati@hpe.com>
Tue, 22 Dec 2015 14:04:30 +0000 (14:04 +0000)
committerSujoy Saraswati <ssaraswati@gcc.gnu.org>
Tue, 22 Dec 2015 14:04:30 +0000 (14:04 +0000)
This series of patches fix PR61441. This patch avoids various transformations
with signaling NaN operands when flag_signaling_nans is on, to avoid folding
which would lose exceptions.

Bootstrapped & regression-tested on x86_64-linux-gnu.

gcc/
* fold-const.c (const_binop): Convert sNaN to qNaN when
flag_signaling_nans is off.
(const_unop): Avoid the operation, other than NEGATE and
ABS, if flag_signaling_nans is on and the operand is an sNaN.
(fold_convert_const_real_from_real): Avoid the operation if
flag_signaling_nans is on and the operand is an sNaN.
(integer_valued_real_unary_p): Update comment stating it
returns false for sNaN values.
(integer_valued_real_binary_p, integer_valued_real_call_p): Same.
(integer_valued_real_single_p): Same.
(integer_valued_real_invalid_p, integer_valued_real_p): Same.
* fold-const-call.c (fold_const_pow): Avoid the operation
if flag_signaling_nans is on and the operand is an sNaN.
(fold_const_builtin_load_exponent) Same.
(fold_const_call_sss): Same for CASE_CFN_POWI.
* gimple-fold.c (gimple_assign_integer_valued_real_p): Same.
(gimple_call_integer_valued_real_p): Same.
(gimple_phi_integer_valued_real_p): Same.
(gimple_stmt_integer_valued_real_p): Same.
* simplify-rtx.c (simplify_const_unary_operation): Avoid the
operation if flag_signaling_nans is on and the operand is an sNaN.
(simplify_const_binary_operation): Same.
* tree-ssa-math-opts.c (gimple_expand_builtin_pow): Avoid the
operation if flag_signaling_nans is on and the operand is an sNaN.

* gcc.dg/pr61441.c: New testcase.

From-SVN: r231901

gcc/ChangeLog
gcc/fold-const-call.c
gcc/fold-const.c
gcc/gimple-fold.c
gcc/simplify-rtx.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr61441.c [new file with mode: 0644]
gcc/tree-ssa-math-opts.c

index b314c1aeab2f47e18ed4d57a922fd99e91b559e8..134e4fb584d6815535018b3217c5e6f3a64f11a8 100644 (file)
@@ -1,3 +1,30 @@
+2015-12-22  Sujoy Saraswati  <sujoy.saraswati@hpe.com>
+
+       * fold-const.c (const_binop): Convert sNaN to qNaN when
+       flag_signaling_nans is off.
+       (const_unop): Avoid the operation, other than NEGATE and
+       ABS, if flag_signaling_nans is on and the operand is an sNaN.
+       (fold_convert_const_real_from_real): Avoid the operation if
+       flag_signaling_nans is on and the operand is an sNaN.
+       (integer_valued_real_unary_p): Update comment stating it
+       returns false for sNaN values.
+       (integer_valued_real_binary_p, integer_valued_real_call_p): Same.
+       (integer_valued_real_single_p): Same.
+       (integer_valued_real_invalid_p, integer_valued_real_p): Same.
+       * fold-const-call.c (fold_const_pow): Avoid the operation
+       if flag_signaling_nans is on and the operand is an sNaN.
+       (fold_const_builtin_load_exponent) Same.
+       (fold_const_call_sss): Same for CASE_CFN_POWI.
+       * gimple-fold.c (gimple_assign_integer_valued_real_p): Same.
+       (gimple_call_integer_valued_real_p): Same.
+       (gimple_phi_integer_valued_real_p): Same.
+       (gimple_stmt_integer_valued_real_p): Same.
+       * simplify-rtx.c (simplify_const_unary_operation): Avoid the
+       operation if flag_signaling_nans is on and the operand is an sNaN.
+       (simplify_const_binary_operation): Same.
+       * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Avoid the
+       operation if flag_signaling_nans is on and the operand is an sNaN.
+
 2015-12-22  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        * combine.c (simplify_comparison): Convert preprocessor check of
index 94801d23fde99d5626832f235de099081e7797bc..7d1351c3691727c79de5db41aeaa6252136777c0 100644 (file)
@@ -512,7 +512,11 @@ fold_const_pow (real_value *result, const real_value *arg0,
          || !real_equal (arg0, &dconst0)))
     {
       bool inexact = real_powi (result, format, arg0, n1);
-      if (flag_unsafe_math_optimizations || !inexact)
+      /* Avoid the folding if flag_signaling_nans is on.  */
+      if (flag_unsafe_math_optimizations
+         || (!inexact
+             && !(flag_signaling_nans
+                  && REAL_VALUE_ISSIGNALING_NAN (*arg0))))
        return true;
     }
 
@@ -541,6 +545,13 @@ fold_const_builtin_load_exponent (real_value *result, const real_value *arg0,
   if (wi::les_p (arg1, -max_exp_adj) || wi::ges_p (arg1, max_exp_adj))
     return false;
 
+  /* Don't perform operation if we honor signaling NaNs and
+     operand is a signaling NaN.  */
+  if (!flag_unsafe_math_optimizations
+      && flag_signaling_nans
+      && REAL_VALUE_ISSIGNALING_NAN (*arg0))
+    return false;
+
   REAL_VALUE_TYPE initial_result;
   real_ldexp (&initial_result, arg0, arg1.to_shwi ());
 
@@ -1202,6 +1213,13 @@ fold_const_call_sss (real_value *result, combined_fn fn,
                                                   format));
 
     CASE_CFN_POWI:
+      /* Avoid the folding if flag_signaling_nans is on and
+         operand is a signaling NaN.  */
+      if (!flag_unsafe_math_optimizations
+         && flag_signaling_nans
+         && REAL_VALUE_ISSIGNALING_NAN (*arg0))
+        return false;
+
       real_powi (result, format, arg0, arg1.to_shwi ());
       return true;
 
index fff0285bd13f7e73d66c11ee32b98bb54152e042..5ad5112992226d0bac5fdd506809ca6f9d527d5b 100644 (file)
@@ -1166,9 +1166,21 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
       /* If either operand is a NaN, just return it.  Otherwise, set up
         for floating-point trap; we return an overflow.  */
       if (REAL_VALUE_ISNAN (d1))
-       return arg1;
+      {
+       /* Make resulting NaN value to be qNaN when flag_signaling_nans
+          is off.  */
+       d1.signalling = 0;
+       t = build_real (type, d1);
+       return t;
+      }
       else if (REAL_VALUE_ISNAN (d2))
-       return arg2;
+      {
+       /* Make resulting NaN value to be qNaN when flag_signaling_nans
+          is off.  */
+       d2.signalling = 0;
+       t = build_real (type, d2);
+       return t;
+      }
 
       inexact = real_arithmetic (&value, code, &d1, &d2);
       real_convert (&result, mode, &value);
@@ -1538,6 +1550,15 @@ const_binop (enum tree_code code, tree type, tree arg1, tree arg2)
 tree
 const_unop (enum tree_code code, tree type, tree arg0)
 {
+  /* Don't perform the operation, other than NEGATE and ABS, if
+     flag_signaling_nans is on and the operand is a signaling NaN.  */
+  if (TREE_CODE (arg0) == REAL_CST
+      && HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+      && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0))
+      && code != NEGATE_EXPR
+      && code != ABS_EXPR)
+    return NULL_TREE;
+
   switch (code)
     {
     CASE_CONVERT:
@@ -1949,6 +1970,12 @@ fold_convert_const_real_from_real (tree type, const_tree arg1)
   REAL_VALUE_TYPE value;
   tree t;
 
+  /* Don't perform the operation if flag_signaling_nans is on
+     and the operand is a signaling NaN.  */
+  if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))
+      && REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1)))
+    return NULL_TREE; 
+
   real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
   t = build_real (type, value);
 
@@ -13414,7 +13441,7 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
 
 /* Return true if the floating point result of (CODE OP0) has an
    integer value.  We also allow +Inf, -Inf and NaN to be considered
-   integer values.
+   integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -13447,7 +13474,7 @@ integer_valued_real_unary_p (tree_code code, tree op0, int depth)
 
 /* Return true if the floating point result of (CODE OP0 OP1) has an
    integer value.  We also allow +Inf, -Inf and NaN to be considered
-   integer values.
+   integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -13471,8 +13498,8 @@ integer_valued_real_binary_p (tree_code code, tree op0, tree op1, int depth)
 
 /* Return true if the floating point result of calling FNDECL with arguments
    ARG0 and ARG1 has an integer value.  We also allow +Inf, -Inf and NaN to be
-   considered integer values.  If FNDECL takes fewer than 2 arguments,
-   the remaining ARGn are null.
+   considered integer values. Return false for signaling NaN.  If FNDECL
+   takes fewer than 2 arguments, the remaining ARGn are null.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -13501,7 +13528,7 @@ integer_valued_real_call_p (combined_fn fn, tree arg0, tree arg1, int depth)
 
 /* Return true if the floating point expression T (a GIMPLE_SINGLE_RHS)
    has an integer value.  We also allow +Inf, -Inf and NaN to be
-   considered integer values.
+   considered integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -13535,7 +13562,7 @@ integer_valued_real_single_p (tree t, int depth)
 
 /* Return true if the floating point expression T (a GIMPLE_INVALID_RHS)
    has an integer value.  We also allow +Inf, -Inf and NaN to be
-   considered integer values.
+   considered integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -13563,6 +13590,7 @@ integer_valued_real_invalid_p (tree t, int depth)
 
 /* Return true if the floating point expression T has an integer value.
    We also allow +Inf, -Inf and NaN to be considered integer values.
+   Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
index 6f8ec6f90a626d1fb9d70de3e6e76de3a2fe823f..eddb18d4db6ea259acce47ac43ccf436a23a6522 100644 (file)
@@ -6267,7 +6267,7 @@ gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
 
 /* Return true if the floating-point value computed by assignment STMT
    is known to have an integer value.  We also allow +Inf, -Inf and NaN
-   to be considered integer values.
+   to be considered integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -6296,7 +6296,7 @@ gimple_assign_integer_valued_real_p (gimple *stmt, int depth)
 
 /* Return true if the floating-point value computed by call STMT is known
    to have an integer value.  We also allow +Inf, -Inf and NaN to be
-   considered integer values.
+   considered integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -6315,7 +6315,7 @@ gimple_call_integer_valued_real_p (gimple *stmt, int depth)
 
 /* Return true if the floating-point result of phi STMT is known to have
    an integer value.  We also allow +Inf, -Inf and NaN to be considered
-   integer values.
+   integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
@@ -6333,7 +6333,7 @@ gimple_phi_integer_valued_real_p (gimple *stmt, int depth)
 
 /* Return true if the floating-point value computed by STMT is known
    to have an integer value.  We also allow +Inf, -Inf and NaN to be
-   considered integer values.
+   considered integer values. Return false for signaling NaN.
 
    DEPTH is the current nesting depth of the query.  */
 
index 225742ec73e7fcf09afa5f3791b579476249e817..44de1555dc56e86b8217e9037a648329f70391a9 100644 (file)
@@ -1703,6 +1703,12 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
        }
 
       real_from_integer (&d, mode, std::make_pair (op, op_mode), SIGNED);
+
+      /* Avoid the folding if flag_signaling_nans is on and
+         operand is a signaling NaN.  */
+      if (HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d))
+        return 0;
+
       d = real_value_truncate (mode, d);
       return const_double_from_real_value (d, mode);
     }
@@ -1721,6 +1727,12 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
        }
 
       real_from_integer (&d, mode, std::make_pair (op, op_mode), UNSIGNED);
+
+      /* Avoid the folding if flag_signaling_nans is on and
+         operand is a signaling NaN.  */
+      if (HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d))
+        return 0;
+
       d = real_value_truncate (mode, d);
       return const_double_from_real_value (d, mode);
     }
@@ -1825,16 +1837,25 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
          d = real_value_negate (&d);
          break;
        case FLOAT_TRUNCATE:
-         d = real_value_truncate (mode, d);
+         /* Don't perform the operation if flag_signaling_nans is on
+            and the operand is a signaling NaN.  */
+         if (!(HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d)))
+           d = real_value_truncate (mode, d);
          break;
        case FLOAT_EXTEND:
          /* All this does is change the mode, unless changing
             mode class.  */
-         if (GET_MODE_CLASS (mode) != GET_MODE_CLASS (GET_MODE (op)))
+         /* Don't perform the operation if flag_signaling_nans is on
+            and the operand is a signaling NaN.  */
+         if (GET_MODE_CLASS (mode) != GET_MODE_CLASS (GET_MODE (op))
+             && !(HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d)))
            real_convert (&d, mode, &d);
          break;
        case FIX:
-         real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
+         /* Don't perform the operation if flag_signaling_nans is on
+            and the operand is a signaling NaN.  */
+         if (!(HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d)))
+           real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
          break;
        case NOT:
          {
@@ -3886,16 +3907,20 @@ simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
       else
        {
          REAL_VALUE_TYPE f0, f1, value, result;
+         const REAL_VALUE_TYPE *opr0, *opr1;
          bool inexact;
 
-         real_convert (&f0, mode, CONST_DOUBLE_REAL_VALUE (op0));
-         real_convert (&f1, mode, CONST_DOUBLE_REAL_VALUE (op1));
+         opr0 = CONST_DOUBLE_REAL_VALUE (op0);
+         opr1 = CONST_DOUBLE_REAL_VALUE (op1);
 
          if (HONOR_SNANS (mode)
-             && (REAL_VALUE_ISSIGNALING_NAN (f0)
-                 || REAL_VALUE_ISSIGNALING_NAN (f1)))
+             && (REAL_VALUE_ISSIGNALING_NAN (*opr0)
+                 || REAL_VALUE_ISSIGNALING_NAN (*opr1)))
            return 0;
 
+         real_convert (&f0, mode, opr0);
+         real_convert (&f1, mode, opr1);
+
          if (code == DIV
              && real_equal (&f1, &dconst0)
              && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
index 04d48b88617adc3358a0838106558655349691cb..d5c679e63e2f3632edc888cc010603cf8008f350 100644 (file)
@@ -1,3 +1,7 @@
+2015-12-22  Sujoy Saraswati  <sujoy.saraswati@hpe.com>
+
+       * gcc.dg/pr61441.c: New testcase.
+
 2015-12-22  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.dg/torture/pr68264.c: Tweak for Solaris.
diff --git a/gcc/testsuite/gcc.dg/pr61441.c b/gcc/testsuite/gcc.dg/pr61441.c
new file mode 100644 (file)
index 0000000..608a763
--- /dev/null
@@ -0,0 +1,61 @@
+/* { dg-do run } */
+/* { dg-options "-O1 -lm" } */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <math.h>
+
+void conversion()
+{
+  float sNaN = __builtin_nansf ("");
+  double x = (double) sNaN;
+  if (issignaling(x))
+  {
+    __builtin_abort();
+  }
+}
+
+enum op {Add, Mult, Div, Abs};
+
+void operation(enum op t)
+{
+  float x, y;
+  float sNaN = __builtin_nansf ("");
+  switch (t)
+  {
+    case Abs:
+      x = fabs(sNaN);
+      break;
+    case Add:
+      x = sNaN + 2.0;
+      break;
+    case Mult:
+      x = sNaN * 2.0;
+      break;
+    case Div:
+    default:
+      x = sNaN / 2.0;
+      break;
+  }
+  if (t == Abs)
+  {
+    if (!issignaling(x))
+    {
+      __builtin_abort();
+    }
+  }
+  else if (issignaling(x))
+  {
+    __builtin_abort();
+  }
+}
+
+int main (void)
+{
+  conversion();
+  operation(Add);
+  operation(Mult);
+  operation(Div);
+  operation(Abs);
+  return 0;
+}
index b00f046074b8b0b4322659725ce16c3c5328f669..244cf196277778ad1acef403a8cd58ec4481cd99 100644 (file)
@@ -1535,6 +1535,13 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
   if (TREE_CODE (arg1) != REAL_CST)
     return NULL_TREE;
 
+  /* Don't perform the operation if flag_signaling_nans is on
+     and the operand is a signaling NaN.  */
+  if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))
+      && (REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg0))
+         || REAL_VALUE_ISSIGNALING_NAN (TREE_REAL_CST (arg1))))
+    return NULL_TREE;
+
   /* If the exponent is equivalent to an integer, expand to an optimal
      multiplication sequence when profitable.  */
   c = TREE_REAL_CST (arg1);