This makes FRE/PRE substitute values into all uses instead of leaving copies and initializations from constants in the IL which requires a copyprop pass to clean up things (which we usually place directly after FRE/PRE).
This should open the possibility to remove some of the passes, respectively the two copy-prop passes right after the two FREs and the copyprop pass we do early in loop opts. The patch exposes a weakness in invariant motion cost computation and thus gfortran.dg/vect/fast-math-vect-8.f90 fails for me on i?86 (but not on x86_64). I want to revisit some of the ???s and uglinesses in the patch, but this is a state that passes bootstrap and regtest otherwise and thus ready. Any comments? Thanks, Richard. 2014-05-14 Richard Biener <rguent...@suse.de> * 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. * 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-pre-16.c: Likewise. Index: trunk/gcc/tree-ssa-pre.c =================================================================== *** trunk.orig/gcc/tree-ssa-pre.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/tree-ssa-pre.c 2014-05-14 14:20:29.068849910 +0200 *************** eliminate_dom_walker::before_dom_childre *** 4012,4120 **** 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; } ! sprime = eliminate_avail (res); ! if (!sprime ! || sprime == 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)) { ! 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 (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++; } for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi)) { ! tree lhs = NULL_TREE; ! tree rhs = NULL_TREE; ! stmt = gsi_stmt (gsi); ! ! if (gimple_has_lhs (stmt)) ! lhs = gimple_get_lhs (stmt); ! ! if (gimple_assign_single_p (stmt)) ! rhs = gimple_assign_rhs1 (stmt); ! ! /* 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; ! ! sprime = eliminate_avail (lhs); ! /* If there is no usable leader mark lhs as leader for its value. */ ! if (!sprime) ! eliminate_push_avail (lhs); ! /* 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; ! if (!sprime) { /* If there is no existing usable leader but SCCVN thinks --- 4012,4163 ---- for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);) { ! gimple phi = gsi_stmt (gsi); ! tree res = PHI_RESULT (phi); ! ! if (virtual_operand_p (res)) { gsi_next (&gsi); continue; } ! tree sprime = eliminate_avail (res); ! if (sprime ! && sprime != res) { ! 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 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 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; ! } ! ! remove_phi_node (&gsi, false); ! ! 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); ! gimple stmt = gimple_build_assign (res, sprime); ! /* ??? It cannot yet be necessary (DOM walk). */ ! gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY)); ! ! gimple_stmt_iterator gsi2 = gsi_after_labels (b); ! gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); continue; } ! ! /* Inhibit the use of an inserted PHI on a loop header when ! there is a load with that value whose address is a simple induction ! variable. In other cases the vectorizer won't do anything ! anyway (either it's loop invariant or a complicated ! expression). ! ??? This is a somewhat awkward implementation give we don't ! have a mapping back from load VNs to loads. */ ! bool found = false; ! if (flag_tree_loop_vectorize ! && b->loop_father->header == b ! && loop_outer (b->loop_father) ! && inserted_exprs ! && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))) { ! basic_block *bbs = get_loop_body (b->loop_father); ! for (unsigned i = 0; i < b->loop_father->num_nodes; ++i) ! { ! basic_block bb = bbs[i]; ! for (gimple_stmt_iterator gsi2 = gsi_start_bb (bb); ! !gsi_end_p (gsi2); gsi_next (&gsi2)) ! { ! gimple stmt = gsi_stmt (gsi2); ! if (!gimple_assign_load_p (stmt) ! || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) ! continue; ! if (VN_INFO (gimple_assign_lhs (stmt))->valnum ! != VN_INFO (res)->valnum) ! continue; ! ssa_op_iter iter; ! tree op; ! FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) ! { ! affine_iv iv; ! basic_block 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; ! } ! } ! if (found) ! break; ! } ! if (found) ! break; ! } ! free (bbs); } ! if (found) { ! if (dump_file && (dump_flags & TDF_DETAILS)) ! { ! fprintf (dump_file, "Not replacing 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); ! } } else ! 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. ! ??? 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 *************** eliminate_dom_walker::before_dom_childre *** 4128,4229 **** && (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++; ! propagate_tree_value_into_stmt (&gsi, sprime); ! stmt = gsi_stmt (gsi); ! update_stmt (stmt); - /* If we removed EH side-effects from the statement, clean - its EH information. */ - if (maybe_clean_or_replace_eh_stmt (orig_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"); } - continue; - } ! if (sprime ! && sprime != lhs ! && (rhs == NULL_TREE ! || TREE_CODE (rhs) != SSA_NAME ! || may_propagate_copy (rhs, sprime))) ! { 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 (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 - && has_zero_uses (sprime)) - { - 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)) - { - found = true; - break; - } - } - if (found) - { - 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; - } - } - } - if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Replaced "); --- 4171,4243 ---- && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE) eliminate_push_avail (sprime); } ! if (sprime) { ! /* 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 (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)) ! { ! 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)); ! } ! 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)); ! } ! ! /* 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)) { fprintf (dump_file, "Replaced "); *************** eliminate_dom_walker::before_dom_childre *** 4237,4251 **** 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++; propagate_tree_value_into_stmt (&gsi, sprime); stmt = gsi_stmt (gsi); update_stmt (stmt); --- 4251,4262 ---- if (TREE_CODE (sprime) == SSA_NAME) gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); 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); propagate_tree_value_into_stmt (&gsi, sprime); stmt = gsi_stmt (gsi); update_stmt (stmt); *************** eliminate_dom_walker::before_dom_childre *** 4269,4336 **** if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Removed AB side-effects.\n"); } } } /* 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); ! } - /* 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) - { - 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) - { - if (integer_zerop (result)) - gimple_cond_make_false (stmt); - else - gimple_cond_make_true (stmt); - update_stmt (stmt); - el_todo = TODO_cleanup_cfg; - } - } /* Visit indirect calls and turn them into direct calls if possible. */ 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) --- 4280,4333 ---- 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. */ ! 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; ! } ! } ! ! bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt); ! bool was_noreturn = (is_gimple_call (stmt) ! && gimple_call_noreturn_p (stmt)); /* Visit indirect calls and turn them into direct calls if possible. */ if (is_gimple_call (stmt)) { tree orig_fn = gimple_call_fn (stmt); ! tree fn = NULL_TREE; if (!orig_fn) ! ; ! else 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) *************** eliminate_dom_walker::before_dom_childre *** 4343,4358 **** fn = build_fold_addr_expr (fn); } } ! else ! continue; ! if (gimple_call_addr_fndecl (fn) != NULL_TREE ! && useless_type_conversion_p (TREE_TYPE (orig_fn), ! TREE_TYPE (fn))) { - bool can_make_abnormal_goto - = stmt_can_make_abnormal_goto (stmt); - bool was_noreturn = gimple_call_noreturn_p (stmt); - if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Replacing call target with "); --- 4340,4347 ---- fn = build_fold_addr_expr (fn); } } ! if (fn && gimple_call_addr_fndecl (fn) != NULL_TREE) { if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Replacing call target with "); *************** eliminate_dom_walker::before_dom_childre *** 4363,4398 **** gimple_call_set_fn (stmt, fn); el_to_update.safe_push (stmt); /* 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; ! /* 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"); ! } ! /* 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; } } } --- 4352,4477 ---- gimple_call_set_fn (stmt, fn); el_to_update.safe_push (stmt); + gimple_set_modified (stmt, true); + + /* 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; + } + } + + /* 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 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)))) + { + 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); + } + } + 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 the stmt if that was not defered. */ + if (el_to_update.is_empty () + || el_to_update.last () != stmt) + update_stmt (stmt); + } ! /* 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); ! } ! /* 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); } } } *************** eliminate (void) *** 4431,4485 **** el_avail.release (); el_avail_stack.release (); /* 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) { ! 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)) { ! 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); } ! /* If this is a store or a now unused copy, remove it. */ ! if (TREE_CODE (lhs) != SSA_NAME ! || has_zero_uses (lhs)) { 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); } } el_to_remove.release (); - /* We cannot update call statements with virtual operands during - SSA walk. This might remove them which in turn makes our - VN lattice invalid. */ - FOR_EACH_VEC_ELT (el_to_update, i, stmt) - update_stmt (stmt); - el_to_update.release (); - return el_todo; } --- 4510,4560 ---- el_avail.release (); el_avail_stack.release (); + /* We cannot update call statements with virtual operands during + SSA walk. This might remove them which in turn makes our + VN lattice invalid. */ + FOR_EACH_VEC_ELT (el_to_update, i, stmt) + update_stmt (stmt); + el_to_update.release (); + /* 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. ! Remove stmts in reverse order to make debug stmt creation possible. */ ! while (!el_to_remove.is_empty ()) { ! stmt = el_to_remove.pop (); ! if (dump_file && (dump_flags & TDF_DETAILS)) { ! fprintf (dump_file, "Removing dead stmt "); ! print_gimple_stmt (dump_file, stmt, 0, 0); } ! 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); unlink_stmt_vdef (stmt); if (gsi_remove (&gsi, true)) bitmap_set_bit (need_eh_cleanup, bb->index); release_defs (stmt); } } el_to_remove.release (); return el_todo; } Index: trunk/gcc/testsuite/c-c++-common/pr46562-2.c =================================================================== *** trunk.orig/gcc/testsuite/c-c++-common/pr46562-2.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/testsuite/c-c++-common/pr46562-2.c 2014-05-14 14:15:15.536871496 +0200 *************** int foo(void) *** 9,13 **** return *p; } ! /* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ --- 9,13 ---- return *p; } ! /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ Index: trunk/gcc/tree-ssa-propagate.c =================================================================== *** trunk.orig/gcc/tree-ssa-propagate.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/tree-ssa-propagate.c 2014-05-14 14:15:15.537871496 +0200 *************** replace_exp (use_operand_p op_p, tree va *** 1410,1420 **** 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 --- 1410,1415 ---- Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c 2014-05-14 14:15:15.537871496 +0200 *************** int bazzoo (void) *** 30,34 **** return b.i; } ! /* { dg-final { scan-tree-dump-times "= 0;" 5 "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ --- 30,34 ---- return b.i; } ! /* { dg-final { scan-tree-dump-times "return 0;" 4 "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c 2014-05-14 14:15:15.537871496 +0200 *************** int foo (struct X *p) *** 14,18 **** /* We should optimize this to return 0. */ ! /* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ --- 14,18 ---- /* We should optimize this to return 0. */ ! /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c 2014-05-14 14:15:15.538871496 +0200 *************** bar (_Complex float x) *** 23,28 **** 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" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */ --- 23,28 ---- return z; } ! /* 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" } } */ Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c 2014-05-14 14:06:26.860907895 +0200 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c 2014-05-14 14:15:15.538871496 +0200 *************** int foo(int k, int *x) *** 11,15 **** } while (++j<k); return res; } ! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */ /* { dg-final { cleanup-tree-dump "pre" } } */ --- 11,15 ---- } while (++j<k); return res; } ! /* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */ /* { dg-final { cleanup-tree-dump "pre" } } */