Add Early VRP

gcc/ChangeLog:

2016-09-21  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* doc/invoke.texi: Document -fdump-tree-evrp.
	* passes.def: Define new pass_early_vrp.
	* timevar.def: Define new TV_TREE_EARLY_VRP.
	* tree-pass.h (make_pass_early_vrp): New.
	* tree-ssa-propagate.c: Make replace_uses_in non static.
	* tree-ssa-propagate.h: Export replace_uses_in.
	* tree-vrp.c (extract_range_for_var_from_comparison_expr): New.
	(extract_range_from_assert): Factor out
	extract_range_for_var_from_comparison_expr.
	(vrp_initialize_lattice): New.
	(vrp_initialize): Factor out vrp_initialize_lattice.
	(vrp_valueize): Fix it to reject complex value ranges.
	(vrp_free_lattice): New.
	(evrp_dom_walker::before_dom_children): Likewise.
	(evrp_dom_walker::after_dom_children): Likewise.
	(evrp_dom_walker::push_value_range): Likewise.
	(evrp_dom_walker::pop_value_range): Likewise.
	(execute_early_vrp): Likewise.
	(execute_vrp): Call vrp_initialize_lattice and
	vrp_free_lattice.
	(make_pass_early_vrp): New.


gcc/testsuite/ChangeLog:

2016-09-21  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
	does the same transformation.
	* g++.dg/warn/pr33738.C: XFAIL as optimization now happens in ccp.
	* gcc.dg/tree-ssa/evrp1.c: New test.
	* gcc.dg/tree-ssa/evrp2.c: New test.
	* gcc.dg/tree-ssa/evrp3.c: New test.
	* gcc.dg/tree-ssa/pr20657.c: Check for the pattern in evrp dump.
	* gcc.dg/tree-ssa/pr22117.c: Likewise.
	* gcc.dg/tree-ssa/pr61839_2.c: Likewise.
	* gcc.dg/tree-ssa/pr64130.c: Likewise.
	* gcc.dg/tree-ssa/pr37508.c: Change the pattern to be checked as
	foling now happens early.
	* gcc.dg/tree-ssa/vrp04.c: Likewise.
	* gcc.dg/tree-ssa/vrp06.c: Likewise.
	* gcc.dg/tree-ssa/vrp16.c: Likewise.
	* gcc.dg/tree-ssa/vrp25.c: Likewise.
	* gcc.dg/tree-ssa/vrp67.c: Likewise.

From-SVN: r240291
This commit is contained in:
Kugan Vivekanandarajah 2016-09-20 23:23:55 +00:00 committed by Kugan Vivekanandarajah
parent aa9baacfc9
commit 973625a04b
24 changed files with 536 additions and 76 deletions

View File

@ -1,3 +1,27 @@
2016-09-21 Kugan Vivekanandarajah <kuganv@linaro.org>
* doc/invoke.texi: Document -fdump-tree-evrp.
* passes.def: Define new pass_early_vrp.
* timevar.def: Define new TV_TREE_EARLY_VRP.
* tree-pass.h (make_pass_early_vrp): New.
* tree-ssa-propagate.c: Make replace_uses_in non static.
* tree-ssa-propagate.h: Export replace_uses_in.
* tree-vrp.c (extract_range_for_var_from_comparison_expr): New.
(extract_range_from_assert): Factor out
extract_range_for_var_from_comparison_expr.
(vrp_initialize_lattice): New.
(vrp_initialize): Factor out vrp_initialize_lattice.
(vrp_valueize): Fix it to reject complex value ranges.
(vrp_free_lattice): New.
(evrp_dom_walker::before_dom_children): Likewise.
(evrp_dom_walker::after_dom_children): Likewise.
(evrp_dom_walker::push_value_range): Likewise.
(evrp_dom_walker::pop_value_range): Likewise.
(execute_early_vrp): Likewise.
(execute_vrp): Call vrp_initialize_lattice and
vrp_free_lattice.
(make_pass_early_vrp): New.
2016-09-20 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (mult->ashift peephole2s): Use pow2p_hwi

View File

@ -12523,6 +12523,11 @@ is made by appending @file{.slp} to the source file name.
Dump each function after Value Range Propagation (VRP). The file name
is made by appending @file{.vrp} to the source file name.
@item early vrp
@opindex fdump-tree-evrp
Dump each function after Early Value Range Propagation (EVRP). The file name
is made by appending @file{.evrp} to the source file name.
@item oaccdevlow
@opindex fdump-tree-oaccdevlow
Dump each function after applying device-specific OpenACC transformations.

View File

@ -90,6 +90,7 @@ along with GCC; see the file COPYING3. If not see
execute TODO_rebuild_alias at this point. */
NEXT_PASS (pass_build_ealias);
NEXT_PASS (pass_fre);
NEXT_PASS (pass_early_vrp);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_dse);
NEXT_PASS (pass_cd_dce);

View File

@ -1,3 +1,23 @@
2016-09-21 Kugan Vivekanandarajah <kuganv@linaro.org>
* g++.dg/tree-ssa/pr31146-2.C: Run with -fno-tree-evrp as evrp also
does the same transformation.
* g++.dg/warn/pr33738.C: XFAIL as optimization now happens in ccp.
* gcc.dg/tree-ssa/evrp1.c: New test.
* gcc.dg/tree-ssa/evrp2.c: New test.
* gcc.dg/tree-ssa/evrp3.c: New test.
* gcc.dg/tree-ssa/pr20657.c: Check for the pattern in evrp dump.
* gcc.dg/tree-ssa/pr22117.c: Likewise.
* gcc.dg/tree-ssa/pr61839_2.c: Likewise.
* gcc.dg/tree-ssa/pr64130.c: Likewise.
* gcc.dg/tree-ssa/pr37508.c: Change the pattern to be checked as
foling now happens early.
* gcc.dg/tree-ssa/vrp04.c: Likewise.
* gcc.dg/tree-ssa/vrp06.c: Likewise.
* gcc.dg/tree-ssa/vrp16.c: Likewise.
* gcc.dg/tree-ssa/vrp25.c: Likewise.
* gcc.dg/tree-ssa/vrp67.c: Likewise.
2016-09-20 Uros Bizjak <ubizjak@gmail.com>
PR target/77621

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-forwprop1" } */
/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
#include <new>

View File

@ -15,11 +15,11 @@ int GetM1() {
int main() {
a2 = static_cast<Alpha>(GetM1());
if (a2 == -1) { // { dg-warning "always false due" }
if (a2 == -1) { // { dg-warning "always false due" "" { xfail *-*-* } } */
link_error ();
}
a2 = static_cast<Alpha>(GetM1());
if (-1 == a2) { // { dg-warning "always false due" }
if (-1 == a2) { // { dg-warning "always false due" "" { xfail *-*-* } } */
link_error ();
}
return 0;

View File

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
int foo (int i);
int bar (int j)
{
if (j > 2)
return foo (j + 2);
else
return j;
}
/* { dg-final { scan-tree-dump "\\\[5, \\+INF" "evrp" } } */

View File

@ -0,0 +1,18 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
int foo (int i);
int bar2 (int j)
{
if (j > 2)
{
if (j < 7)
return foo (j + 1);
else
return foo (j + 2);
}
return j;
}
/* { dg-final { scan-tree-dump "\\\[4, 7\\\]" "evrp" } } */

View File

@ -0,0 +1,15 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
int foo (int i);
void bar (int j)
{
unsigned int i;
for (i = 0; i < 10; ++i)
{
bar (i + 1);
}
}
/* { dg-final { scan-tree-dump "\\\[1, 10\\\]" "evrp" } } */

View File

@ -3,7 +3,7 @@
statement, which was needed to eliminate the second "if" statement. */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-vrp1-details" } */
/* { dg-options "-O2 -fno-tree-dominator-opts -fno-tree-fre -fdump-tree-evrp" } */
int
foo (int a)
@ -14,4 +14,4 @@ foo (int a)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 1 "vrp1"} } */
/* { dg-final { scan-tree-dump-times "if" 1 "evrp"} } */

View File

@ -21,4 +21,4 @@ foo (int *p, int q)
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate r_.* != 0B to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "link_error" 0 "vrp1" } } */

