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
This commit is contained in:
Richard Biener 2014-06-13 10:21:40 +00:00 committed by Richard Biener
parent 80298c3b46
commit 6aa4c5b68d
11 changed files with 388 additions and 339 deletions

View File

@ -1,3 +1,14 @@
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

View File

@ -1,3 +1,13 @@
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

View File

@ -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" } } */

View File

@ -1,5 +1,5 @@
/* { 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()
/* 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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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 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); if (dump_file && (dump_flags & TDF_DETAILS))
gsi_next (&gsi); {
continue; fprintf (dump_file, "Replaced redundant PHI node defining ");
} print_generic_expr (dump_file, res, 0);
else if (is_gimple_min_invariant (sprime)) fprintf (dump_file, " with ");
{ print_generic_expr (dump_file, sprime, 0);
if (!useless_type_conversion_p (TREE_TYPE (res), fprintf (dump_file, "\n");
TREE_TYPE (sprime))) }
/* 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); 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;
} }
if (dump_file && (dump_flags & TDF_DETAILS)) eliminate_push_avail (res);
{ gsi_next (&gsi);
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)) 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,108 +4112,129 @@ 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 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)
{ {
/* If there is no existing leader but SCCVN knows this basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
value is constant, use that constant. */ if (POINTER_TYPE_P (TREE_TYPE (lhs))
if (!useless_type_conversion_p (TREE_TYPE (lhs), && SSA_NAME_PTR_INFO (lhs)
TREE_TYPE (sprime))) && !SSA_NAME_PTR_INFO (sprime))
sprime = fold_convert (TREE_TYPE (lhs), sprime);
if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "Replaced "); duplicate_ssa_name_ptr_info (sprime,
print_gimple_expr (dump_file, stmt, 0, 0); SSA_NAME_PTR_INFO (lhs));
fprintf (dump_file, " with "); if (b != sprime_b)
print_generic_expr (dump_file, sprime, 0); mark_ptr_info_alignment_unknown
fprintf (dump_file, " in "); (SSA_NAME_PTR_INFO (sprime));
print_gimple_stmt (dump_file, stmt, 0, 0);
} }
pre_stats.eliminations++; else if (!POINTER_TYPE_P (TREE_TYPE (lhs))
&& SSA_NAME_RANGE_INFO (lhs)
tree vdef = gimple_vdef (stmt); && !SSA_NAME_RANGE_INFO (sprime)
tree vuse = gimple_vuse (stmt); && b == sprime_b)
propagate_tree_value_into_stmt (&gsi, sprime); duplicate_ssa_name_range_info (sprime,
stmt = gsi_stmt (gsi); SSA_NAME_RANGE_TYPE (lhs),
update_stmt (stmt); SSA_NAME_RANGE_INFO (lhs));
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;
} }
/* 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))
{ {
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 bool can_make_abnormal_goto
= is_gimple_call (stmt) = is_gimple_call (stmt)
&& stmt_can_make_abnormal_goto (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)) 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)
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)
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. */ /* Queue stmt for removal. */
el_to_remove.safe_push (stmt); 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 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 /* 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 if (gimple_modified_p (stmt))
&& useless_type_conversion_p (TREE_TYPE (orig_fn), {
TREE_TYPE (fn)) /* If a formerly non-invariant ADDR_EXPR is turned into an
&& dbg_cnt (devirt)) 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))
{ {
bool can_make_abnormal_goto /* ??? Only fold calls inplace for now, this may create new
= stmt_can_make_abnormal_goto (stmt); SSA names which in turn will confuse free_scc_vn SSA name
bool was_noreturn = gimple_call_noreturn_p (stmt); release code. */
fold_stmt_inplace (&gsi);
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 /* 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. */ /* Replace destination PHI arguments. */
if (can_make_abnormal_goto edge_iterator ei;
&& !stmt_can_make_abnormal_goto (stmt)) edge e;
{ FOR_EACH_EDGE (e, ei, b->succs)
bitmap_set_bit (need_ab_cleanup, {
gimple_bb (stmt)->index); for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
if (dump_file && (dump_flags & TDF_DETAILS)) {
fprintf (dump_file, " Removed AB side-effects.\n"); 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);
/* Changing an indirect call to a direct call may if (TREE_CODE (arg) != SSA_NAME
have exposed different semantics. This may || virtual_operand_p (arg))
require an SSA update. */ continue;
el_todo |= TODO_update_ssa_only_virtuals; 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)
{ {
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)
/* 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);
} }
} }

View File

@ -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