diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2020-03-26 09:54:11 +0100 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2020-03-30 14:00:14 +0200 |
commit | 5b6d81b17ebf860a9a3ca3945d99514437927c81 (patch) | |
tree | 6f6c812ba78d1baf1af9f7305192ea15bc90d4b3 | |
parent | fde9e8acfb0eaf3e70569e22360f9167b48eb36f (diff) | |
download | gcc-5b6d81b17ebf860a9a3ca3945d99514437927c81.zip gcc-5b6d81b17ebf860a9a3ca3945d99514437927c81.tar.gz gcc-5b6d81b17ebf860a9a3ca3945d99514437927c81.tar.bz2 |
New simplify_using_ranges and range_store classes.
simplify_using_ranges class contains the simplication with ranges code.
range_store is a class which provides a generic mechanism to get a stored
range for an SSA. All goris and vr_values inherit from it.
-rw-r--r-- | gcc/gimple-range-gori.cc | 7 | ||||
-rw-r--r-- | gcc/gimple-range-gori.h | 10 | ||||
-rw-r--r-- | gcc/gimple-ssa-evrp-analyze.c | 170 | ||||
-rw-r--r-- | gcc/gimple-ssa-evrp-analyze.h | 6 | ||||
-rw-r--r-- | gcc/gimple-ssa-evrp.c | 22 | ||||
-rw-r--r-- | gcc/tree-ssa-dom.c | 11 | ||||
-rw-r--r-- | gcc/tree-vrp.c | 37 | ||||
-rw-r--r-- | gcc/vr-values.c | 444 | ||||
-rw-r--r-- | gcc/vr-values.h | 126 |
9 files changed, 460 insertions, 373 deletions
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 86e0970..f44a6b2 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -481,6 +481,13 @@ debug (gori_map &g) g.dump (stderr); } +const value_range_equiv * +range_store::get_value_range (const_tree expr ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); + return NULL; +} + // Return the legacy global known value for NAME in R. void diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index 7560542..45aaa24 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -133,11 +133,19 @@ public: bitmap exports (basic_block bb); }; +// Generic object to return a range for an SSA. +class range_store +{ +public: + virtual bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL) = 0; + virtual const value_range_equiv *get_value_range (const_tree expr); +}; + // This class utilizes a GORI map to determine which SSA_NAMES can // have ranges calculated for them on outgoing edges from basic // blocks. -class gori_compute +class gori_compute : public range_store { public: gori_compute (); diff --git a/gcc/gimple-ssa-evrp-analyze.c b/gcc/gimple-ssa-evrp-analyze.c index 7d9289e..281170a 100644 --- a/gcc/gimple-ssa-evrp-analyze.c +++ b/gcc/gimple-ssa-evrp-analyze.c @@ -45,6 +45,32 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "ssa-range.h" +class vr_gori_interface : public trace_gori_compute +{ +public: + vr_gori_interface (range_store *store) : store (store) { } + virtual bool outgoing_edge_range_p (irange &, edge, tree name, + const irange *name_range = NULL); + bool gori_computable_p (tree name, basic_block); +protected: + virtual bool refine_range_with_equivalences (irange &, edge, tree name); +private: + virtual void range_of_ssa_name (irange &r, tree op, gimple * = NULL); + bool solve_name_at_statement (irange &, tree, gimple *stmt, const irange &); + bool solve_name_given_equivalence (irange &r, tree name, tree equiv, + const irange &equiv_range); + range_store *store; +}; + +class trace_vr_gori_interface : public vr_gori_interface +{ +public: + trace_vr_gori_interface (range_store *store) : vr_gori_interface (store) { } +private: + virtual bool refine_range_with_equivalences (irange &, edge, tree name); + typedef vr_gori_interface super; +}; + evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges) : stack (10), m_update_global_ranges (update_global_ranges) { @@ -59,6 +85,7 @@ evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges) } vr_values = new class vr_values; ranger = new global_ranger; + gori = new trace_vr_gori_interface (vr_values); } evrp_range_analyzer::~evrp_range_analyzer (void) @@ -66,6 +93,7 @@ evrp_range_analyzer::~evrp_range_analyzer (void) delete vr_values; stack.release (); delete ranger; + delete gori; } /* Push an unwinding marker onto the unwinding stack. */ @@ -163,6 +191,144 @@ all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt) return true; } +void +vr_gori_interface::range_of_ssa_name (irange &r, tree op, + gimple *stmt ATTRIBUTE_UNUSED) +{ + r = *store->get_value_range (op); + r.normalize_symbolics (); +} + +// Return TRUE if NAME is computable by GORI in BB. + +bool +vr_gori_interface::gori_computable_p (tree name, basic_block bb) +{ + return m_gori_map.is_export_p (name, bb); +} + +// Calculate the range for NAME on edge E and return it in R. +// Return FALSE if unable to compute a range. + +bool +vr_gori_interface::outgoing_edge_range_p (irange &r, edge e, tree name, + const irange *known_range ATTRIBUTE_UNUSED) +{ + if (!gori_compute::outgoing_edge_range_p (r, e, name)) + r.set_varying (TREE_TYPE (name)); + if (!r.singleton_p ()) + refine_range_with_equivalences (r, e, name); + widest_irange tmp; + range_of_ssa_name (tmp, name); + r.intersect (tmp); + return !r.varying_p (); +} + +// R is a known range for NAME on edge E. Refine it with any +// equivalences NAME may have. + +bool +vr_gori_interface::refine_range_with_equivalences (irange &r, + edge e, tree name) +{ + widest_irange branch_range, tmp; + gimple *branch = gimple_outgoing_edge_range_p (branch_range, e); + if (!branch) + return false; + + // Solve each equivalence and use them to refine the range. + bitmap_iterator bi; + unsigned i; + bitmap gori_exports = m_gori_map.exports (e->src); + EXECUTE_IF_SET_IN_BITMAP (gori_exports, 0, i, bi) + { + tree equiv = ssa_name (i); + if (equiv == name) + continue; + widest_irange equiv_range; + if (solve_name_at_statement (equiv_range, equiv, branch, branch_range)) + { + gimple *equiv_def = SSA_NAME_DEF_STMT (equiv); + if (!equiv_def->bb + || !dominated_by_p (CDI_DOMINATORS, e->src, equiv_def->bb)) + continue; + + if (solve_name_given_equivalence (tmp, name, equiv, equiv_range)) + r.intersect (tmp); + } + } + return !r.varying_p (); +} + +// Compute a range for NAME as it would appear in STMT and return it +// in R. LHS is the known range for STMT. + +bool +vr_gori_interface::solve_name_at_statement (irange &r, + tree name, gimple *stmt, + const irange &lhs) +{ + widest_irange name_range; + range_of_ssa_name (name_range, name, stmt); + return compute_operand_range (r, stmt, lhs, name, &name_range); +} + +bool +vr_gori_interface::solve_name_given_equivalence (irange &r, + tree name, + tree equiv, + const irange &equiv_range) +{ + // Solve NAME in EQUIV = USE(NAME). + gimple *def = SSA_NAME_DEF_STMT (equiv); + if (gimple_range_handler (def) && gimple_range_operand1 (def) == name) + { + widest_irange op2_range; + if (tree op2 = gimple_range_operand2 (def)) + range_of_expr (op2_range, op2, def); + else + { + tree type = TREE_TYPE (gimple_range_operand1 (def)); + op2_range.set_varying (type); + } + return gimple_range_calc_op1 (def, r, equiv_range, op2_range); + } + // Solve NAME in NAME = USE(EQUIV). + def = SSA_NAME_DEF_STMT (name); + if (gimple_range_handler (def) && gimple_range_operand1 (def) == equiv) + { + widest_irange op2_range; + if (tree op2 = gimple_range_operand2 (def)) + range_of_expr (op2_range, op2, def); + else + { + tree type = gimple_expr_type (def); + op2_range.set_varying (type); + } + return gimple_range_fold (def, r, equiv_range, op2_range); + } + return false; +} + +bool +trace_vr_gori_interface::refine_range_with_equivalences (irange &r, + edge e, tree name) +{ + unsigned idx = ++trace_count; + if (dumping (idx)) + { + fprintf (dump_file, "refine_range_with_equivalences ("); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") on edge %d->%d, with range ", + e->src->index, e->dest->index); + r.dump (dump_file); + fputc ('\n', dump_file); + indent += bump; + } + bool res = super::refine_range_with_equivalences (r, e, name); + return trailer (idx, "refine_range_with_equivalences", res, name, r); +} + // Class to assert that gori/ranger provide ranges that are at least // as good as evrp. @@ -313,11 +479,11 @@ evrp_range_analyzer::try_find_new_range_for_assert (const assert_info &assert, widest_irange tmp; bitmap_iterator bi; bool gori_can_calculate = (assert.gori_computable_p - && vr_values->gori_computable_p (name, e->src)); + && gori->gori_computable_p (name, e->src)); if (gori_can_calculate) { - if (!vr_values->outgoing_edge_range_p (vr_gori, e, name)) + if (!gori->outgoing_edge_range_p (vr_gori, e, name)) vr_gori.set_varying (TREE_TYPE (name)); } diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h index f7cef41..d157191 100644 --- a/gcc/gimple-ssa-evrp-analyze.h +++ b/gcc/gimple-ssa-evrp-analyze.h @@ -46,7 +46,10 @@ class evrp_range_analyzer /* A bit of a wart. This should ideally go away. */ void vrp_visit_cond_stmt (gcond *cond, edge *e) - { return vr_values->vrp_visit_cond_stmt (cond, e); } + { + simplify_using_ranges simpl (vr_values); + simpl.vrp_visit_cond_stmt (cond, e); + } /* Get the underlying vr_values class instance. If TRANSFER is true, then we are transferring ownership. Else we keep ownership. @@ -72,6 +75,7 @@ class evrp_range_analyzer /* True if we are updating global ranges, false otherwise. */ bool m_update_global_ranges; + class trace_vr_gori_interface *gori; class gimple_ranger *ranger; }; diff --git a/gcc/gimple-ssa-evrp.c b/gcc/gimple-ssa-evrp.c index af953cb..ffe83a6 100644 --- a/gcc/gimple-ssa-evrp.c +++ b/gcc/gimple-ssa-evrp.c @@ -46,13 +46,18 @@ class evrp_folder : public substitute_and_fold_engine { public: tree get_value (tree) FINAL OVERRIDE; - evrp_folder (class vr_values *vr_values_) : vr_values (vr_values_) { } + evrp_folder (class vr_values *vr_values_) + : vr_values (vr_values_), + simplifier (vr_values_) { } bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) - { return vr_values->simplify_stmt_using_ranges (gsi); } + { + return simplifier.simplify (gsi); + } class vr_values *vr_values; private: DISABLE_COPY_AND_ASSIGN (evrp_folder); + simplify_using_ranges simplifier; }; tree @@ -306,16 +311,15 @@ evrp_dom_walker::cleanup (void) gimple *stmt = stmts_to_fixup.pop (); fixup_noreturn_call (stmt); } - - evrp_folder.vr_values->cleanup_edges_and_switches (); } class xevrp_folder : public substitute_and_fold_engine { public: - xevrp_folder () : range_analyzer (true) + xevrp_folder () : range_analyzer (true), + vr_values (range_analyzer.get_vr_values ()), + simplifier (vr_values) { - vr_values = range_analyzer.get_vr_values (); } ~xevrp_folder () @@ -326,7 +330,6 @@ public: range_analyzer.dump_all_value_ranges (dump_file); fprintf (dump_file, "\n"); } - vr_values->cleanup_edges_and_switches (); } tree get_value (tree op) @@ -353,7 +356,7 @@ public: bool fold_stmt (gimple_stmt_iterator *gsi) { - return vr_values->simplify_stmt_using_ranges (gsi); + return simplifier.simplify (gsi); } void post_fold_bb (basic_block bb) @@ -368,8 +371,9 @@ public: private: DISABLE_COPY_AND_ASSIGN (xevrp_folder); - class vr_values *vr_values; class evrp_range_analyzer range_analyzer; + class vr_values *vr_values; + simplify_using_ranges simplifier; }; /* Main entry point for the early vrp pass which is a simplified non-iterative diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index 1dbfb38..ab4cee6 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -886,12 +886,11 @@ simplify_stmt_for_jump_threading (gimple *stmt, copy in tree-vrp is scheduled for removal in gcc-9. */ if (gcond *cond_stmt = dyn_cast <gcond *> (stmt)) { - cached_lhs - = x_vr_values->vrp_evaluate_conditional (gimple_cond_code (cond_stmt), - gimple_cond_lhs (cond_stmt), - gimple_cond_rhs (cond_stmt), - within_stmt); - return cached_lhs; + simplify_using_ranges simplifier (x_vr_values); + return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + gimple_cond_lhs (cond_stmt), + gimple_cond_rhs (cond_stmt), + within_stmt); } if (gswitch *switch_stmt = dyn_cast <gswitch *> (stmt)) diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index ead8552..fcc79c7 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -3500,7 +3500,7 @@ class vrp_prop : public ssa_propagation_engine enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE; void vrp_initialize (void); - void vrp_finalize (bool); + void vrp_finalize (class vrp_folder *, bool); void check_all_array_refs (void); bool check_array_ref (location_t, tree, bool); bool check_mem_ref (location_t, tree, bool); @@ -4850,21 +4850,26 @@ vrp_prop::visit_phi (gphi *phi) class vrp_folder : public substitute_and_fold_engine { public: - vrp_folder () : substitute_and_fold_engine (/* Fold all stmts. */ true) { } + vrp_folder (vr_values *v) + : substitute_and_fold_engine (/* Fold all stmts. */ true), + m_vr_values (v), simplifier (v) + { } tree get_value (tree) FINAL OVERRIDE; bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE; bool fold_predicate_in (gimple_stmt_iterator *); - class vr_values *vr_values; - /* Delegators. */ tree vrp_evaluate_conditional (tree_code code, tree op0, tree op1, gimple *stmt) - { return vr_values->vrp_evaluate_conditional (code, op0, op1, stmt); } + { return simplifier.vrp_evaluate_conditional (code, op0, op1, stmt); } bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) - { return vr_values->simplify_stmt_using_ranges (gsi); } + { return simplifier.simplify (gsi); } tree op_with_constant_singleton_value_range (tree op) - { return vr_values->op_with_constant_singleton_value_range (op); } + { return m_vr_values->op_with_constant_singleton_value_range (op); } + +private: + vr_values *m_vr_values; + simplify_using_ranges simplifier; }; /* If the statement pointed by SI has a predicate whose value can be @@ -5006,7 +5011,8 @@ simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt, tree op1 = gimple_cond_rhs (cond_stmt); op1 = lhs_of_dominating_assert (op1, bb, stmt); - return vr_values->vrp_evaluate_conditional (gimple_cond_code (cond_stmt), + simplify_using_ranges simplifier (vr_values); + return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt), op0, op1, within_stmt); } @@ -5242,7 +5248,7 @@ identify_jump_threads (class vr_values *vr_values) /* Traverse all the blocks folding conditionals with known ranges. */ void -vrp_prop::vrp_finalize (bool warn_array_bounds_p) +vrp_prop::vrp_finalize (vrp_folder *folder, bool warn_array_bounds_p) { size_t i; @@ -5286,9 +5292,7 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p) if (warn_array_bounds && warn_array_bounds_p) set_all_edges_as_executable (cfun); - class vrp_folder vrp_folder; - vrp_folder.vr_values = &vr_values; - vrp_folder.substitute_and_fold (); + folder->substitute_and_fold (); if (warn_array_bounds && warn_array_bounds_p) check_all_array_refs (); @@ -5359,7 +5363,10 @@ execute_vrp (bool warn_array_bounds_p) class vrp_prop vrp_prop; vrp_prop.vrp_initialize (); vrp_prop.ssa_propagate (); - vrp_prop.vrp_finalize (warn_array_bounds_p); + /* Instantiate the folder here, so that edge cleanups happen at the + end of this function. */ + vrp_folder folder (&vrp_prop.vr_values); + vrp_prop.vrp_finalize (&folder, warn_array_bounds_p); /* We must identify jump threading opportunities before we release the datastructures built by VRP. */ @@ -5377,7 +5384,8 @@ execute_vrp (bool warn_array_bounds_p) { gimple *last = last_stmt (bb); if (last && gimple_code (last) == GIMPLE_COND) - vrp_prop.vr_values.simplify_cond_using_ranges_2 (as_a <gcond *> (last)); + simplify_cond_using_ranges_2 (&vrp_prop.vr_values, + as_a <gcond *> (last)); } free_numbers_of_iterations_estimates (cfun); @@ -5402,7 +5410,6 @@ execute_vrp (bool warn_array_bounds_p) processing by the pass manager. */ thread_through_all_blocks (false); - vrp_prop.vr_values.cleanup_edges_and_switches (); threadedge_finalize_values (); scev_finalize (); diff --git a/gcc/vr-values.c b/gcc/vr-values.c index 1ea121f..d327f22 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -173,6 +173,25 @@ vr_values::get_value_range (const_tree var) return vr; } +bool +vr_values::range_of_expr (irange &r, tree expr, gimple *stmt ATTRIBUTE_UNUSED) +{ + tree type = TREE_TYPE (expr); + if (!irange::supports_type_p (type)) + return false; + + if (TREE_CODE (expr) == SSA_NAME) + { + const value_range_equiv *vr = get_value_range (expr); + r = *vr; + } + else if (TREE_CODE (expr) == INTEGER_CST) + r.set (expr, expr); + else + r.set_varying (type); + return true; +} + /* Set the lattice entry for DEF to VARYING. */ void @@ -437,10 +456,8 @@ vr_values::op_with_constant_singleton_value_range (tree op) /* Return true if op is in a boolean [0, 1] value-range. */ bool -vr_values::op_with_boolean_value_range_p (tree op) +simplify_using_ranges::op_with_boolean_value_range_p (tree op, gimple *stmt) { - const value_range_equiv *vr; - if (TYPE_PRECISION (TREE_TYPE (op)) == 1) return true; @@ -451,10 +468,11 @@ vr_values::op_with_boolean_value_range_p (tree op) if (TREE_CODE (op) != SSA_NAME) return false; - vr = get_value_range (op); - return (vr->kind () == VR_RANGE - && integer_zerop (vr->min ()) - && integer_onep (vr->max ())); + widest_irange r; + gcc_checking_assert (store->range_of_expr (r, op, stmt)); + return (r.kind () == VR_RANGE + && integer_zerop (r.min ()) + && integer_onep (r.max ())); } /* Extract value range information for VAR when (OP COND_CODE LIMIT) is @@ -980,8 +998,8 @@ vr_values::extract_range_from_comparison (value_range_equiv *vr, bool sop; tree val; - val = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, false, &sop, - NULL); + val = simplifier.vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, + false, &sop, NULL); if (val) { /* Since this expression was found on the RHS of an assignment, @@ -1004,20 +1022,21 @@ vr_values::extract_range_from_comparison (value_range_equiv *vr, always overflow. Set *OVF to true if it is known to always overflow. */ -bool -vr_values::check_for_binary_op_overflow (enum tree_code subcode, tree type, - tree op0, tree op1, bool *ovf) +static bool +check_for_binary_op_overflow (range_store *store, + enum tree_code subcode, tree type, + tree op0, tree op1, bool *ovf) { value_range vr0, vr1; if (TREE_CODE (op0) == SSA_NAME) - vr0 = *get_value_range (op0); + gcc_checking_assert (store->range_of_expr (vr0, op0)); else if (TREE_CODE (op0) == INTEGER_CST) vr0.set (op0); else vr0.set_varying (TREE_TYPE (op0)); if (TREE_CODE (op1) == SSA_NAME) - vr1 = *get_value_range (op1); + store->range_of_expr (vr1, op1); else if (TREE_CODE (op1) == INTEGER_CST) vr1.set (op1); else @@ -1397,7 +1416,8 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt) if (code == IMAGPART_EXPR) { bool ovf = false; - if (check_for_binary_op_overflow (subcode, type, + if (check_for_binary_op_overflow (this, + subcode, type, op0, op1, &ovf)) vr->set (build_int_cst (type, ovf)); else if (TYPE_PRECISION (type) == 1 @@ -1638,7 +1658,7 @@ compare_ranges (enum tree_code comp, const value_range_equiv *vr0, assumed signed overflow is undefined. */ static tree -compare_range_with_value (enum tree_code comp, const value_range_equiv *vr, +compare_range_with_value (enum tree_code comp, const irange *vr, tree val, bool *strict_overflow_p) { if (vr->varying_p () || vr->undefined_p ()) @@ -1932,13 +1952,6 @@ vr_values::dump_all_value_ranges (FILE *file) { size_t i; - if (dump_flags & TDF_GORI) - { - fprintf (file, "GORI map:\n"); - m_gori_map.dump (file); - fprintf (file, "-----------------\n"); - } - for (i = 0; i < num_vr_values; i++) { if (vr_value[i]) @@ -1951,155 +1964,16 @@ vr_values::dump_all_value_ranges (FILE *file) } } -void -vr_values::range_of_ssa_name (irange &r, tree op, - gimple *stmt ATTRIBUTE_UNUSED) -{ - r = *(get_value_range (op)); - r.normalize_symbolics (); -} - -// Return TRUE if NAME is computable by GORI in BB. - -bool -vr_gori_interface::gori_computable_p (tree name, basic_block bb) -{ - return m_gori_map.is_export_p (name, bb); -} - -// Calculate the range for NAME on edge E and return it in R. -// Return FALSE if unable to compute a range. - -bool -vr_gori_interface::outgoing_edge_range_p (irange &r, edge e, tree name, - const irange *known_range ATTRIBUTE_UNUSED) -{ - if (!gori_compute::outgoing_edge_range_p (r, e, name)) - r.set_varying (TREE_TYPE (name)); - if (!r.singleton_p ()) - refine_range_with_equivalences (r, e, name); - widest_irange tmp; - range_of_ssa_name (tmp, name); - r.intersect (tmp); - return !r.varying_p (); -} - -// R is a known range for NAME on edge E. Refine it with any -// equivalences NAME may have. - -bool -vr_gori_interface::refine_range_with_equivalences (irange &r, - edge e, tree name) -{ - widest_irange branch_range, tmp; - gimple *branch = gimple_outgoing_edge_range_p (branch_range, e); - if (!branch) - return false; - - // Solve each equivalence and use them to refine the range. - bitmap_iterator bi; - unsigned i; - bitmap gori_exports = m_gori_map.exports (e->src); - EXECUTE_IF_SET_IN_BITMAP (gori_exports, 0, i, bi) - { - tree equiv = ssa_name (i); - if (equiv == name) - continue; - widest_irange equiv_range; - if (solve_name_at_statement (equiv_range, equiv, branch, branch_range)) - { - gimple *equiv_def = SSA_NAME_DEF_STMT (equiv); - if (!equiv_def->bb - || !dominated_by_p (CDI_DOMINATORS, e->src, equiv_def->bb)) - continue; - - if (solve_name_given_equivalence (tmp, name, equiv, equiv_range)) - r.intersect (tmp); - } - } - return !r.varying_p (); -} - -// Compute a range for NAME as it would appear in STMT and return it -// in R. LHS is the known range for STMT. - -bool -vr_gori_interface::solve_name_at_statement (irange &r, - tree name, gimple *stmt, - const irange &lhs) -{ - widest_irange name_range; - range_of_ssa_name (name_range, name, stmt); - return compute_operand_range (r, stmt, lhs, name, &name_range); -} - -bool -vr_gori_interface::solve_name_given_equivalence (irange &r, - tree name, - tree equiv, - const irange &equiv_range) -{ - // Solve NAME in EQUIV = USE(NAME). - gimple *def = SSA_NAME_DEF_STMT (equiv); - if (gimple_range_handler (def) && gimple_range_operand1 (def) == name) - { - widest_irange op2_range; - if (tree op2 = gimple_range_operand2 (def)) - range_of_expr (op2_range, op2, def); - else - { - tree type = TREE_TYPE (gimple_range_operand1 (def)); - op2_range.set_varying (type); - } - return gimple_range_calc_op1 (def, r, equiv_range, op2_range); - } - // Solve NAME in NAME = USE(EQUIV). - def = SSA_NAME_DEF_STMT (name); - if (gimple_range_handler (def) && gimple_range_operand1 (def) == equiv) - { - widest_irange op2_range; - if (tree op2 = gimple_range_operand2 (def)) - range_of_expr (op2_range, op2, def); - else - { - tree type = gimple_expr_type (def); - op2_range.set_varying (type); - } - return gimple_range_fold (def, r, equiv_range, op2_range); - } - return false; -} - -bool -trace_vr_gori_interface::refine_range_with_equivalences (irange &r, - edge e, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "refine_range_with_equivalences ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") on edge %d->%d, with range ", - e->src->index, e->dest->index); - r.dump (dump_file); - fputc ('\n', dump_file); - indent += bump; - } - bool res = super::refine_range_with_equivalences (r, e, name); - return trailer (idx, "refine_range_with_equivalences", res, name, r); -} - /* Initialize VRP lattice. */ -vr_values::vr_values () : vrp_value_range_pool ("Tree VRP value ranges") +vr_values::vr_values () : vrp_value_range_pool ("Tree VRP value ranges"), + simplifier (this) { values_propagated = false; num_vr_values = num_ssa_names * 2; vr_value = XCNEWVEC (value_range_equiv *, num_vr_values); vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names); bitmap_obstack_initialize (&vrp_equiv_obstack); - to_remove_edges = vNULL; - to_update_switch_stmts = vNULL; } /* Free VRP lattice. */ @@ -2116,12 +1990,6 @@ vr_values::~vr_values () and not available. */ vr_value = NULL; vr_phi_edge_counts = NULL; - - /* If there are entries left in TO_REMOVE_EDGES or TO_UPDATE_SWITCH_STMTS - then an EVRP client did not clean up properly. Catch it now rather - than seeing something more obscure later. */ - gcc_assert (to_remove_edges.is_empty () - && to_update_switch_stmts.is_empty ()); } @@ -2239,10 +2107,10 @@ vr_values::vrp_visit_assignment_or_call (gimple *stmt, tree *output_p, is varying or undefined. Uses TEM as storage for the alternate range. */ const value_range_equiv * -vr_values::get_vr_for_comparison (int i, value_range_equiv *tem) +simplify_using_ranges::get_vr_for_comparison (int i, value_range_equiv *tem) { /* Shallow-copy equiv bitmap. */ - const value_range_equiv *vr = get_value_range (ssa_name (i)); + const value_range_equiv *vr = get_value_range_equiv (ssa_name (i)); /* If name N_i does not have a valid range, use N_i as its own range. This allows us to compare against names that may @@ -2262,11 +2130,12 @@ vr_values::get_vr_for_comparison (int i, value_range_equiv *tem) *STRICT_OVERFLOW_P. */ tree -vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val, - bool *strict_overflow_p, bool use_equiv_p) +simplify_using_ranges::compare_name_with_value + (enum tree_code comp, tree var, tree val, + bool *strict_overflow_p, bool use_equiv_p) { /* Get the set of equivalences for VAR. */ - bitmap e = get_value_range (var)->equiv (); + bitmap e = get_value_range_equiv (var)->equiv (); /* Start at -1. Set it to 0 if we do a comparison without relying on overflow, or 1 if all comparisons rely on overflow. */ @@ -2341,13 +2210,13 @@ vr_values::compare_name_with_value (enum tree_code comp, tree var, tree val, tree -vr_values::compare_names (enum tree_code comp, tree n1, tree n2, - bool *strict_overflow_p) +simplify_using_ranges::compare_names (enum tree_code comp, tree n1, tree n2, + bool *strict_overflow_p) { /* Compare the ranges of every name equivalent to N1 against the ranges of every name equivalent to N2. */ - bitmap e1 = get_value_range (n1)->equiv (); - bitmap e2 = get_value_range (n2)->equiv (); + bitmap e1 = get_value_range_equiv (n1)->equiv (); + bitmap e2 = get_value_range_equiv (n2)->equiv (); /* Use the fake bitmaps if e1 or e2 are not available. */ static bitmap s_e1 = NULL, s_e2 = NULL; @@ -2455,12 +2324,12 @@ vr_values::compare_names (enum tree_code comp, tree n1, tree n2, optimizers. */ tree -vr_values::vrp_evaluate_conditional_warnv_with_ops_using_ranges +simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code code, tree op0, tree op1, bool * strict_overflow_p) { const value_range_equiv *vr0, *vr1; - vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL; - vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL; + vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range_equiv (op0) : NULL; + vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range_equiv (op1) : NULL; tree res = NULL_TREE; if (vr0 && vr1) @@ -2476,11 +2345,12 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops_using_ranges /* Helper function for vrp_evaluate_conditional_warnv. */ tree -vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, - tree op0, tree op1, - bool use_equiv_p, - bool *strict_overflow_p, - bool *only_ranges) +simplify_using_ranges::vrp_evaluate_conditional_warnv_with_ops + (enum tree_code code, + tree op0, tree op1, + bool use_equiv_p, + bool *strict_overflow_p, + bool *only_ranges) { tree ret; if (only_ranges) @@ -2537,7 +2407,7 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, } else gcc_unreachable (); - const value_range_equiv *vr0 = get_value_range (op0); + const value_range_equiv *vr0 = get_value_range_equiv (op0); /* If vro, the range for OP0 to pass the overflow test, has no intersection with *vr0, OP0's known range, then the overflow test can't pass, so return the node for false. @@ -2583,8 +2453,8 @@ vr_values::vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, appropriate. */ tree -vr_values::vrp_evaluate_conditional (tree_code code, tree op0, - tree op1, gimple *stmt) +simplify_using_ranges::vrp_evaluate_conditional (tree_code code, tree op0, + tree op1, gimple *stmt) { bool sop; tree ret; @@ -2643,7 +2513,7 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0, always fold regardless of the value of OP0. If -Wtype-limits was specified, emit a warning. */ tree type = TREE_TYPE (op0); - const value_range_equiv *vr0 = get_value_range (op0); + const value_range_equiv *vr0 = get_value_range_equiv (op0); if (vr0->kind () == VR_RANGE && INTEGRAL_TYPE_P (type) @@ -2676,7 +2546,7 @@ vr_values::vrp_evaluate_conditional (tree_code code, tree op0, *TAKEN_EDGE_P. Otherwise, set *TAKEN_EDGE_P to NULL. */ void -vr_values::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p) +simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p) { tree val; @@ -2696,7 +2566,7 @@ vr_values::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p) fprintf (dump_file, "\t"); print_generic_expr (dump_file, use); fprintf (dump_file, ": "); - dump_value_range (dump_file, vr_value[SSA_NAME_VERSION (use)]); + dump_value_range (dump_file, store->get_value_range (use)); } fprintf (dump_file, "\n"); @@ -2769,7 +2639,7 @@ vr_values::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p) Returns true if the default label is not needed. */ static bool -find_case_label_ranges (gswitch *stmt, const value_range_equiv *vr, +find_case_label_ranges (gswitch *stmt, const irange *vr, size_t *min_idx1, size_t *max_idx1, size_t *min_idx2, size_t *max_idx2) { @@ -2953,7 +2823,7 @@ vr_values::extract_range_from_stmt (gimple *stmt, edge *taken_edge_p, else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) vrp_visit_assignment_or_call (stmt, output_p, vr); else if (gimple_code (stmt) == GIMPLE_COND) - vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p); + simplifier.vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p); else if (gimple_code (stmt) == GIMPLE_SWITCH) vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p); } @@ -3174,8 +3044,9 @@ update_range: /* Simplify boolean operations if the source is known to be already a boolean. */ bool -vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_truth_ops_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { enum tree_code rhs_code = gimple_assign_rhs_code (stmt); tree lhs, op0, op1; @@ -3185,11 +3056,11 @@ vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR); op0 = gimple_assign_rhs1 (stmt); - if (!op_with_boolean_value_range_p (op0)) + if (!op_with_boolean_value_range_p (op0, stmt)) return false; op1 = gimple_assign_rhs2 (stmt); - if (!op_with_boolean_value_range_p (op1)) + if (!op_with_boolean_value_range_p (op1, stmt)) return false; /* Reduce number of cases to handle to NE_EXPR. As there is no @@ -3251,8 +3122,9 @@ vr_values::simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, modulo. */ bool -vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_div_or_mod_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { enum tree_code rhs_code = gimple_assign_rhs_code (stmt); tree val = NULL; @@ -3260,7 +3132,11 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, tree op1 = gimple_assign_rhs2 (stmt); tree op0min = NULL_TREE, op0max = NULL_TREE; tree op1min = op1; - const value_range_equiv *vr = NULL; + /* ?? All uses of value_range in the simplifier should be converted + to widest_irange. However, in order to do this, there must be no + VR_ANTI_RANGE uses downstream, as widest_irange has no concept of + them except for symbolics. */ + value_range vr; if (TREE_CODE (op0) == INTEGER_CST) { @@ -3269,20 +3145,21 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, } else { - vr = get_value_range (op0); - if (range_int_cst_p (vr)) + gcc_checking_assert (store->range_of_expr (vr, op0, stmt)); + if (range_int_cst_p (&vr)) { - op0min = vr->min (); - op0max = vr->max (); + op0min = vr.min (); + op0max = vr.max (); } } if (rhs_code == TRUNC_MOD_EXPR && TREE_CODE (op1) == SSA_NAME) { - const value_range_equiv *vr1 = get_value_range (op1); - if (range_int_cst_p (vr1)) - op1min = vr1->min (); + value_range vr1; + gcc_checking_assert (store->range_of_expr (vr1, op1, stmt)); + if (range_int_cst_p (&vr1)) + op1min = vr1.min (); } if (rhs_code == TRUNC_MOD_EXPR && TREE_CODE (op1min) == INTEGER_CST @@ -3323,7 +3200,7 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, { bool sop = false; - val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop); + val = compare_range_with_value (GE_EXPR, &vr, integer_zero_node, &sop); if (val && sop @@ -3376,8 +3253,9 @@ vr_values::simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, disjoint. Return true if we do simplify. */ bool -vr_values::simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_min_or_max_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { tree op0 = gimple_assign_rhs1 (stmt); if (!irange::supports_type_p (TREE_TYPE (op0))) @@ -3385,13 +3263,13 @@ vr_values::simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi, tree op1 = gimple_assign_rhs2 (stmt); value_range vr0, vr1; if (TREE_CODE (op0) == SSA_NAME) - vr0 = *get_value_range (op0); + gcc_checking_assert (store->range_of_expr (vr0, op0, stmt)); else if (TREE_CODE (op0) == INTEGER_CST) vr0.set (op0); else vr0.set_varying (TREE_TYPE (op0)); if (TREE_CODE (op1) == SSA_NAME) - vr1 = *get_value_range (op1); + gcc_checking_assert (store->range_of_expr (vr1, op1, stmt)); else if (TREE_CODE (op1) == INTEGER_CST) vr1.set (op1); else @@ -3427,23 +3305,25 @@ vr_values::simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi, ABS_EXPR into a NEGATE_EXPR. */ bool -vr_values::simplify_abs_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt) +simplify_using_ranges::simplify_abs_using_ranges (gimple_stmt_iterator *gsi, + gimple *stmt) { tree op = gimple_assign_rhs1 (stmt); - const value_range_equiv *vr = get_value_range (op); + value_range vr; + gcc_checking_assert (store->range_of_expr (vr, op, stmt)); - if (vr) + if (!vr.varying_p () && !vr.undefined_p ()) { tree val = NULL; bool sop = false; - val = compare_range_with_value (LE_EXPR, vr, integer_zero_node, &sop); + val = compare_range_with_value (LE_EXPR, &vr, integer_zero_node, &sop); if (!val) { /* The range is neither <= 0 nor > 0. Now see if it is either < 0 or >= 0. */ sop = false; - val = compare_range_with_value (LT_EXPR, vr, integer_zero_node, + val = compare_range_with_value (LT_EXPR, &vr, integer_zero_node, &sop); } @@ -3507,8 +3387,9 @@ vr_set_zero_nonzero_bits (const tree expr_type, operation is redundant. */ bool -vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_bit_ops_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { tree op0 = gimple_assign_rhs1 (stmt); tree op1 = gimple_assign_rhs2 (stmt); @@ -3519,14 +3400,14 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, wide_int mask; if (TREE_CODE (op0) == SSA_NAME) - vr0 = *(get_value_range (op0)); + gcc_checking_assert (store->range_of_expr (vr0, op0, stmt)); else if (is_gimple_min_invariant (op0)) vr0.set (op0); else return false; if (TREE_CODE (op1) == SSA_NAME) - vr1 = *(get_value_range (op1)); + gcc_checking_assert (store->range_of_expr (vr1, op1, stmt)); else if (is_gimple_min_invariant (op1)) vr1.set (op1); else @@ -3592,7 +3473,7 @@ vr_values::simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, static tree test_for_singularity (enum tree_code cond_code, tree op0, - tree op1, const value_range_equiv *vr) + tree op1, const irange *vr) { tree min = NULL; tree max = NULL; @@ -3650,7 +3531,7 @@ test_for_singularity (enum tree_code cond_code, tree op0, by PRECISION and UNSIGNED_P. */ static bool -range_fits_type_p (const value_range_equiv *vr, +range_fits_type_p (const value_range *vr, unsigned dest_precision, signop dest_sgn) { tree src_type; @@ -3699,7 +3580,8 @@ range_fits_type_p (const value_range_equiv *vr, } bool -vr_values::simplify_cond_using_ranges_when_edge_is_known (gcond *cond) +simplify_using_ranges::simplify_cond_using_ranges_when_edge_is_known + (gcond *cond) { /* ?? vrp_folder::fold_predicate_in() is a superset of this. At some point we should merge all variants of this code. */ @@ -3724,7 +3606,7 @@ vr_values::simplify_cond_using_ranges_when_edge_is_known (gcond *cond) the original conditional. */ bool -vr_values::simplify_cond_using_ranges_1 (gcond *stmt) +simplify_using_ranges::simplify_cond_using_ranges_1 (gcond *stmt) { tree op0 = gimple_cond_lhs (stmt); tree op1 = gimple_cond_rhs (stmt); @@ -3739,13 +3621,14 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt) && INTEGRAL_TYPE_P (TREE_TYPE (op0)) && is_gimple_min_invariant (op1)) { - const value_range_equiv *vr = get_value_range (op0); + value_range vr; + gcc_checking_assert (store->range_of_expr (vr, op0, stmt)); /* If we have range information for OP0, then we might be able to simplify this conditional. */ - if (vr->kind () == VR_RANGE) + if (vr.kind () == VR_RANGE) { - tree new_tree = test_for_singularity (cond_code, op0, op1, vr); + tree new_tree = test_for_singularity (cond_code, op0, op1, &vr); if (new_tree) { if (dump_file) @@ -3775,7 +3658,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt) issues with inverting FP comparisons. */ new_tree = test_for_singularity (invert_tree_comparison (cond_code, false), - op0, op1, vr); + op0, op1, &vr); if (new_tree) { if (dump_file) @@ -3812,7 +3695,7 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt) subsequent passes. */ void -vr_values::simplify_cond_using_ranges_2 (gcond *stmt) +simplify_cond_using_ranges_2 (range_store *store, gcond *stmt) { tree op0 = gimple_cond_lhs (stmt); tree op1 = gimple_cond_rhs (stmt); @@ -3842,10 +3725,11 @@ vr_values::simplify_cond_using_ranges_2 (gcond *stmt) && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop) && desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0))) { - const value_range_equiv *vr = get_value_range (innerop); + value_range vr; + gcc_checking_assert (store->range_of_expr (vr, innerop, stmt)); - if (range_int_cst_p (vr) - && range_fits_type_p (vr, + if (range_int_cst_p (&vr) + && range_fits_type_p (&vr, TYPE_PRECISION (TREE_TYPE (op0)), TYPE_SIGN (TREE_TYPE (op0))) && int_fits_type_p (op1, TREE_TYPE (innerop))) @@ -3869,10 +3753,10 @@ vr_values::simplify_cond_using_ranges_2 (gcond *stmt) argument. */ bool -vr_values::simplify_switch_using_ranges (gswitch *stmt) +simplify_using_ranges::simplify_switch_using_ranges (gswitch *stmt) { tree op = gimple_switch_index (stmt); - const value_range_equiv *vr = NULL; + value_range vr; bool take_default; edge e; edge_iterator ei; @@ -3883,16 +3767,16 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt) if (TREE_CODE (op) == SSA_NAME) { - vr = get_value_range (op); + gcc_checking_assert (store->range_of_expr (vr, op, stmt)); /* We can only handle integer ranges. */ - if (vr->varying_p () - || vr->undefined_p () - || vr->symbolic_p ()) + if (vr.varying_p () + || vr.undefined_p () + || vr.symbolic_p ()) return false; /* Find case label for min/max of the value range. */ - take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l); + take_default = !find_case_label_ranges (stmt, &vr, &i, &j, &k, &l); } else if (TREE_CODE (op) == INTEGER_CST) { @@ -3915,8 +3799,8 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt) /* We can truncate the case label ranges that partially overlap with OP's value range. */ size_t min_idx = 1, max_idx = 0; - if (vr != NULL) - find_case_label_range (stmt, vr->min (), vr->max (), &min_idx, &max_idx); + if (!vr.varying_p () && !vr.undefined_p ()) + find_case_label_range (stmt, vr.min (), vr.max (), &min_idx, &max_idx); if (min_idx <= max_idx) { tree min_label = gimple_switch_label (stmt, min_idx); @@ -3924,10 +3808,10 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt) /* Avoid changing the type of the case labels when truncating. */ tree case_label_type = TREE_TYPE (CASE_LOW (min_label)); - tree vr_min = fold_convert (case_label_type, vr->min ()); - tree vr_max = fold_convert (case_label_type, vr->max ()); + tree vr_min = fold_convert (case_label_type, vr.min ()); + tree vr_max = fold_convert (case_label_type, vr.max ()); - if (vr->kind () == VR_RANGE) + if (vr.kind () == VR_RANGE) { /* If OP's value range is [2,8] and the low label range is 0 ... 3, truncate the label's range to 2 .. 3. */ @@ -3943,7 +3827,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt) && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0) CASE_HIGH (max_label) = vr_max; } - else if (vr->kind () == VR_ANTI_RANGE) + else if (vr.kind () == VR_ANTI_RANGE) { tree one_cst = build_one_cst (case_label_type); @@ -4050,7 +3934,7 @@ vr_values::simplify_switch_using_ranges (gswitch *stmt) } void -vr_values::cleanup_edges_and_switches (void) +simplify_using_ranges::cleanup_edges_and_switches (void) { int i; edge e; @@ -4168,11 +4052,13 @@ simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt) /* Simplify a conversion from integral SSA name to float in STMT. */ bool -vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_float_conversion_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { tree rhs1 = gimple_assign_rhs1 (stmt); - const value_range_equiv *vr = get_value_range (rhs1); + value_range vr; + gcc_checking_assert (store->range_of_expr (vr, rhs1, stmt)); scalar_float_mode fltmode = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))); scalar_int_mode mode; @@ -4180,14 +4066,14 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gassign *conv; /* We can only handle constant ranges. */ - if (!range_int_cst_p (vr)) + if (!range_int_cst_p (&vr)) return false; /* First check if we can use a signed type in place of an unsigned. */ scalar_int_mode rhs_mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs1)); if (TYPE_UNSIGNED (TREE_TYPE (rhs1)) && can_float_p (fltmode, rhs_mode, 0) != CODE_FOR_nothing - && range_fits_type_p (vr, TYPE_PRECISION (TREE_TYPE (rhs1)), SIGNED)) + && range_fits_type_p (&vr, TYPE_PRECISION (TREE_TYPE (rhs1)), SIGNED)) mode = rhs_mode; /* If we can do the conversion in the current input mode do nothing. */ else if (can_float_p (fltmode, rhs_mode, @@ -4204,7 +4090,7 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, or if the value-range does not fit in the signed type try with a wider mode. */ if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing - && range_fits_type_p (vr, GET_MODE_PRECISION (mode), SIGNED)) + && range_fits_type_p (&vr, GET_MODE_PRECISION (mode), SIGNED)) break; /* But do not widen the input. Instead leave that to the @@ -4230,8 +4116,9 @@ vr_values::simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, /* Simplify an internal fn call using ranges if possible. */ bool -vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, - gimple *stmt) +simplify_using_ranges::simplify_internal_call_using_ranges + (gimple_stmt_iterator *gsi, + gimple *stmt) { enum tree_code subcode; bool is_ubsan = false; @@ -4276,7 +4163,7 @@ vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, return false; else type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt))); - if (!check_for_binary_op_overflow (subcode, type, op0, op1, &ovf) + if (!check_for_binary_op_overflow (store, subcode, type, op0, op1, &ovf) || (is_ubsan && ovf)) return false; @@ -4333,29 +4220,30 @@ vr_values::simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, two-values when it is true. Return false otherwise. */ bool -vr_values::two_valued_val_range_p (tree var, tree *a, tree *b) +simplify_using_ranges::two_valued_val_range_p (tree var, tree *a, tree *b) { - const value_range_equiv *vr = get_value_range (var); - if (vr->varying_p () - || vr->undefined_p () - || TREE_CODE (vr->min ()) != INTEGER_CST - || TREE_CODE (vr->max ()) != INTEGER_CST) + value_range vr; + gcc_checking_assert (store->range_of_expr (vr, var)); + if (vr.varying_p () + || vr.undefined_p () + || TREE_CODE (vr.min ()) != INTEGER_CST + || TREE_CODE (vr.max ()) != INTEGER_CST) return false; - if (vr->kind () == VR_RANGE - && wi::to_wide (vr->max ()) - wi::to_wide (vr->min ()) == 1) + if (vr.kind () == VR_RANGE + && wi::to_wide (vr.max ()) - wi::to_wide (vr.min ()) == 1) { - *a = vr->min (); - *b = vr->max (); + *a = vr.min (); + *b = vr.max (); return true; } /* ~[TYPE_MIN + 1, TYPE_MAX - 1] */ - if (vr->kind () == VR_ANTI_RANGE - && (wi::to_wide (vr->min ()) + if (vr.kind () == VR_ANTI_RANGE + && (wi::to_wide (vr.min ()) - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1 && (wi::to_wide (vrp_val_max (TREE_TYPE (var))) - - wi::to_wide (vr->max ())) == 1) + - wi::to_wide (vr.max ())) == 1) { *a = vrp_val_min (TREE_TYPE (var)); *b = vrp_val_max (TREE_TYPE (var)); @@ -4365,10 +4253,22 @@ vr_values::two_valued_val_range_p (tree var, tree *a, tree *b) return false; } +simplify_using_ranges::simplify_using_ranges (range_store *store) + : store (store) +{ + to_remove_edges = vNULL; + to_update_switch_stmts = vNULL; +} + +simplify_using_ranges::~simplify_using_ranges () +{ + cleanup_edges_and_switches (); +} + /* Simplify STMT using ranges if possible. */ bool -vr_values::simplify_stmt_using_ranges (gimple_stmt_iterator *gsi) +simplify_using_ranges::simplify (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) diff --git a/gcc/vr-values.h b/gcc/vr-values.h index 2a6273c..bd121b7 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -22,28 +22,61 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range-gori.h" -class vr_gori_interface : public trace_gori_compute +class simplify_using_ranges { public: - virtual bool outgoing_edge_range_p (irange &, edge, tree name, - const irange *name_range = NULL); - bool gori_computable_p (tree name, basic_block); -protected: - virtual void range_of_ssa_name (irange &r ATTRIBUTE_UNUSED, - tree op ATTRIBUTE_UNUSED, - gimple *stmt ATTRIBUTE_UNUSED = NULL) - { gcc_unreachable (); } - virtual bool refine_range_with_equivalences (irange &, edge, tree name); - bool solve_name_at_statement (irange &, tree, gimple *stmt, const irange &); - bool solve_name_given_equivalence (irange &r, tree name, tree equiv, - const irange &equiv_range); -}; + simplify_using_ranges (range_store *); + ~simplify_using_ranges (); + bool simplify (gimple_stmt_iterator *); + + // ?? These should be cleaned, merged, and made private. + tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *); + void vrp_visit_cond_stmt (gcond *, edge *); + tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code, + tree, tree, bool, + bool *, bool *); -class trace_vr_gori_interface : public vr_gori_interface -{ private: - virtual bool refine_range_with_equivalences (irange &, edge, tree name); - typedef vr_gori_interface super; + // This is named differently than get_value_range to make it obvious + // that it returns an equivalence. Only use this for calculations + // that may take equivalences, otherwise use range_of_expr. + const value_range_equiv *get_value_range_equiv (const_tree op) + { return store->get_value_range (op); } + bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *); + bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *); + bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *); + bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *); + bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *); + bool simplify_cond_using_ranges_1 (gcond *); + bool simplify_cond_using_ranges_when_edge_is_known (gcond *); + bool simplify_switch_using_ranges (gswitch *); + bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *, + gimple *); + bool simplify_internal_call_using_ranges (gimple_stmt_iterator *, gimple *); + + bool two_valued_val_range_p (tree, tree *, tree *); + bool op_with_boolean_value_range_p (tree, gimple *); + tree compare_name_with_value (enum tree_code, tree, tree, bool *, bool); + tree compare_names (enum tree_code, tree, tree, bool *); + const value_range_equiv *get_vr_for_comparison (int, value_range_equiv *); + tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code, + tree, tree, + bool *); + void cleanup_edges_and_switches (void); + + /* Vectors of edges that need removing and switch statements that + need updating. It is expected that a pass using the simplification + routines will, at the end of the pass, clean up the edges and + switch statements. The class dtor will try to detect cases + that do not follow that expectation. */ + struct switch_update { + gswitch *stmt; + tree vec; + }; + + vec<edge> to_remove_edges; + vec<switch_update> to_update_switch_stmts; + range_store *store; }; /* The VR_VALUES class holds the current view of range information @@ -60,15 +93,16 @@ private: gets attached to an SSA_NAME. It's unclear how useful that global information will be in a world where we can compute context sensitive range information fast or perform on-demand queries. */ -class vr_values : public trace_vr_gori_interface +class vr_values : public range_store { public: vr_values (void); - ~vr_values (void); + virtual ~vr_values (void); const value_range_equiv *get_value_range (const_tree); void set_vr_value (tree, value_range_equiv *); value_range_equiv *swap_vr_value (tree, value_range_equiv *); + bool range_of_expr (irange &r, tree expr, gimple *stmt = NULL); void set_def_to_varying (const_tree); void set_defs_to_varying (gimple *); @@ -76,7 +110,6 @@ class vr_values : public trace_vr_gori_interface tree op_with_constant_singleton_value_range (tree); void adjust_range_with_scev (value_range_equiv *, class loop *, gimple *, tree); - tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *); void dump_all_value_ranges (FILE *); void extract_range_for_var_from_comparison_expr (tree, enum tree_code, @@ -86,11 +119,6 @@ class vr_values : public trace_vr_gori_interface void extract_range_basic (value_range_equiv *, gimple *); void extract_range_from_stmt (gimple *, edge *, tree *, value_range_equiv *); - void vrp_visit_cond_stmt (gcond *, edge *); - - void simplify_cond_using_ranges_2 (gcond *); - bool simplify_stmt_using_ranges (gimple_stmt_iterator *); - /* Indicate that propagation through the lattice is complete. */ void set_lattice_propagation_complete (void) { values_propagated = true; } @@ -100,26 +128,9 @@ class vr_values : public trace_vr_gori_interface void free_value_range (value_range_equiv *vr) { vrp_value_range_pool.remove (vr); } - /* */ - void cleanup_edges_and_switches (void); - private: - virtual void range_of_ssa_name (irange &r, tree op, gimple * = NULL); - value_range_equiv *get_lattice_entry (const_tree); bool vrp_stmt_computes_nonzero (gimple *); - bool op_with_boolean_value_range_p (tree); - bool check_for_binary_op_overflow (enum tree_code, tree, tree, tree, bool *); - const value_range_equiv *get_vr_for_comparison (int, value_range_equiv *); - tree compare_name_with_value (enum tree_code, tree, tree, bool *, bool); - tree compare_names (enum tree_code, tree, tree, bool *); - bool two_valued_val_range_p (tree, tree *, tree *); - tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code, - tree, tree, - bool *); - tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code, - tree, tree, bool, - bool *, bool *); void extract_range_from_assignment (value_range_equiv *, gassign *); void extract_range_from_assert (value_range_equiv *, tree); void extract_range_from_ssa_name (value_range_equiv *, tree); @@ -132,17 +143,6 @@ class vr_values : public trace_vr_gori_interface tree, tree, tree); void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *); void vrp_visit_switch_stmt (gswitch *, edge *); - bool simplify_truth_ops_using_ranges (gimple_stmt_iterator *, gimple *); - bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *); - bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *); - bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *); - bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *); - bool simplify_cond_using_ranges_1 (gcond *); - bool simplify_cond_using_ranges_when_edge_is_known (gcond *); - bool simplify_switch_using_ranges (gswitch *); - bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *, - gimple *); - bool simplify_internal_call_using_ranges (gimple_stmt_iterator *, gimple *); /* Allocation pools for value_range objects. */ object_allocator<value_range_equiv> vrp_value_range_pool; @@ -162,20 +162,12 @@ class vr_values : public trace_vr_gori_interface number of executable edges we saw the last time we visited the node. */ int *vr_phi_edge_counts; - - /* Vectors of edges that need removing and switch statements that - need updating. It is expected that a pass using the simplification - routines will, at the end of the pass, clean up the edges and - switch statements. The class dtor will try to detect cases - that do not follow that expectation. */ - struct switch_update { - gswitch *stmt; - tree vec; - }; - - vec<edge> to_remove_edges; - vec<switch_update> to_update_switch_stmts; + simplify_using_ranges simplifier; }; extern tree get_output_for_vrp (gimple *); + +// FIXME: Move this to tree-vrp.c. +void simplify_cond_using_ranges_2 (range_store *, gcond *); + #endif /* GCC_VR_VALUES_H */ |