OSDN Git Service

2006-02-15 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index 373be91..c2c262c 100644 (file)
@@ -1,6 +1,6 @@
 /* Control flow optimization code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This file contains optimizer of the control flow.  The main entry point is
    cleanup_cfg.  Following optimizations are performed:
@@ -50,32 +50,19 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "cfglayout.h"
 #include "emit-rtl.h"
+#include "tree-pass.h"
+#include "cfgloop.h"
+#include "expr.h"
 
-/* cleanup_cfg maintains following flags for each basic block.  */
-
-enum bb_flags
-{
-    /* Set if BB is the forwarder block to avoid too many
-       forwarder_block_p calls.  */
-    BB_FORWARDER_BLOCK = 1,
-    BB_NONTHREADABLE_BLOCK = 2
-};
-
-#define BB_FLAGS(BB) (enum bb_flags) (BB)->aux
-#define BB_SET_FLAG(BB, FLAG) \
-  (BB)->aux = (void *) (long) ((enum bb_flags) (BB)->aux | (FLAG))
-#define BB_CLEAR_FLAG(BB, FLAG) \
-  (BB)->aux = (void *) (long) ((enum bb_flags) (BB)->aux & ~(FLAG))
-
-#define FORWARDER_BLOCK_P(BB) (BB_FLAGS (BB) & BB_FORWARDER_BLOCK)
-
+#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;
 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);
 static int flow_find_cross_jump (int, basic_block, basic_block, rtx *, rtx *);
-static bool insns_match_p (int, rtx, rtx);
+static bool old_insns_match_p (int, rtx, rtx);
 
 static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
 static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
@@ -98,7 +85,7 @@ notice_new_block (basic_block bb)
     return;
 
   if (forwarder_block_p (bb))
-    BB_SET_FLAG (bb, BB_FORWARDER_BLOCK);
+    bb->flags |= BB_FORWARDER_BLOCK;
 }
 
 /* Recompute forwarder flag after block has been modified.  */
@@ -107,9 +94,9 @@ static void
 update_forwarder_flag (basic_block bb)
 {
   if (forwarder_block_p (bb))
-    BB_SET_FLAG (bb, BB_FORWARDER_BLOCK);
+    bb->flags |= BB_FORWARDER_BLOCK;
   else
-    BB_CLEAR_FLAG (bb, BB_FORWARDER_BLOCK);
+    bb->flags &= ~BB_FORWARDER_BLOCK;
 }
 \f
 /* Simplify a conditional jump around an unconditional jump.
@@ -139,11 +126,11 @@ try_simplify_condjump (basic_block cbranch_block)
      be the last block in the function, and must contain just the
      unconditional jump.  */
   jump_block = cbranch_fallthru_edge->dest;
-  if (EDGE_COUNT (jump_block->preds) >= 2
+  if (!single_pred_p (jump_block)
       || jump_block->next_bb == EXIT_BLOCK_PTR
       || !FORWARDER_BLOCK_P (jump_block))
     return false;
-  jump_dest_block = EDGE_SUCC (jump_block, 0)->dest;
+  jump_dest_block = single_succ (jump_block);
 
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
@@ -155,9 +142,8 @@ try_simplify_condjump (basic_block cbranch_block)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
-         || (cbranch_jump_edge->flags & EDGE_CROSSING)))
+  if (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
+      || (cbranch_jump_edge->flags & EDGE_CROSSING))
     return false;
 
   /* The conditional branch must target the block after the
@@ -283,7 +269,7 @@ thread_jump (int mode, edge e, basic_block b)
   bool failed = false;
   reg_set_iterator rsi;
 
-  if (BB_FLAGS (b) & BB_NONTHREADABLE_BLOCK)
+  if (b->flags & BB_NONTHREADABLE_BLOCK)
     return NULL;
 
   /* At the moment, we do handle only conditional jumps, but later we may
@@ -292,7 +278,7 @@ thread_jump (int mode, edge e, basic_block b)
     return NULL;
   if (EDGE_COUNT (b->succs) != 2)
     {
-      BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+      b->flags |= BB_NONTHREADABLE_BLOCK;
       return NULL;
     }
 
@@ -302,7 +288,7 @@ thread_jump (int mode, edge e, basic_block b)
 
   if (!any_condjump_p (BB_END (b)) || !onlyjump_p (BB_END (b)))
     {
-      BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+      b->flags |= BB_NONTHREADABLE_BLOCK;
       return NULL;
     }
 
@@ -340,7 +326,7 @@ thread_jump (int mode, edge e, basic_block b)
        insn = NEXT_INSN (insn))
     if (INSN_P (insn) && side_effects_p (PATTERN (insn)))
       {
-       BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+       b->flags |= BB_NONTHREADABLE_BLOCK;
        return NULL;
       }
 
@@ -353,7 +339,7 @@ thread_jump (int mode, edge e, basic_block b)
     if (INSN_P (insn))
       cselib_process_insn (insn);
 
-  nonequal = BITMAP_XMALLOC();
+  nonequal = BITMAP_ALLOC (NULL);
   CLEAR_REG_SET (nonequal);
 
   /* Now assume that we've continued by the edge E to B and continue
@@ -384,7 +370,7 @@ thread_jump (int mode, edge e, basic_block b)
      have life information in cfg_cleanup.  */
   if (failed)
     {
-      BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+      b->flags |= BB_NONTHREADABLE_BLOCK;
       goto failed_exit;
     }
 
@@ -396,12 +382,12 @@ thread_jump (int mode, edge e, basic_block b)
   /* In case liveness information is available, we need to prove equivalence
      only of the live values.  */
   if (mode & CLEANUP_UPDATE_LIFE)
-    AND_REG_SET (nonequal, b->global_live_at_end);
+    AND_REG_SET (nonequal, b->il.rtl->global_live_at_end);
 
   EXECUTE_IF_SET_IN_REG_SET (nonequal, 0, i, rsi)
     goto failed_exit;
 
-  BITMAP_XFREE (nonequal);
+  BITMAP_FREE (nonequal);
   cselib_finish ();
   if ((comparison_dominates_p (code1, code2) != 0)
       != (XEXP (SET_SRC (set2), 1) == pc_rtx))
@@ -410,7 +396,7 @@ thread_jump (int mode, edge e, basic_block b)
     return FALLTHRU_EDGE (b);
 
 failed_exit:
-  BITMAP_XFREE (nonequal);
+  BITMAP_FREE (nonequal);
   cselib_finish ();
   return NULL;
 }
@@ -435,8 +421,7 @@ try_forward_edges (int mode, basic_block b)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
+  if (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
     return false;
 
   for (ei = ei_start (b->succs); (e = ei_safe_edge (ei)); )
@@ -459,7 +444,7 @@ try_forward_edges (int mode, basic_block b)
        }
 
       target = first = e->dest;
-      counter = 0;
+      counter = NUM_FIXED_BLOCKS;
 
       /* If we are partitioning hot/cold basic_blocks, we don't want to mess
         up jumps that cross between hot/cold sections.
@@ -471,8 +456,7 @@ try_forward_edges (int mode, basic_block b)
         bb-reorder.c:partition_hot_cold_basic_blocks for complete
         details.  */
 
-      if (flag_reorder_blocks_and_partition
-         && first != EXIT_BLOCK_PTR
+      if (first != EXIT_BLOCK_PTR
          && find_reg_note (BB_END (first), REG_CROSSING_JUMP, NULL_RTX))
        return false;
 
@@ -483,13 +467,13 @@ try_forward_edges (int mode, basic_block b)
          may_thread |= target->flags & BB_DIRTY;
 
          if (FORWARDER_BLOCK_P (target)
-             && !(EDGE_SUCC (target, 0)->flags & EDGE_CROSSING)
-             && EDGE_SUCC (target, 0)->dest != EXIT_BLOCK_PTR)
+             && !(single_succ_edge (target)->flags & EDGE_CROSSING)
+             && single_succ (target) != EXIT_BLOCK_PTR)
            {
              /* Bypass trivial infinite loops.  */
-             if (target == EDGE_SUCC (target, 0)->dest)
+             new_target = single_succ (target);
+             if (target == new_target)
                counter = n_basic_blocks;
-             new_target = EDGE_SUCC (target, 0)->dest;
            }
 
          /* Allow to thread only over one edge at time to simplify updating
@@ -500,8 +484,7 @@ try_forward_edges (int mode, basic_block b)
              if (t)
                {
                  if (!threaded_edges)
-                   threaded_edges = xmalloc (sizeof (*threaded_edges)
-                                             * n_basic_blocks);
+                   threaded_edges = XNEWVEC (edge, n_basic_blocks);
                  else
                    {
                      int i;
@@ -522,7 +505,7 @@ try_forward_edges (int mode, basic_block b)
                  if (t->dest == b)
                    break;
 
-                 gcc_assert (nthreaded_edges < n_basic_blocks);
+                 gcc_assert (nthreaded_edges < n_basic_blocks - NUM_FIXED_BLOCKS);
                  threaded_edges[nthreaded_edges++] = t;
 
                  new_target = t->dest;
@@ -539,7 +522,7 @@ try_forward_edges (int mode, basic_block b)
             For fallthru forwarders, the LOOP_BEG note must appear between
             the header of block and CODE_LABEL of the loop, for non forwarders
             it must appear before the JUMP_INSN.  */
-         if ((mode & CLEANUP_PRE_LOOP) && optimize)
+         if ((mode & CLEANUP_PRE_LOOP) && optimize && flag_loop_optimize)
            {
              rtx insn = (EDGE_SUCC (target, 0)->flags & EDGE_FALLTHRU
                          ? BB_HEAD (target) : prev_nonnote_insn (BB_END (target)));
@@ -553,7 +536,7 @@ try_forward_edges (int mode, basic_block b)
                    && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
                  break;
 
-             if (NOTE_P (insn))
+             if (insn && NOTE_P (insn))
                break;
 
              /* Do not clean up branches to just past the end of a loop
@@ -612,13 +595,13 @@ try_forward_edges (int mode, basic_block b)
                            / REG_BR_PROB_BASE);
 
          if (!FORWARDER_BLOCK_P (b) && forwarder_block_p (b))
-           BB_SET_FLAG (b, BB_FORWARDER_BLOCK);
+           b->flags |= BB_FORWARDER_BLOCK;
 
          do
            {
              edge t;
 
-             if (EDGE_COUNT (first->succs) > 1)
+             if (!single_succ_p (first))
                {
                  gcc_assert (n < nthreaded_edges);
                  t = threaded_edges [n++];
@@ -642,7 +625,7 @@ try_forward_edges (int mode, basic_block b)
                  if (n < nthreaded_edges
                      && first == threaded_edges [n]->src)
                    n++;
-                 t = EDGE_SUCC (first, 0);
+                 t = single_succ_edge (first);
                }
 
              t->count -= edge_count;
@@ -684,9 +667,7 @@ merge_blocks_move_predecessor_nojumps (basic_block a, basic_block b)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && (BB_PARTITION (a) != BB_PARTITION (b)
-         || find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)))
+  if (BB_PARTITION (a) != BB_PARTITION (b))
     return;
 
   barrier = next_nonnote_insn (BB_END (a));
@@ -742,9 +723,7 @@ merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
-         || BB_PARTITION (a) != BB_PARTITION (b)))
+  if (BB_PARTITION (a) != BB_PARTITION (b))
     return;
 
   real_b_end = BB_END (b);
@@ -814,10 +793,7 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
-         || find_reg_note (BB_END (c), REG_CROSSING_JUMP, NULL_RTX)
-         || BB_PARTITION (b) != BB_PARTITION (c)))
+  if (BB_PARTITION (b) != BB_PARTITION (c))
     return NULL;
       
     
@@ -999,7 +975,7 @@ merge_memattrs (rtx x, rtx y)
 /* Return true if I1 and I2 are equivalent and thus can be crossjumped.  */
 
 static bool
-insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
+old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
 {
   rtx p1, p2;
 
@@ -1153,7 +1129,7 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
       if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
        break;
 
-      if (!insns_match_p (mode, i1, i2))
+      if (!old_insns_match_p (mode, i1, i2))
        break;
 
       merge_memattrs (i1, i2);
@@ -1217,6 +1193,134 @@ 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.
@@ -1233,11 +1337,12 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
 
   /* If BB1 has only one successor, we may be looking at either an
      unconditional jump, or a fake edge to exit.  */
-  if (EDGE_COUNT (bb1->succs) == 1
-      && (EDGE_SUCC (bb1, 0)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+  if (single_succ_p (bb1)
+      && (single_succ_edge (bb1)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
       && (!JUMP_P (BB_END (bb1)) || simplejump_p (BB_END (bb1))))
-    return (EDGE_COUNT (bb2->succs) == 1
-           && (EDGE_SUCC (bb2, 0)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+    return (single_succ_p (bb2)
+           && (single_succ_edge (bb2)->flags
+               & (EDGE_COMPLEX | EDGE_FAKE)) == 0
            && (!JUMP_P (BB_END (bb2)) || simplejump_p (BB_END (bb2))));
 
   /* Match conditional jumps - this may get tricky when fallthru and branch
@@ -1264,10 +1369,10 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
       /* Get around possible forwarders on fallthru edges.  Other cases
          should be optimized out already.  */
       if (FORWARDER_BLOCK_P (f1->dest))
-       f1 = EDGE_SUCC (f1->dest, 0);
+       f1 = single_succ_edge (f1->dest);
 
       if (FORWARDER_BLOCK_P (f2->dest))
-       f2 = EDGE_SUCC (f2->dest, 0);
+       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
@@ -1353,7 +1458,6 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
   /* Generic case - we are seeing a computed jump, table jump or trapping
      instruction.  */
 
-#ifndef CASE_DROPS_THROUGH
   /* Check whether there are tablejumps in the end of BB1 and BB2.
      Return true if they are identical.  */
     {
@@ -1408,7 +1512,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
                  rr.update_label_nuses = false;
                  for_each_rtx (&BB_END (bb1), replace_label, &rr);
 
-                 match = insns_match_p (mode, BB_END (bb1), BB_END (bb2));
+                 match = old_insns_match_p (mode, BB_END (bb1), BB_END (bb2));
                  if (dump_file && match)
                    fprintf (dump_file,
                             "Tablejumps in bb %i and %i match.\n",
@@ -1427,11 +1531,10 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
          return false;
        }
     }
-#endif
 
   /* First ensure that the instructions match.  There may be many outgoing
      edges so this test is generally cheaper.  */
-  if (!insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
+  if (!old_insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
     return false;
 
   /* Search the outgoing edges, ensure that the counts do match, find possible
@@ -1465,9 +1568,9 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
   if (fallthru1)
     {
       basic_block d1 = (forwarder_block_p (fallthru1->dest)
-                       ? EDGE_SUCC (fallthru1->dest, 0)->dest: fallthru1->dest);
+                       ? single_succ (fallthru1->dest): fallthru1->dest);
       basic_block d2 = (forwarder_block_p (fallthru2->dest)
-                       ? EDGE_SUCC (fallthru2->dest, 0)->dest: fallthru2->dest);
+                       ? single_succ (fallthru2->dest): fallthru2->dest);
 
       if (d1 != d2)
        return false;
@@ -1485,11 +1588,43 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
       return false;
   }
 
-  /* We don't need to match the rest of edges as above checks should be enough
-     to ensure that they are equivalent.  */
+  /* The same checks as in try_crossjump_to_edge. It is required for RTL
+     version of sequence abstraction.  */
+  FOR_EACH_EDGE (e1, ei, bb2->succs)
+    {
+      edge e2;
+      edge_iterator ei;
+      basic_block d1 = e1->dest;
+
+      if (FORWARDER_BLOCK_P (d1))
+        d1 = EDGE_SUCC (d1, 0)->dest;
+
+      FOR_EACH_EDGE (e2, ei, bb1->succs)
+        {
+          basic_block d2 = e2->dest;
+          if (FORWARDER_BLOCK_P (d2))
+            d2 = EDGE_SUCC (d2, 0)->dest;
+          if (d1 == d2)
+            break;
+        }
+
+      if (!e2)
+        return false;
+    }
+
   return true;
 }
 
+/* Returns true if BB basic block has a preserve label.  */
+
+static bool
+block_has_preserve_label (basic_block bb)
+{
+  return (bb
+          && block_label (bb)
+          && LABEL_PRESERVE_P (block_label (bb)));
+}
+
 /* E1 and E2 are edges with the same destination block.  Search their
    predecessors for common code.  If found, redirect control flow from
    (maybe the middle of) E1->SRC to (maybe the middle of) E2->SRC.  */
@@ -1522,13 +1657,13 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
      about multiple entry or chained forwarders, as they will be optimized
      away.  We do this to look past the unconditional jump following a
      conditional jump that is required due to the current CFG shape.  */
-  if (EDGE_COUNT (src1->preds) == 1
+  if (single_pred_p (src1)
       && FORWARDER_BLOCK_P (src1))
-    e1 = EDGE_PRED (src1, 0), src1 = e1->src;
+    e1 = single_pred_edge (src1), src1 = e1->src;
 
-  if (EDGE_COUNT (src2->preds) == 1
+  if (single_pred_p (src2)
       && FORWARDER_BLOCK_P (src2))
-    e2 = EDGE_PRED (src2, 0), src2 = e2->src;
+    e2 = single_pred_edge (src2), src2 = e2->src;
 
   /* Nothing to do if we reach ENTRY, or a common source block.  */
   if (src1 == ENTRY_BLOCK_PTR || src2 == ENTRY_BLOCK_PTR)
@@ -1538,11 +1673,11 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
 
   /* Seeing more than 1 forwarder blocks would confuse us later...  */
   if (FORWARDER_BLOCK_P (e1->dest)
-      && FORWARDER_BLOCK_P (EDGE_SUCC (e1->dest, 0)->dest))
+      && FORWARDER_BLOCK_P (single_succ (e1->dest)))
     return false;
 
   if (FORWARDER_BLOCK_P (e2->dest)
-      && FORWARDER_BLOCK_P (EDGE_SUCC (e2->dest, 0)->dest))
+      && FORWARDER_BLOCK_P (single_succ (e2->dest)))
     return false;
 
   /* Likewise with dead code (possibly newly created by the other optimizations
@@ -1565,7 +1700,11 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
       && (newpos1 != BB_HEAD (src1)))
     return false;
 
-#ifndef CASE_DROPS_THROUGH
+  /* Avoid deleting preserve label when redirecting ABNORMAL edeges.  */
+  if (block_has_preserve_label (e1->dest)
+      && (e1->flags & EDGE_ABNORMAL))
+    return false;
+
   /* Here we know that the insns in the end of SRC1 which are common with SRC2
      will be deleted.
      If we have tablejumps in the end of SRC1 and SRC2
@@ -1596,13 +1735,24 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
            }
        }
     }
-#endif
 
-  /* Avoid splitting if possible.  */
-  if (newpos2 == BB_HEAD (src2))
+  /* Avoid splitting if possible.  We must always split when SRC2 has
+     EH predecessor edges, or we may end up with basic blocks with both
+     normal and EH predecessor edges.  */
+  if (newpos2 == BB_HEAD (src2)
+      && !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
     redirect_to = src2;
   else
     {
+      if (newpos2 == BB_HEAD (src2))
+       {
+         /* Skip possible basic block header.  */
+         if (LABEL_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
+         if (NOTE_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
+       }
+
       if (dump_file)
        fprintf (dump_file, "Splitting bb %i before %i insns\n",
                 src2->index, nmatch);
@@ -1627,13 +1777,13 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
       basic_block d = s->dest;
 
       if (FORWARDER_BLOCK_P (d))
-       d = EDGE_SUCC (d, 0)->dest;
+       d = single_succ (d);
 
       FOR_EACH_EDGE (s2, ei, src1->succs)
        {
          basic_block d2 = s2->dest;
          if (FORWARDER_BLOCK_P (d2))
-           d2 = EDGE_SUCC (d2, 0)->dest;
+           d2 = single_succ (d2);
          if (d == d2)
            break;
        }
@@ -1645,16 +1795,16 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
          into infinite loop.  */
       if (FORWARDER_BLOCK_P (s->dest))
        {
-         EDGE_SUCC (s->dest, 0)->count += s2->count;
+         single_succ_edge (s->dest)->count += s2->count;
          s->dest->count += s2->count;
          s->dest->frequency += EDGE_FREQUENCY (s);
        }
 
       if (FORWARDER_BLOCK_P (s2->dest))
        {
-         EDGE_SUCC (s2->dest, 0)->count -= s2->count;
-         if (EDGE_SUCC (s2->dest, 0)->count < 0)
-           EDGE_SUCC (s2->dest, 0)->count = 0;
+         single_succ_edge (s2->dest)->count -= s2->count;
+         if (single_succ_edge (s2->dest)->count < 0)
+           single_succ_edge (s2->dest)->count = 0;
          s2->dest->count -= s2->count;
          s2->dest->frequency -= EDGE_FREQUENCY (s);
          if (s2->dest->frequency < 0)
@@ -1684,12 +1834,14 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
     newpos1 = NEXT_INSN (newpos1);
 
   redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
-  to_remove = EDGE_SUCC (redirect_from, 0)->dest;
+  to_remove = single_succ (redirect_from);
 
-  redirect_edge_and_branch_force (EDGE_SUCC (redirect_from, 0), redirect_to);
+  redirect_edge_and_branch_force (single_succ_edge (redirect_from), redirect_to);
   delete_basic_block (to_remove);
 
   update_forwarder_flag (redirect_from);
+  if (redirect_to != src2)
+    update_forwarder_flag (src2);
 
   return true;
 }
@@ -1711,6 +1863,13 @@ try_crossjump_bb (int mode, basic_block bb)
   if (EDGE_COUNT (bb->preds) < 2)
     return false;
 
+  /* Don't crossjump if this block ends in a computed jump,
+     unless we are optimizing for size.  */
+  if (!optimize_size
+      && bb != EXIT_BLOCK_PTR
+      && computed_jump_p (BB_END (bb)))
+    return false;
+
   /* If we are partitioning hot/cold basic blocks, we don't want to
      mess up unconditional or indirect jumps that cross between hot
      and cold sections. 
@@ -1721,9 +1880,9 @@ try_crossjump_bb (int mode, basic_block bb)
      partition boundaries).  See the comments at the top of 
      bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
 
-  if (flag_reorder_blocks_and_partition
-      && (BB_PARTITION (EDGE_PRED (bb, 0)->src) != BB_PARTITION (EDGE_PRED (bb, 1)->src)
-         || (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING)))
+  if (BB_PARTITION (EDGE_PRED (bb, 0)->src) != 
+                                        BB_PARTITION (EDGE_PRED (bb, 1)->src)
+      || (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING))
     return false;
 
   /* It is always cheapest to redirect a block that ends in a branch to
@@ -1838,12 +1997,12 @@ try_optimize_cfg (int mode)
   if (mode & CLEANUP_CROSSJUMP)
     add_noreturn_fake_exit_edges ();
 
-  FOR_EACH_BB (bb)
-    update_forwarder_flag (bb);
-
   if (mode & (CLEANUP_UPDATE_LIFE | CLEANUP_CROSSJUMP | CLEANUP_THREADING))
     clear_bb_flags ();
 
+  FOR_EACH_BB (bb)
+    update_forwarder_flag (bb);
+
   if (! targetm.cannot_modify_jumps_p ())
     {
       first_pass = true;
@@ -1881,9 +2040,9 @@ try_optimize_cfg (int mode)
                }
 
              /* Remove code labels no longer used.  */
-             if (EDGE_COUNT (b->preds) == 1
-                 && (EDGE_PRED (b, 0)->flags & EDGE_FALLTHRU)
-                 && !(EDGE_PRED (b, 0)->flags & EDGE_COMPLEX)
+             if (single_pred_p (b)
+                 && (single_pred_edge (b)->flags & EDGE_FALLTHRU)
+                 && !(single_pred_edge (b)->flags & EDGE_COMPLEX)
                  && LABEL_P (BB_HEAD (b))
                  /* If the previous block ends with a branch to this
                     block, we can't delete the label.  Normally this
@@ -1891,10 +2050,10 @@ try_optimize_cfg (int mode)
                     if CASE_DROPS_THRU, this can be a tablejump with
                     some element going to the same place as the
                     default (fallthru).  */
-                 && (EDGE_PRED (b, 0)->src == ENTRY_BLOCK_PTR
-                     || !JUMP_P (BB_END (EDGE_PRED (b, 0)->src))
+                 && (single_pred (b) == ENTRY_BLOCK_PTR
+                     || !JUMP_P (BB_END (single_pred (b)))
                      || ! label_is_jump_target_p (BB_HEAD (b),
-                                                  BB_END (EDGE_PRED (b, 0)->src))))
+                                                  BB_END (single_pred (b)))))
                {
                  rtx label = BB_HEAD (b);
 
@@ -1915,14 +2074,14 @@ try_optimize_cfg (int mode)
 
              /* If we fall through an empty block, we can remove it.  */
              if (!(mode & CLEANUP_CFGLAYOUT)
-                 && EDGE_COUNT (b->preds) == 1
-                 && (EDGE_PRED (b, 0)->flags & EDGE_FALLTHRU)
+                 && single_pred_p (b)
+                 && (single_pred_edge (b)->flags & EDGE_FALLTHRU)
                  && !LABEL_P (BB_HEAD (b))
                  && FORWARDER_BLOCK_P (b)
                  /* Note that forwarder_block_p true ensures that
                     there is a successor for this block.  */
-                 && (EDGE_SUCC (b, 0)->flags & EDGE_FALLTHRU)
-                 && n_basic_blocks > 1)
+                 && (single_succ_edge (b)->flags & EDGE_FALLTHRU)
+                 && n_basic_blocks > NUM_FIXED_BLOCKS + 1)
                {
                  if (dump_file)
                    fprintf (dump_file,
@@ -1930,17 +2089,18 @@ try_optimize_cfg (int mode)
                             b->index);
 
                  c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
-                 redirect_edge_succ_nodup (EDGE_PRED (b, 0), EDGE_SUCC (b, 0)->dest);
+                 redirect_edge_succ_nodup (single_pred_edge (b),
+                                           single_succ (b));
                  delete_basic_block (b);
                  changed = true;
                  b = c;
                }
 
-             if (EDGE_COUNT (b->succs) == 1
-                 && (s = EDGE_SUCC (b, 0))
+             if (single_succ_p (b)
+                 && (s = single_succ_edge (b))
                  && !(s->flags & EDGE_COMPLEX)
                  && (c = s->dest) != EXIT_BLOCK_PTR
-                 && EDGE_COUNT (c->preds) == 1
+                 && single_pred_p (c)
                  && b != c)
                {
                  /* When not in cfg_layout mode use code aware of reordering
@@ -1982,11 +2142,12 @@ try_optimize_cfg (int mode)
                 non-trivial jump instruction without side-effects, we
                 can either delete the jump entirely, or replace it
                 with a simple unconditional jump.  */
-             if (EDGE_COUNT (b->succs) == 1
-                 && EDGE_SUCC (b, 0)->dest != EXIT_BLOCK_PTR
+             if (single_succ_p (b)
+                 && single_succ (b) != EXIT_BLOCK_PTR
                  && onlyjump_p (BB_END (b))
                  && !find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
-                 && try_redirect_by_replacing_jump (EDGE_SUCC (b, 0), EDGE_SUCC (b, 0)->dest,
+                 && try_redirect_by_replacing_jump (single_succ_edge (b),
+                                                    single_succ (b),
                                                     (mode & CLEANUP_CFGLAYOUT) != 0))
                {
                  update_forwarder_flag (b);
@@ -2028,7 +2189,8 @@ try_optimize_cfg (int mode)
   if (mode & CLEANUP_CROSSJUMP)
     remove_fake_exit_edges ();
 
-  clear_aux_for_blocks ();
+  FOR_ALL_BB (b)
+    b->flags &= ~(BB_FORWARDER_BLOCK | BB_NONTHREADABLE_BLOCK);
 
   return changed_overall;
 }
@@ -2071,11 +2233,11 @@ merge_seq_blocks (void)
 
   for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; )
     {
-      if (EDGE_COUNT (bb->succs) == 1
-         && can_merge_blocks_p (bb, EDGE_SUCC (bb, 0)->dest))
+      if (single_succ_p (bb)
+         && can_merge_blocks_p (bb, single_succ (bb)))
        {
          /* Merge the blocks and retry.  */
-         merge_blocks (bb, EDGE_SUCC (bb, 0)->dest);
+         merge_blocks (bb, single_succ (bb));
          changed = true;
          continue;
        }
@@ -2134,9 +2296,85 @@ cleanup_cfg (int mode)
       delete_dead_jumptables ();
     }
 
-  /* Kill the data we won't maintain.  */
-  free_EXPR_LIST_list (&label_value_list);
   timevar_pop (TV_CLEANUP_CFG);
 
   return changed;
 }
+\f
+static void
+rest_of_handle_jump (void)
+{
+  delete_unreachable_blocks ();
+
+  if (cfun->tail_call_emit)
+    fixup_tail_calls ();
+}
+
+struct tree_opt_pass pass_jump =
+{
+  "sibling",                            /* name */
+  NULL,                                 /* gate */   
+  rest_of_handle_jump,                 /* execute */       
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_JUMP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  TODO_ggc_collect,                     /* todo_flags_start */
+  TODO_dump_func |
+  TODO_verify_flow,                     /* todo_flags_finish */
+  'i'                                   /* letter */
+};
+
+
+static void
+rest_of_handle_jump2 (void)
+{
+  /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB.  Do this
+     before jump optimization switches branch directions.  */
+  if (flag_guess_branch_prob)
+    expected_value_to_br_prob ();
+
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  reg_scan (get_insns (), max_reg_num ());
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+  cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
+               | (flag_thread_jumps ? CLEANUP_THREADING : 0));
+
+  create_loop_notes ();
+
+  purge_line_number_notes ();
+
+  if (optimize)
+    cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
+
+  /* Jump optimization, and the removal of NULL pointer checks, may
+     have reduced the number of instructions substantially.  CSE, and
+     future passes, allocate arrays whose dimensions involve the
+     maximum instruction UID, so if we can reduce the maximum UID
+     we'll save big on memory.  */
+  renumber_insns ();
+}
+
+
+struct tree_opt_pass pass_jump2 =
+{
+  "jump",                               /* name */
+  NULL,                                 /* gate */   
+  rest_of_handle_jump2,                        /* execute */       
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_JUMP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  TODO_ggc_collect,                     /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'j'                                   /* letter */
+};
+
+