@@ -609,8 +609,39 @@ pass_dominator::execute (function *fun)
dom_opt_dom_walker walker (CDI_DOMINATORS,
const_and_copies,
avail_exprs_stack);
+ walker.init_edge_executable (cfun);
walker.walk (fun->cfg->x_entry_block_ptr);
+ /* Look for blocks where we cleared EDGE_EXECUTABLE on an outgoing
+ edge. When found, remove jump threads which contain any outgoing
+ edge from the affected block. */
+ if (cfg_altered)
+ {
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ edge_iterator ei;
+ edge e;
+
+ /* First see if there are any edges without EDGE_EXECUTABLE
+ set. */
+ bool found = false;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ if ((e->flags & EDGE_EXECUTABLE) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ /* If there were any such edges found, then remove jump threads
+ containing any edge leaving BB. */
+ if (found)
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ remove_jump_threads_including (e);
+ }
+ }
+
{
gimple_stmt_iterator gsi;
basic_block bb;
@@ -893,6 +924,11 @@ record_temporary_equivalences (edge e,
void
dom_opt_dom_walker::thread_across_edge (edge e)
{
+ /* If E is not executable, then there's no reason to bother
+ threading across it. */
+ if ((e->flags & EDGE_EXECUTABLE) == 0)
+ return;
+
if (! m_dummy_cond)
m_dummy_cond =
gimple_build_cond (NE_EXPR,
@@ -951,6 +987,11 @@ record_equivalences_from_phis (basic_block bb)
if (lhs == t)
continue;
+ /* If the associated edge is not marked as executable, then it
+ can be ignored. */
+ if ((gimple_phi_arg_edge (phi, i)->flags & EDGE_EXECUTABLE) == 0)
+ continue;
+
t = dom_valueize (t);
/* If we have not processed an alternative yet, then set
@@ -997,6 +1038,10 @@ single_incoming_edge_ignoring_loop_edges (basic_block bb)
if (dominated_by_p (CDI_DOMINATORS, e->src, e->dest))
continue;
+ /* We can safely ignore edges that are not executable. */
+ if ((e->flags & EDGE_EXECUTABLE) == 0)
+ continue;
+
/* If we have already seen a non-loop edge, then we must have
multiple incoming non-loop edges and thus we return NULL. */
if (retval)
@@ -1307,6 +1352,14 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
m_avail_exprs_stack->push_marker ();
m_const_and_copies->push_marker ();
+ /* If BB is not reachable, then propagate that property to edges, but
+ do not process this block any further. */
+ if (!this->bb_reachable (cfun, bb))
+ {
+ this->propagate_unreachable_to_edges (bb, dump_file, dump_flags);
+ return;
+ }
+
record_equivalences_from_incoming_edge (bb, m_const_and_copies,
m_avail_exprs_stack);
@@ -1339,6 +1392,16 @@ dom_opt_dom_walker::after_dom_children (basic_block bb)
{
gimple *last;
+ /* If this block is not reachable, then there's nothing to do here.
+ However, make sure to restore the tables to their proper state. */
+ if (!this->bb_reachable (cfun, bb))
+ {
+ this->maybe_clear_unreachable_dom (bb);
+ m_avail_exprs_stack->pop_to_marker ();
+ m_const_and_copies->pop_to_marker ();
+ return;
+ }
+
/* If we have an outgoing edge to a block with multiple incoming and
outgoing edges, then we may be able to thread the edge, i.e., we
may be able to statically determine which of the outgoing edges
@@ -1852,22 +1915,25 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
edge taken_edge = find_taken_edge (bb, val);
if (taken_edge)
{
-
- /* We need to remove any queued jump threads that
- reference outgoing edges from this block. */
+ /* Clear the EXECUTABLE flag on the other edges. */
edge_iterator ei;
edge e;
FOR_EACH_EDGE (e, ei, bb->succs)
- remove_jump_threads_including (e);
-
- /* 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);
+ {
+ if (e != taken_edge)
+ e->flags &= ~EDGE_EXECUTABLE;
+ }
- /* Fixup the flags on the single remaining edge. */
- taken_edge->flags
- &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE | EDGE_ABNORMAL);
- taken_edge->flags |= EDGE_FALLTHRU;
+ /* And fix the condition to be either true or false. */
+ if (gimple_code (stmt) == GIMPLE_COND)
+ {
+ if (integer_zerop (val))
+ gimple_cond_make_false (as_a <gcond *> (stmt));
+ else if (integer_onep (val))
+ gimple_cond_make_true (as_a <gcond *> (stmt));
+ else
+ gcc_unreachable ();
+ }
/* Further simplifications may be possible. */
cfg_altered = true;