vr-values.h (VR_INITIALIZER): Move #define here.
* vr-values.h (VR_INITIALIZER): Move #define here. * gimple-ssa-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. From-SVN: r254639
This commit is contained in:
parent
54df588530
commit
16207ddd2e
6 changed files with 672 additions and 594 deletions
|
@ -1,3 +1,18 @@
|
|||
2017-11-10 Jeff Law <law@redhat.com>
|
||||
|
||||
* vr-values.h (VR_INITIALIZER): Move #define here.
|
||||
* gimple-ssa-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.
|
||||
|
||||
2017-11-10 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
* auto-profile.c (afdo_indirect_call): Drop frequency.
|
||||
|
|
|
@ -1301,6 +1301,7 @@ OBJS = \
|
|||
gimple-low.o \
|
||||
gimple-pretty-print.o \
|
||||
gimple-ssa-backprop.o \
|
||||
gimple-ssa-evrp.o \
|
||||
gimple-ssa-isolate-paths.o \
|
||||
gimple-ssa-nonnull-compare.o \
|
||||
gimple-ssa-split-paths.o \
|
||||
|
|
624
gcc/gimple-ssa-evrp.c
Normal file
624
gcc/gimple-ssa-evrp.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
600
gcc/tree-vrp.c
600
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue