diff mbox series

[COMMITTED] Add operand ranges to op1_op2_relation API.

Message ID aae445c7-c137-1f0c-e746-016163509887@redhat.com
State New
Headers show
Series [COMMITTED] Add operand ranges to op1_op2_relation API. | expand

Commit Message

Andrew MacLeod Aug. 3, 2023, 6:25 p.m. UTC
We're looking to add the unordered relations for floating point, and as 
a result, we can no longer determine the relation between op1 and op2 in 
a statement based purely on the LHS... we also need to know the type of 
the operands on the RHS.

This patch adjusts op1_op2_relation to fit the same mold as 
fold_range... ie, takes 3 vrange instead of just a LHS.

It also copies the functionality of the integral relations to the 
floating point counterparts, and when the unordered relations are added, 
those floating point routines can be adjusted to do the right thing.

This results in no current functional changes.

Bootstraps on  x86_64-pc-linux-gnu with no regressions.   Pushed.

Andrew
diff mbox series

Patch

From de7ae277f497ed5b533af877fe26d8f133760f8b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Tue, 1 Aug 2023 14:33:09 -0400
Subject: [PATCH 3/3] Add operand ranges to op1_op2_relation API.

With additional floating point relations in the pipeline, we can no
longer tell based on the LHS what the relation of X < Y is without knowing
the type of X and Y.

	* gimple-range-fold.cc (fold_using_range::range_of_range_op): Add
	ranges to the call to relation_fold_and_or.
	(fold_using_range::relation_fold_and_or): Add op1 and op2 ranges.
	(fur_source::register_outgoing_edges): Add op1 and op2 ranges.
	* gimple-range-fold.h (relation_fold_and_or): Adjust params.
	* gimple-range-gori.cc (gori_compute::compute_operand_range): Add
	a varying op1 and op2 to call.
	* range-op-float.cc (range_operator::op1_op2_relation): New dafaults.
	(operator_equal::op1_op2_relation): New float version.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation) Ditto.
	* range-op-mixed.h (operator_equal::op1_op2_relation): New float
	prototype.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation): Ditto.
	* range-op.cc (range_op_handler::op1_op2_relation): Dispatch new
	variations.
	(range_operator::op1_op2_relation): Add extra params.
	(operator_equal::op1_op2_relation): Ditto.
	(operator_not_equal::op1_op2_relation): Ditto.
	(operator_lt::op1_op2_relation): Ditto.
	(operator_le::op1_op2_relation): Ditto.
	(operator_gt::op1_op2_relation): Ditto.
	(operator_ge::op1_op2_relation): Ditto.
	* range-op.h (range_operator): New prototypes.
	(range_op_handler): Ditto.
---
 gcc/gimple-range-fold.cc |  26 +++++---
 gcc/gimple-range-fold.h  |   3 +-
 gcc/gimple-range-gori.cc |   5 +-
 gcc/range-op-float.cc    | 129 ++++++++++++++++++++++++++++++++++++++-
 gcc/range-op-mixed.h     |  30 +++++++--
 gcc/range-op.cc          |  41 +++++++++----
 gcc/range-op.h           |  15 ++++-
 7 files changed, 216 insertions(+), 33 deletions(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index ab2d996c4eb..7fa5a27cb12 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -700,7 +700,7 @@  fold_using_range::range_of_range_op (vrange &r,
 				   relation_trio::op1_op2 (rel)))
 	    r.set_varying (type);
 	  if (irange::supports_p (type))
-	    relation_fold_and_or (as_a <irange> (r), s, src);
+	    relation_fold_and_or (as_a <irange> (r), s, src, range1, range2);
 	  if (lhs)
 	    {
 	      if (src.gori ())
@@ -1103,7 +1103,8 @@  fold_using_range::range_of_ssa_name_with_loop_info (vrange &r, tree name,
 
 void
 fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
-					fur_source &src)
+					fur_source &src, vrange &op1,
+					vrange &op2)
 {
   // No queries or already folded.
   if (!src.gori () || !src.query ()->oracle () || lhs_range.singleton_p ())
@@ -1164,9 +1165,8 @@  fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
     return;
 
   int_range<2> bool_one = range_true ();
-
-  relation_kind relation1 = handler1.op1_op2_relation (bool_one);
-  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
+  relation_kind relation1 = handler1.op1_op2_relation (bool_one, op1, op2);
+  relation_kind relation2 = handler2.op1_op2_relation (bool_one, op1, op2);
   if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
     return;
 
@@ -1201,7 +1201,8 @@  fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 // Register any outgoing edge relations from a conditional branch.
 
 void
-fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1)
+fur_source::register_outgoing_edges (gcond *s, irange &lhs_range,
+				     edge e0, edge e1)
 {
   int_range<2> e0_range, e1_range;
   tree name;
@@ -1236,17 +1237,20 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   // if (a_2 < b_5)
   tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
   tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
+  Value_Range r1,r2;
   if (ssa1 && ssa2)
     {
+      r1.set_varying (TREE_TYPE (ssa1));
+      r2.set_varying (TREE_TYPE (ssa2));
       if (e0)
 	{
-	  relation_kind relation = handler.op1_op2_relation (e0_range);
+	  relation_kind relation = handler.op1_op2_relation (e0_range, r1, r2);
 	  if (relation != VREL_VARYING)
 	    register_relation (e0, relation, ssa1, ssa2);
 	}
       if (e1)
 	{
-	  relation_kind relation = handler.op1_op2_relation (e1_range);
+	  relation_kind relation = handler.op1_op2_relation (e1_range, r1, r2);
 	  if (relation != VREL_VARYING)
 	    register_relation (e1, relation, ssa1, ssa2);
 	}
@@ -1273,17 +1277,19 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       Value_Range r (TREE_TYPE (name));
       if (ssa1 && ssa2)
 	{
+	  r1.set_varying (TREE_TYPE (ssa1));
+	  r2.set_varying (TREE_TYPE (ssa2));
 	  if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler.op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r, r1, r2);
 	      if (relation != VREL_VARYING)
 		register_relation (e0, relation, ssa1, ssa2);
 	    }
 	  if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler.op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r, r1, r2);
 	      if (relation != VREL_VARYING)
 		register_relation (e1, relation, ssa1, ssa2);
 	    }
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 939b7a76f0e..fcbe1626790 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -173,6 +173,7 @@  protected:
   bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
   void range_of_ssa_name_with_loop_info (vrange &, tree, class loop *, gphi *,
 					 fur_source &src);
