https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107569

--- Comment #11 from Aldy Hernandez <aldyh at gcc dot gnu.org> ---
(In reply to Andrew Macleod from comment #5)
> (In reply to Jakub Jelinek from comment #4)
> > The cdce case is something I've mentioned today:
> > https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605338.html
> > The comparisons in there are artificial and so unlike user comparisons we
> > should (if they were marked somehow) be able to optimize them away if frange
> > can prove their result.
> > But that isn't something happening on the #c0 testcase, is it?
> 
> in vrp2 I see:
> 384      range_of_stmt () at stmt if (_9 u>= 0.0)
> 385        range_of_expr(_9) at stmt if (_9 u>= 0.0)
>            TRUE : (385) range_of_expr (_9) [frange] double [-0.0
> (-0x0.0p+0), +Inf] +-NAN
>          TRUE : (384) range_of_stmt () [irange] bool VARYING
> 
> so we think that 
> [frange] double [-0.0 (-0x0.0p+0), +Inf] +-NAN  u>=   0.0  does not fold.  
> 
> possibly some signalling NaN thing not allowing us to remove it?

By vrp2 I see:

=========== BB 2 ============
Imports: _6  _8  
Exports: _6  _8  _9  
         _9 : _6(I)  _8(I)  
    <bb 2> [local count: 1073741824]:
    _3 = u_2(D)->x;
    _6 = _3 * _3;
    _7 = u_2(D)->y;
    _8 = _7 * _7;
    _9 = _6 + _8;
    if (_9 u>= 0.0)
      goto <bb 3>; [99.95%]
    else
      goto <bb 4>; [0.05%]

_9 : [frange] double [-0.0 (-0x0.0p+0), +Inf] +-NAN
2->4  (F) _9 :  [frange] double [-0.0 (-0x0.0p+0), 0.0 (0x0.0p+0)]
2->3  (T) _9 :  [frange] double [-0.0 (-0x0.0p+0), +Inf] +-NAN

We can't fold the u>= 0.0 because that would remove a possible NAN at runtime,
and it would be user-visible for signalling NANs.  At least, that's been my
understanding all along.  You'll notice most of folding of relops in
range-op-float.cc is predicated by !maybe_isnan(op1, op2) to disable them if
NAN is a possibility, which in the case of _9 could happen:

  else if (!maybe_isnan (op1, op2))
    {
      if (real_compare (GE_EXPR, &op1.lower_bound (), &op2.upper_bound ()))
        r = range_true (type);
      else if (!real_compare (GE_EXPR, &op1.upper_bound (), &op2.lower_bound
()))
        r = range_false (type);
      else
        r = range_true_and_false (type);
    }

However, we should be able to mark that the 2->4 edge as undefined.  For
example, on the 2->4 edge, _9 is technically UNDEFINED.  But we can't do that
because frange's are represented as closed intervals, so we can't represent <
0.0 on the false side.  Instead we represent it as +-0.0 which intersected with
_9 is still +-0.0.

If we could represent < 0.0 with one less ulp, say -0.000000000000001 (or
whatever), intersecting that with the known _9 would yield UNDEFINED.  I don't
know if that would help in this PR, but ISTM the threader would be able to do
something (or some other pass??).

Unfortunately, we don't represent < and > very well.  Technically all we would
need is to tweak range-op-float.cc's build_gt() and build_lt() to do
real_nexafter, but as with everything FP, the devil is in the details (what do
we do when we go past the representable range for -ffinite-math-only, etc etc).
 It does seem a bit late in the cycle to fudge with this, but it is possible.

Again, I don't know if this helps the PR, but these are the 2 issues I see.

Reply via email to