From 60760c70505fd7089d4446aeea5fd3a046304eb8 Mon Sep 17 00:00:00 2001 From: rguenth Date: Fri, 13 Jun 2014 10:21:40 +0000 Subject: [PATCH] 2014-06-13 Richard Biener * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Rewrite to propagate the VN result into all uses where possible and to remove stmts becoming dead because of that. (eliminate): Generalize stmt removal handling, remove in reverse dominator order to support proper debug stmt generation. Update stmts before removing stmts. * tree-ssa-propagate.c (propagate_tree_value): Remove bogus assert. * c-c++-common/pr46562-2.c: Adjust. * g++.dg/tree-ssa/pr8781.C: Likewise. * gcc.dg/tree-ssa/ssa-fre-24.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-25.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-32.c: Likewise. * gcc.dg/tree-ssa/ssa-fre-39.c: Likewise. * gcc.dg/tree-ssa/ssa-pre-16.c: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@211625 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 11 + gcc/testsuite/ChangeLog | 10 + gcc/testsuite/c-c++-common/pr46562-2.c | 2 +- gcc/testsuite/g++.dg/tree-ssa/pr8781.C | 4 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c | 4 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c | 2 +- gcc/tree-ssa-pre.c | 673 +++++++++++++++-------------- gcc/tree-ssa-propagate.c | 5 - 11 files changed, 383 insertions(+), 334 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3ddd98c..1e30212 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2014-06-13 Richard Biener + + * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): + Rewrite to propagate the VN result into all uses where + possible and to remove stmts becoming dead because of that. + (eliminate): Generalize stmt removal handling, remove in + reverse dominator order to support proper debug stmt + generation. Update stmts before removing stmts. + * tree-ssa-propagate.c (propagate_tree_value): Remove + bogus assert. + 2014-06-13 Thomas Preud'homme PR tree-optimization/61375 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7bb2d7a..d6bb704 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2014-06-13 Richard Biener + + * c-c++-common/pr46562-2.c: Adjust. + * g++.dg/tree-ssa/pr8781.C: Likewise. + * gcc.dg/tree-ssa/ssa-fre-24.c: Likewise. + * gcc.dg/tree-ssa/ssa-fre-25.c: Likewise. + * gcc.dg/tree-ssa/ssa-fre-32.c: Likewise. + * gcc.dg/tree-ssa/ssa-fre-39.c: Likewise. + * gcc.dg/tree-ssa/ssa-pre-16.c: Likewise. + 2014-06-13 Thomas Preud'homme PR tree-optimization/61375 diff --git a/gcc/testsuite/c-c++-common/pr46562-2.c b/gcc/testsuite/c-c++-common/pr46562-2.c index 45bf5cf..e64432c 100644 --- a/gcc/testsuite/c-c++-common/pr46562-2.c +++ b/gcc/testsuite/c-c++-common/pr46562-2.c @@ -9,5 +9,5 @@ int foo(void) return *p; } -/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ +/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C index bf75413..19549c4 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */ +/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */ int f(); @@ -24,5 +24,5 @@ int x() /* We should optimize this to a direct call. */ -/* { dg-final { scan-tree-dump "converting indirect call to function int f()" "fre1" } } */ +/* { dg-final { scan-tree-dump-times "= f \\(\\);" 1 "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c index c683218..833a1b9 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c @@ -30,5 +30,5 @@ int bazzoo (void) return b.i; } -/* { dg-final { scan-tree-dump-times "= 0;" 5 "fre1" } } */ +/* { dg-final { scan-tree-dump-times "return 0;" 4 "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c index e7723f9..5317a18 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c @@ -14,5 +14,5 @@ int foo (struct X *p) /* We should optimize this to return 0. */ -/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ +/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c index 537fd5a..ad4f1d0 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c @@ -23,6 +23,6 @@ bar (_Complex float x) return z; } -/* We should CSE all the way to replace the final assignment to z with x. */ -/* { dg-final { scan-tree-dump-times "with x_1\\\(D\\\) in z" 3 "fre1" } } */ +/* We should CSE all the way to replace the return value with x. */ +/* { dg-final { scan-tree-dump-times "return x_\\d\+\\(D\\);" 2 "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c index a30926c..4c5ed0b 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c @@ -15,5 +15,5 @@ int foo (int i) /* We should be able to value-number the final assignment to k to 1. */ -/* { dg-final { scan-tree-dump "k_. = 1;" "fre1" } } */ +/* { dg-final { scan-tree-dump "return 1;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c index b087dc1..7bc1dd3 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c @@ -11,5 +11,5 @@ int foo(int k, int *x) } while (++jpreds) - if (e->flags & EDGE_EXECUTABLE) - break; - if (!e) - return; + /* ??? If we do nothing for unreachable blocks then this will confuse + tailmerging. Eventually we can reduce its reliance on SCCVN now + that we fully copy/constant-propagate (most) things. */ for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);) { - gimple stmt, phi = gsi_stmt (gsi); - tree sprime = NULL_TREE, res = PHI_RESULT (phi); - gimple_stmt_iterator gsi2; - - /* We want to perform redundant PHI elimination. Do so by - replacing the PHI with a single copy if possible. - Do not touch inserted, single-argument or virtual PHIs. */ - if (gimple_phi_num_args (phi) == 1 - || virtual_operand_p (res)) - { - gsi_next (&gsi); - continue; - } + gimple phi = gsi_stmt (gsi); + tree res = PHI_RESULT (phi); - sprime = eliminate_avail (res); - if (!sprime - || sprime == res) + if (virtual_operand_p (res)) { - eliminate_push_avail (res); gsi_next (&gsi); continue; } - else if (is_gimple_min_invariant (sprime)) - { - if (!useless_type_conversion_p (TREE_TYPE (res), - TREE_TYPE (sprime))) - sprime = fold_convert (TREE_TYPE (res), sprime); - } - if (dump_file && (dump_flags & TDF_DETAILS)) + tree sprime = eliminate_avail (res); + if (sprime + && sprime != res) { - fprintf (dump_file, "Replaced redundant PHI node defining "); - print_generic_expr (dump_file, res, 0); - fprintf (dump_file, " with "); - print_generic_expr (dump_file, sprime, 0); - fprintf (dump_file, "\n"); - } - - remove_phi_node (&gsi, false); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Replaced redundant PHI node defining "); + print_generic_expr (dump_file, res, 0); + fprintf (dump_file, " with "); + print_generic_expr (dump_file, sprime, 0); + fprintf (dump_file, "\n"); + } - if (inserted_exprs - && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)) - && TREE_CODE (sprime) == SSA_NAME) - gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); - - if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime))) - sprime = fold_convert (TREE_TYPE (res), sprime); - stmt = gimple_build_assign (res, sprime); - gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY)); - - gsi2 = gsi_after_labels (b); - gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); - /* Queue the copy for eventual removal. */ - el_to_remove.safe_push (stmt); - /* If we inserted this PHI node ourself, it's not an elimination. */ - if (inserted_exprs - && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))) - pre_stats.phis--; - else - pre_stats.eliminations++; - } + /* If we inserted this PHI node ourself, it's not an elimination. */ + if (inserted_exprs + && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))) + pre_stats.phis--; + else + pre_stats.eliminations++; - for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi)) - { - tree lhs = NULL_TREE; - tree rhs = NULL_TREE; + /* If we will propagate into all uses don't bother to do + anything. */ + if (may_propagate_copy (res, sprime)) + { + /* Mark the PHI for removal. */ + el_to_remove.safe_push (phi); + gsi_next (&gsi); + continue; + } - stmt = gsi_stmt (gsi); + remove_phi_node (&gsi, false); - if (gimple_has_lhs (stmt)) - lhs = gimple_get_lhs (stmt); + if (inserted_exprs + && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)) + && TREE_CODE (sprime) == SSA_NAME) + gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); - if (gimple_assign_single_p (stmt)) - rhs = gimple_assign_rhs1 (stmt); + if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime))) + sprime = fold_convert (TREE_TYPE (res), sprime); + gimple stmt = gimple_build_assign (res, sprime); + /* ??? It cannot yet be necessary (DOM walk). */ + gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY)); - /* Lookup the RHS of the expression, see if we have an - available computation for it. If so, replace the RHS with - the available computation. */ - if (gimple_has_lhs (stmt) - && TREE_CODE (lhs) == SSA_NAME - && !gimple_has_volatile_ops (stmt)) - { - tree sprime; - gimple orig_stmt = stmt; + gimple_stmt_iterator gsi2 = gsi_after_labels (b); + gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); + continue; + } - sprime = eliminate_avail (lhs); - /* If there is no usable leader mark lhs as leader for its value. */ - if (!sprime) - eliminate_push_avail (lhs); + eliminate_push_avail (res); + gsi_next (&gsi); + } + for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi)) + { + tree sprime = NULL_TREE; + stmt = gsi_stmt (gsi); + tree lhs = gimple_get_lhs (stmt); + if (lhs && TREE_CODE (lhs) == SSA_NAME + && !gimple_has_volatile_ops (stmt) /* See PR43491. Do not replace a global register variable when it is a the RHS of an assignment. Do replace local register variables since gcc does not guarantee a local variable will be allocated in register. - Do not perform copy propagation or undo constant propagation. */ - if (gimple_assign_single_p (stmt) - && (TREE_CODE (rhs) == SSA_NAME - || is_gimple_min_invariant (rhs) - || (TREE_CODE (rhs) == VAR_DECL - && is_global_var (rhs) - && DECL_HARD_REGISTER (rhs)))) - continue; - + ??? The fix isn't effective here. This should instead + be ensured by not value-numbering them the same but treating + them like volatiles? */ + && !(gimple_assign_single_p (stmt) + && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL + && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt)) + && is_global_var (gimple_assign_rhs1 (stmt))))) + { + sprime = eliminate_avail (lhs); if (!sprime) { /* If there is no existing usable leader but SCCVN thinks @@ -4139,107 +4112,128 @@ eliminate_dom_walker::before_dom_children (basic_block b) && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE) eliminate_push_avail (sprime); } - else if (is_gimple_min_invariant (sprime)) - { - /* If there is no existing leader but SCCVN knows this - value is constant, use that constant. */ - if (!useless_type_conversion_p (TREE_TYPE (lhs), - TREE_TYPE (sprime))) - sprime = fold_convert (TREE_TYPE (lhs), sprime); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Replaced "); - print_gimple_expr (dump_file, stmt, 0, 0); - fprintf (dump_file, " with "); - print_generic_expr (dump_file, sprime, 0); - fprintf (dump_file, " in "); - print_gimple_stmt (dump_file, stmt, 0, 0); - } - pre_stats.eliminations++; - - tree vdef = gimple_vdef (stmt); - tree vuse = gimple_vuse (stmt); - propagate_tree_value_into_stmt (&gsi, sprime); - stmt = gsi_stmt (gsi); - update_stmt (stmt); - if (vdef != gimple_vdef (stmt)) - VN_INFO (vdef)->valnum = vuse; - /* If we removed EH side-effects from the statement, clean - its EH information. */ - if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) + /* If this now constitutes a copy duplicate points-to + and range info appropriately. This is especially + important for inserted code. See tree-ssa-copy.c + for similar code. */ + if (sprime + && TREE_CODE (sprime) == SSA_NAME) + { + basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime)); + if (POINTER_TYPE_P (TREE_TYPE (lhs)) + && SSA_NAME_PTR_INFO (lhs) + && !SSA_NAME_PTR_INFO (sprime)) { - bitmap_set_bit (need_eh_cleanup, - gimple_bb (stmt)->index); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Removed EH side-effects.\n"); + duplicate_ssa_name_ptr_info (sprime, + SSA_NAME_PTR_INFO (lhs)); + if (b != sprime_b) + mark_ptr_info_alignment_unknown + (SSA_NAME_PTR_INFO (sprime)); } - continue; + else if (!POINTER_TYPE_P (TREE_TYPE (lhs)) + && SSA_NAME_RANGE_INFO (lhs) + && !SSA_NAME_RANGE_INFO (sprime) + && b == sprime_b) + duplicate_ssa_name_range_info (sprime, + SSA_NAME_RANGE_TYPE (lhs), + SSA_NAME_RANGE_INFO (lhs)); } + /* Inhibit the use of an inserted PHI on a loop header when + the address of the memory reference is a simple induction + variable. In other cases the vectorizer won't do anything + anyway (either it's loop invariant or a complicated + expression). */ if (sprime - && sprime != lhs - && (rhs == NULL_TREE - || TREE_CODE (rhs) != SSA_NAME - || may_propagate_copy (rhs, sprime))) + && TREE_CODE (sprime) == SSA_NAME + && do_pre + && flag_tree_loop_vectorize + && loop_outer (b->loop_father) + && has_zero_uses (sprime) + && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime)) + && gimple_assign_load_p (stmt)) { - bool can_make_abnormal_goto - = is_gimple_call (stmt) - && stmt_can_make_abnormal_goto (stmt); - - gcc_assert (sprime != rhs); - - /* Inhibit the use of an inserted PHI on a loop header when - the address of the memory reference is a simple induction - variable. In other cases the vectorizer won't do anything - anyway (either it's loop invariant or a complicated - expression). */ - if (do_pre - && flag_tree_loop_vectorize - && gimple_assign_single_p (stmt) - && TREE_CODE (sprime) == SSA_NAME - && loop_outer (b->loop_father)) + gimple def_stmt = SSA_NAME_DEF_STMT (sprime); + basic_block def_bb = gimple_bb (def_stmt); + if (gimple_code (def_stmt) == GIMPLE_PHI + && b->loop_father->header == def_bb) { - gimple def_stmt = SSA_NAME_DEF_STMT (sprime); - basic_block def_bb = gimple_bb (def_stmt); - if (gimple_code (def_stmt) == GIMPLE_PHI - && b->loop_father->header == def_bb - && has_zero_uses (sprime)) + ssa_op_iter iter; + tree op; + bool found = false; + FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) { - ssa_op_iter iter; - tree op; - bool found = false; - FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) + affine_iv iv; + def_bb = gimple_bb (SSA_NAME_DEF_STMT (op)); + if (def_bb + && flow_bb_inside_loop_p (b->loop_father, def_bb) + && simple_iv (b->loop_father, + b->loop_father, op, &iv, true)) { - affine_iv iv; - def_bb = gimple_bb (SSA_NAME_DEF_STMT (op)); - if (def_bb - && flow_bb_inside_loop_p (b->loop_father, - def_bb) - && simple_iv (b->loop_father, - b->loop_father, op, &iv, true)) - { - found = true; - break; - } + found = true; + break; } - if (found) + } + if (found) + { + if (dump_file && (dump_flags & TDF_DETAILS)) { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Not replacing "); - print_gimple_expr (dump_file, stmt, 0, 0); - fprintf (dump_file, " with "); - print_generic_expr (dump_file, sprime, 0); - fprintf (dump_file, " which would add a loop" - " carried dependence to loop %d\n", - b->loop_father->num); - } - continue; + fprintf (dump_file, "Not replacing "); + print_gimple_expr (dump_file, stmt, 0, 0); + fprintf (dump_file, " with "); + print_generic_expr (dump_file, sprime, 0); + fprintf (dump_file, " which would add a loop" + " carried dependence to loop %d\n", + b->loop_father->num); } + /* Don't keep sprime available. */ + eliminate_push_avail (lhs); + sprime = NULL_TREE; } } + } + + if (sprime) + { + /* If we can propagate the value computed for LHS into + all uses don't bother doing anything with this stmt. */ + if (may_propagate_copy (lhs, sprime)) + { + /* Mark it for removal. */ + el_to_remove.safe_push (stmt); + + /* ??? Don't count copy/constant propagations. */ + if (gimple_assign_single_p (stmt) + && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME + || gimple_assign_rhs1 (stmt) == sprime)) + continue; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Replaced "); + print_gimple_expr (dump_file, stmt, 0, 0); + fprintf (dump_file, " with "); + print_generic_expr (dump_file, sprime, 0); + fprintf (dump_file, " in all uses of "); + print_gimple_stmt (dump_file, stmt, 0, 0); + } + + pre_stats.eliminations++; + continue; + } + + /* If this is an assignment from our leader (which + happens in the case the value-number is a constant) + then there is nothing to do. */ + if (gimple_assign_single_p (stmt) + && sprime == gimple_assign_rhs1 (stmt)) + continue; + + /* Else replace its RHS. */ + bool can_make_abnormal_goto + = is_gimple_call (stmt) + && stmt_can_make_abnormal_goto (stmt); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -4254,16 +4248,12 @@ eliminate_dom_walker::before_dom_children (basic_block b) if (TREE_CODE (sprime) == SSA_NAME) gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); - /* We need to make sure the new and old types actually match, - which may require adding a simple cast, which fold_convert - will do for us. */ - if ((!rhs || TREE_CODE (rhs) != SSA_NAME) - && !useless_type_conversion_p (gimple_expr_type (stmt), - TREE_TYPE (sprime))) - sprime = fold_convert (gimple_expr_type (stmt), sprime); pre_stats.eliminations++; - + gimple orig_stmt = stmt; + if (!useless_type_conversion_p (TREE_TYPE (lhs), + TREE_TYPE (sprime))) + sprime = fold_convert (TREE_TYPE (lhs), sprime); tree vdef = gimple_vdef (stmt); tree vuse = gimple_vuse (stmt); propagate_tree_value_into_stmt (&gsi, sprime); @@ -4291,135 +4281,183 @@ eliminate_dom_walker::before_dom_children (basic_block b) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Removed AB side-effects.\n"); } + + continue; } } + /* If the statement is a scalar store, see if the expression - has the same value number as its rhs. If so, the store is - dead. */ - else if (gimple_assign_single_p (stmt) - && !gimple_has_volatile_ops (stmt) - && !is_gimple_reg (gimple_assign_lhs (stmt)) - && (TREE_CODE (rhs) == SSA_NAME - || is_gimple_min_invariant (rhs))) - { - tree val; - val = vn_reference_lookup (gimple_assign_lhs (stmt), - gimple_vuse (stmt), VN_WALK, NULL); - if (TREE_CODE (rhs) == SSA_NAME) - rhs = VN_INFO (rhs)->valnum; - if (val - && operand_equal_p (val, rhs, 0)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Deleted redundant store "); - print_gimple_stmt (dump_file, stmt, 0, 0); - } + has the same value number as its rhs. If so, the store is + dead. */ + if (gimple_assign_single_p (stmt) + && !gimple_has_volatile_ops (stmt) + && !is_gimple_reg (gimple_assign_lhs (stmt)) + && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME + || is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))) + { + tree val; + tree rhs = gimple_assign_rhs1 (stmt); + val = vn_reference_lookup (gimple_assign_lhs (stmt), + gimple_vuse (stmt), VN_WALK, NULL); + if (TREE_CODE (rhs) == SSA_NAME) + rhs = VN_INFO (rhs)->valnum; + if (val + && operand_equal_p (val, rhs, 0)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Deleted redundant store "); + print_gimple_stmt (dump_file, stmt, 0, 0); + } + + /* Queue stmt for removal. */ + el_to_remove.safe_push (stmt); + continue; + } + } - /* Queue stmt for removal. */ - el_to_remove.safe_push (stmt); - } - } - /* Visit COND_EXPRs and fold the comparison with the - available value-numbers. */ - else if (gimple_code (stmt) == GIMPLE_COND) + bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt); + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); + tree vdef = gimple_vdef (stmt); + tree vuse = gimple_vuse (stmt); + + /* If we didn't replace the whole stmt (or propagate the result + into all uses), replace all uses on this stmt with their + leaders. */ + use_operand_p use_p; + ssa_op_iter iter; + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE) { - tree op0 = gimple_cond_lhs (stmt); - tree op1 = gimple_cond_rhs (stmt); - tree result; - - if (TREE_CODE (op0) == SSA_NAME) - op0 = VN_INFO (op0)->valnum; - if (TREE_CODE (op1) == SSA_NAME) - op1 = VN_INFO (op1)->valnum; - result = fold_binary (gimple_cond_code (stmt), boolean_type_node, - op0, op1); - if (result && TREE_CODE (result) == INTEGER_CST) + tree use = USE_FROM_PTR (use_p); + /* ??? The call code above leaves stmt operands un-updated. */ + if (TREE_CODE (use) != SSA_NAME) + continue; + tree sprime = eliminate_avail (use); + if (sprime && sprime != use + && may_propagate_copy (use, sprime) + /* We substitute into debug stmts to avoid excessive + debug temporaries created by removed stmts, but we need + to avoid doing so for inserted sprimes as we never want + to create debug temporaries for them. */ + && (!inserted_exprs + || TREE_CODE (sprime) != SSA_NAME + || !is_gimple_debug (stmt) + || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime)))) { - if (integer_zerop (result)) - gimple_cond_make_false (stmt); - else - gimple_cond_make_true (stmt); - update_stmt (stmt); - el_todo = TODO_cleanup_cfg; + propagate_value (use_p, sprime); + gimple_set_modified (stmt, true); + if (TREE_CODE (sprime) == SSA_NAME + && !is_gimple_debug (stmt)) + gimple_set_plf (SSA_NAME_DEF_STMT (sprime), + NECESSARY, true); } } + /* Visit indirect calls and turn them into direct calls if - possible. */ + possible using the devirtualization machinery. */ if (is_gimple_call (stmt)) { - tree orig_fn = gimple_call_fn (stmt); - tree fn; - if (!orig_fn) - continue; - if (TREE_CODE (orig_fn) == SSA_NAME) - fn = VN_INFO (orig_fn)->valnum; - else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF - && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME) + tree fn = gimple_call_fn (stmt); + if (fn + && TREE_CODE (fn) == OBJ_TYPE_REF + && TREE_CODE (OBJ_TYPE_REF_EXPR (fn)) == SSA_NAME) { - fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum; - if (!gimple_call_addr_fndecl (fn)) + fn = ipa_intraprocedural_devirtualization (stmt); + if (fn && dbg_cnt (devirt)) { - fn = ipa_intraprocedural_devirtualization (stmt); - if (fn) - fn = build_fold_addr_expr (fn); + if (dump_enabled_p ()) + { + location_t loc = gimple_location (stmt); + dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, + "converting indirect call to " + "function %s\n", + cgraph_get_node (fn)->name ()); + } + gimple_call_set_fndecl (stmt, fn); + gimple_set_modified (stmt, true); } } - else - continue; - if (gimple_call_addr_fndecl (fn) != NULL_TREE - && useless_type_conversion_p (TREE_TYPE (orig_fn), - TREE_TYPE (fn)) - && dbg_cnt (devirt)) - { - bool can_make_abnormal_goto - = stmt_can_make_abnormal_goto (stmt); - bool was_noreturn = gimple_call_noreturn_p (stmt); - - if (dump_enabled_p ()) - { - location_t loc = gimple_location (stmt); - dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, - "converting indirect call to function %s\n", - cgraph_get_node (gimple_call_addr_fndecl (fn))->name ()); - } - - gimple_call_set_fn (stmt, fn); - tree vdef = gimple_vdef (stmt); - tree vuse = gimple_vuse (stmt); - update_stmt (stmt); - if (vdef != gimple_vdef (stmt)) - VN_INFO (vdef)->valnum = vuse; + } + if (gimple_modified_p (stmt)) + { + /* If a formerly non-invariant ADDR_EXPR is turned into an + invariant one it was on a separate stmt. */ + if (gimple_assign_single_p (stmt) + && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR) + recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt)); + gimple old_stmt = stmt; + if (is_gimple_call (stmt)) + { + /* ??? Only fold calls inplace for now, this may create new + SSA names which in turn will confuse free_scc_vn SSA name + release code. */ + fold_stmt_inplace (&gsi); /* When changing a call into a noreturn call, cfg cleanup is needed to fix up the noreturn call. */ if (!was_noreturn && gimple_call_noreturn_p (stmt)) el_todo |= TODO_cleanup_cfg; + } + else + { + fold_stmt (&gsi); + stmt = gsi_stmt (gsi); + if ((gimple_code (stmt) == GIMPLE_COND + && (gimple_cond_true_p (stmt) + || gimple_cond_false_p (stmt))) + || (gimple_code (stmt) == GIMPLE_SWITCH + && TREE_CODE (gimple_switch_index (stmt)) == INTEGER_CST)) + el_todo |= TODO_cleanup_cfg; + } + /* If we removed EH side-effects from the statement, clean + its EH information. */ + if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) + { + bitmap_set_bit (need_eh_cleanup, + gimple_bb (stmt)->index); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Removed EH side-effects.\n"); + } + /* Likewise for AB side-effects. */ + if (can_make_abnormal_goto + && !stmt_can_make_abnormal_goto (stmt)) + { + bitmap_set_bit (need_ab_cleanup, + gimple_bb (stmt)->index); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Removed AB side-effects.\n"); + } + update_stmt (stmt); + if (vdef != gimple_vdef (stmt)) + VN_INFO (vdef)->valnum = vuse; + } - /* If we removed EH side-effects from the statement, clean - its EH information. */ - if (maybe_clean_or_replace_eh_stmt (stmt, stmt)) - { - bitmap_set_bit (need_eh_cleanup, - gimple_bb (stmt)->index); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Removed EH side-effects.\n"); - } - - /* Likewise for AB side-effects. */ - if (can_make_abnormal_goto - && !stmt_can_make_abnormal_goto (stmt)) - { - bitmap_set_bit (need_ab_cleanup, - gimple_bb (stmt)->index); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " Removed AB side-effects.\n"); - } + /* Make the new value available - for fully redundant LHS we + continue with the next stmt above. */ + if (lhs && TREE_CODE (lhs) == SSA_NAME) + eliminate_push_avail (lhs); + } - /* Changing an indirect call to a direct call may - have exposed different semantics. This may - require an SSA update. */ - el_todo |= TODO_update_ssa_only_virtuals; + /* Replace destination PHI arguments. */ + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, b->succs) + { + for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple phi = gsi_stmt (gsi); + 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 sprime = eliminate_avail (arg); + if (sprime && may_propagate_copy (arg, sprime)) + { + propagate_value (use_p, sprime); + if (TREE_CODE (sprime) == SSA_NAME) + gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); } } } @@ -4442,7 +4480,6 @@ eliminate (bool do_pre) { gimple_stmt_iterator gsi; gimple stmt; - unsigned i; need_eh_cleanup = BITMAP_ALLOC (NULL); need_ab_cleanup = BITMAP_ALLOC (NULL); @@ -4460,41 +4497,37 @@ eliminate (bool do_pre) /* We cannot remove stmts during BB walk, especially not release SSA names there as this confuses the VN machinery. The stmts ending - up in el_to_remove are either stores or simple copies. */ - FOR_EACH_VEC_ELT (el_to_remove, i, stmt) + up in el_to_remove are either stores or simple copies. + Remove stmts in reverse order to make debug stmt creation possible. */ + while (!el_to_remove.is_empty ()) { - tree lhs = gimple_assign_lhs (stmt); - tree rhs = gimple_assign_rhs1 (stmt); - use_operand_p use_p; - gimple use_stmt; - - /* If there is a single use only, propagate the equivalency - instead of keeping the copy. */ - if (TREE_CODE (lhs) == SSA_NAME - && TREE_CODE (rhs) == SSA_NAME - && single_imm_use (lhs, &use_p, &use_stmt) - && may_propagate_copy (USE_FROM_PTR (use_p), rhs)) + stmt = el_to_remove.pop (); + + if (dump_file && (dump_flags & TDF_DETAILS)) { - SET_USE (use_p, rhs); - update_stmt (use_stmt); - if (inserted_exprs - && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs)) - && TREE_CODE (rhs) == SSA_NAME) - gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true); + fprintf (dump_file, "Removing dead stmt "); + print_gimple_stmt (dump_file, stmt, 0, 0); } - /* If this is a store or a now unused copy, remove it. */ - if (TREE_CODE (lhs) != SSA_NAME - || has_zero_uses (lhs)) + tree lhs; + if (gimple_code (stmt) == GIMPLE_PHI) + lhs = gimple_phi_result (stmt); + else + lhs = gimple_get_lhs (stmt); + + if (inserted_exprs + && TREE_CODE (lhs) == SSA_NAME) + bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs)); + + gsi = gsi_for_stmt (stmt); + if (gimple_code (stmt) == GIMPLE_PHI) + remove_phi_node (&gsi, true); + else { basic_block bb = gimple_bb (stmt); - gsi = gsi_for_stmt (stmt); unlink_stmt_vdef (stmt); if (gsi_remove (&gsi, true)) bitmap_set_bit (need_eh_cleanup, bb->index); - if (inserted_exprs - && TREE_CODE (lhs) == SSA_NAME) - bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs)); release_defs (stmt); } } diff --git a/gcc/tree-ssa-propagate.c b/gcc/tree-ssa-propagate.c index 1988835..255bff9 100644 --- a/gcc/tree-ssa-propagate.c +++ b/gcc/tree-ssa-propagate.c @@ -1410,11 +1410,6 @@ replace_exp (use_operand_p op_p, tree val) void propagate_tree_value (tree *op_p, tree val) { - gcc_checking_assert (!(TREE_CODE (val) == SSA_NAME - && *op_p - && TREE_CODE (*op_p) == SSA_NAME - && !may_propagate_copy (*op_p, val))); - if (TREE_CODE (val) == SSA_NAME) *op_p = val; else -- 2.7.4