re PR middle-end/30905 (Fails to cross-jump)
authorSteven Bosscher <stevenb.gcc@gmail.com>
Fri, 11 Jan 2008 14:55:34 +0000 (14:55 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 11 Jan 2008 14:55:34 +0000 (14:55 +0000)
2008-01-11  Steven Bosscher  <stevenb.gcc@gmail.com>

PR rtl-optimization/30905
* cfgcleanup.c: Include dce.h
(crossjumps_occured): New global variable.
(try_crossjump_bb): Exit loop after finding a fallthru edge.
If something changed, set crossjumps_occured to true.
(try_optimize_cfg): Clear crossjumps_occured at the beginning.
Don't add/remove fake edges to exit here...
(cleanup_cfg): ...but do it here, when crossjumping.
Run a fast DCE when successful crossjumps occured in the latest
iteration of try_optimize_cfg.

From-SVN: r131468

gcc/ChangeLog
gcc/cfgcleanup.c

index 7d9f5e7..a6017c5 100644 (file)
@@ -1,3 +1,16 @@
+2008-01-11  Steven Bosscher  <stevenb.gcc@gmail.com>
+
+       PR rtl-optimization/30905
+       * cfgcleanup.c: Include dce.h
+       (crossjumps_occured): New global variable.
+       (try_crossjump_bb): Exit loop after finding a fallthru edge.
+       If something changed, set crossjumps_occured to true.
+       (try_optimize_cfg): Clear crossjumps_occured at the beginning.
+       Don't add/remove fake edges to exit here...
+       (cleanup_cfg): ...but do it here, when crossjumping.
+       Run a fast DCE when successful crossjumps occured in the latest
+       iteration of try_optimize_cfg.
+
 2008-01-11  Richard Guenther  <rguenther@suse.de>
 
        * tree-ssa-sccvn.c (struct vn_binary_op_s): Move hashcode near opcode.
index b1c94da..3ec7d3f 100644 (file)
@@ -54,11 +54,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "expr.h"
 #include "df.h"
+#include "dce.h"
 
 #define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
 
 /* Set to true when we are running first pass of try_optimize_cfg loop.  */
 static bool first_pass;
+
+/* Set to true if crossjumps occured in the latest run of try_optimize_cfg.  */
+static bool crossjumps_occured;
+
 static bool try_crossjump_to_edge (int, edge, edge);
 static bool try_crossjump_bb (int, basic_block);
 static bool outgoing_edges_match (int, basic_block, basic_block);
@@ -1838,7 +1843,10 @@ try_crossjump_bb (int mode, basic_block bb)
   FOR_EACH_EDGE (e, ei, bb->preds)
     {
       if (e->flags & EDGE_FALLTHRU)
-       fallthru = e;
+       {
+         fallthru = e;
+         break;
+       }
     }
 
   changed = false;
@@ -1847,7 +1855,8 @@ try_crossjump_bb (int mode, basic_block bb)
       e = EDGE_PRED (ev, ix);
       ix++;
 
-      /* As noted above, first try with the fallthru predecessor.  */
+      /* As noted above, first try with the fallthru predecessor (or, a
+        fallthru predecessor if we are in cfglayout mode).  */
       if (fallthru)
        {
          /* Don't combine the fallthru edge into anything else.
@@ -1921,6 +1930,9 @@ try_crossjump_bb (int mode, basic_block bb)
        }
     }
 
+  if (changed)
+    crossjumps_occured = true;
+
   return changed;
 }
 
@@ -1935,12 +1947,11 @@ try_optimize_cfg (int mode)
   int iterations = 0;
   basic_block bb, b, next;
 
-  if (mode & CLEANUP_CROSSJUMP)
-    add_noreturn_fake_exit_edges ();
-
   if (mode & (CLEANUP_CROSSJUMP | CLEANUP_THREADING))
     clear_bb_flags ();
 
+  crossjumps_occured = false;
+
   FOR_EACH_BB (bb)
     update_forwarder_flag (bb);
 
@@ -2131,9 +2142,6 @@ try_optimize_cfg (int mode)
       while (changed);
     }
 
-  if (mode & CLEANUP_CROSSJUMP)
-    remove_fake_exit_edges ();
-
   FOR_ALL_BB (b)
     b->flags &= ~(BB_FORWARDER_BLOCK | BB_NONTHREADABLE_BLOCK);
 
@@ -2235,20 +2243,44 @@ cleanup_cfg (int mode)
 
   compact_blocks ();
 
+  /* To tail-merge blocks ending in the same noreturn function (e.g.
+     a call to abort) we have to insert fake edges to exit.  Do this
+     here once.  The fake edges do not interfere with any other CFG
+     cleanups.  */
+  if (mode & CLEANUP_CROSSJUMP)
+    add_noreturn_fake_exit_edges ();
+
   while (try_optimize_cfg (mode))
     {
       delete_unreachable_blocks (), changed = true;
-      if (!(mode & CLEANUP_NO_INSN_DEL)
-         && (mode & CLEANUP_EXPENSIVE)
-         && !reload_completed)
+      if (!(mode & CLEANUP_NO_INSN_DEL))
        {
-         if (!delete_trivially_dead_insns (get_insns (), max_reg_num ()))
+         /* Try to remove some trivially dead insns when doing an expensive
+            cleanup.  But delete_trivially_dead_insns doesn't work after
+            reload (it only handles pseudos) and run_fast_dce is too costly
+            to run in every iteration.
+
+            For effective cross jumping, we really want to run a fast DCE to
+            clean up any dead conditions, or they get in the way of performing
+            useful tail merges.
+
+            Other transformations in cleanup_cfg are not so sensitive to dead
+            code, so delete_trivially_dead_insns or even doing nothing at all
+            is good enough.  */
+         if ((mode & CLEANUP_EXPENSIVE) && !reload_completed
+             && !delete_trivially_dead_insns (get_insns (), max_reg_num ()))
            break;
+         else if ((mode & CLEANUP_CROSSJUMP)
+                  && crossjumps_occured)
+           run_fast_dce ();
        }
       else
        break;
     }
 
+  if (mode & CLEANUP_CROSSJUMP)
+    remove_fake_exit_edges ();
+
   /* Don't call delete_dead_jumptables in cfglayout mode, because
      that function assumes that jump tables are in the insns stream.
      But we also don't _have_ to delete dead jumptables in cfglayout