Convert range-op.* to vrange.
authorAldy Hernandez <aldyh@redhat.com>
Mon, 14 Mar 2022 12:31:18 +0000 (13:31 +0100)
committerAldy Hernandez <aldyh@redhat.com>
Wed, 1 Jun 2022 08:55:45 +0000 (10:55 +0200)
This patch provides the infrastructure to make range-ops type agnostic.

First, the range_op_handler function has been replaced with an object
of the same name.  It's coded in such a way to minimize changes to the
code base, and to encapsulate the dispatch code.

Instead of:

range_operator *op = range_op_handler (code, type);
if (op)
  op->fold_range (...);

We now do:
range_op_handler op (code, type);
if (op)
  op->fold_range (...);

I've folded gimple_range_handler into the range_op_handler class,
since it's also a query into the range operators.

Instead of:

range_operator *handler = gimple_range_handler (stmt);

We now do:

range_op_handler handler (stmt);

This all has the added benefit of moving all the dispatch code into an
independent class and avoid polluting range_operator (which we'll
further split later when frange and prange come live).

There's this annoying "using" keyword that's been added to each
operator due to hiding rules in C++.  The issue is that we will have
different virtual versions of fold_range() for each combination of
operands.  For example:

// Traditional binary op on irange's.
fold_range (irange &lhs, const irange &op1, const irange &op2);
// For POINTER_DIFF_EXPR:
fold_range (irange &lhs, const prange &op1, const prange &op2);
// Cast from irange to prange.
fold_range (prange &lhs, const irange &op1, const irange &op2);

Overloading virtuals when there are multiple same named methods causes
hidden virtuals warnings from -Woverloaded-virtual, thus the using
keyword.  An alternative would be to have different names:
fold_range_III, fold_range_IPP, fold_range_PII, but that's uglier
still.

Tested on x86-64 & ppc64le Linux.

gcc/ChangeLog:

* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for
vrange and convert range_op_handler function calls to use the
identically named object.
* gimple-range-fold.cc (gimple_range_operand1): Same.
(gimple_range_operand2): Same.
(fold_using_range::fold_stmt): Same.
(fold_using_range::range_of_range_op): Same.
(fold_using_range::range_of_builtin_ubsan_call): Same.
(fold_using_range::relation_fold_and_or): Same.
(fur_source::register_outgoing_edges): Same.
* gimple-range-fold.h (gimple_range_handler): Remove.
* gimple-range-gori.cc (gimple_range_calc_op1): Adjust for vrange.
(gimple_range_calc_op2): Same.
(range_def_chain::get_def_chain): Same.
(gori_compute::compute_operand_range): Same.
(gori_compute::condexpr_adjust): Same.
* gimple-range.cc (gimple_ranger::prefill_name): Same.
(gimple_ranger::prefill_stmt_dependencies): Same.
* range-op.cc (get_bool_state): Same.
(class operator_equal): Add using clause.
(class operator_not_equal): Same.
(class operator_lt): Same.
(class operator_le): Same.
(class operator_gt): Same.
(class operator_ge): Same.
(class operator_plus): Same.
(class operator_minus): Same.
(class operator_mult): Same.
(class operator_exact_divide): Same.
(class operator_lshift): Same.
(class operator_rshift): Same.
(class operator_cast): Same.
(class operator_logical_and): Same.
(class operator_bitwise_and): Same.
(class operator_logical_or): Same.
(class operator_bitwise_or): Same.
(class operator_bitwise_xor): Same.
(class operator_trunc_mod): Same.
(class operator_logical_not): Same.
(class operator_bitwise_not): Same.
(class operator_cst): Same.
(class operator_identity): Same.
(class operator_unknown): Same.
(class operator_abs): Same.
(class operator_negate): Same.
(class operator_addr_expr): Same.
(class pointer_or_operator): Same.
(operator_plus::op1_range): Adjust for vrange.
(operator_minus::op1_range): Same.
(operator_mult::op1_range): Same.
(operator_cast::op1_range): Same.
(operator_bitwise_not::fold_range): Same.
(operator_negate::fold_range): Same.
(range_op_handler): Rename to...
(get_handler): ...this.
(range_op_handler::range_op_handler): New.
(range_op_handler::fold_range): New.
(range_op_handler::op1_range): New.
(range_op_handler::op2_range): New.
(range_op_handler::lhs_op1_relation): New.
(range_op_handler::lhs_op2_relation): New.
(range_op_handler::op1_op2_relation): New.
(range_cast): Adjust for vrange.
* range-op.h (range_op_handler): Remove function.
(range_cast): Adjust for vrange.
(class range_op_handler): New.
(get_bool_state): Adjust for vrange.
(empty_range_varying): Same.
(relop_early_resolve): Same.
* tree-data-ref.cc (compute_distributive_range): Same.
* tree-vrp.cc (get_range_op_handler): Remove.
(range_fold_binary_symbolics_p): Use range_op_handler class
instead of get_range_op_handler.
(range_fold_unary_symbolics_p): Same.
(range_fold_binary_expr): Same.
(range_fold_unary_expr): Same.
* value-query.cc (range_query::get_tree_range): Adjust for vrange.

gcc/gimple-range-edge.cc
gcc/gimple-range-fold.cc
gcc/gimple-range-fold.h
gcc/gimple-range-gori.cc
gcc/gimple-range.cc
gcc/range-op.cc
gcc/range-op.h
gcc/tree-data-ref.cc
gcc/tree-vrp.cc
gcc/value-query.cc

index 0bee38b..5bbe23a 100644 (file)
@@ -42,7 +42,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
   if (!gsi_end_p (gsi))
     {
       gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && gimple_range_handler (s))
+      if (is_a<gcond *> (s) && range_op_handler (s))
        return gsi_stmt (gsi);
       gswitch *sw = dyn_cast<gswitch *> (s);
       if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw))))
index 0a947c1..c53d286 100644 (file)
@@ -482,7 +482,7 @@ gimple_range_base_of_assignment (const gimple *stmt)
 tree
 gimple_range_operand1 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -515,7 +515,7 @@ gimple_range_operand1 (const gimple *stmt)
 tree
 gimple_range_operand2 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -551,7 +551,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
     return range_of_address (r, s, src);
 
-  if (gimple_range_handler (s))
+  if (range_op_handler (s))
     res = range_of_range_op (r, s, src);
   else if (is_a<gphi *>(s))
     res = range_of_phi (r, as_a<gphi *> (s), src);
@@ -593,7 +593,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
   tree type = gimple_range_type (s);
   if (!type)
     return false;
-  range_operator *handler = gimple_range_handler (s);
+  range_op_handler handler (s);
   gcc_checking_assert (handler);
 
   tree lhs = gimple_get_lhs (s);
@@ -606,13 +606,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
        {
          // Fold range, and register any dependency if available.
          int_range<2> r2 (type);
-         handler->fold_range (r, type, range1, r2);
+         handler.fold_range (r, type, range1, r2);
          if (lhs && gimple_range_ssa_p (op1))
            {
              if (src.gori ())
                src.gori ()->register_dependency (lhs, op1);
              relation_kind rel;
-             rel = handler->lhs_op1_relation (r, range1, range1);
+             rel = handler.lhs_op1_relation (r, range1, range1);
              if (rel != VREL_VARYING)
                src.register_relation (s, rel, lhs, op1);
            }
@@ -629,7 +629,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
              fputc ('\n', dump_file);
            }
          // Fold range, and register any dependency if available.
-         handler->fold_range (r, type, range1, range2, rel);
+         handler.fold_range (r, type, range1, range2, rel);
          relation_fold_and_or (r, s, src);
          if (lhs)
            {
@@ -640,13 +640,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
                }
              if (gimple_range_ssa_p (op1))
                {
-                 rel = handler->lhs_op1_relation (r, range1, range2, rel);
+                 rel = handler.lhs_op1_relation (r, range1, range2, rel);
                  if (rel != VREL_VARYING)
                    src.register_relation (s, rel, lhs, op1);
                }
              if (gimple_range_ssa_p (op2))
                {
-                 rel= handler->lhs_op2_relation (r, range1, range2, rel);
+                 rel= handler.lhs_op2_relation (r, range1, range2, rel);
                  if (rel != VREL_VARYING)
                    src.register_relation (s, rel, lhs, op2);
                }
