Commit 6aa4c5b6 by Richard Biener Committed by Richard Biener

tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Rewrite to propagate…

tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Rewrite to propagate the VN result into all uses where possible and to remove...

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.

From-SVN: r211625
parent 80298c3b
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.
2014-06-13 Thomas Preud'homme <thomas.preudhomme@arm.com> 2014-06-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
PR tree-optimization/61375 PR tree-optimization/61375
......
2014-06-13 Richard Biener <rguenther@suse.de>
* c-c++-common/pr46562-2.c: Adjust.
* g++.dg/tree-ssa/pr8781.C: Likewise.
* gcc.dg/tree-ssa/ssa-fre-24.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-25.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-32.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-39.c: Likewise.
* gcc.dg/tree-ssa/ssa-pre-16.c: Likewise.
2014-06-13 Thomas Preud'homme <thomas.preudhomme@arm.com> 2014-06-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
PR tree-optimization/61375 PR tree-optimization/61375
......
...@@ -9,5 +9,5 @@ int foo(void) ...@@ -9,5 +9,5 @@ int foo(void)
return *p; return *p;
} }
/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */ /* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */
int f(); int f();
...@@ -24,5 +24,5 @@ int x() ...@@ -24,5 +24,5 @@ int x()
/* We should optimize this to a direct call. */ /* We should optimize this to a direct call. */
/* { dg-final { scan-tree-dump "converting indirect call to function int f()" "fre1" } } */ /* { dg-final { scan-tree-dump-times "= f \\(\\);" 1 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -30,5 +30,5 @@ int bazzoo (void) ...@@ -30,5 +30,5 @@ int bazzoo (void)
return b.i; return b.i;
} }
/* { dg-final { scan-tree-dump-times "= 0;" 5 "fre1" } } */ /* { dg-final { scan-tree-dump-times "return 0;" 4 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -14,5 +14,5 @@ int foo (struct X *p) ...@@ -14,5 +14,5 @@ int foo (struct X *p)
/* We should optimize this to return 0. */ /* We should optimize this to return 0. */
/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */ /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -23,6 +23,6 @@ bar (_Complex float x) ...@@ -23,6 +23,6 @@ bar (_Complex float x)
return z; return z;
} }
/* We should CSE all the way to replace the final assignment to z with x. */ /* We should CSE all the way to replace the return value with x. */
/* { dg-final { scan-tree-dump-times "with x_1\\\(D\\\) in z" 3 "fre1" } } */ /* { dg-final { scan-tree-dump-times "return x_\\d\+\\(D\\);" 2 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -15,5 +15,5 @@ int foo (int i) ...@@ -15,5 +15,5 @@ int foo (int i)
/* We should be able to value-number the final assignment to k to 1. */ /* We should be able to value-number the final assignment to k to 1. */
/* { dg-final { scan-tree-dump "k_. = 1;" "fre1" } } */ /* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */ /* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -11,5 +11,5 @@ int foo(int k, int *x) ...@@ -11,5 +11,5 @@ int foo(int k, int *x)
} while (++j<k); } while (++j<k);
return res; return res;
} }
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */ /* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
/* { dg-final { cleanup-tree-dump "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */
...@@ -4012,46 +4012,25 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4012,46 +4012,25 @@ eliminate_dom_walker::before_dom_children (basic_block b)
/* Mark new bb. */ /* Mark new bb. */
el_avail_stack.safe_push (NULL_TREE); el_avail_stack.safe_push (NULL_TREE);
/* If this block is not reachable do nothing. */ /* ??? If we do nothing for unreachable blocks then this will confuse
edge_iterator ei; tailmerging. Eventually we can reduce its reliance on SCCVN now
edge e; that we fully copy/constant-propagate (most) things. */
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);) for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
{ {
gimple stmt, phi = gsi_stmt (gsi); gimple phi = gsi_stmt (gsi);
tree sprime = NULL_TREE, res = PHI_RESULT (phi); tree res = PHI_RESULT (phi);
gimple_stmt_iterator gsi2;
/* We want to perform redundant PHI elimination. Do so by if (virtual_operand_p (res))
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); gsi_next (&gsi);
continue; continue;
} }
sprime = eliminate_avail (res); tree sprime = eliminate_avail (res);
if (!sprime if (sprime
|| sprime == res) && 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)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "Replaced redundant PHI node defining "); fprintf (dump_file, "Replaced redundant PHI node defining ");
...@@ -4061,6 +4040,23 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4061,6 +4040,23 @@ eliminate_dom_walker::before_dom_children (basic_block b)
fprintf (dump_file, "\n"); 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); remove_phi_node (&gsi, false);
if (inserted_exprs if (inserted_exprs
...@@ -4070,62 +4066,39 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4070,62 +4066,39 @@ eliminate_dom_walker::before_dom_children (basic_block b)
if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime))) if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime); sprime = fold_convert (TREE_TYPE (res), sprime);
stmt = gimple_build_assign (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_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
gsi2 = gsi_after_labels (b); gimple_stmt_iterator gsi2 = gsi_after_labels (b);
gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
/* Queue the copy for eventual removal. */ continue;
el_to_remove.safe_push (stmt); }
/* If we inserted this PHI node ourself, it's not an elimination. */
if (inserted_exprs eliminate_push_avail (res);
&& bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))) gsi_next (&gsi);
pre_stats.phis--;
else
pre_stats.eliminations++;
} }
for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi)) for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
tree lhs = NULL_TREE; tree sprime = NULL_TREE;
tree rhs = NULL_TREE;
stmt = gsi_stmt (gsi); stmt = gsi_stmt (gsi);
tree lhs = gimple_get_lhs (stmt);
if (gimple_has_lhs (stmt)) if (lhs && TREE_CODE (lhs) == SSA_NAME
lhs = gimple_get_lhs (stmt); && !gimple_has_volatile_ops (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 /* See PR43491. Do not replace a global register variable when
it is a the RHS of an assignment. Do replace local register it is a the RHS of an assignment. Do replace local register
variables since gcc does not guarantee a local variable will variables since gcc does not guarantee a local variable will
be allocated in register. be allocated in register.
Do not perform copy propagation or undo constant propagation. */ ??? The fix isn't effective here. This should instead
if (gimple_assign_single_p (stmt) be ensured by not value-numbering them the same but treating
&& (TREE_CODE (rhs) == SSA_NAME them like volatiles? */
|| is_gimple_min_invariant (rhs) && !(gimple_assign_single_p (stmt)
|| (TREE_CODE (rhs) == VAR_DECL && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
&& is_global_var (rhs) && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))
&& DECL_HARD_REGISTER (rhs)))) && is_global_var (gimple_assign_rhs1 (stmt)))))
continue; {
sprime = eliminate_avail (lhs);
if (!sprime) if (!sprime)
{ {
/* If there is no existing usable leader but SCCVN thinks /* If there is no existing usable leader but SCCVN thinks
...@@ -4139,73 +4112,52 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4139,73 +4112,52 @@ eliminate_dom_walker::before_dom_children (basic_block b)
&& (sprime = eliminate_insert (&gsi, val)) != NULL_TREE) && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
eliminate_push_avail (sprime); 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)) /* 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)
{ {
fprintf (dump_file, "Replaced "); basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
print_gimple_expr (dump_file, stmt, 0, 0); if (POINTER_TYPE_P (TREE_TYPE (lhs))
fprintf (dump_file, " with "); && SSA_NAME_PTR_INFO (lhs)
print_generic_expr (dump_file, sprime, 0); && !SSA_NAME_PTR_INFO (sprime))
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, duplicate_ssa_name_ptr_info (sprime,
gimple_bb (stmt)->index); SSA_NAME_PTR_INFO (lhs));
if (dump_file && (dump_flags & TDF_DETAILS)) if (b != sprime_b)
fprintf (dump_file, " Removed EH side-effects.\n"); mark_ptr_info_alignment_unknown
(SSA_NAME_PTR_INFO (sprime));
} }
continue; else if (!POINTER_TYPE_P (TREE_TYPE (lhs))
&& SSA_NAME_RANGE_INFO (lhs)
&& !SSA_NAME_RANGE_INFO (sprime)
&& b == sprime_b)
duplicate_ssa_name_range_info (sprime,
SSA_NAME_RANGE_TYPE (lhs),
SSA_NAME_RANGE_INFO (lhs));
} }
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 /* Inhibit the use of an inserted PHI on a loop header when
the address of the memory reference is a simple induction the address of the memory reference is a simple induction
variable. In other cases the vectorizer won't do anything variable. In other cases the vectorizer won't do anything
anyway (either it's loop invariant or a complicated anyway (either it's loop invariant or a complicated
expression). */ expression). */
if (do_pre if (sprime
&& flag_tree_loop_vectorize
&& gimple_assign_single_p (stmt)
&& TREE_CODE (sprime) == SSA_NAME && TREE_CODE (sprime) == SSA_NAME
&& loop_outer (b->loop_father)) && 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); gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
basic_block def_bb = gimple_bb (def_stmt); basic_block def_bb = gimple_bb (def_stmt);
if (gimple_code (def_stmt) == GIMPLE_PHI if (gimple_code (def_stmt) == GIMPLE_PHI
&& b->loop_father->header == def_bb && b->loop_father->header == def_bb)
&& has_zero_uses (sprime))
{ {
ssa_op_iter iter; ssa_op_iter iter;
tree op; tree op;
...@@ -4215,8 +4167,7 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4215,8 +4167,7 @@ eliminate_dom_walker::before_dom_children (basic_block b)
affine_iv iv; affine_iv iv;
def_bb = gimple_bb (SSA_NAME_DEF_STMT (op)); def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
if (def_bb if (def_bb
&& flow_bb_inside_loop_p (b->loop_father, && flow_bb_inside_loop_p (b->loop_father, def_bb)
def_bb)
&& simple_iv (b->loop_father, && simple_iv (b->loop_father,
b->loop_father, op, &iv, true)) b->loop_father, op, &iv, true))
{ {
...@@ -4236,11 +4187,54 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4236,11 +4187,54 @@ eliminate_dom_walker::before_dom_children (basic_block b)
" carried dependence to loop %d\n", " carried dependence to loop %d\n",
b->loop_father->num); b->loop_father->num);
} }
continue; /* 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)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "Replaced "); fprintf (dump_file, "Replaced ");
...@@ -4254,16 +4248,12 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4254,16 +4248,12 @@ eliminate_dom_walker::before_dom_children (basic_block b)
if (TREE_CODE (sprime) == SSA_NAME) if (TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
NECESSARY, true); 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++; 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 vdef = gimple_vdef (stmt);
tree vuse = gimple_vuse (stmt); tree vuse = gimple_vuse (stmt);
propagate_tree_value_into_stmt (&gsi, sprime); propagate_tree_value_into_stmt (&gsi, sprime);
...@@ -4291,18 +4281,22 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4291,18 +4281,22 @@ eliminate_dom_walker::before_dom_children (basic_block b)
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n"); fprintf (dump_file, " Removed AB side-effects.\n");
} }
continue;
} }
} }
/* If the statement is a scalar store, see if the expression /* If the statement is a scalar store, see if the expression
has the same value number as its rhs. If so, the store is has the same value number as its rhs. If so, the store is
dead. */ dead. */
else if (gimple_assign_single_p (stmt) if (gimple_assign_single_p (stmt)
&& !gimple_has_volatile_ops (stmt) && !gimple_has_volatile_ops (stmt)
&& !is_gimple_reg (gimple_assign_lhs (stmt)) && !is_gimple_reg (gimple_assign_lhs (stmt))
&& (TREE_CODE (rhs) == SSA_NAME && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
|| is_gimple_min_invariant (rhs))) || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
{ {
tree val; tree val;
tree rhs = gimple_assign_rhs1 (stmt);
val = vn_reference_lookup (gimple_assign_lhs (stmt), val = vn_reference_lookup (gimple_assign_lhs (stmt),
gimple_vuse (stmt), VN_WALK, NULL); gimple_vuse (stmt), VN_WALK, NULL);
if (TREE_CODE (rhs) == SSA_NAME) if (TREE_CODE (rhs) == SSA_NAME)
...@@ -4318,94 +4312,113 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4318,94 +4312,113 @@ eliminate_dom_walker::before_dom_children (basic_block b)
/* Queue stmt for removal. */ /* Queue stmt for removal. */
el_to_remove.safe_push (stmt); el_to_remove.safe_push (stmt);
continue;
} }
} }
/* 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) bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
op0 = VN_INFO (op0)->valnum; bool was_noreturn = (is_gimple_call (stmt)
if (TREE_CODE (op1) == SSA_NAME) && gimple_call_noreturn_p (stmt));
op1 = VN_INFO (op1)->valnum; tree vdef = gimple_vdef (stmt);
result = fold_binary (gimple_cond_code (stmt), boolean_type_node, tree vuse = gimple_vuse (stmt);
op0, op1);
if (result && TREE_CODE (result) == INTEGER_CST) /* 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)
{ {
if (integer_zerop (result)) tree use = USE_FROM_PTR (use_p);
gimple_cond_make_false (stmt); /* ??? The call code above leaves stmt operands un-updated. */
else if (TREE_CODE (use) != SSA_NAME)
gimple_cond_make_true (stmt); continue;
update_stmt (stmt); tree sprime = eliminate_avail (use);
el_todo = TODO_cleanup_cfg; 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 /* Visit indirect calls and turn them into direct calls if
possible. */ possible using the devirtualization machinery. */
if (is_gimple_call (stmt)) if (is_gimple_call (stmt))
{ {
tree orig_fn = gimple_call_fn (stmt); tree fn = gimple_call_fn (stmt);
tree fn; if (fn
if (!orig_fn) && TREE_CODE (fn) == OBJ_TYPE_REF
continue; && TREE_CODE (OBJ_TYPE_REF_EXPR (fn)) == SSA_NAME)
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); fn = ipa_intraprocedural_devirtualization (stmt);
if (fn) if (fn && dbg_cnt (devirt))
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 ()) if (dump_enabled_p ())
{ {
location_t loc = gimple_location (stmt); location_t loc = gimple_location (stmt);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc, dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
"converting indirect call to function %s\n", "converting indirect call to "
cgraph_get_node (gimple_call_addr_fndecl (fn))->name ()); "function %s\n",
cgraph_get_node (fn)->name ());
}
gimple_call_set_fndecl (stmt, fn);
gimple_set_modified (stmt, true);
}
}
} }
gimple_call_set_fn (stmt, fn); if (gimple_modified_p (stmt))
tree vdef = gimple_vdef (stmt); {
tree vuse = gimple_vuse (stmt); /* If a formerly non-invariant ADDR_EXPR is turned into an
update_stmt (stmt); invariant one it was on a separate stmt. */
if (vdef != gimple_vdef (stmt)) if (gimple_assign_single_p (stmt)
VN_INFO (vdef)->valnum = vuse; && 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 /* When changing a call into a noreturn call, cfg cleanup
is needed to fix up the noreturn call. */ is needed to fix up the noreturn call. */
if (!was_noreturn && gimple_call_noreturn_p (stmt)) if (!was_noreturn && gimple_call_noreturn_p (stmt))
el_todo |= TODO_cleanup_cfg; 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 /* If we removed EH side-effects from the statement, clean
its EH information. */ its EH information. */
if (maybe_clean_or_replace_eh_stmt (stmt, stmt)) if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
{ {
bitmap_set_bit (need_eh_cleanup, bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index); gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed EH side-effects.\n"); fprintf (dump_file, " Removed EH side-effects.\n");
} }
/* Likewise for AB side-effects. */ /* Likewise for AB side-effects. */
if (can_make_abnormal_goto if (can_make_abnormal_goto
&& !stmt_can_make_abnormal_goto (stmt)) && !stmt_can_make_abnormal_goto (stmt))
...@@ -4415,11 +4428,36 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4415,11 +4428,36 @@ eliminate_dom_walker::before_dom_children (basic_block b)
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n"); 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);
}
/* Changing an indirect call to a direct call may /* Replace destination PHI arguments. */
have exposed different semantics. This may edge_iterator ei;
require an SSA update. */ edge e;
el_todo |= TODO_update_ssa_only_virtuals; FOR_EACH_EDGE (e, ei, b->succs)
{
for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple phi = gsi_stmt (gsi);
use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
tree arg = USE_FROM_PTR (use_p);
if (TREE_CODE (arg) != SSA_NAME
|| virtual_operand_p (arg))
continue;
tree sprime = eliminate_avail (arg);
if (sprime && may_propagate_copy (arg, sprime))
{
propagate_value (use_p, sprime);
if (TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
} }
} }
} }
...@@ -4442,7 +4480,6 @@ eliminate (bool do_pre) ...@@ -4442,7 +4480,6 @@ eliminate (bool do_pre)
{ {
gimple_stmt_iterator gsi; gimple_stmt_iterator gsi;
gimple stmt; gimple stmt;
unsigned i;
need_eh_cleanup = BITMAP_ALLOC (NULL); need_eh_cleanup = BITMAP_ALLOC (NULL);
need_ab_cleanup = BITMAP_ALLOC (NULL); need_ab_cleanup = BITMAP_ALLOC (NULL);
...@@ -4460,41 +4497,37 @@ eliminate (bool do_pre) ...@@ -4460,41 +4497,37 @@ eliminate (bool do_pre)
/* We cannot remove stmts during BB walk, especially not release SSA /* We cannot remove stmts during BB walk, especially not release SSA
names there as this confuses the VN machinery. The stmts ending names there as this confuses the VN machinery. The stmts ending
up in el_to_remove are either stores or simple copies. */ up in el_to_remove are either stores or simple copies.
FOR_EACH_VEC_ELT (el_to_remove, i, stmt) Remove stmts in reverse order to make debug stmt creation possible. */
while (!el_to_remove.is_empty ())
{ {
tree lhs = gimple_assign_lhs (stmt); stmt = el_to_remove.pop ();
tree rhs = gimple_assign_rhs1 (stmt);
use_operand_p use_p;
gimple use_stmt;
/* If there is a single use only, propagate the equivalency if (dump_file && (dump_flags & TDF_DETAILS))
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); fprintf (dump_file, "Removing dead stmt ");
update_stmt (use_stmt); print_gimple_stmt (dump_file, stmt, 0, 0);
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. */ tree lhs;
if (TREE_CODE (lhs) != SSA_NAME if (gimple_code (stmt) == GIMPLE_PHI)
|| has_zero_uses (lhs)) 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); basic_block bb = gimple_bb (stmt);
gsi = gsi_for_stmt (stmt);
unlink_stmt_vdef (stmt); unlink_stmt_vdef (stmt);
if (gsi_remove (&gsi, true)) if (gsi_remove (&gsi, true))
bitmap_set_bit (need_eh_cleanup, bb->index); 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); release_defs (stmt);
} }
} }
......
...@@ -1410,11 +1410,6 @@ replace_exp (use_operand_p op_p, tree val) ...@@ -1410,11 +1410,6 @@ replace_exp (use_operand_p op_p, tree val)
void void
propagate_tree_value (tree *op_p, tree val) 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) if (TREE_CODE (val) == SSA_NAME)
*op_p = val; *op_p = val;
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment