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,120 +4012,93 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4012,120 +4012,93 @@ 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
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 (virtual_operand_p (res))
if (!sprime
|| sprime == res)
{ {
eliminate_push_avail (res);
gsi_next (&gsi); gsi_next (&gsi);
continue; continue;
} }
else if (is_gimple_min_invariant (sprime))
{
if (!useless_type_conversion_p (TREE_TYPE (res),
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime);
}
if (dump_file && (dump_flags & TDF_DETAILS)) tree sprime = eliminate_avail (res);
if (sprime
&& sprime != res)
{ {
fprintf (dump_file, "Replaced redundant PHI node defining "); if (dump_file && (dump_flags & TDF_DETAILS))
print_generic_expr (dump_file, res, 0); {
fprintf (dump_file, " with "); fprintf (dump_file, "Replaced redundant PHI node defining ");
print_generic_expr (dump_file, sprime, 0); print_generic_expr (dump_file, res, 0);
fprintf (dump_file, "\n"); fprintf (dump_file, " with ");
} print_generic_expr (dump_file, sprime, 0);
fprintf (dump_file, "\n");
remove_phi_node (&gsi, false); }
if (inserted_exprs /* If we inserted this PHI node ourself, it's not an elimination. */
&& !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)) if (inserted_exprs
&& TREE_CODE (sprime) == SSA_NAME) && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true); pre_stats.phis--;
else
if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime))) pre_stats.eliminations++;
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)) /* If we will propagate into all uses don't bother to do
{ anything. */
tree lhs = NULL_TREE; if (may_propagate_copy (res, sprime))
tree rhs = NULL_TREE; {
/* Mark the PHI for removal. */
el_to_remove.safe_push (phi);
gsi_next (&gsi);
continue;
}
stmt = gsi_stmt (gsi); remove_phi_node (&gsi, false);
if (gimple_has_lhs (stmt)) if (inserted_exprs
lhs = gimple_get_lhs (stmt); && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
&& TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
if (gimple_assign_single_p (stmt)) if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
rhs = gimple_assign_rhs1 (stmt); sprime = fold_convert (TREE_TYPE (res), sprime);
gimple stmt = gimple_build_assign (res, sprime);
/* ??? It cannot yet be necessary (DOM walk). */
gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
/* Lookup the RHS of the expression, see if we have an gimple_stmt_iterator gsi2 = gsi_after_labels (b);
available computation for it. If so, replace the RHS with gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
the available computation. */ continue;
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); eliminate_push_avail (res);
/* If there is no usable leader mark lhs as leader for its value. */ gsi_next (&gsi);
if (!sprime) }
eliminate_push_avail (lhs);
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 /* 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,107 +4112,128 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4139,107 +4112,128 @@ 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))
{
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 /* If this now constitutes a copy duplicate points-to
its EH information. */ and range info appropriately. This is especially
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) important for inserted code. See tree-ssa-copy.c
for similar code. */
if (sprime
&& TREE_CODE (sprime) == SSA_NAME)
{
basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
if (POINTER_TYPE_P (TREE_TYPE (lhs))
&& SSA_NAME_PTR_INFO (lhs)
&& !SSA_NAME_PTR_INFO (sprime))
{ {
bitmap_set_bit (need_eh_cleanup, 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));
} }
/* 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 if (sprime
&& sprime != lhs && TREE_CODE (sprime) == SSA_NAME
&& (rhs == NULL_TREE && do_pre
|| TREE_CODE (rhs) != SSA_NAME && flag_tree_loop_vectorize
|| may_propagate_copy (rhs, sprime))) && loop_outer (b->loop_father)
&& has_zero_uses (sprime)
&& bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))
&& gimple_assign_load_p (stmt))
{ {
bool can_make_abnormal_goto gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
= is_gimple_call (stmt) basic_block def_bb = gimple_bb (def_stmt);
&& stmt_can_make_abnormal_goto (stmt); if (gimple_code (def_stmt) == GIMPLE_PHI
&& b->loop_father->header == def_bb)
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); ssa_op_iter iter;
basic_block def_bb = gimple_bb (def_stmt); tree op;
if (gimple_code (def_stmt) == GIMPLE_PHI bool found = false;
&& b->loop_father->header == def_bb FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
&& has_zero_uses (sprime))
{ {
ssa_op_iter iter; affine_iv iv;
tree op; def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
bool found = false; if (def_bb
FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE) && flow_bb_inside_loop_p (b->loop_father, def_bb)
&& simple_iv (b->loop_father,
b->loop_father, op, &iv, true))
{ {
affine_iv iv; found = true;
def_bb = gimple_bb (SSA_NAME_DEF_STMT (op)); break;
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 (found)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{ {
if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Not replacing ");
{ print_gimple_expr (dump_file, stmt, 0, 0);
fprintf (dump_file, "Not replacing "); fprintf (dump_file, " with ");
print_gimple_expr (dump_file, stmt, 0, 0); print_generic_expr (dump_file, sprime, 0);
fprintf (dump_file, " with "); fprintf (dump_file, " which would add a loop"
print_generic_expr (dump_file, sprime, 0); " carried dependence to loop %d\n",
fprintf (dump_file, " which would add a loop" b->loop_father->num);
" carried dependence to loop %d\n",
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))
{ {
...@@ -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,135 +4281,183 @@ eliminate_dom_walker::before_dom_children (basic_block b) ...@@ -4291,135 +4281,183 @@ 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;
val = vn_reference_lookup (gimple_assign_lhs (stmt), tree rhs = gimple_assign_rhs1 (stmt);
gimple_vuse (stmt), VN_WALK, NULL); val = vn_reference_lookup (gimple_assign_lhs (stmt),
if (TREE_CODE (rhs) == SSA_NAME) gimple_vuse (stmt), VN_WALK, NULL);
rhs = VN_INFO (rhs)->valnum; if (TREE_CODE (rhs) == SSA_NAME)
if (val rhs = VN_INFO (rhs)->valnum;
&& operand_equal_p (val, rhs, 0)) if (val
{ && operand_equal_p (val, rhs, 0))
if (dump_file && (dump_flags & TDF_DETAILS)) {
{ if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Deleted redundant store "); {
print_gimple_stmt (dump_file, stmt, 0, 0); fprintf (dump_file, "Deleted redundant store ");
} print_gimple_stmt (dump_file, stmt, 0, 0);
}
/* Queue stmt for removal. */
el_to_remove.safe_push (stmt);
continue;
}
}
/* Queue stmt for removal. */ bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
el_to_remove.safe_push (stmt); bool was_noreturn = (is_gimple_call (stmt)
} && gimple_call_noreturn_p (stmt));
} tree vdef = gimple_vdef (stmt);
/* Visit COND_EXPRs and fold the comparison with the tree vuse = gimple_vuse (stmt);
available value-numbers. */
else if (gimple_code (stmt) == GIMPLE_COND) /* If we didn't replace the whole stmt (or propagate the result
into all uses), replace all uses on this stmt with their
leaders. */
use_operand_p use_p;
ssa_op_iter iter;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
{ {
tree op0 = gimple_cond_lhs (stmt); tree use = USE_FROM_PTR (use_p);
tree op1 = gimple_cond_rhs (stmt); /* ??? The call code above leaves stmt operands un-updated. */
tree result; if (TREE_CODE (use) != SSA_NAME)
continue;
if (TREE_CODE (op0) == SSA_NAME) tree sprime = eliminate_avail (use);
op0 = VN_INFO (op0)->valnum; if (sprime && sprime != use
if (TREE_CODE (op1) == SSA_NAME) && may_propagate_copy (use, sprime)
op1 = VN_INFO (op1)->valnum; /* We substitute into debug stmts to avoid excessive
result = fold_binary (gimple_cond_code (stmt), boolean_type_node, debug temporaries created by removed stmts, but we need
op0, op1); to avoid doing so for inserted sprimes as we never want
if (result && TREE_CODE (result) == INTEGER_CST) to create debug temporaries for them. */
&& (!inserted_exprs
|| TREE_CODE (sprime) != SSA_NAME
|| !is_gimple_debug (stmt)
|| !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
{ {
if (integer_zerop (result)) propagate_value (use_p, sprime);
gimple_cond_make_false (stmt); gimple_set_modified (stmt, true);
else if (TREE_CODE (sprime) == SSA_NAME
gimple_cond_make_true (stmt); && !is_gimple_debug (stmt))
update_stmt (stmt); gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
el_todo = TODO_cleanup_cfg; 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; fn = ipa_intraprocedural_devirtualization (stmt);
if (!gimple_call_addr_fndecl (fn)) if (fn && dbg_cnt (devirt))
{ {
fn = ipa_intraprocedural_devirtualization (stmt); if (dump_enabled_p ())
if (fn) {
fn = build_fold_addr_expr (fn); location_t loc = gimple_location (stmt);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
"converting indirect call to "
"function %s\n",
cgraph_get_node (fn)->name ());
}
gimple_call_set_fndecl (stmt, fn);
gimple_set_modified (stmt, true);
} }
} }
else }
continue;
if (gimple_call_addr_fndecl (fn) != NULL_TREE
&& useless_type_conversion_p (TREE_TYPE (orig_fn),
TREE_TYPE (fn))
&& dbg_cnt (devirt))
{
bool can_make_abnormal_goto
= stmt_can_make_abnormal_goto (stmt);
bool was_noreturn = gimple_call_noreturn_p (stmt);
if (dump_enabled_p ())
{
location_t loc = gimple_location (stmt);
dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
"converting indirect call to function %s\n",
cgraph_get_node (gimple_call_addr_fndecl (fn))->name ());
}
gimple_call_set_fn (stmt, fn);
tree vdef = gimple_vdef (stmt);
tree vuse = gimple_vuse (stmt);
update_stmt (stmt);
if (vdef != gimple_vdef (stmt))
VN_INFO (vdef)->valnum = vuse;
if (gimple_modified_p (stmt))
{
/* If a formerly non-invariant ADDR_EXPR is turned into an
invariant one it was on a separate stmt. */
if (gimple_assign_single_p (stmt)
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
gimple old_stmt = stmt;
if (is_gimple_call (stmt))
{
/* ??? Only fold calls inplace for now, this may create new
SSA names which in turn will confuse free_scc_vn SSA name
release code. */
fold_stmt_inplace (&gsi);
/* When changing a call into a noreturn call, cfg cleanup /* 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
its EH information. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
{
bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed EH side-effects.\n");
}
/* Likewise for AB side-effects. */
if (can_make_abnormal_goto
&& !stmt_can_make_abnormal_goto (stmt))
{
bitmap_set_bit (need_ab_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n");
}
update_stmt (stmt);
if (vdef != gimple_vdef (stmt))
VN_INFO (vdef)->valnum = vuse;
}
/* If we removed EH side-effects from the statement, clean /* Make the new value available - for fully redundant LHS we
its EH information. */ continue with the next stmt above. */
if (maybe_clean_or_replace_eh_stmt (stmt, stmt)) if (lhs && TREE_CODE (lhs) == SSA_NAME)
{ eliminate_push_avail (lhs);
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 /* 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; if (dump_file && (dump_flags & TDF_DETAILS))
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); 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