@@ -921,7 +921,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
                       || code == MULT_EXPR);
   tree type = gimple_range_type (call);
-  range_operator *op = range_op_handler (code, type);
+  range_op_handler op (code, type);
   gcc_checking_assert (op);
   int_range_max ir0, ir1;
   tree arg0 = gimple_call_arg (call, 0);
@@ -935,7 +935,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   // Pretend the arithmetic is wrapping.  If there is any overflow,
   // we'll complain, but will actually do wrapping operation.
   flag_wrapv = 1;
-  op->fold_range (r, type, ir0, ir1, relation);
+  op.fold_range (r, type, ir0, ir1, relation);
   flag_wrapv = saved_flag_wrapv;
 
   // If for both arguments vrp_valueize returned non-NULL, this should
@@ -1391,8 +1391,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1)
     return;
 
-  range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1));
-  range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2));
+  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
+  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
 
   // If either handler is not present, no relation is found.
   if (!handler1 || !handler2)
@@ -1400,8 +1400,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 
   int_range<2> bool_one (boolean_true_node, boolean_true_node);
 
-  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);
+  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
   if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
     return;
 
@@ -1441,7 +1441,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   int_range_max r;
   int_range<2> e0_range, e1_range;
   tree name;
-  range_operator *handler;
   basic_block bb = gimple_bb (s);
 
   if (e0)
@@ -1472,17 +1471,17 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
   if (ssa1 && ssa2)
     {
-      handler = gimple_range_handler (s);
+      range_op_handler handler (s);
       gcc_checking_assert (handler);
       if (e0)
        {
-         relation_kind relation = handler->op1_op2_relation (e0_range);
+         relation_kind relation = handler.op1_op2_relation (e0_range);
          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);
          if (relation != VREL_VARYING)
            register_relation (e1, relation, ssa1, ssa2);
        }
@@ -1501,7 +1500,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
        continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
-      handler = gimple_range_handler (stmt);
+      range_op_handler handler (stmt);
       if (!handler)
        continue;
       tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1511,14 +1510,14 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
          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);
              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);
              if (relation != VREL_VARYING)
                register_relation (e1, relation, ssa1, ssa2);
            }
index 20cb73d..4b5d4b6 100644 (file)
@@ -41,21 +41,6 @@ bool fold_range (irange &r, gimple *s, irange &r1);
 bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
 bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
 
-// Return the range_operator pointer for this statement.  This routine
-// can also be used to gate whether a routine is range-ops enabled.
-
-static inline range_operator *
-gimple_range_handler (const gimple *s)
-{
-  if (const gassign *ass = dyn_cast<const gassign *> (s))
-    return range_op_handler (gimple_assign_rhs_code (ass),
-                            TREE_TYPE (gimple_assign_lhs (ass)));
-  if (const gcond *cond = dyn_cast<const gcond *> (s))
-    return range_op_handler (gimple_cond_code (cond),
-                            TREE_TYPE (gimple_cond_lhs (cond)));
-  return NULL;
-}
-
 // Return the type of range which statement S calculates.  If the type is
 // unsupported or no type can be determined, return NULL_TREE.
 
index 3e15eb5..7203213 100644 (file)
@@ -44,9 +44,9 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
   // Unary operations require the type of the first operand in the
   // second range position.
   tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  int_range<2> type_range (type);
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-                                                type_range);
+  Value_Range type_range (type);
+  type_range.set_varying (type);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -72,12 +72,12 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
       // This is sometimes invoked on single operand stmts.
       if (gimple_num_ops (stmt) < 3)
        return false;
