[PATCH] Improve DOM's optimization of control statements
* tree-ssa-dom.c (optimize_stmt): Collapse control flow statements with constant conditions. * tree-ssa-threadupdate.c (remove_jump_threads_starting_at): New. (remove_ctrl_stmt_and_useless_edges): No longer static. * tree-ssa-threadupdate.h (remove_jump_threads_starting_at): Prototype. (remove_ctrl_stmt_and_useless_edges): Likewise. * gcc.dg/tree-ssa/ssa-dom-branch-1.c: New test. From-SVN: r228306
This commit is contained in:
parent
9702ee6a6f
commit
d64f8dd280
6 changed files with 99 additions and 28 deletions
|
@ -1,3 +1,12 @@
|
|||
2015-09-30 Jeff Law <law@redhat.com>
|
||||
|
||||
* tree-ssa-dom.c (optimize_stmt): Collapse control flow statements
|
||||
with constant conditions.
|
||||
* tree-ssa-threadupdate.c (remove_jump_threads_starting_at): New.
|
||||
(remove_ctrl_stmt_and_useless_edges): No longer static.
|
||||
* tree-ssa-threadupdate.h (remove_jump_threads_starting_at): Prototype.
|
||||
(remove_ctrl_stmt_and_useless_edges): Likewise.
|
||||
|
||||
2015-09-30 Nathan Sidwell <nathan@codesourcery.com>
|
||||
Cesar Philippidis <cesar@codesourcery.com>
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2015-09-30 Jeff Law <law@redhat.com>
|
||||
|
||||
* gcc.dg/tree-ssa/ssa-dom-branch-1.c: New test.
|
||||
|
||||
2015-09-30 Bernd Edlinger <bernd.edlinger@hotmail.de>
|
||||
|
||||
PR rtl-optimization/67037
|
||||
|
|
29
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c
Normal file
29
gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -w -fdump-tree-dom1-details" } */
|
||||
|
||||
typedef struct rtx_def *rtx;
|
||||
struct rtx_def
|
||||
{
|
||||
int code;
|
||||
rtx rt_rtx;
|
||||
};
|
||||
rtx
|
||||
try_combine (rtx i1, rtx newpat)
|
||||
{
|
||||
rtx temp;
|
||||
if (i1 && (temp = ((((((newpat->rt_rtx, ((((temp)->code) == 42)))))))))
|
||||
&& ((temp =
|
||||
(((((((((((newpat)->rt_rtx),
|
||||
((((temp)->code) == 42) && arf ())))))))))))))
|
||||
;
|
||||
else if (i1 && foo ());
|
||||
}
|
||||
|
||||
/* There should be three tests against i1. Two from the hash table
|
||||
dumps, one in the code itself. */
|
||||
/* { dg-final { scan-tree-dump-times "if .i1_" 3 "dom1"} } */
|
||||
|
||||
/* There should be no actual jump threads realized by DOM. The
|
||||
legitimize jump threads are handled in VRP and those discovered
|
||||
by DOM are subsumed by collapsing a conditional. */
|
||||
/* { dg-final { scan-tree-dump-not "Threaded" "dom1"} } */
|
|
@ -1820,31 +1820,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
|
|||
if (is_gimple_assign (stmt))
|
||||
record_equivalences_from_stmt (stmt, may_optimize_p, avail_exprs_stack);
|
||||
|
||||
/* If STMT is a COND_EXPR and it was modified, then we may know
|
||||
where it goes. If that is the case, then mark the CFG as altered.
|
||||
|
||||
This will cause us to later call remove_unreachable_blocks and
|
||||
cleanup_tree_cfg when it is safe to do so. It is not safe to
|
||||
clean things up here since removal of edges and such can trigger
|
||||
the removal of PHI nodes, which in turn can release SSA_NAMEs to
|
||||
the manager.
|
||||
|
||||
That's all fine and good, except that once SSA_NAMEs are released
|
||||
to the manager, we must not call create_ssa_name until all references
|
||||
to released SSA_NAMEs have been eliminated.
|
||||
|
||||
All references to the deleted SSA_NAMEs can not be eliminated until
|
||||
we remove unreachable blocks.
|
||||
|
||||
We can not remove unreachable blocks until after we have completed
|
||||
any queued jump threading.
|
||||
|
||||
We can not complete any queued jump threads until we have taken
|
||||
appropriate variables out of SSA form. Taking variables out of
|
||||
SSA form can call create_ssa_name and thus we lose.
|
||||
|
||||
Ultimately I suspect we're going to need to change the interface
|
||||
into the SSA_NAME manager. */
|
||||
/* If STMT is a COND_EXPR or SWITCH_EXPR and it was modified, then we may
|
||||
know where it goes. */
|
||||
if (gimple_modified_p (stmt) || modified_p)
|
||||
{
|
||||
tree val = NULL;
|
||||
|
@ -1858,8 +1835,27 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
|
|||
else if (gswitch *swtch_stmt = dyn_cast <gswitch *> (stmt))
|
||||
val = gimple_switch_index (swtch_stmt);
|
||||
|
||||
if (val && TREE_CODE (val) == INTEGER_CST && find_taken_edge (bb, val))
|
||||
cfg_altered = true;
|
||||
if (val && TREE_CODE (val) == INTEGER_CST)
|
||||
{
|
||||
edge taken_edge = find_taken_edge (bb, val);
|
||||
if (taken_edge)
|
||||
{
|
||||
/* Delete threads that start at BB. */
|
||||
remove_jump_threads_starting_at (bb);
|
||||
|
||||
/* Now clean up the control statement at the end of
|
||||
BB and remove unexecutable edges. */
|
||||
remove_ctrl_stmt_and_useless_edges (bb, taken_edge->dest);
|
||||
|
||||
/* Fixup the flags on the single remaining edge. */
|
||||
taken_edge->flags
|
||||
&= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE | EDGE_ABNORMAL);
|
||||
taken_edge->flags |= EDGE_FALLTHRU;
|
||||
|
||||
/* Further simplifications may be possible. */
|
||||
cfg_altered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we simplified a statement in such a way as to be shown that it
|
||||
cannot trap, update the eh information and the cfg to match. */
|
||||
|
|
|
@ -260,7 +260,7 @@ struct thread_stats_d thread_stats;
|
|||
Also remove all outgoing edges except the edge which reaches DEST_BB.
|
||||
If DEST_BB is NULL, then remove all outgoing edges. */
|
||||
|
||||
static void
|
||||
void
|
||||
remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
|
@ -2539,6 +2539,37 @@ valid_jump_thread_path (vec<jump_thread_edge *> *path)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Remove any queued jump threads that start at BB. */
|
||||
|
||||
void
|
||||
remove_jump_threads_starting_at (basic_block bb)
|
||||
{
|
||||
if (!paths.exists ())
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < paths.length ();)
|
||||
{
|
||||
vec<jump_thread_edge *> *path = paths[i];
|
||||
|
||||
/* Sadly, FSM jump threads have a slightly different
|
||||
representation than the rest of the jump threads. */
|
||||
if ((*path)[0]->type == EDGE_FSM_THREAD
|
||||
&& (*path)[0]->e->src == bb)
|
||||
{
|
||||
delete_jump_thread_path (path);
|
||||
paths.unordered_remove (i);
|
||||
}
|
||||
else if ((*path)[0]->type != EDGE_FSM_THREAD
|
||||
&& (*path)[0]->e->dest == bb)
|
||||
{
|
||||
delete_jump_thread_path (path);
|
||||
paths.unordered_remove (i);
|
||||
}
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Walk through all blocks and thread incoming edges to the appropriate
|
||||
outgoing edge for each edge pair recorded in THREADED_EDGES.
|
||||
|
||||
|
|
|
@ -43,5 +43,7 @@ public:
|
|||
};
|
||||
|
||||
extern void register_jump_thread (vec <class jump_thread_edge *> *);
|
||||
extern void remove_jump_threads_starting_at (basic_block);
|
||||
extern void delete_jump_thread_path (vec <class jump_thread_edge *> *);
|
||||
extern void remove_ctrl_stmt_and_useless_edges (basic_block, basic_block);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue