===================================================================
@@ -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:
===================================================================
@@ -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. */
===================================================================
@@ -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. */
===================================================================
@@ -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
===================================================================
@@ -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)
===================================================================
@@ -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))
===================================================================
@@ -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
===================================================================
@@ -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);
===================================================================
@@ -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;
+}