OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index b1c94da..203963e 100644 (file)
@@ -54,11 +54,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "expr.h"
 #include "df.h"
+#include "dce.h"
+#include "dbgcnt.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);
@@ -1128,134 +1134,6 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
   return ninsns;
 }
 
-/* Return true iff the condbranches at the end of BB1 and BB2 match.  */
-bool
-condjump_equiv_p (struct equiv_info *info, bool call_init)
-{
-  basic_block bb1 = info->x_block;
-  basic_block bb2 = info->y_block;
-  edge b1 = BRANCH_EDGE (bb1);
-  edge b2 = BRANCH_EDGE (bb2);
-  edge f1 = FALLTHRU_EDGE (bb1);
-  edge f2 = FALLTHRU_EDGE (bb2);
-  bool reverse, match;
-  rtx set1, set2, cond1, cond2;
-  rtx src1, src2;
-  enum rtx_code code1, code2;
-
-  /* Get around possible forwarders on fallthru edges.  Other cases
-     should be optimized out already.  */
-  if (FORWARDER_BLOCK_P (f1->dest))
-    f1 = single_succ_edge (f1->dest);
-
-  if (FORWARDER_BLOCK_P (f2->dest))
-    f2 = single_succ_edge (f2->dest);
-
-  /* To simplify use of this function, return false if there are
-     unneeded forwarder blocks.  These will get eliminated later
-     during cleanup_cfg.  */
-  if (FORWARDER_BLOCK_P (f1->dest)
-      || FORWARDER_BLOCK_P (f2->dest)
-      || FORWARDER_BLOCK_P (b1->dest)
-      || FORWARDER_BLOCK_P (b2->dest))
-    return false;
-
-  if (f1->dest == f2->dest && b1->dest == b2->dest)
-    reverse = false;
-  else if (f1->dest == b2->dest && b1->dest == f2->dest)
-    reverse = true;
-  else
-    return false;
-
-  set1 = pc_set (BB_END (bb1));
-  set2 = pc_set (BB_END (bb2));
-  if ((XEXP (SET_SRC (set1), 1) == pc_rtx)
-      != (XEXP (SET_SRC (set2), 1) == pc_rtx))
-    reverse = !reverse;
-
-  src1 = SET_SRC (set1);
-  src2 = SET_SRC (set2);
-  cond1 = XEXP (src1, 0);
-  cond2 = XEXP (src2, 0);
-  code1 = GET_CODE (cond1);
-  if (reverse)
-    code2 = reversed_comparison_code (cond2, BB_END (bb2));
-  else
-    code2 = GET_CODE (cond2);
-
-  if (code2 == UNKNOWN)
-    return false;
-
-  if (call_init && !struct_equiv_init (STRUCT_EQUIV_START | info->mode, info))
-    gcc_unreachable ();
-  /* Make the sources of the pc sets unreadable so that when we call
-     insns_match_p it won't process them.
-     The death_notes_match_p from insns_match_p won't see the local registers
-     used for the pc set, but that could only cause missed optimizations when
-     there are actually condjumps that use stack registers.  */
-  SET_SRC (set1) = pc_rtx;
-  SET_SRC (set2) = pc_rtx;
-  /* Verify codes and operands match.  */
-  if (code1 == code2)
-    {
-      match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
-              && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 0), 1, info)
-              && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 1), 1, info));
-
-    }
-  else if (code1 == swap_condition (code2))
-    {
-      match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
-              && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 0), 1, info)
-              && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 1), 1, info));
-
-    }
-  else
-    match = false;
-  SET_SRC (set1) = src1;
-  SET_SRC (set2) = src2;
-  match &= verify_changes (0);
-
-  /* If we return true, we will join the blocks.  Which means that
-     we will only have one branch prediction bit to work with.  Thus
-     we require the existing branches to have probabilities that are
-     roughly similar.  */
-  if (match
-      && !optimize_size
-      && maybe_hot_bb_p (bb1)
-      && maybe_hot_bb_p (bb2))
-    {
-      int prob2;
-
-      if (b1->dest == b2->dest)
-       prob2 = b2->probability;
-      else
-       /* Do not use f2 probability as f2 may be forwarded.  */
-       prob2 = REG_BR_PROB_BASE - b2->probability;
-
-      /* Fail if the difference in probabilities is greater than 50%.
-        This rules out two well-predicted branches with opposite
-        outcomes.  */
-      if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 2)
-       {
-         if (dump_file)
-           fprintf (dump_file,
-                    "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
-                    bb1->index, bb2->index, b1->probability, prob2);
-
-         match = false;
-       }
-    }
-
-  if (dump_file && match)
-    fprintf (dump_file, "Conditionals in bb %i and %i match.\n",
-            bb1->index, bb2->index);
-
-  if (!match)
-    cancel_changes (0);
-  return match;
-}
-
 /* Return true iff outgoing edges of BB1 and BB2 match, together with
    the branch instruction.  This means that if we commonize the control
    flow before end of the basic block, the semantic remains unchanged.
@@ -1838,7 +1716,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 +1728,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 +1803,9 @@ try_crossjump_bb (int mode, basic_block bb)
        }
     }
 
+  if (changed)
+    crossjumps_occured = true;
+
   return changed;
 }
 
@@ -1935,12 +1820,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 +2015,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 +2116,47 @@ 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 ();
+
+  if (!dbg_cnt (cfg_cleanup))
+    return changed;
+
   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
@@ -2273,8 +2181,10 @@ rest_of_handle_jump (void)
   return 0;
 }
 
-struct tree_opt_pass pass_jump =
+struct rtl_opt_pass pass_jump =
 {
+ {
+  RTL_PASS,
   "sibling",                            /* name */
   NULL,                                 /* gate */
   rest_of_handle_jump,                 /* execute */
@@ -2287,7 +2197,7 @@ struct tree_opt_pass pass_jump =
   0,                                    /* properties_destroyed */
   TODO_ggc_collect,                     /* todo_flags_start */
   TODO_verify_flow,                     /* todo_flags_finish */
-  'i'                                   /* letter */
+ }
 };
 
 
@@ -2303,8 +2213,10 @@ rest_of_handle_jump2 (void)
 }
 
 
-struct tree_opt_pass pass_jump2 =
+struct rtl_opt_pass pass_jump2 =
 {
+ {
+  RTL_PASS,
   "jump",                               /* name */
   NULL,                                 /* gate */
   rest_of_handle_jump2,                        /* execute */
@@ -2317,7 +2229,7 @@ struct tree_opt_pass pass_jump2 =
   0,                                    /* properties_destroyed */
   TODO_ggc_collect,                     /* todo_flags_start */
   TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
-  'j'                                   /* letter */
+ }
 };