public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 00/23] prange: pointer ranges
@ 2024-05-04  8:30 Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP Aldy Hernandez
                   ` (22 more replies)
  0 siblings, 23 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

This patchset implements prange, a range class for pointers.

This is meant to be a drop-in replacement for pointer ranges, so we
can pull them out of irange, simplifying both irange and prange in the
process.  Initially we have two integer endpoints and the usual
value/mask bitmasks as this is how irange currently implements them,
but the end goal is to provide points-to info to replace the hacky
pointer equivalency we do in class pointer_equiv_analyzer.

I have split up the patchset into tiny pieces to make it easier to
track any problems.  I have also disabled it by default, choosing to
wait a few days until the dust has settled.  In a few days I will
throw the switch enabling pranges, which will make it invalid for
irange's to hold pointers.  Once pranges are enabled, I will do some
minor cleanups like removing pointer support from range-ops, etc.

The performance of prange is a wash for VRP and a 7% improvement for
IPA-cp.  This is taking into account the unrelated 2% hit we take due to
inlining as discussed here:

https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html

Also, as part of this work, we improved VRP by 6% (on top of the above
numbers):

https://gcc.gnu.org/pipermail/gcc-patches/2024-May/650320.html

So things are looking relatively good.

The memory usage will also decrease, both by the 14% reduction in
Value_Range, and by prange's being smaller than say int_range_max or
int_range<3>.

Tested and benchmarked on x86-64 Linux.

Aldy Hernandez (23):
  Minimal prange class showing inlining degradation to VRP.
  Implement basic prange class.
  Add streaming support for prange.
  Add storage support for prange.
  Add hashing support for prange.
  Add prange implementation for get_legacy_range.
  Implement range-op dispatch for prange.
  Implement operator_identity for prange.
  Implement operator_cst for prange.
  Implement operator_cast for prange.
  Implement operator_min and operator_max for prange.
  Implement operator_addr_expr for prange.
  Implement pointer_plus_operator for prange.
  Implement operator_pointer_diff for prange.
  Implement operator_bitwise_and for prange.
  Implement operator_bitwise_or for prange.
  Implement operator_not_equal for prange.
  Implement operator_equal for prange.
  Implement operator_lt for prange.
  Implement operator_le for prange.
  Implement operator_gt for prange.
  Implement operator_ge for prange....
  Add prange entries in gimple-range-op.cc.

 gcc/data-streamer-in.cc         |   12 +
 gcc/data-streamer-out.cc        |   10 +
 gcc/gimple-range-op.cc          |   36 +
 gcc/range-op-mixed.h            |  156 ++++
 gcc/range-op-ptr.cc             | 1545 +++++++++++++++++++++++++++++++
 gcc/range-op.cc                 |  124 +++
 gcc/range-op.h                  |  111 +++
 gcc/value-range-pretty-print.cc |   25 +
 gcc/value-range-pretty-print.h  |    1 +
 gcc/value-range-storage.cc      |  117 +++
 gcc/value-range-storage.h       |   33 +
 gcc/value-range.cc              |  354 ++++++-
 gcc/value-range.h               |  214 ++++-
 13 files changed, 2730 insertions(+), 8 deletions(-)

-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 02/23] Implement basic prange class Aldy Hernandez
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

There is a 2% slowdown to VRP unrelated to the work at hand.  This patch
is a skeleton implementation of prange that exhibits this degradation.  It
is meant as a place in the commit history we can return to in order to revisit
the issue.

The relevant discussion is here:

https://gcc.gnu.org/pipermail/gcc/2024-May/243898.html

gcc/ChangeLog:

	* value-range.h (class prange): New.

---
 gcc/value-range.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/gcc/value-range.h b/gcc/value-range.h
index 934eec9e386..f52d5165707 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -378,6 +378,39 @@ private:
   wide_int m_ranges[N*2];
 };
 
+class prange : public vrange
+{
+public:
+  static bool supports_p (const_tree) { return false; }
+  virtual bool supports_type_p (const_tree) const final override { return false; }
+  virtual void accept (const vrange_visitor &) const final override {}
+  virtual void set_undefined () final override {}
+  virtual void set_varying (tree) final override {}
+  virtual void set_nonzero (tree) final override {}
+  virtual void set_zero (tree) final override;
+  virtual void set_nonnegative (tree) final override {}
+  virtual bool contains_p (tree) const final override { return false; }
+  virtual bool fits_p (const vrange &) const final override { return false; }
+  virtual bool singleton_p (tree * = NULL) const final override { return false; }
+  virtual bool zero_p () const final override { return false; }
+  virtual bool nonzero_p () const final override { return false; }
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) final override {}
+  virtual tree type () const final override { return NULL; }
+  virtual bool union_ (const vrange &) final override { return false; }
+  virtual bool intersect (const vrange &) final override { return false; }
+  virtual tree lbound () const final override { return NULL; }
+  virtual tree ubound () const final override { return NULL; }
+
+  wide_int lower_bound () const;
+  wide_int upper_bound () const;
+  irange_bitmask get_bitmask () const final override;
+  void update_bitmask (const irange_bitmask &) final override {}
+private:
+  wide_int m_min;
+  wide_int m_max;
+  irange_bitmask m_bitmask;
+};
+
 // Unsupported temporaries may be created by ranger before it's known
 // they're unsupported, or by vr_values::get_value_range.
 
@@ -1187,6 +1220,32 @@ irange_val_max (const_tree type)
   return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
 }
 
+inline void
+prange::set_zero (tree type)
+{
+  wide_int zero = wi::zero (TYPE_PRECISION (type));
+  m_min = m_max = zero;
+  m_bitmask = irange_bitmask (zero, zero);
+}
+
+inline wide_int
+prange::lower_bound () const
+{
+  return m_min;
+}
+
+inline wide_int
+prange::upper_bound () const
+{
+  return m_max;
+}
+
+inline irange_bitmask
+prange::get_bitmask () const
+{
+  return m_bitmask;
+}
+
 inline
 frange::frange ()
   : vrange (VR_FRANGE)
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 02/23] Implement basic prange class.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 03/23] Add streaming support for prange Aldy Hernandez
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

This provides a bare prange class with bounds and bitmasks.  It will
be a drop-in replacement for pointer ranges, so we can pull their
support from irange.  The range-op code will be contributed as a
follow-up.

The code is disabled by default, as irange::supports_p still accepts
pointers:

inline bool
irange::supports_p (const_tree type)
{
  return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
}

Once the prange operators are implemented in range-ops, pointer
support will be removed from irange to activate pranges.

gcc/ChangeLog:

	* value-range-pretty-print.cc (vrange_printer::visit): New.
	* value-range-pretty-print.h: Declare prange visit() method.
	* value-range.cc (vrange::operator=): Add prange support.
	(vrange::operator==): Same.
	(prange::accept): New.
	(prange::set_nonnegative): New.
	(prange::set): New.
	(prange::contains_p): New.
	(prange::singleton_p): New.
	(prange::lbound): New.
	(prange::ubound): New.
	(prange::union_): New.
	(prange::intersect): New.
	(prange::operator=): New.
	(prange::operator==): New.
	(prange::invert): New.
	(prange::verify_range): New.
	(prange::update_bitmask): New.
	(range_tests_misc): Use prange.
	* value-range.h (enum value_range_discriminator): Add VR_PRANGE.
	(class prange): New.
	(Value_Range::init): Add prange support.
	(Value_Range::operator=): Same.
	(Value_Range::supports_type_p): Same.
	(prange::prange):  New.
	(prange::supports_p): New.
	(prange::supports_type_p): New.
	(prange::set_undefined): New.
	(prange::set_varying): New.
	(prange::set_nonzero): New.
	(prange::set_zero): New.
	(prange::contains_p): New.
	(prange::zero_p): New.
	(prange::nonzero_p): New.
	(prange::type): New.
	(prange::lower_bound): New.
	(prange::upper_bound): New.
	(prange::varying_compatible_p): New.
	(prange::get_bitmask): New.
	(prange::fits_p): New.
---
 gcc/value-range-pretty-print.cc |  25 +++
 gcc/value-range-pretty-print.h  |   1 +
 gcc/value-range.cc              | 303 +++++++++++++++++++++++++++++++-
 gcc/value-range.h               | 199 ++++++++++++++++++---
 4 files changed, 500 insertions(+), 28 deletions(-)

diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc
index b6d23dce6d2..b11d6494774 100644
--- a/gcc/value-range-pretty-print.cc
+++ b/gcc/value-range-pretty-print.cc
@@ -112,6 +112,31 @@ vrange_printer::visit (const irange &r) const
   print_irange_bitmasks (pp, r.m_bitmask);
 }
 
+void
+vrange_printer::visit (const prange &r) const
+{
+  pp_string (pp, "[prange] ");
+  if (r.undefined_p ())
+    {
+      pp_string (pp, "UNDEFINED");
+      return;
+    }
+  dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false);
+  pp_character (pp, ' ');
+  if (r.varying_p ())
+    {
+      pp_string (pp, "VARYING");
+      return;
+    }
+
+  pp_character (pp, '[');
+  print_int_bound (pp, r.lower_bound (), r.type ());
+  pp_string (pp, ", ");
+  print_int_bound (pp, r.upper_bound (), r.type ());
+  pp_character (pp, ']');
+  print_irange_bitmasks (pp, r.m_bitmask);
+}
+
 void
 vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const
 {
diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h
index 44cd6e81298..5522aad0673 100644
--- a/gcc/value-range-pretty-print.h
+++ b/gcc/value-range-pretty-print.h
@@ -27,6 +27,7 @@ public:
   vrange_printer (pretty_printer *pp_) : pp (pp_) { }
   void visit (const unsupported_range &) const override;
   void visit (const irange &) const override;
+  void visit (const prange &) const override;
   void visit (const frange &) const override;
 private:
   void print_frange_nan (const frange &) const;
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 7250115261f..84113ccfbd0 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -251,6 +251,8 @@ vrange::operator= (const vrange &src)
 {
   if (is_a <irange> (src))
     as_a <irange> (*this) = as_a <irange> (src);
+  else if (is_a <prange> (src))
+    as_a <prange> (*this) = as_a <prange> (src);
   else if (is_a <frange> (src))
     as_a <frange> (*this) = as_a <frange> (src);
   else
@@ -268,6 +270,8 @@ vrange::operator== (const vrange &src) const
 {
   if (is_a <irange> (src))
     return as_a <irange> (*this) == as_a <irange> (src);
+  if (is_a <prange> (src))
+    return as_a <prange> (*this) == as_a <prange> (src);
   if (is_a <frange> (src))
     return as_a <frange> (*this) == as_a <frange> (src);
   gcc_unreachable ();
@@ -397,6 +401,294 @@ irange::set_nonnegative (tree type)
        wi::to_wide (TYPE_MAX_VALUE (type)));
 }
 
+// Prange implementation.
+
+void
+prange::accept (const vrange_visitor &v) const
+{
+  v.visit (*this);
+}
+
+void
+prange::set_nonnegative (tree type)
+{
+  set (type,
+       wi::zero (TYPE_PRECISION (type)),
+       wi::max_value (TYPE_PRECISION (type), UNSIGNED));
+}
+
+void
+prange::set (tree min, tree max, value_range_kind kind)
+{
+  return set (TREE_TYPE (min), wi::to_wide (min), wi::to_wide (max), kind);
+}
+
+void
+prange::set (tree type, const wide_int &min, const wide_int &max,
+	     value_range_kind kind)
+{
+  if (kind == VR_UNDEFINED)
+    {
+      set_undefined ();
+      return;
+    }
+  if (kind == VR_VARYING)
+    {
+      set_varying (type);
+      return;
+    }
+  if (kind == VR_ANTI_RANGE)
+    {
+      gcc_checking_assert (min == 0 && max == 0);
+      set_nonzero (type);
+      return;
+    }
+  m_type = type;
+  m_min = min;
+  m_max = max;
+  if (m_min == 0 && m_max == -1)
+    {
+      m_kind = VR_VARYING;
+      m_bitmask.set_unknown (TYPE_PRECISION (type));
+      if (flag_checking)
+	verify_range ();
+      return;
+    }
+
+  m_kind = VR_RANGE;
+  m_bitmask = get_bitmask_from_range (type, min, max);
+  if (flag_checking)
+    verify_range ();
+}
+
+bool
+prange::contains_p (const wide_int &w) const
+{
+  if (undefined_p ())
+    return false;
+
+  if (varying_p ())
+    return true;
+
+  return (wi::le_p (lower_bound (), w, UNSIGNED)
+	  && wi::ge_p (upper_bound (), w, UNSIGNED));
+}
+
+bool
+prange::singleton_p (tree *result) const
+{
+  if (m_kind == VR_RANGE && lower_bound () == upper_bound ())
+    {
+      if (result)
+	*result = wide_int_to_tree (type (), m_min);
+      return true;
+    }
+  return false;
+}
+
+tree
+prange::lbound () const
+{
+  return wide_int_to_tree (type (), m_min);
+}
+
+tree
+prange::ubound () const
+{
+  return wide_int_to_tree (type (), m_max);
+}
+
+bool
+prange::union_ (const vrange &v)
+{
+  const prange &r = as_a <prange> (v);
+
+  if (r.undefined_p ())
+    return false;
+  if (undefined_p ())
+    {
+      *this = r;
+      if (flag_checking)
+	verify_range ();
+      return true;
+    }
+  if (varying_p ())
+    return false;
+  if (r.varying_p ())
+    {
+      set_varying (type ());
+      return true;
+    }
+
+  wide_int new_lb = wi::min (r.lower_bound (), lower_bound (), UNSIGNED);
+  wide_int new_ub = wi::max (r.upper_bound (), upper_bound (), UNSIGNED);
+  prange new_range (type (), new_lb, new_ub);
+  new_range.m_bitmask.union_ (m_bitmask);
+  new_range.m_bitmask.union_ (r.m_bitmask);
+  if (new_range.varying_compatible_p ())
+    {
+      set_varying (type ());
+      return true;
+    }
+  if (flag_checking)
+    new_range.verify_range ();
+  if (new_range == *this)
+    return false;
+  *this = new_range;
+  return true;
+}
+
+bool
+prange::intersect (const vrange &v)
+{
+  const prange &r = as_a <prange> (v);
+  gcc_checking_assert (undefined_p () || r.undefined_p ()
+		       || range_compatible_p (type (), r.type ()));
+
+  if (undefined_p ())
+    return false;
+  if (r.undefined_p ())
+    {
+      set_undefined ();
+      return true;
+    }
+  if (r.varying_p ())
+    return false;
+  if (varying_p ())
+    {
+      *this = r;
+      return true;
+    }
+
+  prange save = *this;
+  m_min = wi::max (r.lower_bound (), lower_bound (), UNSIGNED);
+  m_max = wi::min (r.upper_bound (), upper_bound (), UNSIGNED);
+  if (wi::gt_p (m_min, m_max, UNSIGNED))
+    {
+      set_undefined ();
+      return true;
+    }
+
+  // Intersect all bitmasks: the old one, the new one, and the other operand's.
+  irange_bitmask new_bitmask = get_bitmask_from_range (m_type, m_min, m_max);
+  m_bitmask.intersect (new_bitmask);
+  m_bitmask.intersect (r.m_bitmask);
+
+  if (flag_checking)
+    verify_range ();
+  if (*this == save)
+    return false;
+  return true;
+}
+
+prange &
+prange::operator= (const prange &src)
+{
+  m_type = src.m_type;
+  m_kind = src.m_kind;
+  m_min = src.m_min;
+  m_max = src.m_max;
+  m_bitmask = src.m_bitmask;
+  if (flag_checking)
+    verify_range ();
+  return *this;
+}
+
+bool
+prange::operator== (const prange &src) const
+{
+  if (m_kind == src.m_kind)
+    {
+      if (undefined_p ())
+	return true;
+
+      if (varying_p ())
+	return types_compatible_p (type (), src.type ());
+
+      return (m_min == src.m_min && m_max == src.m_max
+	      && m_bitmask == src.m_bitmask);
+    }
+  return false;
+}
+
+void
+prange::invert ()
+{
+  gcc_checking_assert (!undefined_p () && !varying_p ());
+
+  wide_int new_lb, new_ub;
+  unsigned prec = TYPE_PRECISION (type ());
+  wide_int type_min = wi::zero (prec);
+  wide_int type_max = wi::max_value (prec, UNSIGNED);
+  wi::overflow_type ovf;
+
+  if (lower_bound () == type_min)
+    {
+      new_lb = wi::add (upper_bound (), 1, UNSIGNED, &ovf);
+      if (ovf)
+	new_lb = type_min;
+      new_ub = type_max;
+      set (type (), new_lb, new_ub);
+    }
+  else if (upper_bound () == type_max)
+    {
+      wi::overflow_type ovf;
+      new_lb = type_min;
+      new_ub = wi::sub (lower_bound (), 1, UNSIGNED, &ovf);
+      if (ovf)
+	new_ub = type_max;
+      set (type (), new_lb, new_ub);
+    }
+  else
+    set_varying (type ());
+}
+
+void
+prange::verify_range () const
+{
+  gcc_checking_assert (m_discriminator == VR_PRANGE);
+
+  if (m_kind == VR_UNDEFINED)
+    return;
+
+  gcc_checking_assert (supports_p (type ()));
+
+  if (m_kind == VR_VARYING)
+    {
+      gcc_checking_assert (varying_compatible_p ());
+      return;
+    }
+  gcc_checking_assert (!varying_compatible_p ());
+  gcc_checking_assert (m_kind == VR_RANGE);
+}
+
+void
+prange::update_bitmask (const irange_bitmask &bm)
+{
+  gcc_checking_assert (!undefined_p ());
+
+  // If all the bits are known, this is a singleton.
+  if (bm.mask () == 0)
+    {
+      set (type (), m_bitmask.value (), m_bitmask.value ());
+      return;
+    }
+
+  // Drop VARYINGs with known bits to a plain range.
+  if (m_kind == VR_VARYING && !bm.unknown_p ())
+    m_kind = VR_RANGE;
+
+  m_bitmask = bm;
+  if (varying_compatible_p ())
+    m_kind = VR_VARYING;
+
+  if (flag_checking)
+    verify_range ();
+}
+
+
+// Frange implementation.
+
 void
 frange::accept (const vrange_visitor &v) const
 {
@@ -2542,11 +2834,12 @@ range_tests_misc ()
   // Make sure NULL and non-NULL of pointer types work, and that
   // inverses of them are consistent.
   tree voidp = build_pointer_type (void_type_node);
-  r0.set_zero (voidp);
-  r1 = r0;
-  r0.invert ();
-  r0.invert ();
-  ASSERT_TRUE (r0 == r1);
+  prange p0;
+  p0.set_zero (voidp);
+  prange p1 = p0;
+  p0.invert ();
+  p0.invert ();
+  ASSERT_TRUE (p0 == p1);
 
   // [10,20] U [15, 30] => [10, 30].
   r0 = range_int (10, 20);
diff --git a/gcc/value-range.h b/gcc/value-range.h
index f52d5165707..6fe31d67582 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -47,6 +47,8 @@ enum value_range_discriminator
 {
   // Range holds an integer or pointer.
   VR_IRANGE,
+  // Pointer range.
+  VR_PRANGE,
   // Floating point range.
   VR_FRANGE,
   // Range holds an unsupported type.
@@ -380,32 +382,49 @@ private:
 
 class prange : public vrange
 {
+  friend class prange_storage;
+  friend class vrange_printer;
 public:
-  static bool supports_p (const_tree) { return false; }
-  virtual bool supports_type_p (const_tree) const final override { return false; }
-  virtual void accept (const vrange_visitor &) const final override {}
-  virtual void set_undefined () final override {}
-  virtual void set_varying (tree) final override {}
-  virtual void set_nonzero (tree) final override {}
-  virtual void set_zero (tree) final override;
-  virtual void set_nonnegative (tree) final override {}
-  virtual bool contains_p (tree) const final override { return false; }
-  virtual bool fits_p (const vrange &) const final override { return false; }
-  virtual bool singleton_p (tree * = NULL) const final override { return false; }
-  virtual bool zero_p () const final override { return false; }
-  virtual bool nonzero_p () const final override { return false; }
-  virtual void set (tree, tree, value_range_kind = VR_RANGE) final override {}
-  virtual tree type () const final override { return NULL; }
-  virtual bool union_ (const vrange &) final override { return false; }
-  virtual bool intersect (const vrange &) final override { return false; }
-  virtual tree lbound () const final override { return NULL; }
-  virtual tree ubound () const final override { return NULL; }
-
+  prange ();
+  prange (const prange &);
+  prange (tree type);
+  prange (tree type, const wide_int &, const wide_int &,
+	  value_range_kind = VR_RANGE);
+  static bool supports_p (const_tree type);
+  virtual bool supports_type_p (const_tree type) const final override;
+  virtual void accept (const vrange_visitor &v) const final override;
+  virtual void set_undefined () final override;
+  virtual void set_varying (tree type) final override;
+  virtual void set_nonzero (tree type) final override;
+  virtual void set_zero (tree type) final override;
+  virtual void set_nonnegative (tree type) final override;
+  virtual bool contains_p (tree cst) const final override;
+  virtual bool fits_p (const vrange &v) const final override;
+  virtual bool singleton_p (tree *result = NULL) const final override;
+  virtual bool zero_p () const final override;
+  virtual bool nonzero_p () const final override;
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) final override;
+  virtual tree type () const final override;
+  virtual bool union_ (const vrange &v) final override;
+  virtual bool intersect (const vrange &v) final override;
+  virtual tree lbound () const final override;
+  virtual tree ubound () const final override;
+
+  prange& operator= (const prange &);
+  bool operator== (const prange &) const;
+  void set (tree type, const wide_int &, const wide_int &,
+	    value_range_kind = VR_RANGE);
+  void invert ();
+  bool contains_p (const wide_int &) const;
   wide_int lower_bound () const;
   wide_int upper_bound () const;
+  void verify_range () const;
   irange_bitmask get_bitmask () const final override;
-  void update_bitmask (const irange_bitmask &) final override {}
-private:
+  void update_bitmask (const irange_bitmask &) final override;
+protected:
+  bool varying_compatible_p () const;
+
+  tree m_type;
   wide_int m_min;
   wide_int m_max;
   irange_bitmask m_bitmask;
@@ -656,6 +675,13 @@ is_a <irange> (vrange &v)
   return v.m_discriminator == VR_IRANGE;
 }
 
+template <>
+inline bool
+is_a <prange> (vrange &v)
+{
+  return v.m_discriminator == VR_PRANGE;
+}
+
 template <>
 inline bool
 is_a <frange> (vrange &v)
@@ -708,6 +734,7 @@ class vrange_visitor
 {
 public:
   virtual void visit (const irange &) const { }
+  virtual void visit (const prange &) const { }
   virtual void visit (const frange &) const { }
   virtual void visit (const unsupported_range &) const { }
 };
@@ -775,6 +802,7 @@ private:
   vrange *m_vrange;
   // The buffer must be at least the size of the largest range.
   static_assert (sizeof (int_range_max) > sizeof (frange), "");
+  static_assert (sizeof (int_range_max) > sizeof (prange), "");
   char m_buffer[sizeof (int_range_max)];
 };
 
@@ -850,6 +878,8 @@ Value_Range::init (tree type)
 
   if (irange::supports_p (type))
     m_vrange = new (&m_buffer) int_range_max ();
+  else if (prange::supports_p (type))
+    m_vrange = new (&m_buffer) prange ();
   else if (frange::supports_p (type))
     m_vrange = new (&m_buffer) frange ();
   else
@@ -863,6 +893,8 @@ Value_Range::init (const vrange &r)
 {
   if (is_a <irange> (r))
     m_vrange = new (&m_buffer) int_range_max (as_a <irange> (r));
+  else if (is_a <prange> (r))
+    m_vrange = new (&m_buffer) prange (as_a <prange> (r));
   else if (is_a <frange> (r))
     m_vrange = new (&m_buffer) frange (as_a <frange> (r));
   else
@@ -920,7 +952,9 @@ Value_Range::operator const vrange &() const
 inline bool
 Value_Range::supports_type_p (const_tree type)
 {
-  return irange::supports_p (type) || frange::supports_p (type);
+  return irange::supports_p (type)
+    || prange::supports_p (type)
+    || frange::supports_p (type);
 }
 
 extern value_range_kind get_legacy_range (const vrange &, tree &min, tree &max);
@@ -1220,32 +1254,151 @@ irange_val_max (const_tree type)
   return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
 }
 
+inline
+prange::prange ()
+  : vrange (VR_PRANGE)
+{
+  set_undefined ();
+}
+
+inline
+prange::prange (const prange &r)
+  : vrange (VR_PRANGE)
+{
+  *this = r;
+}
+
+inline
+prange::prange (tree type)
+  : vrange (VR_PRANGE)
+{
+  set_varying (type);
+}
+
+inline
+prange::prange (tree type, const wide_int &lb, const wide_int &ub,
+		value_range_kind kind)
+  : vrange (VR_PRANGE)
+{
+  set (type, lb, ub, kind);
+}
+
+inline bool
+prange::supports_p (const_tree type)
+{
+  return POINTER_TYPE_P (type);
+}
+
+inline bool
+prange::supports_type_p (const_tree type) const
+{
+  return POINTER_TYPE_P (type);
+}
+
+inline void
+prange::set_undefined ()
+{
+  m_kind = VR_UNDEFINED;
+}
+
+inline void
+prange::set_varying (tree type)
+{
+  m_kind = VR_VARYING;
+  m_type = type;
+  m_min = wi::zero (TYPE_PRECISION (type));
+  m_max = wi::max_value (TYPE_PRECISION (type), UNSIGNED);
+  m_bitmask.set_unknown (TYPE_PRECISION (type));
+
+  if (flag_checking)
+    verify_range ();
+}
+
+inline void
+prange::set_nonzero (tree type)
+{
+  m_kind = VR_RANGE;
+  m_type = type;
+  m_min = wi::one (TYPE_PRECISION (type));
+  m_max = wi::max_value (TYPE_PRECISION (type), UNSIGNED);
+  m_bitmask.set_unknown (TYPE_PRECISION (type));
+
+  if (flag_checking)
+    verify_range ();
+}
+
 inline void
 prange::set_zero (tree type)
 {
+  m_kind = VR_RANGE;
+  m_type = type;
   wide_int zero = wi::zero (TYPE_PRECISION (type));
   m_min = m_max = zero;
   m_bitmask = irange_bitmask (zero, zero);
+
+  if (flag_checking)
+    verify_range ();
+}
+
+inline bool
+prange::contains_p (tree cst) const
+{
+  return contains_p (wi::to_wide (cst));
+}
+
+inline bool
+prange::zero_p () const
+{
+  return m_kind == VR_RANGE && m_min == 0 && m_max == 0;
+}
+
+inline bool
+prange::nonzero_p () const
+{
+  return m_kind == VR_RANGE && m_min == 1 && m_max == -1;
+}
+
+inline tree
+prange::type () const
+{
+  gcc_checking_assert (!undefined_p ());
+  return m_type;
 }
 
 inline wide_int
 prange::lower_bound () const
 {
+  gcc_checking_assert (!undefined_p ());
   return m_min;
 }
 
 inline wide_int
 prange::upper_bound () const
 {
+  gcc_checking_assert (!undefined_p ());
   return m_max;
 }
 
+inline bool
+prange::varying_compatible_p () const
+{
+  return (!undefined_p ()
+	  && m_min == 0 && m_max == -1 && get_bitmask ().unknown_p ());
+}
+
 inline irange_bitmask
 prange::get_bitmask () const
 {
   return m_bitmask;
 }
 
+inline bool
+prange::fits_p (const vrange &) const
+{
+  return true;
+}
+
+
 inline
 frange::frange ()
   : vrange (VR_FRANGE)
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 03/23] Add streaming support for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 02/23] Implement basic prange class Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 04/23] Add storage " Aldy Hernandez
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* data-streamer-in.cc (streamer_read_value_range): Add prange support.
	* data-streamer-out.cc (streamer_write_vrange): Same.
---
 gcc/data-streamer-in.cc  | 12 ++++++++++++
 gcc/data-streamer-out.cc | 10 ++++++++++
 2 files changed, 22 insertions(+)

diff --git a/gcc/data-streamer-in.cc b/gcc/data-streamer-in.cc
index 3a0d3c6ad0f..12cb10e42c0 100644
--- a/gcc/data-streamer-in.cc
+++ b/gcc/data-streamer-in.cc
@@ -268,6 +268,18 @@ streamer_read_value_range (class lto_input_block *ib, data_in *data_in,
 	}
       return;
     }
+  if (is_a <prange> (vr))
+    {
+      prange &r = as_a <prange> (vr);
+      wide_int lb = streamer_read_wide_int (ib);
+      wide_int ub = streamer_read_wide_int (ib);
+      r.set (type, lb, ub);
+      wide_int value = streamer_read_wide_int (ib);
+      wide_int mask = streamer_read_wide_int (ib);
+      irange_bitmask bm (value, mask);
+      r.update_bitmask (bm);
+      return;
+    }
   gcc_unreachable ();
 }
 
diff --git a/gcc/data-streamer-out.cc b/gcc/data-streamer-out.cc
index 07cc6bd2018..c237e30f704 100644
--- a/gcc/data-streamer-out.cc
+++ b/gcc/data-streamer-out.cc
@@ -450,6 +450,16 @@ streamer_write_vrange (struct output_block *ob, const vrange &v)
 	}
       return;
     }
+  if (is_a <prange> (v))
+    {
+      const prange &r = as_a <prange> (v);
+      streamer_write_wide_int (ob, r.lower_bound ());
+      streamer_write_wide_int (ob, r.upper_bound ());
+      irange_bitmask bm = r.get_bitmask ();
+      streamer_write_wide_int (ob, bm.value ());
+      streamer_write_wide_int (ob, bm.mask ());
+      return;
+    }
   gcc_unreachable ();
 }
 
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 04/23] Add storage support for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (2 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 03/23] Add streaming support for prange Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 05/23] Add hashing " Aldy Hernandez
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* value-range-storage.cc (vrange_allocator::clone_varying): Add
	prange support.
	(vrange_allocator::clone_undefined): Same.
	(vrange_storage::alloc): Same.
	(vrange_storage::set_vrange): Same.
	(vrange_storage::get_vrange): Same.
	(vrange_storage::fits_p): Same.
	(vrange_storage::equal_p): Same.
	(prange_storage::alloc): New.
	(prange_storage::prange_storage): New.
	(prange_storage::set_prange): New.
	(prange_storage::get_prange): New.
	(prange_storage::equal_p): New.
	(prange_storage::fits_p): New.
	* value-range-storage.h (class prange_storage): Add prange support.
---
 gcc/value-range-storage.cc | 117 +++++++++++++++++++++++++++++++++++++
 gcc/value-range-storage.h  |  33 +++++++++++
 2 files changed, 150 insertions(+)

diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc
index 09a29776a0e..bbae0da4772 100644
--- a/gcc/value-range-storage.cc
+++ b/gcc/value-range-storage.cc
@@ -118,6 +118,8 @@ vrange_allocator::clone_varying (tree type)
 {
   if (irange::supports_p (type))
     return irange_storage::alloc (*m_alloc, int_range <1> (type));
+  if (prange::supports_p (type))
+    return prange_storage::alloc (*m_alloc, prange (type));
   if (frange::supports_p (type))
     return frange_storage::alloc (*m_alloc, frange (type));
   return NULL;
@@ -128,6 +130,8 @@ vrange_allocator::clone_undefined (tree type)
 {
   if (irange::supports_p (type))
     return irange_storage::alloc (*m_alloc, int_range<1> ());
+  if (prange::supports_p (type))
+    return prange_storage::alloc (*m_alloc, prange ());
   if (frange::supports_p (type))
     return frange_storage::alloc  (*m_alloc, frange ());
   return NULL;
@@ -141,6 +145,8 @@ vrange_storage::alloc (vrange_internal_alloc &allocator, const vrange &r)
 {
   if (is_a <irange> (r))
     return irange_storage::alloc (allocator, as_a <irange> (r));
+  if (is_a <prange> (r))
+    return prange_storage::alloc (allocator, as_a <prange> (r));
   if (is_a <frange> (r))
     return frange_storage::alloc (allocator, as_a <frange> (r));
   return NULL;
@@ -157,6 +163,12 @@ vrange_storage::set_vrange (const vrange &r)
       gcc_checking_assert (s->fits_p (as_a <irange> (r)));
       s->set_irange (as_a <irange> (r));
     }
+  else if (is_a <prange> (r))
+    {
+      prange_storage *s = static_cast <prange_storage *> (this);
+      gcc_checking_assert (s->fits_p (as_a <prange> (r)));
+      s->set_prange (as_a <prange> (r));
+    }
   else if (is_a <frange> (r))
     {
       frange_storage *s = static_cast <frange_storage *> (this);
@@ -190,6 +202,11 @@ vrange_storage::get_vrange (vrange &r, tree type) const
       const irange_storage *s = static_cast <const irange_storage *> (this);
       s->get_irange (as_a <irange> (r), type);
     }
+  else if (is_a <prange> (r))
+    {
+      const prange_storage *s = static_cast <const prange_storage *> (this);
+      s->get_prange (as_a <prange> (r), type);
+    }
   else if (is_a <frange> (r))
     {
       const frange_storage *s = static_cast <const frange_storage *> (this);
@@ -209,6 +226,11 @@ vrange_storage::fits_p (const vrange &r) const
       const irange_storage *s = static_cast <const irange_storage *> (this);
       return s->fits_p (as_a <irange> (r));
     }
+  if (is_a <prange> (r))
+    {
+      const prange_storage *s = static_cast <const prange_storage *> (this);
+      return s->fits_p (as_a <prange> (r));
+    }
   if (is_a <frange> (r))
     {
       const frange_storage *s = static_cast <const frange_storage *> (this);
@@ -230,6 +252,11 @@ vrange_storage::equal_p (const vrange &r) const
       const irange_storage *s = static_cast <const irange_storage *> (this);
       return s->equal_p (as_a <irange> (r));
     }
+  if (is_a <prange> (r))
+    {
+      const prange_storage *s = static_cast <const prange_storage *> (this);
+      return s->equal_p (as_a <prange> (r));
+    }
   if (is_a <frange> (r))
     {
       const frange_storage *s = static_cast <const frange_storage *> (this);
@@ -559,6 +586,96 @@ frange_storage::fits_p (const frange &) const
   return true;
 }
 
+//============================================================================
+// prange_storage implementation
+//============================================================================
+
+prange_storage *
+prange_storage::alloc (vrange_internal_alloc &allocator, const prange &r)
+{
+  // Assume all pointers are the same size.
+  unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node));
+  gcc_checking_assert (r.undefined_p () || TYPE_PRECISION (r.type ()) == prec);
+
+  typedef trailing_wide_ints<NINTS> twi;
+  size_t size = sizeof (prange_storage) + twi::extra_size (prec);
+  prange_storage *p = static_cast <prange_storage *> (allocator.alloc (size));
+  new (p) prange_storage (r);
+  return p;
+}
+
+// Initialize the storage with R.
+
+prange_storage::prange_storage (const prange &r)
+{
+  // It is the caller's responsibility to allocate enough space such
+  // that the precision fits.
+  unsigned prec = TYPE_PRECISION (TREE_TYPE (null_pointer_node));
+  m_trailing_ints.set_precision (prec);
+
+  set_prange (r);
+}
+
+void
+prange_storage::set_prange (const prange &r)
+{
+  if (r.undefined_p ())
+    m_kind = VR_UNDEFINED;
+  else if (r.varying_p ())
+    m_kind = VR_VARYING;
+  else
+    {
+      m_kind = VR_RANGE;
+      set_low (r.lower_bound ());
+      set_high (r.upper_bound ());
+      irange_bitmask bm = r.m_bitmask;
+      set_value (bm.value ());
+      set_mask (bm.mask ());
+    }
+}
+
+void
+prange_storage::get_prange (prange &r, tree type) const
+{
+  gcc_checking_assert (r.supports_type_p (type));
+
+  if (m_kind == VR_UNDEFINED)
+    r.set_undefined ();
+  else if (m_kind == VR_VARYING)
+    r.set_varying (type);
+  else
+    {
+      gcc_checking_assert (m_kind == VR_RANGE);
+      gcc_checking_assert (TYPE_PRECISION (type) == m_trailing_ints.get_precision ());
+      r.m_kind = VR_RANGE;
+      r.m_type = type;
+      r.m_min = get_low ();
+      r.m_max = get_high ();
+      r.m_bitmask = irange_bitmask (get_value (), get_mask ());
+      if (flag_checking)
+	r.verify_range ();
+    }
+}
+
+bool
+prange_storage::equal_p (const prange &r) const
+{
+  if (r.undefined_p ())
+    return m_kind == VR_UNDEFINED;
+
+  prange tmp;
+  get_prange (tmp, r.type ());
+  return tmp == r;
+}
+
+bool
+prange_storage::fits_p (const prange &) const
+{
+  // All pointers are the same size.
+  return true;
+}
+
+\f
 static vrange_allocator ggc_vrange_allocator (true);
 
 vrange_storage *ggc_alloc_vrange_storage (tree type)
diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h
index 5756de7e32d..dd6813873ea 100644
--- a/gcc/value-range-storage.h
+++ b/gcc/value-range-storage.h
@@ -98,6 +98,39 @@ private:
   irange_storage (const irange &r);
 };
 
+// Efficient memory storage for a prange.
+
+class prange_storage : public vrange_storage
+{
+public:
+  static prange_storage *alloc (vrange_internal_alloc &, const prange &);
+  void set_prange (const prange &r);
+  void get_prange (prange &r, tree type) const;
+  bool equal_p (const prange &r) const;
+  bool fits_p (const prange &r) const;
+  void dump () const;
+private:
+  DISABLE_COPY_AND_ASSIGN (prange_storage);
+  prange_storage (const prange &r);
+
+  enum value_range_kind m_kind : 3;
+
+  // We don't use TRAILING_WIDE_INT_ACCESSOR because the getters here
+  // must be const.  Perhaps TRAILING_WIDE_INT_ACCESSOR could be made
+  // const and return wide_int instead of trailing_wide_int.
+  wide_int get_low () const { return m_trailing_ints[0]; }
+  wide_int get_high () const { return m_trailing_ints[1]; }
+  wide_int get_value () const { return m_trailing_ints[2]; }
+  wide_int get_mask () const { return m_trailing_ints[3]; }
+  template <typename T> void set_low (const T &x) { m_trailing_ints[0] = x; }
+  template <typename T> void set_high (const T &x) { m_trailing_ints[1] = x; }
+  template <typename T> void set_value (const T &x) { m_trailing_ints[2] = x; }
+  template <typename T> void set_mask (const T &x) { m_trailing_ints[3] = x; }
+
+  static const unsigned int NINTS = 4;
+  trailing_wide_ints<NINTS> m_trailing_ints;
+};
+
 // Efficient memory storage for an frange.
 
 class frange_storage : public vrange_storage
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 05/23] Add hashing support for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (3 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 04/23] Add storage " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 06/23] Add prange implementation for get_legacy_range Aldy Hernandez
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* value-range.cc (add_vrange): Add prange support.
---
 gcc/value-range.cc | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 84113ccfbd0..62170a438bf 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -346,6 +346,22 @@ add_vrange (const vrange &v, inchash::hash &hstate,
       hstate.add_wide_int (bm.mask ());
       return;
     }
+  if (is_a <prange> (v))
+    {
+      const prange &r = as_a <prange> (v);
+      if (r.varying_p ())
+	hstate.add_int (VR_VARYING);
+      else
+	{
+	  hstate.add_int (VR_RANGE);
+	  hstate.add_wide_int (r.lower_bound ());
+	  hstate.add_wide_int (r.upper_bound ());
+	  irange_bitmask bm = r.get_bitmask ();
+	  hstate.add_wide_int (bm.value ());
+	  hstate.add_wide_int (bm.mask ());
+	}
+      return;
+    }
   if (is_a <frange> (v))
     {
       const frange &r = as_a <frange> (v);
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 06/23] Add prange implementation for get_legacy_range.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (4 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 05/23] Add hashing " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 07/23] Implement range-op dispatch for prange Aldy Hernandez
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* value-range.cc (get_legacy_range): New version for prange.
---
 gcc/value-range.cc | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 62170a438bf..3e1ecf69517 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -1377,6 +1377,38 @@ get_legacy_range (const irange &r, tree &min, tree &max)
   return VR_RANGE;
 }
 
+static value_range_kind
+get_legacy_range (const prange &r, tree &min, tree &max)
+{
+  if (r.undefined_p ())
+    {
+      min = NULL_TREE;
+      max = NULL_TREE;
+      return VR_UNDEFINED;
+    }
+
+  tree type = r.type ();
+  if (r.varying_p ())
+    {
+      min = r.lbound ();
+      max = r.ubound ();
+      return VR_VARYING;
+    }
+  if (r.zero_p ())
+    {
+      min = max = r.lbound ();
+      return VR_RANGE;
+    }
+  if (r.nonzero_p ())
+    {
+      min = max = build_zero_cst (type);
+      return VR_ANTI_RANGE;
+    }
+  min = r.lbound ();
+  max = r.ubound ();
+  return VR_RANGE;
+}
+
 // Given a range in V, return an old-style legacy range consisting of
 // a value_range_kind with a MIN/MAX.  This is to maintain
 // compatibility with passes that still depend on VR_ANTI_RANGE, and
@@ -1388,8 +1420,7 @@ get_legacy_range (const vrange &v, tree &min, tree &max)
   if (is_a <irange> (v))
     return get_legacy_range (as_a <irange> (v), min, max);
 
-  gcc_unreachable ();
-  return VR_UNDEFINED;
+  return get_legacy_range (as_a <prange> (v), min, max);
 }
 
 /* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 07/23] Implement range-op dispatch for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (5 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 06/23] Add prange implementation for get_legacy_range Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 08/23] Implement operator_identity " Aldy Hernandez
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

This patch adds the range-op dispatch code for prange, and adds some
temporary sanity checks (for flag_checking only) to make sure we handle
all the pointer/integer variants.

In order to make sure I got all the combinations right, I started with
a clean slate, trapping on all pointer operands.  Then I added support
for each one piecemeal.  To verify the work, I added a
pointers_handled_p() helper that is implemented for each range-op
entry and returns TRUE iff the operator can handle a given combination
of pointers.  If this helper returns false, we will trap, because it
indicates an operator that was not implemented.  This is temporary
checking code, and I will rip it out once the the dust has
settled in a few days.

gcc/ChangeLog:

	* range-op-mixed.h: Add using declarator for all classes.
	* range-op-ptr.cc (range_operator::pointers_handled_p): New.
	(range_operator::fold_range): New.
	(range_operator::op1_op2_relation_effect): New.
	(range_operator::op1_range): New.
	(range_operator::op2_range): New.
	(range_operator::op1_op2_relation): New.
	(range_operator::lhs_op1_relation): New.
	(range_operator::update_bitmask): New.
	(class pointer_plus_operator): New.
	(class operator_pointer_diff): New.
	(class hybrid_min_operator): New.
	(class hybrid_max_operator): New.
	* range-op.cc: Add RO_PPP, RO_PPI, RO_IPP, RO_IPI, RO_PIP, RO_PII.
	(range_op_handler::discriminator_fail): New.
	(has_pointer_operand_p): New.
	(range_op_handler::fold_range): Add pointer support.
	(range_op_handler::op1_range): Same.
	(range_op_handler::op2_range): Same.
	(range_op_handler::lhs_op1_relation): Same.
	(range_op_handler::lhs_op2_relation): Same.
	(range_op_handler::op1_op2_relation): Same.
	(class operator_div): Add using.
	(class operator_lshift): Add using.
	(class operator_rshift):Add using.
	(class operator_trunc_mod):Add using.
	(class operator_absu):Add using.
	* range-op.h (enum range_op_dispatch_type): New.
	Add extern definitions for RO_*.
---
 gcc/range-op-mixed.h |  19 ++++
 gcc/range-op-ptr.cc  | 220 +++++++++++++++++++++++++++++++++++++++++++
 gcc/range-op.cc      | 124 ++++++++++++++++++++++++
 gcc/range-op.h       | 111 ++++++++++++++++++++++
 4 files changed, 474 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 3ee7c9d6e0d..8163a4b53ca 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -111,6 +111,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -150,6 +151,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -189,6 +191,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -225,6 +228,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -264,6 +268,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -302,6 +307,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::op1_op2_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -376,6 +382,7 @@ public:
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
@@ -402,6 +409,7 @@ public:
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
   using range_operator::lhs_op2_relation;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio) const final override;
@@ -445,6 +453,7 @@ class operator_abs : public range_operator
  public:
   using range_operator::fold_range;
   using range_operator::op1_range;
+  using range_operator::update_bitmask;
   bool fold_range (frange &r, tree type,
 		   const frange &op1, const frange &,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -473,6 +482,8 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::op1_op2_relation_effect;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio) const final override;
@@ -556,6 +567,7 @@ class operator_mult : public cross_product_operator
 public:
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio) const final override;
@@ -608,6 +620,7 @@ class operator_bitwise_not : public range_operator
 public:
   using range_operator::fold_range;
   using range_operator::op1_range;
+  using range_operator::update_bitmask;
   bool fold_range (irange &r, tree type,
 		   const irange &lh, const irange &rh,
 		   relation_trio rel = TRIO_VARYING) const final override;
@@ -626,6 +639,8 @@ class operator_bitwise_xor : public range_operator
 public:
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation_effect;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const final override;
@@ -654,6 +669,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const override;
@@ -682,6 +698,7 @@ class operator_bitwise_or : public range_operator
 public:
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const override;
@@ -702,6 +719,7 @@ protected:
 class operator_min : public range_operator
 {
 public:
+  using range_operator::update_bitmask;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const override;
   // Check compatibility of all operands.
@@ -716,6 +734,7 @@ protected:
 class operator_max : public range_operator
 {
 public:
+  using range_operator::update_bitmask;
   void update_bitmask (irange &r, const irange &lh,
       const irange &rh) const override;
   // Check compatibility of all operands.
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 7343ef635f3..560c798b90a 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -49,8 +49,222 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "range-op-mixed.h"
 
+// Return TRUE if a range-op folder TYPE either handles or can safely
+// ignore the dispatch pattern in DISPATCH.  Return FALSE for any
+// combination not handled, which will result in a hard fail up the
+// chain.
+
+bool
+range_operator::pointers_handled_p (range_op_dispatch_type ATTRIBUTE_UNUSED,
+				    unsigned dispatch ATTRIBUTE_UNUSED) const
+{
+  return false;
+}
+
+bool
+range_operator::fold_range (prange &r, tree type,
+			    const prange &op1,
+			    const prange &op2,
+			    relation_trio trio) const
+{
+  relation_kind rel = trio.op1_op2 ();
+  r.set_varying (type);
+  op1_op2_relation_effect (r, type, op1, op2, rel);
+  return true;
+}
+
+bool
+range_operator::fold_range (prange &r, tree type,
+			    const prange &op1,
+			    const irange &op2,
+			    relation_trio trio) const
+{
+  relation_kind rel = trio.op1_op2 ();
+  r.set_varying (type);
+  op1_op2_relation_effect (r, type, op1, op2, rel);
+  return true;
+}
+
+bool
+range_operator::fold_range (irange &r, tree type,
+			    const prange &op1,
+			    const prange &op2,
+			    relation_trio trio) const
+{
+  relation_kind rel = trio.op1_op2 ();
+  r.set_varying (type);
+  op1_op2_relation_effect (r, type, op1, op2, rel);
+  return true;
+}
+
+bool
+range_operator::fold_range (prange &r, tree type,
+			    const irange &op1,
+			    const prange &op2,
+			    relation_trio trio) const
+{
+  relation_kind rel = trio.op1_op2 ();
+  r.set_varying (type);
+  op1_op2_relation_effect (r, type, op1, op2, rel);
+  return true;
+}
+
+bool
+range_operator::fold_range (irange &r, tree type,
+			    const prange &op1,
+			    const irange &op2,
+			    relation_trio trio) const
+{
+  relation_kind rel = trio.op1_op2 ();
+  r.set_varying (type);
+  op1_op2_relation_effect (r, type, op1, op2, rel);
+  return true;
+}
+
+bool
+range_operator::op1_op2_relation_effect (prange &, tree,
+					 const prange &,
+					 const prange &,
+					 relation_kind) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_op2_relation_effect (prange &, tree,
+					 const prange &,
+					 const irange &,
+					 relation_kind) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_op2_relation_effect (irange &, tree,
+					 const prange &,
+					 const prange &,
+					 relation_kind) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_op2_relation_effect (prange &, tree,
+					 const irange &,
+					 const prange &,
+					 relation_kind) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_op2_relation_effect (irange &, tree,
+					 const prange &,
+					 const irange &,
+					 relation_kind) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_range (prange &, tree,
+			   const prange &lhs ATTRIBUTE_UNUSED,
+			   const prange &op2 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_range (prange &, tree,
+			   const irange &lhs ATTRIBUTE_UNUSED,
+			   const prange &op2 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_range (prange &, tree,
+			   const prange &lhs ATTRIBUTE_UNUSED,
+			   const irange &op2 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+bool
+range_operator::op1_range (irange &, tree,
+			   const prange &lhs ATTRIBUTE_UNUSED,
+			   const irange &op2 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+bool
+range_operator::op2_range (prange &, tree,
+			   const irange &lhs ATTRIBUTE_UNUSED,
+			   const prange &op1 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+bool
+range_operator::op2_range (irange &, tree,
+			   const prange &lhs ATTRIBUTE_UNUSED,
+			   const prange &op1 ATTRIBUTE_UNUSED,
+			   relation_trio) const
+{
+  return false;
+}
+
+relation_kind
+range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
+				  const prange &op1 ATTRIBUTE_UNUSED,
+				  const prange &op2 ATTRIBUTE_UNUSED) const
+{
+  return VREL_VARYING;
+}
+
+relation_kind
+range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED,
+				  const irange &op1 ATTRIBUTE_UNUSED,
+				  const irange &op2 ATTRIBUTE_UNUSED,
+				  relation_kind rel ATTRIBUTE_UNUSED) const
+{
+  return VREL_VARYING;
+}
+
+relation_kind
+range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
+				  const prange &op1 ATTRIBUTE_UNUSED,
+				  const prange &op2 ATTRIBUTE_UNUSED,
+				  relation_kind rel ATTRIBUTE_UNUSED) const
+{
+  return VREL_VARYING;
+}
+
+relation_kind
+range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED,
+				  const prange &op1 ATTRIBUTE_UNUSED,
+				  const prange &op2 ATTRIBUTE_UNUSED,
+				  relation_kind rel ATTRIBUTE_UNUSED) const
+{
+  return VREL_VARYING;
+}
+
+void
+range_operator::update_bitmask (irange &,
+				const prange &,
+				const prange &) const
+{
+}
+
 class pointer_plus_operator : public range_operator
 {
+  using range_operator::update_bitmask;
   using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
@@ -245,6 +459,8 @@ pointer_or_operator::wi_fold (irange &r, tree type,
 
 class operator_pointer_diff : public range_operator
 {
+  using range_operator::update_bitmask;
+  using range_operator::op1_op2_relation_effect;
   virtual bool op1_op2_relation_effect (irange &lhs_range,
 					tree type,
 					const irange &op1_range,
@@ -274,6 +490,7 @@ operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
 class hybrid_and_operator : public operator_bitwise_and
 {
 public:
+  using range_operator::update_bitmask;
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
@@ -330,6 +547,7 @@ public:
 class hybrid_or_operator : public operator_bitwise_or
 {
 public:
+  using range_operator::update_bitmask;
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
@@ -376,6 +594,7 @@ public:
 
 class hybrid_min_operator : public operator_min
 {
+  using range_operator::update_bitmask;
 public:
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override
@@ -397,6 +616,7 @@ public:
 
 class hybrid_max_operator : public operator_max
 {
+  using range_operator::update_bitmask;
 public:
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index ab3a4f0b200..65f3843227d 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -181,6 +181,12 @@ const unsigned RO_IFF = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_FRANGE);
 const unsigned RO_FFF = dispatch_trio (VR_FRANGE, VR_FRANGE, VR_FRANGE);
 const unsigned RO_FIF = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_FRANGE);
 const unsigned RO_FII = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_IRANGE);
+const unsigned RO_PPP = dispatch_trio (VR_PRANGE, VR_PRANGE, VR_PRANGE);
+const unsigned RO_PPI = dispatch_trio (VR_PRANGE, VR_PRANGE, VR_IRANGE);
+const unsigned RO_IPP = dispatch_trio (VR_IRANGE, VR_PRANGE, VR_PRANGE);
+const unsigned RO_IPI = dispatch_trio (VR_IRANGE, VR_PRANGE, VR_IRANGE);
+const unsigned RO_PIP = dispatch_trio (VR_PRANGE, VR_IRANGE, VR_PRANGE);
+const unsigned RO_PII = dispatch_trio (VR_PRANGE, VR_IRANGE, VR_IRANGE);
 
 // Return a dispatch value for parameter types LHS, OP1 and OP2.
 
@@ -192,6 +198,28 @@ range_op_handler::dispatch_kind (const vrange &lhs, const vrange &op1,
 			op2.m_discriminator);
 }
 
+void
+range_op_handler::discriminator_fail (const vrange &r1,
+				      const vrange &r2,
+				      const vrange &r3) const
+{
+  const char name[] = "IPF";
+  gcc_checking_assert (r1.m_discriminator < sizeof (name) - 1);
+  gcc_checking_assert (r2.m_discriminator < sizeof (name) - 1);
+  gcc_checking_assert (r3.m_discriminator < sizeof (name) - 1);
+  fprintf (stderr, "DISCRIMINATOR FAIL.  Dispatch ====> RO_%c%c%c <====\n",
+	   name[r1.m_discriminator],
+	   name[r2.m_discriminator],
+	   name[r3.m_discriminator]);
+  gcc_unreachable ();
+}
+
+static inline bool
+has_pointer_operand_p (const vrange &r1, const vrange &r2, const vrange &r3)
+{
+  return is_a <prange> (r1) || is_a <prange> (r2) || is_a <prange> (r3);
+}
+
 // Dispatch a call to fold_range based on the types of R, LH and RH.
 
 bool
@@ -204,6 +232,10 @@ range_op_handler::fold_range (vrange &r, tree type,
 #if CHECKING_P
   if (!lh.undefined_p () && !rh.undefined_p ())
     gcc_assert (m_operator->operand_check_p (type, lh.type (), rh.type ()));
+  if (has_pointer_operand_p (r, lh, rh)
+      && !m_operator->pointers_handled_p (DISPATCH_FOLD_RANGE,
+					  dispatch_kind (r, lh, rh)))
+    discriminator_fail (r, lh, rh);
 #endif
   switch (dispatch_kind (r, lh, rh))
     {
@@ -227,6 +259,26 @@ range_op_handler::fold_range (vrange &r, tree type,
 	return m_operator->fold_range (as_a <frange> (r), type,
 				       as_a <irange> (lh),
 				       as_a <irange> (rh), rel);
+      case RO_PPP:
+	return m_operator->fold_range (as_a <prange> (r), type,
+				       as_a <prange> (lh),
+				       as_a <prange> (rh), rel);
+      case RO_PPI:
+	return m_operator->fold_range (as_a <prange> (r), type,
+				       as_a <prange> (lh),
+				       as_a <irange> (rh), rel);
+      case RO_IPP:
+	return m_operator->fold_range (as_a <irange> (r), type,
+				       as_a <prange> (lh),
+				       as_a <prange> (rh), rel);
+      case RO_PIP:
+	return m_operator->fold_range (as_a <prange> (r), type,
+				       as_a <irange> (lh),
+				       as_a <prange> (rh), rel);
+      case RO_IPI:
+	return m_operator->fold_range (as_a <irange> (r), type,
+				       as_a <prange> (lh),
+				       as_a <irange> (rh), rel);
       default:
 	return false;
     }
@@ -246,6 +298,10 @@ range_op_handler::op1_range (vrange &r, tree type,
 #if CHECKING_P
   if (!op2.undefined_p ())
     gcc_assert (m_operator->operand_check_p (lhs.type (), type, op2.type ()));
+  if (has_pointer_operand_p (r, lhs, op2)
+      && !m_operator->pointers_handled_p (DISPATCH_OP1_RANGE,
+					  dispatch_kind (r, lhs, op2)))
+    discriminator_fail (r, lhs, op2);
 #endif
   switch (dispatch_kind (r, lhs, op2))
     {
@@ -253,6 +309,22 @@ range_op_handler::op1_range (vrange &r, tree type,
 	return m_operator->op1_range (as_a <irange> (r), type,
 				      as_a <irange> (lhs),
 				      as_a <irange> (op2), rel);
+      case RO_PPP:
+	return m_operator->op1_range (as_a <prange> (r), type,
+				      as_a <prange> (lhs),
+				      as_a <prange> (op2), rel);
+      case RO_PIP:
+	return m_operator->op1_range (as_a <prange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <prange> (op2), rel);
+      case RO_PPI:
+	return m_operator->op1_range (as_a <prange> (r), type,
+				      as_a <prange> (lhs),
+				      as_a <irange> (op2), rel);
+      case RO_IPI:
+	return m_operator->op1_range (as_a <irange> (r), type,
+				      as_a <prange> (lhs),
+				      as_a <irange> (op2), rel);
       case RO_FIF:
 	return m_operator->op1_range (as_a <frange> (r), type,
 				      as_a <irange> (lhs),
@@ -280,6 +352,10 @@ range_op_handler::op2_range (vrange &r, tree type,
 #if CHECKING_P
   if (!op1.undefined_p ())
     gcc_assert (m_operator->operand_check_p (lhs.type (), op1.type (), type));
+  if (has_pointer_operand_p (r, lhs, op1)
+      && !m_operator->pointers_handled_p (DISPATCH_OP2_RANGE,
+					  dispatch_kind (r, lhs, op1)))
+    discriminator_fail (r, lhs, op1);
 #endif
   switch (dispatch_kind (r, lhs, op1))
     {
@@ -287,6 +363,14 @@ range_op_handler::op2_range (vrange &r, tree type,
 	return m_operator->op2_range (as_a <irange> (r), type,
 				      as_a <irange> (lhs),
 				      as_a <irange> (op1), rel);
+      case RO_PIP:
+	return m_operator->op2_range (as_a <prange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <prange> (op1), rel);
+      case RO_IPP:
+	return m_operator->op2_range (as_a <irange> (r), type,
+				      as_a <prange> (lhs),
+				      as_a <prange> (op1), rel);
       case RO_FIF:
 	return m_operator->op2_range (as_a <frange> (r), type,
 				      as_a <irange> (lhs),
@@ -309,6 +393,12 @@ range_op_handler::lhs_op1_relation (const vrange &lhs,
 				    relation_kind rel) const
 {
   gcc_checking_assert (m_operator);
+#if CHECKING_P
+  if (has_pointer_operand_p (lhs, op1, op2)
+      && !m_operator->pointers_handled_p (DISPATCH_LHS_OP1_RELATION,
+					  dispatch_kind (lhs, op1, op2)))
+    discriminator_fail (lhs, op1, op2);
+#endif
 
   switch (dispatch_kind (lhs, op1, op2))
     {
@@ -316,6 +406,18 @@ range_op_handler::lhs_op1_relation (const vrange &lhs,
 	return m_operator->lhs_op1_relation (as_a <irange> (lhs),
 					     as_a <irange> (op1),
 					     as_a <irange> (op2), rel);
+      case RO_PPP:
+	return m_operator->lhs_op1_relation (as_a <prange> (lhs),
+					     as_a <prange> (op1),
+					     as_a <prange> (op2), rel);
+      case RO_IPP:
+	return m_operator->lhs_op1_relation (as_a <irange> (lhs),
+					     as_a <prange> (op1),
+					     as_a <prange> (op2), rel);
+      case RO_PII:
+	return m_operator->lhs_op1_relation (as_a <prange> (lhs),
+					     as_a <irange> (op1),
+					     as_a <irange> (op2), rel);
       case RO_IFF:
 	return m_operator->lhs_op1_relation (as_a <irange> (lhs),
 					     as_a <frange> (op1),
@@ -338,6 +440,12 @@ range_op_handler::lhs_op2_relation (const vrange &lhs,
 				    relation_kind rel) const
 {
   gcc_checking_assert (m_operator);
+#if CHECKING_P
+  if (has_pointer_operand_p (lhs, op1, op2)
+      && !m_operator->pointers_handled_p (DISPATCH_LHS_OP2_RELATION,
+					  dispatch_kind (lhs, op1, op2)))
+    discriminator_fail (lhs, op1, op2);
+#endif
   switch (dispatch_kind (lhs, op1, op2))
     {
       case RO_III:
@@ -365,6 +473,12 @@ range_op_handler::op1_op2_relation (const vrange &lhs,
 				    const vrange &op2) const
 {
   gcc_checking_assert (m_operator);
+#if CHECKING_P
+  if (has_pointer_operand_p (lhs, op1, op2)
+      && !m_operator->pointers_handled_p (DISPATCH_OP1_OP2_RELATION,
+					  dispatch_kind (lhs, op1, op2)))
+    discriminator_fail (lhs, op1, op2);
+#endif
   switch (dispatch_kind (lhs, op1, op2))
     {
       case RO_III:
@@ -372,6 +486,11 @@ range_op_handler::op1_op2_relation (const vrange &lhs,
 					     as_a <irange> (op1),
 					     as_a <irange> (op2));
 
+      case RO_IPP:
+	return m_operator->op1_op2_relation (as_a <irange> (lhs),
+					     as_a <prange> (op1),
+					     as_a <prange> (op2));
+
       case RO_IFF:
 	return m_operator->op1_op2_relation (as_a <irange> (lhs),
 					     as_a <frange> (op1),
@@ -2327,6 +2446,7 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type,
 
 class operator_div : public cross_product_operator
 {
+  using range_operator::update_bitmask;
 public:
   operator_div (tree_code div_kind) { m_code = div_kind; }
   virtual void wi_fold (irange &r, tree type,
@@ -2474,6 +2594,7 @@ class operator_lshift : public cross_product_operator
 {
   using range_operator::fold_range;
   using range_operator::op1_range;
+  using range_operator::update_bitmask;
 public:
   virtual bool op1_range (irange &r, tree type, const irange &lhs,
 			  const irange &op2, relation_trio rel = TRIO_VARYING)
@@ -2503,6 +2624,7 @@ class operator_rshift : public cross_product_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::update_bitmask;
 public:
   virtual bool fold_range (irange &r, tree type, const irange &op1,
 			   const irange &op2, relation_trio rel = TRIO_VARYING)
@@ -3883,6 +4005,7 @@ class operator_trunc_mod : public range_operator
 {
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::update_bitmask;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -4305,6 +4428,7 @@ operator_abs::update_bitmask (irange &r, const irange &lh,
 
 class operator_absu : public range_operator
 {
+  using range_operator::update_bitmask;
  public:
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 44a3e4f009f..2bad5a90e11 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -22,6 +22,16 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_RANGE_OP_H
 #define GCC_RANGE_OP_H
 
+enum range_op_dispatch_type
+{
+  DISPATCH_FOLD_RANGE,
+  DISPATCH_OP1_RANGE,
+  DISPATCH_OP2_RANGE,
+  DISPATCH_LHS_OP1_RELATION,
+  DISPATCH_LHS_OP2_RELATION,
+  DISPATCH_OP1_OP2_RELATION
+};
+
 // This class is implemented for each kind of operator supported by
 // the range generator.  It serves various purposes.
 //
@@ -76,6 +86,26 @@ public:
 			   const irange &lh,
 			   const irange &rh,
 			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (prange &r, tree type,
+			   const prange &lh,
+			   const prange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (prange &r, tree type,
+			   const prange &lh,
+			   const irange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (irange &r, tree type,
+			   const prange &lh,
+			   const prange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (prange &r, tree type,
+			   const irange &lh,
+			   const prange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (irange &r, tree type,
+			   const prange &lh,
+			   const irange &rh,
+			   relation_trio = TRIO_VARYING) const;
 
   // Return the range for op[12] in the general case.  LHS is the range for
   // the LHS of the expression, OP[12]is the range for the other
@@ -92,6 +122,22 @@ public:
 			  const irange &lhs,
 			  const irange &op2,
 			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (prange &r, tree type,
+			  const prange &lhs,
+			  const prange &op2,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (prange &r, tree type,
+			  const irange &lhs,
+			  const prange &op2,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (prange &r, tree type,
+			  const prange &lhs,
+			  const irange &op2,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (irange &r, tree type,
+			  const prange &lhs,
+			  const irange &op2,
+			  relation_trio = TRIO_VARYING) const;
   virtual bool op1_range (frange &r, tree type,
 			  const frange &lhs,
 			  const frange &op2,
@@ -106,6 +152,14 @@ public:
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
+  virtual bool op2_range (prange &r, tree type,
+			  const irange &lhs,
+			  const prange &op1,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op2_range (irange &r, tree type,
+			  const prange &lhs,
+			  const prange &op1,
+			  relation_trio = TRIO_VARYING) const;
   virtual bool op2_range (frange &r, tree type,
 			  const frange &lhs,
 			  const frange &op1,
@@ -123,6 +177,18 @@ public:
 					  const irange &op1,
 					  const irange &op2,
 					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op1_relation (const prange &lhs,
+					  const prange &op1,
+					  const prange &op2,
+					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op1_relation (const prange &lhs,
+					  const irange &op1,
+					  const irange &op2,
+					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op1_relation (const irange &lhs,
+					  const prange &op1,
+					  const prange &op2,
+					  relation_kind = VREL_VARYING) const;
   virtual relation_kind lhs_op1_relation (const frange &lhs,
 					  const frange &op1,
 					  const frange &op2,
@@ -148,6 +214,9 @@ public:
   virtual relation_kind op1_op2_relation (const irange &lhs,
 					  const irange &op1,
 					  const irange &op2) const;
+  virtual relation_kind op1_op2_relation (const irange &lhs,
+					  const prange &op1,
+					  const prange &op2) const;
   virtual relation_kind op1_op2_relation (const irange &lhs,
 					  const frange &op1,
 					  const frange &op2) const;
@@ -160,6 +229,7 @@ public:
 
   // Compatability check for operands.
   virtual bool operand_check_p (tree, tree, tree) const;
+  virtual bool pointers_handled_p (enum range_op_dispatch_type, unsigned) const;
 
 protected:
   // Perform an integral operation between 2 sub-ranges and return it.
@@ -173,6 +243,26 @@ protected:
 					const irange &op1_range,
 					const irange &op2_range,
 					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (prange &lhs_range, tree type,
+					const prange &op1_range,
+					const prange &op2_range,
+					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (prange &lhs_range, tree type,
+					const prange &op1_range,
+					const irange &op2_range,
+					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
+					const prange &op1_range,
+					const prange &op2_range,
+					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (prange &lhs_range, tree type,
+					const irange &op1_range,
+					const prange &op2_range,
+					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
+					const prange &op1_range,
+					const irange &op2_range,
+					relation_kind rel) const;
   // Called by fold range to split small subranges into parts.
   void wi_fold_in_parts (irange &r, tree type,
 			 const wide_int &lh_lb,
@@ -187,6 +277,7 @@ protected:
 			       unsigned limit) const;
   // Apply any bitmasks implied by these ranges.
   virtual void update_bitmask (irange &, const irange &, const irange &) const;
+  virtual void update_bitmask (irange &, const prange &, const prange &) const;
 
   // Perform an float operation between 2 ranges and return it.
   virtual void rv_fold (frange &r, tree type,
@@ -234,6 +325,9 @@ public:
 protected:
   unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
 			  const vrange& op2) const;
+  void discriminator_fail (const vrange &,
+			   const vrange &,
+			   const vrange &) const;
   range_operator *m_operator;
 };
 
@@ -316,4 +410,21 @@ protected:
   void initialize_pointer_ops ();
   void initialize_float_ops ();
 };
+
+// Temporary exports so the pointers_handled_p() sanity code can see
+// which pointer combination is being attempted.  This will be deleted
+// once pointers_handled_p is gone.
+extern const unsigned RO_III;
+extern const unsigned RO_IFI;
+extern const unsigned RO_IFF;
+extern const unsigned RO_FFF;
+extern const unsigned RO_FIF;
+extern const unsigned RO_FII;
+extern const unsigned RO_PPP;
+extern const unsigned RO_PPI;
+extern const unsigned RO_IPP;
+extern const unsigned RO_IPI;
+extern const unsigned RO_PIP;
+extern const unsigned RO_PII;
+
 #endif // GCC_RANGE_OP_H
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 08/23] Implement operator_identity for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (6 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 07/23] Implement range-op dispatch for prange Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 09/23] Implement operator_cst " Aldy Hernandez
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for fold_range, op1_range,
	lhs_op1_relation, pointers_handled_p.
	* range-op-ptr.cc (operator_identity::fold_range): New.
	(operator_identity::lhs_op1_relation): New.
	(operator_identity::op1_range): New.
	(operator_identity::pointers_handled_p): New.
---
 gcc/range-op-mixed.h | 10 ++++++++++
 gcc/range-op-ptr.cc  | 47 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 8163a4b53ca..60aaea9563d 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -349,18 +349,28 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED,
 		   const frange &op1, const frange &op2 ATTRIBUTE_UNUSED,
 		   relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const prange &lhs, const prange &op2,
+		  relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED,
 		  const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED,
 		  relation_trio = TRIO_VARYING) const final override;
   relation_kind lhs_op1_relation (const irange &lhs,
 				  const irange &op1, const irange &op2,
 				  relation_kind rel) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+				  const prange &op1, const prange &op2,
+				  relation_kind rel) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_cst : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 560c798b90a..08419bfc798 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -636,6 +636,53 @@ public:
     }
 } op_hybrid_max;
 
+bool
+operator_identity::fold_range (prange &r, tree type ATTRIBUTE_UNUSED,
+			       const prange &lh ATTRIBUTE_UNUSED,
+			       const prange &rh ATTRIBUTE_UNUSED,
+			       relation_trio) const
+{
+  r = lh;
+  return true;
+}
+
+relation_kind
+operator_identity::lhs_op1_relation (const prange &lhs,
+				     const prange &op1 ATTRIBUTE_UNUSED,
+				     const prange &op2 ATTRIBUTE_UNUSED,
+				     relation_kind) const
+{
+  if (lhs.undefined_p ())
+    return VREL_VARYING;
+  // Simply a copy, so they are equivalent.
+  return VREL_EQ;
+}
+
+bool
+operator_identity::op1_range (prange &r, tree type ATTRIBUTE_UNUSED,
+			      const prange &lhs,
+			      const prange &op2 ATTRIBUTE_UNUSED,
+			      relation_trio) const
+{
+  r = lhs;
+  return true;
+}
+
+bool
+operator_identity::pointers_handled_p (range_op_dispatch_type type,
+				       unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_LHS_OP1_RELATION:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 09/23] Implement operator_cst for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (7 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 08/23] Implement operator_identity " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 10/23] Implement operator_cast " Aldy Hernandez
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_cst::fold_range): New.
	(operator_cst::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  4 ++++
 gcc/range-op-ptr.cc  | 23 +++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 60aaea9563d..04c8acbd94a 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -380,9 +380,13 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (frange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 08419bfc798..e59e278cbd7 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -683,6 +683,29 @@ operator_identity::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_cst::fold_range (prange &r, tree type ATTRIBUTE_UNUSED,
+			  const prange &lh,
+			  const prange & ATTRIBUTE_UNUSED,
+			  relation_trio) const
+{
+  r = lh;
+  return true;
+}
+
+bool
+operator_cst::pointers_handled_p (range_op_dispatch_type type,
+				  unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 10/23] Implement operator_cast for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (8 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 09/23] Implement operator_cst " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 11/23] Implement operator_min and operator_max " Aldy Hernandez
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_cast::fold_range): New.
	(operator_cast::op1_range): New.
	(operator_cast::lhs_op1_relation): New.
	(operator_cast::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  28 +++++
 gcc/range-op-ptr.cc  | 245 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 273 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 04c8acbd94a..11b1bf0bca4 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -400,14 +400,42 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const irange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+		   const irange &op1, const prange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const prange &lhs, const prange &op2,
+		  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (irange &r, tree type,
+		  const prange &lhs, const irange &op2,
+		  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio rel = TRIO_VARYING) const final override;
   relation_kind lhs_op1_relation (const irange &lhs,
 				  const irange &op1, const irange &op2,
 				  relation_kind) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+				  const prange &op1, const prange &op2,
+				  relation_kind) const final override;
+  relation_kind lhs_op1_relation (const prange &lhs,
+				  const irange &op1, const irange &op2,
+				  relation_kind) const final override;
+  relation_kind lhs_op1_relation (const irange &lhs,
+				  const prange &op1, const prange &op2,
+				  relation_kind) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 private:
   bool truncating_cast_p (const irange &inner, const irange &outer) const;
   bool inside_domain_p (const wide_int &min, const wide_int &max,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index e59e278cbd7..b8f86c8e838 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -706,6 +706,251 @@ operator_cst::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+// Cast between pointers.
+
+bool
+operator_cast::fold_range (prange &r, tree type,
+			   const prange &inner,
+			   const prange &outer,
+			   relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+    return true;
+
+  r.set (type, inner.lower_bound (), inner.upper_bound ());
+  r.update_bitmask (inner.get_bitmask ());
+  return true;
+}
+
+// Cast a pointer to an integer.
+
+bool
+operator_cast::fold_range (irange &r, tree type,
+			   const prange &inner,
+			   const irange &outer,
+			   relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+    return true;
+
+  // Represent INNER as an integer of the same size, and then cast it
+  // to the resulting integer type.
+  tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (inner.type ()));
+  r.set (pointer_uint_type, inner.lower_bound (), inner.upper_bound ());
+  r.update_bitmask (inner.get_bitmask ());
+  range_cast (r, type);
+  return true;
+}
+
+// Cast an integer to a pointer.
+
+bool
+operator_cast::fold_range (prange &r, tree type,
+			   const irange &inner,
+			   const prange &outer,
+			   relation_trio) const
+{
+  if (empty_range_varying (r, type, inner, outer))
+    return true;
+
+  // Cast INNER to an integer of the same size as the pointer we want,
+  // and then copy the bounds to the resulting pointer range.
+  int_range<2> tmp = inner;
+  tree pointer_uint_type = make_unsigned_type (TYPE_PRECISION (type));
+  range_cast (tmp, pointer_uint_type);
+  r.set (type, tmp.lower_bound (), tmp.upper_bound ());
+  r.update_bitmask (tmp.get_bitmask ());
+  return true;
+}
+
+bool
+operator_cast::op1_range (prange &r, tree type,
+			  const prange &lhs,
+			  const prange &op2,
+			  relation_trio trio) const
+{
+  if (lhs.undefined_p ())
+    return false;
+  gcc_checking_assert (types_compatible_p (op2.type(), type));
+
+  // Conversion from other pointers or a constant (including 0/NULL)
+  // are straightforward.
+  if (POINTER_TYPE_P (lhs.type ())
+      || (lhs.singleton_p ()
+	  && TYPE_PRECISION (lhs.type ()) >= TYPE_PRECISION (type)))
+    fold_range (r, type, lhs, op2, trio);
+  else
+    {
+      // If the LHS is not a pointer nor a singleton, then it is
+      // either VARYING or non-zero.
+      if (!lhs.undefined_p () && !range_includes_zero_p (lhs))
+	r.set_nonzero (type);
+      else
+	r.set_varying (type);
+    }
+  r.intersect (op2);
+  return true;
+}
+
+bool
+operator_cast::op1_range (irange &r, tree type,
+			  const prange &lhs,
+			  const irange &op2,
+			  relation_trio trio) const
+{
+  if (lhs.undefined_p ())
+    return false;
+  gcc_checking_assert (types_compatible_p (op2.type(), type));
+
+  // Conversion from other pointers or a constant (including 0/NULL)
+  // are straightforward.
+  if (POINTER_TYPE_P (lhs.type ())
+      || (lhs.singleton_p ()
+	  && TYPE_PRECISION (lhs.type ()) >= TYPE_PRECISION (type)))
+    fold_range (r, type, lhs, op2, trio);
+  else
+    {
+      // If the LHS is not a pointer nor a singleton, then it is
+      // either VARYING or non-zero.
+      if (!lhs.undefined_p () && !range_includes_zero_p (lhs))
+	r.set_nonzero (type);
+      else
+	r.set_varying (type);
+    }
+  r.intersect (op2);
+  return true;
+}
+
+bool
+operator_cast::op1_range (prange &r, tree type,
+			  const irange &lhs,
+			  const prange &op2,
+			  relation_trio trio) const
+{
+  if (lhs.undefined_p ())
+    return false;
+  gcc_checking_assert (types_compatible_p (op2.type(), type));
+
+  // Conversion from other pointers or a constant (including 0/NULL)
+  // are straightforward.
+  if (POINTER_TYPE_P (lhs.type ())
+      || (lhs.singleton_p ()
+	  && TYPE_PRECISION (lhs.type ()) >= TYPE_PRECISION (type)))
+    fold_range (r, type, lhs, op2, trio);
+  else
+    {
+      // If the LHS is not a pointer nor a singleton, then it is
+      // either VARYING or non-zero.
+      if (!lhs.undefined_p () && !range_includes_zero_p (lhs))
+	r.set_nonzero (type);
+      else
+	r.set_varying (type);
+    }
+  r.intersect (op2);
+  return true;
+}
+
+relation_kind
+operator_cast::lhs_op1_relation (const prange &lhs,
+				 const prange &op1,
+				 const prange &op2 ATTRIBUTE_UNUSED,
+				 relation_kind) const
+{
+  if (lhs.undefined_p () || op1.undefined_p ())
+    return VREL_VARYING;
+  unsigned lhs_prec = TYPE_PRECISION (lhs.type ());
+  unsigned op1_prec = TYPE_PRECISION (op1.type ());
+  // If the result gets sign extended into a larger type check first if this
+  // qualifies as a partial equivalence.
+  if (TYPE_SIGN (op1.type ()) == SIGNED && lhs_prec > op1_prec)
+    {
+      // If the result is sign extended, and the LHS is larger than op1,
+      // check if op1's range can be negative as the sign extension will
+      // cause the upper bits to be 1 instead of 0, invalidating the PE.
+      int_range<3> negs = range_negatives (op1.type ());
+      negs.intersect (op1);
+      if (!negs.undefined_p ())
+	return VREL_VARYING;
+    }
+
+  unsigned prec = MIN (lhs_prec, op1_prec);
+  return bits_to_pe (prec);
+}
+
+relation_kind
+operator_cast::lhs_op1_relation (const prange &lhs,
+				 const irange &op1,
+				 const irange &op2 ATTRIBUTE_UNUSED,
+				 relation_kind) const
+{
+  if (lhs.undefined_p () || op1.undefined_p ())
+    return VREL_VARYING;
+  unsigned lhs_prec = TYPE_PRECISION (lhs.type ());
+  unsigned op1_prec = TYPE_PRECISION (op1.type ());
+  // If the result gets sign extended into a larger type check first if this
+  // qualifies as a partial equivalence.
+  if (TYPE_SIGN (op1.type ()) == SIGNED && lhs_prec > op1_prec)
+    {
+      // If the result is sign extended, and the LHS is larger than op1,
+      // check if op1's range can be negative as the sign extension will
+      // cause the upper bits to be 1 instead of 0, invalidating the PE.
+      int_range<3> negs = range_negatives (op1.type ());
+      negs.intersect (op1);
+      if (!negs.undefined_p ())
+	return VREL_VARYING;
+    }
+
+  unsigned prec = MIN (lhs_prec, op1_prec);
+  return bits_to_pe (prec);
+}
+
+relation_kind
+operator_cast::lhs_op1_relation (const irange &lhs,
+				 const prange &op1,
+				 const prange &op2 ATTRIBUTE_UNUSED,
+				 relation_kind) const
+{
+  if (lhs.undefined_p () || op1.undefined_p ())
+    return VREL_VARYING;
+  unsigned lhs_prec = TYPE_PRECISION (lhs.type ());
+  unsigned op1_prec = TYPE_PRECISION (op1.type ());
+  // If the result gets sign extended into a larger type check first if this
+  // qualifies as a partial equivalence.
+  if (TYPE_SIGN (op1.type ()) == SIGNED && lhs_prec > op1_prec)
+    {
+      // If the result is sign extended, and the LHS is larger than op1,
+      // check if op1's range can be negative as the sign extension will
+      // cause the upper bits to be 1 instead of 0, invalidating the PE.
+      int_range<3> negs = range_negatives (op1.type ());
+      negs.intersect (op1);
+      if (!negs.undefined_p ())
+	return VREL_VARYING;
+    }
+
+  unsigned prec = MIN (lhs_prec, op1_prec);
+  return bits_to_pe (prec);
+}
+
+bool
+operator_cast::pointers_handled_p (range_op_dispatch_type type,
+				   unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+    case DISPATCH_OP1_RANGE:
+      return (dispatch == RO_PPP
+	      || dispatch == RO_IPI
+	      || dispatch == RO_PIP);
+    case DISPATCH_LHS_OP1_RELATION:
+      return (dispatch == RO_PPP
+	      || dispatch == RO_PII
+	      || dispatch == RO_IPP);
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 11/23] Implement operator_min and operator_max for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (9 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 10/23] Implement operator_cast " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 12/23] Implement operator_addr_expr " Aldy Hernandez
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_min::fold_range): New.
	(operator_min::pointers_handled_p): New.
	(operator_max::fold_range): New.
	(operator_max::pointers_handled_p): New.
---
 gcc/range-op-mixed.h | 12 ++++++++
 gcc/range-op-ptr.cc  | 70 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 11b1bf0bca4..b69e674a78b 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -761,12 +761,18 @@ protected:
 class operator_min : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1,
+		   const prange &op2,
+		   relation_trio) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const override;
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
     { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
 		const wide_int &lh_ub, const wide_int &rh_lb,
@@ -776,12 +782,18 @@ protected:
 class operator_max : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1,
+		   const prange &op2,
+		   relation_trio) const final override;
   void update_bitmask (irange &r, const irange &lh,
       const irange &rh) const override;
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
     { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
 		const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index b8f86c8e838..0addd1096c2 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -951,6 +951,76 @@ operator_cast::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_min::fold_range (prange &r, tree type,
+			  const prange &op1,
+			  const prange &op2,
+			  relation_trio) const
+{
+  // For MIN/MAX expressions with pointers, we only care about
+  // nullness.  If both are non null, then the result is nonnull.
+  // If both are null, then the result is null.  Otherwise they
+  // are varying.
+  if (!range_includes_zero_p (op1)
+      && !range_includes_zero_p (op2))
+    r.set_nonzero (type);
+  else if (op1.zero_p () && op2.zero_p ())
+    r.set_zero (type);
+  else
+    r.set_varying (type);
+
+  update_known_bitmask (r, MIN_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_min::pointers_handled_p (range_op_dispatch_type type,
+				  unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
+bool
+operator_max::fold_range (prange &r, tree type,
+			  const prange &op1,
+			  const prange &op2,
+			  relation_trio) const
+{
+  // For MIN/MAX expressions with pointers, we only care about
+  // nullness.  If both are non null, then the result is nonnull.
+  // If both are null, then the result is null.  Otherwise they
+  // are varying.
+  if (!range_includes_zero_p (op1)
+      && !range_includes_zero_p (op2))
+    r.set_nonzero (type);
+  else if (op1.zero_p () && op2.zero_p ())
+    r.set_zero (type);
+  else
+    r.set_varying (type);
+
+  update_known_bitmask (r, MAX_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_max::pointers_handled_p (range_op_dispatch_type type,
+				  unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 12/23] Implement operator_addr_expr for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (10 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 11/23] Implement operator_min and operator_max " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 13/23] Implement pointer_plus_operator " Aldy Hernandez
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_addr_expr::op1_range): New.
	(operator_addr_expr::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  4 ++++
 gcc/range-op-ptr.cc  | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b69e674a78b..0df300781f1 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -655,6 +655,10 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const prange &lhs, const prange &op2,
+		  relation_trio rel = TRIO_VARYING) const final override;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_bitwise_not : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 0addd1096c2..38d9f65566f 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1021,6 +1021,44 @@ operator_max::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_addr_expr::op1_range (prange &r, tree type,
+			       const prange &lhs,
+			       const prange &op2,
+			       relation_trio) const
+{
+  if (empty_range_varying (r, type, lhs, op2))
+    return true;
+
+  // Return a non-null pointer of the LHS type (passed in op2), but only
+  // if we cant overflow, eitherwise a no-zero offset could wrap to zero.
+  // See PR 111009.
+  if (!lhs.undefined_p ()
+      && !range_includes_zero_p (lhs)
+      && TYPE_OVERFLOW_UNDEFINED (type))
+    r.set_nonzero (type);
+  else
+    r.set_varying (type);
+  return true;
+}
+
+bool
+operator_addr_expr::pointers_handled_p (range_op_dispatch_type type,
+					unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      // NOTE: It looks like we never generate this combination.
+      gcc_unreachable ();
+      return false;
+    case DISPATCH_OP1_RANGE:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 13/23] Implement pointer_plus_operator for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (11 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 12/23] Implement operator_addr_expr " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 14/23] Implement operator_pointer_diff " Aldy Hernandez
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-ptr.cc (class pointer_plus_operator): Add overloaded declarations
	for pointer variants.
	(pointer_plus_operator::fold_range): New.
	(pointer_plus_operator::op2_range): New.
	(pointer_plus_operator::pointers_handled_p): New.
---
 gcc/range-op-ptr.cc | 98 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)

diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 38d9f65566f..a4418215613 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -265,8 +265,17 @@ range_operator::update_bitmask (irange &,
 class pointer_plus_operator : public range_operator
 {
   using range_operator::update_bitmask;
+  using range_operator::fold_range;
   using range_operator::op2_range;
 public:
+  virtual bool fold_range (prange &r, tree type,
+			   const prange &op1,
+			   const irange &op2,
+			   relation_trio) const final override;
+  virtual bool op2_range (irange &r, tree type,
+			  const prange &lhs,
+			  const prange &op1,
+			  relation_trio = TRIO_VARYING) const final override;
   virtual void wi_fold (irange &r, tree type,
 			const wide_int &lh_lb,
 			const wide_int &lh_ub,
@@ -276,10 +285,99 @@ public:
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
   void update_bitmask (irange &r, const irange &lh, const irange &rh) const
     { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); }
 } op_pointer_plus;
 
+bool
+pointer_plus_operator::fold_range (prange &r, tree type,
+				   const prange &op1,
+				   const irange &op2,
+				   relation_trio) const
+{
+  if (empty_range_varying (r, type, op1, op2))
+    return true;
+
+  const wide_int lh_lb = op1.lower_bound ();
+  const wide_int lh_ub = op1.upper_bound ();
+  const wide_int rh_lb = op2.lower_bound ();
+  const wide_int rh_ub = op2.upper_bound ();
+
+  // Check for [0,0] + const, and simply return the const.
+  if (lh_lb == 0 && lh_ub == 0 && rh_lb == rh_ub)
+    {
+      r.set (type, rh_lb, rh_lb);
+      return true;
+    }
+
+  // For pointer types, we are really only interested in asserting
+  // whether the expression evaluates to non-NULL.
+  //
+  // With -fno-delete-null-pointer-checks we need to be more
+  // conservative.  As some object might reside at address 0,
+  // then some offset could be added to it and the same offset
+  // subtracted again and the result would be NULL.
+  // E.g.
+  // static int a[12]; where &a[0] is NULL and
+  // ptr = &a[6];
+  // ptr -= 6;
+  // ptr will be NULL here, even when there is POINTER_PLUS_EXPR
+  // where the first range doesn't include zero and the second one
+  // doesn't either.  As the second operand is sizetype (unsigned),
+  // consider all ranges where the MSB could be set as possible
+  // subtractions where the result might be NULL.
+  if ((!wi_includes_zero_p (type, lh_lb, lh_ub)
+       || !wi_includes_zero_p (type, rh_lb, rh_ub))
+      && !TYPE_OVERFLOW_WRAPS (type)
+      && (flag_delete_null_pointer_checks
+	  || !wi::sign_mask (rh_ub)))
+    r.set_nonzero (type);
+  else if (lh_lb == lh_ub && lh_lb == 0
+	   && rh_lb == rh_ub && rh_lb == 0)
+    r.set_zero (type);
+  else
+   r.set_varying (type);
+
+  update_known_bitmask (r, POINTER_PLUS_EXPR, op1, op2);
+  return true;
+}
+
+bool
+pointer_plus_operator::op2_range (irange &r, tree type,
+				  const prange &lhs ATTRIBUTE_UNUSED,
+				  const prange &op1 ATTRIBUTE_UNUSED,
+				  relation_trio trio) const
+{
+  relation_kind rel = trio.lhs_op1 ();
+  r.set_varying (type);
+
+  // If the LHS and OP1 are equal, the op2 must be zero.
+  if (rel == VREL_EQ)
+    r.set_zero (type);
+  // If the LHS and OP1 are not equal, the offset must be non-zero.
+  else if (rel == VREL_NE)
+    r.set_nonzero (type);
+  else
+    return false;
+  return true;
+}
+
+bool
+pointer_plus_operator::pointers_handled_p (range_op_dispatch_type type,
+					   unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_PPI;
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 void
 pointer_plus_operator::wi_fold (irange &r, tree type,
 				const wide_int &lh_lb,
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 14/23] Implement operator_pointer_diff for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (12 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 13/23] Implement pointer_plus_operator " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 15/23] Implement operator_bitwise_and " Aldy Hernandez
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-ptr.cc
	(operator_pointer_diff::op1_op2_relation_effect): New.
	(operator_pointer_diff::pointers_handled_p): New.
---
 gcc/range-op-ptr.cc | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index a4418215613..b90b8bb9f65 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -564,10 +564,42 @@ class operator_pointer_diff : public range_operator
 					const irange &op1_range,
 					const irange &op2_range,
 					relation_kind rel) const;
+  virtual bool op1_op2_relation_effect (irange &lhs_range,
+					tree type,
+					const prange &op1_range,
+					const prange &op2_range,
+					relation_kind rel) const final override;
   void update_bitmask (irange &r, const irange &lh, const irange &rh) const
     { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); }
+  void update_bitmask (irange &r,
+		       const prange &lh, const prange &rh) const final override
+  { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 } op_pointer_diff;
 
+bool
+operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
+						const prange &op1_range,
+						const prange &op2_range,
+						relation_kind rel) const
+{
+  int_range<2> op1, op2, tmp;
+  range_op_handler cast (CONVERT_EXPR);
+
+  if (!cast.fold_range (op1, type, op1_range, tmp)
+      || !cast.fold_range (op2, type, op2_range, tmp))
+    return false;
+
+  return minus_op1_op2_relation_effect (lhs_range, type, op1, op2, rel);
+}
+
+bool
+operator_pointer_diff::pointers_handled_p (range_op_dispatch_type,
+					   unsigned) const
+{
+  return true;
+}
+
 bool
 operator_pointer_diff::op1_op2_relation_effect (irange &lhs_range, tree type,
 						const irange &op1_range,
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 15/23] Implement operator_bitwise_and for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (13 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 14/23] Implement operator_pointer_diff " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 16/23] Implement operator_bitwise_or " Aldy Hernandez
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_bitwise_and::fold_range): New.
	(operator_bitwise_and::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  6 ++++++
 gcc/range-op-ptr.cc  | 30 ++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 0df300781f1..6158fc51f8e 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -712,10 +712,15 @@ private:
 class operator_bitwise_and : public range_operator
 {
 public:
+  using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
   using range_operator::update_bitmask;
+  bool fold_range (prange &r, tree type,
+		   const prange &op1,
+		   const prange &op2,
+		   relation_trio) const final override;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio rel = TRIO_VARYING) const override;
@@ -730,6 +735,7 @@ public:
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
     { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
 		const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index b90b8bb9f65..8d5049b1daf 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1189,6 +1189,36 @@ operator_addr_expr::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_bitwise_and::fold_range (prange &r, tree type,
+				  const prange &op1,
+				  const prange &op2 ATTRIBUTE_UNUSED,
+				  relation_trio) const
+{
+  // For pointer types, we are really only interested in asserting
+  // whether the expression evaluates to non-NULL.
+  if (op1.zero_p () || op2.zero_p ())
+    r.set_zero (type);
+  else
+    r.set_varying (type);
+
+  update_known_bitmask (r, BIT_AND_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_bitwise_and::pointers_handled_p (range_op_dispatch_type type,
+					  unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_PPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 16/23] Implement operator_bitwise_or for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (14 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 15/23] Implement operator_bitwise_and " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 17/23] Implement operator_not_equal " Aldy Hernandez
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

We seem to have a range-op entry for pointer bitwise OR that we've
inherited from the original VRP implementation, but it never gets
used.  If this is not valid gimple, we can safely remove this entry.

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_bitwise_or::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  1 +
 gcc/range-op-ptr.cc  | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 6158fc51f8e..c45aed93567 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -762,6 +762,7 @@ public:
   // Check compatibility of all operands.
   bool operand_check_p (tree t1, tree t2, tree t3) const final override
     { return range_compatible_p (t1, t2) && range_compatible_p (t1, t3); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 protected:
   void wi_fold (irange &r, tree type, const wide_int &lh_lb,
 		const wide_int &lh_ub, const wide_int &rh_lb,
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 8d5049b1daf..2f2f4bb2b5d 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1219,6 +1219,17 @@ operator_bitwise_and::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_bitwise_or::pointers_handled_p (range_op_dispatch_type,
+					 unsigned) const
+{
+  // NOTE: It looks like we never generate bitwise OR with pointers.
+  // If this is indeed the case, we can move operator_bitwise_or from
+  // range-op-mixed.h to range-op.h.
+  gcc_unreachable ();
+  return false;
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 17/23] Implement operator_not_equal for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (15 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 16/23] Implement operator_bitwise_or " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 18/23] Implement operator_equal " Aldy Hernandez
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_not_equal::fold_range): New.
	(operator_not_equal::op1_range): New.
	(operator_not_equal::op2_range): New.
	(operator_not_equal::op1_op2_relation): New.
	(operator_not_equal::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++++
 gcc/range-op-ptr.cc  | 118 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index c45aed93567..980611dc339 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -155,6 +155,9 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
@@ -162,6 +165,9 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
@@ -169,12 +175,17 @@ public:
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -182,6 +193,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_lt :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 2f2f4bb2b5d..081e8fdba1f 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1230,6 +1230,124 @@ operator_bitwise_or::pointers_handled_p (range_op_dispatch_type,
   return false;
 }
 
+bool
+operator_not_equal::fold_range (irange &r, tree type,
+				const prange &op1,
+				const prange &op2,
+				relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_NE))
+    return true;
+
+  // We can be sure the values are always equal or not if both ranges
+  // consist of a single value, and then compare them.
+  bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ());
+  bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ());
+  if (op1_const && op2_const)
+    {
+      if (wi::ne_p (op1.lower_bound (), op2.upper_bound()))
+	r = range_true ();
+      else
+	r = range_false ();
+    }
+  else
+    {
+      // If ranges do not intersect, we know the range is not equal,
+      // otherwise we don't know anything for sure.
+      prange tmp = op1;
+      tmp.intersect (op2);
+      if (tmp.undefined_p ())
+	r = range_true ();
+      // Check if a constant cannot satisfy the bitmask requirements.
+      else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+	 r = range_true ();
+      else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+	 r = range_true ();
+      else
+	r = range_true_and_false ();
+    }
+
+  //update_known_bitmask (r, NE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_not_equal::op1_range (prange &r, tree type,
+			       const irange &lhs,
+			       const prange &op2,
+			       relation_trio) const
+{
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      // If the result is true, the only time we know anything is if
+      // OP2 is a constant.
+      if (!op2.undefined_p ()
+	  && wi::eq_p (op2.lower_bound(), op2.upper_bound()))
+	{
+	  r = op2;
+	  r.invert ();
+	}
+      else
+	r.set_varying (type);
+      break;
+
+    case BRS_FALSE:
+      // If it's false, the result is the same as OP2.
+      r = op2;
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+
+bool
+operator_not_equal::op2_range (prange &r, tree type,
+			       const irange &lhs,
+			       const prange &op1,
+			       relation_trio rel) const
+{
+  return operator_not_equal::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ());
+}
+
+relation_kind
+operator_not_equal::op1_op2_relation (const irange &lhs, const prange &,
+				      const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 != op2  indicates EQ_EXPR.
+  if (lhs.zero_p ())
+    return VREL_EQ;
+
+  // TRUE = op1 != op2  indicates NE_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_NE;
+  return VREL_VARYING;
+}
+
+bool
+operator_not_equal::pointers_handled_p (range_op_dispatch_type type,
+					unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 18/23] Implement operator_equal for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (16 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 17/23] Implement operator_not_equal " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 19/23] Implement operator_lt " Aldy Hernandez
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_equal::fold_range): New.
	(operator_equal::op1_range): New.
	(operator_equal::op2_range): New.
	(operator_equal::op1_op2_relation): New.
	(operator_equal::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++++
 gcc/range-op-ptr.cc  | 117 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 129 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 980611dc339..ee8d9dd328f 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -115,6 +115,9 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -122,6 +125,9 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &val,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &val,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
@@ -129,12 +135,17 @@ public:
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &val,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &val,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio rel = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -142,6 +153,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_not_equal : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 081e8fdba1f..fb2888bf079 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1230,6 +1230,123 @@ operator_bitwise_or::pointers_handled_p (range_op_dispatch_type,
   return false;
 }
 
+bool
+operator_equal::fold_range (irange &r, tree type,
+			    const prange &op1,
+			    const prange &op2,
+			    relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_EQ))
+    return true;
+
+  // We can be sure the values are always equal or not if both ranges
+  // consist of a single value, and then compare them.
+  bool op1_const = wi::eq_p (op1.lower_bound (), op1.upper_bound ());
+  bool op2_const = wi::eq_p (op2.lower_bound (), op2.upper_bound ());
+  if (op1_const && op2_const)
+    {
+      if (wi::eq_p (op1.lower_bound (), op2.upper_bound()))
+	r = range_true ();
+      else
+	r = range_false ();
+    }
+  else
+    {
+      // If ranges do not intersect, we know the range is not equal,
+      // otherwise we don't know anything for sure.
+      prange tmp = op1;
+      tmp.intersect (op2);
+      if (tmp.undefined_p ())
+	r = range_false ();
+      // Check if a constant cannot satisfy the bitmask requirements.
+      else if (op2_const && !op1.get_bitmask ().member_p (op2.lower_bound ()))
+	 r = range_false ();
+      else if (op1_const && !op2.get_bitmask ().member_p (op1.lower_bound ()))
+	 r = range_false ();
+      else
+	r = range_true_and_false ();
+    }
+
+  //update_known_bitmask (r, EQ_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_equal::op1_range (prange &r, tree type,
+			   const irange &lhs,
+			   const prange &op2,
+			   relation_trio) const
+{
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      // If it's true, the result is the same as OP2.
+      r = op2;
+      break;
+
+    case BRS_FALSE:
+      // If the result is false, the only time we know anything is
+      // if OP2 is a constant.
+      if (!op2.undefined_p ()
+	  && wi::eq_p (op2.lower_bound(), op2.upper_bound()))
+	{
+	  r = op2;
+	  r.invert ();
+	}
+      else
+	r.set_varying (type);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+bool
+operator_equal::op2_range (prange &r, tree type,
+			   const irange &lhs,
+			   const prange &op1,
+			   relation_trio rel) const
+{
+  return operator_equal::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ());
+}
+
+relation_kind
+operator_equal::op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 == op2 indicates NE_EXPR.
+  if (lhs.zero_p ())
+    return VREL_NE;
+
+  // TRUE = op1 == op2 indicates EQ_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_EQ;
+  return VREL_VARYING;
+}
+
+bool
+operator_equal::pointers_handled_p (range_op_dispatch_type type,
+				    unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 bool
 operator_not_equal::fold_range (irange &r, tree type,
 				const prange &op1,
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 19/23] Implement operator_lt for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (17 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 18/23] Implement operator_equal " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 20/23] Implement operator_le " Aldy Hernandez
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (max_limit): New.
	(min_limit): New.
	(build_lt): New.
	(build_le): New.
	(build_gt): New.
	(build_ge): New.
	(operator_lt::fold_range): New.
	(operator_lt::op1_range): New.
	(operator_lt::op2_range): New.
	(operator_lt::op1_op2_relation): New.
	(operator_lt::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++
 gcc/range-op-ptr.cc  | 174 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 186 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index ee8d9dd328f..b82d06572a7 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -219,23 +219,34 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -243,6 +254,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_le :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index fb2888bf079..11629ba6d8d 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -262,6 +262,69 @@ range_operator::update_bitmask (irange &,
 {
 }
 
+// Return the upper limit for a type.
+
+static inline wide_int
+max_limit (const_tree type)
+{
+  return wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+}
+
+// Return the lower limit for a type.
+
+static inline wide_int
+min_limit (const_tree type)
+{
+  return wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+}
+
+// Build a range that is < VAL and store it in R.
+
+static void
+build_lt (prange &r, tree type, const prange &val)
+{
+  wi::overflow_type ov;
+  wide_int lim = wi::sub (val.upper_bound (), 1, UNSIGNED, &ov);
+
+  // If val - 1 underflows, check if X < MIN, which is an empty range.
+  if (ov)
+    r.set_undefined ();
+  else
+    r.set (type, min_limit (type), lim);
+}
+
+// Build a range that is <= VAL and store it in R.
+
+static void
+build_le (prange &r, tree type, const prange &val)
+{
+  r.set (type, min_limit (type), val.upper_bound ());
+}
+
+// Build a range that is > VAL and store it in R.
+
+static void
+build_gt (prange &r, tree type, const prange &val)
+{
+  wi::overflow_type ov;
+  wide_int lim = wi::add (val.lower_bound (), 1, UNSIGNED, &ov);
+
+  // If val + 1 overflows, check is for X > MAX, which is an empty range.
+  if (ov)
+    r.set_undefined ();
+  else
+    r.set (type, lim, max_limit (type));
+
+}
+
+// Build a range that is >= VAL and store it in R.
+
+static void
+build_ge (prange &r, tree type, const prange &val)
+{
+  r.set (type, val.lower_bound (), max_limit (type));
+}
+
 class pointer_plus_operator : public range_operator
 {
   using range_operator::update_bitmask;
@@ -1465,6 +1528,117 @@ operator_not_equal::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_lt::fold_range (irange &r, tree type,
+			 const prange &op1,
+			 const prange &op2,
+			 relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_LT))
+    return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::lt_p (op1.upper_bound (), op2.lower_bound (), sign))
+    r = range_true ();
+  else if (!wi::lt_p (op1.lower_bound (), op2.upper_bound (), sign))
+    r = range_false ();
+  // Use nonzero bits to determine if < 0 is false.
+  else if (op2.zero_p () && !wi::neg_p (op1.get_nonzero_bits (), sign))
+    r = range_false ();
+  else
+    r = range_true_and_false ();
+
+  //update_known_bitmask (r, LT_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_lt::op1_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op2,
+			relation_trio) const
+{
+  if (op2.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_lt (r, type, op2);
+      break;
+
+    case BRS_FALSE:
+      build_ge (r, type, op2);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+bool
+operator_lt::op2_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op1,
+			relation_trio) const
+{
+  if (op1.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_gt (r, type, op1);
+      break;
+
+    case BRS_FALSE:
+      build_le (r, type, op1);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+relation_kind
+operator_lt::op1_op2_relation (const irange &lhs, const prange &,
+			       const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 < op2 indicates GE_EXPR.
+  if (lhs.zero_p ())
+    return VREL_GE;
+
+  // TRUE = op1 < op2 indicates LT_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_LT;
+  return VREL_VARYING;
+}
+
+bool
+operator_lt::pointers_handled_p (range_op_dispatch_type type,
+				 unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 20/23] Implement operator_le for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (18 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 19/23] Implement operator_lt " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 21/23] Implement operator_gt " Aldy Hernandez
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_le::fold_range): New.
	(operator_le::op1_range): New.
	(operator_le::op2_range): New.
	(operator_le::op1_op2_relation): New.
	(operator_le::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++++
 gcc/range-op-ptr.cc  | 108 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b82d06572a7..571729e2ab6 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -268,6 +268,9 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio rel = TRIO_VARYING) const final override;
@@ -275,6 +278,9 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio rel = TRIO_VARYING) const final override;
@@ -282,12 +288,17 @@ public:
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio rel = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -295,6 +306,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_gt :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 11629ba6d8d..eb28211b583 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1639,6 +1639,114 @@ operator_lt::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_le::fold_range (irange &r, tree type,
+			 const prange &op1,
+			 const prange &op2,
+			 relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_LE))
+    return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::le_p (op1.upper_bound (), op2.lower_bound (), sign))
+    r = range_true ();
+  else if (!wi::le_p (op1.lower_bound (), op2.upper_bound (), sign))
+    r = range_false ();
+  else
+    r = range_true_and_false ();
+
+  //update_known_bitmask (r, LE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_le::op1_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op2,
+			relation_trio) const
+{
+  if (op2.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_le (r, type, op2);
+      break;
+
+    case BRS_FALSE:
+      build_gt (r, type, op2);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+bool
+operator_le::op2_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op1,
+			relation_trio) const
+{
+  if (op1.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_ge (r, type, op1);
+      break;
+
+    case BRS_FALSE:
+      build_lt (r, type, op1);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+relation_kind
+operator_le::op1_op2_relation (const irange &lhs, const prange &,
+			       const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 <= op2 indicates GT_EXPR.
+  if (lhs.zero_p ())
+    return VREL_GT;
+
+  // TRUE = op1 <= op2 indicates LE_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_LE;
+  return VREL_VARYING;
+}
+
+bool
+operator_le::pointers_handled_p (range_op_dispatch_type type,
+				 unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 21/23] Implement operator_gt for prange.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (19 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 20/23] Implement operator_le " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 22/23] Implement operator_ge " Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 23/23] Add prange entries in gimple-range-op.cc Aldy Hernandez
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_gt::fold_range): New.
	(operator_gt::op1_range): New.
	(operator_gt::op2_range): New.
	(operator_gt::op1_op2_relation): New.
	(operator_gt::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++++
 gcc/range-op-ptr.cc  | 106 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 571729e2ab6..f7a07b19635 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -320,6 +320,9 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -327,6 +330,9 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
@@ -334,11 +340,16 @@ public:
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -346,6 +357,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_ge :  public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index eb28211b583..441a18c08c7 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1747,6 +1747,112 @@ operator_le::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_gt::fold_range (irange &r, tree type,
+			 const prange &op1, const prange &op2,
+			 relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_GT))
+    return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::gt_p (op1.lower_bound (), op2.upper_bound (), sign))
+    r = range_true ();
+  else if (!wi::gt_p (op1.upper_bound (), op2.lower_bound (), sign))
+    r = range_false ();
+  else
+    r = range_true_and_false ();
+
+  //update_known_bitmask (r, GT_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_gt::op1_range (prange &r, tree type,
+			const irange &lhs, const prange &op2,
+			relation_trio) const
+{
+  if (op2.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_gt (r, type, op2);
+      break;
+
+    case BRS_FALSE:
+      build_le (r, type, op2);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+bool
+operator_gt::op2_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op1,
+			relation_trio) const
+{
+  if (op1.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_lt (r, type, op1);
+      break;
+
+    case BRS_FALSE:
+      build_ge (r, type, op1);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+relation_kind
+operator_gt::op1_op2_relation (const irange &lhs, const prange &,
+			       const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 > op2 indicates LE_EXPR.
+  if (lhs.zero_p ())
+    return VREL_LE;
+
+  // TRUE = op1 > op2 indicates GT_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_GT;
+  return VREL_VARYING;
+}
+
+bool
+operator_gt::pointers_handled_p (range_op_dispatch_type type,
+				 unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 22/23] Implement operator_ge for prange....
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (20 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 21/23] Implement operator_gt " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  2024-05-04  8:30 ` [COMMITTED 23/23] Add prange entries in gimple-range-op.cc Aldy Hernandez
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* range-op-mixed.h: Add overloaded declarations for pointer variants.
	* range-op-ptr.cc (operator_ge::fold_range): New.
	(operator_ge::op1_range): New.
	(operator_ge::op2_range): New.
	(operator_ge::op1_op2_relation): New.
	(operator_ge::pointers_handled_p): New.
