Commit 23ab2e4e by Kazu Hirata Committed by Kazu Hirata

re PR tree-optimization/15349 ([tree-ssa] Merge two phi nodes.)

	PR tree-optimization/15349
	* timevar.def (TV_TREE_MERGE_PHI): New.
	* tree-cfg.c (tree_forwarder_block_p): Add a new argument
	PHI_WANTED.
	(remove_forwarder_block, cleanup_forwarder_blocks): Adjust the
	calls to tree_forwarder_block_p.
	(remove_forwarder_block_with_phi, merge_phi_nodes,
	gate_merge_phi, pass_merge_phi): New.
	* tree-optimize.c (init_tree_optimization_passes): Add
	pass_merge_phi.
	* tree-pass.h: Add an extern for pass_merge_phi;

	PR tree-optimization/15349
	* testsuite/gcc.dg/tree-ssa/pr15349.c: New.

From-SVN: r93977
parent db01eeba
2005-01-20 Kazu Hirata <kazu@cs.umass.edu>
PR tree-optimization/15349
* timevar.def (TV_TREE_MERGE_PHI): New.
* tree-cfg.c (tree_forwarder_block_p): Add a new argument
PHI_WANTED.
(remove_forwarder_block, cleanup_forwarder_blocks): Adjust the
calls to tree_forwarder_block_p.
(remove_forwarder_block_with_phi, merge_phi_nodes,
gate_merge_phi, pass_merge_phi): New.
* tree-optimize.c (init_tree_optimization_passes): Add
pass_merge_phi.
* tree-pass.h: Add an extern for pass_merge_phi;
2005-01-20 Richard Henderson <rth@redhat.com>
PR target/19418
......
2005-01-20 Kazu Hirata <kazu@cs.umass.edu>
PR tree-optimization/15349
* gcc.dg/tree-ssa/pr15349.c: New.
2005-01-20 Steve Ellcey <sje@cup.hp.com>
* gcc.dg/tree-ssa/loop-1.c: Fix target names on xfail.
......
/* PR 15349. Merge two PHI nodes. */
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-mergephi" } */
int
foo (int a, int b)
{
int t;
if (b)
{
if (a)
t = 3;
else
t = 5;
a = 0;
}
else
t = 7;
return t;
}
/* { dg-final { scan-tree-dump-times "PHI" 1 "mergephi"} } */
......@@ -83,6 +83,7 @@ DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate")
DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE")
DEFTIMEVAR (TV_TREE_CD_DCE , "tree aggressive DCE")
DEFTIMEVAR (TV_TREE_DSE , "tree DSE")
DEFTIMEVAR (TV_TREE_MERGE_PHI , "PHI merge")
DEFTIMEVAR (TV_TREE_LOOP , "tree loop optimization")
DEFTIMEVAR (TV_TREE_LOOP_BOUNDS , "tree record loop bounds")
DEFTIMEVAR (TV_LIM , "loop invariant motion")
......
......@@ -119,7 +119,7 @@ static void split_critical_edges (void);
static inline bool stmt_starts_bb_p (tree, tree);
static int tree_verify_flow_info (void);
static void tree_make_forwarder_block (edge);
static bool tree_forwarder_block_p (basic_block);
static bool tree_forwarder_block_p (basic_block, bool);
static void tree_cfg2vcg (FILE *);
/* Flowgraph optimization and cleanup. */
......@@ -3889,16 +3889,15 @@ tree_make_forwarder_block (edge fallthru)
ENTRY_BLOCK_PTR. */
static bool
tree_forwarder_block_p (basic_block bb)
tree_forwarder_block_p (basic_block bb, bool phi_wanted)
{
block_stmt_iterator bsi;
/* BB must have a single outgoing edge. */
if (EDGE_COUNT (bb->succs) != 1
/* BB can not have any PHI nodes. This could potentially be
relaxed early in compilation if we re-rewrote the variables
appearing in any PHI nodes in forwarder blocks. */
|| phi_nodes (bb)
/* If PHI_WANTED is false, BB must not have any PHI nodes.
Otherwise, BB must have PHI nodes. */
|| (phi_nodes (bb) != NULL_TREE) != phi_wanted
/* BB may not be a predecessor of EXIT_BLOCK_PTR. */
|| EDGE_SUCC (bb, 0)->dest == EXIT_BLOCK_PTR
/* Nor should this be an infinite loop. */
......@@ -4040,7 +4039,7 @@ remove_forwarder_block (basic_block bb, basic_block **worklist)
that it was not a forwarder before, since it used to have
at least two outgoing edges, so we may just add it to
worklist. */
if (tree_forwarder_block_p (s->src))
if (tree_forwarder_block_p (s->src, false))
*(*worklist)++ = s->src;
}
}
......@@ -4097,7 +4096,7 @@ cleanup_forwarder_blocks (void)
FOR_EACH_BB (bb)
{
if (tree_forwarder_block_p (bb))
if (tree_forwarder_block_p (bb, false))
*current++ = bb;
}
......@@ -4111,6 +4110,211 @@ cleanup_forwarder_blocks (void)
return changed;
}
/* Merge the PHI nodes at BB into those at BB's sole successor. */
static void
remove_forwarder_block_with_phi (basic_block bb)
{
edge succ = EDGE_SUCC (bb, 0);
basic_block dest = succ->dest;
basic_block dombb, domdest, dom;
block_stmt_iterator bsi;
/* We check for infinite loops already in tree_forwarder_block_p.
However it may happen that the infinite loop is created
afterwards due to removal of forwarders. */
if (dest == bb)
return;
/* If the destination block consists of a nonlocal label, do not
merge it. */
for (bsi = bsi_start (dest); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
if (TREE_CODE (stmt) != LABEL_EXPR)
break;
if (DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
return;
}
/* Redirect each incoming edge to BB to DEST. */
while (EDGE_COUNT (bb->preds) > 0)
{
edge e = EDGE_PRED (bb, 0), s;
tree phi;
s = find_edge (e->src, dest);
if (s)
{
/* We already have an edge S from E->src to DEST. If S and
E->dest's sole successor edge have the same PHI arguments
at DEST, redirect S to DEST. */
if (phi_alternatives_equal (dest, s, succ))
{
e = redirect_edge_and_branch (e, dest);
PENDING_STMT (e) = NULL_TREE;
continue;
}
/* PHI arguemnts are different. Create a forwarder block by
splitting E so that we can merge PHI arguments on E to
DEST. */
e = EDGE_SUCC (split_edge (e), 0);
}
s = redirect_edge_and_branch (e, dest);
/* redirect_edge_and_branch must not create a new edge. */
gcc_assert (s == e);
/* Add to the PHI nodes at DEST each PHI argument removed at the
destination of E. */
for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
{
tree def = PHI_ARG_DEF (phi, succ->dest_idx);
if (TREE_CODE (def) == SSA_NAME)
{
tree var;
/* If DEF is one of the results of PHI nodes removed during
redirection, replace it with the PHI argument that used
to be on E. */
for (var = PENDING_STMT (e); var; var = TREE_CHAIN (var))
{
tree old_arg = TREE_PURPOSE (var);
tree new_arg = TREE_VALUE (var);
if (def == old_arg)
{
def = new_arg;
break;
}
}
}
add_phi_arg (phi, def, s);
}
PENDING_STMT (e) = NULL;
}
/* Update the dominators. */
dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
if (domdest == bb)
{
/* Shortcut to avoid calling (relatively expensive)
nearest_common_dominator unless necessary. */
dom = dombb;
}
else
dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
set_immediate_dominator (CDI_DOMINATORS, dest, dom);
/* Remove BB since all of BB's incoming edges have been redirected
to DEST. */
delete_basic_block (bb);
}
/* This pass performs merges PHI nodes if one feeds into another. For
example, suppose we have the following:
goto <bb 9> (<L9>);
<L8>:;
tem_17 = foo ();
# tem_6 = PHI <tem_17(8), tem_23(7)>;
<L9>:;
# tem_3 = PHI <tem_6(9), tem_2(5)>;
<L10>:;
Then we merge the first PHI node into the second one like so:
goto <bb 9> (<L10>);
<L8>:;
tem_17 = foo ();
# tem_3 = PHI <tem_23(7), tem_2(5), tem_17(8)>;
<L10>:;
*/
static void
merge_phi_nodes (void)
{
basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks);
basic_block *current = worklist;
basic_block bb;
calculate_dominance_info (CDI_DOMINATORS);
/* Find all PHI nodes that we may be able to merge. */
FOR_EACH_BB (bb)
{
basic_block dest;
/* Look for a forwarder block with PHI nodes. */
if (!tree_forwarder_block_p (bb, true))
continue;
dest = EDGE_SUCC (bb, 0)->dest;
/* We have to feed into another basic block with PHI
nodes. */
if (!phi_nodes (dest)
/* We don't want to deal with a basic block with
abnormal edges. */
|| has_abnormal_incoming_edge_p (bb))
continue;
if (!dominated_by_p (CDI_DOMINATORS, dest, bb))
{
/* If BB does not dominate DEST, then the PHI nodes at
DEST must be the only users of the results of the PHI
nodes at BB. */
*current++ = bb;
}
}
/* Now let's drain WORKLIST. */
while (current != worklist)
{
bb = *--current;
remove_forwarder_block_with_phi (bb);
}
free (worklist);
}
static bool
gate_merge_phi (void)
{
return 1;
}
struct tree_opt_pass pass_merge_phi = {
"mergephi", /* name */
gate_merge_phi, /* gate */
merge_phi_nodes, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_TREE_MERGE_PHI, /* tv_id */
PROP_cfg | PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
| TODO_verify_ssa,
0 /* letter */
};
/* Return a non-special label in the head of basic block BLOCK.
Create one if it doesn't exist. */
......
......@@ -354,6 +354,7 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_dominator);
NEXT_PASS (pass_redundant_phi);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_may_alias);
......
......@@ -142,6 +142,7 @@ extern struct tree_opt_pass pass_del_ssa;
extern struct tree_opt_pass pass_dominator;
extern struct tree_opt_pass pass_dce;
extern struct tree_opt_pass pass_cd_dce;
extern struct tree_opt_pass pass_merge_phi;
extern struct tree_opt_pass pass_may_alias;
extern struct tree_opt_pass pass_split_crit_edges;
extern struct tree_opt_pass pass_pre;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment