diff options
author | Sujoy Saraswati <sujoy.saraswati@hpe.com> | 2015-12-22 14:04:30 +0000 |
---|---|---|
committer | Sujoy Saraswati <ssaraswati@gcc.gnu.org> | 2015-12-22 14:04:30 +0000 |
commit | 5a00b0aaf036edadc48861b91d3804796525c2d5 (patch) | |
tree | b911e1bd2a2f7a4a924f976f2156da6ea60dc25c | |
parent | 9643ce888b6634d4f6c44ad3c48bd105f38474e8 (diff) | |
download | gcc-5a00b0aaf036edadc48861b91d3804796525c2d5.zip gcc-5a00b0aaf036edadc48861b91d3804796525c2d5.tar.gz gcc-5a00b0aaf036edadc48861b91d3804796525c2d5.tar.bz2 |
This series of patches fix PR61441.
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
-rw-r--r-- | gcc/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/fold-const-call.c | 20 | ||||
-rw-r--r-- | gcc/fold-const.c | 44 | ||||
-rw-r--r-- | gcc/gimple-fold.c | 8 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 39 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr61441.c | 61 | ||||
-rw-r--r-- | gcc/tree-ssa-math-opts.c | 7 |
8 files changed, 190 insertions, 20 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b314c1a..134e4fb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index 94801d2..7d1351c 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -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; diff --git a/gcc/fold-const.c b/gcc/fold-const.c index fff0285..5ad5112 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -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. */ diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 6f8ec6f..eddb18d 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -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. */ diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 225742e..44de1555 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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))) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 04d48b8..d5c679e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 index 0000000..608a763 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr61441.c @@ -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; +} diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index b00f046..244cf19 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -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); |