re PR tree-optimization/43934 (LIM should handle PHI nodes)

2010-05-06  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/43934
	* tree-ssa-loop-im.c (movement_possibility): Handle PHI nodes.
	(stmt_cost): Likewise.
	(extract_true_false_args_from_phi): New helper.
	(determine_max_movement): For PHI nodes verify we can hoist them
	and compute their cost.
	(determine_invariantness_stmt): Handle PHI nodes.
	(move_computations_stmt): Likewise.  Hoist PHI nodes in
	if-converted form using COND_EXPRs.
	(move_computations): Return TODO_cleanup_cfg if we hoisted PHI
	nodes.
	(tree_ssa_lim): Likewise.
	* tree-flow.h (tree_ssa_lim): Adjust prototype.
	* tree-ssa-loop.c (tree_ssa_loop_im): Return todo.

	* gcc.dg/tree-ssa/ssa-lim-9.c: New testcase.

From-SVN: r159099
This commit is contained in:
Richard Guenther 2010-05-06 09:04:00 +00:00 committed by Richard Biener
parent a81b065a47
commit e3bdfed62a
6 changed files with 304 additions and 11 deletions

View file

@ -1,3 +1,20 @@
2010-05-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43934
* tree-ssa-loop-im.c (movement_possibility): Handle PHI nodes.
(stmt_cost): Likewise.
(extract_true_false_args_from_phi): New helper.
(determine_max_movement): For PHI nodes verify we can hoist them
and compute their cost.
(determine_invariantness_stmt): Handle PHI nodes.
(move_computations_stmt): Likewise. Hoist PHI nodes in
if-converted form using COND_EXPRs.
(move_computations): Return TODO_cleanup_cfg if we hoisted PHI
nodes.
(tree_ssa_lim): Likewise.
* tree-flow.h (tree_ssa_lim): Adjust prototype.
* tree-ssa-loop.c (tree_ssa_loop_im): Return todo.
2010-05-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43987

View file

@ -1,3 +1,18 @@
2010-05-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43934
* gcc.dg/tree-ssa/ssa-lim-9.c: New testcase.
2010-05-06 Richard Guenther <rguenther@suse.de>
PR tree-optimization/43987
* gcc.c-torture/execute/pr43987.c: New testcase.
* gcc.dg/torture/pta-escape-1.c: Adjust.
* gcc.dg/tree-ssa/pta-escape-1.c: Likewise.
* gcc.dg/tree-ssa/pta-escape-2.c: Likewise.
* gcc.dg/tree-ssa/pta-escape-3.c: Likewise.
* gcc.dg/ipa/ipa-pta-11.c: Likewise.
2010-04-22 Jakub Jelinek <jakub@redhat.com>
Dodji Seketeli <dodji@redhat.com>

View file

@ -0,0 +1,20 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-lim1-details" } */
void bar (int);
void foo (int n, int m)
{
unsigned i;
for (i = 0; i < n; ++i)
{
int x;
if (m < 0)
x = 1+n;
else
x = m-n;
bar (x);
}
}
/* { dg-final { scan-tree-dump-times "Moving PHI node" 1 "lim1" } } */
/* { dg-final { cleanup-tree-dump "lim1" } } */

View file

@ -685,7 +685,7 @@ basic_block *blocks_in_phiopt_order (void);
/* In tree-ssa-loop*.c */
void tree_ssa_lim (void);
unsigned int tree_ssa_lim (void);
unsigned int tree_ssa_unswitch_loops (void);
unsigned int canonicalize_induction_variables (void);
unsigned int tree_unroll_loops_completely (bool, bool);

View file

@ -359,6 +359,12 @@ movement_possibility (gimple stmt)
return MOVE_POSSIBLE;
}
if (gimple_code (stmt) == GIMPLE_PHI
&& gimple_phi_num_args (stmt) <= 2
&& is_gimple_reg (gimple_phi_result (stmt))
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (stmt)))
return MOVE_POSSIBLE;
if (gimple_get_lhs (stmt) == NULL_TREE)
return MOVE_IMPOSSIBLE;
@ -513,7 +519,8 @@ stmt_cost (gimple stmt)
unsigned cost = 1;
/* Always try to create possibilities for unswitching. */
if (gimple_code (stmt) == GIMPLE_COND)
if (gimple_code (stmt) == GIMPLE_COND
|| gimple_code (stmt) == GIMPLE_PHI)
return LIM_EXPENSIVE;
/* Hoisting memory references out should almost surely be a win. */
@ -651,6 +658,63 @@ mem_ref_in_stmt (gimple stmt)
return ref;
}
/* From a controlling predicate in DOM determine the arguments from
the PHI node PHI that are chosen if the predicate evaluates to
true and false and store them to *TRUE_ARG_P and *FALSE_ARG_P if
they are non-NULL. Returns true if the arguments can be determined,
else return false. */
static bool
extract_true_false_args_from_phi (basic_block dom, gimple phi,
tree *true_arg_p, tree *false_arg_p)
{
basic_block bb = gimple_bb (phi);
edge true_edge, false_edge, tem;
tree arg0 = NULL_TREE, arg1 = NULL_TREE;
/* We have to verify that one edge into the PHI node is dominated
by the true edge of the predicate block and the other edge
dominated by the false edge. This ensures that the PHI argument
we are going to take is completely determined by the path we
take from the predicate block. */
extract_true_false_edges_from_block (dom, &true_edge, &false_edge);
tem = EDGE_PRED (bb, 0);
if (tem == true_edge
|| tem->src == true_edge->dest
|| dominated_by_p (CDI_DOMINATORS,
tem->src, true_edge->dest))
arg0 = PHI_ARG_DEF (phi, tem->dest_idx);
else if (tem == false_edge
|| tem->src == false_edge->dest
|| dominated_by_p (CDI_DOMINATORS,
tem->src, false_edge->dest))
arg1 = PHI_ARG_DEF (phi, tem->dest_idx);
else
return false;
tem = EDGE_PRED (bb, 1);
if (tem == true_edge
|| tem->src == true_edge->dest
|| dominated_by_p (CDI_DOMINATORS,
tem->src, true_edge->dest))
arg0 = PHI_ARG_DEF (phi, tem->dest_idx);
else if (tem == false_edge
|| tem->src == false_edge->dest
|| dominated_by_p (CDI_DOMINATORS,
tem->src, false_edge->dest))
arg1 = PHI_ARG_DEF (phi, tem->dest_idx);
else
return false;
if (!arg0 || !arg1)
return false;
if (true_arg_p)
*true_arg_p = arg0;
if (false_arg_p)
*false_arg_p = arg1;
return true;
}
/* Determine the outermost loop to that it is possible to hoist a statement
STMT and store it to LIM_DATA (STMT)->max_loop. To do this we determine
the outermost loop in that the value computed by STMT is invariant.
@ -677,9 +741,81 @@ determine_max_movement (gimple stmt, bool must_preserve_exec)
level = superloop_at_depth (loop, 1);
lim_data->max_loop = level;
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_USE)
if (!add_dependency (val, lim_data, loop, true))
return false;
if (gimple_code (stmt) == GIMPLE_PHI)
{
use_operand_p use_p;
unsigned min_cost = UINT_MAX;
unsigned total_cost = 0;
struct lim_aux_data *def_data;
/* We will end up promoting dependencies to be unconditionally
evaluated. For this reason the PHI cost (and thus the
cost we remove from the loop by doing the invariant motion)
is that of the cheapest PHI argument dependency chain. */
FOR_EACH_PHI_ARG (use_p, stmt, iter, SSA_OP_USE)
{
val = USE_FROM_PTR (use_p);
if (TREE_CODE (val) != SSA_NAME)
continue;
if (!add_dependency (val, lim_data, loop, false))
return false;
def_data = get_lim_data (SSA_NAME_DEF_STMT (val));
if (def_data)
{
min_cost = MIN (min_cost, def_data->cost);
total_cost += def_data->cost;
}
}
lim_data->cost += min_cost;
if (gimple_phi_num_args (stmt) > 1)
{
basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb);
gimple cond;
if (gsi_end_p (gsi_last_bb (dom)))
return false;
cond = gsi_stmt (gsi_last_bb (dom));
if (gimple_code (cond) != GIMPLE_COND)
return false;
/* Verify that this is an extended form of a diamond and
the PHI arguments are completely controlled by the
predicate in DOM. */
if (!extract_true_false_args_from_phi (dom, stmt, NULL, NULL))
return false;
/* Fold in dependencies and cost of the condition. */
FOR_EACH_SSA_TREE_OPERAND (val, cond, iter, SSA_OP_USE)
{
if (!add_dependency (val, lim_data, loop, false))
return false;
def_data = get_lim_data (SSA_NAME_DEF_STMT (val));
if (def_data)
total_cost += def_data->cost;
}
/* We want to avoid unconditionally executing very expensive
operations. As costs for our dependencies cannot be
negative just claim we are not invariand for this case.
We also are not sure whether the control-flow inside the
loop will vanish. */
if (total_cost - min_cost >= 2 * LIM_EXPENSIVE
&& !(min_cost != 0
&& total_cost / min_cost <= 2))
return false;
/* Assume that the control-flow in the loop will vanish.
??? We should verify this and not artificially increase
the cost if that is not the case. */
lim_data->cost += stmt_cost (stmt);
}
return true;
}
else
FOR_EACH_SSA_TREE_OPERAND (val, stmt, iter, SSA_OP_USE)
if (!add_dependency (val, lim_data, loop, true))
return false;
if (gimple_vuse (stmt))
{
@ -920,6 +1056,43 @@ determine_invariantness_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
fprintf (dump_file, "Basic block %d (loop %d -- depth %d):\n\n",
bb->index, bb->loop_father->num, loop_depth (bb->loop_father));
/* Look at PHI nodes, but only if there is at most two.
??? We could relax this further by post-processing the inserted
code and transforming adjacent cond-exprs with the same predicate
to control flow again. */
bsi = gsi_start_phis (bb);
if (!gsi_end_p (bsi)
&& ((gsi_next (&bsi), gsi_end_p (bsi))
|| (gsi_next (&bsi), gsi_end_p (bsi))))
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
stmt = gsi_stmt (bsi);
pos = movement_possibility (stmt);
if (pos == MOVE_IMPOSSIBLE)
continue;
lim_data = init_lim_data (stmt);
lim_data->always_executed_in = outermost;
if (!determine_max_movement (stmt, false))
{
lim_data->max_loop = NULL;
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_gimple_stmt (dump_file, stmt, 2, 0);
fprintf (dump_file, " invariant up to level %d, cost %d.\n\n",
loop_depth (lim_data->max_loop),
lim_data->cost);
}
if (lim_data->cost >= LIM_EXPENSIVE)
set_profitable_level (stmt);
}
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
{
stmt = gsi_stmt (bsi);
@ -1021,7 +1194,7 @@ determine_invariantness (void)
for walk_dominator_tree. */
static void
move_computations_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
move_computations_stmt (struct dom_walk_data *dw_data,
basic_block bb)
{
struct loop *level;
@ -1033,6 +1206,67 @@ move_computations_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
if (!loop_outer (bb->loop_father))
return;
for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); )
{
gimple new_stmt;
stmt = gsi_stmt (bsi);
lim_data = get_lim_data (stmt);
if (lim_data == NULL)
{
gsi_next (&bsi);
continue;
}
cost = lim_data->cost;
level = lim_data->tgt_loop;
clear_lim_data (stmt);
if (!level)
{
gsi_next (&bsi);
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Moving PHI node\n");
print_gimple_stmt (dump_file, stmt, 0, 0);
fprintf (dump_file, "(cost %u) out of loop %d.\n\n",
cost, level->num);
}
if (gimple_phi_num_args (stmt) == 1)
{
tree arg = PHI_ARG_DEF (stmt, 0);
new_stmt = gimple_build_assign_with_ops (TREE_CODE (arg),
gimple_phi_result (stmt),
arg, NULL_TREE);
SSA_NAME_DEF_STMT (gimple_phi_result (stmt)) = new_stmt;
}
else
{
basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb);
gimple cond = gsi_stmt (gsi_last_bb (dom));
tree arg0 = NULL_TREE, arg1 = NULL_TREE, t;
/* Get the PHI arguments corresponding to the true and false
edges of COND. */
extract_true_false_args_from_phi (dom, stmt, &arg0, &arg1);
gcc_assert (arg0 && arg1);
t = build2 (gimple_cond_code (cond), boolean_type_node,
gimple_cond_lhs (cond), gimple_cond_rhs (cond));
t = build3 (COND_EXPR, TREE_TYPE (gimple_phi_result (stmt)),
t, arg0, arg1);
new_stmt = gimple_build_assign_with_ops (COND_EXPR,
gimple_phi_result (stmt),
t, NULL_TREE);
SSA_NAME_DEF_STMT (gimple_phi_result (stmt)) = new_stmt;
*((unsigned int *)(dw_data->global_data)) |= TODO_cleanup_cfg;
}
gsi_insert_on_edge (loop_preheader_edge (level), new_stmt);
remove_phi_node (&bsi, false);
}
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); )
{
stmt = gsi_stmt (bsi);
@ -1076,12 +1310,14 @@ move_computations_stmt (struct dom_walk_data *dw_data ATTRIBUTE_UNUSED,
/* Hoist the statements out of the loops prescribed by data stored in
LIM_DATA structures associated with each statement.*/
static void
static unsigned int
move_computations (void)
{
struct dom_walk_data walk_data;
unsigned int todo = 0;
memset (&walk_data, 0, sizeof (struct dom_walk_data));
walk_data.global_data = &todo;
walk_data.dom_direction = CDI_DOMINATORS;
walk_data.before_dom_children = move_computations_stmt;
@ -1092,6 +1328,8 @@ move_computations (void)
gsi_commit_edge_inserts ();
if (need_ssa_update_p (cfun))
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
return todo;
}
/* Checks whether the statement defining variable *INDEX can be hoisted
@ -2328,9 +2566,11 @@ tree_ssa_lim_finalize (void)
/* Moves invariants from loops. Only "expensive" invariants are moved out --
i.e. those that are likely to be win regardless of the register pressure. */
void
unsigned int
tree_ssa_lim (void)
{
unsigned int todo;
tree_ssa_lim_initialize ();
/* Gathers information about memory accesses in the loops. */
@ -2345,7 +2585,9 @@ tree_ssa_lim (void)
store_motion ();
/* Move the expressions that are expensive enough. */
move_computations ();
todo = move_computations ();
tree_ssa_lim_finalize ();
return todo;
}

View file

@ -109,8 +109,7 @@ tree_ssa_loop_im (void)
if (number_of_loops () <= 1)
return 0;
tree_ssa_lim ();
return 0;
return tree_ssa_lim ();
}
static bool