mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-16 13:01:21 +08:00
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:
parent
17dea42fc4
commit
e106efc780
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" } } */
|
||||
|
18
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c
Normal file
18
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-6.c
Normal 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" } } */
|
19
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c
Normal file
19
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-7.c
Normal 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" } } */
|
28
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c
Normal file
28
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-8.c
Normal 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" } } */
|
19
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c
Normal file
19
gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-9.c
Normal 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" } } */
|
@ -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))
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user