OSDN Git Service

* config/i386/sse.md (xop_pmacsww, xop_pmacssww, xop_pmacsdd,
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index d13e6be..ffe36e4 100644 (file)
@@ -1,12 +1,13 @@
 /* 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, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file contains optimizer of the control flow.  The main entry point is
    cleanup_cfg.  Following optimizations are performed:
@@ -37,7 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 #include "rtl.h"
 #include "hard-reg-set.h"
-#include "basic-block.h"
+#include "regs.h"
 #include "timevar.h"
 #include "output.h"
 #include "insn-config.h"
@@ -48,42 +48,35 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "params.h"
 #include "tm_p.h"
 #include "target.h"
-#include "regs.h"
 #include "cfglayout.h"
 #include "emit-rtl.h"
+#include "tree-pass.h"
+#include "cfgloop.h"
+#include "expr.h"
+#include "df.h"
+#include "dce.h"
+#include "dbgcnt.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;
+
+/* 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);
 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);
 static bool try_optimize_cfg (int);
 static bool try_simplify_condjump (basic_block);
 static bool try_forward_edges (int, basic_block);
-static edge thread_jump (int, edge, basic_block);
+static edge thread_jump (edge, basic_block);
 static bool mark_effect (rtx, bitmap);
 static void notice_new_block (basic_block);
 static void update_forwarder_flag (basic_block);
@@ -99,7 +92,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.  */
@@ -108,9 +101,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.
@@ -124,9 +117,7 @@ try_simplify_condjump (basic_block cbranch_block)
   rtx cbranch_insn;
 
   /* Verify that there are exactly two successors.  */
-  if (!cbranch_block->succ
-      || !cbranch_block->succ->succ_next
-      || cbranch_block->succ->succ_next->succ_next)
+  if (EDGE_COUNT (cbranch_block->succs) != 2)
     return false;
 
   /* Verify that we've got a normal conditional branch at the end
@@ -142,19 +133,24 @@ 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 (jump_block->pred->pred_next
+  if (!single_pred_p (jump_block)
       || jump_block->next_bb == EXIT_BLOCK_PTR
       || !FORWARDER_BLOCK_P (jump_block))
     return false;
-  jump_dest_block = jump_block->succ->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
-     and cold sections.  */
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     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
-      && (jump_block->partition != jump_dest_block->partition
-         || cbranch_jump_edge->crossing_edge))
+  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
@@ -203,7 +199,7 @@ mark_effect (rtx exp, regset nonequal)
   switch (GET_CODE (exp))
     {
       /* In case we do clobber the register, mark it as equal, as we know the
-         value is dead so it don't have to match.  */
+        value is dead so it don't have to match.  */
     case CLOBBER:
       if (REG_P (XEXP (exp, 0)))
        {
@@ -270,25 +266,26 @@ mentions_nonequal_regs (rtx *x, void *data)
    if exist, NULL otherwise.  */
 
 static edge
-thread_jump (int mode, edge e, basic_block b)
+thread_jump (edge e, basic_block b)
 {
   rtx set1, set2, cond1, cond2, insn;
   enum rtx_code code1, code2, reversed_code2;
   bool reverse1 = false;
-  int i;
+  unsigned i;
   regset nonequal;
   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
      want to extend this code to tablejumps and others.  */
-  if (!e->src->succ->succ_next || e->src->succ->succ_next->succ_next)
+  if (EDGE_COUNT (e->src->succs) != 2)
     return NULL;
-  if (!b->succ || !b->succ->succ_next || b->succ->succ_next->succ_next)
+  if (EDGE_COUNT (b->succs) != 2)
     {
-      BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+      b->flags |= BB_NONTHREADABLE_BLOCK;
       return NULL;
     }
 
@@ -298,7 +295,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;
     }
 
@@ -336,26 +333,28 @@ 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;
       }
 
   cselib_init (false);
 
   /* First process all values computed in the source basic block.  */
-  for (insn = NEXT_INSN (BB_HEAD (e->src)); insn != NEXT_INSN (BB_END (e->src));
+  for (insn = NEXT_INSN (BB_HEAD (e->src));
+       insn != NEXT_INSN (BB_END (e->src));
        insn = NEXT_INSN (insn))
     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
      processing as if it were same basic block.
      Our goal is to prove that whole block is an NOOP.  */
 
-  for (insn = NEXT_INSN (BB_HEAD (b)); insn != NEXT_INSN (BB_END (b)) && !failed;
+  for (insn = NEXT_INSN (BB_HEAD (b));
+       insn != NEXT_INSN (BB_END (b)) && !failed;
        insn = NEXT_INSN (insn))
     {
       if (INSN_P (insn))
@@ -364,7 +363,7 @@ thread_jump (int mode, edge e, basic_block b)
 
          if (GET_CODE (pat) == PARALLEL)
            {
-             for (i = 0; i < XVECLEN (pat, 0); i++)
+             for (i = 0; i < (unsigned)XVECLEN (pat, 0); i++)
                failed |= mark_effect (XVECEXP (pat, 0, i), nonequal);
            }
          else
@@ -378,7 +377,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;
     }
 
@@ -387,14 +386,10 @@ thread_jump (int mode, edge e, basic_block b)
   if (for_each_rtx (&cond2, mentions_nonequal_regs, nonequal))
     goto failed_exit;
 
-  /* 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);
-
-  EXECUTE_IF_SET_IN_REG_SET (nonequal, 0, i, goto failed_exit;);
+  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))
@@ -403,7 +398,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;
 }
@@ -415,42 +410,56 @@ static bool
 try_forward_edges (int mode, basic_block b)
 {
   bool changed = false;
-  edge e, next, *threaded_edges = NULL;
+  edge_iterator ei;
+  edge e, *threaded_edges = NULL;
 
   /* 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.  */
-  
-  if (flag_reorder_blocks_and_partition
-      && find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
     return false;
 
-  for (e = b->succ; e; e = next)
+  for (ei = ei_start (b->succs); (e = ei_safe_edge (ei)); )
     {
       basic_block target, first;
-      int counter;
+      int counter, goto_locus;
       bool threaded = false;
       int nthreaded_edges = 0;
-      bool may_thread = first_pass | (b->flags & BB_DIRTY);
-
-      next = e->succ_next;
+      bool may_thread = first_pass | df_get_bb_dirty (b);
 
       /* Skip complex edges because we don't know how to update them.
 
-         Still handle fallthru edges, as we can succeed to forward fallthru
-         edge to the same place as the branch edge of conditional branch
-         and turn conditional branch to an unconditional branch.  */
+        Still handle fallthru edges, as we can succeed to forward fallthru
+        edge to the same place as the branch edge of conditional branch
+        and turn conditional branch to an unconditional branch.  */
       if (e->flags & EDGE_COMPLEX)
-       continue;
+       {
+         ei_next (&ei);
+         continue;
+       }
 
       target = first = e->dest;
-      counter = 0;
+      counter = NUM_FIXED_BLOCKS;
+      goto_locus = e->goto_locus;
 
       /* If we are partitioning hot/cold basic_blocks, we don't want to mess
-        up jumps that cross between hot/cold sections.  */
+        up jumps that cross between hot/cold sections.
 
-      if (flag_reorder_blocks_and_partition
-         && first != EXIT_BLOCK_PTR
+        Basic block partitioning may result in some jumps that appear
+        to be optimizable (or blocks that appear to be mergeable), but which
+        really must be left untouched (they are required to make it safely
+        across partition boundaries).  See the comments at the top of
+        bb-reorder.c:partition_hot_cold_basic_blocks for complete
+        details.  */
+
+      if (first != EXIT_BLOCK_PTR
          && find_reg_note (BB_END (first), REG_CROSSING_JUMP, NULL_RTX))
        return false;
 
@@ -458,28 +467,49 @@ try_forward_edges (int mode, basic_block b)
        {
          basic_block new_target = NULL;
          bool new_target_threaded = false;
-         may_thread |= target->flags & BB_DIRTY;
+         may_thread |= df_get_bb_dirty (target);
 
          if (FORWARDER_BLOCK_P (target)
-             && !target->succ->crossing_edge
-             && target->succ->dest != EXIT_BLOCK_PTR)
+             && !(single_succ_edge (target)->flags & EDGE_CROSSING)
+             && single_succ (target) != EXIT_BLOCK_PTR)
            {
              /* Bypass trivial infinite loops.  */
-             if (target == target->succ->dest)
+             new_target = single_succ (target);
+             if (target == new_target)
                counter = n_basic_blocks;
-             new_target = target->succ->dest;
+             else if (!optimize)
+               {
+                 /* When not optimizing, ensure that edges or forwarder
+                    blocks with different locus are not optimized out.  */
+                 int locus = single_succ_edge (target)->goto_locus;
+
+                 if (locus && goto_locus && !locator_eq (locus, goto_locus))
+                   counter = n_basic_blocks;
+                 else if (locus)
+                   goto_locus = locus;
+
+                 if (INSN_P (BB_END (target)))
+                   {
+                     locus = INSN_LOCATOR (BB_END (target));
+
+                     if (locus && goto_locus
+                         && !locator_eq (locus, goto_locus))
+                       counter = n_basic_blocks;
+                     else if (locus)
+                       goto_locus = locus;
+                   }
+               }
            }
 
          /* Allow to thread only over one edge at time to simplify updating
             of probabilities.  */
          else if ((mode & CLEANUP_THREADING) && may_thread)
            {
-             edge t = thread_jump (mode, e, target);
+             edge t = thread_jump (e, target);
              if (t)
                {
                  if (!threaded_edges)
-                   threaded_edges = xmalloc (sizeof (*threaded_edges)
-                                             * n_basic_blocks);
+                   threaded_edges = XNEWVEC (edge, n_basic_blocks);
                  else
                    {
                      int i;
@@ -500,8 +530,7 @@ try_forward_edges (int mode, basic_block b)
                  if (t->dest == b)
                    break;
 
-                 if (nthreaded_edges >= n_basic_blocks)
-                   abort ();
+                 gcc_assert (nthreaded_edges < n_basic_blocks - NUM_FIXED_BLOCKS);
                  threaded_edges[nthreaded_edges++] = t;
 
                  new_target = t->dest;
@@ -512,39 +541,6 @@ try_forward_edges (int mode, basic_block b)
          if (!new_target)
            break;
 
-         /* Avoid killing of loop pre-headers, as it is the place loop
-            optimizer wants to hoist code to.
-
-            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)
-           {
-             rtx insn = (target->succ->flags & EDGE_FALLTHRU
-                         ? BB_HEAD (target) : prev_nonnote_insn (BB_END (target)));
-
-             if (!NOTE_P (insn))
-               insn = NEXT_INSN (insn);
-
-             for (; insn && !LABEL_P (insn) && !INSN_P (insn);
-                  insn = NEXT_INSN (insn))
-               if (NOTE_P (insn)
-                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-                 break;
-
-             if (NOTE_P (insn))
-               break;
-
-             /* Do not clean up branches to just past the end of a loop
-                at this time; it can mess up the loop optimizer's
-                recognition of some patterns.  */
-
-             insn = PREV_INSN (BB_HEAD (target));
-             if (insn && NOTE_P (insn)
-                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-               break;
-           }
-
          counter++;
          target = new_target;
          threaded |= new_target_threaded;
@@ -566,6 +562,8 @@ try_forward_edges (int mode, basic_block b)
          int edge_frequency;
          int n = 0;
 
+         e->goto_locus = goto_locus;
+
          /* Don't force if target is exit block.  */
          if (threaded && target != EXIT_BLOCK_PTR)
            {
@@ -579,6 +577,7 @@ try_forward_edges (int mode, basic_block b)
                fprintf (dump_file,
                         "Forwarding edge %i->%i to %i failed.\n",
                         b->index, e->dest->index, target->index);
+             ei_next (&ei);
              continue;
            }
 
@@ -590,48 +589,29 @@ 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;
 
-             first->count -= edge_count;
-             if (first->count < 0)
-               first->count = 0;
-             first->frequency -= edge_frequency;
-             if (first->frequency < 0)
-               first->frequency = 0;
-             if (first->succ->succ_next)
+             if (!single_succ_p (first))
                {
-                 edge e;
-                 int prob;
-                 if (n >= nthreaded_edges)
-                   abort ();
+                 gcc_assert (n < nthreaded_edges);
                  t = threaded_edges [n++];
-                 if (t->src != first)
-                   abort ();
-                 if (first->frequency)
-                   prob = edge_frequency * REG_BR_PROB_BASE / first->frequency;
-                 else
-                   prob = 0;
-                 if (prob > t->probability)
-                   prob = t->probability;
-                 t->probability -= prob;
-                 prob = REG_BR_PROB_BASE - prob;
-                 if (prob <= 0)
-                   {
-                     first->succ->probability = REG_BR_PROB_BASE;
-                     first->succ->succ_next->probability = 0;
-                   }
-                 else
-                   for (e = first->succ; e; e = e->succ_next)
-                     e->probability = ((e->probability * REG_BR_PROB_BASE)
-                                       / (double) prob);
+                 gcc_assert (t->src == first);
+                 update_bb_profile_for_threading (first, edge_frequency,
+                                                  edge_count, t);
                  update_br_prob_note (first);
                }
              else
                {
+                 first->count -= edge_count;
+                 if (first->count < 0)
+                   first->count = 0;
+                 first->frequency -= edge_frequency;
+                 if (first->frequency < 0)
+                   first->frequency = 0;
                  /* It is possible that as the result of
                     threading we've removed edge as it is
                     threaded to the fallthru edge.  Avoid
@@ -639,7 +619,7 @@ try_forward_edges (int mode, basic_block b)
                  if (n < nthreaded_edges
                      && first == threaded_edges [n]->src)
                    n++;
-                 t = first->succ;
+                 t = single_succ_edge (first);
                }
 
              t->count -= edge_count;
@@ -650,7 +630,9 @@ try_forward_edges (int mode, basic_block b)
          while (first != target);
 
          changed = true;
+         continue;
        }
+      ei_next (&ei);
     }
 
   if (threaded_edges)
@@ -670,32 +652,25 @@ merge_blocks_move_predecessor_nojumps (basic_block a, basic_block b)
 
   /* 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.  */
-  
-  if (flag_reorder_blocks_and_partition
-      && (a->partition != b->partition
-         || find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)))
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (BB_PARTITION (a) != BB_PARTITION (b))
     return;
 
   barrier = next_nonnote_insn (BB_END (a));
-  if (!BARRIER_P (barrier))
-    abort ();
+  gcc_assert (BARRIER_P (barrier));
   delete_insn (barrier);
 
-  /* Move block and loop notes out of the chain so that we do not
-     disturb their order.
-
-     ??? A better solution would be to squeeze out all the non-nested notes
-     and adjust the block trees appropriately.   Even better would be to have
-     a tighter connection between block trees and rtl so that this is not
-     necessary.  */
-  if (squeeze_notes (&BB_HEAD (a), &BB_END (a)))
-    abort ();
-
   /* Scramble the insn chain.  */
   if (BB_END (a) != PREV_INSN (BB_HEAD (b)))
     reorder_insns_nobb (BB_HEAD (a), BB_END (a), PREV_INSN (BB_HEAD (b)));
-  a->flags |= BB_DIRTY;
+  df_set_bb_dirty (a);
 
   if (dump_file)
     fprintf (dump_file, "Moved block %d before %d and merged.\n",
@@ -722,11 +697,15 @@ merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
 
   /* 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.  */
-  
-  if (flag_reorder_blocks_and_partition
-      && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
-         || a->partition != b->partition))
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (BB_PARTITION (a) != BB_PARTITION (b))
     return;
 
   real_b_end = BB_END (b);
@@ -744,15 +723,6 @@ merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
   if (barrier && BARRIER_P (barrier))
     delete_insn (barrier);
 
-  /* Move block and loop notes out of the chain so that we do not
-     disturb their order.
-
-     ??? A better solution would be to squeeze out all the non-nested notes
-     and adjust the block trees appropriately.   Even better would be to have
-     a tighter connection between block trees and rtl so that this is not
-     necessary.  */
-  if (squeeze_notes (&BB_HEAD (b), &BB_END (b)))
-    abort ();
 
   /* Scramble the insn chain.  */
   reorder_insns_nobb (BB_HEAD (b), BB_END (b), BB_END (a));
@@ -787,15 +757,16 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
 
   /* 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.  */
-  
-  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)
-         || b->partition != c->partition))
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (BB_PARTITION (b) != BB_PARTITION (c))
     return NULL;
-      
-    
 
   /* If B has a fallthru edge to C, no need to move anything.  */
   if (e->flags & EDGE_FALLTHRU)
@@ -818,9 +789,10 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
       edge tmp_edge, b_fallthru_edge;
       bool c_has_outgoing_fallthru;
       bool b_has_incoming_fallthru;
+      edge_iterator ei;
 
       /* Avoid overactive code motion, as the forwarder blocks should be
-         eliminated by edge redirection instead.  One exception might have
+        eliminated by edge redirection instead.  One exception might have
         been if B is a forwarder block and C has no fallthru edge, but
         that should be cleaned up by bb-reorder instead.  */
       if (FORWARDER_BLOCK_P (b) || FORWARDER_BLOCK_P (c))
@@ -830,13 +802,13 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
         and loop notes.  This is done by squeezing out all the notes
         and leaving them there to lie.  Not ideal, but functional.  */
 
-      for (tmp_edge = c->succ; tmp_edge; tmp_edge = tmp_edge->succ_next)
+      FOR_EACH_EDGE (tmp_edge, ei, c->succs)
        if (tmp_edge->flags & EDGE_FALLTHRU)
          break;
 
       c_has_outgoing_fallthru = (tmp_edge != NULL);
 
-      for (tmp_edge = b->pred; tmp_edge; tmp_edge = tmp_edge->pred_next)
+      FOR_EACH_EDGE (tmp_edge, ei, b->preds)
        if (tmp_edge->flags & EDGE_FALLTHRU)
          break;
 
@@ -852,7 +824,7 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
       if (! c_has_outgoing_fallthru)
        {
          merge_blocks_move_successor_nojumps (b, c);
-          return next == ENTRY_BLOCK_PTR ? next->next_bb : next;
+         return next == ENTRY_BLOCK_PTR ? next->next_bb : next;
        }
 
       /* If B does not have an incoming fallthru, then it can be moved
@@ -909,14 +881,16 @@ merge_memattrs (rtx x, rtx y)
        MEM_ATTRS (y) = 0;
       else if (! MEM_ATTRS (y))
        MEM_ATTRS (x) = 0;
-      else 
+      else
        {
+         rtx mem_size;
+
          if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
            {
              set_mem_alias_set (x, 0);
              set_mem_alias_set (y, 0);
            }
-         
+
          if (! mem_expr_equal_p (MEM_EXPR (x), MEM_EXPR (y)))
            {
              set_mem_expr (x, 0);
@@ -929,15 +903,22 @@ merge_memattrs (rtx x, rtx y)
              set_mem_offset (x, 0);
              set_mem_offset (y, 0);
            }
-         
-         set_mem_size (x, MAX (MEM_SIZE (x), MEM_SIZE (y)));
-         set_mem_size (y, MEM_SIZE (x));
+
+         if (!MEM_SIZE (x))
+           mem_size = NULL_RTX;
+         else if (!MEM_SIZE (y))
+           mem_size = NULL_RTX;
+         else
+           mem_size = GEN_INT (MAX (INTVAL (MEM_SIZE (x)),
+                                    INTVAL (MEM_SIZE (y))));
+         set_mem_size (x, mem_size);
+         set_mem_size (y, mem_size);
 
          set_mem_align (x, MIN (MEM_ALIGN (x), MEM_ALIGN (y)));
          set_mem_align (y, MEM_ALIGN (x));
        }
     }
-  
+
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
@@ -964,7 +945,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;
 
@@ -972,6 +953,11 @@ insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
   if (GET_CODE (i1) != GET_CODE (i2))
     return false;
 
+  /* __builtin_unreachable() may lead to empty blocks (ending with
+     NOTE_INSN_BASIC_BLOCK).  They may be crossjumped. */
+  if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2))
+    return true;
+
   p1 = PATTERN (i1);
   p2 = PATTERN (i2);
 
@@ -990,7 +976,7 @@ insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
 
   if (CALL_P (i1)
       && (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
-                       CALL_INSN_FUNCTION_USAGE (i2))
+                       CALL_INSN_FUNCTION_USAGE (i2))
          || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)))
     return false;
 
@@ -1002,8 +988,8 @@ insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
   if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
     {
       /* If register stack conversion has already been done, then
-         death notes must also be compared before it is certain that
-         the two instruction streams match.  */
+        death notes must also be compared before it is certain that
+        the two instruction streams match.  */
 
       rtx note;
       HARD_REG_SET i1_regset, i2_regset;
@@ -1019,12 +1005,8 @@ insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
        if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
          SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
 
-      GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
-
-      return false;
-
-    done:
-      ;
+      if (!hard_reg_set_equal_p (i1_regset, i2_regset))
+       return false;
     }
 #endif
 
@@ -1032,40 +1014,6 @@ insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
       ? rtx_renumbered_equal_p (p1, p2) : rtx_equal_p (p1, p2))
     return true;
 
