tree-ssa-propagate.c: Include domwalk.h.

2014-06-17  Richard Biener  <rguenther@suse.de>

	* tree-ssa-propagate.c: Include domwalk.h.
	(substitute_and_fold): Outline main worker into a domwalker ...
	(substitute_and_fold_dom_walker::before_dom_children): ... here.
	Schedule stmts we can fully propagate for removal.  Remove
	poor-mans DCE.
	(substitute_and_fold): Apply a dominator walk to perform
	substitution.  Process stmts scheduled for removal here.

	* gcc.dg/tree-ssa/20041122-1.c: Adjust.
	* gcc.dg/tree-ssa/forwprop-21.c: Likewise.
	* gcc.dg/tree-ssa/vrp35.c: Revert previous adjustments.
	* gcc.dg/tree-ssa/vrp36.c: Likewise.
	* gcc.dg/vect/nodump-forwprop-22.c: Adjust.

From-SVN: r211725
This commit is contained in:
Richard Biener 2014-06-17 07:42:47 +00:00 committed by Richard Biener
parent a4ab23b698
commit ec18e2ebbf
8 changed files with 217 additions and 204 deletions

View File

@ -1,3 +1,13 @@
2014-06-17 Richard Biener <rguenther@suse.de>
* tree-ssa-propagate.c: Include domwalk.h.
(substitute_and_fold): Outline main worker into a domwalker ...
(substitute_and_fold_dom_walker::before_dom_children): ... here.
Schedule stmts we can fully propagate for removal. Remove
poor-mans DCE.
(substitute_and_fold): Apply a dominator walk to perform
substitution. Process stmts scheduled for removal here.
2014-06-17 Richard Biener <rguenther@suse.de>
* tree-ssa-loop-im.c (determine_max_movement): Adjust cost

View File

@ -1,3 +1,11 @@
2014-06-17 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/20041122-1.c: Adjust.
* gcc.dg/tree-ssa/forwprop-21.c: Likewise.
* gcc.dg/tree-ssa/vrp35.c: Revert previous adjustments.
* gcc.dg/tree-ssa/vrp36.c: Likewise.
* gcc.dg/vect/nodump-forwprop-22.c: Adjust.
2014-06-17 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-lim-12.c: New testcase.

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fstrict-aliasing -fdump-tree-fre1" } */
/* { dg-options "-O1 -fstrict-aliasing -fdump-tree-cddce1" } */
__extension__ typedef __SIZE_TYPE__ size_t;
extern void *xmalloc (size_t) __attribute__ ((__malloc__));
@ -34,5 +34,5 @@ find_unreachable_blocks (void)
able to determine that modifying e->dest->flags does not
modify e or e->dest if we can assert strict-aliasing rules.
The net result is that we only need one load of e->dest. */
/* { dg-final { scan-tree-dump-times "->dest" 1 "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
/* { dg-final { scan-tree-dump-times "->dest" 1 "cddce1" } } */
/* { dg-final { cleanup-tree-dump "cddce1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-copyprop1" } */
/* { dg-options "-O -fdump-tree-cddce1 -fno-tree-fre" } */
typedef int v4si __attribute__ ((vector_size (4 * sizeof(int))));
int
@ -10,7 +10,7 @@ test (v4si *x, v4si *y)
return z[2];
}
/* Optimization in forwprop1, cleanup in copyprop1. */
/* Optimization in forwprop1, cleanup in cddce1. */
/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "copyprop1" } } */
/* { dg-final { cleanup-tree-dump "copyprop1" } } */
/* { dg-final { scan-tree-dump-not "VEC_PERM_EXPR" "cddce1" } } */
/* { dg-final { cleanup-tree-dump "cddce1" } } */

View File

@ -11,5 +11,5 @@ int test1(int i, int k)
return 1;
}
/* { dg-final { scan-tree-dump-not "j_.* == 10" "vrp1" } } */
/* { dg-final { scan-tree-dump "Folding predicate j_.* == 10 to 0" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -8,5 +8,5 @@ int foo(int i)
return 1;
}
/* { dg-final { scan-tree-dump-not "i_.* == 1" "vrp1" } } */
/* { dg-final { scan-tree-dump "Folding predicate i_.* == 1 to 0" "vrp1" } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,7 +1,7 @@
/* { dg-do compile } */
/* { dg-require-effective-target vect_double } */
/* { dg-require-effective-target vect_perm } */
/* { dg-additional-options "-fdump-tree-copyprop1" } */
/* { dg-additional-options "-fdump-tree-cddce1 -fno-tree-fre" } */
typedef double vec __attribute__((vector_size (2 * sizeof (double))));
void f (vec *px, vec *y, vec *z)
@ -13,8 +13,8 @@ void f (vec *px, vec *y, vec *z)
*z = t2;
}
/* Optimization in forwprop1, cleanup in copyprop1. */
/* Optimization in forwprop1, cleanup in cddce1. */
/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 1 "copyprop1" } } */
/* { dg-final { scan-tree-dump-not "BIT_FIELD_REF" "copyprop1" } } */
/* { dg-final { cleanup-tree-dump "copyprop1" } } */
/* { dg-final { scan-tree-dump-times "VEC_PERM_EXPR" 1 "cddce1" } } */
/* { dg-final { scan-tree-dump-not "BIT_FIELD_REF" "cddce1" } } */
/* { dg-final { cleanup-tree-dump "cddce1" } } */

View File

