Final patch committed. Re-tested on x86-64 Linux. On Mon, May 30, 2022 at 3:28 PM Aldy Hernandez wrote: > > 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 | 2 +- > gcc/gimple-range-fold.cc | 43 ++++---- > gcc/gimple-range-fold.h | 15 --- > gcc/gimple-range-gori.cc | 41 ++++---- > gcc/gimple-range.cc | 6 +- > gcc/range-op.cc | 215 ++++++++++++++++++++++++++++++++++----- > gcc/range-op.h | 45 ++++++-- > gcc/tree-data-ref.cc | 8 +- > gcc/tree-vrp.cc | 44 ++++---- > gcc/value-query.cc | 8 +- > 10 files changed, 303 insertions(+), 124 deletions(-) > > diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc > index 0bee38ba770..5bbe23ae03d 100644 > --- a/gcc/gimple-range-edge.cc > +++ b/gcc/gimple-range-edge.cc > @@ -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 (s) && gimple_range_handler (s)) > + if (is_a (s) && range_op_handler (s)) > return gsi_stmt (gsi); > gswitch *sw = dyn_cast (s); > if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw)))) > diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc > index 0a947c16c58..c53d2863d5e 100644 > --- a/gcc/gimple-range-fold.cc > +++ b/gcc/gimple-range-fold.cc > @@ -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(s)) > res = range_of_phi (r, as_a (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); > } > diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h > index 20cb73dabb9..4b5d4b6e0b8 100644 > --- a/gcc/gimple-range-fold.h > +++ b/gcc/gimple-range-fold.h > @@ -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 (s)) > - return range_op_handler (gimple_assign_rhs_code (ass), > - TREE_TYPE (gimple_assign_lhs (ass))); > - if (const gcond *cond = dyn_cast (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. > > diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc > index 3e15eb5192d..0e0cf2128e7 100644 > --- a/gcc/gimple-range-gori.cc > +++ b/gcc/gimple-range-gori.cc > @@ -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); > + tmp_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)); > + tmp_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)); > + tmp_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 (stmt)) > return compute_operand_range_switch (r, as_a (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); > diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc > index f5e9e77bc71..32d57c9e3db 100644 > --- a/gcc/gimple-range.cc > +++ b/gcc/gimple-range.cc > @@ -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 (stmt)) > + if (!range_op_handler (stmt) && !is_a (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 (stmt)) > + if (!range_op_handler (stmt) && !is_a (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); > diff --git a/gcc/range-op.cc b/gcc/range-op.cc > index c88da8caa6c..6f6d2da573a 100644 > --- a/gcc/range-op.cc > +++ b/gcc/range-op.cc > @@ -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 (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 (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 (lh)) > + return m_op->fold_range (as_a (r), type, > + as_a (lh), > + as_a (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 (r)) > + return m_op->op1_range (as_a (r), type, > + as_a (lhs), > + as_a (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 (r)) > + return m_op->op2_range (as_a (r), type, > + as_a (lhs), > + as_a (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 (op1)) > + return m_op->lhs_op1_relation (as_a (lhs), > + as_a (op1), as_a (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 (op1)) > + return m_op->lhs_op2_relation (as_a (lhs), > + as_a (op1), as_a (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 (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); > + tmp_range tmp (r); > + tmp_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 > diff --git a/gcc/range-op.h b/gcc/range-op.h > index 5fdda326d4b..d0f50689897 100644 > --- a/gcc/range-op.h > +++ b/gcc/range-op.h > @@ -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. > diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc > index 397792c3584..ae05fe74b95 100644 > --- a/gcc/tree-data-ref.cc > +++ b/gcc/tree-data-ref.cc > @@ -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; > diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc > index 0784d658567..3c7b5af4737 100644 > --- a/gcc/tree-vrp.cc > +++ b/gcc/tree-vrp.cc > @@ -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, > diff --git a/gcc/value-query.cc b/gcc/value-query.cc > index 26e3858103b..31e56eeae53 100644 > --- a/gcc/value-query.cc > +++ b/gcc/value-query.cc > @@ -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); > -- > 2.36.1 >