-  /* Do not do EQUIV substitution after reload.  First, we're undoing the
-     work of reload_cse.  Second, we may be undoing the work of the post-
-     reload splitting pass.  */
-  /* ??? Possibly add a new phase switch variable that can be used by
-     targets to disallow the troublesome insns after splitting.  */
-  if (!reload_completed)
-    {
-      /* The following code helps take care of G++ cleanups.  */
-      rtx equiv1 = find_reg_equal_equiv_note (i1);
-      rtx equiv2 = find_reg_equal_equiv_note (i2);
-
-      if (equiv1 && equiv2
-         /* If the equivalences are not to a constant, they may
-            reference pseudos that no longer exist, so we can't
-            use them.  */
-         && (! reload_completed
-             || (CONSTANT_P (XEXP (equiv1, 0))
-                 && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))))
-       {
-         rtx s1 = single_set (i1);
-         rtx s2 = single_set (i2);
-         if (s1 != 0 && s2 != 0
-             && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
-           {
-             validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
-             validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
-             if (! rtx_renumbered_equal_p (p1, p2))
-               cancel_changes (0);
-             else if (apply_change_group ())
-               return true;
-           }
-       }
-    }
-
   return false;
 }
 \f
@@ -1109,16 +1057,16 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
   while (true)
     {
       /* Ignore notes.  */
-      while (!INSN_P (i1) && i1 != BB_HEAD (bb1))
+      while (!NONDEBUG_INSN_P (i1) && i1 != BB_HEAD (bb1))
        i1 = PREV_INSN (i1);
 
-      while (!INSN_P (i2) && i2 != BB_HEAD (bb2))
+      while (!NONDEBUG_INSN_P (i2) && i2 != BB_HEAD (bb2))
        i2 = PREV_INSN (i2);
 
       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);