-  void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src);
+  void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src,
+			     vrange &op1, vrange &op2);
 };
 #endif // GCC_GIMPLE_RANGE_FOLD_H
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index c37e54bcf84..51fb542a19c 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -627,7 +627,10 @@  gori_compute::compute_operand_range (vrange &r, gimple *stmt,
   // likely to be more applicable.
   if (op1 && op2)
     {
-      relation_kind k = handler.op1_op2_relation (lhs);
+      Value_Range r1, r2;
+      r1.set_varying (TREE_TYPE (op1));
+      r2.set_varying (TREE_TYPE (op2));
+      relation_kind k = handler.op1_op2_relation (lhs, r1, r2);
       if (k != VREL_VARYING)
 	{
 	  vrel.set_relation (k, op1, op2);
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index a8d39cff27f..e30b489c410 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -244,7 +244,18 @@  range_operator::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator::op1_op2_relation (const frange &lhs ATTRIBUTE_UNUSED) const
+range_operator::op1_op2_relation (const irange &,
+				  const frange &,
+				  const frange &) const
+{
+  return VREL_VARYING;
+}
+
+
+relation_kind
+range_operator::op1_op2_relation (const frange &,
+				  const frange &,
+				  const frange &) const
 {
   return VREL_VARYING;
 }
@@ -705,6 +716,25 @@  operator_equal::op1_range (frange &r, tree type,
   return true;
 }
 
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_equal::op1_op2_relation (const irange &lhs, const frange &,
+				  const frange &) 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 (lhs.undefined_p () || !contains_zero_p (lhs))
+    return VREL_EQ;
+  return VREL_VARYING;
+}
+
 bool
 operator_not_equal::fold_range (irange &r, tree type,
 				const frange &op1, const frange &op2,
@@ -809,6 +839,26 @@  operator_not_equal::op1_range (frange &r, tree type,
   return true;
 }
 
+
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_not_equal::op1_op2_relation (const irange &lhs, const frange &,
+				      const frange &) 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 (lhs.undefined_p () || !contains_zero_p (lhs))
+    return VREL_NE;
+  return VREL_VARYING;
+}
+
 bool
 operator_lt::fold_range (irange &r, tree type,
 			 const frange &op1, const frange &op2,
@@ -903,6 +953,26 @@  operator_lt::op2_range (frange &r,
   return true;
 }
 
+
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_lt::op1_op2_relation (const irange &lhs, const frange &,
+			       const frange &) 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 (lhs.undefined_p () || !contains_zero_p (lhs))
+    return VREL_LT;
+  return VREL_VARYING;
+}
+
 bool
 operator_le::fold_range (irange &r, tree type,
 			 const frange &op1, const frange &op2,
@@ -991,6 +1061,25 @@  operator_le::op2_range (frange &r,
   return true;
 }
 
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_le::op1_op2_relation (const irange &lhs, const frange &,
+			       const frange &) 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 (lhs.undefined_p () || !contains_zero_p (lhs))
+    return VREL_LE;
+  return VREL_VARYING;
+}
+
 bool
 operator_gt::fold_range (irange &r, tree type,
 			 const frange &op1, const frange &op2,
@@ -1089,6 +1178,25 @@  operator_gt::op2_range (frange &r,
   return true;
 }
 
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_gt::op1_op2_relation (const irange &lhs, const frange &,
+			       const frange &) 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 (!contains_zero_p (lhs))
+    return VREL_GT;
+  return VREL_VARYING;
+}
+
 bool
 operator_ge::fold_range (irange &r, tree type,
 			 const frange &op1, const frange &op2,
@@ -1178,6 +1286,25 @@  operator_ge::op2_range (frange &r, tree type,
   return true;
 }
 
+// Check if the LHS range indicates a relation between OP1 and OP2.
+
+relation_kind
+operator_ge::op1_op2_relation (const irange &lhs, const frange &,
+			       const frange &) 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 (!contains_zero_p (lhs))
+    return VREL_GE;
+  return VREL_VARYING;
+}
+
 // UNORDERED_EXPR comparison.
 
 class foperator_unordered : public range_operator
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index b623a88cc71..825f934cf60 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -132,7 +132,10 @@  public:
 		  const irange &lhs, const frange &op1,
 		  relation_trio rel = TRIO_VARYING) const final override;
 
-  relation_kind op1_op2_relation (const irange &lhs) 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 frange &,
+				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
 };
@@ -162,7 +165,10 @@  public:
 		  const irange &lhs, const irange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
 
-  relation_kind op1_op2_relation (const irange &lhs) 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 frange &,
+				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
 };
@@ -192,7 +198,10 @@  public:
   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 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 frange &,
+				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
 };
@@ -225,7 +234,10 @@  public:
 		  const irange &lhs, const frange &op1,
 		  relation_trio rel = TRIO_VARYING) const final override;
 
-  relation_kind op1_op2_relation (const irange &lhs) 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 frange &,
+				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
 };
@@ -257,7 +269,10 @@  public:
   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 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 frange &,
+				  const frange &) const final override;
   void update_bitmask (irange &r, const irange &lh,
 		       const irange &rh) const final override;
 };
@@ -290,7 +305,10 @@  public:
 		  const irange &lhs, const frange &op1,
 		  relation_trio = TRIO_VARYING) const final override;
 
-  relation_kind op1_op2_relation (const irange &lhs) 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 frange &,
+				  const frange &) const final override;
   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 19fdff0eb64..086c6c19735 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -350,16 +350,27 @@  range_op_handler::lhs_op2_relation (const vrange &lhs,
 // Dispatch a call to op1_op2_relation based on the type of LHS.
 
 relation_kind
-range_op_handler::op1_op2_relation (const vrange &lhs) const
+range_op_handler::op1_op2_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2) const
 {
   gcc_checking_assert (m_operator);
-  switch (dispatch_kind (lhs, lhs, lhs))
+  switch (dispatch_kind (lhs, op1, op2))
     {
       case RO_III:
-	return m_operator->op1_op2_relation (as_a <irange> (lhs));
+	return m_operator->op1_op2_relation (as_a <irange> (lhs),
+					     as_a <irange> (op1),
+					     as_a <irange> (op2));
+
+      case RO_IFF:
+	return m_operator->op1_op2_relation (as_a <irange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2));
 
       case RO_FFF:
-	return m_operator->op1_op2_relation (as_a <frange> (lhs));
+	return m_operator->op1_op2_relation (as_a <frange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2));
 
       default:
 	return VREL_VARYING;
@@ -676,7 +687,9 @@  range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const
+range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
+				  const irange &op1 ATTRIBUTE_UNUSED,
+				  const irange &op2 ATTRIBUTE_UNUSED) const
 {
   return VREL_VARYING;
 }
@@ -868,7 +881,8 @@  operator_equal::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_equal::op1_op2_relation (const irange &lhs) const
+operator_equal::op1_op2_relation (const irange &lhs, const irange &,
+				  const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -969,7 +983,8 @@  operator_not_equal::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_not_equal::op1_op2_relation (const irange &lhs) const
+operator_not_equal::op1_op2_relation (const irange &lhs, const irange &,
+				      const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -1129,7 +1144,8 @@  operator_lt::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_lt::op1_op2_relation (const irange &lhs) const
+operator_lt::op1_op2_relation (const irange &lhs, const irange &,
+			       const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -1229,7 +1245,8 @@  operator_le::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_le::op1_op2_relation (const irange &lhs) const
+operator_le::op1_op2_relation (const irange &lhs, const irange &,
+			       const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -1326,7 +1343,8 @@  operator_gt::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_gt::op1_op2_relation (const irange &lhs) const
+operator_gt::op1_op2_relation (const irange &lhs, const irange &,
+			       const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -1421,7 +1439,8 @@  operator_ge::update_bitmask (irange &r, const irange &lh,
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-operator_ge::op1_op2_relation (const irange &lhs) const
+operator_ge::op1_op2_relation (const irange &lhs, const irange &,
+			       const irange &) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
diff --git a/gcc/range-op.h b/gcc/range-op.h
index af94c2756a7..51121410233 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -145,8 +145,15 @@  public:
 					  const frange &op2,
 					  relation_kind = VREL_VARYING) const;
 
-  virtual relation_kind op1_op2_relation (const irange &lhs) const;
-  virtual relation_kind op1_op2_relation (const frange &lhs) const;
+  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 frange &op1,
+					  const frange &op2) const;
+  virtual relation_kind op1_op2_relation (const frange &lhs,
+					  const frange &op1,
+					  const frange &op2) const;
 protected:
   // Perform an integral operation between 2 sub-ranges and return it.
   virtual void wi_fold (irange &r, tree type,
@@ -213,7 +220,9 @@  public:
 				  const vrange &op1,
 				  const vrange &op2,
 				  relation_kind = VREL_VARYING) const;
-  relation_kind op1_op2_relation (const vrange &lhs) const;
+  relation_kind op1_op2_relation (const vrange &lhs,
+				  const vrange &op1,
+				  const vrange &op2) const;
 protected:
   unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
 			  const vrange& op2) const;
-- 
2.40.1