@ -49,6 +49,7 @@
#include "tree-ssa-propagate.h"
#include "langhooks.h"
#include "value-prof.h"
#include "domwalk.h"
/* This file implements a generic value propagation engine based on
the same propagation used by the SSA-CCP algorithm [1].
@ -1017,6 +1018,164 @@ replace_phi_args_in (gimple phi, ssa_prop_get_value_fn get_value)
}
class substitute_and_fold_dom_walker : public dom_walker
{
public:
substitute_and_fold_dom_walker (cdi_direction direction,
ssa_prop_get_value_fn get_value_fn_,
ssa_prop_fold_stmt_fn fold_fn_,
bool do_dce_)
: dom_walker (direction), get_value_fn (get_value_fn_),
fold_fn (fold_fn_), do_dce (do_dce_), something_changed (false)
{
stmts_to_remove.create (0);
}
~substitute_and_fold_dom_walker () { stmts_to_remove.release (); }
virtual void before_dom_children (basic_block);
virtual void after_dom_children (basic_block) {}
ssa_prop_get_value_fn get_value_fn;
ssa_prop_fold_stmt_fn fold_fn;
bool do_dce;
bool something_changed;
vec<gimple> stmts_to_remove;
};
void
substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
{
gimple_stmt_iterator i;
/* Propagate known values into PHI nodes. */
for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
{
gimple phi = gsi_stmt (i);
tree res = gimple_phi_result (phi);
if (virtual_operand_p (res))
continue;
if (do_dce
&& res && TREE_CODE (res) == SSA_NAME)
{
tree sprime = get_value_fn (res);
if (sprime
&& sprime != res
&& may_propagate_copy (res, sprime))
{
stmts_to_remove.safe_push (phi);
continue;
}
}
replace_phi_args_in (phi, get_value_fn);
}
/* Propagate known values into stmts. In some case it exposes
more trivially deletable stmts to walk backward. */
for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
{
bool did_replace;
gimple stmt = gsi_stmt (i);
gimple old_stmt;
enum gimple_code code = gimple_code (stmt);
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
range information for names and they are discarded
afterwards. */
if (code == GIMPLE_ASSIGN
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR)
continue;
/* No point propagating into a stmt we have a value for we
can propagate into all uses. Mark it for removal instead. */
tree lhs = gimple_get_lhs (stmt);
if (do_dce
&& lhs && TREE_CODE (lhs) == SSA_NAME)
{
tree sprime = get_value_fn (lhs);
if (sprime
&& sprime != lhs
&& may_propagate_copy (lhs, sprime)
&& !stmt_could_throw_p (stmt)
&& !gimple_has_side_effects (stmt))
{
stmts_to_remove.safe_push (stmt);
continue;
}
}
/* Replace the statement with its folded version and mark it
folded. */
did_replace = false;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding statement: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
old_stmt = stmt;
/* Some statements may be simplified using propagator
specific information. Do this before propagating
into the stmt to not disturb pass specific information. */
if (fold_fn
&& (*fold_fn)(&i))
{
did_replace = true;
prop_stats.num_stmts_folded++;
stmt = gsi_stmt (i);
update_stmt (stmt);
}
/* Replace real uses in the statement. */
did_replace |= replace_uses_in (stmt, get_value_fn);
/* If we made a replacement, fold the statement. */
if (did_replace)
fold_stmt (&i);
/* Now cleanup. */
if (did_replace)
{
stmt = gsi_stmt (i);
/* If we cleaned up EH information from the statement,
remove EH edges. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
gimple_purge_dead_eh_edges (bb);
if (is_gimple_assign (stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
== GIMPLE_SINGLE_RHS))
{
tree rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (rhs) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (rhs);
}
/* Determine what needs to be done to update the SSA form. */
update_stmt (stmt);
if (!is_gimple_debug (stmt))
something_changed = true;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
if (did_replace)
{
fprintf (dump_file, "Folded into: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
fprintf (dump_file, "\n");
}
else
fprintf (dump_file, "Not folded\n");
}
}
}
/* Perform final substitution and folding of propagated values.
PROP_VALUE[I] contains the single value that should be substituted
@ -1038,204 +1197,39 @@ substitute_and_fold (ssa_prop_get_value_fn get_value_fn,
ssa_prop_fold_stmt_fn fold_fn,
bool do_dce)
{
basic_block bb;
bool something_changed = false;
unsigned i;
if (!get_value_fn && !fold_fn)
return false;
gcc_assert (get_value_fn);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nSubstituting values and folding statements\n\n");
memset (&prop_stats, 0, sizeof (prop_stats));
/* Substitute lattice values at definition sites. */
if (get_value_fn)
for (i = 1; i < num_ssa_names; ++i)
{
tree name = ssa_name (i);
tree val;
gimple def_stmt;
gimple_stmt_iterator gsi;
calculate_dominance_info (CDI_DOMINATORS);
substitute_and_fold_dom_walker walker(CDI_DOMINATORS,
get_value_fn, fold_fn, do_dce);
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
if (!name
|| virtual_operand_p (name))
continue;
def_stmt = SSA_NAME_DEF_STMT (name);
if (gimple_nop_p (def_stmt)
/* Do not substitute ASSERT_EXPR rhs, this will confuse VRP. */
|| (gimple_assign_single_p (def_stmt)
&& gimple_assign_rhs_code (def_stmt) == ASSERT_EXPR)
|| !(val = (*get_value_fn) (name))
|| !may_propagate_copy (name, val))
continue;
gsi = gsi_for_stmt (def_stmt);
if (is_gimple_assign (def_stmt))
{
gimple_assign_set_rhs_with_ops (&gsi, TREE_CODE (val),
val, NULL_TREE);
gcc_assert (gsi_stmt (gsi) == def_stmt);
if (maybe_clean_eh_stmt (def_stmt))
gimple_purge_dead_eh_edges (gimple_bb (def_stmt));
update_stmt (def_stmt);
}
else if (is_gimple_call (def_stmt))
{
int flags = gimple_call_flags (def_stmt);
/* Don't optimize away calls that have side-effects. */
if ((flags & (ECF_CONST|ECF_PURE)) == 0
|| (flags & ECF_LOOPING_CONST_OR_PURE))
continue;
if (update_call_from_tree (&gsi, val)
&& maybe_clean_or_replace_eh_stmt (def_stmt, gsi_stmt (gsi)))
gimple_purge_dead_eh_edges (gimple_bb (gsi_stmt (gsi)));
}
else if (gimple_code (def_stmt) == GIMPLE_PHI)
{
gimple new_stmt = gimple_build_assign (name, val);
gimple_stmt_iterator gsi2;
gsi2 = gsi_after_labels (gimple_bb (def_stmt));
gsi_insert_before (&gsi2, new_stmt, GSI_SAME_STMT);
remove_phi_node (&gsi, false);
}
something_changed = true;
}
/* Propagate into all uses and fold. */
FOR_EACH_BB_FN (bb, cfun)
/* We cannot remove stmts during the BB walk, especially not release
SSA names there as that destroys the lattice of our callers.
Remove stmts in reverse order to make debug stmt creation possible. */
while (!walker.stmts_to_remove.is_empty ())
{
gimple_stmt_iterator i;
/* Propagate known values into PHI nodes. */
if (get_value_fn)
for (i = gsi_start_phis (bb); !gsi_end_p (i); gsi_next (&i))
replace_phi_args_in (gsi_stmt (i), get_value_fn);
/* Propagate known values into stmts. Do a backward walk if
do_dce is true. In some case it exposes
more trivially deletable stmts to walk backward. */
for (i = (do_dce ? gsi_last_bb (bb) : gsi_start_bb (bb)); !gsi_end_p (i);)
gimple stmt = walker.stmts_to_remove.pop ();
if (dump_file && dump_flags & TDF_DETAILS)
{
bool did_replace;
gimple stmt = gsi_stmt (i);
gimple old_stmt;
enum gimple_code code = gimple_code (stmt);
gimple_stmt_iterator oldi;
oldi = i;
if (do_dce)
gsi_prev (&i);
else
gsi_next (&i);
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
range information for names and they are discarded
afterwards. */
if (code == GIMPLE_ASSIGN
&& TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR)
continue;
/* No point propagating into a stmt whose result is not used,
but instead we might be able to remove a trivially dead stmt.
Don't do this when called from VRP, since the SSA_NAME which
is going to be released could be still referenced in VRP
ranges. */
if (do_dce
&& gimple_get_lhs (stmt)
&& TREE_CODE (gimple_get_lhs (stmt)) == SSA_NAME
&& has_zero_uses (gimple_get_lhs (stmt))
&& !stmt_could_throw_p (stmt)
&& !gimple_has_side_effects (stmt))
{
gimple_stmt_iterator i2;
if (dump_file && dump_flags & TDF_DETAILS)
{
fprintf (dump_file, "Removing dead stmt ");
print_gimple_stmt (dump_file, stmt, 0, 0);
fprintf (dump_file, "\n");
}
prop_stats.num_dce++;
i2 = gsi_for_stmt (stmt);
gsi_remove (&i2, true);
release_defs (stmt);
continue;
}
/* Replace the statement with its folded version and mark it
folded. */
did_replace = false;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding statement: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
old_stmt = stmt;
/* Some statements may be simplified using propagator
specific information. Do this before propagating
into the stmt to not disturb pass specific information. */
if (fold_fn
&& (*fold_fn)(&oldi))
{
did_replace = true;
prop_stats.num_stmts_folded++;
stmt = gsi_stmt (oldi);
update_stmt (stmt);
}
/* Replace real uses in the statement. */
if (get_value_fn)
did_replace |= replace_uses_in (stmt, get_value_fn);
/* If we made a replacement, fold the statement. */
if (did_replace)
fold_stmt (&oldi);
/* Now cleanup. */
if (did_replace)
{
stmt = gsi_stmt (oldi);
/* If we cleaned up EH information from the statement,
remove EH edges. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
gimple_purge_dead_eh_edges (bb);
if (is_gimple_assign (stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
== GIMPLE_SINGLE_RHS))
{
tree rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (rhs) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (rhs);
}
/* Determine what needs to be done to update the SSA form. */
update_stmt (stmt);
if (!is_gimple_debug (stmt))
something_changed = true;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
if (did_replace)
{
fprintf (dump_file, "Folded into: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
fprintf (dump_file, "\n");
}
else
fprintf (dump_file, "Not folded\n");
}
fprintf (dump_file, "Removing dead stmt ");
print_gimple_stmt (dump_file, stmt, 0, 0);
fprintf (dump_file, "\n");
}
prop_stats.num_dce++;
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
if (gimple_code (stmt) == GIMPLE_PHI)
remove_phi_node (&gsi, true);
else
{
unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
release_defs (stmt);
}
}
@ -1247,7 +1241,8 @@ substitute_and_fold (ssa_prop_get_value_fn get_value_fn,
prop_stats.num_stmts_folded);
statistics_counter_event (cfun, "Statements deleted",
prop_stats.num_dce);
return something_changed;
return walker.something_changed;
}