@@ -1163,13 +1111,13 @@ flow_find_cross_jump (int mode ATTRIBUTE_UNUSED, basic_block bb1,
      Two, it keeps line number notes as matched as may be.  */
   if (ninsns)
     {
-      while (last1 != BB_HEAD (bb1) && !INSN_P (PREV_INSN (last1)))
+      while (last1 != BB_HEAD (bb1) && !NONDEBUG_INSN_P (PREV_INSN (last1)))
        last1 = PREV_INSN (last1);
 
       if (last1 != BB_HEAD (bb1) && LABEL_P (PREV_INSN (last1)))
        last1 = PREV_INSN (last1);
 
-      while (last2 != BB_HEAD (bb2) && !INSN_P (PREV_INSN (last2)))
+      while (last2 != BB_HEAD (bb2) && !NONDEBUG_INSN_P (PREV_INSN (last2)))
        last2 = PREV_INSN (last2);
 
       if (last2 != BB_HEAD (bb2) && LABEL_P (PREV_INSN (last2)))
@@ -1194,21 +1142,21 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
   int nehedges1 = 0, nehedges2 = 0;
   edge fallthru1 = 0, fallthru2 = 0;
   edge e1, e2;
+  edge_iterator ei;
 
   /* If BB1 has only one successor, we may be looking at either an
      unconditional jump, or a fake edge to exit.  */
-  if (bb1->succ && !bb1->succ->succ_next
-      && (bb1->succ->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 (bb2->succ &&  !bb2->succ->succ_next
-           && (bb2->succ->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
      edges are crossed.  */
-  if (bb1->succ
-      && bb1->succ->succ_next
-      && !bb1->succ->succ_next->succ_next
+  if (EDGE_COUNT (bb1->succs) == 2
       && any_condjump_p (BB_END (bb1))
       && onlyjump_p (BB_END (bb1)))
     {
@@ -1217,9 +1165,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
       rtx set1, set2, cond1, cond2;
       enum rtx_code code1, code2;
 
-      if (!bb2->succ
-         || !bb2->succ->succ_next
-         || bb2->succ->succ_next->succ_next
+      if (EDGE_COUNT (bb2->succs) != 2
          || !any_condjump_p (BB_END (bb2))
          || !onlyjump_p (BB_END (bb2)))
        return false;
@@ -1230,12 +1176,12 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
       f2 = FALLTHRU_EDGE (bb2);
 
       /* Get around possible forwarders on fallthru edges.  Other cases
-         should be optimized out already.  */
+        should be optimized out already.  */
       if (FORWARDER_BLOCK_P (f1->dest))
-       f1 = f1->dest->succ;
+       f1 = single_succ_edge (f1->dest);
 
       if (FORWARDER_BLOCK_P (f2->dest))
-       f2 = f2->dest->succ;
+       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
@@ -1285,9 +1231,8 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
         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))
+         && optimize_bb_for_speed_p (bb1)
+         && optimize_bb_for_speed_p (bb2))
        {
          int prob2;
 
@@ -1304,7 +1249,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
            {
              if (dump_file)
                fprintf (dump_file,
-                        "Outcomes of branch in bb %i and %i differs to much (%i %i)\n",
+                        "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
                         bb1->index, bb2->index, b1->probability, prob2);
 
              return false;
@@ -1321,7 +1266,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.  */
     {
@@ -1376,7 +1320,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",
@@ -1395,19 +1339,22 @@ 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
      fallthru and exception handling edges since these needs more
      validation.  */
-  for (e1 = bb1->succ, e2 = bb2->succ; e1 && e2;
-       e1 = e1->succ_next, e2 = e2->succ_next)
+  if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
+    return false;
+
+  FOR_EACH_EDGE (e1, ei, bb1->succs)
     {
+      e2 = EDGE_SUCC (bb2, ei.index);
+
       if (e1->flags & EDGE_EH)
        nehedges1++;
 
@@ -1421,8 +1368,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
     }
 
   /* If number of edges of various types does not match, fail.  */
-  if (e1 || e2
-      || nehedges1 != nehedges2
+  if (nehedges1 != nehedges2
       || (fallthru1 != 0) != (fallthru2 != 0))
     return false;
 
@@ -1430,9 +1376,9 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
   if (fallthru1)
     {
       basic_block d1 = (forwarder_block_p (fallthru1->dest)
-                       ? fallthru1->dest->succ->dest: fallthru1->dest);
+                       ? single_succ (fallthru1->dest): fallthru1->dest);
       basic_block d2 = (forwarder_block_p (fallthru2->dest)
-                       ? fallthru2->dest->succ->dest: fallthru2->dest);
+                       ? single_succ (fallthru2->dest): fallthru2->dest);
 
       if (d1 != d2)
        return false;
@@ -1450,11 +1396,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.  */
@@ -1467,28 +1445,33 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
   basic_block redirect_to, redirect_from, to_remove;
   rtx newpos1, newpos2;
   edge s;
+  edge_iterator ei;
 
   newpos1 = newpos2 = NULL_RTX;
 
   /* If we have partitioned hot/cold basic blocks, it is a bad idea
-     to try this optimization.  */
+     to try this optimization.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     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 && no_new_pseudos)
+  if (flag_reorder_blocks_and_partition && reload_completed)
     return false;
 
   /* Search backward through forwarder blocks.  We don't need to worry
      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 (src1->pred
-      && !src1->pred->pred_next
+  if (single_pred_p (src1)
       && FORWARDER_BLOCK_P (src1))
-    e1 = src1->pred, src1 = e1->src;
+    e1 = single_pred_edge (src1), src1 = e1->src;
 
-  if (src2->pred
-      && !src2->pred->pred_next
+  if (single_pred_p (src2)
       && FORWARDER_BLOCK_P (src2))
-    e2 = src2->pred, 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)
@@ -1498,16 +1481,16 @@ 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 (e1->dest->succ->dest))
+      && FORWARDER_BLOCK_P (single_succ (e1->dest)))
     return false;
 
   if (FORWARDER_BLOCK_P (e2->dest)
-      && FORWARDER_BLOCK_P (e2->dest->succ->dest))
+      && FORWARDER_BLOCK_P (single_succ (e2->dest)))
     return false;
 
   /* Likewise with dead code (possibly newly created by the other optimizations
      of cfg_cleanup).  */
-  if (!src1->pred || !src2->pred)
+  if (EDGE_COUNT (src1->preds) == 0 || EDGE_COUNT (src2->preds) == 0)
     return false;
 
   /* Look for the common insn sequence, part the first ...  */
@@ -1525,7 +1508,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 edges.  */
+  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
@@ -1556,13 +1543,28 @@ 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);
+         while (DEBUG_INSN_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
+         if (NOTE_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
+         while (DEBUG_INSN_P (newpos2))
+           newpos2 = NEXT_INSN (newpos2);
+       }
+
       if (dump_file)
        fprintf (dump_file, "Splitting bb %i before %i insns\n",
                 src2->index, nmatch);
@@ -1574,25 +1576,24 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
             "Cross jumping from bb %i to bb %i; %i common insns\n",
             src1->index, src2->index, nmatch);
 
-  redirect_to->count += src1->count;
-  redirect_to->frequency += src1->frequency;
-  /* We may have some registers visible trought the block.  */
-  redirect_to->flags |= BB_DIRTY;
+  /* We may have some registers visible through the block.  */
+  df_set_bb_dirty (redirect_to);
 
   /* Recompute the frequencies and counts of outgoing edges.  */
-  for (s = redirect_to->succ; s; s = s->succ_next)
+  FOR_EACH_EDGE (s, ei, redirect_to->succs)
     {
       edge s2;
+      edge_iterator ei;
       basic_block d = s->dest;
 
       if (FORWARDER_BLOCK_P (d))
-       d = d->succ->dest;
+       d = single_succ (d);
 
-      for (s2 = src1->succ; ; s2 = s2->succ_next)
+      FOR_EACH_EDGE (s2, ei, src1->succs)
        {
          basic_block d2 = s2->dest;
          if (FORWARDER_BLOCK_P (d2))
-           d2 = d2->succ->dest;
+           d2 = single_succ (d2);
          if (d == d2)
            break;
        }
@@ -1600,20 +1601,20 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
       s->count += s2->count;
 
       /* Take care to update possible forwarder blocks.  We verified
-         that there is no more than one in the chain, so we can't run
-         into infinite loop.  */
+        that there is no more than one in the chain, so we can't run
+        into infinite loop.  */
       if (FORWARDER_BLOCK_P (s->dest))
        {
-         s->dest->succ->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))
        {
-         s2->dest->succ->count -= s2->count;
-         if (s2->dest->succ->count < 0)
-           s2->dest->succ->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)
@@ -1631,6 +1632,14 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
             / (redirect_to->frequency + src1->frequency));
     }
 
+  /* Adjust count and frequency for the block.  An earlier jump
+     threading pass may have left the profile in an inconsistent
+     state (see update_bb_profile_for_threading) so we must be
+     prepared for overflows.  */
+  redirect_to->count += src1->count;
+  redirect_to->frequency += src1->frequency;
+  if (redirect_to->frequency > BB_FREQ_MAX)
+    redirect_to->frequency = BB_FREQ_MAX;
   update_br_prob_note (redirect_to);
 
   /* Edit SRC1 to go to REDIRECT_TO at NEWPOS1.  */
@@ -1639,16 +1648,24 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
   if (LABEL_P (newpos1))
     newpos1 = NEXT_INSN (newpos1);
 
-  if (NOTE_P (newpos1))
+  while (DEBUG_INSN_P (newpos1))
+    newpos1 = NEXT_INSN (newpos1);
+
+  if (NOTE_INSN_BASIC_BLOCK_P (newpos1))
+    newpos1 = NEXT_INSN (newpos1);
+
+  while (DEBUG_INSN_P (newpos1))
     newpos1 = NEXT_INSN (newpos1);
 
   redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
-  to_remove = redirect_from->succ->dest;
+  to_remove = single_succ (redirect_from);
 
-  redirect_edge_and_branch_force (redirect_from->succ, 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;
 }
@@ -1660,21 +1677,36 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
 static bool
 try_crossjump_bb (int mode, basic_block bb)
 {
-  edge e, e2, nexte2, nexte, fallthru;
+  edge e, e2, fallthru;
   bool changed;
-  int n = 0, max;
+  unsigned max, ix, ix2;
+  basic_block ev, ev2;
+  edge_iterator ei;
 
   /* Nothing to do if there is not at least two incoming edges.  */
-  if (!bb->pred || !bb->pred->pred_next)
+  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_bb_for_size_p (bb)
+      && 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.  */
-  
-  if (flag_reorder_blocks_and_partition
-      && (bb->pred->src->partition != bb->pred->pred_next->src->partition
-         || bb->pred->crossing_edge))
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really
+     must be left untouched (they are required to make it safely across
+     partition boundaries).  See the comments at the top of
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  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
@@ -1682,20 +1714,27 @@ try_crossjump_bb (int mode, basic_block bb)
      program.  We'll try that combination first.  */
   fallthru = NULL;
   max = PARAM_VALUE (PARAM_MAX_CROSSJUMP_EDGES);
-  for (e = bb->pred; e ; e = e->pred_next, n++)
+
+  if (EDGE_COUNT (bb->preds) > max)
+    return false;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
     {
       if (e->flags & EDGE_FALLTHRU)
-       fallthru = e;
-      if (n > max)
-       return false;
+       {
+         fallthru = e;
+         break;
+       }
     }
 
   changed = false;
-  for (e = bb->pred; e; e = nexte)
+  for (ix = 0, ev = bb; ix < EDGE_COUNT (ev->preds); )
     {
-      nexte = e->pred_next;
+      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.
@@ -1705,14 +1744,15 @@ try_crossjump_bb (int mode, basic_block bb)
          /* If nothing changed since the last attempt, there is nothing
             we can do.  */
          if (!first_pass
-             && (!(e->src->flags & BB_DIRTY)
-                 && !(fallthru->src->flags & BB_DIRTY)))
+             && (!(df_get_bb_dirty (e->src))
+                 && !(df_get_bb_dirty (fallthru->src))))
            continue;
 
          if (try_crossjump_to_edge (mode, e, fallthru))
            {
              changed = true;
-             nexte = bb->pred;
+             ix = 0;
+             ev = bb;
              continue;
            }
        }
@@ -1729,12 +1769,13 @@ try_crossjump_bb (int mode, basic_block bb)
         can eliminate redundant checks of crossjump(A,B) by arbitrarily
         choosing to do the check from the block for which the edge
         in question is the first successor of A.  */
-      if (e->src->succ != e)
+      if (EDGE_SUCC (e->src, 0) != e)
        continue;
 
-      for (e2 = bb->pred; e2; e2 = nexte2)
+      for (ix2 = 0, ev2 = bb; ix2 < EDGE_COUNT (ev2->preds); )
        {
-         nexte2 = e2->pred_next;
+         e2 = EDGE_PRED (ev2, ix2);
+         ix2++;
 
          if (e2 == e)
            continue;
@@ -1753,22 +1794,44 @@ try_crossjump_bb (int mode, basic_block bb)
          /* If nothing changed since the last attempt, there is nothing
             we can do.  */
          if (!first_pass
-             && (!(e->src->flags & BB_DIRTY)
-                 && !(e2->src->flags & BB_DIRTY)))
+             && (!(df_get_bb_dirty (e->src))
+                 && !(df_get_bb_dirty (e2->src))))
            continue;
 
          if (try_crossjump_to_edge (mode, e, e2))
            {
              changed = true;
-             nexte = bb->pred;
+             ev2 = bb;
+             ix = 0;
              break;
            }
        }
     }
 
+  if (changed)
+    crossjumps_occured = true;
+
   return changed;
 }
 
+/* Return true if BB contains just bb note, or bb note followed
+   by only DEBUG_INSNs.  */
+
+static bool
+trivially_empty_bb_p (basic_block bb)
+{
+  rtx insn = BB_END (bb);
+
+  while (1)
+    {
+      if (insn == BB_HEAD (bb))
+       return true;
+      if (!DEBUG_INSN_P (insn))
+       return false;
+      insn = PREV_INSN (insn);
+    }
+}
+
 /* Do simple CFG optimizations - basic block merging, simplifying of jump
    instructions etc.  Return nonzero if changes were made.  */
 
@@ -1780,15 +1843,14 @@ 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);
 
-  if (mode & (CLEANUP_UPDATE_LIFE | CLEANUP_CROSSJUMP | CLEANUP_THREADING))
-    clear_bb_flags ();
-
   if (! targetm.cannot_modify_jumps_p ())
     {
       first_pass = true;
@@ -1811,24 +1873,32 @@ try_optimize_cfg (int mode)
              edge s;
              bool changed_here = false;
 
-             /* Delete trivially dead basic blocks.  */
-             while (b->pred == NULL)
+             /* Delete trivially dead basic blocks.  This is either
+                blocks with no predecessors, or empty blocks with no
+                successors.  However if the empty block with no
+                successors is the successor of the ENTRY_BLOCK, it is
+                kept.  This ensures that the ENTRY_BLOCK will have a
+                successor which is a precondition for many RTL
+                passes.  Empty blocks may result from expanding
+                __builtin_unreachable ().  */
+             if (EDGE_COUNT (b->preds) == 0
+                 || (EDGE_COUNT (b->succs) == 0
+                     && trivially_empty_bb_p (b)
+                     && single_succ_edge (ENTRY_BLOCK_PTR)->dest != b))
                {
                  c = b->prev_bb;
-                 if (dump_file)
-                   fprintf (dump_file, "Deleting block %i.\n",
-                            b->index);
-
                  delete_basic_block (b);
                  if (!(mode & CLEANUP_CFGLAYOUT))
                    changed = true;
-                 b = c;
+                 /* Avoid trying to remove ENTRY_BLOCK_PTR.  */
+                 b = (c == ENTRY_BLOCK_PTR ? c->next_bb : c);
+                 continue;
                }
 
              /* Remove code labels no longer used.  */
-             if (b->pred->pred_next == NULL
-                 && (b->pred->flags & EDGE_FALLTHRU)
-                 && !(b->pred->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
@@ -1836,22 +1906,24 @@ 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).  */
-                 && (b->pred->src == ENTRY_BLOCK_PTR
-                     || !JUMP_P (BB_END (b->pred->src))
+                 && (single_pred (b) == ENTRY_BLOCK_PTR
+                     || !JUMP_P (BB_END (single_pred (b)))
                      || ! label_is_jump_target_p (BB_HEAD (b),
-                                                  BB_END (b->pred->src))))
+                                                  BB_END (single_pred (b)))))
                {
                  rtx label = BB_HEAD (b);
 
-                 delete_insn_chain (label, label);
-                 /* In the case label is undeletable, move it after the
+                 delete_insn_chain (label, label, false);
+                 /* If the case label is undeletable, move it after the
                     BASIC_BLOCK note.  */
-                 if (NOTE_LINE_NUMBER (BB_HEAD (b)) == NOTE_INSN_DELETED_LABEL)
+                 if (NOTE_KIND (BB_HEAD (b)) == NOTE_INSN_DELETED_LABEL)
                    {
                      rtx bb_note = NEXT_INSN (BB_HEAD (b));
 
                      reorder_insns_nobb (label, label, bb_note);
                      BB_HEAD (b) = bb_note;
+                     if (BB_END (b) == bb_note)
+                       BB_END (b) = label;
                    }
                  if (dump_file)
                    fprintf (dump_file, "Deleted label in block %i.\n",
@@ -1860,14 +1932,14 @@ try_optimize_cfg (int mode)
 
              /* If we fall through an empty block, we can remove it.  */
              if (!(mode & CLEANUP_CFGLAYOUT)
-                 && b->pred->pred_next == NULL
-                 && (b->pred->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.  */
-                 && (b->succ->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,
@@ -1875,17 +1947,19 @@ try_optimize_cfg (int mode)
                             b->index);
 
                  c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
-                 redirect_edge_succ_nodup (b->pred, b->succ->dest);
+                 redirect_edge_succ_nodup (single_pred_edge (b),
+                                           single_succ (b));
                  delete_basic_block (b);
                  changed = true;
                  b = c;
+                 continue;
                }
 
-             if ((s = b->succ) != NULL
-                 && s->succ_next == NULL
+             if (single_succ_p (b)
+                 && (s = single_succ_edge (b))
                  && !(s->flags & EDGE_COMPLEX)
                  && (c = s->dest) != EXIT_BLOCK_PTR
-                 && c->pred->pred_next == NULL
+                 && single_pred_p (c)
                  && b != c)
                {
                  /* When not in cfg_layout mode use code aware of reordering
@@ -1893,7 +1967,7 @@ try_optimize_cfg (int mode)
                     does not fit merge_blocks interface and is kept here in
                     hope that it will become useless once more of compiler
                     is transformed to use cfg_layout mode.  */
-                    
+
                  if ((mode & CLEANUP_CFGLAYOUT)
                      && can_merge_blocks_p (b, c))
                    {
@@ -1927,12 +2001,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 (b->succ
-                 && ! b->succ->succ_next
-                 && b->succ->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 (b->succ, b->succ->dest,
+                 && try_redirect_by_replacing_jump (single_succ_edge (b),
+                                                    single_succ (b),
                                                     (mode & CLEANUP_CFGLAYOUT) != 0))
                {
                  update_forwarder_flag (b);
@@ -1971,10 +2045,8 @@ try_optimize_cfg (int mode)
       while (changed);
     }
 
-  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;
 }
@@ -1985,20 +2057,64 @@ bool
 delete_unreachable_blocks (void)
 {
   bool changed = false;
-  basic_block b, next_bb;
+  basic_block b, prev_bb;
 
   find_unreachable_blocks ();
 
-  /* Delete all unreachable basic blocks.  */
-
-  for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR; b = next_bb)
+  /* When we're in GIMPLE mode and there may be debug insns, we should
+     delete blocks in reverse dominator order, so as to get a chance
+     to substitute all released DEFs into debug stmts.  If we don't
+     have dominators information, walking blocks backward gets us a
+     better chance of retaining most debug information than
+     otherwise.  */
+  if (MAY_HAVE_DEBUG_STMTS && current_ir_type () == IR_GIMPLE
+      && dom_info_available_p (CDI_DOMINATORS))
     {
-      next_bb = b->next_bb;
+      for (b = EXIT_BLOCK_PTR->prev_bb; b != ENTRY_BLOCK_PTR; b = prev_bb)
+       {
+         prev_bb = b->prev_bb;
+
+         if (!(b->flags & BB_REACHABLE))
+           {
+             /* Speed up the removal of blocks that don't dominate
+                others.  Walking backwards, this should be the common
+                case.  */
+             if (!first_dom_son (CDI_DOMINATORS, b))
+               delete_basic_block (b);
+             else
+               {
+                 VEC (basic_block, heap) *h
+                   = get_all_dominated_blocks (CDI_DOMINATORS, b);
+
+                 while (VEC_length (basic_block, h))
+                   {
+                     b = VEC_pop (basic_block, h);
 
-      if (!(b->flags & BB_REACHABLE))
+                     prev_bb = b->prev_bb;
+
+                     gcc_assert (!(b->flags & BB_REACHABLE));
+
+                     delete_basic_block (b);
+                   }
+
+                 VEC_free (basic_block, heap, h);
+               }
+
+             changed = true;
+           }
+       }
+    }
+  else
+    {
+      for (b = EXIT_BLOCK_PTR->prev_bb; b != ENTRY_BLOCK_PTR; b = prev_bb)
        {
-         delete_basic_block (b);
-         changed = true;
+         prev_bb = b->prev_bb;
+
+         if (!(b->flags & BB_REACHABLE))
+           {
+             delete_basic_block (b);
+             changed = true;
+           }
        }
     }
 
@@ -2007,31 +2123,44 @@ delete_unreachable_blocks (void)
   return changed;
 }
 
-/* Merges sequential blocks if possible.  */
-
-bool
-merge_seq_blocks (void)
+/* Delete any jump tables never referenced.  We can't delete them at the
+   time of removing tablejump insn as they are referenced by the preceding
+   insns computing the destination, so we delay deleting and garbagecollect
+   them once life information is computed.  */
+void
+delete_dead_jumptables (void)
 {
   basic_block bb;
-  bool changed = false;
 
-  for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; )
+  /* A dead jump table does not belong to any basic block.  Scan insns
+     between two adjacent basic blocks.  */
+  FOR_EACH_BB (bb)
     {
-      if (bb->succ
-         && !bb->succ->succ_next
-         && can_merge_blocks_p (bb, bb->succ->dest))
+      rtx insn, next;
+
+      for (insn = NEXT_INSN (BB_END (bb));
+          insn && !NOTE_INSN_BASIC_BLOCK_P (insn);
+          insn = next)
        {
-         /* Merge the blocks and retry.  */
-         merge_blocks (bb, bb->succ->dest);
-         changed = true;
-         continue;
-       }
+         next = NEXT_INSN (insn);
+         if (LABEL_P (insn)
+             && LABEL_NUSES (insn) == LABEL_PRESERVE_P (insn)
+             && JUMP_TABLE_DATA_P (next))
+           {
+             rtx label = insn, jump = next;
 
-      bb = bb->next_bb;
-    }
+             if (dump_file)
+               fprintf (dump_file, "Dead jumptable %i removed\n",
+                        INSN_UID (insn));
 
-  return changed;
+             next = NEXT_INSN (next);
+             delete_insn (jump);
+             delete_insn (label);
+           }
+       }
+    }
 }
+
 \f
 /* Tidy the CFG by deleting unreachable code and whatnot.  */
 
@@ -2040,50 +2169,137 @@ cleanup_cfg (int mode)
 {
   bool changed = false;
 
+  /* Set the cfglayout mode flag here.  We could update all the callers
+     but that is just inconvenient, especially given that we eventually
+     want to have cfglayout mode as the default.  */
+  if (current_ir_type () == IR_RTL_CFGLAYOUT)
+    mode |= CLEANUP_CFGLAYOUT;
+
   timevar_push (TV_CLEANUP_CFG);
   if (delete_unreachable_blocks ())
     {
       changed = true;
       /* We've possibly created trivially dead code.  Cleanup it right
         now to introduce more opportunities for try_optimize_cfg.  */
-      if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_UPDATE_LIFE))
+      if (!(mode & (CLEANUP_NO_INSN_DEL))
          && !reload_completed)
-       delete_trivially_dead_insns (get_insns(), max_reg_num ());
+       delete_trivially_dead_insns (get_insns (), max_reg_num ());
     }
 
   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_UPDATE_LIFE)
