Re: [PATCH] [frange] Implement set_nonzero and nonzero_p.
Richard Biener <[email protected]> Wed, 5 Aug 2026 09:09:01 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAFiYyc0dWF_oYKiOicQ=ezQ0N5PD5faSmwzUbMR8YJbMZeQLiQ@mail.gmail.com> |
On Tue, Aug 4, 2026 at 3:12=E2=80=AFPM Andrew MacLeod <[email protected]>= wrote: > > > On 8/3/26 09:09, Aldy Hernandez wrote: > > [Jakub, Richi, Andrew, etc: Does anyone remember the reason for this > > craziness? Should we revisit what vrange::nonzero_p() does, or will > > this mess up the ranger's cache or something I'm not aware of?] > > > > Excluding an interval is now expressible, and excluding zero is just > > the [-0.0, +0.0] case of it, so say so. > > > > For some stupid historical reason which I can't remember, the irange > > and prange nonzero_p() predicates returns true only for ~[0,0], so > > even [5,5] returns false. When we want to test whether a range > > contains a zero, we usually use the contains_p() idiom. I think this > > is idotic, but perhaps there is a reason for it. > > > It was historical.. probably related to pointers. > > I have no issues with changing it, it certainly can be confusing... It > would require changing existing uses, and then finding all the places > where we use the !contains_p(zero) version. > > Perhaps part of the problem is that it is ambiguous anyway.. perhaps it > would be much clearer to simply introduce a contains_zero_p () method. > thats seems better to me. > > We could also audit the existing nonzero_p () uses and see if there > might be a better name, or even a real need for it.. There is no sense in a query for exactly ~[0, 0] give ranges conservatively error on the wider side. So asking for ~[0, 0] but not accepting ~[0, 0] intersected with ~[5, 5] doesn't make sense. So IMO no ambiguity here. Richard. > > Andrew > > > > > I've implemented the frange version the same way, with the wrinkle > > that the constructor for ~[-0.0, +0.0] includes the possibility of > > +-NAN, which means that nonzero_p() must ignore the NAN bits, > > otherwise anything but a strict ~[-0.0, +0.0] +-NAN would return > > false. For example, this: > > > > x =3D frange(0.0, VR_ANTI_RANGE); > > x.clear_nan(); > > x.nonzero_p(); <-- would return false > > > > Tested on ppc64le Linux: regstrap and LAPACK. Surprisingly there are > > no changes to generated output in my Fortran files, presumably because > > intersect/union are enough to fold inequalities away, and also because > > there are no callers to nonzero_p() for frange. Every nonzero_p() > > call is guarded by prange or irange checks, but it's nice to > > implement these since they are pure virtuals from the base vrange > > class. > > > > Pushed. > > > > p.s. This concludes the multi-range frange work, sans the > > range-op-float.cc tidbit Jakub pointed out. > > > > gcc/ChangeLog: > > > > * value-range.cc (frange::set_nonzero): Implement. > > (frange::nonzero_p): Implement. > > (range_tests_excluding): Test set_nonzero and nonzero_p. > > --- > > gcc/value-range.cc | 41 +++++++++++++++++++++++++++++++++++++---- > > 1 file changed, 37 insertions(+), 4 deletions(-) > > > > diff --git a/gcc/value-range.cc b/gcc/value-range.cc > > index b4c097343d9..69d89f34227 100644 > > --- a/gcc/value-range.cc > > +++ b/gcc/value-range.cc > > @@ -1685,18 +1685,35 @@ frange::verify_range () const > > || !frange_val_is_max (m_pairs[0].max, m_type)); > > } > > > > -// We can't do much with nonzeros yet. > > void > > frange::set_nonzero (tree type) > > { > > - set_varying (type); > > + set (type, dconstm0, dconst0, VR_ANTI_RANGE); > > } > > > > -// We can't do much with nonzeros yet. > > +// Return TRUE when this range is exactly the "everything but zero" se= t that > > +// set_nonzero builds, mirroring irange::nonzero_p. Callers wanting "= does not > > +// contain zero" should use the !contains_p (0) idiom. > > +// > > +// A NAN is not a zero, so nonzero-ness depends only on the intervals,= not on > > +// whether the range may also be a NAN. We therefore recognize the no= nzero > > +// range by comparing intervals against set_nonzero's with the NAN sta= te > > +// ignored. A strict *this =3D=3D set_nonzero () would be wrong: set_= nonzero > > +// leaves the NAN able to be either sign, so a range that is otherwise= exactly > > +// nonzero but whose NAN has been cleared would compare unequal. > > + > > bool > > frange::nonzero_p () const > > { > > - return false; > > + if (undefined_p () || known_isnan ()) > > + return false; > > + > > + frange nz; > > + nz.set_nonzero (type ()); > > + nz.clear_nan (); > > + frange tmp =3D *this; > > + tmp.clear_nan (); > > + return tmp =3D=3D nz; > > } > > > > // Set range to [+0.0, +0.0] if honoring signed zeros, or [0.0, 0.0] > > @@ -3826,11 +3843,27 @@ range_tests_sub_ranges_zero () > > ASSERT_TRUE (r0.contains_p (real_from_str ("-1.0"))); > > > > // Excluding zero from [-0.0, 5.0] eats the lower end entirely. > > + r0.set_nonzero (float_type_node); > > + ASSERT_TRUE (r0.nonzero_p ()); > > + ASSERT_FALSE (r0.contains_p (dconst0)); > > + ASSERT_FALSE (r0.contains_p (dconstm0)); > > + > > + // A NAN is not a zero, so clearing the NAN leaves a nonzero range n= onzero. > > + r0.clear_nan (); > > + ASSERT_TRUE (r0.nonzero_p ()); > > + > > + // A range that merely avoids zero is not the nonzero range. > > + r0 =3D frange_float ("1.0", "10.0"); > > + ASSERT_FALSE (r0.nonzero_p ()); > > + > > + // Excluding zero from [-0.0, 5.0] leaves (0, 5]: it avoids zero but= is not > > + // the whole nonzero range. > > r0 =3D frange_float ("-0.0", "5.0"); > > r0.clear_nan (); > > r1 =3D frange_float_excluding ("0.0"); > > r0.intersect (r1); > > ASSERT_EQ (r0.num_pairs (), 1); > > + ASSERT_FALSE (r0.nonzero_p ()); > > ASSERT_FALSE (r0.contains_p (dconst0)); > > ASSERT_FALSE (r0.contains_p (dconstm0)); > > ASSERT_TRUE (r0.contains_p (real_from_str ("5.0"))); >