-      int_range<2> trange (TREE_TYPE (gimple_range_operand2 (stmt)));
-      return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-                                                    trange);
+      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
+      Value_Range trange (op2_type);
+      trange.set_varying (op2_type);
+      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-                                                op2_range);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -97,12 +97,13 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt,
   // If op1 is undefined, solve as if it is varying.
   if (op1_range.undefined_p ())
     {
-      int_range<2> trange (TREE_TYPE (gimple_range_operand1 (stmt)));
-      return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-                                                    trange);
+      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
+      Value_Range trange (op1_type);
+      trange.set_varying (op1_type);
+      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-                                                op1_range);
+  return range_op_handler (stmt).op2_range (r, type, lhs_range,
+                                           op1_range);
 }
 
 // Return TRUE if GS is a logical && or || expression.
@@ -346,7 +347,7 @@ range_def_chain::get_def_chain (tree name)
     }
 
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (gimple_range_handler (stmt))
+  if (range_op_handler (stmt))
     {
       ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
       ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
@@ -707,7 +708,7 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
   if (is_a<gswitch *> (stmt))
     return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
                                         src);
-  if (!gimple_range_handler (stmt))
+  if (!range_op_handler (stmt))
     return false;
 
   tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1328,7 +1329,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   tree type = TREE_TYPE (gimple_assign_rhs1 (cond_def));
   if (!range_compatible_p (type, TREE_TYPE (gimple_assign_rhs2 (cond_def))))
     return false;
-  range_operator *hand = range_op_handler (gimple_assign_rhs_code (cond_def), type);
+  range_op_handler hand (gimple_assign_rhs_code (cond_def), type);
   if (!hand)
     return false;
 
@@ -1351,18 +1352,18 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   // the op1 or op2 routines based on its location.
   if (c1)
     {
-      if (!hand->op1_range (cond_false, type, m_bool_zero, cr))
+      if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
        return false;
-      if (!hand->op1_range (cond_true, type, m_bool_one, cr))
+      if (!hand.op1_range (cond_true, type, m_bool_one, cr))
        return false;
       cond_false.intersect (cl);
       cond_true.intersect (cl);
     }
   else
     {
-      if (!hand->op2_range (cond_false, type, m_bool_zero, cl))
+      if (!hand.op2_range (cond_false, type, m_bool_zero, cl))
        return false;
-      if (!hand->op2_range (cond_true, type, m_bool_one, cl))
+      if (!hand.op2_range (cond_true, type, m_bool_one, cl))
        return false;
       cond_false.intersect (cr);
       cond_true.intersect (cr);
index 53f4865..0a99787 100644 (file)
@@ -339,7 +339,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
   if (!gimple_range_ssa_p (name))
     return;
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   bool current;
@@ -363,7 +363,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   gcc_checking_assert (stmt && gimple_bb (stmt));
 
   // Only pre-process range-ops and phis.
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   // Mark where on the stack we are starting.
@@ -419,7 +419,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
        }
       else
        {
-         gcc_checking_assert (gimple_range_handler (stmt));
+         gcc_checking_assert (range_op_handler (stmt));
          tree op = gimple_range_operand2 (stmt);
          if (op)
            prefill_name (r, op);
index c88da8c..028b4b7 100644 (file)
@@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type,
 // return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
 
 bool_range_state
-get_bool_state (irange &r, const irange &lhs, tree val_type)
+get_bool_state (vrange &r, const vrange &lhs, tree val_type)
 {
   // If there is no result, then this is unexecutable.
   if (lhs.undefined_p ())
@@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
 
 class operator_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type,
 
 class operator_not_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val)
 
 class operator_lt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type,
 
 class operator_le :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type,
 
 class operator_gt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type,
 
 class operator_ge :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type,
 
 class operator_plus : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
+  using range_operator::lhs_op2_relation;
 public:
   virtual bool op1_range (irange &r, tree type,
                          const irange &lhs,
@@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type,
                          const irange &op2,
                          relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type,
                          const irange &op1,
                          relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1);
 }
 
 
 class operator_minus : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
                          const irange &lhs,
@@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type,
                           const irange &op2,
                           relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type,
 
 class operator_mult : public cross_product_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
@@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type,
     return false;
 
   if (op2.singleton_p (&offset) && !integer_zerop (offset))
-    return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
-                                                               lhs, op2);
+    return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
+                                                              lhs, op2);
   return false;
 }
 
@@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR);
 
 class operator_exact_divide : public operator_div
 {
+  using range_operator::op1_range;
 public:
   operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
   virtual bool op1_range (irange &r, tree type,
@@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type,
   // If op2 is a multiple of 2, we would be able to set some non-zero bits.
   if (op2.singleton_p (&offset)
       && !integer_zerop (offset))
-    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
+    return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2);
   return false;
 }
 
 
 class operator_lshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool op1_range (irange &r, tree type,
                          const irange &lhs,
@@ -1909,6 +1939,9 @@ public:
 
 class operator_rshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type,
 
 class operator_cast: public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type,
          // Add this to the unsigned LHS range(s).
          int_range_max lim_range (type, lim, lim);
          int_range_max lhs_neg;
-         range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
-                                                         type,
-                                                         converted_lhs,
-                                                         lim_range);
+         range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type,
+                                                        converted_lhs,
+                                                        lim_range);
          // lhs_neg now has all the negative versions of the LHS.
          // Now union in all the values from SIGNED MIN (0x80000) to
          // lim-1 in order to fill in all the ranges with the upper
@@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type,
 
 class operator_logical_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &lh,
@@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type,
 
 class operator_bitwise_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &lh,
@@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type,
 
 class operator_logical_or : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &lh,
@@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_or : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
                          const irange &lhs,
@@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_xor : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
@@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type,
 
 class operator_trunc_mod : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
@@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type,
 
 class operator_logical_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &lh,
@@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r,
 
 class operator_bitwise_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &lh,
@@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type,
   // ~X is simply -1 - X.
   int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
                         wi::minus_one (TYPE_PRECISION (type)));
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
-                                                         lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh);
 }
 
 bool
@@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type,
 
 class operator_cst : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_identity : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_unknown : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type,
 
 class operator_abs : public range_operator
 {
+  using range_operator::op1_range;
  public:
   virtual void wi_fold (irange &r, tree type,
                        const wide_int &lh_lb,
@@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type,
 
 class operator_negate : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
  public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type,
   if (empty_range_varying (r, type, lh, rh))
     return true;
   // -X is simply 0 - X.
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
-                                                         range_zero (type),
-                                                         lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type,
+                                                        range_zero (type), lh);
 }
 
 bool
@@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type,
 
 class operator_addr_expr : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
                           const irange &op1,
@@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type,
 
 class pointer_or_operator : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
                          const irange &lhs,
@@ -4139,8 +4202,8 @@ pointer_table::pointer_table ()
 
 // The tables are hidden and accessed via a simple extern function.
 
-range_operator *
-range_op_handler (enum tree_code code, tree type)
+static inline range_operator *
+get_handler (enum tree_code code, tree type)
 {
   // First check if there is a pointer specialization.
   if (POINTER_TYPE_P (type))
@@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type)
   return NULL;
 }
 
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+  m_op = get_handler (code, type);
+}
+
+range_op_handler::range_op_handler (const gimple *s)
+{
+  if (const gassign *ass = dyn_cast<const gassign *> (s))
+    {
+      enum tree_code code = gimple_assign_rhs_code (ass);
+      // The LHS of a comparison is always an int, so we must look at
+      // the operands.
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+       m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass)));
+      else
+       m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass)));
+    }
+  else if (const gcond *cond = dyn_cast<const gcond *> (s))
+    m_op = get_handler (gimple_cond_code (cond),
+                       TREE_TYPE (gimple_cond_lhs (cond)));
+  else
+    m_op = NULL;
+}
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+                             const vrange &lh,
+                             const vrange &rh,
+                             relation_kind rel) const
+{
+  if (is_a <irange> (lh))
+    return m_op->fold_range (as_a <irange> (r), type,
+                            as_a <irange> (lh),
+                            as_a <irange> (rh), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+                            const vrange &lhs,
+                            const vrange &op2,
+                            relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op1_range (as_a <irange> (r), type,
+                           as_a <irange> (lhs),
+                           as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+                            const vrange &lhs,
+                            const vrange &op1,
+                            relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op2_range (as_a <irange> (r), type,
+                           as_a <irange> (lhs),
+                           as_a <irange> (op1), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+                                   const vrange &op1,
+                                   const vrange &op2,
+                                   relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op1_relation (as_a <irange> (lhs),
+                                  as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+                                   const vrange &op1,
+                                   const vrange &op2,
+                                   relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op2_relation (as_a <irange> (lhs),
+                                  as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+  return m_op->op1_op2_relation (as_a <irange> (lhs));
+}
+
 // Cast the range in R to TYPE.
 
-void
-range_cast (irange &r, tree type)
+bool
+range_cast (vrange &r, tree type)
 {
-  int_range_max tmp = r;
-  range_operator *op = range_op_handler (CONVERT_EXPR, type);
+  Value_Range tmp (r);
+  Value_Range varying (type);
+  varying.set_varying (type);
+  range_op_handler op (CONVERT_EXPR, type);
   // Call op_convert, if it fails, the result is varying.
-  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
-    r.set_varying (type);
+  if (!op || !op.fold_range (r, type, tmp, varying))
+    {
+      r.set_varying (type);
+      return false;
+    }
+  return true;
 }
 
 #if CHECKING_P
index 300974f..262c796 100644 (file)
@@ -108,8 +108,39 @@ protected:
                         const wide_int &rh_ub) const;
 };
 
-extern range_operator *range_op_handler (enum tree_code code, tree type);
-extern void range_cast (irange &, tree type);
+class range_op_handler
+{
+public:
+  range_op_handler (enum tree_code code, tree type);
+  range_op_handler (const gimple *s);
+  operator bool () const { return m_op; }
+
+  bool fold_range (vrange &r, tree type,
+                  const vrange &lh,
+                  const vrange &rh,
+                  relation_kind rel = VREL_VARYING) const;
+  bool op1_range (vrange &r, tree type,
+                 const vrange &lhs,
+                 const vrange &op2,
+                 relation_kind rel = VREL_VARYING) const;
+  bool op2_range (vrange &r, tree type,
+                 const vrange &lhs,
+                 const vrange &op1,
+                 relation_kind rel = VREL_VARYING) const;
+  relation_kind lhs_op1_relation (const vrange &lhs,
+                                 const vrange &op1,
+                                 const vrange &op2,
+                                 relation_kind = VREL_VARYING) const;
+  relation_kind lhs_op2_relation (const vrange &lhs,
+                                 const vrange &op1,
+                                 const vrange &op2,
+                                 relation_kind = VREL_VARYING) const;
+  relation_kind op1_op2_relation (const vrange &lhs) const;
+private:
+  range_operator *m_op;
+};
+
+extern bool range_cast (vrange &, tree type);
 extern void wi_set_zero_nonzero_bits (tree type,
                                      const wide_int &, const wide_int &,
                                      wide_int &maybe_nonzero,
@@ -124,7 +155,7 @@ relation_kind gt_op1_op2_relation (const irange &lhs);
 relation_kind ge_op1_op2_relation (const irange &lhs);
 
 enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
-bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
+bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
 
 // If the range of either op1 or op2 is undefined, set the result to
 // varying and return TRUE.  If the caller truely cares about a result,
@@ -132,8 +163,8 @@ bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
 // treated as a varying.
 
 inline bool
-empty_range_varying (irange &r, tree type,
-                    const irange &op1, const irange & op2)
+empty_range_varying (vrange &r, tree type,
+                    const vrange &op1, const vrange & op2)
 {
   if (op1.undefined_p () || op2.undefined_p ())
     {
@@ -150,8 +181,8 @@ empty_range_varying (irange &r, tree type,
 // return false.
 
 inline bool
-relop_early_resolve (irange &r, tree type, const irange &op1,
-                    const irange &op2, relation_kind rel,
+relop_early_resolve (irange &r, tree type, const vrange &op1,
+                    const vrange &op2, relation_kind rel,
                     relation_kind my_rel)
 {
   // If known relation is a complete subset of this relation, always true.
index 397792c..ae05fe7 100644 (file)
@@ -593,8 +593,8 @@ compute_distributive_range (tree type, value_range &op0_range,
   gcc_assert (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type));
   if (result_range)
     {
-      range_operator *op = range_op_handler (code, type);
-      op->fold_range (*result_range, type, op0_range, op1_range);
+      range_op_handler op (code, type);
+      op.fold_range (*result_range, type, op0_range, op1_range);
     }
 
   /* The distributive property guarantees that if TYPE is no narrower
@@ -639,10 +639,10 @@ compute_distributive_range (tree type, value_range &op0_range,
   range_cast (op0_range, ssizetype);
   range_cast (op1_range, ssizetype);
   value_range wide_range;
-  range_operator *op = range_op_handler (code, ssizetype);
+  range_op_handler op (code, ssizetype);
   bool saved_flag_wrapv = flag_wrapv;
   flag_wrapv = 1;
-  op->fold_range (wide_range, ssizetype, op0_range, op1_range);
+  op.fold_range (wide_range, ssizetype, op0_range, op1_range);
   flag_wrapv = saved_flag_wrapv;
   if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
     return false;
index 62ae5a9..7427761 100644 (file)
@@ -924,20 +924,6 @@ extract_range_from_plus_minus_expr (value_range *vr,
     vr->set (min, max, kind);
 }
 
-/* Return the range-ops handler for CODE and EXPR_TYPE.  If no
-   suitable operator is found, return NULL and set VR to VARYING.  */
-
-static const range_operator *
-get_range_op_handler (value_range *vr,
-                     enum tree_code code,
-                     tree expr_type)
-{
-  const range_operator *op = range_op_handler (code, expr_type);
-  if (!op)
-    vr->set_varying (expr_type);
-  return op;
-}
-
 /* If the types passed are supported, return TRUE, otherwise set VR to
    VARYING and return FALSE.  */
 
@@ -1005,10 +991,12 @@ range_fold_binary_symbolics_p (value_range *vr,
                                                &vr0, &vr1);
          return true;
        }
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+       vr->set_varying (expr_type);
       vr0.normalize_symbolics ();
       vr1.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0, vr1);
+      return op.fold_range (*vr, expr_type, vr0, vr1);
     }
   return false;
 }
@@ -1040,10 +1028,12 @@ range_fold_unary_symbolics_p (value_range *vr,
          range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
          return true;
        }
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+       vr->set_varying (expr_type);
       value_range vr0_cst (*vr0);
       vr0_cst.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+      return op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
     }
   return false;
 }
@@ -1060,9 +1050,12 @@ range_fold_binary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type)
       || !defined_ranges_p (vr, vr0_, vr1_))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
     return;
@@ -1075,7 +1068,7 @@ range_fold_binary_expr (value_range *vr,
     vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0, vr1);
+  op.fold_range (*vr, expr_type, vr0, vr1);
 }
 
 /* Perform a unary operation on a range.  */
@@ -1089,16 +1082,19 @@ range_fold_unary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type, vr0_type)
       || !defined_ranges_p (vr, vr0))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
     return;
 
   value_range vr0_cst (*vr0);
   vr0_cst.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+  op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
 }
 
 /* If the range of values taken by OP can be inferred after STMT executes,
index 26e3858..31e56ee 100644 (file)
@@ -234,13 +234,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (BINARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       if (op)
        {
          int_range_max r0, r1;
          range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
          range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
-         op->fold_range (r, type, r0, r1);
+         op.fold_range (r, type, r0, r1);
        }
       else
        r.set_varying (type);
@@ -248,13 +248,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (UNARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
       if (op && irange::supports_type_p (op0_type))
        {
          int_range_max r0;
          range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-         op->fold_range (r, type, r0, int_range<1> (type));
+         op.fold_range (r, type, r0, int_range<1> (type));
        }
       else
        r.set_varying (type);