---
 gcc/range-op-mixed.h |  12 +++++
 gcc/range-op-ptr.cc  | 108 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+)

diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index f7a07b19635..44d51d68655 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -371,6 +371,9 @@ public:
   bool fold_range (irange &r, tree type,
 		   const irange &op1, const irange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const prange &op1, const prange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
 		   relation_trio = TRIO_VARYING) const final override;
@@ -378,6 +381,9 @@ public:
   bool op1_range (irange &r, tree type,
 		  const irange &lhs, const irange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+		  const irange &lhs, const prange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op1_range (frange &r, tree type,
 		  const irange &lhs, const frange &op2,
 		  relation_trio = TRIO_VARYING) const final override;
@@ -385,12 +391,17 @@ public:
   bool op2_range (irange &r, tree type,
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
+  bool op2_range (prange &r, tree type,
+		  const irange &lhs, const prange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
   bool op2_range (frange &r, tree type,
 		  const irange &lhs, const frange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
 
   relation_kind op1_op2_relation (const irange &lhs, const irange &,
 				  const irange &) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const prange &,
+				  const prange &) const final override;
   relation_kind op1_op2_relation (const irange &lhs, const frange &,
 				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
@@ -398,6 +409,7 @@ public:
   // Check op1 and op2 for compatibility.
   bool operand_check_p (tree, tree t1, tree t2) const final override
     { return range_compatible_p (t1, t2); }
+  bool pointers_handled_p (range_op_dispatch_type, unsigned) const final override;
 };
 
 class operator_identity : public range_operator
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index 441a18c08c7..466edc6bf74 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -1853,6 +1853,114 @@ operator_gt::pointers_handled_p (range_op_dispatch_type type,
     }
 }
 
+bool
+operator_ge::fold_range (irange &r, tree type,
+			 const prange &op1,
+			 const prange &op2,
+			 relation_trio rel) const
+{
+  if (relop_early_resolve (r, type, op1, op2, rel, VREL_GE))
+    return true;
+
+  signop sign = TYPE_SIGN (op1.type ());
+  gcc_checking_assert (sign == TYPE_SIGN (op2.type ()));
+
+  if (wi::ge_p (op1.lower_bound (), op2.upper_bound (), sign))
+    r = range_true ();
+  else if (!wi::ge_p (op1.upper_bound (), op2.lower_bound (), sign))
+    r = range_false ();
+  else
+    r = range_true_and_false ();
+
+  //update_known_bitmask (r, GE_EXPR, op1, op2);
+  return true;
+}
+
+bool
+operator_ge::op1_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op2,
+			relation_trio) const
+{
+  if (op2.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_ge (r, type, op2);
+      break;
+
+    case BRS_FALSE:
+      build_lt (r, type, op2);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+bool
+operator_ge::op2_range (prange &r, tree type,
+			const irange &lhs,
+			const prange &op1,
+			relation_trio) const
+{
+  if (op1.undefined_p ())
+    return false;
+
+  switch (get_bool_state (r, lhs, type))
+    {
+    case BRS_TRUE:
+      build_le (r, type, op1);
+      break;
+
+    case BRS_FALSE:
+      build_gt (r, type, op1);
+      break;
+
+    default:
+      break;
+    }
+  return true;
+}
+
+relation_kind
+operator_ge::op1_op2_relation (const irange &lhs, const prange &,
+			       const prange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  // FALSE = op1 >= op2 indicates LT_EXPR.
+  if (lhs.zero_p ())
+    return VREL_LT;
+
+  // TRUE = op1 >= op2 indicates GE_EXPR.
+  if (!range_includes_zero_p (lhs))
+    return VREL_GE;
+  return VREL_VARYING;
+}
+
+bool
+operator_ge::pointers_handled_p (range_op_dispatch_type type,
+				 unsigned dispatch) const
+{
+  switch (type)
+    {
+    case DISPATCH_FOLD_RANGE:
+      return dispatch == RO_IPP;
+    case DISPATCH_OP1_RANGE:
+    case DISPATCH_OP2_RANGE:
+      return dispatch == RO_PIP;
+    case DISPATCH_OP1_OP2_RELATION:
+      return dispatch == RO_IPP;
+    default:
+      return true;
+    }
+}
+
 // Initialize any pointer operators to the primary table
 
 void
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [COMMITTED 23/23] Add prange entries in gimple-range-op.cc.
  2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
                   ` (21 preceding siblings ...)
  2024-05-04  8:30 ` [COMMITTED 22/23] Implement operator_ge " Aldy Hernandez
@ 2024-05-04  8:30 ` Aldy Hernandez
  22 siblings, 0 replies; 25+ messages in thread
From: Aldy Hernandez @ 2024-05-04  8:30 UTC (permalink / raw)
  To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez

gcc/ChangeLog:

	* gimple-range-op.cc (class cfn_pass_through_arg1): Add overloads
	for prange operations.
	(cfn_strlen): Same.
---
 gcc/gimple-range-op.cc | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 587de186db2..55dfbb23ce2 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -311,12 +311,37 @@ public:
     r = lh;
     return true;
   }
+  virtual bool fold_range (prange &r, tree, const prange &lh,
+			   const prange &, relation_trio) const
+  {
+    r = lh;
+    return true;
+  }
   virtual bool op1_range (irange &r, tree, const irange &lhs,
 			  const irange &, relation_trio) const
   {
     r = lhs;
     return true;
   }
+  virtual bool op1_range (prange &r, tree, const prange &lhs,
+			  const prange &, relation_trio) const
+  {
+    r = lhs;
+    return true;
+  }
+  virtual bool pointers_handled_p (range_op_dispatch_type type,
+				   unsigned dispatch) const
+  {
+    switch (type)
+      {
+      case DISPATCH_FOLD_RANGE:
+	return dispatch == RO_PPP;
+      case DISPATCH_OP1_RANGE:
+	return dispatch == RO_PPP;
+      default:
+	return true;
+      }
+  }
 } op_cfn_pass_through_arg1;
 
 // Implement range operator for CFN_BUILT_IN_SIGNBIT.
@@ -1107,6 +1132,17 @@ public:
     r.set (type, wi::zero (TYPE_PRECISION (type)), max - 2);
     return true;
   }
+  virtual bool pointers_handled_p (range_op_dispatch_type type,
+				   unsigned dispatch) const
+  {
+    switch (type)
+      {
+      case DISPATCH_FOLD_RANGE:
+	return dispatch == RO_IPI;
+      default:
+	return true;
+      }
+  }
 } op_cfn_strlen;
 
 
-- 
2.44.0


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/23] prange: pointer ranges
@ 2024-05-09 14:58 David Edelsohn
  0 siblings, 0 replies; 25+ messages in thread
From: David Edelsohn @ 2024-05-09 14:58 UTC (permalink / raw)
  To: GCC Patches, Aldy Hernandez

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]

> Tested and benchmarked on x86-64 Linux.

Why aren't these patches being tested on all major architectures,
especially those available in the Compile Farm?  At least for correctness,
if not performance.

Thanks, David

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2024-05-09 14:58 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-05-04  8:30 [PATCH 00/23] prange: pointer ranges Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 01/23] Minimal prange class showing inlining degradation to VRP Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 02/23] Implement basic prange class Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 03/23] Add streaming support for prange Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 04/23] Add storage " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 05/23] Add hashing " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 06/23] Add prange implementation for get_legacy_range Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 07/23] Implement range-op dispatch for prange Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 08/23] Implement operator_identity " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 09/23] Implement operator_cst " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 10/23] Implement operator_cast " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 11/23] Implement operator_min and operator_max " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 12/23] Implement operator_addr_expr " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 13/23] Implement pointer_plus_operator " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 14/23] Implement operator_pointer_diff " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 15/23] Implement operator_bitwise_and " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 16/23] Implement operator_bitwise_or " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 17/23] Implement operator_not_equal " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 18/23] Implement operator_equal " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 19/23] Implement operator_lt " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 20/23] Implement operator_le " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 21/23] Implement operator_gt " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 22/23] Implement operator_ge " Aldy Hernandez
2024-05-04  8:30 ` [COMMITTED 23/23] Add prange entries in gimple-range-op.cc Aldy Hernandez
2024-05-09 14:58 [PATCH 00/23] prange: pointer ranges David Edelsohn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).