+      if (!(mode & CLEANUP_NO_INSN_DEL))
        {
-         /* Cleaning up CFG introduces more opportunities for dead code
-            removal that in turn may introduce more opportunities for
-            cleaning up the CFG.  */
-         if (!update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
-                                                PROP_DEATH_NOTES
-                                                | PROP_SCAN_DEAD_CODE
-                                                | PROP_KILL_DEAD_CODE
-                                                | ((mode & CLEANUP_LOG_LINKS)
-                                                   ? PROP_LOG_LINKS : 0)))
-           break;
-       }
-      else if (!(mode & CLEANUP_NO_INSN_DEL)
-              && (mode & CLEANUP_EXPENSIVE)
-              && !reload_completed)
-       {
-         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;
-      delete_dead_jumptables ();
     }
 
-  /* Kill the data we won't maintain.  */
-  free_EXPR_LIST_list (&label_value_list);
+  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
+     mode because we shouldn't even be looking at things that are
+     not in a basic block.  Dead jumptables are cleaned up when
+     going out of cfglayout mode.  */
+  if (!(mode & CLEANUP_CFGLAYOUT))
+    delete_dead_jumptables ();
+
   timevar_pop (TV_CLEANUP_CFG);
 
   return changed;
 }
+\f
+static unsigned int
+rest_of_handle_jump (void)
+{
+  if (crtl->tail_call_emit)
+    fixup_tail_calls ();
+  return 0;
+}
+
+struct rtl_opt_pass pass_jump =
+{
+ {
+  RTL_PASS,
+  "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_verify_flow,                     /* todo_flags_finish */
+ }
+};
+
+
+static unsigned int
+rest_of_handle_jump2 (void)
+{
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+  cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0)
+              | (flag_thread_jumps ? CLEANUP_THREADING : 0));
+  return 0;
+}
+
+
+struct rtl_opt_pass pass_jump2 =
+{
+ {
+  RTL_PASS,
+  "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_verify_rtl_sharing,/* todo_flags_finish */
+ }
+};
+
+