Fix 61441

Sujoy Saraswati ssaraswati@gmail.com
Thu Nov 5 11:29:00 GMT 2015


Hi,

> It seems this code has moved to fold-const.c, so the patch will need
> updating.

I have updated the patch and sending again.

> Now, is it actually correct for integer_valued_real_single_p (now) to
> treat sNaN as an integer?  Looking at existing uses, they all appear to be
> in match.pd: it's used for removing redundant trunc / floor / ceil / round
> / nearbyint on integer values.  In such cases, it's *incorrect* to count
> sNaN as an integer, because while those functions map qNaN quietly to
> qNaN, they should map sNaN to qNaN and raise "invalid" in the process.  So
> I don't think you should have this change at all.

Ok. I have also updated the comments for the functions stating they
return false for sNaN.

> (I don't see why the handling of rint checks flag_errno_math.  rint should
> quietly return infinite and qNaN arguments just like nearbyint; it never
> needs to set errno and distinguishing rint / nearbyint here is spurious;
> the only difference is regarding the "inexact" exception.)

With these changes, real_isinteger returns false for sNaN. This in
turn means that integer_valued_real_p would return false with sNaN.
This means that for sNaN, rint will not go to the path of checking
flag_errno_math. Anyway, I modified that also as part of this patch to
make rint similar to nearbyint.

> I realise this corresponds to some existing code (in const_binop, at
> least), but I don't think that existing code is a good model.
>
> If -fsignaling-nans, it's still perfectly fine to fold when the argument
> is a quiet NaN.  So what you actually want in such cases where you have a
> known constant argument - as opposed to an unknown argument that might or
> might not be constant - is to check whether that argument is itself a
> signaling NaN.  So you want to add a new REAL_VALUE_ISSIGNALING, or
> something like that.  And then find existing code that has the wrong (NaN
> and sNaNs supported) check and convert it to checking (this value is
> sNaN).
>
> (This code has also moved to another function in fold-const.c, it seems.)
>
> Cf. the match.pd handling of fmin / fmax checking for signaling NaN
> arguments explicitly.
>
> Some other places in this patch have similar issues with checking
> HONOR_SNANS && REAL_VALUE_ISNAN when they should check if the particular
> value is sNaN.

I modified the code to check for sNaN specifically. The modified patch is below.

Bootstrap and regression tests on x86_64-linux-gnu passed with changes
done on trunk.

Is this fine ?

Regards,
Sujoy

2015-11-04  Sujoy Saraswati <ssaraswati@gmail.com>

       PR tree-optimization/61441
       * fold-const-call.c (fold_const_pow): Avoid the operation
       if flag_signaling_nans is on and the operand is an sNaN.
       (fold_const_call_sss): Same for BUILT_IN_POWI.
       * 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.
       * 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.
       * match.pd (f(x) -> x): Removed flag_errno_math check for RINT.
       * real.c (do_add): Make resulting NaN value to be qNaN.
       (do_multiply, do_divide, do_fix_trunc): Same.
       (real_arithmetic, real_ldexp): Same.
       (real_issignaling_nan): New.
       (real_isinteger): Updated comment stating it returns false for sNaN.
       * real.h (real_issignaling_nan, REAL_VALUE_ISSIGNALING_NAN): New.
       * 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): Check for sNaN instead of NaN.
       * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Avoid the
       operation if flag_signaling_nans is on and the operand is an sNaN.

       PR tree-optimization/61441
       * gcc.dg/pr61441.c: New testcase.

Index: gcc/fold-const-call.c
===================================================================
--- gcc/fold-const-call.c       (revision 229805)
+++ gcc/fold-const-call.c       (working copy)
@@ -484,7 +484,11 @@ fold_const_pow (real_value *result, const real_val
          || !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 (*result))))
        return true;
     }

