Message ID | 20220627190358.126291-1-aldyh@redhat.com |
---|---|
State | New |
Headers | show |
Series | Remove legacy EVRP code. | expand |
On Mon, Jun 27, 2022 at 9:04 PM Aldy Hernandez <aldyh@redhat.com> wrote: > > With DOM converted to ranger, there are no longer any uses of the EVRP > engine. For that matter, we haven't used the legacy mode in quite a > while, so I think it's safe to remove any associated code. > > There are some methods in vr_values which should now be private, but I > didn't bother changing them, as most of the vr_values class will be > removed when VRP1 is converted to ranger. > > Does anyone have any issues with me pushing this? Fine with me. > gcc/ChangeLog: > > * Makefile.in: Remove gimple-ssa-evrp.o and gimple-ssa-evrp-analyze.o. > * flag-types.h (enum evrp_mode): Remove. > * params.opt: Remove --param=evrp-mode. > * tree-vrp.cc (make_pass_early_vrp): New. > (pass_vrp::execute): Call early VRP instance. > * gimple-ssa-evrp-analyze.cc: Removed. > * gimple-ssa-evrp-analyze.h: Removed. > * gimple-ssa-evrp.cc: Removed. > --- > gcc/Makefile.in | 2 - > gcc/flag-types.h | 9 - > gcc/gimple-ssa-evrp-analyze.cc | 456 -------------------------------- > gcc/gimple-ssa-evrp-analyze.h | 58 ---- > gcc/gimple-ssa-evrp.cc | 395 --------------------------- > gcc/params.opt | 19 -- > gcc/testsuite/g++.dg/pr100774.C | 2 +- > gcc/testsuite/gcc.dg/pr100781.c | 2 +- > gcc/tree-vrp.cc | 34 ++- > 9 files changed, 31 insertions(+), 946 deletions(-) > delete mode 100644 gcc/gimple-ssa-evrp-analyze.cc > delete mode 100644 gcc/gimple-ssa-evrp-analyze.h > delete mode 100644 gcc/gimple-ssa-evrp.cc > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index b6dcc45a58a..86257a8b84f 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -1413,8 +1413,6 @@ OBJS = \ > gimple-range-infer.o \ > gimple-range-trace.o \ > gimple-ssa-backprop.o \ > - gimple-ssa-evrp.o \ > - gimple-ssa-evrp-analyze.o \ > gimple-ssa-isolate-paths.o \ > gimple-ssa-nonnull-compare.o \ > gimple-ssa-split-paths.o \ > diff --git a/gcc/flag-types.h b/gcc/flag-types.h > index 2c8498169e0..a11f99af887 100644 > --- a/gcc/flag-types.h > +++ b/gcc/flag-types.h > @@ -479,15 +479,6 @@ enum threader_debug > THREADER_DEBUG_ALL = 1 > }; > > -/* EVRP mode. */ > -enum evrp_mode > -{ > - EVRP_MODE_RVRP_ONLY, > - EVRP_MODE_EVRP_ONLY, > - EVRP_MODE_EVRP_FIRST, > - EVRP_MODE_RVRP_FIRST > -}; > - > /* VRP modes. */ > enum vrp_mode > { > diff --git a/gcc/gimple-ssa-evrp-analyze.cc b/gcc/gimple-ssa-evrp-analyze.cc > deleted file mode 100644 > index 82142db7976..00000000000 > --- a/gcc/gimple-ssa-evrp-analyze.cc > +++ /dev/null > @@ -1,456 +0,0 @@ > -/* Support routines for Value Range Propagation (VRP). > - Copyright (C) 2005-2022 Free Software Foundation, Inc. > - > -This file is part of GCC. > - > -GCC is free software; you can redistribute it and/or modify > -it under the terms of the GNU General Public License as published by > -the Free Software Foundation; either version 3, or (at your option) > -any later version. > - > -GCC is distributed in the hope that it will be useful, > -but WITHOUT ANY WARRANTY; without even the implied warranty of > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -GNU General Public License for more details. > - > -You should have received a copy of the GNU General Public License > -along with GCC; see the file COPYING3. If not see > -<http://www.gnu.org/licenses/>. */ > - > -#include "config.h" > -#include "system.h" > -#include "coretypes.h" > -#include "backend.h" > -#include "tree.h" > -#include "gimple.h" > -#include "tree-pass.h" > -#include "ssa.h" > -#include "gimple-pretty-print.h" > -#include "cfganal.h" > -#include "gimple-iterator.h" > -#include "gimple-fold.h" > -#include "tree-eh.h" > -#include "tree-cfg.h" > -#include "tree-ssa-loop-manip.h" > -#include "tree-ssa-loop.h" > -#include "cfgloop.h" > -#include "tree-scalar-evolution.h" > -#include "tree-ssa-propagate.h" > -#include "alloc-pool.h" > -#include "domwalk.h" > -#include "tree-cfgcleanup.h" > -#include "vr-values.h" > -#include "gimple-ssa-evrp-analyze.h" > - > -evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges) > - : stack (10), m_update_global_ranges (update_global_ranges) > -{ > - edge e; > - edge_iterator ei; > - basic_block bb; > - FOR_EACH_BB_FN (bb, cfun) > - { > - bb->flags &= ~BB_VISITED; > - FOR_EACH_EDGE (e, ei, bb->preds) > - e->flags |= EDGE_EXECUTABLE; > - } > -} > - > -/* Push an unwinding marker onto the unwinding stack. */ > - > -void > -evrp_range_analyzer::push_marker () > -{ > - stack.safe_push (std::make_pair (NULL_TREE, (value_range_equiv *)NULL)); > -} > - > -/* Analyze ranges as we enter basic block BB. */ > - > -void > -evrp_range_analyzer::enter (basic_block bb) > -{ > - if (!optimize) > - return; > - push_marker (); > - record_ranges_from_incoming_edge (bb); > - record_ranges_from_phis (bb); > - bb->flags |= BB_VISITED; > -} > - > -/* Find new range for NAME such that (OP CODE LIMIT) is true. */ > -value_range_equiv * > -evrp_range_analyzer::try_find_new_range (tree name, > - tree op, tree_code code, tree limit) > -{ > - value_range_equiv vr; > - const value_range_equiv *old_vr = get_value_range (name); > - > - /* Discover VR when condition is true. */ > - extract_range_for_var_from_comparison_expr (name, code, op, limit, &vr); > - /* If we found any usable VR, set the VR to ssa_name and create a > - PUSH old value in the stack with the old VR. */ > - if (!vr.undefined_p () && !vr.varying_p ()) > - { > - if (old_vr->equal_p (vr, /*ignore_equivs=*/true)) > - return NULL; > - value_range_equiv *new_vr = allocate_value_range_equiv (); > - new_vr->move (&vr); > - return new_vr; > - } > - return NULL; > -} > - > -/* For LHS record VR in the SSA info. */ > -void > -evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range_equiv *vr) > -{ > - gcc_assert (m_update_global_ranges); > - > - /* Set the SSA with the value range. */ > - if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) > - { > - if (!vr->varying_p () && vr->constant_p ()) > - set_range_info (lhs, *vr); > - } > - else if (POINTER_TYPE_P (TREE_TYPE (lhs)) > - && range_includes_zero_p (vr) == 0) > - set_ptr_nonnull (lhs); > -} > - > -/* Return true if all uses of NAME are dominated by STMT or feed STMT > - via a chain of single immediate uses. */ > - > -static bool > -all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt) > -{ > - use_operand_p use_p, use2_p; > - imm_use_iterator iter; > - basic_block stmt_bb = gimple_bb (stmt); > - > - FOR_EACH_IMM_USE_FAST (use_p, iter, name) > - { > - gimple *use_stmt = USE_STMT (use_p), *use_stmt2; > - if (use_stmt == stmt > - || is_gimple_debug (use_stmt) > - || (gimple_bb (use_stmt) != stmt_bb > - && dominated_by_p (CDI_DOMINATORS, > - gimple_bb (use_stmt), stmt_bb))) > - continue; > - while (use_stmt != stmt > - && is_gimple_assign (use_stmt) > - && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME > - && single_imm_use (gimple_assign_lhs (use_stmt), > - &use2_p, &use_stmt2)) > - use_stmt = use_stmt2; > - if (use_stmt != stmt) > - return false; > - } > - return true; > -} > - > -void > -evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb) > -{ > - edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); > - if (pred_e) > - { > - gimple *stmt = last_stmt (pred_e->src); > - tree op0 = NULL_TREE; > - > - if (stmt > - && gimple_code (stmt) == GIMPLE_COND > - && (op0 = gimple_cond_lhs (stmt)) > - && TREE_CODE (op0) == SSA_NAME > - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) > - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) > - { > - if (dump_file && (dump_flags & TDF_DETAILS)) > - { > - fprintf (dump_file, "Visiting controlling predicate "); > - print_gimple_stmt (dump_file, stmt, 0); > - } > - /* Entering a new scope. Try to see if we can find a VR > - here. */ > - tree op1 = gimple_cond_rhs (stmt); > - if (TREE_OVERFLOW_P (op1)) > - op1 = drop_tree_overflow (op1); > - tree_code code = gimple_cond_code (stmt); > - > - auto_vec<assert_info, 8> asserts; > - register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); > - if (TREE_CODE (op1) == SSA_NAME) > - register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); > - > - auto_vec<std::pair<tree, value_range_equiv *>, 8> vrs; > - for (unsigned i = 0; i < asserts.length (); ++i) > - { > - value_range_equiv *vr > - = try_find_new_range (asserts[i].name, > - asserts[i].expr, > - asserts[i].comp_code, > - asserts[i].val); > - if (vr) > - vrs.safe_push (std::make_pair (asserts[i].name, vr)); > - } > - > - /* If pred_e is really a fallthru we can record value ranges > - in SSA names as well. */ > - bool is_fallthru = assert_unreachable_fallthru_edge_p (pred_e); > - > - /* Push updated ranges only after finding all of them to avoid > - ordering issues that can lead to worse ranges. */ > - for (unsigned i = 0; i < vrs.length (); ++i) > - { > - /* But make sure we do not weaken ranges like when > - getting first [64, +INF] and then ~[0, 0] from > - conditions like (s & 0x3cc0) == 0). */ > - const value_range_equiv *old_vr > - = get_value_range (vrs[i].first); > - value_range tem (*old_vr); > - tem.legacy_verbose_intersect (vrs[i].second); > - if (tem.equal_p (*old_vr)) > - { > - free_value_range (vrs[i].second); > - continue; > - } > - push_value_range (vrs[i].first, vrs[i].second); > - if (is_fallthru > - && m_update_global_ranges > - && all_uses_feed_or_dominated_by_stmt (vrs[i].first, stmt) > - /* The condition must post-dominate the definition point. */ > - && (SSA_NAME_IS_DEFAULT_DEF (vrs[i].first) > - || (gimple_bb (SSA_NAME_DEF_STMT (vrs[i].first)) > - == pred_e->src))) > - { > - set_ssa_range_info (vrs[i].first, vrs[i].second); > - maybe_set_nonzero_bits (pred_e, vrs[i].first); > - } > - } > - } > - } > -} > - > -void > -evrp_range_analyzer::record_ranges_from_phis (basic_block bb) > -{ > - /* Visit PHI stmts and discover any new VRs possible. */ > - bool has_unvisited_preds = false; > - edge_iterator ei; > - edge e; > - FOR_EACH_EDGE (e, ei, bb->preds) > - if (e->flags & EDGE_EXECUTABLE > - && !(e->src->flags & BB_VISITED)) > - { > - has_unvisited_preds = true; > - break; > - } > - > - for (gphi_iterator gpi = gsi_start_phis (bb); > - !gsi_end_p (gpi); gsi_next (&gpi)) > - { > - gphi *phi = gpi.phi (); > - tree lhs = PHI_RESULT (phi); > - if (virtual_operand_p (lhs)) > - continue; > - > - /* Skips floats and other things we can't represent in a > - range. */ > - if (!value_range_equiv::supports_p (TREE_TYPE (lhs))) > - continue; > - > - value_range_equiv vr_result; > - bool interesting = stmt_interesting_for_vrp (phi); > - if (!has_unvisited_preds && interesting) > - extract_range_from_phi_node (phi, &vr_result); > - else > - { > - vr_result.set_varying (TREE_TYPE (lhs)); > - /* When we have an unvisited executable predecessor we can't > - use PHI arg ranges which may be still UNDEFINED but have > - to use VARYING for them. But we can still resort to > - SCEV for loop header PHIs. */ > - class loop *l; > - if (scev_initialized_p () > - && interesting > - && (l = loop_containing_stmt (phi)) > - && l->header == gimple_bb (phi)) > - adjust_range_with_scev (&vr_result, l, phi, lhs); > - } > - update_value_range (lhs, &vr_result); > - > - /* Set the SSA with the value range. */ > - if (m_update_global_ranges) > - set_ssa_range_info (lhs, &vr_result); > - } > -} > - > -/* Record ranges from STMT into our VR_VALUES class. If TEMPORARY is > - true, then this is a temporary equivalence and should be recorded > - into the unwind table. Othewise record the equivalence into the > - global table. */ > - > -void > -evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary) > -{ > - tree output = NULL_TREE; > - > - if (!optimize) > - return; > - > - if (dyn_cast <gcond *> (stmt)) > - ; > - else if (stmt_interesting_for_vrp (stmt)) > - { > - edge taken_edge; > - value_range_equiv vr; > - extract_range_from_stmt (stmt, &taken_edge, &output, &vr); > - if (output) > - { > - /* Set the SSA with the value range. There are two cases to > - consider. First (the the most common) is we are processing > - STMT in a context where its resulting range globally holds > - and thus it can be reflected into the global ranges and need > - not be unwound as we leave scope. > - > - The second case occurs if we are processing a statement in > - a context where the resulting range must not be reflected > - into the global tables and must be unwound as we leave > - the current context. This happens in jump threading for > - example. */ > - if (!temporary) > - { > - /* Case one. We can just update the underlying range > - information as well as the global information. */ > - update_value_range (output, &vr); > - if (m_update_global_ranges) > - set_ssa_range_info (output, &vr); > - } > - else > - { > - /* We're going to need to unwind this range. We cannot > - use VR as that's a stack object. We have to allocate > - a new range and push the old range onto the stack. We > - also have to be very careful about sharing the underlying > - bitmaps. Ugh. */ > - value_range_equiv *new_vr = allocate_value_range_equiv (); > - new_vr->set (vr.min (), vr.max (), NULL, vr.kind ()); > - vr.equiv_clear (); > - push_value_range (output, new_vr); > - } > - } > - else > - set_defs_to_varying (stmt); > - } > - else > - set_defs_to_varying (stmt); > - > - /* See if we can derive a range for any of STMT's operands. */ > - tree op; > - ssa_op_iter i; > - FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) > - { > - tree value; > - enum tree_code comp_code; > - > - /* If OP is used in such a way that we can infer a value > - range for it, and we don't find a previous assertion for > - it, create a new assertion location node for OP. */ > - if (infer_value_range (stmt, op, &comp_code, &value)) > - { > - /* If we are able to infer a nonzero value range for OP, > - then walk backwards through the use-def chain to see if OP > - was set via a typecast. > - If so, then we can also infer a nonzero value range > - for the operand of the NOP_EXPR. */ > - if (comp_code == NE_EXPR && integer_zerop (value)) > - { > - tree t = op; > - gimple *def_stmt = SSA_NAME_DEF_STMT (t); > - while (is_gimple_assign (def_stmt) > - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) > - && TREE_CODE > - (gimple_assign_rhs1 (def_stmt)) == SSA_NAME > - && POINTER_TYPE_P > - (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))) > - { > - t = gimple_assign_rhs1 (def_stmt); > - def_stmt = SSA_NAME_DEF_STMT (t); > - > - /* Add VR when (T COMP_CODE value) condition is > - true. */ > - value_range_equiv *op_range > - = try_find_new_range (t, t, comp_code, value); > - if (op_range) > - push_value_range (t, op_range); > - } > - } > - /* Add VR when (OP COMP_CODE value) condition is true. */ > - value_range_equiv *op_range = try_find_new_range (op, op, > - comp_code, value); > - if (op_range) > - push_value_range (op, op_range); > - } > - } > -} > - > -/* Unwind recorded ranges to their most recent state. */ > - > -void > -evrp_range_analyzer::pop_to_marker (void) > -{ > - gcc_checking_assert (!stack.is_empty ()); > - while (stack.last ().first != NULL_TREE) > - pop_value_range (); > - stack.pop (); > -} > - > -/* Restore/pop VRs valid only for BB when we leave BB. */ > - > -void > -evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED) > -{ > - if (!optimize) > - return; > - pop_to_marker (); > -} > - > - > -/* Push the Value Range of VAR to the stack and update it with new VR. */ > - > -void > -evrp_range_analyzer::push_value_range (tree var, value_range_equiv *vr) > -{ > - if (dump_file && (dump_flags & TDF_DETAILS)) > - { > - fprintf (dump_file, "pushing new range for "); > - print_generic_expr (dump_file, var); > - fprintf (dump_file, ": "); > - dump_value_range (dump_file, vr); > - fprintf (dump_file, "\n"); > - } > - value_range_equiv *old_vr = swap_vr_value (var, vr); > - stack.safe_push (std::make_pair (var, old_vr)); > -} > - > -/* Pop a Value Range from the vrp_stack. */ > - > -void > -evrp_range_analyzer::pop_value_range () > -{ > - std::pair<tree, value_range_equiv *> e = stack.pop (); > - tree var = e.first; > - value_range_equiv *vr = e.second; > - if (dump_file && (dump_flags & TDF_DETAILS)) > - { > - fprintf (dump_file, "popping range for "); > - print_generic_expr (dump_file, var); > - fprintf (dump_file, ", restoring "); > - dump_value_range (dump_file, vr); > - fprintf (dump_file, "\n"); > - } > - /* We saved off a lattice entry, now give it back and release > - the one we popped. */ > - value_range_equiv *popped_vr = swap_vr_value (var, vr); > - if (popped_vr) > - free_value_range (popped_vr); > -} > diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h > deleted file mode 100644 > index 51c32099dc5..00000000000 > --- a/gcc/gimple-ssa-evrp-analyze.h > +++ /dev/null > @@ -1,58 +0,0 @@ > -/* Support routines for Value Range Propagation (VRP). > - Copyright (C) 2016-2022 Free Software Foundation, Inc. > - > -This file is part of GCC. > - > -GCC is free software; you can redistribute it and/or modify > -it under the terms of the GNU General Public License as published by > -the Free Software Foundation; either version 3, or (at your option) > -any later version. > - > -GCC is distributed in the hope that it will be useful, > -but WITHOUT ANY WARRANTY; without even the implied warranty of > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -GNU General Public License for more details. > - > -You should have received a copy of the GNU General Public License > -along with GCC; see the file COPYING3. If not see > -<http://www.gnu.org/licenses/>. */ > - > -#ifndef GCC_GIMPLE_SSA_EVRP_ANALYZE_H > -#define GCC_GIMPLE_SSA_EVRP_ANALYZE_H > - > -class evrp_range_analyzer : public vr_values > -{ > - public: > - evrp_range_analyzer (bool update_global_ranges); > - ~evrp_range_analyzer (void) > - { > - stack.release (); > - } > - > - void enter (basic_block); > - void push_marker (void); > - void pop_to_marker (void); > - void leave (basic_block); > - void record_ranges_from_stmt (gimple *, bool); > - > - /* Record a new unwindable range. */ > - void push_value_range (tree var, value_range_equiv *vr); > - > - private: > - DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer); > - > - void pop_value_range (); > - value_range_equiv *try_find_new_range (tree, tree op, tree_code code, > - tree limit); > - void record_ranges_from_incoming_edge (basic_block); > - void record_ranges_from_phis (basic_block); > - void set_ssa_range_info (tree, value_range_equiv *); > - > - /* STACK holds the old VR. */ > - auto_vec<std::pair <tree, value_range_equiv *> > stack; > - > - /* True if we are updating global ranges, false otherwise. */ > - bool m_update_global_ranges; > -}; > - > -#endif /* GCC_GIMPLE_SSA_EVRP_ANALYZE_H */ > diff --git a/gcc/gimple-ssa-evrp.cc b/gcc/gimple-ssa-evrp.cc > deleted file mode 100644 > index 20388ed5431..00000000000 > --- a/gcc/gimple-ssa-evrp.cc > +++ /dev/null > @@ -1,395 +0,0 @@ > -/* Support routines for Value Range Propagation (VRP). > - Copyright (C) 2005-2022 Free Software Foundation, Inc. > - > -This file is part of GCC. > - > -GCC is free software; you can redistribute it and/or modify > -it under the terms of the GNU General Public License as published by > -the Free Software Foundation; either version 3, or (at your option) > -any later version. > - > -GCC is distributed in the hope that it will be useful, > -but WITHOUT ANY WARRANTY; without even the implied warranty of > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > -GNU General Public License for more details. > - > -You should have received a copy of the GNU General Public License > -along with GCC; see the file COPYING3. If not see > -<http://www.gnu.org/licenses/>. */ > - > -#include "config.h" > -#include "system.h" > -#include "coretypes.h" > -#include "backend.h" > -#include "tree.h" > -#include "gimple.h" > -#include "tree-pass.h" > -#include "ssa.h" > -#include "gimple-pretty-print.h" > -#include "cfganal.h" > -#include "gimple-iterator.h" > -#include "gimple-fold.h" > -#include "tree-eh.h" > -#include "tree-cfg.h" > -#include "tree-ssa-loop-manip.h" > -#include "tree-ssa-loop.h" > -#include "cfgloop.h" > -#include "tree-scalar-evolution.h" > -#include "tree-ssa-propagate.h" > -#include "alloc-pool.h" > -#include "domwalk.h" > -#include "tree-cfgcleanup.h" > -#include "vr-values.h" > -#include "gimple-ssa-evrp-analyze.h" > -#include "gimple-range.h" > -#include "fold-const.h" > -#include "value-pointer-equiv.h" > -#include "tree-vrp.h" > - > -// This is the classic EVRP folder which uses a dominator walk and pushes > -// ranges into the next block if it is a single predecessor block. > - > -class evrp_folder : public substitute_and_fold_engine > -{ > -public: > - evrp_folder () : > - substitute_and_fold_engine (), > - m_range_analyzer (/*update_global_ranges=*/true), > - simplifier (&m_range_analyzer) > - { } > - > - ~evrp_folder () > - { > - if (dump_file) > - { > - fprintf (dump_file, "\nValue ranges after Early VRP:\n\n"); > - m_range_analyzer.dump (dump_file); > - fprintf (dump_file, "\n"); > - } > - } > - > - tree value_of_expr (tree name, gimple *stmt) override > - { > - return m_range_analyzer.value_of_expr (name, stmt); > - } > - > - void pre_fold_bb (basic_block bb) override > - { > - if (dump_file && (dump_flags & TDF_DETAILS)) > - fprintf (dump_file, "evrp visiting BB%d\n", bb->index); > - m_range_analyzer.enter (bb); > - } > - > - void pre_fold_stmt (gimple *stmt) override > - { > - if (dump_file && (dump_flags & TDF_DETAILS)) > - { > - fprintf (dump_file, "evrp visiting stmt "); > - print_gimple_stmt (dump_file, stmt, 0); > - } > - m_range_analyzer.record_ranges_from_stmt (stmt, false); > - } > - > - bool fold_stmt (gimple_stmt_iterator *gsi) override > - { > - return simplifier.simplify (gsi); > - } > - > - void post_fold_bb (basic_block bb) override > - { > - m_range_analyzer.leave (bb); > - } > - > - void post_new_stmt (gimple *stmt) override > - { > - m_range_analyzer.set_defs_to_varying (stmt); > - } > - > -protected: > - DISABLE_COPY_AND_ASSIGN (evrp_folder); > - evrp_range_analyzer m_range_analyzer; > - simplify_using_ranges simplifier; > -}; > - > -// In a hybrid folder, start with an EVRP folder, and add the required > -// fold_stmt bits to either try the ranger first or second. > -// > -// The 3 value_* routines will always query both EVRP and the ranger for > -// a result, and ensure they return the same value. If either returns a value > -// when the other doesn't, it is flagged in the listing, and the discoverd > -// value is returned. > -// > -// The simplifier is unable to process 2 different sources, thus we try to > -// use one engine, and if it fails to simplify, try using the other engine. > -// It is reported when the first attempt fails and the second succeeds. > - > -class hybrid_folder : public evrp_folder > -{ > -public: > - hybrid_folder (bool evrp_first) > - { > - m_ranger = enable_ranger (cfun); > - > - if (evrp_first) > - { > - first = &m_range_analyzer; > - first_exec_flag = 0; > - second = m_ranger; > - second_exec_flag = m_ranger->non_executable_edge_flag; > - } > - else > - { > - first = m_ranger; > - first_exec_flag = m_ranger->non_executable_edge_flag; > - second = &m_range_analyzer; > - second_exec_flag = 0; > - } > - m_pta = new pointer_equiv_analyzer (m_ranger); > - } > - > - ~hybrid_folder () > - { > - if (dump_file && (dump_flags & TDF_DETAILS)) > - m_ranger->dump (dump_file); > - > - m_ranger->export_global_ranges (); > - disable_ranger (cfun); > - delete m_pta; > - } > - > - bool fold_stmt (gimple_stmt_iterator *gsi) override > - { > - simplifier.set_range_query (first, first_exec_flag); > - if (simplifier.simplify (gsi)) > - return true; > - > - simplifier.set_range_query (second, second_exec_flag); > - if (simplifier.simplify (gsi)) > - { > - if (dump_file) > - fprintf (dump_file, "EVRP:hybrid: Second query simplifed stmt\n"); > - return true; > - } > - return false; > - } > - > - void pre_fold_stmt (gimple *stmt) override > - { > - evrp_folder::pre_fold_stmt (stmt); > - m_pta->visit_stmt (stmt); > - } > - > - void pre_fold_bb (basic_block bb) override > - { > - evrp_folder::pre_fold_bb (bb); > - m_pta->enter (bb); > - } > - > - void post_fold_bb (basic_block bb) override > - { > - evrp_folder::post_fold_bb (bb); > - m_pta->leave (bb); > - } > - > - tree value_of_expr (tree name, gimple *) override; > - tree value_on_edge (edge, tree name) override; > - tree value_of_stmt (gimple *, tree name) override; > - > -private: > - DISABLE_COPY_AND_ASSIGN (hybrid_folder); > - gimple_ranger *m_ranger; > - range_query *first; > - int first_exec_flag; > - range_query *second; > - int second_exec_flag; > - pointer_equiv_analyzer *m_pta; > - tree choose_value (tree evrp_val, tree ranger_val); > -}; > - > - > -tree > -hybrid_folder::value_of_expr (tree op, gimple *stmt) > -{ > - tree evrp_ret = evrp_folder::value_of_expr (op, stmt); > - tree ranger_ret; > - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > - ranger_ret = NULL; > - else > - { > - ranger_ret = m_ranger->value_of_expr (op, stmt); > - if (!ranger_ret && supported_pointer_equiv_p (op)) > - ranger_ret = m_pta->get_equiv (op); > - } > - return choose_value (evrp_ret, ranger_ret); > -} > - > -tree > -hybrid_folder::value_on_edge (edge e, tree op) > -{ > - // Call evrp::value_of_expr directly. Otherwise another dual call is made > - // via hybrid_folder::value_of_expr, but without an edge. > - tree evrp_ret = evrp_folder::value_of_expr (op, NULL); > - tree ranger_ret; > - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > - ranger_ret = NULL; > - else > - { > - ranger_ret = m_ranger->value_on_edge (e, op); > - if (!ranger_ret && supported_pointer_equiv_p (op)) > - ranger_ret = m_pta->get_equiv (op); > - } > - return choose_value (evrp_ret, ranger_ret); > -} > - > -tree > -hybrid_folder::value_of_stmt (gimple *stmt, tree op) > -{ > - // Call evrp::value_of_expr directly. Otherwise another dual call is made > - // via hybrid_folder::value_of_expr, but without a stmt. > - tree evrp_ret; > - if (op) > - evrp_ret = evrp_folder::value_of_expr (op, NULL); > - else > - evrp_ret = NULL_TREE; > - > - tree ranger_ret; > - if (op && TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > - ranger_ret = NULL; > - else > - ranger_ret = m_ranger->value_of_stmt (stmt, op); > - return choose_value (evrp_ret, ranger_ret); > -} > - > -// Given trees returned by EVRP and Ranger, choose/report the value to use > -// by the folder. > - > -tree > -hybrid_folder::choose_value (tree evrp_val, tree ranger_val) > -{ > - // If both found the same value, just return it. > - if (evrp_val && ranger_val && !compare_values (evrp_val, ranger_val)) > - return evrp_val; > - > - // If neither returned a value, return NULL_TREE. > - if (!ranger_val && !evrp_val) > - return NULL_TREE; > - > - // Otherwise there is a discrepancy to flag. > - if (dump_file) > - { > - if (evrp_val && ranger_val) > - fprintf (dump_file, "EVRP:hybrid: Disagreement\n"); > - if (evrp_val) > - { > - fprintf (dump_file, "EVRP:hybrid: EVRP found singleton "); > - print_generic_expr (dump_file, evrp_val); > - fprintf (dump_file, "\n"); > - } > - if (ranger_val) > - { > - fprintf (dump_file, "EVRP:hybrid: RVRP found singleton "); > - print_generic_expr (dump_file, ranger_val); > - fprintf (dump_file, "\n"); > - } > - } > - > - // If one value was found, return it. > - if (!evrp_val) > - return ranger_val; > - if (!ranger_val) > - return evrp_val; > - > - // If values are different, return the first calculated value. > - if (param_evrp_mode == EVRP_MODE_RVRP_FIRST) > - return ranger_val; > - return evrp_val; > -} > - > -/* Main entry point for the early vrp pass which is a simplified non-iterative > - version of vrp where basic blocks are visited in dominance order. Value > - ranges discovered in early vrp will also be used by ipa-vrp. */ > - > -static unsigned int > -execute_early_vrp () > -{ > - if (param_evrp_mode == EVRP_MODE_RVRP_ONLY) > - return execute_ranger_vrp (cfun, false); > - > - /* Ideally this setup code would move into the ctor for the folder > - However, this setup can change the number of blocks which > - invalidates the internal arrays that are set up by the dominator > - walker in substitute_and_fold_engine. */ > - loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); > - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); > - scev_initialize (); > - calculate_dominance_info (CDI_DOMINATORS); > - > - // Only the last 2 bits matter for choosing the folder. > - switch (param_evrp_mode) > - { > - case EVRP_MODE_EVRP_ONLY: > - { > - evrp_folder folder; > - folder.substitute_and_fold (); > - break; > - } > - case EVRP_MODE_EVRP_FIRST: > - { > - hybrid_folder folder (true); > - folder.substitute_and_fold (); > - break; > - } > - case EVRP_MODE_RVRP_FIRST: > - { > - hybrid_folder folder (false); > - folder.substitute_and_fold (); > - break; > - } > - default: > - gcc_unreachable (); > - } > - > - scev_finalize (); > - loop_optimizer_finalize (); > - return 0; > -} > - > -namespace { > - > -const pass_data pass_data_early_vrp = > -{ > - GIMPLE_PASS, /* type */ > - "evrp", /* name */ > - OPTGROUP_NONE, /* optinfo_flags */ > - TV_TREE_EARLY_VRP, /* tv_id */ > - PROP_ssa, /* properties_required */ > - 0, /* properties_provided */ > - 0, /* properties_destroyed */ > - 0, /* todo_flags_start */ > - ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), > -}; > - > -class pass_early_vrp : public gimple_opt_pass > -{ > -public: > - pass_early_vrp (gcc::context *ctxt) > - : gimple_opt_pass (pass_data_early_vrp, ctxt) > - {} > - > - /* opt_pass methods: */ > - opt_pass * clone () { return new pass_early_vrp (m_ctxt); } > - virtual bool gate (function *) > - { > - return flag_tree_vrp != 0; > - } > - virtual unsigned int execute (function *) > - { return execute_early_vrp (); } > - > -}; // class pass_vrp > -} // anon namespace > - > -gimple_opt_pass * > -make_pass_early_vrp (gcc::context *ctxt) > -{ > - return new pass_early_vrp (ctxt); > -} > diff --git a/gcc/params.opt b/gcc/params.opt > index bcf1423671a..2f9c9cf27dd 100644 > --- a/gcc/params.opt > +++ b/gcc/params.opt > @@ -134,25 +134,6 @@ Maximum number of basic blocks before EVRP uses a sparse cache. > Common Joined UInteger Var(param_evrp_switch_limit) Init(50) Optimization Param > Maximum number of outgoing edges in a switch before EVRP will not process it. > > --param=evrp-mode= > -Common Joined Var(param_evrp_mode) Enum(evrp_mode) Init(EVRP_MODE_RVRP_ONLY) Param Optimization > ---param=evrp-mode=[legacy|ranger|legacy-first|ranger-first] Specifies the mode Early VRP should operate in. > - > -Enum > -Name(evrp_mode) Type(enum evrp_mode) UnknownError(unknown evrp mode %qs) > - > -EnumValue > -Enum(evrp_mode) String(legacy) Value(EVRP_MODE_EVRP_ONLY) > - > -EnumValue > -Enum(evrp_mode) String(ranger) Value(EVRP_MODE_RVRP_ONLY) > - > -EnumValue > -Enum(evrp_mode) String(legacy-first) Value(EVRP_MODE_EVRP_FIRST) > - > -EnumValue > -Enum(evrp_mode) String(ranger-first) Value(EVRP_MODE_RVRP_FIRST) > - > -param=fsm-scale-path-blocks= > Common Joined UInteger Var(param_fsm_scale_path_blocks) Init(3) IntegerRange(1, 10) Param Optimization > Scale factor to apply to the number of blocks in a threading path when comparing to the number of (scaled) statements. > diff --git a/gcc/testsuite/g++.dg/pr100774.C b/gcc/testsuite/g++.dg/pr100774.C > index 345fcfa0d01..63320ef73fc 100644 > --- a/gcc/testsuite/g++.dg/pr100774.C > +++ b/gcc/testsuite/g++.dg/pr100774.C > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O2 -fno-tree-forwprop --param=evrp-mode=ranger -fcompare-debug " } */ > +/* { dg-options "-O2 -fno-tree-forwprop -fcompare-debug " } */ > > extern void __attribute__((noreturn)) error(); > > diff --git a/gcc/testsuite/gcc.dg/pr100781.c b/gcc/testsuite/gcc.dg/pr100781.c > index c0e008a3ba5..96f0a7a6012 100644 > --- a/gcc/testsuite/gcc.dg/pr100781.c > +++ b/gcc/testsuite/gcc.dg/pr100781.c > @@ -1,5 +1,5 @@ > /* { dg-do compile } */ > -/* { dg-options "-O2 --param=evrp-mode=ranger -fcompare-debug " } */ > +/* { dg-options "-O2 -fcompare-debug " } */ > > struct a { > int b; > diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc > index 30022dac108..7b4e2917340 100644 > --- a/gcc/tree-vrp.cc > +++ b/gcc/tree-vrp.cc > @@ -4388,17 +4388,30 @@ const pass_data pass_data_vrp = > ( TODO_cleanup_cfg | TODO_update_ssa ), /* todo_flags_finish */ > }; > > +const pass_data pass_data_early_vrp = > +{ > + GIMPLE_PASS, /* type */ > + "evrp", /* name */ > + OPTGROUP_NONE, /* optinfo_flags */ > + TV_TREE_EARLY_VRP, /* tv_id */ > + PROP_ssa, /* properties_required */ > + 0, /* properties_provided */ > + 0, /* properties_destroyed */ > + 0, /* todo_flags_start */ > + ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), > +}; > + > static int vrp_pass_num = 0; > class pass_vrp : public gimple_opt_pass > { > public: > - pass_vrp (gcc::context *ctxt) > - : gimple_opt_pass (pass_data_vrp, ctxt), warn_array_bounds_p (false), > - my_pass (++vrp_pass_num) > + pass_vrp (gcc::context *ctxt, const pass_data &data_) > + : gimple_opt_pass (data_, ctxt), data (data_), warn_array_bounds_p (false), > + my_pass (vrp_pass_num++) > {} > > /* opt_pass methods: */ > - opt_pass * clone () { return new pass_vrp (m_ctxt); } > + opt_pass * clone () { return new pass_vrp (m_ctxt, data); } > void set_pass_param (unsigned int n, bool param) > { > gcc_assert (n == 0); > @@ -4407,6 +4420,10 @@ public: > virtual bool gate (function *) { return flag_tree_vrp != 0; } > virtual unsigned int execute (function *fun) > { > + // Early VRP pass. > + if (my_pass == 0) > + return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false); > + > if ((my_pass == 1 && param_vrp1_mode == VRP_MODE_RANGER) > || (my_pass == 2 && param_vrp2_mode == VRP_MODE_RANGER)) > return execute_ranger_vrp (fun, warn_array_bounds_p); > @@ -4414,6 +4431,7 @@ public: > } > > private: > + const pass_data &data; > bool warn_array_bounds_p; > int my_pass; > }; // class pass_vrp > @@ -4423,5 +4441,11 @@ public: > gimple_opt_pass * > make_pass_vrp (gcc::context *ctxt) > { > - return new pass_vrp (ctxt); > + return new pass_vrp (ctxt, pass_data_vrp); > +} > + > +gimple_opt_pass * > +make_pass_early_vrp (gcc::context *ctxt) > +{ > + return new pass_vrp (ctxt, pass_data_early_vrp); > } > -- > 2.36.1 >
Since Andrew, Jeff, and Richi have all agreed, I have pushed the patch. Thanks. Aldy On Tue, Jun 28, 2022 at 9:37 AM Richard Biener <richard.guenther@gmail.com> wrote: > > On Mon, Jun 27, 2022 at 9:04 PM Aldy Hernandez <aldyh@redhat.com> wrote: > > > > With DOM converted to ranger, there are no longer any uses of the EVRP > > engine. For that matter, we haven't used the legacy mode in quite a > > while, so I think it's safe to remove any associated code. > > > > There are some methods in vr_values which should now be private, but I > > didn't bother changing them, as most of the vr_values class will be > > removed when VRP1 is converted to ranger. > > > > Does anyone have any issues with me pushing this? > > Fine with me. > > > gcc/ChangeLog: > > > > * Makefile.in: Remove gimple-ssa-evrp.o and gimple-ssa-evrp-analyze.o. > > * flag-types.h (enum evrp_mode): Remove. > > * params.opt: Remove --param=evrp-mode. > > * tree-vrp.cc (make_pass_early_vrp): New. > > (pass_vrp::execute): Call early VRP instance. > > * gimple-ssa-evrp-analyze.cc: Removed. > > * gimple-ssa-evrp-analyze.h: Removed. > > * gimple-ssa-evrp.cc: Removed. > > --- > > gcc/Makefile.in | 2 - > > gcc/flag-types.h | 9 - > > gcc/gimple-ssa-evrp-analyze.cc | 456 -------------------------------- > > gcc/gimple-ssa-evrp-analyze.h | 58 ---- > > gcc/gimple-ssa-evrp.cc | 395 --------------------------- > > gcc/params.opt | 19 -- > > gcc/testsuite/g++.dg/pr100774.C | 2 +- > > gcc/testsuite/gcc.dg/pr100781.c | 2 +- > > gcc/tree-vrp.cc | 34 ++- > > 9 files changed, 31 insertions(+), 946 deletions(-) > > delete mode 100644 gcc/gimple-ssa-evrp-analyze.cc > > delete mode 100644 gcc/gimple-ssa-evrp-analyze.h > > delete mode 100644 gcc/gimple-ssa-evrp.cc > > > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > > index b6dcc45a58a..86257a8b84f 100644 > > --- a/gcc/Makefile.in > > +++ b/gcc/Makefile.in > > @@ -1413,8 +1413,6 @@ OBJS = \ > > gimple-range-infer.o \ > > gimple-range-trace.o \ > > gimple-ssa-backprop.o \ > > - gimple-ssa-evrp.o \ > > - gimple-ssa-evrp-analyze.o \ > > gimple-ssa-isolate-paths.o \ > > gimple-ssa-nonnull-compare.o \ > > gimple-ssa-split-paths.o \ > > diff --git a/gcc/flag-types.h b/gcc/flag-types.h > > index 2c8498169e0..a11f99af887 100644 > > --- a/gcc/flag-types.h > > +++ b/gcc/flag-types.h > > @@ -479,15 +479,6 @@ enum threader_debug > > THREADER_DEBUG_ALL = 1 > > }; > > > > -/* EVRP mode. */ > > -enum evrp_mode > > -{ > > - EVRP_MODE_RVRP_ONLY, > > - EVRP_MODE_EVRP_ONLY, > > - EVRP_MODE_EVRP_FIRST, > > - EVRP_MODE_RVRP_FIRST > > -}; > > - > > /* VRP modes. */ > > enum vrp_mode > > { > > diff --git a/gcc/gimple-ssa-evrp-analyze.cc b/gcc/gimple-ssa-evrp-analyze.cc > > deleted file mode 100644 > > index 82142db7976..00000000000 > > --- a/gcc/gimple-ssa-evrp-analyze.cc > > +++ /dev/null > > @@ -1,456 +0,0 @@ > > -/* Support routines for Value Range Propagation (VRP). > > - Copyright (C) 2005-2022 Free Software Foundation, Inc. > > - > > -This file is part of GCC. > > - > > -GCC is free software; you can redistribute it and/or modify > > -it under the terms of the GNU General Public License as published by > > -the Free Software Foundation; either version 3, or (at your option) > > -any later version. > > - > > -GCC is distributed in the hope that it will be useful, > > -but WITHOUT ANY WARRANTY; without even the implied warranty of > > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > -GNU General Public License for more details. > > - > > -You should have received a copy of the GNU General Public License > > -along with GCC; see the file COPYING3. If not see > > -<http://www.gnu.org/licenses/>. */ > > - > > -#include "config.h" > > -#include "system.h" > > -#include "coretypes.h" > > -#include "backend.h" > > -#include "tree.h" > > -#include "gimple.h" > > -#include "tree-pass.h" > > -#include "ssa.h" > > -#include "gimple-pretty-print.h" > > -#include "cfganal.h" > > -#include "gimple-iterator.h" > > -#include "gimple-fold.h" > > -#include "tree-eh.h" > > -#include "tree-cfg.h" > > -#include "tree-ssa-loop-manip.h" > > -#include "tree-ssa-loop.h" > > -#include "cfgloop.h" > > -#include "tree-scalar-evolution.h" > > -#include "tree-ssa-propagate.h" > > -#include "alloc-pool.h" > > -#include "domwalk.h" > > -#include "tree-cfgcleanup.h" > > -#include "vr-values.h" > > -#include "gimple-ssa-evrp-analyze.h" > > - > > -evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges) > > - : stack (10), m_update_global_ranges (update_global_ranges) > > -{ > > - edge e; > > - edge_iterator ei; > > - basic_block bb; > > - FOR_EACH_BB_FN (bb, cfun) > > - { > > - bb->flags &= ~BB_VISITED; > > - FOR_EACH_EDGE (e, ei, bb->preds) > > - e->flags |= EDGE_EXECUTABLE; > > - } > > -} > > - > > -/* Push an unwinding marker onto the unwinding stack. */ > > - > > -void > > -evrp_range_analyzer::push_marker () > > -{ > > - stack.safe_push (std::make_pair (NULL_TREE, (value_range_equiv *)NULL)); > > -} > > - > > -/* Analyze ranges as we enter basic block BB. */ > > - > > -void > > -evrp_range_analyzer::enter (basic_block bb) > > -{ > > - if (!optimize) > > - return; > > - push_marker (); > > - record_ranges_from_incoming_edge (bb); > > - record_ranges_from_phis (bb); > > - bb->flags |= BB_VISITED; > > -} > > - > > -/* Find new range for NAME such that (OP CODE LIMIT) is true. */ > > -value_range_equiv * > > -evrp_range_analyzer::try_find_new_range (tree name, > > - tree op, tree_code code, tree limit) > > -{ > > - value_range_equiv vr; > > - const value_range_equiv *old_vr = get_value_range (name); > > - > > - /* Discover VR when condition is true. */ > > - extract_range_for_var_from_comparison_expr (name, code, op, limit, &vr); > > - /* If we found any usable VR, set the VR to ssa_name and create a > > - PUSH old value in the stack with the old VR. */ > > - if (!vr.undefined_p () && !vr.varying_p ()) > > - { > > - if (old_vr->equal_p (vr, /*ignore_equivs=*/true)) > > - return NULL; > > - value_range_equiv *new_vr = allocate_value_range_equiv (); > > - new_vr->move (&vr); > > - return new_vr; > > - } > > - return NULL; > > -} > > - > > -/* For LHS record VR in the SSA info. */ > > -void > > -evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range_equiv *vr) > > -{ > > - gcc_assert (m_update_global_ranges); > > - > > - /* Set the SSA with the value range. */ > > - if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) > > - { > > - if (!vr->varying_p () && vr->constant_p ()) > > - set_range_info (lhs, *vr); > > - } > > - else if (POINTER_TYPE_P (TREE_TYPE (lhs)) > > - && range_includes_zero_p (vr) == 0) > > - set_ptr_nonnull (lhs); > > -} > > - > > -/* Return true if all uses of NAME are dominated by STMT or feed STMT > > - via a chain of single immediate uses. */ > > - > > -static bool > > -all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt) > > -{ > > - use_operand_p use_p, use2_p; > > - imm_use_iterator iter; > > - basic_block stmt_bb = gimple_bb (stmt); > > - > > - FOR_EACH_IMM_USE_FAST (use_p, iter, name) > > - { > > - gimple *use_stmt = USE_STMT (use_p), *use_stmt2; > > - if (use_stmt == stmt > > - || is_gimple_debug (use_stmt) > > - || (gimple_bb (use_stmt) != stmt_bb > > - && dominated_by_p (CDI_DOMINATORS, > > - gimple_bb (use_stmt), stmt_bb))) > > - continue; > > - while (use_stmt != stmt > > - && is_gimple_assign (use_stmt) > > - && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME > > - && single_imm_use (gimple_assign_lhs (use_stmt), > > - &use2_p, &use_stmt2)) > > - use_stmt = use_stmt2; > > - if (use_stmt != stmt) > > - return false; > > - } > > - return true; > > -} > > - > > -void > > -evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb) > > -{ > > - edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); > > - if (pred_e) > > - { > > - gimple *stmt = last_stmt (pred_e->src); > > - tree op0 = NULL_TREE; > > - > > - if (stmt > > - && gimple_code (stmt) == GIMPLE_COND > > - && (op0 = gimple_cond_lhs (stmt)) > > - && TREE_CODE (op0) == SSA_NAME > > - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) > > - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) > > - { > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - { > > - fprintf (dump_file, "Visiting controlling predicate "); > > - print_gimple_stmt (dump_file, stmt, 0); > > - } > > - /* Entering a new scope. Try to see if we can find a VR > > - here. */ > > - tree op1 = gimple_cond_rhs (stmt); > > - if (TREE_OVERFLOW_P (op1)) > > - op1 = drop_tree_overflow (op1); > > - tree_code code = gimple_cond_code (stmt); > > - > > - auto_vec<assert_info, 8> asserts; > > - register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); > > - if (TREE_CODE (op1) == SSA_NAME) > > - register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); > > - > > - auto_vec<std::pair<tree, value_range_equiv *>, 8> vrs; > > - for (unsigned i = 0; i < asserts.length (); ++i) > > - { > > - value_range_equiv *vr > > - = try_find_new_range (asserts[i].name, > > - asserts[i].expr, > > - asserts[i].comp_code, > > - asserts[i].val); > > - if (vr) > > - vrs.safe_push (std::make_pair (asserts[i].name, vr)); > > - } > > - > > - /* If pred_e is really a fallthru we can record value ranges > > - in SSA names as well. */ > > - bool is_fallthru = assert_unreachable_fallthru_edge_p (pred_e); > > - > > - /* Push updated ranges only after finding all of them to avoid > > - ordering issues that can lead to worse ranges. */ > > - for (unsigned i = 0; i < vrs.length (); ++i) > > - { > > - /* But make sure we do not weaken ranges like when > > - getting first [64, +INF] and then ~[0, 0] from > > - conditions like (s & 0x3cc0) == 0). */ > > - const value_range_equiv *old_vr > > - = get_value_range (vrs[i].first); > > - value_range tem (*old_vr); > > - tem.legacy_verbose_intersect (vrs[i].second); > > - if (tem.equal_p (*old_vr)) > > - { > > - free_value_range (vrs[i].second); > > - continue; > > - } > > - push_value_range (vrs[i].first, vrs[i].second); > > - if (is_fallthru > > - && m_update_global_ranges > > - && all_uses_feed_or_dominated_by_stmt (vrs[i].first, stmt) > > - /* The condition must post-dominate the definition point. */ > > - && (SSA_NAME_IS_DEFAULT_DEF (vrs[i].first) > > - || (gimple_bb (SSA_NAME_DEF_STMT (vrs[i].first)) > > - == pred_e->src))) > > - { > > - set_ssa_range_info (vrs[i].first, vrs[i].second); > > - maybe_set_nonzero_bits (pred_e, vrs[i].first); > > - } > > - } > > - } > > - } > > -} > > - > > -void > > -evrp_range_analyzer::record_ranges_from_phis (basic_block bb) > > -{ > > - /* Visit PHI stmts and discover any new VRs possible. */ > > - bool has_unvisited_preds = false; > > - edge_iterator ei; > > - edge e; > > - FOR_EACH_EDGE (e, ei, bb->preds) > > - if (e->flags & EDGE_EXECUTABLE > > - && !(e->src->flags & BB_VISITED)) > > - { > > - has_unvisited_preds = true; > > - break; > > - } > > - > > - for (gphi_iterator gpi = gsi_start_phis (bb); > > - !gsi_end_p (gpi); gsi_next (&gpi)) > > - { > > - gphi *phi = gpi.phi (); > > - tree lhs = PHI_RESULT (phi); > > - if (virtual_operand_p (lhs)) > > - continue; > > - > > - /* Skips floats and other things we can't represent in a > > - range. */ > > - if (!value_range_equiv::supports_p (TREE_TYPE (lhs))) > > - continue; > > - > > - value_range_equiv vr_result; > > - bool interesting = stmt_interesting_for_vrp (phi); > > - if (!has_unvisited_preds && interesting) > > - extract_range_from_phi_node (phi, &vr_result); > > - else > > - { > > - vr_result.set_varying (TREE_TYPE (lhs)); > > - /* When we have an unvisited executable predecessor we can't > > - use PHI arg ranges which may be still UNDEFINED but have > > - to use VARYING for them. But we can still resort to > > - SCEV for loop header PHIs. */ > > - class loop *l; > > - if (scev_initialized_p () > > - && interesting > > - && (l = loop_containing_stmt (phi)) > > - && l->header == gimple_bb (phi)) > > - adjust_range_with_scev (&vr_result, l, phi, lhs); > > - } > > - update_value_range (lhs, &vr_result); > > - > > - /* Set the SSA with the value range. */ > > - if (m_update_global_ranges) > > - set_ssa_range_info (lhs, &vr_result); > > - } > > -} > > - > > -/* Record ranges from STMT into our VR_VALUES class. If TEMPORARY is > > - true, then this is a temporary equivalence and should be recorded > > - into the unwind table. Othewise record the equivalence into the > > - global table. */ > > - > > -void > > -evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary) > > -{ > > - tree output = NULL_TREE; > > - > > - if (!optimize) > > - return; > > - > > - if (dyn_cast <gcond *> (stmt)) > > - ; > > - else if (stmt_interesting_for_vrp (stmt)) > > - { > > - edge taken_edge; > > - value_range_equiv vr; > > - extract_range_from_stmt (stmt, &taken_edge, &output, &vr); > > - if (output) > > - { > > - /* Set the SSA with the value range. There are two cases to > > - consider. First (the the most common) is we are processing > > - STMT in a context where its resulting range globally holds > > - and thus it can be reflected into the global ranges and need > > - not be unwound as we leave scope. > > - > > - The second case occurs if we are processing a statement in > > - a context where the resulting range must not be reflected > > - into the global tables and must be unwound as we leave > > - the current context. This happens in jump threading for > > - example. */ > > - if (!temporary) > > - { > > - /* Case one. We can just update the underlying range > > - information as well as the global information. */ > > - update_value_range (output, &vr); > > - if (m_update_global_ranges) > > - set_ssa_range_info (output, &vr); > > - } > > - else > > - { > > - /* We're going to need to unwind this range. We cannot > > - use VR as that's a stack object. We have to allocate > > - a new range and push the old range onto the stack. We > > - also have to be very careful about sharing the underlying > > - bitmaps. Ugh. */ > > - value_range_equiv *new_vr = allocate_value_range_equiv (); > > - new_vr->set (vr.min (), vr.max (), NULL, vr.kind ()); > > - vr.equiv_clear (); > > - push_value_range (output, new_vr); > > - } > > - } > > - else > > - set_defs_to_varying (stmt); > > - } > > - else > > - set_defs_to_varying (stmt); > > - > > - /* See if we can derive a range for any of STMT's operands. */ > > - tree op; > > - ssa_op_iter i; > > - FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) > > - { > > - tree value; > > - enum tree_code comp_code; > > - > > - /* If OP is used in such a way that we can infer a value > > - range for it, and we don't find a previous assertion for > > - it, create a new assertion location node for OP. */ > > - if (infer_value_range (stmt, op, &comp_code, &value)) > > - { > > - /* If we are able to infer a nonzero value range for OP, > > - then walk backwards through the use-def chain to see if OP > > - was set via a typecast. > > - If so, then we can also infer a nonzero value range > > - for the operand of the NOP_EXPR. */ > > - if (comp_code == NE_EXPR && integer_zerop (value)) > > - { > > - tree t = op; > > - gimple *def_stmt = SSA_NAME_DEF_STMT (t); > > - while (is_gimple_assign (def_stmt) > > - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) > > - && TREE_CODE > > - (gimple_assign_rhs1 (def_stmt)) == SSA_NAME > > - && POINTER_TYPE_P > > - (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))) > > - { > > - t = gimple_assign_rhs1 (def_stmt); > > - def_stmt = SSA_NAME_DEF_STMT (t); > > - > > - /* Add VR when (T COMP_CODE value) condition is > > - true. */ > > - value_range_equiv *op_range > > - = try_find_new_range (t, t, comp_code, value); > > - if (op_range) > > - push_value_range (t, op_range); > > - } > > - } > > - /* Add VR when (OP COMP_CODE value) condition is true. */ > > - value_range_equiv *op_range = try_find_new_range (op, op, > > - comp_code, value); > > - if (op_range) > > - push_value_range (op, op_range); > > - } > > - } > > -} > > - > > -/* Unwind recorded ranges to their most recent state. */ > > - > > -void > > -evrp_range_analyzer::pop_to_marker (void) > > -{ > > - gcc_checking_assert (!stack.is_empty ()); > > - while (stack.last ().first != NULL_TREE) > > - pop_value_range (); > > - stack.pop (); > > -} > > - > > -/* Restore/pop VRs valid only for BB when we leave BB. */ > > - > > -void > > -evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED) > > -{ > > - if (!optimize) > > - return; > > - pop_to_marker (); > > -} > > - > > - > > -/* Push the Value Range of VAR to the stack and update it with new VR. */ > > - > > -void > > -evrp_range_analyzer::push_value_range (tree var, value_range_equiv *vr) > > -{ > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - { > > - fprintf (dump_file, "pushing new range for "); > > - print_generic_expr (dump_file, var); > > - fprintf (dump_file, ": "); > > - dump_value_range (dump_file, vr); > > - fprintf (dump_file, "\n"); > > - } > > - value_range_equiv *old_vr = swap_vr_value (var, vr); > > - stack.safe_push (std::make_pair (var, old_vr)); > > -} > > - > > -/* Pop a Value Range from the vrp_stack. */ > > - > > -void > > -evrp_range_analyzer::pop_value_range () > > -{ > > - std::pair<tree, value_range_equiv *> e = stack.pop (); > > - tree var = e.first; > > - value_range_equiv *vr = e.second; > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - { > > - fprintf (dump_file, "popping range for "); > > - print_generic_expr (dump_file, var); > > - fprintf (dump_file, ", restoring "); > > - dump_value_range (dump_file, vr); > > - fprintf (dump_file, "\n"); > > - } > > - /* We saved off a lattice entry, now give it back and release > > - the one we popped. */ > > - value_range_equiv *popped_vr = swap_vr_value (var, vr); > > - if (popped_vr) > > - free_value_range (popped_vr); > > -} > > diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h > > deleted file mode 100644 > > index 51c32099dc5..00000000000 > > --- a/gcc/gimple-ssa-evrp-analyze.h > > +++ /dev/null > > @@ -1,58 +0,0 @@ > > -/* Support routines for Value Range Propagation (VRP). > > - Copyright (C) 2016-2022 Free Software Foundation, Inc. > > - > > -This file is part of GCC. > > - > > -GCC is free software; you can redistribute it and/or modify > > -it under the terms of the GNU General Public License as published by > > -the Free Software Foundation; either version 3, or (at your option) > > -any later version. > > - > > -GCC is distributed in the hope that it will be useful, > > -but WITHOUT ANY WARRANTY; without even the implied warranty of > > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > -GNU General Public License for more details. > > - > > -You should have received a copy of the GNU General Public License > > -along with GCC; see the file COPYING3. If not see > > -<http://www.gnu.org/licenses/>. */ > > - > > -#ifndef GCC_GIMPLE_SSA_EVRP_ANALYZE_H > > -#define GCC_GIMPLE_SSA_EVRP_ANALYZE_H > > - > > -class evrp_range_analyzer : public vr_values > > -{ > > - public: > > - evrp_range_analyzer (bool update_global_ranges); > > - ~evrp_range_analyzer (void) > > - { > > - stack.release (); > > - } > > - > > - void enter (basic_block); > > - void push_marker (void); > > - void pop_to_marker (void); > > - void leave (basic_block); > > - void record_ranges_from_stmt (gimple *, bool); > > - > > - /* Record a new unwindable range. */ > > - void push_value_range (tree var, value_range_equiv *vr); > > - > > - private: > > - DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer); > > - > > - void pop_value_range (); > > - value_range_equiv *try_find_new_range (tree, tree op, tree_code code, > > - tree limit); > > - void record_ranges_from_incoming_edge (basic_block); > > - void record_ranges_from_phis (basic_block); > > - void set_ssa_range_info (tree, value_range_equiv *); > > - > > - /* STACK holds the old VR. */ > > - auto_vec<std::pair <tree, value_range_equiv *> > stack; > > - > > - /* True if we are updating global ranges, false otherwise. */ > > - bool m_update_global_ranges; > > -}; > > - > > -#endif /* GCC_GIMPLE_SSA_EVRP_ANALYZE_H */ > > diff --git a/gcc/gimple-ssa-evrp.cc b/gcc/gimple-ssa-evrp.cc > > deleted file mode 100644 > > index 20388ed5431..00000000000 > > --- a/gcc/gimple-ssa-evrp.cc > > +++ /dev/null > > @@ -1,395 +0,0 @@ > > -/* Support routines for Value Range Propagation (VRP). > > - Copyright (C) 2005-2022 Free Software Foundation, Inc. > > - > > -This file is part of GCC. > > - > > -GCC is free software; you can redistribute it and/or modify > > -it under the terms of the GNU General Public License as published by > > -the Free Software Foundation; either version 3, or (at your option) > > -any later version. > > - > > -GCC is distributed in the hope that it will be useful, > > -but WITHOUT ANY WARRANTY; without even the implied warranty of > > -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > > -GNU General Public License for more details. > > - > > -You should have received a copy of the GNU General Public License > > -along with GCC; see the file COPYING3. If not see > > -<http://www.gnu.org/licenses/>. */ > > - > > -#include "config.h" > > -#include "system.h" > > -#include "coretypes.h" > > -#include "backend.h" > > -#include "tree.h" > > -#include "gimple.h" > > -#include "tree-pass.h" > > -#include "ssa.h" > > -#include "gimple-pretty-print.h" > > -#include "cfganal.h" > > -#include "gimple-iterator.h" > > -#include "gimple-fold.h" > > -#include "tree-eh.h" > > -#include "tree-cfg.h" > > -#include "tree-ssa-loop-manip.h" > > -#include "tree-ssa-loop.h" > > -#include "cfgloop.h" > > -#include "tree-scalar-evolution.h" > > -#include "tree-ssa-propagate.h" > > -#include "alloc-pool.h" > > -#include "domwalk.h" > > -#include "tree-cfgcleanup.h" > > -#include "vr-values.h" > > -#include "gimple-ssa-evrp-analyze.h" > > -#include "gimple-range.h" > > -#include "fold-const.h" > > -#include "value-pointer-equiv.h" > > -#include "tree-vrp.h" > > - > > -// This is the classic EVRP folder which uses a dominator walk and pushes > > -// ranges into the next block if it is a single predecessor block. > > - > > -class evrp_folder : public substitute_and_fold_engine > > -{ > > -public: > > - evrp_folder () : > > - substitute_and_fold_engine (), > > - m_range_analyzer (/*update_global_ranges=*/true), > > - simplifier (&m_range_analyzer) > > - { } > > - > > - ~evrp_folder () > > - { > > - if (dump_file) > > - { > > - fprintf (dump_file, "\nValue ranges after Early VRP:\n\n"); > > - m_range_analyzer.dump (dump_file); > > - fprintf (dump_file, "\n"); > > - } > > - } > > - > > - tree value_of_expr (tree name, gimple *stmt) override > > - { > > - return m_range_analyzer.value_of_expr (name, stmt); > > - } > > - > > - void pre_fold_bb (basic_block bb) override > > - { > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - fprintf (dump_file, "evrp visiting BB%d\n", bb->index); > > - m_range_analyzer.enter (bb); > > - } > > - > > - void pre_fold_stmt (gimple *stmt) override > > - { > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - { > > - fprintf (dump_file, "evrp visiting stmt "); > > - print_gimple_stmt (dump_file, stmt, 0); > > - } > > - m_range_analyzer.record_ranges_from_stmt (stmt, false); > > - } > > - > > - bool fold_stmt (gimple_stmt_iterator *gsi) override > > - { > > - return simplifier.simplify (gsi); > > - } > > - > > - void post_fold_bb (basic_block bb) override > > - { > > - m_range_analyzer.leave (bb); > > - } > > - > > - void post_new_stmt (gimple *stmt) override > > - { > > - m_range_analyzer.set_defs_to_varying (stmt); > > - } > > - > > -protected: > > - DISABLE_COPY_AND_ASSIGN (evrp_folder); > > - evrp_range_analyzer m_range_analyzer; > > - simplify_using_ranges simplifier; > > -}; > > - > > -// In a hybrid folder, start with an EVRP folder, and add the required > > -// fold_stmt bits to either try the ranger first or second. > > -// > > -// The 3 value_* routines will always query both EVRP and the ranger for > > -// a result, and ensure they return the same value. If either returns a value > > -// when the other doesn't, it is flagged in the listing, and the discoverd > > -// value is returned. > > -// > > -// The simplifier is unable to process 2 different sources, thus we try to > > -// use one engine, and if it fails to simplify, try using the other engine. > > -// It is reported when the first attempt fails and the second succeeds. > > - > > -class hybrid_folder : public evrp_folder > > -{ > > -public: > > - hybrid_folder (bool evrp_first) > > - { > > - m_ranger = enable_ranger (cfun); > > - > > - if (evrp_first) > > - { > > - first = &m_range_analyzer; > > - first_exec_flag = 0; > > - second = m_ranger; > > - second_exec_flag = m_ranger->non_executable_edge_flag; > > - } > > - else > > - { > > - first = m_ranger; > > - first_exec_flag = m_ranger->non_executable_edge_flag; > > - second = &m_range_analyzer; > > - second_exec_flag = 0; > > - } > > - m_pta = new pointer_equiv_analyzer (m_ranger); > > - } > > - > > - ~hybrid_folder () > > - { > > - if (dump_file && (dump_flags & TDF_DETAILS)) > > - m_ranger->dump (dump_file); > > - > > - m_ranger->export_global_ranges (); > > - disable_ranger (cfun); > > - delete m_pta; > > - } > > - > > - bool fold_stmt (gimple_stmt_iterator *gsi) override > > - { > > - simplifier.set_range_query (first, first_exec_flag); > > - if (simplifier.simplify (gsi)) > > - return true; > > - > > - simplifier.set_range_query (second, second_exec_flag); > > - if (simplifier.simplify (gsi)) > > - { > > - if (dump_file) > > - fprintf (dump_file, "EVRP:hybrid: Second query simplifed stmt\n"); > > - return true; > > - } > > - return false; > > - } > > - > > - void pre_fold_stmt (gimple *stmt) override > > - { > > - evrp_folder::pre_fold_stmt (stmt); > > - m_pta->visit_stmt (stmt); > > - } > > - > > - void pre_fold_bb (basic_block bb) override > > - { > > - evrp_folder::pre_fold_bb (bb); > > - m_pta->enter (bb); > > - } > > - > > - void post_fold_bb (basic_block bb) override > > - { > > - evrp_folder::post_fold_bb (bb); > > - m_pta->leave (bb); > > - } > > - > > - tree value_of_expr (tree name, gimple *) override; > > - tree value_on_edge (edge, tree name) override; > > - tree value_of_stmt (gimple *, tree name) override; > > - > > -private: > > - DISABLE_COPY_AND_ASSIGN (hybrid_folder); > > - gimple_ranger *m_ranger; > > - range_query *first; > > - int first_exec_flag; > > - range_query *second; > > - int second_exec_flag; > > - pointer_equiv_analyzer *m_pta; > > - tree choose_value (tree evrp_val, tree ranger_val); > > -}; > > - > > - > > -tree > > -hybrid_folder::value_of_expr (tree op, gimple *stmt) > > -{ > > - tree evrp_ret = evrp_folder::value_of_expr (op, stmt); > > - tree ranger_ret; > > - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > > - ranger_ret = NULL; > > - else > > - { > > - ranger_ret = m_ranger->value_of_expr (op, stmt); > > - if (!ranger_ret && supported_pointer_equiv_p (op)) > > - ranger_ret = m_pta->get_equiv (op); > > - } > > - return choose_value (evrp_ret, ranger_ret); > > -} > > - > > -tree > > -hybrid_folder::value_on_edge (edge e, tree op) > > -{ > > - // Call evrp::value_of_expr directly. Otherwise another dual call is made > > - // via hybrid_folder::value_of_expr, but without an edge. > > - tree evrp_ret = evrp_folder::value_of_expr (op, NULL); > > - tree ranger_ret; > > - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > > - ranger_ret = NULL; > > - else > > - { > > - ranger_ret = m_ranger->value_on_edge (e, op); > > - if (!ranger_ret && supported_pointer_equiv_p (op)) > > - ranger_ret = m_pta->get_equiv (op); > > - } > > - return choose_value (evrp_ret, ranger_ret); > > -} > > - > > -tree > > -hybrid_folder::value_of_stmt (gimple *stmt, tree op) > > -{ > > - // Call evrp::value_of_expr directly. Otherwise another dual call is made > > - // via hybrid_folder::value_of_expr, but without a stmt. > > - tree evrp_ret; > > - if (op) > > - evrp_ret = evrp_folder::value_of_expr (op, NULL); > > - else > > - evrp_ret = NULL_TREE; > > - > > - tree ranger_ret; > > - if (op && TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) > > - ranger_ret = NULL; > > - else > > - ranger_ret = m_ranger->value_of_stmt (stmt, op); > > - return choose_value (evrp_ret, ranger_ret); > > -} > > - > > -// Given trees returned by EVRP and Ranger, choose/report the value to use > > -// by the folder. > > - > > -tree > > -hybrid_folder::choose_value (tree evrp_val, tree ranger_val) > > -{ > > - // If both found the same value, just return it. > > - if (evrp_val && ranger_val && !compare_values (evrp_val, ranger_val)) > > - return evrp_val; > > - > > - // If neither returned a value, return NULL_TREE. > > - if (!ranger_val && !evrp_val) > > - return NULL_TREE; > > - > > - // Otherwise there is a discrepancy to flag. > > - if (dump_file) > > - { > > - if (evrp_val && ranger_val) > > - fprintf (dump_file, "EVRP:hybrid: Disagreement\n"); > > - if (evrp_val) > > - { > > - fprintf (dump_file, "EVRP:hybrid: EVRP found singleton "); > > - print_generic_expr (dump_file, evrp_val); > > - fprintf (dump_file, "\n"); > > - } > > - if (ranger_val) > > - { > > - fprintf (dump_file, "EVRP:hybrid: RVRP found singleton "); > > - print_generic_expr (dump_file, ranger_val); > > - fprintf (dump_file, "\n"); > > - } > > - } > > - > > - // If one value was found, return it. > > - if (!evrp_val) > > - return ranger_val; > > - if (!ranger_val) > > - return evrp_val; > > - > > - // If values are different, return the first calculated value. > > - if (param_evrp_mode == EVRP_MODE_RVRP_FIRST) > > - return ranger_val; > > - return evrp_val; > > -} > > - > > -/* Main entry point for the early vrp pass which is a simplified non-iterative > > - version of vrp where basic blocks are visited in dominance order. Value > > - ranges discovered in early vrp will also be used by ipa-vrp. */ > > - > > -static unsigned int > > -execute_early_vrp () > > -{ > > - if (param_evrp_mode == EVRP_MODE_RVRP_ONLY) > > - return execute_ranger_vrp (cfun, false); > > - > > - /* Ideally this setup code would move into the ctor for the folder > > - However, this setup can change the number of blocks which > > - invalidates the internal arrays that are set up by the dominator > > - walker in substitute_and_fold_engine. */ > > - loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); > > - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); > > - scev_initialize (); > > - calculate_dominance_info (CDI_DOMINATORS); > > - > > - // Only the last 2 bits matter for choosing the folder. > > - switch (param_evrp_mode) > > - { > > - case EVRP_MODE_EVRP_ONLY: > > - { > > - evrp_folder folder; > > - folder.substitute_and_fold (); > > - break; > > - } > > - case EVRP_MODE_EVRP_FIRST: > > - { > > - hybrid_folder folder (true); > > - folder.substitute_and_fold (); > > - break; > > - } > > - case EVRP_MODE_RVRP_FIRST: > > - { > > - hybrid_folder folder (false); > > - folder.substitute_and_fold (); > > - break; > > - } > > - default: > > - gcc_unreachable (); > > - } > > - > > - scev_finalize (); > > - loop_optimizer_finalize (); > > - return 0; > > -} > > - > > -namespace { > > - > > -const pass_data pass_data_early_vrp = > > -{ > > - GIMPLE_PASS, /* type */ > > - "evrp", /* name */ > > - OPTGROUP_NONE, /* optinfo_flags */ > > - TV_TREE_EARLY_VRP, /* tv_id */ > > - PROP_ssa, /* properties_required */ > > - 0, /* properties_provided */ > > - 0, /* properties_destroyed */ > > - 0, /* todo_flags_start */ > > - ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), > > -}; > > - > > -class pass_early_vrp : public gimple_opt_pass > > -{ > > -public: > > - pass_early_vrp (gcc::context *ctxt) > > - : gimple_opt_pass (pass_data_early_vrp, ctxt) > > - {} > > - > > - /* opt_pass methods: */ > > - opt_pass * clone () { return new pass_early_vrp (m_ctxt); } > > - virtual bool gate (function *) > > - { > > - return flag_tree_vrp != 0; > > - } > > - virtual unsigned int execute (function *) > > - { return execute_early_vrp (); } > > - > > -}; // class pass_vrp > > -} // anon namespace > > - > > -gimple_opt_pass * > > -make_pass_early_vrp (gcc::context *ctxt) > > -{ > > - return new pass_early_vrp (ctxt); > > -} > > diff --git a/gcc/params.opt b/gcc/params.opt > > index bcf1423671a..2f9c9cf27dd 100644 > > --- a/gcc/params.opt > > +++ b/gcc/params.opt > > @@ -134,25 +134,6 @@ Maximum number of basic blocks before EVRP uses a sparse cache. > > Common Joined UInteger Var(param_evrp_switch_limit) Init(50) Optimization Param > > Maximum number of outgoing edges in a switch before EVRP will not process it. > > > > --param=evrp-mode= > > -Common Joined Var(param_evrp_mode) Enum(evrp_mode) Init(EVRP_MODE_RVRP_ONLY) Param Optimization > > ---param=evrp-mode=[legacy|ranger|legacy-first|ranger-first] Specifies the mode Early VRP should operate in. > > - > > -Enum > > -Name(evrp_mode) Type(enum evrp_mode) UnknownError(unknown evrp mode %qs) > > - > > -EnumValue > > -Enum(evrp_mode) String(legacy) Value(EVRP_MODE_EVRP_ONLY) > > - > > -EnumValue > > -Enum(evrp_mode) String(ranger) Value(EVRP_MODE_RVRP_ONLY) > > - > > -EnumValue > > -Enum(evrp_mode) String(legacy-first) Value(EVRP_MODE_EVRP_FIRST) > > - > > -EnumValue > > -Enum(evrp_mode) String(ranger-first) Value(EVRP_MODE_RVRP_FIRST) > > - > > -param=fsm-scale-path-blocks= > > Common Joined UInteger Var(param_fsm_scale_path_blocks) Init(3) IntegerRange(1, 10) Param Optimization > > Scale factor to apply to the number of blocks in a threading path when comparing to the number of (scaled) statements. > > diff --git a/gcc/testsuite/g++.dg/pr100774.C b/gcc/testsuite/g++.dg/pr100774.C > > index 345fcfa0d01..63320ef73fc 100644 > > --- a/gcc/testsuite/g++.dg/pr100774.C > > +++ b/gcc/testsuite/g++.dg/pr100774.C > > @@ -1,5 +1,5 @@ > > /* { dg-do compile } */ > > -/* { dg-options "-O2 -fno-tree-forwprop --param=evrp-mode=ranger -fcompare-debug " } */ > > +/* { dg-options "-O2 -fno-tree-forwprop -fcompare-debug " } */ > > > > extern void __attribute__((noreturn)) error(); > > > > diff --git a/gcc/testsuite/gcc.dg/pr100781.c b/gcc/testsuite/gcc.dg/pr100781.c > > index c0e008a3ba5..96f0a7a6012 100644 > > --- a/gcc/testsuite/gcc.dg/pr100781.c > > +++ b/gcc/testsuite/gcc.dg/pr100781.c > > @@ -1,5 +1,5 @@ > > /* { dg-do compile } */ > > -/* { dg-options "-O2 --param=evrp-mode=ranger -fcompare-debug " } */ > > +/* { dg-options "-O2 -fcompare-debug " } */ > > > > struct a { > > int b; > > diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc > > index 30022dac108..7b4e2917340 100644 > > --- a/gcc/tree-vrp.cc > > +++ b/gcc/tree-vrp.cc > > @@ -4388,17 +4388,30 @@ const pass_data pass_data_vrp = > > ( TODO_cleanup_cfg | TODO_update_ssa ), /* todo_flags_finish */ > > }; > > > > +const pass_data pass_data_early_vrp = > > +{ > > + GIMPLE_PASS, /* type */ > > + "evrp", /* name */ > > + OPTGROUP_NONE, /* optinfo_flags */ > > + TV_TREE_EARLY_VRP, /* tv_id */ > > + PROP_ssa, /* properties_required */ > > + 0, /* properties_provided */ > > + 0, /* properties_destroyed */ > > + 0, /* todo_flags_start */ > > + ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), > > +}; > > + > > static int vrp_pass_num = 0; > > class pass_vrp : public gimple_opt_pass > > { > > public: > > - pass_vrp (gcc::context *ctxt) > > - : gimple_opt_pass (pass_data_vrp, ctxt), warn_array_bounds_p (false), > > - my_pass (++vrp_pass_num) > > + pass_vrp (gcc::context *ctxt, const pass_data &data_) > > + : gimple_opt_pass (data_, ctxt), data (data_), warn_array_bounds_p (false), > > + my_pass (vrp_pass_num++) > > {} > > > > /* opt_pass methods: */ > > - opt_pass * clone () { return new pass_vrp (m_ctxt); } > > + opt_pass * clone () { return new pass_vrp (m_ctxt, data); } > > void set_pass_param (unsigned int n, bool param) > > { > > gcc_assert (n == 0); > > @@ -4407,6 +4420,10 @@ public: > > virtual bool gate (function *) { return flag_tree_vrp != 0; } > > virtual unsigned int execute (function *fun) > > { > > + // Early VRP pass. > > + if (my_pass == 0) > > + return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false); > > + > > if ((my_pass == 1 && param_vrp1_mode == VRP_MODE_RANGER) > > || (my_pass == 2 && param_vrp2_mode == VRP_MODE_RANGER)) > > return execute_ranger_vrp (fun, warn_array_bounds_p); > > @@ -4414,6 +4431,7 @@ public: > > } > > > > private: > > + const pass_data &data; > > bool warn_array_bounds_p; > > int my_pass; > > }; // class pass_vrp > > @@ -4423,5 +4441,11 @@ public: > > gimple_opt_pass * > > make_pass_vrp (gcc::context *ctxt) > > { > > - return new pass_vrp (ctxt); > > + return new pass_vrp (ctxt, pass_data_vrp); > > +} > > + > > +gimple_opt_pass * > > +make_pass_early_vrp (gcc::context *ctxt) > > +{ > > + return new pass_vrp (ctxt, pass_data_early_vrp); > > } > > -- > > 2.36.1 > > >
On 6/28/2022 1:37 AM, Richard Biener via Gcc-patches wrote: > On Mon, Jun 27, 2022 at 9:04 PM Aldy Hernandez <aldyh@redhat.com> wrote: >> With DOM converted to ranger, there are no longer any uses of the EVRP >> engine. For that matter, we haven't used the legacy mode in quite a >> while, so I think it's safe to remove any associated code. >> >> There are some methods in vr_values which should now be private, but I >> didn't bother changing them, as most of the vr_values class will be >> removed when VRP1 is converted to ranger. >> >> Does anyone have any issues with me pushing this? > Fine with me. Likewise. jeff
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b6dcc45a58a..86257a8b84f 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1413,8 +1413,6 @@ OBJS = \ gimple-range-infer.o \ gimple-range-trace.o \ gimple-ssa-backprop.o \ - gimple-ssa-evrp.o \ - gimple-ssa-evrp-analyze.o \ gimple-ssa-isolate-paths.o \ gimple-ssa-nonnull-compare.o \ gimple-ssa-split-paths.o \ diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 2c8498169e0..a11f99af887 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -479,15 +479,6 @@ enum threader_debug THREADER_DEBUG_ALL = 1 }; -/* EVRP mode. */ -enum evrp_mode -{ - EVRP_MODE_RVRP_ONLY, - EVRP_MODE_EVRP_ONLY, - EVRP_MODE_EVRP_FIRST, - EVRP_MODE_RVRP_FIRST -}; - /* VRP modes. */ enum vrp_mode { diff --git a/gcc/gimple-ssa-evrp-analyze.cc b/gcc/gimple-ssa-evrp-analyze.cc deleted file mode 100644 index 82142db7976..00000000000 --- a/gcc/gimple-ssa-evrp-analyze.cc +++ /dev/null @@ -1,456 +0,0 @@ -/* Support routines for Value Range Propagation (VRP). - Copyright (C) 2005-2022 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "tree.h" -#include "gimple.h" -#include "tree-pass.h" -#include "ssa.h" -#include "gimple-pretty-print.h" -#include "cfganal.h" -#include "gimple-iterator.h" -#include "gimple-fold.h" -#include "tree-eh.h" -#include "tree-cfg.h" -#include "tree-ssa-loop-manip.h" -#include "tree-ssa-loop.h" -#include "cfgloop.h" -#include "tree-scalar-evolution.h" -#include "tree-ssa-propagate.h" -#include "alloc-pool.h" -#include "domwalk.h" -#include "tree-cfgcleanup.h" -#include "vr-values.h" -#include "gimple-ssa-evrp-analyze.h" - -evrp_range_analyzer::evrp_range_analyzer (bool update_global_ranges) - : stack (10), m_update_global_ranges (update_global_ranges) -{ - edge e; - edge_iterator ei; - basic_block bb; - FOR_EACH_BB_FN (bb, cfun) - { - bb->flags &= ~BB_VISITED; - FOR_EACH_EDGE (e, ei, bb->preds) - e->flags |= EDGE_EXECUTABLE; - } -} - -/* Push an unwinding marker onto the unwinding stack. */ - -void -evrp_range_analyzer::push_marker () -{ - stack.safe_push (std::make_pair (NULL_TREE, (value_range_equiv *)NULL)); -} - -/* Analyze ranges as we enter basic block BB. */ - -void -evrp_range_analyzer::enter (basic_block bb) -{ - if (!optimize) - return; - push_marker (); - record_ranges_from_incoming_edge (bb); - record_ranges_from_phis (bb); - bb->flags |= BB_VISITED; -} - -/* Find new range for NAME such that (OP CODE LIMIT) is true. */ -value_range_equiv * -evrp_range_analyzer::try_find_new_range (tree name, - tree op, tree_code code, tree limit) -{ - value_range_equiv vr; - const value_range_equiv *old_vr = get_value_range (name); - - /* Discover VR when condition is true. */ - extract_range_for_var_from_comparison_expr (name, code, op, limit, &vr); - /* If we found any usable VR, set the VR to ssa_name and create a - PUSH old value in the stack with the old VR. */ - if (!vr.undefined_p () && !vr.varying_p ()) - { - if (old_vr->equal_p (vr, /*ignore_equivs=*/true)) - return NULL; - value_range_equiv *new_vr = allocate_value_range_equiv (); - new_vr->move (&vr); - return new_vr; - } - return NULL; -} - -/* For LHS record VR in the SSA info. */ -void -evrp_range_analyzer::set_ssa_range_info (tree lhs, value_range_equiv *vr) -{ - gcc_assert (m_update_global_ranges); - - /* Set the SSA with the value range. */ - if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))) - { - if (!vr->varying_p () && vr->constant_p ()) - set_range_info (lhs, *vr); - } - else if (POINTER_TYPE_P (TREE_TYPE (lhs)) - && range_includes_zero_p (vr) == 0) - set_ptr_nonnull (lhs); -} - -/* Return true if all uses of NAME are dominated by STMT or feed STMT - via a chain of single immediate uses. */ - -static bool -all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt) -{ - use_operand_p use_p, use2_p; - imm_use_iterator iter; - basic_block stmt_bb = gimple_bb (stmt); - - FOR_EACH_IMM_USE_FAST (use_p, iter, name) - { - gimple *use_stmt = USE_STMT (use_p), *use_stmt2; - if (use_stmt == stmt - || is_gimple_debug (use_stmt) - || (gimple_bb (use_stmt) != stmt_bb - && dominated_by_p (CDI_DOMINATORS, - gimple_bb (use_stmt), stmt_bb))) - continue; - while (use_stmt != stmt - && is_gimple_assign (use_stmt) - && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME - && single_imm_use (gimple_assign_lhs (use_stmt), - &use2_p, &use_stmt2)) - use_stmt = use_stmt2; - if (use_stmt != stmt) - return false; - } - return true; -} - -void -evrp_range_analyzer::record_ranges_from_incoming_edge (basic_block bb) -{ - edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false); - if (pred_e) - { - gimple *stmt = last_stmt (pred_e->src); - tree op0 = NULL_TREE; - - if (stmt - && gimple_code (stmt) == GIMPLE_COND - && (op0 = gimple_cond_lhs (stmt)) - && TREE_CODE (op0) == SSA_NAME - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Visiting controlling predicate "); - print_gimple_stmt (dump_file, stmt, 0); - } - /* Entering a new scope. Try to see if we can find a VR - here. */ - tree op1 = gimple_cond_rhs (stmt); - if (TREE_OVERFLOW_P (op1)) - op1 = drop_tree_overflow (op1); - tree_code code = gimple_cond_code (stmt); - - auto_vec<assert_info, 8> asserts; - register_edge_assert_for (op0, pred_e, code, op0, op1, asserts); - if (TREE_CODE (op1) == SSA_NAME) - register_edge_assert_for (op1, pred_e, code, op0, op1, asserts); - - auto_vec<std::pair<tree, value_range_equiv *>, 8> vrs; - for (unsigned i = 0; i < asserts.length (); ++i) - { - value_range_equiv *vr - = try_find_new_range (asserts[i].name, - asserts[i].expr, - asserts[i].comp_code, - asserts[i].val); - if (vr) - vrs.safe_push (std::make_pair (asserts[i].name, vr)); - } - - /* If pred_e is really a fallthru we can record value ranges - in SSA names as well. */ - bool is_fallthru = assert_unreachable_fallthru_edge_p (pred_e); - - /* Push updated ranges only after finding all of them to avoid - ordering issues that can lead to worse ranges. */ - for (unsigned i = 0; i < vrs.length (); ++i) - { - /* But make sure we do not weaken ranges like when - getting first [64, +INF] and then ~[0, 0] from - conditions like (s & 0x3cc0) == 0). */ - const value_range_equiv *old_vr - = get_value_range (vrs[i].first); - value_range tem (*old_vr); - tem.legacy_verbose_intersect (vrs[i].second); - if (tem.equal_p (*old_vr)) - { - free_value_range (vrs[i].second); - continue; - } - push_value_range (vrs[i].first, vrs[i].second); - if (is_fallthru - && m_update_global_ranges - && all_uses_feed_or_dominated_by_stmt (vrs[i].first, stmt) - /* The condition must post-dominate the definition point. */ - && (SSA_NAME_IS_DEFAULT_DEF (vrs[i].first) - || (gimple_bb (SSA_NAME_DEF_STMT (vrs[i].first)) - == pred_e->src))) - { - set_ssa_range_info (vrs[i].first, vrs[i].second); - maybe_set_nonzero_bits (pred_e, vrs[i].first); - } - } - } - } -} - -void -evrp_range_analyzer::record_ranges_from_phis (basic_block bb) -{ - /* Visit PHI stmts and discover any new VRs possible. */ - bool has_unvisited_preds = false; - edge_iterator ei; - edge e; - FOR_EACH_EDGE (e, ei, bb->preds) - if (e->flags & EDGE_EXECUTABLE - && !(e->src->flags & BB_VISITED)) - { - has_unvisited_preds = true; - break; - } - - for (gphi_iterator gpi = gsi_start_phis (bb); - !gsi_end_p (gpi); gsi_next (&gpi)) - { - gphi *phi = gpi.phi (); - tree lhs = PHI_RESULT (phi); - if (virtual_operand_p (lhs)) - continue; - - /* Skips floats and other things we can't represent in a - range. */ - if (!value_range_equiv::supports_p (TREE_TYPE (lhs))) - continue; - - value_range_equiv vr_result; - bool interesting = stmt_interesting_for_vrp (phi); - if (!has_unvisited_preds && interesting) - extract_range_from_phi_node (phi, &vr_result); - else - { - vr_result.set_varying (TREE_TYPE (lhs)); - /* When we have an unvisited executable predecessor we can't - use PHI arg ranges which may be still UNDEFINED but have - to use VARYING for them. But we can still resort to - SCEV for loop header PHIs. */ - class loop *l; - if (scev_initialized_p () - && interesting - && (l = loop_containing_stmt (phi)) - && l->header == gimple_bb (phi)) - adjust_range_with_scev (&vr_result, l, phi, lhs); - } - update_value_range (lhs, &vr_result); - - /* Set the SSA with the value range. */ - if (m_update_global_ranges) - set_ssa_range_info (lhs, &vr_result); - } -} - -/* Record ranges from STMT into our VR_VALUES class. If TEMPORARY is - true, then this is a temporary equivalence and should be recorded - into the unwind table. Othewise record the equivalence into the - global table. */ - -void -evrp_range_analyzer::record_ranges_from_stmt (gimple *stmt, bool temporary) -{ - tree output = NULL_TREE; - - if (!optimize) - return; - - if (dyn_cast <gcond *> (stmt)) - ; - else if (stmt_interesting_for_vrp (stmt)) - { - edge taken_edge; - value_range_equiv vr; - extract_range_from_stmt (stmt, &taken_edge, &output, &vr); - if (output) - { - /* Set the SSA with the value range. There are two cases to - consider. First (the the most common) is we are processing - STMT in a context where its resulting range globally holds - and thus it can be reflected into the global ranges and need - not be unwound as we leave scope. - - The second case occurs if we are processing a statement in - a context where the resulting range must not be reflected - into the global tables and must be unwound as we leave - the current context. This happens in jump threading for - example. */ - if (!temporary) - { - /* Case one. We can just update the underlying range - information as well as the global information. */ - update_value_range (output, &vr); - if (m_update_global_ranges) - set_ssa_range_info (output, &vr); - } - else - { - /* We're going to need to unwind this range. We cannot - use VR as that's a stack object. We have to allocate - a new range and push the old range onto the stack. We - also have to be very careful about sharing the underlying - bitmaps. Ugh. */ - value_range_equiv *new_vr = allocate_value_range_equiv (); - new_vr->set (vr.min (), vr.max (), NULL, vr.kind ()); - vr.equiv_clear (); - push_value_range (output, new_vr); - } - } - else - set_defs_to_varying (stmt); - } - else - set_defs_to_varying (stmt); - - /* See if we can derive a range for any of STMT's operands. */ - tree op; - ssa_op_iter i; - FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE) - { - tree value; - enum tree_code comp_code; - - /* If OP is used in such a way that we can infer a value - range for it, and we don't find a previous assertion for - it, create a new assertion location node for OP. */ - if (infer_value_range (stmt, op, &comp_code, &value)) - { - /* If we are able to infer a nonzero value range for OP, - then walk backwards through the use-def chain to see if OP - was set via a typecast. - If so, then we can also infer a nonzero value range - for the operand of the NOP_EXPR. */ - if (comp_code == NE_EXPR && integer_zerop (value)) - { - tree t = op; - gimple *def_stmt = SSA_NAME_DEF_STMT (t); - while (is_gimple_assign (def_stmt) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) - && TREE_CODE - (gimple_assign_rhs1 (def_stmt)) == SSA_NAME - && POINTER_TYPE_P - (TREE_TYPE (gimple_assign_rhs1 (def_stmt)))) - { - t = gimple_assign_rhs1 (def_stmt); - def_stmt = SSA_NAME_DEF_STMT (t); - - /* Add VR when (T COMP_CODE value) condition is - true. */ - value_range_equiv *op_range - = try_find_new_range (t, t, comp_code, value); - if (op_range) - push_value_range (t, op_range); - } - } - /* Add VR when (OP COMP_CODE value) condition is true. */ - value_range_equiv *op_range = try_find_new_range (op, op, - comp_code, value); - if (op_range) - push_value_range (op, op_range); - } - } -} - -/* Unwind recorded ranges to their most recent state. */ - -void -evrp_range_analyzer::pop_to_marker (void) -{ - gcc_checking_assert (!stack.is_empty ()); - while (stack.last ().first != NULL_TREE) - pop_value_range (); - stack.pop (); -} - -/* Restore/pop VRs valid only for BB when we leave BB. */ - -void -evrp_range_analyzer::leave (basic_block bb ATTRIBUTE_UNUSED) -{ - if (!optimize) - return; - pop_to_marker (); -} - - -/* Push the Value Range of VAR to the stack and update it with new VR. */ - -void -evrp_range_analyzer::push_value_range (tree var, value_range_equiv *vr) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "pushing new range for "); - print_generic_expr (dump_file, var); - fprintf (dump_file, ": "); - dump_value_range (dump_file, vr); - fprintf (dump_file, "\n"); - } - value_range_equiv *old_vr = swap_vr_value (var, vr); - stack.safe_push (std::make_pair (var, old_vr)); -} - -/* Pop a Value Range from the vrp_stack. */ - -void -evrp_range_analyzer::pop_value_range () -{ - std::pair<tree, value_range_equiv *> e = stack.pop (); - tree var = e.first; - value_range_equiv *vr = e.second; - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "popping range for "); - print_generic_expr (dump_file, var); - fprintf (dump_file, ", restoring "); - dump_value_range (dump_file, vr); - fprintf (dump_file, "\n"); - } - /* We saved off a lattice entry, now give it back and release - the one we popped. */ - value_range_equiv *popped_vr = swap_vr_value (var, vr); - if (popped_vr) - free_value_range (popped_vr); -} diff --git a/gcc/gimple-ssa-evrp-analyze.h b/gcc/gimple-ssa-evrp-analyze.h deleted file mode 100644 index 51c32099dc5..00000000000 --- a/gcc/gimple-ssa-evrp-analyze.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Support routines for Value Range Propagation (VRP). - Copyright (C) 2016-2022 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#ifndef GCC_GIMPLE_SSA_EVRP_ANALYZE_H -#define GCC_GIMPLE_SSA_EVRP_ANALYZE_H - -class evrp_range_analyzer : public vr_values -{ - public: - evrp_range_analyzer (bool update_global_ranges); - ~evrp_range_analyzer (void) - { - stack.release (); - } - - void enter (basic_block); - void push_marker (void); - void pop_to_marker (void); - void leave (basic_block); - void record_ranges_from_stmt (gimple *, bool); - - /* Record a new unwindable range. */ - void push_value_range (tree var, value_range_equiv *vr); - - private: - DISABLE_COPY_AND_ASSIGN (evrp_range_analyzer); - - void pop_value_range (); - value_range_equiv *try_find_new_range (tree, tree op, tree_code code, - tree limit); - void record_ranges_from_incoming_edge (basic_block); - void record_ranges_from_phis (basic_block); - void set_ssa_range_info (tree, value_range_equiv *); - - /* STACK holds the old VR. */ - auto_vec<std::pair <tree, value_range_equiv *> > stack; - - /* True if we are updating global ranges, false otherwise. */ - bool m_update_global_ranges; -}; - -#endif /* GCC_GIMPLE_SSA_EVRP_ANALYZE_H */ diff --git a/gcc/gimple-ssa-evrp.cc b/gcc/gimple-ssa-evrp.cc deleted file mode 100644 index 20388ed5431..00000000000 --- a/gcc/gimple-ssa-evrp.cc +++ /dev/null @@ -1,395 +0,0 @@ -/* Support routines for Value Range Propagation (VRP). - Copyright (C) 2005-2022 Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "tree.h" -#include "gimple.h" -#include "tree-pass.h" -#include "ssa.h" -#include "gimple-pretty-print.h" -#include "cfganal.h" -#include "gimple-iterator.h" -#include "gimple-fold.h" -#include "tree-eh.h" -#include "tree-cfg.h" -#include "tree-ssa-loop-manip.h" -#include "tree-ssa-loop.h" -#include "cfgloop.h" -#include "tree-scalar-evolution.h" -#include "tree-ssa-propagate.h" -#include "alloc-pool.h" -#include "domwalk.h" -#include "tree-cfgcleanup.h" -#include "vr-values.h" -#include "gimple-ssa-evrp-analyze.h" -#include "gimple-range.h" -#include "fold-const.h" -#include "value-pointer-equiv.h" -#include "tree-vrp.h" - -// This is the classic EVRP folder which uses a dominator walk and pushes -// ranges into the next block if it is a single predecessor block. - -class evrp_folder : public substitute_and_fold_engine -{ -public: - evrp_folder () : - substitute_and_fold_engine (), - m_range_analyzer (/*update_global_ranges=*/true), - simplifier (&m_range_analyzer) - { } - - ~evrp_folder () - { - if (dump_file) - { - fprintf (dump_file, "\nValue ranges after Early VRP:\n\n"); - m_range_analyzer.dump (dump_file); - fprintf (dump_file, "\n"); - } - } - - tree value_of_expr (tree name, gimple *stmt) override - { - return m_range_analyzer.value_of_expr (name, stmt); - } - - void pre_fold_bb (basic_block bb) override - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "evrp visiting BB%d\n", bb->index); - m_range_analyzer.enter (bb); - } - - void pre_fold_stmt (gimple *stmt) override - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "evrp visiting stmt "); - print_gimple_stmt (dump_file, stmt, 0); - } - m_range_analyzer.record_ranges_from_stmt (stmt, false); - } - - bool fold_stmt (gimple_stmt_iterator *gsi) override - { - return simplifier.simplify (gsi); - } - - void post_fold_bb (basic_block bb) override - { - m_range_analyzer.leave (bb); - } - - void post_new_stmt (gimple *stmt) override - { - m_range_analyzer.set_defs_to_varying (stmt); - } - -protected: - DISABLE_COPY_AND_ASSIGN (evrp_folder); - evrp_range_analyzer m_range_analyzer; - simplify_using_ranges simplifier; -}; - -// In a hybrid folder, start with an EVRP folder, and add the required -// fold_stmt bits to either try the ranger first or second. -// -// The 3 value_* routines will always query both EVRP and the ranger for -// a result, and ensure they return the same value. If either returns a value -// when the other doesn't, it is flagged in the listing, and the discoverd -// value is returned. -// -// The simplifier is unable to process 2 different sources, thus we try to -// use one engine, and if it fails to simplify, try using the other engine. -// It is reported when the first attempt fails and the second succeeds. - -class hybrid_folder : public evrp_folder -{ -public: - hybrid_folder (bool evrp_first) - { - m_ranger = enable_ranger (cfun); - - if (evrp_first) - { - first = &m_range_analyzer; - first_exec_flag = 0; - second = m_ranger; - second_exec_flag = m_ranger->non_executable_edge_flag; - } - else - { - first = m_ranger; - first_exec_flag = m_ranger->non_executable_edge_flag; - second = &m_range_analyzer; - second_exec_flag = 0; - } - m_pta = new pointer_equiv_analyzer (m_ranger); - } - - ~hybrid_folder () - { - if (dump_file && (dump_flags & TDF_DETAILS)) - m_ranger->dump (dump_file); - - m_ranger->export_global_ranges (); - disable_ranger (cfun); - delete m_pta; - } - - bool fold_stmt (gimple_stmt_iterator *gsi) override - { - simplifier.set_range_query (first, first_exec_flag); - if (simplifier.simplify (gsi)) - return true; - - simplifier.set_range_query (second, second_exec_flag); - if (simplifier.simplify (gsi)) - { - if (dump_file) - fprintf (dump_file, "EVRP:hybrid: Second query simplifed stmt\n"); - return true; - } - return false; - } - - void pre_fold_stmt (gimple *stmt) override - { - evrp_folder::pre_fold_stmt (stmt); - m_pta->visit_stmt (stmt); - } - - void pre_fold_bb (basic_block bb) override - { - evrp_folder::pre_fold_bb (bb); - m_pta->enter (bb); - } - - void post_fold_bb (basic_block bb) override - { - evrp_folder::post_fold_bb (bb); - m_pta->leave (bb); - } - - tree value_of_expr (tree name, gimple *) override; - tree value_on_edge (edge, tree name) override; - tree value_of_stmt (gimple *, tree name) override; - -private: - DISABLE_COPY_AND_ASSIGN (hybrid_folder); - gimple_ranger *m_ranger; - range_query *first; - int first_exec_flag; - range_query *second; - int second_exec_flag; - pointer_equiv_analyzer *m_pta; - tree choose_value (tree evrp_val, tree ranger_val); -}; - - -tree -hybrid_folder::value_of_expr (tree op, gimple *stmt) -{ - tree evrp_ret = evrp_folder::value_of_expr (op, stmt); - tree ranger_ret; - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) - ranger_ret = NULL; - else - { - ranger_ret = m_ranger->value_of_expr (op, stmt); - if (!ranger_ret && supported_pointer_equiv_p (op)) - ranger_ret = m_pta->get_equiv (op); - } - return choose_value (evrp_ret, ranger_ret); -} - -tree -hybrid_folder::value_on_edge (edge e, tree op) -{ - // Call evrp::value_of_expr directly. Otherwise another dual call is made - // via hybrid_folder::value_of_expr, but without an edge. - tree evrp_ret = evrp_folder::value_of_expr (op, NULL); - tree ranger_ret; - if (TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) - ranger_ret = NULL; - else - { - ranger_ret = m_ranger->value_on_edge (e, op); - if (!ranger_ret && supported_pointer_equiv_p (op)) - ranger_ret = m_pta->get_equiv (op); - } - return choose_value (evrp_ret, ranger_ret); -} - -tree -hybrid_folder::value_of_stmt (gimple *stmt, tree op) -{ - // Call evrp::value_of_expr directly. Otherwise another dual call is made - // via hybrid_folder::value_of_expr, but without a stmt. - tree evrp_ret; - if (op) - evrp_ret = evrp_folder::value_of_expr (op, NULL); - else - evrp_ret = NULL_TREE; - - tree ranger_ret; - if (op && TREE_CODE (op) == SSA_NAME && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op)) - ranger_ret = NULL; - else - ranger_ret = m_ranger->value_of_stmt (stmt, op); - return choose_value (evrp_ret, ranger_ret); -} - -// Given trees returned by EVRP and Ranger, choose/report the value to use -// by the folder. - -tree -hybrid_folder::choose_value (tree evrp_val, tree ranger_val) -{ - // If both found the same value, just return it. - if (evrp_val && ranger_val && !compare_values (evrp_val, ranger_val)) - return evrp_val; - - // If neither returned a value, return NULL_TREE. - if (!ranger_val && !evrp_val) - return NULL_TREE; - - // Otherwise there is a discrepancy to flag. - if (dump_file) - { - if (evrp_val && ranger_val) - fprintf (dump_file, "EVRP:hybrid: Disagreement\n"); - if (evrp_val) - { - fprintf (dump_file, "EVRP:hybrid: EVRP found singleton "); - print_generic_expr (dump_file, evrp_val); - fprintf (dump_file, "\n"); - } - if (ranger_val) - { - fprintf (dump_file, "EVRP:hybrid: RVRP found singleton "); - print_generic_expr (dump_file, ranger_val); - fprintf (dump_file, "\n"); - } - } - - // If one value was found, return it. - if (!evrp_val) - return ranger_val; - if (!ranger_val) - return evrp_val; - - // If values are different, return the first calculated value. - if (param_evrp_mode == EVRP_MODE_RVRP_FIRST) - return ranger_val; - return evrp_val; -} - -/* Main entry point for the early vrp pass which is a simplified non-iterative - version of vrp where basic blocks are visited in dominance order. Value - ranges discovered in early vrp will also be used by ipa-vrp. */ - -static unsigned int -execute_early_vrp () -{ - if (param_evrp_mode == EVRP_MODE_RVRP_ONLY) - return execute_ranger_vrp (cfun, false); - - /* Ideally this setup code would move into the ctor for the folder - However, this setup can change the number of blocks which - invalidates the internal arrays that are set up by the dominator - walker in substitute_and_fold_engine. */ - loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS); - rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa); - scev_initialize (); - calculate_dominance_info (CDI_DOMINATORS); - - // Only the last 2 bits matter for choosing the folder. - switch (param_evrp_mode) - { - case EVRP_MODE_EVRP_ONLY: - { - evrp_folder folder; - folder.substitute_and_fold (); - break; - } - case EVRP_MODE_EVRP_FIRST: - { - hybrid_folder folder (true); - folder.substitute_and_fold (); - break; - } - case EVRP_MODE_RVRP_FIRST: - { - hybrid_folder folder (false); - folder.substitute_and_fold (); - break; - } - default: - gcc_unreachable (); - } - - scev_finalize (); - loop_optimizer_finalize (); - return 0; -} - -namespace { - -const pass_data pass_data_early_vrp = -{ - GIMPLE_PASS, /* type */ - "evrp", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - TV_TREE_EARLY_VRP, /* tv_id */ - PROP_ssa, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), -}; - -class pass_early_vrp : public gimple_opt_pass -{ -public: - pass_early_vrp (gcc::context *ctxt) - : gimple_opt_pass (pass_data_early_vrp, ctxt) - {} - - /* opt_pass methods: */ - opt_pass * clone () { return new pass_early_vrp (m_ctxt); } - virtual bool gate (function *) - { - return flag_tree_vrp != 0; - } - virtual unsigned int execute (function *) - { return execute_early_vrp (); } - -}; // class pass_vrp -} // anon namespace - -gimple_opt_pass * -make_pass_early_vrp (gcc::context *ctxt) -{ - return new pass_early_vrp (ctxt); -} diff --git a/gcc/params.opt b/gcc/params.opt index bcf1423671a..2f9c9cf27dd 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -134,25 +134,6 @@ Maximum number of basic blocks before EVRP uses a sparse cache. Common Joined UInteger Var(param_evrp_switch_limit) Init(50) Optimization Param Maximum number of outgoing edges in a switch before EVRP will not process it. --param=evrp-mode= -Common Joined Var(param_evrp_mode) Enum(evrp_mode) Init(EVRP_MODE_RVRP_ONLY) Param Optimization ---param=evrp-mode=[legacy|ranger|legacy-first|ranger-first] Specifies the mode Early VRP should operate in. - -Enum -Name(evrp_mode) Type(enum evrp_mode) UnknownError(unknown evrp mode %qs) - -EnumValue -Enum(evrp_mode) String(legacy) Value(EVRP_MODE_EVRP_ONLY) - -EnumValue -Enum(evrp_mode) String(ranger) Value(EVRP_MODE_RVRP_ONLY) - -EnumValue -Enum(evrp_mode) String(legacy-first) Value(EVRP_MODE_EVRP_FIRST) - -EnumValue -Enum(evrp_mode) String(ranger-first) Value(EVRP_MODE_RVRP_FIRST) - -param=fsm-scale-path-blocks= Common Joined UInteger Var(param_fsm_scale_path_blocks) Init(3) IntegerRange(1, 10) Param Optimization Scale factor to apply to the number of blocks in a threading path when comparing to the number of (scaled) statements. diff --git a/gcc/testsuite/g++.dg/pr100774.C b/gcc/testsuite/g++.dg/pr100774.C index 345fcfa0d01..63320ef73fc 100644 --- a/gcc/testsuite/g++.dg/pr100774.C +++ b/gcc/testsuite/g++.dg/pr100774.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fno-tree-forwprop --param=evrp-mode=ranger -fcompare-debug " } */ +/* { dg-options "-O2 -fno-tree-forwprop -fcompare-debug " } */ extern void __attribute__((noreturn)) error(); diff --git a/gcc/testsuite/gcc.dg/pr100781.c b/gcc/testsuite/gcc.dg/pr100781.c index c0e008a3ba5..96f0a7a6012 100644 --- a/gcc/testsuite/gcc.dg/pr100781.c +++ b/gcc/testsuite/gcc.dg/pr100781.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 --param=evrp-mode=ranger -fcompare-debug " } */ +/* { dg-options "-O2 -fcompare-debug " } */ struct a { int b; diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 30022dac108..7b4e2917340 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -4388,17 +4388,30 @@ const pass_data pass_data_vrp = ( TODO_cleanup_cfg | TODO_update_ssa ), /* todo_flags_finish */ }; +const pass_data pass_data_early_vrp = +{ + GIMPLE_PASS, /* type */ + "evrp", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_TREE_EARLY_VRP, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ), +}; + static int vrp_pass_num = 0; class pass_vrp : public gimple_opt_pass { public: - pass_vrp (gcc::context *ctxt) - : gimple_opt_pass (pass_data_vrp, ctxt), warn_array_bounds_p (false), - my_pass (++vrp_pass_num) + pass_vrp (gcc::context *ctxt, const pass_data &data_) + : gimple_opt_pass (data_, ctxt), data (data_), warn_array_bounds_p (false), + my_pass (vrp_pass_num++) {} /* opt_pass methods: */ - opt_pass * clone () { return new pass_vrp (m_ctxt); } + opt_pass * clone () { return new pass_vrp (m_ctxt, data); } void set_pass_param (unsigned int n, bool param) { gcc_assert (n == 0); @@ -4407,6 +4420,10 @@ public: virtual bool gate (function *) { return flag_tree_vrp != 0; } virtual unsigned int execute (function *fun) { + // Early VRP pass. + if (my_pass == 0) + return execute_ranger_vrp (fun, /*warn_array_bounds_p=*/false); + if ((my_pass == 1 && param_vrp1_mode == VRP_MODE_RANGER) || (my_pass == 2 && param_vrp2_mode == VRP_MODE_RANGER)) return execute_ranger_vrp (fun, warn_array_bounds_p); @@ -4414,6 +4431,7 @@ public: } private: + const pass_data &data; bool warn_array_bounds_p; int my_pass; }; // class pass_vrp @@ -4423,5 +4441,11 @@ public: gimple_opt_pass * make_pass_vrp (gcc::context *ctxt) { - return new pass_vrp (ctxt); + return new pass_vrp (ctxt, pass_data_vrp); +} + +gimple_opt_pass * +make_pass_early_vrp (gcc::context *ctxt) +{ + return new pass_vrp (ctxt, pass_data_early_vrp); }