From 42cef3f7abc956ece46e4303e3a6d68464dde99c Mon Sep 17 00:00:00 2001
From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org>
Date: Tue, 23 Aug 2016 16:18:30 +1000
Subject: [PATCH 1/3] Add early-vrp
---
gcc/doc/invoke.texi | 5 +
gcc/passes.def | 1 +
gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C | 2 +-
gcc/testsuite/g++.dg/warn/pr33738.C | 4 +-
gcc/testsuite/gcc.dg/tree-ssa/evrp1.c | 13 +
gcc/testsuite/gcc.dg/tree-ssa/evrp2.c | 18 ++
gcc/testsuite/gcc.dg/tree-ssa/evrp3.c | 15 +
gcc/testsuite/gcc.dg/tree-ssa/pr20657.c | 4 +-
gcc/testsuite/gcc.dg/tree-ssa/pr22117.c | 2 +-
gcc/testsuite/gcc.dg/tree-ssa/pr37508.c | 2 +-
gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c | 8 +-
gcc/testsuite/gcc.dg/tree-ssa/pr64130.c | 6 +-
gcc/testsuite/gcc.dg/tree-ssa/vrp04.c | 2 +-
gcc/testsuite/gcc.dg/tree-ssa/vrp06.c | 4 +-
gcc/testsuite/gcc.dg/tree-ssa/vrp16.c | 4 +-
gcc/testsuite/gcc.dg/tree-ssa/vrp25.c | 4 +-
gcc/testsuite/gcc.dg/tree-ssa/vrp67.c | 2 +-
gcc/timevar.def | 1 +
gcc/tree-pass.h | 1 +
gcc/tree-ssa-propagate.c | 2 +-
gcc/tree-ssa-propagate.h | 1 +
gcc/tree-vrp.c | 467 ++++++++++++++++++++++++++----
22 files changed, 492 insertions(+), 76 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp2.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/evrp3.c
@@ -12454,6 +12454,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.
@@ -89,6 +89,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);
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1" } */
+/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */
#include <new>
@@ -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;
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
new file mode 100644
@@ -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" } } */
+
@@ -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"} } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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" } } */
@@ -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")
@@ -440,6 +440,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);
@@ -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;
@@ -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 */
@@ -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 }
@@ -1455,44 +1457,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);
@@ -1538,15 +1513,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
{
@@ -1730,6 +1705,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
@@ -6947,19 +6957,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)
{
@@ -7010,6 +7025,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;
}
@@ -10500,6 +10517,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. */
@@ -10546,17 +10579,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;
}
@@ -10627,9 +10945,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);
@@ -10727,3 +11047,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);
+}
+
--
2.7.4