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.