Bug 67052 - tree_single_nonnegative_warnv_p and fold_relational_const are inconsistent with NaNs
Summary: tree_single_nonnegative_warnv_p and fold_relational_const are inconsistent wi...
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization, wrong-code
Depends on:
Blocks:
 
Reported: 2015-07-29 09:03 UTC by Richard Biener
Modified: 2024-01-04 18:57 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Richard Biener 2015-07-29 09:03:05 UTC
int main ()
{
  double x = __builtin_nan ("");
  if (x < 0.0)
    return 1;
  return 0;
}

this simplifies via

      /* Convert ABS_EXPR<x> < 0 to false.  */
      strict_overflow_p = false;
      if (code == LT_EXPR
          && (integer_zerop (arg1) || real_zerop (arg1))
          && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
        {
          if (strict_overflow_p)
            fold_overflow_warning (("assuming signed overflow does not occur "
                                    "when simplifying comparison of "
                                    "absolute value and zero"),
                                   WARN_STRICT_OVERFLOW_CONDITIONAL);
          return omit_one_operand_loc (loc, type,
                                       constant_boolean_node (false, type),
                                       arg0);
        }

(the ABS_EXPR<x> >= 0 case is guarded with ! HONOR_NANS)

but not via constant folding in fold_relational_const.

bool
tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
{
...
    case REAL_CST:
      return ! REAL_VALUE_NEGATIVE (TREE_REAL_CST (t));

but

static tree
fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
{
...
      /* Handle the cases where either operand is a NaN.  */
      if (real_isnan (c0) || real_isnan (c1))
        {
...
            case LT_EXPR:
            case LE_EXPR:
            case GT_EXPR:
            case GE_EXPR:
            case LTGT_EXPR:
              if (flag_trapping_math)
                return NULL_TREE;

is this a missed optimization or wrong-code?
Comment 1 jsm-csl@polyomino.org.uk 2015-07-29 17:30:57 UTC
The uses of the *nonnegative* functions should be removed to determine 
what semantics are expected for for floating-point arguments.

If the semantics are "sign bit is 0", NaNs should return according to 
their sign bit (and -0 should return false).  If the semantics are "value
>= 0", NaNs should always return false, but -0 should return true.  If 
the semantics are "!(value < 0)", NaNs should return true, as should -0.  
It's possible different places expect different semantics.

>       /* Convert ABS_EXPR<x> < 0 to false.  */
>       strict_overflow_p = false;
>       if (code == LT_EXPR
>           && (integer_zerop (arg1) || real_zerop (arg1))
>           && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
>         {
>           if (strict_overflow_p)
>             fold_overflow_warning (("assuming signed overflow does not occur "
>                                     "when simplifying comparison of "
>                                     "absolute value and zero"),
>                                    WARN_STRICT_OVERFLOW_CONDITIONAL);
>           return omit_one_operand_loc (loc, type,
>                                        constant_boolean_node (false, type),
>                                        arg0);

Omitting an ordered NaN comparison with 0 also loses an exception (if 
flag_trapping_math && HONOR_NANS) (as does an equality comparison in the 
case of signaling NaNs).  (Modulo the unresolved discussion in the thread 
starting at 
<https://gcc.gnu.org/ml/gcc-patches/2015-02/threads.html#00555> of which 
sort of comparison LTGT should be, and so which existing code handling it 
the other way is buggy.)
Comment 2 jsm-csl@polyomino.org.uk 2015-07-29 17:33:05 UTC
(s/removed/reviewed/)
Comment 3 Richard Biener 2015-07-30 11:16:04 UTC
This means that the ABS_EXPR<x> < 0 code is correct in simplifying
NaN < 0 to true and it is correct to _not_ simplify NaN >= 0 to true.

But at the same time it has to do the same as fold_relational_const and
preserve traps with -ftrapping-math for the ordered compares.

So the following patch should fix the inconsistency and avoid the wrong-code
issue in the ABS_EXPR<x> < 0 folding:

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c    (revision 226387)
+++ gcc/fold-const.c    (working copy)
@@ -11634,7 +11455,9 @@ fold_binary_loc (location_t loc,
       /* Convert ABS_EXPR<x> < 0 to false.  */
       strict_overflow_p = false;
       if (code == LT_EXPR
-         && (integer_zerop (arg1) || real_zerop (arg1))
+         && (integer_zerop (arg1)
+             || ((! HONOR_NANS (arg0) || !flag_trapping_math)
+                 && real_zerop (arg1)))
          && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
        {
          if (strict_overflow_p)