@@ -1035,6 +1039,11 @@ fold_const_call_sss (real_value *result, built_in_

     CASE_FLT_FN (BUILT_IN_POWI):
       real_powi (result, format, arg0, arg1.to_shwi ());
+      /* Avoid the folding if flag_signaling_nans is on.  */
+      if (!flag_unsafe_math_optimizations
+          && flag_signaling_nans
+          && REAL_VALUE_ISSIGNALING_NAN (*result))
+       return false;
       return true;

     default:
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c    (revision 229805)
+++ gcc/fold-const.c    (working copy)
@@ -1151,7 +1151,8 @@ const_binop (enum tree_code code, tree arg1, tree
       /* Don't perform operation if we honor signaling NaNs and
         either operand is a NaN.  */
       if (HONOR_SNANS (mode)
-         && (REAL_VALUE_ISNAN (d1) || REAL_VALUE_ISNAN (d2)))
+         && (REAL_VALUE_ISSIGNALING_NAN (d1)
+              || REAL_VALUE_ISSIGNALING_NAN (d2)))
        return NULL_TREE;

       /* Don't perform operation if it would raise a division
@@ -1164,9 +1165,21 @@ const_binop (enum tree_code code, tree arg1, tree
       /* 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);
@@ -1536,6 +1549,15 @@ const_binop (enum tree_code code, tree type, tree
 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 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:
@@ -1943,7 +1965,17 @@ fold_convert_const_real_from_real (tree type, cons
   REAL_VALUE_TYPE value;
   tree t;

+  /* Don't perform the operation if flag_signaling_nans is on
+     and the operand is a 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));
+  /* Make resulting NaN value to be qNaN when flag_signaling_nans
+     is off.  */
+  if (REAL_VALUE_ISSIGNALING_NAN (value))
+    value.signalling = 0;
   t = build_real (type, value);

   /* If converting an infinity or NAN to a representation that doesn't
@@ -13413,7 +13445,7 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -13446,7 +13478,7 @@ integer_valued_real_unary_p (tree_code code, tree

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -13470,8 +13502,8 @@ integer_valued_real_binary_p (tree_code code, tree

 /* 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 signalling NaN.
+   If FNDECL takes fewer than 2 arguments, the remaining ARGn are null.

    DEPTH is the current nesting depth of the query.  */

@@ -13501,7 +13533,7 @@ integer_valued_real_call_p (tree fndecl, tree arg0

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -13535,7 +13567,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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -13563,6 +13595,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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c   (revision 229805)
+++ gcc/gimple-fold.c   (working copy)
@@ -6221,7 +6221,7 @@ gimple_stmt_nonnegative_warnv_p (gimple *stmt, boo

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -6250,7 +6250,7 @@ gimple_assign_integer_valued_real_p (gimple *stmt,

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -6269,7 +6269,7 @@ gimple_call_integer_valued_real_p (gimple *stmt, i

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

@@ -6287,7 +6287,7 @@ gimple_phi_integer_valued_real_p (gimple *stmt, in

 /* 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 signalling NaN.

    DEPTH is the current nesting depth of the query.  */

Index: gcc/match.pd
===================================================================
--- gcc/match.pd        (revision 229805)
+++ gcc/match.pd        (working copy)
@@ -2572,16 +2572,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (fns (fns @0))
   (fns @0)))
 /* f(x) -> x if x is integer valued and f does nothing for such values.  */
-(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT)
+(for fns (TRUNC FLOOR CEIL ROUND NEARBYINT RINT)
  (simplify
   (fns integer_valued_real_p@0)
   @0))
-/* Same for rint.  We have to check flag_errno_math because
-   integer_valued_real_p accepts +Inf, -Inf and NaNs as integers.  */
-(if (!flag_errno_math)
- (simplify
-  (RINT integer_valued_real_p@0)
-  @0))

 /* hypot(x,0) and hypot(0,x) -> abs(x).  */
 (simplify
Index: gcc/real.c
===================================================================
--- gcc/real.c  (revision 229805)
+++ gcc/real.c  (working copy)
@@ -541,6 +541,10 @@ do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE
     case CLASS2 (rvc_normal, rvc_inf):
       /* R + Inf = Inf.  */
       *r = *b;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       r->sign = sign ^ subtract_p;
       return false;

@@ -554,6 +558,10 @@ do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE
     case CLASS2 (rvc_inf, rvc_normal):
       /* Inf + R = Inf.  */
       *r = *a;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       return false;

     case CLASS2 (rvc_inf, rvc_inf):
@@ -676,6 +684,10 @@ do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_
     case CLASS2 (rvc_nan, rvc_nan):
       /* ANY * NaN = NaN.  */
       *r = *b;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       r->sign = sign;
       return false;

@@ -684,6 +696,10 @@ do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_
     case CLASS2 (rvc_nan, rvc_inf):
       /* NaN * ANY = NaN.  */
       *r = *a;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       r->sign = sign;
       return false;

@@ -826,6 +842,10 @@ do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TY
     case CLASS2 (rvc_nan, rvc_nan):
       /* ANY / NaN = NaN.  */
       *r = *b;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       r->sign = sign;
       return false;

@@ -834,6 +854,10 @@ do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TY
     case CLASS2 (rvc_nan, rvc_inf):
       /* NaN / ANY = NaN.  */
       *r = *a;
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       r->sign = sign;
       return false;

@@ -964,6 +988,10 @@ do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE
     case rvc_zero:
     case rvc_inf:
     case rvc_nan:
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       break;

     case rvc_normal:
@@ -1022,7 +1050,13 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, co

     case MIN_EXPR:
       if (op1->cl == rvc_nan)
+      {
        *r = *op1;
+        /* Make resulting NaN value to be qNaN. The caller has the
+           responsibility to avoid the operation if flag_signaling_nans
+           is on.  */
+        r->signalling = 0;
+      }
       else if (do_compare (op0, op1, -1) < 0)
        *r = *op0;
       else
@@ -1031,7 +1065,13 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, co

     case MAX_EXPR:
       if (op1->cl == rvc_nan)
+      {
        *r = *op1;
+        /* Make resulting NaN value to be qNaN. The caller has the
+           responsibility to avoid the operation if flag_signaling_nans
+           is on.  */
+        r->signalling = 0;
+      }
       else if (do_compare (op0, op1, 1) < 0)
        *r = *op1;
       else
@@ -1162,6 +1202,10 @@ real_ldexp (REAL_VALUE_TYPE *r, const REAL_VALUE_T
     case rvc_zero:
     case rvc_inf:
     case rvc_nan:
+      /* Make resulting NaN value to be qNaN. The caller has the
+         responsibility to avoid the operation if flag_signaling_nans
+         is on.  */
+      r->signalling = 0;
       break;

     case rvc_normal:
@@ -1195,6 +1239,14 @@ real_isnan (const REAL_VALUE_TYPE *r)
   return (r->cl == rvc_nan);
 }

+/* Determine whether a floating-point value X is a signalling NaN.  */
+
+bool
+real_issignaling_nan (const REAL_VALUE_TYPE *r)
+{
+  return real_isnan (r) && r->signalling;
+}
+
 /* Determine whether a floating-point value X is finite.  */

 bool
@@ -4937,7 +4989,8 @@ real_copysign (REAL_VALUE_TYPE *r, const REAL_VALU
   r->sign = x->sign;
 }

-/* Check whether the real constant value given is an integer.  */
+/* Check whether the real constant value given is an integer.
+   Returns false for signalling NaN.  */

 bool
 real_isinteger (const REAL_VALUE_TYPE *c, format_helper fmt)
Index: gcc/real.h
===================================================================
--- gcc/real.h  (revision 229805)
+++ gcc/real.h  (working copy)
@@ -262,6 +262,9 @@ extern bool real_isinf (const REAL_VALUE_TYPE *);
 /* Determine whether a floating-point value X is a NaN.  */
 extern bool real_isnan (const REAL_VALUE_TYPE *);

+/* Determine whether a floating-point value X is a signalling NaN.  */
+extern bool real_issignaling_nan (const REAL_VALUE_TYPE *);
+
 /* Determine whether a floating-point value X is finite.  */
 extern bool real_isfinite (const REAL_VALUE_TYPE *);

@@ -357,6 +360,9 @@ extern const struct real_format arm_half_format;
 /* Determine whether a floating-point value X is a NaN.  */
 #define REAL_VALUE_ISNAN(x)            real_isnan (&(x))

+/* Determine whether a floating-point value X is a signalling NaN.  */
+#define REAL_VALUE_ISSIGNALING_NAN(x)  real_issignaling_nan (&(x))
+
 /* Determine whether a floating-point value X is negative.  */
 #define REAL_VALUE_NEGATIVE(x)         real_isneg (&(x))

Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c  (revision 229805)
+++ gcc/simplify-rtx.c  (working copy)
@@ -1789,16 +1789,25 @@ simplify_const_unary_operation (enum rtx_code code
          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 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 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 NaN.  */
+         if (!(HONOR_SNANS (mode) && REAL_VALUE_ISSIGNALING_NAN (d)))
+           real_arithmetic (&d, FIX_TRUNC_EXPR, &d, NULL);
          break;
        case NOT:
          {
@@ -3856,7 +3865,8 @@ simplify_const_binary_operation (enum rtx_code cod
          real_convert (&f1, mode, CONST_DOUBLE_REAL_VALUE (op1));

          if (HONOR_SNANS (mode)
-             && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
+             && (REAL_VALUE_ISSIGNALING_NAN (f0)
+                  || REAL_VALUE_ISSIGNALING_NAN (f1)))
            return 0;

          if (code == DIV
Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c    (revision 229805)
+++ gcc/tree-ssa-math-opts.c    (working copy)
@@ -1482,6 +1482,13 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
   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 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);
Index: gcc/testsuite/gcc.dg/pr61441.c
===================================================================
--- gcc/testsuite/gcc.dg/pr61441.c      (revision 0)
+++ gcc/testsuite/gcc.dg/pr61441.c      (working copy)
@@ -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;
+}



More information about the Gcc-patches mailing list