+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>
+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
--- /dev/null
+/* { 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"} } */
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;
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. */
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;
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.
};
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