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 <ssarasw...@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; +}