* [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
@ 2014-05-14 14:04 Richard Biener
2014-06-13 10:01 ` Richard Biener
0 siblings, 1 reply; 4+ messages in thread
From: Richard Biener @ 2014-05-14 14:04 UTC (permalink / raw)
To: gcc-patches
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 <rguenther@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" } } */
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
2014-05-14 14:04 [PATCH][RFC] Make FRE/PRE apply copy/constant propagation Richard Biener
@ 2014-06-13 10:01 ` Richard Biener
2014-06-14 15:15 ` Eric Botcazou
0 siblings, 1 reply; 4+ messages in thread
From: Richard Biener @ 2014-06-13 10:01 UTC (permalink / raw)
To: gcc-patches
On Wed, 14 May 2014, Richard Biener wrote:
>
> 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?
Ok, so here goes the final variant I am about to commit.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
Richard.
2014-06-13 Richard Biener <rguenther@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.
* 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.
Index: trunk/gcc/tree-ssa-pre.c
===================================================================
*** trunk.orig/gcc/tree-ssa-pre.c 2014-06-12 13:05:07.459653680 +0200
--- trunk/gcc/tree-ssa-pre.c 2014-06-13 09:48:28.646517479 +0200
*************** eliminate_dom_walker::before_dom_childre
*** 4012,4131 ****
/* Mark new bb. */
el_avail_stack.safe_push (NULL_TREE);
! /* If this block is not reachable do nothing. */
! edge_iterator ei;
! edge e;
! FOR_EACH_EDGE (e, ei, b->preds)
! if (e->flags & EDGE_EXECUTABLE)
! break;
! if (!e)
! return;
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,4104 ----
/* Mark new bb. */
el_avail_stack.safe_push (NULL_TREE);
! /* ??? 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 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;
! }
! 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
*** 4139,4246 ****
&& (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))
! {
! 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 (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
! && 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 ");
--- 4112,4240 ----
&& (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
eliminate_push_avail (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 (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))
! {
! 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));
}
+ /* 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
! && 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))
{
! 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)
! {
! 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);
}
+ /* 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))
{
fprintf (dump_file, "Replaced ");
*************** eliminate_dom_walker::before_dom_childre
*** 4254,4269 ****
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++;
!
tree vdef = gimple_vdef (stmt);
tree vuse = gimple_vuse (stmt);
propagate_tree_value_into_stmt (&gsi, sprime);
--- 4248,4259 ----
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);
tree vdef = gimple_vdef (stmt);
tree vuse = gimple_vuse (stmt);
propagate_tree_value_into_stmt (&gsi, sprime);
*************** eliminate_dom_walker::before_dom_childre
*** 4291,4425 ****
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)
{
! fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
! if (!gimple_call_addr_fndecl (fn))
{
! fn = ipa_intraprocedural_devirtualization (stmt);
! if (fn)
! 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))
! && 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;
/* 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;
}
}
}
--- 4281,4463 ----
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));
! 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 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);
}
}
+
/* Visit indirect calls and turn them into direct calls if
! possible using the devirtualization machinery. */
if (is_gimple_call (stmt))
{
! tree fn = gimple_call_fn (stmt);
! if (fn
! && TREE_CODE (fn) == OBJ_TYPE_REF
! && TREE_CODE (OBJ_TYPE_REF_EXPR (fn)) == SSA_NAME)
{
! fn = ipa_intraprocedural_devirtualization (stmt);
! if (fn && dbg_cnt (devirt))
{
! 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);
}
}
! }
+ 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;
+ }
! /* 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 (bool do_pre)
*** 4442,4448 ****
{
gimple_stmt_iterator gsi;
gimple stmt;
- unsigned i;
need_eh_cleanup = BITMAP_ALLOC (NULL);
need_ab_cleanup = BITMAP_ALLOC (NULL);
--- 4480,4485 ----
*************** eliminate (bool do_pre)
*** 4460,4500 ****
/* 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);
}
}
--- 4497,4533 ----
/* 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);
}
}
Index: trunk/gcc/testsuite/c-c++-common/pr46562-2.c
===================================================================
*** trunk.orig/gcc/testsuite/c-c++-common/pr46562-2.c 2014-06-12 13:05:44.962651098 +0200
--- trunk/gcc/testsuite/c-c++-common/pr46562-2.c 2014-06-12 13:05:49.149650810 +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-06-12 13:05:44.962651098 +0200
--- trunk/gcc/tree-ssa-propagate.c 2014-06-12 13:05:49.149650810 +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-06-12 13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c 2014-06-12 13:05:49.150650810 +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-06-12 13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c 2014-06-12 13:05:49.150650810 +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-06-12 13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c 2014-06-12 13:05:49.150650810 +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-06-12 13:05:44.964651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c 2014-06-12 13:05:49.150650810 +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" } } */
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
===================================================================
*** trunk.orig/gcc/testsuite/g++.dg/tree-ssa/pr8781.C 2014-06-12 13:05:44.964651098 +0200
--- trunk/gcc/testsuite/g++.dg/tree-ssa/pr8781.C 2014-06-12 13:06:08.487649479 +0200
***************
*** 1,5 ****
/* { dg-do compile } */
! /* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */
int f();
--- 1,5 ----
/* { dg-do compile } */
! /* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */
int f();
*************** int x()
*** 24,28 ****
/* We should optimize this to a direct call. */
! /* { dg-final { scan-tree-dump "converting indirect call to function int f()" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
--- 24,28 ----
/* We should optimize this to a direct call. */
! /* { dg-final { scan-tree-dump-times "= f \\(\\);" 1 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c 2014-06-12 13:05:44.964651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c 2014-06-12 13:05:49.151650810 +0200
*************** int foo (int i)
*** 15,19 ****
/* We should be able to value-number the final assignment to k to 1. */
! /* { dg-final { scan-tree-dump "k_. = 1;" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
--- 15,19 ----
/* We should be able to value-number the final assignment to k to 1. */
! /* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
2014-06-13 10:01 ` Richard Biener
@ 2014-06-14 15:15 ` Eric Botcazou
2014-06-16 9:30 ` Richard Biener
0 siblings, 1 reply; 4+ messages in thread
From: Eric Botcazou @ 2014-06-14 15:15 UTC (permalink / raw)
To: Richard Biener; +Cc: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1222 bytes --]
> 2014-06-13 Richard Biener <rguenther@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.
This breaks Ada bootstrap with non-standard build options (-gnatpgn). I have
attached a reduced testcase, but you need the Ada SJLJ scheme to see it so the
following procedure can be used:
1. Put p.ad[bs] in $(BUILDDIR)
2. Do "gcc/gnat1 -quiet p.adb -I $(SRCDIR)/gcc/ada -I gcc/ada -O2 -gnatn"
eric@polaris:~/build/gcc/native> gcc/gnat1 -quiet p.adb -I ~/svn/gcc/gcc/ada -
I gcc/ada -O2 -gnatn
+===========================GNAT BUG DETECTED==============================+
| 4.10.0 20140614 (experimental) [trunk revision 211664] (x86_64-suse-linux)
GCC error:|
| in forward_edge_to_pdom, at tree-ssa-dce.c:1042 |
| Error detected around /home/eric/svn/gcc/gcc/ada/sinfo.adb:6010:8 |
--
Eric Botcazou
[-- Attachment #2: p.adb --]
[-- Type: text/x-adasrc, Size: 2716 bytes --]
with Atree; use Atree;
with Einfo; use Einfo;
with Elists; use Elists;
with Exp_Ch6; use Exp_Ch6;
with Nmake; use Nmake;
with Opt; use Opt;
with Rtsfind; use Rtsfind;
with Sem_Aux; use Sem_Aux;
with Sinfo; use Sinfo;
with Tbuild; use Tbuild;
package body P is
procedure Expand_Allocator_Expression (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Exp : constant Node_Id := Expression (Expression (N));
procedure Apply_Accessibility_Check (Ref : Node_Id) is
begin
null;
end Apply_Accessibility_Check;
Indic : constant Node_Id := Subtype_Mark (Expression (N));
T : constant Entity_Id := Entity (Indic);
Tag_Assign : Node_Id;
Temp : Entity_Id;
TagT : Entity_Id := Empty;
TagR : Node_Id := Empty;
begin
if Ada_Version >= Ada_2012 and then Nkind (Exp) = N_Function_Call then
declare
Subp : Entity_Id;
begin
if Nkind (Name (Exp)) = N_Explicit_Dereference then
Subp := Designated_Type (Etype (Prefix (Name (Exp))));
else
Subp := Entity (Name (Exp));
end if;
end;
end if;
if Is_Tagged_Type (T) then
if Ada_Version >= Ada_2005 then
Make_Build_In_Place_Call_In_Allocator (N, Exp);
Apply_Accessibility_Check (N);
return;
end if;
Temp := Make_Temporary (Loc, 'P', N);
if Is_Private_Type (T)
and then Is_Tagged_Type (Underlying_Type (T))
then
TagT := Underlying_Type (T);
TagR :=
Unchecked_Convert_To (Underlying_Type (T),
Make_Explicit_Dereference (Loc,
Prefix => New_Occurrence_Of (Temp, Loc)));
end if;
if Present (TagT) then
declare
Full_T : constant Entity_Id := Underlying_Type (TagT);
begin
Tag_Assign :=
Make_Assignment_Statement (Loc,
Name =>
Make_Selected_Component (Loc,
Prefix => TagR,
Selector_Name =>
New_Occurrence_Of
(First_Tag_Component (Full_T), Loc)),
Expression =>
Unchecked_Convert_To (RTE (RE_Tag),
New_Occurrence_Of
(Elists.Node
(First_Elmt (Access_Disp_Table (Full_T))), Loc)));
end;
end if;
end if;
exception
when RE_Not_Available => return;
end;
end P;
[-- Attachment #3: p.ads --]
[-- Type: text/x-adasrc, Size: 101 bytes --]
with Types; use Types;
package P is
procedure Expand_Allocator_Expression (N : Node_Id);
end P;
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
2014-06-14 15:15 ` Eric Botcazou
@ 2014-06-16 9:30 ` Richard Biener
0 siblings, 0 replies; 4+ messages in thread
From: Richard Biener @ 2014-06-16 9:30 UTC (permalink / raw)
To: Eric Botcazou; +Cc: gcc-patches
On Sat, 14 Jun 2014, Eric Botcazou wrote:
> > 2014-06-13 Richard Biener <rguenther@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.
>
> This breaks Ada bootstrap with non-standard build options (-gnatpgn). I have
> attached a reduced testcase, but you need the Ada SJLJ scheme to see it so the
> following procedure can be used:
>
> 1. Put p.ad[bs] in $(BUILDDIR)
> 2. Do "gcc/gnat1 -quiet p.adb -I $(SRCDIR)/gcc/ada -I gcc/ada -O2 -gnatn"
>
> eric@polaris:~/build/gcc/native> gcc/gnat1 -quiet p.adb -I ~/svn/gcc/gcc/ada -
> I gcc/ada -O2 -gnatn
> +===========================GNAT BUG DETECTED==============================+
> | 4.10.0 20140614 (experimental) [trunk revision 211664] (x86_64-suse-linux)
> GCC error:|
> | in forward_edge_to_pdom, at tree-ssa-dce.c:1042 |
> | Error detected around /home/eric/svn/gcc/gcc/ada/sinfo.adb:6010:8 |
Seems to be an issue with the assert
1041 /* The resulting PHI if not dead can only be degenerate.
*/
1042 gcc_assert (degenerate_phi_p (phi));
and the fact that the PHI is abnormal and thus while it really _is_
degenerate value-wise, we can't easily prove it (by that predicate).
Not sure what to do here but adjust it to
gcc_assert (degenerate_phi_p (phi) || SSA_NAME_OCCURS_IN_ABNORMAL_PHI
(gimple_phi_result (phi)));
So - can you check if bootstrap works with that?
Thanks,
Richard.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2014-06-16 9:30 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-14 14:04 [PATCH][RFC] Make FRE/PRE apply copy/constant propagation Richard Biener
2014-06-13 10:01 ` Richard Biener
2014-06-14 15:15 ` Eric Botcazou
2014-06-16 9:30 ` Richard Biener
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).