diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f25c00b5703..e447aabb367 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2019-08-16 Richard Biener + + * tree-ssa-forwprop.c (simplify_builtin_call): Do not remove + stmt at gsi_p, instead replace it with a NOP removed later. + (pass_forwprop::execute): Fully propagate lattice, DCE stmts + that became dead because of that. + 2019-08-16 Aldy Hernandez * gimple-ssa-evrp-analyze.c (record_ranges_from_phis): Skip PHIs diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 3ddb00728a5..e745f48bddd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,8 @@ +2019-08-16 Richard Biener + + * trans-intrinsic.c (gfc_conv_intrinsic_findloc): Initialize + forward_branch to avoid bogus uninitialized warning. + 2019-08-15 Thomas Koenig PR fortran/91443 diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 8f64c387258..26ea624101d 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5428,7 +5428,7 @@ gfc_conv_intrinsic_findloc (gfc_se *se, gfc_expr *expr) tree type; tree tmp; tree found; - tree forward_branch; + tree forward_branch = NULL_TREE; tree back_branch; gfc_loopinfo loop; gfc_ss *arrayss; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a5870f6022c..cbe637eaca1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-08-16 Richard Biener + + * gcc.dg/tree-ssa/forwprop-31.c: Adjust. + 2019-08-16 Martin Liska PR ipa/91447 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c index e146ade61af..edf80264884 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-31.c @@ -9,7 +9,6 @@ int foo (int x) return w - z; /* becomes 0 */ } -/* The original y = 0 stmt is also retained. */ -/* { dg-final { scan-tree-dump-times "= 0;" 2 "forwprop1" } } */ -/* { dg-final { scan-tree-dump-times "-" 0 "forwprop1" } } */ -/* { dg-final { scan-tree-dump-times "\\+" 1 "forwprop1" } } */ +/* Only z = x + 1 is retained. */ +/* { dg-final { scan-tree-dump-times " = " 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump "return 0;" "forwprop1" } } */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index 2828c6be351..c464c899586 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -1403,7 +1403,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2) build_int_cst (TREE_TYPE (len1), src_len)); update_stmt (stmt1); unlink_stmt_vdef (stmt2); - gsi_remove (gsi_p, true); + gsi_replace (gsi_p, gimple_build_nop (), false); fwprop_invalidate_lattice (gimple_get_lhs (stmt2)); release_defs (stmt2); if (lhs1 && DECL_FUNCTION_CODE (callee1) == BUILT_IN_MEMPCPY) @@ -2299,13 +2299,14 @@ pass_forwprop::execute (function *fun) int postorder_num = pre_and_rev_post_order_compute_fn (cfun, NULL, postorder, false); auto_vec to_fixup; + auto_vec to_remove; to_purge = BITMAP_ALLOC (NULL); for (int i = 0; i < postorder_num; ++i) { gimple_stmt_iterator gsi; basic_block bb = BASIC_BLOCK_FOR_FN (fun, postorder[i]); - /* Propagate into PHIs and record degenerate ones in the lattice. */ + /* Record degenerate PHIs in the lattice. */ for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) { @@ -2321,17 +2322,20 @@ pass_forwprop::execute (function *fun) FOR_EACH_PHI_ARG (use_p, phi, it, SSA_OP_USE) { tree use = USE_FROM_PTR (use_p); - tree tem = fwprop_ssa_val (use); if (! first) - first = tem; - else if (! operand_equal_p (first, tem, 0)) - all_same = false; - if (tem != use - && may_propagate_copy (use, tem)) - propagate_value (use_p, tem); + first = use; + else if (! operand_equal_p (first, use, 0)) + { + all_same = false; + break; + } } if (all_same) - fwprop_set_lattice_val (res, first); + { + if (may_propagate_copy (res, first)) + to_remove.safe_push (phi); + fwprop_set_lattice_val (res, first); + } } /* Apply forward propagation to all stmts in the basic-block. @@ -2648,148 +2652,223 @@ pass_forwprop::execute (function *fun) /* Combine stmts with the stmts defining their operands. Note we update GSI within the loop as necessary. */ - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - gimple *orig_stmt = stmt; - bool changed = false; - bool was_noreturn = (is_gimple_call (stmt) - && gimple_call_noreturn_p (stmt)); /* Mark stmt as potentially needing revisiting. */ gimple_set_plf (stmt, GF_PLF_1, false); - if (fold_stmt (&gsi, fwprop_ssa_val)) + /* Substitute from our lattice. We need to do so only once. */ + bool substituted_p = false; + use_operand_p usep; + ssa_op_iter iter; + FOR_EACH_SSA_USE_OPERAND (usep, stmt, iter, SSA_OP_USE) { - changed = true; - stmt = gsi_stmt (gsi); - if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) - bitmap_set_bit (to_purge, bb->index); - if (!was_noreturn - && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) - to_fixup.safe_push (stmt); - /* Cleanup the CFG if we simplified a condition to - true or false. */ - if (gcond *cond = dyn_cast (stmt)) - if (gimple_cond_true_p (cond) - || gimple_cond_false_p (cond)) - cfg_changed = true; - update_stmt (stmt); - } - - switch (gimple_code (stmt)) - { - case GIMPLE_ASSIGN: - { - tree rhs1 = gimple_assign_rhs1 (stmt); - enum tree_code code = gimple_assign_rhs_code (stmt); - - if (code == COND_EXPR - || code == VEC_COND_EXPR) - { - /* In this case the entire COND_EXPR is in rhs1. */ - if (forward_propagate_into_cond (&gsi)) - { - changed = true; - stmt = gsi_stmt (gsi); - } - } - else if (TREE_CODE_CLASS (code) == tcc_comparison) - { - int did_something; - did_something = forward_propagate_into_comparison (&gsi); - if (maybe_clean_or_replace_eh_stmt (stmt, gsi_stmt (gsi))) - bitmap_set_bit (to_purge, bb->index); - if (did_something == 2) - cfg_changed = true; - changed = did_something != 0; - } - else if ((code == PLUS_EXPR - || code == BIT_IOR_EXPR - || code == BIT_XOR_EXPR) - && simplify_rotate (&gsi)) - changed = true; - else if (code == VEC_PERM_EXPR) - { - int did_something = simplify_permutation (&gsi); - if (did_something == 2) - cfg_changed = true; - changed = did_something != 0; - } - else if (code == BIT_FIELD_REF) - changed = simplify_bitfield_ref (&gsi); - else if (code == CONSTRUCTOR - && TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE) - changed = simplify_vector_constructor (&gsi); - break; - } - - case GIMPLE_SWITCH: - changed = simplify_gimple_switch (as_a (stmt)); - break; - - case GIMPLE_COND: - { - int did_something - = forward_propagate_into_gimple_cond (as_a (stmt)); - if (did_something == 2) - cfg_changed = true; - changed = did_something != 0; - break; - } - - case GIMPLE_CALL: - { - tree callee = gimple_call_fndecl (stmt); - if (callee != NULL_TREE - && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) - changed = simplify_builtin_call (&gsi, callee); - break; - } - - default:; - } - - if (changed) - { - /* If the stmt changed then re-visit it and the statements - inserted before it. */ - for (; !gsi_end_p (gsi); gsi_prev (&gsi)) - if (gimple_plf (gsi_stmt (gsi), GF_PLF_1)) - break; - if (gsi_end_p (gsi)) - gsi = gsi_start_bb (bb); - else - gsi_next (&gsi); - } - else - { - /* Stmt no longer needs to be revisited. */ - gimple_set_plf (stmt, GF_PLF_1, true); - - /* Fill up the lattice. */ - if (gimple_assign_single_p (stmt)) + tree use = USE_FROM_PTR (usep); + tree val = fwprop_ssa_val (use); + if (val && val != use && may_propagate_copy (use, val)) { - tree lhs = gimple_assign_lhs (stmt); - tree rhs = gimple_assign_rhs1 (stmt); - if (TREE_CODE (lhs) == SSA_NAME) - { - tree val = lhs; - if (TREE_CODE (rhs) == SSA_NAME) - val = fwprop_ssa_val (rhs); - else if (is_gimple_min_invariant (rhs)) - val = rhs; - fwprop_set_lattice_val (lhs, val); - } + propagate_value (usep, val); + substituted_p = true; + } + } + if (substituted_p + && is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == ADDR_EXPR) + recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt)); + + bool changed; + do + { + gimple *orig_stmt = stmt = gsi_stmt (gsi); + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); + changed = false; + + if (fold_stmt (&gsi, fwprop_ssa_val)) + { + changed = true; + stmt = gsi_stmt (gsi); + /* Cleanup the CFG if we simplified a condition to + true or false. */ + if (gcond *cond = dyn_cast (stmt)) + if (gimple_cond_true_p (cond) + || gimple_cond_false_p (cond)) + cfg_changed = true; } - gsi_next (&gsi); + if (changed || substituted_p) + { + if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) + bitmap_set_bit (to_purge, bb->index); + if (!was_noreturn + && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) + to_fixup.safe_push (stmt); + update_stmt (stmt); + substituted_p = false; + } + + switch (gimple_code (stmt)) + { + case GIMPLE_ASSIGN: + { + tree rhs1 = gimple_assign_rhs1 (stmt); + enum tree_code code = gimple_assign_rhs_code (stmt); + + if (code == COND_EXPR + || code == VEC_COND_EXPR) + { + /* In this case the entire COND_EXPR is in rhs1. */ + if (forward_propagate_into_cond (&gsi)) + { + changed = true; + stmt = gsi_stmt (gsi); + } + } + else if (TREE_CODE_CLASS (code) == tcc_comparison) + { + int did_something; + did_something = forward_propagate_into_comparison (&gsi); + if (maybe_clean_or_replace_eh_stmt (stmt, gsi_stmt (gsi))) + bitmap_set_bit (to_purge, bb->index); + if (did_something == 2) + cfg_changed = true; + changed = did_something != 0; + } + else if ((code == PLUS_EXPR + || code == BIT_IOR_EXPR + || code == BIT_XOR_EXPR) + && simplify_rotate (&gsi)) + changed = true; + else if (code == VEC_PERM_EXPR) + { + int did_something = simplify_permutation (&gsi); + if (did_something == 2) + cfg_changed = true; + changed = did_something != 0; + } + else if (code == BIT_FIELD_REF) + changed = simplify_bitfield_ref (&gsi); + else if (code == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE) + changed = simplify_vector_constructor (&gsi); + break; + } + + case GIMPLE_SWITCH: + changed = simplify_gimple_switch (as_a (stmt)); + break; + + case GIMPLE_COND: + { + int did_something = forward_propagate_into_gimple_cond + (as_a (stmt)); + if (did_something == 2) + cfg_changed = true; + changed = did_something != 0; + break; + } + + case GIMPLE_CALL: + { + tree callee = gimple_call_fndecl (stmt); + if (callee != NULL_TREE + && fndecl_built_in_p (callee, BUILT_IN_NORMAL)) + changed = simplify_builtin_call (&gsi, callee); + break; + } + + default:; + } + + if (changed) + { + /* If the stmt changed then re-visit it and the statements + inserted before it. */ + for (; !gsi_end_p (gsi); gsi_prev (&gsi)) + if (gimple_plf (gsi_stmt (gsi), GF_PLF_1)) + break; + if (gsi_end_p (gsi)) + gsi = gsi_start_bb (bb); + else + gsi_next (&gsi); + } } + while (changed); + + /* Stmt no longer needs to be revisited. */ + stmt = gsi_stmt (gsi); + gcc_checking_assert (!gimple_plf (stmt, GF_PLF_1)); + gimple_set_plf (stmt, GF_PLF_1, true); + + /* Fill up the lattice. */ + if (gimple_assign_single_p (stmt)) + { + tree lhs = gimple_assign_lhs (stmt); + tree rhs = gimple_assign_rhs1 (stmt); + if (TREE_CODE (lhs) == SSA_NAME) + { + tree val = lhs; + if (TREE_CODE (rhs) == SSA_NAME) + val = fwprop_ssa_val (rhs); + else if (is_gimple_min_invariant (rhs)) + val = rhs; + /* If we can propagate the lattice-value mark the + stmt for removal. */ + if (val != lhs + && may_propagate_copy (lhs, val)) + to_remove.safe_push (stmt); + fwprop_set_lattice_val (lhs, val); + } + } + else if (gimple_nop_p (stmt)) + to_remove.safe_push (stmt); } + + /* Substitute in destination PHI arguments. */ + edge_iterator ei; + edge e; + FOR_EACH_EDGE (e, ei, bb->succs) + for (gphi_iterator gsi = gsi_start_phis (e->dest); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gphi *phi = gsi.phi (); + use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e); + tree arg = USE_FROM_PTR (use_p); + if (TREE_CODE (arg) != SSA_NAME + || virtual_operand_p (arg)) + continue; + tree val = fwprop_ssa_val (arg); + if (val != arg + && may_propagate_copy (arg, val)) + propagate_value (use_p, val); + } } free (postorder); lattice.release (); + /* Remove stmts in reverse order to make debug stmt creation possible. */ + while (!to_remove.is_empty()) + { + gimple *stmt = to_remove.pop (); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Removing dead stmt "); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "\n"); + } + gimple_stmt_iterator gsi = gsi_for_stmt (stmt); + if (gimple_code (stmt) == GIMPLE_PHI) + remove_phi_node (&gsi, true); + else + { + unlink_stmt_vdef (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + } + } + /* Fixup stmts that became noreturn calls. This may require splitting blocks and thus isn't possible during the walk. Do this in reverse order so we don't inadvertedly remove a stmt we want to