aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSujoy Saraswati <sujoy.saraswati@hpe.com>2015-12-22 14:04:30 +0000
committerSujoy Saraswati <ssaraswati@gcc.gnu.org>2015-12-22 14:04:30 +0000
commit5a00b0aaf036edadc48861b91d3804796525c2d5 (patch)
treeb911e1bd2a2f7a4a924f976f2156da6ea60dc25c
parent9643ce888b6634d4f6c44ad3c48bd105f38474e8 (diff)
downloadgcc-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/ChangeLog27
-rw-r--r--gcc/fold-const-call.c20
-rw-r--r--gcc/fold-const.c44
-rw-r--r--gcc/gimple-fold.c8
-rw-r--r--gcc/simplify-rtx.c39
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/pr61441.c61
-rw-r--r--gcc/tree-ssa-math-opts.c7
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);