View File

@ -46,4 +46,4 @@ int test4 (struct foo2 *x)
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding" 2 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if" 2 "vrp1" } } */

View File

@ -1,6 +1,6 @@
/* PR tree-optimization/61839. */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
/* { dg-require-effective-target int32plus } */
__attribute__ ((noinline))
@ -47,8 +47,8 @@ int bar2 ()
/* Dont optimize 972195717 / 0 in function foo. */
/* { dg-final { scan-tree-dump-times "972195717 / _" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "972195717 / _" 1 "evrp" } } */
/* Dont optimize 972195717 % 0 in function bar. */
/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "972195717 % _" 1 "evrp" } } */
/* Optimize in function bar2. */
/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "972195715 % _" 0 "evrp" } } */

View File

@ -1,6 +1,6 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp1" } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
int funsigned (unsigned a)
{
@ -13,6 +13,6 @@ int funsigned2 (unsigned a)
return (-1 * 0x1ffffffffL) / a == 0;
}
/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "vrp1" } } */
/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "vrp1" } } */
/* { dg-final { scan-tree-dump ": \\\[2, 8589934591\\\]" "evrp" } } */
/* { dg-final { scan-tree-dump ": \\\[-8589934591, -2\\\]" "evrp" } } */

View File

@ -10,4 +10,4 @@ foo (int a, int b)
return a + b;
}
/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if" 1 "vrp1" } } */

View File

@ -28,6 +28,6 @@ foo (int i, int j, int a)
return i + a + j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate j_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate \[i|j\]_\[0-9\]+.*0 to 1" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate i_\[0-9]+.*j_\[0-9\]+.* to 0" 1 "vrp1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-evrp" } */
extern void abort (void) __attribute__ ((__noreturn__));
@ -19,5 +19,5 @@ nonlocal_mentioned_p (rtx x)
abort ();
}
/* { dg-final { scan-tree-dump-times "Folding predicate .*to 0" 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if" 0 "evrp" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1-details" } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp1" } */
extern void abort ();
extern void arf ();
@ -49,5 +49,5 @@ L9:
/* The second test of (code1 != 53) and the test (D18670 <= 2) are
both totally subsumed by earlier tests and thus should be folded
away using VRP. */
/* { dg-final { scan-tree-dump-times "Folding predicate" 2 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */

View File

@ -36,4 +36,4 @@ unsigned baz (unsigned i)
return i;
}
/* { dg-final { scan-tree-dump-times "Folding predicate" 3 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if" 3 "vrp1" } } */

View File

@ -149,6 +149,7 @@ DEFTIMEVAR (TV_TREE_CFG , "tree CFG construction")
DEFTIMEVAR (TV_TREE_CLEANUP_CFG , "tree CFG cleanup")
DEFTIMEVAR (TV_TREE_TAIL_MERGE , "tree tail merge")
DEFTIMEVAR (TV_TREE_VRP , "tree VRP")
DEFTIMEVAR (TV_TREE_EARLY_VRP , "tree Early VRP")
DEFTIMEVAR (TV_TREE_COPY_PROP , "tree copy propagation")
DEFTIMEVAR (TV_FIND_REFERENCED_VARS , "tree find ref. vars")
DEFTIMEVAR (TV_TREE_PTA , "tree PTA")

View File

