This patch tweaks tree-ssa-dom.c to use the new capability in the dom walker. Additionally:

The code to remove jump threading paths now runs after the walk is finished rather than when the conditional is optimized. The code which optimizes conditionals replaces the condition with a true/false condition and clears EDGE_EXECUTABLE.

When we try to find equivalences from PHIs, we ignore a PHI arg associated with an unexecutable edge.

When we look for blocks that have a single incoming edge, ignoring loop edges, we ignore edges that are not executable.

That's enough to get all the benefits of the current implementation on the trunk, and as slightly better code than the trunk in certain cases.

Obviously if we twiddle the member names in patch #1, then this patch will need corresponding trivial updates.

Jeff
commit 89a7f78005a5ec4788383ecd44474c85103693b5
Author: Jeff Law <l...@redhat.com>
Date:   Mon Dec 7 22:43:06 2015 -0700

        PR tree-optimization/68619
        * tree-ssa-dom.c (pass_dominator:execute): Use new methods
        from dom_walker to handle unreachable code.  If a block has an
        unreachable edge, remove all jump threads through any successor
        of the affected block.
        (dom_opt_dom_walker::thread_across_edge): Do not thread across
        edges without EDGE_EXECUTABLE set.
        (record_equivalences_from_phis): Ignore alternatives if the edge
        does not have EDGE_EXECUTABLE set.
        (single_incoming_edge_ignoring_loop_edges): Similarly.
        (dom_opt_dom_walker::before_dom_children): Use new methods from
        dom_walker to handle unreachable code.
        (dom_opt_dom_walker::after_dom_children): Similarly.
        (optimize_stmt): If a gimple_code has a compile-time constant
        condition, clear EDGE_EXECUTABLE on the non-taken edges.  Also
        change the condition to true/false as necessary.

diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index aeb726c..c48951e 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -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;

Reply via email to