diff mbox series

[COMMITTED,07/23] Implement range-op dispatch for prange.

Message ID 20240504083056.139719-8-aldyh@redhat.com
State New
Headers show
Series prange: pointer ranges | expand

Commit Message

Aldy Hernandez May 4, 2024, 8:30 a.m. UTC
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 mbox series

Patch

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