@ -441,6 +441,7 @@ extern gimple_opt_pass *make_pass_fre (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_check_data_deps (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_copy_prop (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_isolate_erroneous_paths (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_early_vrp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_vrp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_uncprop (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_return_slot (gcc::context *ctxt);

View File

@ -863,7 +863,7 @@ static struct prop_stats_d prop_stats;
/* Replace USE references in statement STMT with the values stored in
PROP_VALUE. Return true if at least one reference was replaced. */
static bool
bool
replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value)
{
bool replaced = false;

View File

@ -84,5 +84,6 @@ extern void propagate_value (use_operand_p, tree);
extern void replace_exp (use_operand_p, tree);
extern void propagate_tree_value (tree *, tree);
extern void propagate_tree_value_into_stmt (gimple_stmt_iterator *, tree);
extern bool replace_uses_in (gimple *stmt, ssa_prop_get_value_fn get_value);
#endif /* _TREE_SSA_PROPAGATE_H */

View File

@ -60,6 +60,8 @@ along with GCC; see the file COPYING3. If not see
#include "case-cfn-macros.h"
#include "params.h"
#include "alloc-pool.h"
#include "domwalk.h"
#include "tree-cfgcleanup.h"
#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
@ -1461,44 +1463,17 @@ op_with_boolean_value_range_p (tree op)
&& integer_onep (vr->max));
}
/* Extract value range information from an ASSERT_EXPR EXPR and store
it in *VR_P. */
/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
true and store it in *VR_P. */
static void
extract_range_from_assert (value_range *vr_p, tree expr)
extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
tree op, tree limit,
value_range *vr_p)
{
tree var, cond, limit, min, max, type;
tree min, max, type;
value_range *limit_vr;
enum tree_code cond_code;
var = ASSERT_EXPR_VAR (expr);
cond = ASSERT_EXPR_COND (expr);
gcc_assert (COMPARISON_CLASS_P (cond));
/* Find VAR in the ASSERT_EXPR conditional. */
if (var == TREE_OPERAND (cond, 0)
|| TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
|| TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
{
/* If the predicate is of the form VAR COMP LIMIT, then we just
take LIMIT from the RHS and use the same comparison code. */
cond_code = TREE_CODE (cond);
limit = TREE_OPERAND (cond, 1);
cond = TREE_OPERAND (cond, 0);
}
else
{
/* If the predicate is of the form LIMIT COMP VAR, then we need
to flip around the comparison code to create the proper range
for VAR. */
cond_code = swap_tree_comparison (TREE_CODE (cond));
limit = TREE_OPERAND (cond, 0);
cond = TREE_OPERAND (cond, 1);
}
limit = avoid_overflow_infinity (limit);
type = TREE_TYPE (var);
gcc_assert (limit != var);
@ -1544,15 +1519,15 @@ extract_range_from_assert (value_range *vr_p, tree expr)
as well build the range [b_4, +INF] for it.
One special case we handle is extracting a range from a
range test encoded as (unsigned)var + CST <= limit. */
if (TREE_CODE (cond) == NOP_EXPR
|| TREE_CODE (cond) == PLUS_EXPR)
if (TREE_CODE (op) == NOP_EXPR
|| TREE_CODE (op) == PLUS_EXPR)
{
if (TREE_CODE (cond) == PLUS_EXPR)
if (TREE_CODE (op) == PLUS_EXPR)
{
min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (cond, 1)),
TREE_OPERAND (cond, 1));
min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
TREE_OPERAND (op, 1));
max = int_const_binop (PLUS_EXPR, limit, min);
cond = TREE_OPERAND (cond, 0);
op = TREE_OPERAND (op, 0);
}
else
{
@ -1736,6 +1711,41 @@ extract_range_from_assert (value_range *vr_p, tree expr)
vrp_intersect_ranges (vr_p, get_value_range (var));
}
/* Extract value range information from an ASSERT_EXPR EXPR and store
it in *VR_P. */
static void
extract_range_from_assert (value_range *vr_p, tree expr)
{
tree var = ASSERT_EXPR_VAR (expr);
tree cond = ASSERT_EXPR_COND (expr);
tree limit, op;
enum tree_code cond_code;
gcc_assert (COMPARISON_CLASS_P (cond));
/* Find VAR in the ASSERT_EXPR conditional. */
if (var == TREE_OPERAND (cond, 0)
|| TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
|| TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
{
/* If the predicate is of the form VAR COMP LIMIT, then we just
take LIMIT from the RHS and use the same comparison code. */
cond_code = TREE_CODE (cond);
limit = TREE_OPERAND (cond, 1);
op = TREE_OPERAND (cond, 0);
}
else
{
/* If the predicate is of the form LIMIT COMP VAR, then we need
to flip around the comparison code to create the proper range
for VAR. */
cond_code = swap_tree_comparison (TREE_CODE (cond));
limit = TREE_OPERAND (cond, 0);
op = TREE_OPERAND (cond, 1);
}
extract_range_for_var_from_comparison_expr (var, cond_code, op,
limit, vr_p);
}
/* Extract range information from SSA name VAR and store it in VR. If
VAR has an interesting range, use it. Otherwise, create the
@ -6953,19 +6963,24 @@ stmt_interesting_for_vrp (gimple *stmt)
return false;
}
/* Initialize local data structures for VRP. */
/* Initialize VRP lattice. */
static void
vrp_initialize (void)
vrp_initialize_lattice ()
{
basic_block bb;
values_propagated = false;
num_vr_values = num_ssa_names;
vr_value = XCNEWVEC (value_range *, num_vr_values);
vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
bitmap_obstack_initialize (&vrp_equiv_obstack);
}
/* Initialization required by ssa_propagate engine. */
static void
vrp_initialize ()
{
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
{
@ -7016,6 +7031,8 @@ vrp_valueize (tree name)
{
value_range *vr = get_value_range (name);
if (vr->type == VR_RANGE
&& (TREE_CODE (vr->min) == SSA_NAME
|| is_gimple_min_invariant (vr->min))
&& vrp_operand_equal_p (vr->min, vr->max))
return vr->min;
}
@ -10506,6 +10523,22 @@ finalize_jump_threads (void)
delete equiv_stack;
}
/* Free VRP lattice. */
static void
vrp_free_lattice ()
{
/* Free allocated memory. */
free (vr_value);
free (vr_phi_edge_counts);
bitmap_obstack_release (&vrp_equiv_obstack);
vrp_value_range_pool.release ();
/* So that we can distinguish between VRP data being available
and not available. */
vr_value = NULL;
vr_phi_edge_counts = NULL;
}
/* Traverse all the blocks folding conditionals with known ranges. */
@ -10552,17 +10585,302 @@ vrp_finalize (bool warn_array_bounds_p)
/* We must identify jump threading opportunities before we release
the datastructures built by VRP. */
identify_jump_threads ();
}
/* Free allocated memory. */
free (vr_value);
free (vr_phi_edge_counts);
bitmap_obstack_release (&vrp_equiv_obstack);
vrp_value_range_pool.release ();
/* 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. */
/* So that we can distinguish between VRP data being available
and not available. */
vr_value = NULL;
vr_phi_edge_counts = NULL;
class evrp_dom_walker : public dom_walker
{
public:
evrp_dom_walker ()
: dom_walker (CDI_DOMINATORS), stack (10)
{
stmts_to_fixup.create (0);
need_eh_cleanup = BITMAP_ALLOC (NULL);
}
~evrp_dom_walker ()
{
stmts_to_fixup.release ();
BITMAP_FREE (need_eh_cleanup);
}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
void push_value_range (const_tree var, value_range *vr);
value_range *pop_value_range (const_tree var);
/* Cond_stack holds the old VR. */
auto_vec<std::pair <const_tree, value_range*> > stack;
bitmap need_eh_cleanup;
vec<gimple *> stmts_to_fixup;
};
/* 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)
{
value_range *new_vr = NULL;
tree op0 = NULL_TREE;
push_value_range (NULL_TREE, NULL);
if (single_pred_p (bb))
{
edge e = single_pred_edge (bb);
value_range vr = VR_INITIALIZER;
gimple *stmt = last_stmt (e->src);
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))))
{
/* Entering a new scope. Try to see if we can find a VR
here. */
tree op1 = gimple_cond_rhs (stmt);
tree_code code = gimple_cond_code (stmt);
value_range *old_vr = get_value_range (op0);
if (TREE_OVERFLOW_P (op1))
op1 = drop_tree_overflow (op1);
/* If condition is false, invert the cond. */
if (e->flags & EDGE_FALSE_VALUE)
code = invert_tree_comparison (gimple_cond_code (stmt),
HONOR_NANS (op0));
/* Discover VR when condition is true. */
extract_range_for_var_from_comparison_expr (op0, code, op0, op1, &vr);
if (old_vr->type == VR_RANGE || old_vr->type == VR_ANTI_RANGE)
vrp_intersect_ranges (&vr, old_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)
{
new_vr = vrp_value_range_pool.allocate ();
*new_vr = vr;
push_value_range (op0, new_vr);
}
}
}
/* Visit PHI stmts and discover any new VRs possible. */
gimple_stmt_iterator gsi;
edge e;
edge_iterator ei;
bool has_unvisived_preds = false;
FOR_EACH_EDGE (e, ei, bb->preds)
if (!(e->src->flags & BB_VISITED))
{
has_unvisived_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);
value_range vr_result = VR_INITIALIZER;
if (!has_unvisived_preds
&& stmt_interesting_for_vrp (phi))
extract_range_from_phi_node (phi, &vr_result);
else
set_value_range_to_varying (&vr_result);
update_value_range (lhs, &vr_result);
}
/* Visit all other stmts and discover any new VRs possible. */
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
edge taken_edge;
tree output = NULL_TREE;
gimple *old_stmt = stmt;
bool was_noreturn = (is_gimple_call (stmt)
&& gimple_call_noreturn_p (stmt));
/* TODO, if found taken_edge, we should visit (return it) and travel
again to improve VR as done in DOM/SCCVN optimizations. It should
be done carefully as stmts might prematurely leave a BB like
in EH. */
if (stmt_interesting_for_vrp (stmt))
{
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);
else
{
tree def;
ssa_op_iter iter;
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
set_value_range_to_varying (get_value_range (def));
}
/* Try folding stmts with the VR discovered. */
bool did_replace
= replace_uses_in (stmt,
op_with_constant_singleton_value_range);
if (fold_stmt (&gsi, follow_single_use_edges)
|| did_replace)
update_stmt (gsi_stmt (gsi));
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);
}
}
def_operand_p def_p = SINGLE_SSA_DEF_OPERAND (stmt, SSA_OP_DEF);
/* Set the SSA with the value range. */
if (def_p
&& TREE_CODE (DEF_FROM_PTR (def_p)) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (DEF_FROM_PTR (def_p))))
{
tree def = DEF_FROM_PTR (def_p);
value_range *vr = get_value_range (def);
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 (def, vr->type, vr->min, vr->max);
}
}
else
{
tree def;
ssa_op_iter iter;
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
set_value_range_to_varying (get_value_range (def));
}
}
bb->flags |= BB_VISITED;
return NULL;
}
/* 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);
pop_value_range (stack.last ().first);
}
/* Push the Value Range of VAR to the stack and update it with new VR. */
void
evrp_dom_walker::push_value_range (const_tree var, value_range *vr)
{
if (vr != NULL)
{
unsigned ver = SSA_NAME_VERSION (var);
gcc_checking_assert (vr_value);
stack.safe_push (std::make_pair (var, vr_value[ver]));
if (ver < num_vr_values)
vr_value[ver] = vr;
}
else
stack.safe_push (std::make_pair (var, vr));
}
/* Pop the Value Range from the vrp_stack and update VAR with it. */
value_range *
evrp_dom_walker::pop_value_range (const_tree var)
{
value_range *vr = stack.last ().second;
if (vr != NULL)
{
unsigned ver = SSA_NAME_VERSION (var);
gcc_checking_assert (var == stack.last ().first);
gcc_checking_assert (vr_value);
if (ver < num_vr_values)
vr_value[ver] = 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;
}
vrp_initialize_lattice ();
/* Walk stmts in dominance order and propagate VRP. */
evrp_dom_walker walker;
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
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);
}
if (dump_file)
{
fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
dump_all_value_ranges (dump_file);
fprintf (dump_file, "\n");
}
vrp_free_lattice ();
scev_finalize ();
loop_optimizer_finalize ();
FOR_EACH_BB_FN (bb, cfun)
bb->flags &= ~BB_VISITED;
return 0;
}
@ -10633,9 +10951,11 @@ execute_vrp (bool warn_array_bounds_p)
/* For visiting PHI nodes we need EDGE_DFS_BACK computed. */
mark_dfs_back_edges ();
vrp_initialize_lattice ();
vrp_initialize ();
ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
vrp_finalize (warn_array_bounds_p);
vrp_free_lattice ();
free_numbers_of_iterations_estimates (cfun);
@ -10733,3 +11053,44 @@ 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);
}