On Fri, Jun 21, 2019 at 1:41 PM Aldy Hernandez <al...@redhat.com> wrote:
>
> Hi Richard.  Hi folks.
>
> In order to unify the APIs for value_range and irange, we'd like to make
> some minor changes to value_range.  We believe most of these changes
> could go in now, and would prefer so, to get broader testing and
> minimize the plethora of changes we drag around on our branch.
>
> First, introduce a type for VR_VARYING and VR_UNDEFINED.
> --------------------------------------------------------
>
> irange utilizes 0 or more sub-ranges to represent a range, and VARYING
> is simply one subrange [MIN, MAX].    value_range represents this with
> VR_VARYING, and since there is no type associated with it, we cannot
> calculate the lower and upper bounds for the range.  There is also a
> lack of canonicalness in value range in that VR_VARYING and [MIN, MAX]
> are two different representations of the same value.
>
> We tried to adjust irange to not associate a type with the empty range
> [] (representing undefined), but found we were unable to perform all
> operations properly.  In particular, we cannot invert an empty range.
> i.e. invert ( [] ) should produce [MIN, MAX].  Again, we need to have a
> type associated with this empty range.
>
> We'd like to tweak value_range so that set_varying() and set_undefined()
> both take a type, and then always set the min/max fields based on that
> type.  This takes no additional memory in the structure, and is
> virtually transparent to all the existing uses of value_range.
>
> This allows:
>    1)  invert to be implemented properly for both VARYING and UNDEFINED
> by simply changing one to the other.
>    2)  the type() method to always work without any special casing by
> simply returning TREE_TYPE(min)
>    3)  the new incoming bounds() routines to work trivially for these
> cases as well (lbound/ubound, num_pairs(), etc).
>
> This functionality is provided in the first attached patch.
>
> Note, the current implementation sets min/max to TREE_TYPE, not to
> TYPE_MIN/MAX_VALUE.  We can fix this if preferred.

How does this work with

value_range *
vr_values::get_value_range (const_tree var)
{
  static const value_range vr_const_varying (VR_VARYING, NULL, NULL);
...
  /* If we query the range for a new SSA name return an unmodifiable VARYING.
     We should get here at most from the substitute-and-fold stage which
     will never try to change values.  */
  if (ver >= num_vr_values)
    return CONST_CAST (value_range *, &vr_const_varying);

?

> Second, enforce canonicalization at value_range build time.
> -----------------------------------------------------------
>
> As discussed above, value_range has multiple representations for the
> same range.  For instance, ~[0,0] is the same as [1,MAX] in unsigned and
> [MIN, MAX] is really varying, among others.  We found it quite difficult
> to make things work, with multiple representations for a given range.
> Canonicalizing at build time solves this, as well as removing explicit
> set_and_canonicalize() calls throughout.  Furthermore, it avoids some
> special casing in VRP.
>
> Along with canonicalizing, we also enforce the existing value_range API
> more strongly.  For instance, we don't allow setting equivalences for
> either VR_VARYING or VR_UNDEFINED.
>
> This functionality is provided in the second patch.

Fair enough.  Didn't look at the patch yet, sending separate mails would have
been prefered - or are the patches not independent of each other?  Note
canonicalization performs quite some work so a shortcut
set () with just checking the input is already canonicalized would be nice?

I wonder you still have anti-ranges since you can handle > 1 subranges
in ranger?

> Third, irange on value_range implementation.
> ---------------------------------------------
>
> The third attached patch shows how we use the above two to implement
> irange using value_ranges.  value_range would be a drop-in replacement
> for irange, by just doing the following in range.h:
>
> +// Enable this to implement irange piggybacking on value_range.
> +#define IRANGE_WITH_VALUE_RANGE 1
> +
> +#if IRANGE_WITH_VALUE_RANGE
> +#include "tree-vrp.h"
> +typedef value_range_base irange;
> +typedef value_range_storage irange_storage;
> +#define IRANGE_PLAIN VR_RANGE
> +#define IRANGE_INVERSE VR_ANTI_RANGE
> +#else
> ...
>
> The additions to the value_range API would be mostly the following (full
> details in the third attached patch):
>
> +  value_range_base (tree, tree);
> +  value_range_base (value_range_kind,
> +                   tree type, const wide_int &, const wide_int &);
> +  value_range_base (tree type, const wide_int &, const wide_int &);
> +  value_range_base (tree type, const value_range_storage *);
> +  value_range_base (tree type);
>
>     void set (value_range_kind, tree, tree);
>     void set (tree);
> @@ -77,7 +86,25 @@ public:
>     bool singleton_p (tree *result = NULL) const;
>     void dump (FILE *) const;
>
> +  /* Support machinery for irange.  */
> +  static const unsigned int m_max_pairs = 2;
> +  static bool supports_type_p (tree type);
> +  static bool supports_ssa_p (tree ssa);
> +  static bool supports_p (tree expr);
> +  void cast (tree);
> +  bool contains_p (tree) const;
> +  unsigned num_pairs () const;
> +  wide_int lower_bound (unsigned = 0) const;
> +  wide_int upper_bound (unsigned) const;
> +  wide_int upper_bound () const;
> +  void invert ();
> +  void dump () const { dump (stderr); }
> +  // FIXME: Perhaps rewrite the irange versions to use pointers instead.
> +  void union_ (const value_range_base &);
> +  void intersect (const value_range_base &);
> +
>   protected:
> +  value_range_base normalize_symbolics () const;
>
> There are no regressions from mainline, and we are catching every one of
> our internal ranger tests, with the exception of two that require more
> than 2 sub-ranges to work.  i.e. Not a regression from mainline-- just
> new functionality we can't get with the limited sub-ranges in value_range.
>
> Note: Please ignore the value_range_base::normalize_symbolics stuff.
> It's likely to go through multiple revisions as Andrew gets the ranger
> to deal with symbolics.
>
> Finally
> -------
>
> All these patches are already in our branch, and irange with value_range
> can be enabled by #define IRANGE_WITH_VALUE_RANGE 1.
>
> With these changes, we can successfully build and run the ranger branch
> using value_range in place of irange, which indicates a successful API
> merge.
>
> After some minor cleanups, I would like to contribute at least the first
> two patches to trunk (VARYING types and the enforced canonicalization).
> This will enable us to move forward with trying to integrate the
> range-ops code which makes heavy use of the subrange interface, and
> allows for broader testing instead of dropping everything in one-go.
> These two patches stand on their own independently, and IMO provide
> useful functionality right now.

Works for me.  Please send any such patches separately (after cleanup)

> I would ideally like to contribute the third patch to mainline, but I do
> understand that it currently has no users... although I could rewrite
> bits of tree-vrp to use these new functions (lower_bound, upper_bound,
> etc), thus providing a use case ??.  However, I do understand if you'd
> prefer to keep this last patch on the branch.

I'd prefer to keep the last one on the branch indeed.

Richard.

> Thoughts?
>
> Aldy (and Andrew)

Reply via email to