re PR tree-optimization/41490 (tree-ssa-sink does not really work)

2011-03-15  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/41490
	* tree-ssa-dce.c (propagate_necessity): Handle returns without
	value but with VUSE.
	* tree-ssa-operands.c (parse_ssa_operands): Add a VUSE on all
	return statements.
	* tree-ssa-sink.c (statement_sink_location): Fix store sinking.
	* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Handle virtual PHIs.
	* tree-tailcall.c (find_tail_calls): Ignore returns.

	* gcc.dg/tree-ssa/ssa-sink-6.c: New testcase.
	* gcc.dg/tree-ssa/ssa-sink-7.c: Likewise.
	* gcc.dg/tree-ssa/ssa-sink-8.c: Likewise.
	* gcc.dg/tree-ssa/ssa-sink-9.c: Likewise.
	* g++.dg/tree-ssa/pr33604.C: Adjust.

From-SVN: r170984
This commit is contained in:
Richard Guenther 2011-03-15 11:09:09 +00:00 committed by Richard Biener
parent 17dea42fc4
commit e106efc780
12 changed files with 204 additions and 54 deletions

View File

@ -1,3 +1,14 @@
2011-03-15 Richard Guenther <rguenther@suse.de>
PR tree-optimization/41490
* tree-ssa-dce.c (propagate_necessity): Handle returns without
value but with VUSE.
* tree-ssa-operands.c (parse_ssa_operands): Add a VUSE on all
return statements.
* tree-ssa-sink.c (statement_sink_location): Fix store sinking.
* tree-ssa-phiopt.c (tree_ssa_phiopt_worker): Handle virtual PHIs.
* tree-tailcall.c (find_tail_calls): Ignore returns.
2011-03-15 Richard Guenther <rguenther@suse.de>
PR middle-end/48031

View File

@ -1,3 +1,12 @@
2011-03-15 Richard Guenther <rguenther@suse.de>
PR tree-optimization/41490
* gcc.dg/tree-ssa/ssa-sink-6.c: New testcase.
* gcc.dg/tree-ssa/ssa-sink-7.c: Likewise.
* gcc.dg/tree-ssa/ssa-sink-8.c: Likewise.
* gcc.dg/tree-ssa/ssa-sink-9.c: Likewise.
* g++.dg/tree-ssa/pr33604.C: Adjust.
2011-03-14 Jakub Jelinek <jakub@redhat.com>
PR middle-end/47917

View File

@ -42,7 +42,8 @@ int main(int argc, char *argv[])
yielding
D.2137.lhs.m ={v} &I;
so that SRA can promote all locals to registers and we end up
referencing a single virtual operand at abort () after optimization. */
referencing two virtual operands at abort () and the return
after optimization. */
/* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 1 "optimized" } } */
/* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 2 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -0,0 +1,18 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-sink" } */
int foo(int *a, int r)
{
int ret = 0;
*a = 1;
if (r == 3)
*a = 5;
else
ret = r + 20;
return ret;
}
/* *a = 1 should be sunk to the else block. */
/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
/* { dg-final { cleanup-tree-dump "sink" } } */

View File

@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-sink" } */
int foo(int *a, int r, short *b)
{
int ret = 0;
*a = 1;
if (r == 3)
*a = 5;
else
ret = r + 20;
*b = 9;
return ret;
}
/* *a = 1 should be sunk to the else block. */
/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
/* { dg-final { cleanup-tree-dump "sink" } } */

View File

@ -0,0 +1,28 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-sink" } */
int foo(int *a, int r, short *b)
{
int ret = 0;
*a = 1;
switch (r)
{
case 3:
*a = 5;
break;
case 4:
case 5:
*a = 9;
ret = r + 25;
break;
default:
ret = r + 20;
}
*b = 9;
return ret;
}
/* *a = 1 should be sunk into the default case. */
/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
/* { dg-final { cleanup-tree-dump "sink" } } */

View File

@ -0,0 +1,19 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-sink" } */
int foo(int *a, int r, int *b)
{
int ret = 0;
*a = 1;
if (r == 3)
{
*a = 5;
*b = 3;
}
return ret;
}
/* *a = 1 should be sunk to the else block. */
/* { dg-final { scan-tree-dump-times "Sinking" 1 "sink" } } */
/* { dg-final { cleanup-tree-dump "sink" } } */

View File

@ -869,7 +869,8 @@ propagate_necessity (struct edge_list *el)
{
tree rhs = gimple_return_retval (stmt);
/* A return statement may perform a load. */
if (TREE_CODE (rhs) != SSA_NAME
if (rhs
&& TREE_CODE (rhs) != SSA_NAME
&& !is_gimple_min_invariant (rhs))
{
if (!ref_may_be_aliased (rhs))

View File

@ -1065,6 +1065,9 @@ parse_ssa_operands (gimple stmt)
/* Add call-clobbered operands, if needed. */
if (code == GIMPLE_CALL)
maybe_add_call_vops (stmt);
if (code == GIMPLE_RETURN)
append_vuse (gimple_vop (cfun));
}
}

View File

@ -311,14 +311,26 @@ tree_ssa_phiopt_worker (bool do_store_elim)
else
{
gimple_seq phis = phi_nodes (bb2);
gimple_stmt_iterator gsi;
/* Check to make sure that there is only one PHI node.
/* Check to make sure that there is only one non-virtual PHI node.
TODO: we could do it with more than one iff the other PHI nodes
have the same elements for these two edges. */
if (! gimple_seq_singleton_p (phis))
phi = NULL;
for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
{
if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
continue;
if (phi)
{
phi = NULL;
break;
}
phi = gsi_stmt (gsi);
}
if (!phi)
continue;
phi = gsi_stmt (gsi_start (phis));
arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
arg1 = gimple_phi_arg_def (phi, e2->dest_idx);

View File

@ -268,7 +268,6 @@ statement_sink_location (gimple stmt, basic_block frombb,
gimple_stmt_iterator *togsi)
{
gimple use;
tree def;
use_operand_p one_use = NULL_USE_OPERAND_P;
basic_block sinkbb;
use_operand_p use_p;
@ -276,24 +275,17 @@ statement_sink_location (gimple stmt, basic_block frombb,
ssa_op_iter iter;
imm_use_iterator imm_iter;
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
{
FOR_EACH_IMM_USE_FAST (one_use, imm_iter, def)
{
if (is_gimple_debug (USE_STMT (one_use)))
continue;
break;
}
if (one_use != NULL_USE_OPERAND_P)
break;
}
/* Return if there are no immediate uses of this stmt. */
if (one_use == NULL_USE_OPERAND_P)
/* We only can sink assignments. */
if (!is_gimple_assign (stmt))
return false;
if (gimple_code (stmt) != GIMPLE_ASSIGN)
/* We only can sink stmts with a single definition. */
def_p = single_ssa_def_operand (stmt, SSA_OP_ALL_DEFS);
if (def_p == NULL_DEF_OPERAND_P)
return false;
/* Return if there are no immediate uses of this stmt. */
if (has_zero_uses (DEF_FROM_PTR (def_p)))
return false;
/* There are a few classes of things we can't or don't move, some because we
@ -323,20 +315,14 @@ statement_sink_location (gimple stmt, basic_block frombb,
*/
if (stmt_ends_bb_p (stmt)
|| gimple_has_side_effects (stmt)
|| is_hidden_global_store (stmt)
|| gimple_has_volatile_ops (stmt)
|| gimple_vuse (stmt)
|| (gimple_vuse (stmt) && !gimple_vdef (stmt))
|| (cfun->has_local_explicit_reg_vars
&& TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode))
return false;
FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
{
tree def = DEF_FROM_PTR (def_p);
if (is_global_var (SSA_NAME_VAR (def))
|| SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
return false;
}
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (DEF_FROM_PTR (def_p)))
return false;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
{
@ -345,11 +331,40 @@ statement_sink_location (gimple stmt, basic_block frombb,
return false;
}
use = NULL;
/* If stmt is a store the one and only use needs to be the VOP
merging PHI node. */
if (gimple_vdef (stmt))
{
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
{
gimple use_stmt = USE_STMT (use_p);
/* A killing definition is not a use. */
if (gimple_assign_single_p (use_stmt)
&& gimple_vdef (use_stmt)
&& operand_equal_p (gimple_assign_lhs (stmt),
gimple_assign_lhs (use_stmt), 0))
continue;
if (gimple_code (use_stmt) != GIMPLE_PHI)
return false;
if (use
&& use != use_stmt)
return false;
use = use_stmt;
}
if (!use)
return false;
}
/* If all the immediate uses are not in the same place, find the nearest
common dominator of all the immediate uses. For PHI nodes, we have to
find the nearest common dominator of all of the predecessor blocks, since
that is where insertion would have to take place. */
if (!all_immediate_uses_same_place (stmt))
else if (!all_immediate_uses_same_place (stmt))
{
bool debug_stmts = false;
basic_block commondom = nearest_common_dominator_of_uses (stmt,
@ -387,31 +402,35 @@ statement_sink_location (gimple stmt, basic_block frombb,
return true;
}
use = USE_STMT (one_use);
if (gimple_code (use) != GIMPLE_PHI)
else
{
sinkbb = gimple_bb (use);
if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
|| sinkbb->loop_father != frombb->loop_father)
return false;
FOR_EACH_IMM_USE_FAST (one_use, imm_iter, DEF_FROM_PTR (def_p))
{
if (is_gimple_debug (USE_STMT (one_use)))
continue;
break;
}
use = USE_STMT (one_use);
/* Move the expression to a post dominator can't reduce the number of
executions. */
if (dominated_by_p (CDI_POST_DOMINATORS, frombb, sinkbb))
return false;
if (gimple_code (use) != GIMPLE_PHI)
{
sinkbb = gimple_bb (use);
if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
|| sinkbb->loop_father != frombb->loop_father)
return false;
*togsi = gsi_for_stmt (use);
/* Move the expression to a post dominator can't reduce the number of
executions. */
if (dominated_by_p (CDI_POST_DOMINATORS, frombb, sinkbb))
return false;
return true;
*togsi = gsi_for_stmt (use);
return true;
}
}
/* Note that at this point, all uses must be in the same statement, so it
doesn't matter which def op we choose, pick the first one. */
FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
break;
sinkbb = find_bb_for_arg (use, def);
sinkbb = find_bb_for_arg (use, DEF_FROM_PTR (def_p));
if (!sinkbb)
return false;
@ -486,6 +505,14 @@ sink_code_in_bb (basic_block bb)
bb->index, (gsi_bb (togsi))->index);
}
/* Prepare for VOP update. */
if (gimple_vdef (stmt))
{
unlink_stmt_vdef (stmt);
gimple_set_vdef (stmt, gimple_vop (cfun));
mark_sym_for_renaming (gimple_vop (cfun));
}
/* If this is the end of the basic block, we need to insert at the end
of the basic block. */
if (gsi_end_p (togsi))

View File

@ -399,8 +399,10 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
{
stmt = gsi_stmt (gsi);
/* Ignore labels. */
if (gimple_code (stmt) == GIMPLE_LABEL || is_gimple_debug (stmt))
/* Ignore labels, returns and debug stmts. */
if (gimple_code (stmt) == GIMPLE_LABEL
|| gimple_code (stmt) == GIMPLE_RETURN
|| is_gimple_debug (stmt))
continue;
/* Check for a call. */