Commit 5a00b0aa by Sujoy Saraswati Committed by Sujoy Saraswati

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
parent 9643ce88
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> 2015-12-22 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* combine.c (simplify_comparison): Convert preprocessor check of * combine.c (simplify_comparison): Convert preprocessor check of
...@@ -512,7 +512,11 @@ fold_const_pow (real_value *result, const real_value *arg0, ...@@ -512,7 +512,11 @@ fold_const_pow (real_value *result, const real_value *arg0,
|| !real_equal (arg0, &dconst0))) || !real_equal (arg0, &dconst0)))
{ {
bool inexact = real_powi (result, format, arg0, n1); 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; return true;
} }
...@@ -541,6 +545,13 @@ fold_const_builtin_load_exponent (real_value *result, const real_value *arg0, ...@@ -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)) if (wi::les_p (arg1, -max_exp_adj) || wi::ges_p (arg1, max_exp_adj))
return false; 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_VALUE_TYPE initial_result;
real_ldexp (&initial_result, arg0, arg1.to_shwi ()); real_ldexp (&initial_result, arg0, arg1.to_shwi ());
...@@ -1202,6 +1213,13 @@ fold_const_call_sss (real_value *result, combined_fn fn, ...@@ -1202,6 +1213,13 @@ fold_const_call_sss (real_value *result, combined_fn fn,
format)); format));
CASE_CFN_POWI: 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 ()); real_powi (result, format, arg0, arg1.to_shwi ());
return true; return true;
......
...@@ -1166,9 +1166,21 @@ const_binop (enum tree_code code, tree arg1, tree arg2) ...@@ -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 /* If either operand is a NaN, just return it. Otherwise, set up
for floating-point trap; we return an overflow. */ for floating-point trap; we return an overflow. */
if (REAL_VALUE_ISNAN (d1)) 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)) 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); inexact = real_arithmetic (&value, code, &d1, &d2);
real_convert (&result, mode, &value); real_convert (&result, mode, &value);
...@@ -1538,6 +1550,15 @@ const_binop (enum tree_code code, tree type, tree arg1, tree arg2) ...@@ -1538,6 +1550,15 @@ const_binop (enum tree_code code, tree type, tree arg1, tree arg2)
tree tree
const_unop (enum tree_code code, tree type, tree arg0) 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) switch (code)
{ {
CASE_CONVERT: CASE_CONVERT:
...@@ -1949,6 +1970,12 @@ fold_convert_const_real_from_real (tree type, const_tree arg1) ...@@ -1949,6 +1970,12 @@ fold_convert_const_real_from_real (tree type, const_tree arg1)
REAL_VALUE_TYPE value; REAL_VALUE_TYPE value;
tree t; 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)); real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
t = build_real (type, value); t = build_real (type, value);
...@@ -13414,7 +13441,7 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p) ...@@ -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 /* 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 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. */ 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) ...@@ -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 /* 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 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. */ 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) ...@@ -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 /* 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 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, considered integer values. Return false for signaling NaN. If FNDECL
the remaining ARGn are null. takes fewer than 2 arguments, the remaining ARGn are null.
DEPTH is the current nesting depth of the query. */ 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) ...@@ -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) /* 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 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. */ DEPTH is the current nesting depth of the query. */
...@@ -13535,7 +13562,7 @@ integer_valued_real_single_p (tree t, int depth) ...@@ -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) /* 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 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. */ DEPTH is the current nesting depth of the query. */
...@@ -13563,6 +13590,7 @@ integer_valued_real_invalid_p (tree t, int depth) ...@@ -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. /* Return true if the floating point expression T has an integer value.
We also allow +Inf, -Inf and NaN to be considered integer values. 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. */ DEPTH is the current nesting depth of the query. */
......
...@@ -6267,7 +6267,7 @@ gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p, ...@@ -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 /* 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 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. */ DEPTH is the current nesting depth of the query. */
...@@ -6296,7 +6296,7 @@ gimple_assign_integer_valued_real_p (gimple *stmt, int depth) ...@@ -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 /* 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 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. */ DEPTH is the current nesting depth of the query. */
...@@ -6315,7 +6315,7 @@ gimple_call_integer_valued_real_p (gimple *stmt, int depth) ...@@ -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 /* 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 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. */ DEPTH is the current nesting depth of the query. */
...@@ -6333,7 +6333,7 @@ gimple_phi_integer_valued_real_p (gimple *stmt, int depth) ...@@ -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 /* 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 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. */ DEPTH is the current nesting depth of the query. */
......
...@@ -1703,6 +1703,12 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode, ...@@ -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); 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); d = real_value_truncate (mode, d);
return const_double_from_real_value (d, mode); return const_double_from_real_value (d, mode);
} }
...@@ -1721,6 +1727,12 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode 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); 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); d = real_value_truncate (mode, d);
return const_double_from_real_value (d, mode); return const_double_from_real_value (d, mode);
} }
...@@ -1825,16 +1837,25 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode, ...@@ -1825,16 +1837,25 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
d = real_value_negate (&d); d = real_value_negate (&d);
break; break;
case FLOAT_TRUNCATE: 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; break;
case FLOAT_EXTEND: case FLOAT_EXTEND:
/* All this does is change the mode, unless changing /* All this does is change the mode, unless changing
mode class. */ 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); real_convert (&d, mode, &d);
break; break;
case FIX: 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; break;
case NOT: case NOT:
{ {
...@@ -3886,16 +3907,20 @@ simplify_const_binary_operation (enum rtx_code code, machine_mode mode, ...@@ -3886,16 +3907,20 @@ simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
else else
{ {
REAL_VALUE_TYPE f0, f1, value, result; REAL_VALUE_TYPE f0, f1, value, result;
const REAL_VALUE_TYPE *opr0, *opr1;
bool inexact; bool inexact;
real_convert (&f0, mode, CONST_DOUBLE_REAL_VALUE (op0)); opr0 = CONST_DOUBLE_REAL_VALUE (op0);
real_convert (&f1, mode, CONST_DOUBLE_REAL_VALUE (op1)); opr1 = CONST_DOUBLE_REAL_VALUE (op1);
if (HONOR_SNANS (mode) if (HONOR_SNANS (mode)
&& (REAL_VALUE_ISSIGNALING_NAN (f0) && (REAL_VALUE_ISSIGNALING_NAN (*opr0)
|| REAL_VALUE_ISSIGNALING_NAN (f1))) || REAL_VALUE_ISSIGNALING_NAN (*opr1)))
return 0; return 0;
real_convert (&f0, mode, opr0);
real_convert (&f1, mode, opr1);
if (code == DIV if (code == DIV
&& real_equal (&f1, &dconst0) && real_equal (&f1, &dconst0)
&& (flag_trapping_math || ! MODE_HAS_INFINITIES (mode))) && (flag_trapping_math || ! MODE_HAS_INFINITIES (mode)))
......
2015-12-22 Sujoy Saraswati <sujoy.saraswati@hpe.com>
* gcc.dg/pr61441.c: New testcase.
2015-12-22 Eric Botcazou <ebotcazou@adacore.com> 2015-12-22 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/torture/pr68264.c: Tweak for Solaris. * gcc.dg/torture/pr68264.c: Tweak for Solaris.
......
/* { 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;
}
...@@ -1535,6 +1535,13 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc, ...@@ -1535,6 +1535,13 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
if (TREE_CODE (arg1) != REAL_CST) if (TREE_CODE (arg1) != REAL_CST)
return NULL_TREE; 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 /* If the exponent is equivalent to an integer, expand to an optimal
multiplication sequence when profitable. */ multiplication sequence when profitable. */
c = TREE_REAL_CST (arg1); c = TREE_REAL_CST (arg1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment