This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RFA][PATCH] 2/n Refactoring tree-vrp.c -- pull evrp bits into their own file
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Jeff Law <law at redhat dot com>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Fri, 10 Nov 2017 15:11:01 +0100
- Subject: Re: [RFA][PATCH] 2/n Refactoring tree-vrp.c -- pull evrp bits into their own file
- Authentication-results: sourceware.org; auth=none
- References: <740f201b-c668-3315-fb18-5ef3d66c5ac6@redhat.com>
On Fri, Nov 10, 2017 at 1:30 AM, Jeff Law <law@redhat.com> wrote:
> This patch pulls out the EVRP class & methods from tree-vrp.c. It's a
> straight copy-n-paste with the exception of the evrp_folder class which
> I trimmed back down to its minimal form.
>
> This obviously forces shared structures/routines between tree-vrp.c and
> tree-evrp.c to get exposed in a header file (tree-vrp.h). I consider
> this a positive as those dependencies are now fairly explicit and we can
> work to rationalize that set (ie, does the dependency make sense, where
> is the most natural place for the shared bits, etc).
>
> I'm not ready to pull the trigger on submission, but I fully expect
> tree-evrp.c to go through another refactoring to separate analysis from
> optimization -- which then allows us to embed the analysis bits into
> other passes.
>
> Bootstrapped and regression tested on x86_64. OK for the trunk?
Ok, but can you name it gimple-ssa-evrp.c please? ;)
Richard.
> Jeff
>
> * vr-values.h (VR_INITIALIZER): Move #define here.
> * tree-evrp.c: New file with contents extracted from tree-vrp.c
> * Makefile.in (OBJS): Add tree-evrp.o
> * tree-vrp.h (assert_info): Move structure definition here.
> (set_value_range_to_varying): Prototype.
> (vrp_operand_equal_p, range_includes_zero_p): Likewise.
> (infer_value_range, register_edge_assert_for): Likewise.
> (stmt_interesting_for_vrp): Likewise.
> * tree-vrp.c: Move all methods for evrp class into tree-evrp.c.
> (set_value_range_to_varying): No longer static.
> (vrp_operand_equal_p, range_includes_zero_p): Likewise.
> (infer_value_range, register_edge_assert_for): Likewise.
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 1bb1d6ec0ff..364d656db26 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1491,6 +1491,7 @@ OBJS = \
> tree-dump.o \
> tree-eh.o \
> tree-emutls.o \
> + tree-evrp.o \
> tree-if-conv.o \
> tree-inline.o \
> tree-into-ssa.o \
> diff --git a/gcc/tree-evrp.c b/gcc/tree-evrp.c
> new file mode 100644
> index 00000000000..13ba31d7cd7
> --- /dev/null
> +++ b/gcc/tree-evrp.c
> @@ -0,0 +1,624 @@
> +/* Support routines for Value Range Propagation (VRP).
> + Copyright (C) 2005-2017 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-fold.h"
> +#include "tree-eh.h"
> +#include "gimple-iterator.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"
> +
> +class evrp_folder : public substitute_and_fold_engine
> +{
> + public:
> + tree get_value (tree) FINAL OVERRIDE;
> +
> + class vr_values *vr_values;
> +};
> +
> +tree
> +evrp_folder::get_value (tree op)
> +{
> + return vr_values->op_with_constant_singleton_value_range (op);
> +}
> +
> +/* evrp_dom_walker visits the basic blocks in the dominance order and set
> + the Value Ranges (VR) for SSA_NAMEs in the scope. Use this VR to
> + discover more VRs. */
> +
> +class evrp_dom_walker : public dom_walker
> +{
> +public:
> + evrp_dom_walker ()
> + : dom_walker (CDI_DOMINATORS), stack (10)
> + {
> + need_eh_cleanup = BITMAP_ALLOC (NULL);
> + }
> + ~evrp_dom_walker ()
> + {
> + BITMAP_FREE (need_eh_cleanup);
> + }
> + virtual edge before_dom_children (basic_block);
> + virtual void after_dom_children (basic_block);
> + void push_value_range (tree var, value_range *vr);
> + value_range *pop_value_range (tree var);
> + value_range *try_find_new_range (tree, tree op, tree_code code, tree limit);
> +
> + /* Cond_stack holds the old VR. */
> + auto_vec<std::pair <tree, value_range*> > stack;
> + bitmap need_eh_cleanup;
> + auto_vec<gimple *> stmts_to_fixup;
> + auto_vec<gimple *> stmts_to_remove;
> +
> + class vr_values vr_values;
> +
> + /* Temporary delegators. */
> + value_range *get_value_range (const_tree op)
> + { return vr_values.get_value_range (op); }
> + bool update_value_range (const_tree op, value_range *vr)
> + { return vr_values.update_value_range (op, vr); }
> + void extract_range_from_phi_node (gphi *phi, value_range *vr)
> + { vr_values.extract_range_from_phi_node (phi, vr); }
> + void extract_range_for_var_from_comparison_expr (tree var,
> + enum tree_code cond_code,
> + tree op, tree limit,
> + value_range *vr_p)
> + { vr_values.extract_range_for_var_from_comparison_expr (var, cond_code,
> + op, limit, vr_p); }
> + void adjust_range_with_scev (value_range *vr, struct loop *loop,
> + gimple *stmt, tree var)
> + { vr_values.adjust_range_with_scev (vr, loop, stmt, var); }
> + tree op_with_constant_singleton_value_range (tree op)
> + { return vr_values.op_with_constant_singleton_value_range (op); }
> + void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
> + tree *output_p, value_range *vr)
> + { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); }
> + void set_defs_to_varying (gimple *stmt)
> + { return vr_values.set_defs_to_varying (stmt); }
> + void set_vr_value (tree name, value_range *vr)
> + { vr_values.set_vr_value (name, vr); }
> + void simplify_cond_using_ranges_2 (gcond *stmt)
> + { vr_values.simplify_cond_using_ranges_2 (stmt); }
> + void vrp_visit_cond_stmt (gcond *cond, edge *e)
> + { vr_values.vrp_visit_cond_stmt (cond, e); }
> +};
> +
> +/* Find new range for NAME such that (OP CODE LIMIT) is true. */
> +
> +value_range *
> +evrp_dom_walker::try_find_new_range (tree name,
> + tree op, tree_code code, tree limit)
> +{
> + value_range vr = VR_INITIALIZER;
> + value_range *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.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> + {
> + if (old_vr->type == vr.type
> + && vrp_operand_equal_p (old_vr->min, vr.min)
> + && vrp_operand_equal_p (old_vr->max, vr.max))
> + return NULL;
> + value_range *new_vr = vr_values.vrp_value_range_pool.allocate ();
> + *new_vr = vr;
> + return new_vr;
> + }
> + return NULL;
> +}
> +
> +/* See if there is any new scope is entered with new VR and set that VR to
> + ssa_name before visiting the statements in the scope. */
> +
> +edge
> +evrp_dom_walker::before_dom_children (basic_block bb)
> +{
> + if (dump_file && (dump_flags & TDF_DETAILS))
> + fprintf (dump_file, "Visiting BB%d\n", bb->index);
> +
> + stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
> +
> + 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 *>, 8> vrs;
> + for (unsigned i = 0; i < asserts.length (); ++i)
> + {
> + value_range *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));
> + }
> + /* 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)
> + push_value_range (vrs[i].first, vrs[i].second);
> + }
> + }
> +
> + /* 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;
> + value_range vr_result = VR_INITIALIZER;
> + bool interesting = stmt_interesting_for_vrp (phi);
> + if (interesting && dump_file && (dump_flags & TDF_DETAILS))
> + {
> + fprintf (dump_file, "Visiting PHI node ");
> + print_gimple_stmt (dump_file, phi, 0);
> + }
> + if (!has_unvisited_preds
> + && interesting)
> + extract_range_from_phi_node (phi, &vr_result);
> + else
> + {
> + set_value_range_to_varying (&vr_result);
> + /* 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. */
> + struct loop *l;
> + if (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);
> +
> + /* Mark PHIs whose lhs we fully propagate for removal. */
> + tree val = op_with_constant_singleton_value_range (lhs);
> + if (val && may_propagate_copy (lhs, val))
> + {
> + stmts_to_remove.safe_push (phi);
> + continue;
> + }
> +
> + /* Set the SSA with the value range. */
> + if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
> + {
> + if ((vr_result.type == VR_RANGE
> + || vr_result.type == VR_ANTI_RANGE)
> + && (TREE_CODE (vr_result.min) == INTEGER_CST)
> + && (TREE_CODE (vr_result.max) == INTEGER_CST))
> + set_range_info (lhs, vr_result.type,
> + wi::to_wide (vr_result.min),
> + wi::to_wide (vr_result.max));
> + }
> + else if (POINTER_TYPE_P (TREE_TYPE (lhs))
> + && ((vr_result.type == VR_RANGE
> + && range_includes_zero_p (vr_result.min,
> + vr_result.max) == 0)
> + || (vr_result.type == VR_ANTI_RANGE
> + && range_includes_zero_p (vr_result.min,
> + vr_result.max) == 1)))
> + set_ptr_nonnull (lhs);
> + }
> +
> + edge taken_edge = NULL;
> +
> + /* Visit all other stmts and discover any new VRs possible. */
> + for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> + !gsi_end_p (gsi); gsi_next (&gsi))
> + {
> + gimple *stmt = gsi_stmt (gsi);
> + tree output = NULL_TREE;
> + gimple *old_stmt = stmt;
> + bool was_noreturn = (is_gimple_call (stmt)
> + && gimple_call_noreturn_p (stmt));
> +
> + if (dump_file && (dump_flags & TDF_DETAILS))
> + {
> + fprintf (dump_file, "Visiting stmt ");
> + print_gimple_stmt (dump_file, stmt, 0);
> + }
> +
> + if (gcond *cond = dyn_cast <gcond *> (stmt))
> + {
> + vrp_visit_cond_stmt (cond, &taken_edge);
> + if (taken_edge)
> + {
> + if (taken_edge->flags & EDGE_TRUE_VALUE)
> + gimple_cond_make_true (cond);
> + else if (taken_edge->flags & EDGE_FALSE_VALUE)
> + gimple_cond_make_false (cond);
> + else
> + gcc_unreachable ();
> + update_stmt (stmt);
> + }
> + }
> + else if (stmt_interesting_for_vrp (stmt))
> + {
> + edge taken_edge;
> + value_range vr = VR_INITIALIZER;
> + extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
> + if (output
> + && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
> + {
> + update_value_range (output, &vr);
> + vr = *get_value_range (output);
> +
> + /* Mark stmts whose output we fully propagate for removal. */
> + tree val;
> + if ((val = op_with_constant_singleton_value_range (output))
> + && may_propagate_copy (output, val)
> + && !stmt_could_throw_p (stmt)
> + && !gimple_has_side_effects (stmt))
> + {
> + stmts_to_remove.safe_push (stmt);
> + continue;
> + }
> +
> + /* Set the SSA with the value range. */
> + if (INTEGRAL_TYPE_P (TREE_TYPE (output)))
> + {
> + if ((vr.type == VR_RANGE
> + || vr.type == VR_ANTI_RANGE)
> + && (TREE_CODE (vr.min) == INTEGER_CST)
> + && (TREE_CODE (vr.max) == INTEGER_CST))
> + set_range_info (output, vr.type,
> + wi::to_wide (vr.min),
> + wi::to_wide (vr.max));
> + }
> + else if (POINTER_TYPE_P (TREE_TYPE (output))
> + && ((vr.type == VR_RANGE
> + && range_includes_zero_p (vr.min,
> + vr.max) == 0)
> + || (vr.type == VR_ANTI_RANGE
> + && range_includes_zero_p (vr.min,
> + vr.max) == 1)))
> + set_ptr_nonnull (output);
> + }
> + 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 *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 *op_range = try_find_new_range (op, op,
> + comp_code, value);
> + if (op_range)
> + push_value_range (op, op_range);
> + }
> + }
> +
> + /* Try folding stmts with the VR discovered. */
> + class evrp_folder evrp_folder;
> + evrp_folder.vr_values = &vr_values;
> + bool did_replace = evrp_folder.replace_uses_in (stmt);
> + if (fold_stmt (&gsi, follow_single_use_edges)
> + || did_replace)
> + {
> + stmt = gsi_stmt (gsi);
> + update_stmt (stmt);
> + did_replace = true;
> + }
> +
> + if (did_replace)
> + {
> + /* If we cleaned up EH information from the statement,
> + remove EH edges. */
> + if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
> + bitmap_set_bit (need_eh_cleanup, bb->index);
> +
> + /* If we turned a not noreturn call into a noreturn one
> + schedule it for fixup. */
> + if (!was_noreturn
> + && is_gimple_call (stmt)
> + && gimple_call_noreturn_p (stmt))
> + stmts_to_fixup.safe_push (stmt);
> +
> + if (gimple_assign_single_p (stmt))
> + {
> + tree rhs = gimple_assign_rhs1 (stmt);
> + if (TREE_CODE (rhs) == ADDR_EXPR)
> + recompute_tree_invariant_for_addr_expr (rhs);
> + }
> + }
> + }
> +
> + /* Visit BB successor PHI nodes and replace PHI args. */
> + FOR_EACH_EDGE (e, ei, bb->succs)
> + {
> + for (gphi_iterator gpi = gsi_start_phis (e->dest);
> + !gsi_end_p (gpi); gsi_next (&gpi))
> + {
> + gphi *phi = gpi.phi ();
> + use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
> + tree arg = USE_FROM_PTR (use_p);
> + if (TREE_CODE (arg) != SSA_NAME
> + || virtual_operand_p (arg))
> + continue;
> + tree val = op_with_constant_singleton_value_range (arg);
> + if (val && may_propagate_copy (arg, val))
> + propagate_value (use_p, val);
> + }
> + }
> +
> + bb->flags |= BB_VISITED;
> +
> + return taken_edge;
> +}
> +
> +/* Restore/pop VRs valid only for BB when we leave BB. */
> +
> +void
> +evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
> +{
> + gcc_checking_assert (!stack.is_empty ());
> + while (stack.last ().first != NULL_TREE)
> + pop_value_range (stack.last ().first);
> + stack.pop ();
> +}
> +
> +/* Push the Value Range of VAR to the stack and update it with new VR. */
> +
> +void
> +evrp_dom_walker::push_value_range (tree var, value_range *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");
> + }
> + stack.safe_push (std::make_pair (var, get_value_range (var)));
> + set_vr_value (var, vr);
> +}
> +
> +/* Pop the Value Range from the vrp_stack and update VAR with it. */
> +
> +value_range *
> +evrp_dom_walker::pop_value_range (tree var)
> +{
> + value_range *vr = stack.last ().second;
> + gcc_checking_assert (var == stack.last ().first);
> + 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");
> + }
> + set_vr_value (var, vr);
> + stack.pop ();
> + return vr;
> +}
> +
> +
> +/* 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 ()
> +{
> + edge e;
> + edge_iterator ei;
> + basic_block bb;
> +
> + 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);
> + FOR_EACH_BB_FN (bb, cfun)
> + {
> + bb->flags &= ~BB_VISITED;
> + FOR_EACH_EDGE (e, ei, bb->preds)
> + e->flags |= EDGE_EXECUTABLE;
> + }
> +
> + /* Walk stmts in dominance order and propagate VRP. */
> + evrp_dom_walker walker;
> + walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> +
> + if (dump_file)
> + {
> + fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
> + walker.vr_values.dump_all_value_ranges (dump_file);
> + fprintf (dump_file, "\n");
> + }
> +
> + /* Remove stmts in reverse order to make debug stmt creation possible. */
> + while (! walker.stmts_to_remove.is_empty ())
> + {
> + gimple *stmt = walker.stmts_to_remove.pop ();
> + if (dump_file && dump_flags & TDF_DETAILS)
> + {
> + fprintf (dump_file, "Removing dead stmt ");
> + print_gimple_stmt (dump_file, stmt, 0);
> + fprintf (dump_file, "\n");
> + }
> + gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
> + if (gimple_code (stmt) == GIMPLE_PHI)
> + remove_phi_node (&gsi, true);
> + else
> + {
> + unlink_stmt_vdef (stmt);
> + gsi_remove (&gsi, true);
> + release_defs (stmt);
> + }
> + }
> +
> + if (!bitmap_empty_p (walker.need_eh_cleanup))
> + gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
> +
> + /* Fixup stmts that became noreturn calls. This may require splitting
> + blocks and thus isn't possible during the dominator walk. Do this
> + in reverse order so we don't inadvertedly remove a stmt we want to
> + fixup by visiting a dominating now noreturn call first. */
> + while (!walker.stmts_to_fixup.is_empty ())
> + {
> + gimple *stmt = walker.stmts_to_fixup.pop ();
> + fixup_noreturn_call (stmt);
> + }
> +
> + 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/tree-vrp.c b/gcc/tree-vrp.c
> index 7173ab22478..6fae6b2efb8 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -66,8 +66,6 @@ along with GCC; see the file COPYING3. If not see
> #include "attribs.h"
> #include "vr-values.h"
>
> -#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
> -
> /* Set of SSA names found live during the RPO traversal of the function
> for still active basic-blocks. */
> static sbitmap *live;
> @@ -85,21 +83,6 @@ live_on_edge (edge e, tree name)
> static int compare_values (tree val1, tree val2);
> static int compare_values_warnv (tree val1, tree val2, bool *);
>
> -struct assert_info
> -{
> - /* Predicate code for the ASSERT_EXPR. Must be COMPARISON_CLASS_P. */
> - enum tree_code comp_code;
> -
> - /* Name to register the assert for. */
> - tree name;
> -
> - /* Value being compared against. */
> - tree val;
> -
> - /* Expression to compare. */
> - tree expr;
> -};
> -
> /* Location information for ASSERT_EXPRs. Each instance of this
> structure describes an ASSERT_EXPR for an SSA name. Since a single
> SSA name may have more than one assertion associated with it, these
> @@ -207,10 +190,9 @@ set_value_range_to_undefined (value_range *vr)
> bitmap_clear (vr->equiv);
> }
>
> -
> /* Set value range VR to VR_VARYING. */
>
> -static inline void
> +void
> set_value_range_to_varying (value_range *vr)
> {
> vr->type = VR_VARYING;
> @@ -219,7 +201,6 @@ set_value_range_to_varying (value_range *vr)
> bitmap_clear (vr->equiv);
> }
>
> -
> /* Set value range VR to {T, MIN, MAX, EQUIV}. */
>
> static void
> @@ -582,7 +563,7 @@ vr_values::set_defs_to_varying (gimple *stmt)
>
> /* Return true, if VAL1 and VAL2 are equal values for VRP purposes. */
>
> -static inline bool
> +bool
> vrp_operand_equal_p (const_tree val1, const_tree val2)
> {
> if (val1 == val2)
> @@ -1201,7 +1182,7 @@ value_ranges_intersect_p (value_range *vr0, value_range *vr1)
> /* Return 1 if [MIN, MAX] includes the value zero, 0 if it does not
> include the value zero, -2 if we cannot tell. */
>
> -static inline int
> +int
> range_includes_zero_p (tree min, tree max)
> {
> tree zero = build_int_cst (TREE_TYPE (min), 0);
> @@ -4524,7 +4505,7 @@ fp_predicate (gimple *stmt)
> describes the inferred range. Return true if a range could be
> inferred. */
>
> -static bool
> +bool
> infer_value_range (gimple *stmt, tree op, tree_code *comp_code_p, tree *val_p)
> {
> *val_p = NULL_TREE;
> @@ -5696,7 +5677,7 @@ is_masked_range_test (tree name, tree valt, enum tree_code cond_code,
> the condition COND contributing to the conditional jump pointed to by
> SI. */
>
> -static void
> +void
> register_edge_assert_for (tree name, edge e,
> enum tree_code cond_code, tree cond_op0,
> tree cond_op1, vec<assert_info> &asserts)
> @@ -7072,7 +7053,7 @@ remove_range_assertions (void)
>
> /* Return true if STMT is interesting for VRP. */
>
> -static bool
> +bool
> stmt_interesting_for_vrp (gimple *stmt)
> {
> if (gimple_code (stmt) == GIMPLE_PHI)
> @@ -10920,423 +10901,6 @@ vrp_prop::vrp_finalize (bool warn_array_bounds_p)
> check_all_array_refs ();
> }
>
> -/* evrp_dom_walker visits the basic blocks in the dominance order and set
> - the Value Ranges (VR) for SSA_NAMEs in the scope. Use this VR to
> - discover more VRs. */
> -
> -class evrp_dom_walker : public dom_walker
> -{
> -public:
> - evrp_dom_walker ()
> - : dom_walker (CDI_DOMINATORS), stack (10)
> - {
> - need_eh_cleanup = BITMAP_ALLOC (NULL);
> - }
> - ~evrp_dom_walker ()
> - {
> - BITMAP_FREE (need_eh_cleanup);
> - }
> - virtual edge before_dom_children (basic_block);
> - virtual void after_dom_children (basic_block);
> - void push_value_range (tree var, value_range *vr);
> - value_range *pop_value_range (tree var);
> - value_range *try_find_new_range (tree, tree op, tree_code code, tree limit);
> -
> - /* Cond_stack holds the old VR. */
> - auto_vec<std::pair <tree, value_range*> > stack;
> - bitmap need_eh_cleanup;
> - auto_vec<gimple *> stmts_to_fixup;
> - auto_vec<gimple *> stmts_to_remove;
> -
> - class vr_values vr_values;
> -
> - /* Temporary delegators. */
> - value_range *get_value_range (const_tree op)
> - { return vr_values.get_value_range (op); }
> - bool update_value_range (const_tree op, value_range *vr)
> - { return vr_values.update_value_range (op, vr); }
> - void extract_range_from_phi_node (gphi *phi, value_range *vr)
> - { vr_values.extract_range_from_phi_node (phi, vr); }
> - void extract_range_for_var_from_comparison_expr (tree var,
> - enum tree_code cond_code,
> - tree op, tree limit,
> - value_range *vr_p)
> - { vr_values.extract_range_for_var_from_comparison_expr (var, cond_code,
> - op, limit, vr_p); }
> - void adjust_range_with_scev (value_range *vr, struct loop *loop,
> - gimple *stmt, tree var)
> - { vr_values.adjust_range_with_scev (vr, loop, stmt, var); }
> - tree op_with_constant_singleton_value_range (tree op)
> - { return vr_values.op_with_constant_singleton_value_range (op); }
> - void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
> - tree *output_p, value_range *vr)
> - { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); }
> - void set_defs_to_varying (gimple *stmt)
> - { return vr_values.set_defs_to_varying (stmt); }
> - void set_vr_value (tree name, value_range *vr)
> - { vr_values.set_vr_value (name, vr); }
> - void simplify_cond_using_ranges_2 (gcond *stmt)
> - { vr_values.simplify_cond_using_ranges_2 (stmt); }
> - void vrp_visit_cond_stmt (gcond *cond, edge *e)
> - { vr_values.vrp_visit_cond_stmt (cond, e); }
> -};
> -
> -/* Find new range for NAME such that (OP CODE LIMIT) is true. */
> -
> -value_range *
> -evrp_dom_walker::try_find_new_range (tree name,
> - tree op, tree_code code, tree limit)
> -{
> - value_range vr = VR_INITIALIZER;
> - value_range *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.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
> - {
> - if (old_vr->type == vr.type
> - && vrp_operand_equal_p (old_vr->min, vr.min)
> - && vrp_operand_equal_p (old_vr->max, vr.max))
> - return NULL;
> - value_range *new_vr = vr_values.vrp_value_range_pool.allocate ();
> - *new_vr = vr;
> - return new_vr;
> - }
> - return NULL;
> -}
> -
> -/* See if there is any new scope is entered with new VR and set that VR to
> - ssa_name before visiting the statements in the scope. */
> -
> -edge
> -evrp_dom_walker::before_dom_children (basic_block bb)
> -{
> - if (dump_file && (dump_flags & TDF_DETAILS))
> - fprintf (dump_file, "Visiting BB%d\n", bb->index);
> -
> - stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
> -
> - 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 *>, 8> vrs;
> - for (unsigned i = 0; i < asserts.length (); ++i)
> - {
> - value_range *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));
> - }
> - /* 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)
> - push_value_range (vrs[i].first, vrs[i].second);
> - }
> - }
> -
> - /* 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;
> - value_range vr_result = VR_INITIALIZER;
> - bool interesting = stmt_interesting_for_vrp (phi);
> - if (interesting && dump_file && (dump_flags & TDF_DETAILS))
> - {
> - fprintf (dump_file, "Visiting PHI node ");
> - print_gimple_stmt (dump_file, phi, 0);
> - }
> - if (!has_unvisited_preds
> - && interesting)
> - extract_range_from_phi_node (phi, &vr_result);
> - else
> - {
> - set_value_range_to_varying (&vr_result);
> - /* 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. */
> - struct loop *l;
> - if (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);
> -
> - /* Mark PHIs whose lhs we fully propagate for removal. */
> - tree val = op_with_constant_singleton_value_range (lhs);
> - if (val && may_propagate_copy (lhs, val))
> - {
> - stmts_to_remove.safe_push (phi);
> - continue;
> - }
> -
> - /* Set the SSA with the value range. */
> - if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
> - {
> - if ((vr_result.type == VR_RANGE
> - || vr_result.type == VR_ANTI_RANGE)
> - && (TREE_CODE (vr_result.min) == INTEGER_CST)
> - && (TREE_CODE (vr_result.max) == INTEGER_CST))
> - set_range_info (lhs, vr_result.type,
> - wi::to_wide (vr_result.min),
> - wi::to_wide (vr_result.max));
> - }
> - else if (POINTER_TYPE_P (TREE_TYPE (lhs))
> - && ((vr_result.type == VR_RANGE
> - && range_includes_zero_p (vr_result.min,
> - vr_result.max) == 0)
> - || (vr_result.type == VR_ANTI_RANGE
> - && range_includes_zero_p (vr_result.min,
> - vr_result.max) == 1)))
> - set_ptr_nonnull (lhs);
> - }
> -
> - edge taken_edge = NULL;
> -
> - /* Visit all other stmts and discover any new VRs possible. */
> - for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
> - !gsi_end_p (gsi); gsi_next (&gsi))
> - {
> - gimple *stmt = gsi_stmt (gsi);
> - tree output = NULL_TREE;
> - gimple *old_stmt = stmt;
> - bool was_noreturn = (is_gimple_call (stmt)
> - && gimple_call_noreturn_p (stmt));
> -
> - if (dump_file && (dump_flags & TDF_DETAILS))
> - {
> - fprintf (dump_file, "Visiting stmt ");
> - print_gimple_stmt (dump_file, stmt, 0);
> - }
> -
> - if (gcond *cond = dyn_cast <gcond *> (stmt))
> - {
> - vrp_visit_cond_stmt (cond, &taken_edge);
> - if (taken_edge)
> - {
> - if (taken_edge->flags & EDGE_TRUE_VALUE)
> - gimple_cond_make_true (cond);
> - else if (taken_edge->flags & EDGE_FALSE_VALUE)
> - gimple_cond_make_false (cond);
> - else
> - gcc_unreachable ();
> - update_stmt (stmt);
> - }
> - }
> - else if (stmt_interesting_for_vrp (stmt))
> - {
> - edge taken_edge;
> - value_range vr = VR_INITIALIZER;
> - extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
> - if (output
> - && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
> - {
> - update_value_range (output, &vr);
> - vr = *get_value_range (output);
> -
> - /* Mark stmts whose output we fully propagate for removal. */
> - tree val;
> - if ((val = op_with_constant_singleton_value_range (output))
> - && may_propagate_copy (output, val)
> - && !stmt_could_throw_p (stmt)
> - && !gimple_has_side_effects (stmt))
> - {
> - stmts_to_remove.safe_push (stmt);
> - continue;
> - }
> -
> - /* Set the SSA with the value range. */
> - if (INTEGRAL_TYPE_P (TREE_TYPE (output)))
> - {
> - if ((vr.type == VR_RANGE
> - || vr.type == VR_ANTI_RANGE)
> - && (TREE_CODE (vr.min) == INTEGER_CST)
> - && (TREE_CODE (vr.max) == INTEGER_CST))
> - set_range_info (output, vr.type,
> - wi::to_wide (vr.min),
> - wi::to_wide (vr.max));
> - }
> - else if (POINTER_TYPE_P (TREE_TYPE (output))
> - && ((vr.type == VR_RANGE
> - && range_includes_zero_p (vr.min,
> - vr.max) == 0)
> - || (vr.type == VR_ANTI_RANGE
> - && range_includes_zero_p (vr.min,
> - vr.max) == 1)))
> - set_ptr_nonnull (output);
> - }
> - 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 *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 *op_range = try_find_new_range (op, op,
> - comp_code, value);
> - if (op_range)
> - push_value_range (op, op_range);
> - }
> - }
> -
> - /* Try folding stmts with the VR discovered. */
> - class vrp_folder vrp_folder;
> - vrp_folder.vr_values = &vr_values;
> - bool did_replace = vrp_folder.replace_uses_in (stmt);
> - if (fold_stmt (&gsi, follow_single_use_edges)
> - || did_replace)
> - {
> - stmt = gsi_stmt (gsi);
> - update_stmt (stmt);
> - did_replace = true;
> - }
> -
> - if (did_replace)
> - {
> - /* If we cleaned up EH information from the statement,
> - remove EH edges. */
> - if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
> - bitmap_set_bit (need_eh_cleanup, bb->index);
> -
> - /* If we turned a not noreturn call into a noreturn one
> - schedule it for fixup. */
> - if (!was_noreturn
> - && is_gimple_call (stmt)
> - && gimple_call_noreturn_p (stmt))
> - stmts_to_fixup.safe_push (stmt);
> -
> - if (gimple_assign_single_p (stmt))
> - {
> - tree rhs = gimple_assign_rhs1 (stmt);
> - if (TREE_CODE (rhs) == ADDR_EXPR)
> - recompute_tree_invariant_for_addr_expr (rhs);
> - }
> - }
> - }
> -
> - /* Visit BB successor PHI nodes and replace PHI args. */
> - FOR_EACH_EDGE (e, ei, bb->succs)
> - {
> - for (gphi_iterator gpi = gsi_start_phis (e->dest);
> - !gsi_end_p (gpi); gsi_next (&gpi))
> - {
> - gphi *phi = gpi.phi ();
> - use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
> - tree arg = USE_FROM_PTR (use_p);
> - if (TREE_CODE (arg) != SSA_NAME
> - || virtual_operand_p (arg))
> - continue;
> - tree val = op_with_constant_singleton_value_range (arg);
> - if (val && may_propagate_copy (arg, val))
> - propagate_value (use_p, val);
> - }
> - }
> -
> - bb->flags |= BB_VISITED;
> -
> - return taken_edge;
> -}
> -
> -/* Restore/pop VRs valid only for BB when we leave BB. */
> -
> -void
> -evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
> -{
> - gcc_checking_assert (!stack.is_empty ());
> - while (stack.last ().first != NULL_TREE)
> - pop_value_range (stack.last ().first);
> - stack.pop ();
> -}
> -
> void
> vr_values::set_vr_value (tree var, value_range *vr)
> {
> @@ -11345,117 +10909,6 @@ vr_values::set_vr_value (tree var, value_range *vr)
> vr_value[SSA_NAME_VERSION (var)] = vr;
> }
>
> -/* Push the Value Range of VAR to the stack and update it with new VR. */
> -
> -void
> -evrp_dom_walker::push_value_range (tree var, value_range *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");
> - }
> - stack.safe_push (std::make_pair (var, get_value_range (var)));
> - set_vr_value (var, vr);
> -}
> -
> -/* Pop the Value Range from the vrp_stack and update VAR with it. */
> -
> -value_range *
> -evrp_dom_walker::pop_value_range (tree var)
> -{
> - value_range *vr = stack.last ().second;
> - gcc_checking_assert (var == stack.last ().first);
> - 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");
> - }
> - set_vr_value (var, vr);
> - stack.pop ();
> - return vr;
> -}
> -
> -
> -/* 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 ()
> -{
> - edge e;
> - edge_iterator ei;
> - basic_block bb;
> -
> - 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);
> - FOR_EACH_BB_FN (bb, cfun)
> - {
> - bb->flags &= ~BB_VISITED;
> - FOR_EACH_EDGE (e, ei, bb->preds)
> - e->flags |= EDGE_EXECUTABLE;
> - }
> -
> - /* Walk stmts in dominance order and propagate VRP. */
> - evrp_dom_walker walker;
> - walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> -
> - if (dump_file)
> - {
> - fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
> - walker.vr_values.dump_all_value_ranges (dump_file);
> - fprintf (dump_file, "\n");
> - }
> -
> - /* Remove stmts in reverse order to make debug stmt creation possible. */
> - while (! walker.stmts_to_remove.is_empty ())
> - {
> - gimple *stmt = walker.stmts_to_remove.pop ();
> - if (dump_file && dump_flags & TDF_DETAILS)
> - {
> - fprintf (dump_file, "Removing dead stmt ");
> - print_gimple_stmt (dump_file, stmt, 0);
> - fprintf (dump_file, "\n");
> - }
> - gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
> - if (gimple_code (stmt) == GIMPLE_PHI)
> - remove_phi_node (&gsi, true);
> - else
> - {
> - unlink_stmt_vdef (stmt);
> - gsi_remove (&gsi, true);
> - release_defs (stmt);
> - }
> - }
> -
> - if (!bitmap_empty_p (walker.need_eh_cleanup))
> - gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
> -
> - /* Fixup stmts that became noreturn calls. This may require splitting
> - blocks and thus isn't possible during the dominator walk. Do this
> - in reverse order so we don't inadvertedly remove a stmt we want to
> - fixup by visiting a dominating now noreturn call first. */
> - while (!walker.stmts_to_fixup.is_empty ())
> - {
> - gimple *stmt = walker.stmts_to_fixup.pop ();
> - fixup_noreturn_call (stmt);
> - }
> -
> - scev_finalize ();
> - loop_optimizer_finalize ();
> - return 0;
> -}
> -
> -
> /* Main entry point to VRP (Value Range Propagation). This pass is
> loosely based on J. R. C. Patterson, ``Accurate Static Branch
> Prediction by Value Range Propagation,'' in SIGPLAN Conference on
> @@ -11649,44 +11102,3 @@ make_pass_vrp (gcc::context *ctxt)
> {
> return new pass_vrp (ctxt);
> }
> -
> -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/tree-vrp.h b/gcc/tree-vrp.h
> index 1b68956c6fd..455a9ac9252 100644
> --- a/gcc/tree-vrp.h
> +++ b/gcc/tree-vrp.h
> @@ -60,4 +60,28 @@ extern void extract_range_from_unary_expr (value_range *vr,
> value_range *vr0_,
> tree op0_type);
>
> +extern bool vrp_operand_equal_p (const_tree, const_tree);
> +
> +struct assert_info
> +{
> + /* Predicate code for the ASSERT_EXPR. Must be COMPARISON_CLASS_P. */
> + enum tree_code comp_code;
> +
> + /* Name to register the assert for. */
> + tree name;
> +
> + /* Value being compared against. */
> + tree val;
> +
> + /* Expression to compare. */
> + tree expr;
> +};
> +
> +extern void register_edge_assert_for (tree, edge, enum tree_code,
> + tree, tree, vec<assert_info> &);
> +extern bool stmt_interesting_for_vrp (gimple *);
> +extern void set_value_range_to_varying (value_range *);
> +extern int range_includes_zero_p (tree, tree);
> +extern bool infer_value_range (gimple *, tree, tree_code *, tree *);
> +
> #endif /* GCC_TREE_VRP_H */
> diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> index 3b38ab6e941..20bd6c57a6c 100644
> --- a/gcc/vr-values.h
> +++ b/gcc/vr-values.h
> @@ -116,4 +116,6 @@ class vr_values
> bool simplify_stmt_using_ranges (gimple_stmt_iterator *);
> };
>
> +#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
> +
> #endif /* GCC_VR_VALUES_H */
>