diff mbox

[RFA,PR,tree-optimization/68619] Avoid direct cfg cleanups in tree-ssa-dom.c [2/3]

Message ID 5666758A.7030608@redhat.com
State New
Headers show

Commit Message

Jeff Law Dec. 8, 2015, 6:15 a.m. UTC
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 <law@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 mbox

Patch

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;