diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 7b26896..f7f174d 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -15076,16 +15076,27 @@ tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0, break; case MULT_EXPR: - if (FLOAT_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) + if (FLOAT_TYPE_P (type)) { - /* x * x is always non-negative for floating point x - or without overflow. */ + /* x * x is non-negative for floating point x except + that -NaN*-NaN may return -NaN. PR middle-end/111701. */ + if (operand_equal_p (op0, op1, 0)) + { + if (!tree_expr_maybe_signaling_nan_p (op0) || RECURSE (op0)) + return true; + } + else if (RECURSE (op0) && RECURSE (op1)) + return true; + } + + if (ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_UNDEFINED (type)) + { + /* x * x is always non-negative without overflow. */ if (operand_equal_p (op0, op1, 0) || (RECURSE (op0) && RECURSE (op1))) { - if (ANY_INTEGRAL_TYPE_P (type) - && TYPE_OVERFLOW_UNDEFINED (type)) - *strict_overflow_p = true; + *strict_overflow_p = true; return true; } } diff --git a/gcc/testsuite/gcc.dg/pr111701-1.c b/gcc/testsuite/gcc.dg/pr111701-1.c new file mode 100644 index 0000000..5cbfac2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111701-1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fsignaling-nans -fdump-tree-optimized" } */ + +int foo(double x) +{ + return __builtin_signbit(x*x); +} + +int bar(float x) +{ + return __builtin_signbit(x*x); +} + +/* { dg-final { scan-tree-dump-times " \\* " 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr111701-2.c b/gcc/testsuite/gcc.dg/pr111701-2.c new file mode 100644 index 0000000..f79c7ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr111701-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(double x) +{ + return __builtin_signbit(x*x); +} + +int bar(float x) +{ + return __builtin_signbit(x*x); +} + +/* { dg-final { scan-tree-dump-not " \\* " "optimized" } } */