diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c7f108013e3..fe7376ebf1b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2016-09-21 Kugan Vivekanandarajah + + * 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 * config/i386/i386.md (mult->ashift peephole2s): Use pow2p_hwi diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index d171cfd9aeb..05566ba62a0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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. diff --git a/gcc/passes.def b/gcc/passes.def index e98a719fc2b..6a83371f8c2 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -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); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 89024bb89d0..4efb5894b56 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,23 @@ +2016-09-21 Kugan Vivekanandarajah + + * 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 PR target/77621 diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C index 5e095831be8..cf4ed33dd50 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr31146-2.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fdump-tree-forwprop1" } */ +/* { dg-options "-O -fno-tree-vrp -fdump-tree-forwprop1" } */ #include diff --git a/gcc/testsuite/g++.dg/warn/pr33738.C b/gcc/testsuite/g++.dg/warn/pr33738.C index 60ee0b48412..73e98d5e083 100644 --- a/gcc/testsuite/g++.dg/warn/pr33738.C +++ b/gcc/testsuite/g++.dg/warn/pr33738.C @@ -15,11 +15,11 @@ int GetM1() { int main() { a2 = static_cast(GetM1()); - if (a2 == -1) { // { dg-warning "always false due" } + if (a2 == -1) { // { dg-warning "always false due" "" { xfail *-*-* } } */ link_error (); } a2 = static_cast(GetM1()); - if (-1 == a2) { // { dg-warning "always false due" } + if (-1 == a2) { // { dg-warning "always false due" "" { xfail *-*-* } } */ link_error (); } return 0; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c new file mode 100644 index 00000000000..8c6e4e60a66 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c new file mode 100644 index 00000000000..e6d423555c1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp2.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c new file mode 100644 index 00000000000..1a3bbd52aa0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp3.c @@ -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" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c index 727ca4c116a..e67823150da 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr20657.c @@ -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"} } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c index 7efdd634fff..01cd33e9581 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr22117.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c index 0963cd99281..2ba09afe481 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr37508.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c index ffa00a7e674..e44dc576c51 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr61839_2.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c index 0b254660c99..f39bd179a8c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64130.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c index 61b7a47a194..67f8f01139e 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp04.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c index cdad534ef04..c4ce1703f55 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp06.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c index 8f5d5c85b93..d09f3aea46a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp16.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c index cbc4ec354c4..a49f0793f96 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp25.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c index ef5e8f9b58e..5155f7b6daf 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp67.c @@ -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" } } */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 5f121182e14..88378328a79 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -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") diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index cc87b184d67..251b30ffcdf 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -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); diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index c8cf0783e10..97cfde57c9d 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -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; diff --git a/gcc/tree-ssa-propagate.h b/gcc/tree-ssa-propagate.h index 30d66a9742c..1a969765f09 100644 --- a/gcc/tree-ssa-propagate.h +++ b/gcc/tree-ssa-propagate.h @@ -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 */ diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index e7067ab8e6e..e779759d381 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -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 > stack; + bitmap need_eh_cleanup; + vec 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); +} +