This patch normalizes more bitmap function names.
[platform/upstream/gcc.git] / gcc / cfgrtl.c
index 9de8d12..9156ee8 100644 (file)
@@ -1,7 +1,7 @@
 /* Control flow graph manipulation code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
         insert_insn_on_edge, commit_edge_insertions
      - CFG updating after insn simplification
         purge_dead_edges, purge_all_dead_edges
+     - CFG fixing after coarse manipulation
+       fixup_abnormal_edges
 
    Functions not supposed for generic use:
      - Infrastructure to determine quickly basic block for insn
@@ -42,29 +44,39 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "rtl.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "regs.h"
 #include "flags.h"
-#include "output.h"
 #include "function.h"
 #include "except.h"
-#include "toplev.h"
+#include "rtl-error.h"
 #include "tm_p.h"
 #include "obstack.h"
+#include "insn-attr.h"
 #include "insn-config.h"
-#include "cfglayout.h"
 #include "expr.h"
 #include "target.h"
+#include "common/common-target.h"
 #include "cfgloop.h"
 #include "ggc.h"
 #include "tree-pass.h"
 #include "df.h"
 
+/* Holds the interesting leading and trailing notes for the function.
+   Only applicable if the CFG is in cfglayout mode.  */
+static GTY(()) rtx cfg_layout_function_footer;
+static GTY(()) rtx cfg_layout_function_header;
+
+static rtx skip_insns_after_block (basic_block);
+static void record_effective_endpoints (void);
+static rtx label_for_bb (basic_block);
+static void fixup_reorder_chain (void);
+
+void verify_insn_chain (void);
+static void fixup_fallthru_exit_predecessor (void);
 static int can_delete_note_p (const_rtx);
 static int can_delete_label_p (const_rtx);
-static void commit_one_edge_insertion (edge);
 static basic_block rtl_split_edge (edge);
 static bool rtl_move_block_after (basic_block, basic_block);
 static int rtl_verify_flow_info (void);
@@ -76,7 +88,7 @@ static void rtl_delete_block (basic_block);
 static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
 static edge rtl_redirect_edge_and_branch (edge, basic_block);
 static basic_block rtl_split_block (basic_block, void *);
-static void rtl_dump_bb (basic_block, FILE *, int);
+static void rtl_dump_bb (FILE *, basic_block, int, int);
 static int rtl_verify_flow_info_1 (void);
 static void rtl_make_forwarder_block (edge);
 \f
@@ -86,8 +98,16 @@ static void rtl_make_forwarder_block (edge);
 static int
 can_delete_note_p (const_rtx note)
 {
-  return (NOTE_KIND (note) == NOTE_INSN_DELETED
-         || NOTE_KIND (note) == NOTE_INSN_BASIC_BLOCK);
+  switch (NOTE_KIND (note))
+    {
+    case NOTE_INSN_DELETED:
+    case NOTE_INSN_BASIC_BLOCK:
+    case NOTE_INSN_EPILOGUE_BEG:
+      return true;
+
+    default:
+      return false;
+    }
 }
 
 /* True if a given label can be deleted.  */
@@ -101,12 +121,11 @@ can_delete_label_p (const_rtx label)
          && !in_expr_list_p (forced_labels, label));
 }
 
-/* Delete INSN by patching it out.  Return the next insn.  */
+/* Delete INSN by patching it out.  */
 
-rtx
+void
 delete_insn (rtx insn)
 {
-  rtx next = NEXT_INSN (insn);
   rtx note;
   bool really_delete = true;
 
@@ -118,11 +137,22 @@ delete_insn (rtx insn)
       if (! can_delete_label_p (insn))
        {
          const char *name = LABEL_NAME (insn);
+         basic_block bb = BLOCK_FOR_INSN (insn);
+         rtx bb_note = NEXT_INSN (insn);
 
          really_delete = false;
          PUT_CODE (insn, NOTE);
          NOTE_KIND (insn) = NOTE_INSN_DELETED_LABEL;
          NOTE_DELETED_LABEL_NAME (insn) = name;
+
+         if (bb_note != NULL_RTX && NOTE_INSN_BASIC_BLOCK_P (bb_note)
+             && BLOCK_FOR_INSN (bb_note) == bb)
+           {
+             reorder_insns_nobb (insn, insn, bb_note);
+             BB_HEAD (bb) = bb_note;
+             if (BB_END (bb) == bb_note)
+               BB_END (bb) = insn;
+           }
        }
 
       remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
@@ -138,18 +168,15 @@ delete_insn (rtx insn)
 
   /* If deleting a jump, decrement the use count of the label.  Deleting
      the label itself should happen in the normal course of block merging.  */
-  if (JUMP_P (insn)
-      && JUMP_LABEL (insn)
-      && LABEL_P (JUMP_LABEL (insn)))
+  if (JUMP_P (insn))
     {
-      LABEL_NUSES (JUMP_LABEL (insn))--;
-      JUMP_LABEL (insn) = NULL;
-    }
+      if (JUMP_LABEL (insn)
+         && LABEL_P (JUMP_LABEL (insn)))
+       LABEL_NUSES (JUMP_LABEL (insn))--;
 
-  /* Also if deleting an insn that references a label.  */
-  else
-    {
-      while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
+      /* If there are more targets, remove them too.  */
+      while ((note
+             = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX
             && LABEL_P (XEXP (note, 0)))
        {
          LABEL_NUSES (XEXP (note, 0))--;
@@ -157,9 +184,15 @@ delete_insn (rtx insn)
        }
     }
 
-  if (JUMP_P (insn)
-      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
-         || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+  /* Also if deleting any insn that references a label as an operand.  */
+  while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX
+        && LABEL_P (XEXP (note, 0)))
+    {
+      LABEL_NUSES (XEXP (note, 0))--;
+      remove_note (insn, note);
+    }
+
+  if (JUMP_TABLE_DATA_P (insn))
     {
       rtx pat = PATTERN (insn);
       int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
@@ -177,25 +210,22 @@ delete_insn (rtx insn)
            LABEL_NUSES (label)--;
        }
     }
-
-  return next;
 }
 
 /* Like delete_insn but also purge dead edges from BB.  */
-rtx
+
+void
 delete_insn_and_edges (rtx insn)
 {
-  rtx x;
   bool purge = false;
 
   if (INSN_P (insn)
       && BLOCK_FOR_INSN (insn)
       && BB_END (BLOCK_FOR_INSN (insn)) == insn)
     purge = true;
-  x = delete_insn (insn);
+  delete_insn (insn);
   if (purge)
     purge_dead_edges (BLOCK_FOR_INSN (insn));
-  return x;
 }
 
 /* Unlink a chain of insns between START and FINISH, leaving notes
@@ -205,25 +235,26 @@ delete_insn_and_edges (rtx insn)
 void
 delete_insn_chain (rtx start, rtx finish, bool clear_bb)
 {
-  rtx next;
+  rtx prev, current;
 
   /* Unchain the insns one by one.  It would be quicker to delete all of these
      with a single unchaining, rather than one at a time, but we need to keep
      the NOTE's.  */
+  current = finish;
   while (1)
     {
-      next = NEXT_INSN (start);
-      if (NOTE_P (start) && !can_delete_note_p (start))
+      prev = PREV_INSN (current);
+      if (NOTE_P (current) && !can_delete_note_p (current))
        ;
       else
-       next = delete_insn (start);
+       delete_insn (current);
 
-      if (clear_bb && !INSN_DELETED_P (start))
-       set_block_for_insn (start, NULL);
+      if (clear_bb && !INSN_DELETED_P (current))
+       set_block_for_insn (current, NULL);
 
-      if (start == finish)
+      if (current == start)
        break;
-      start = next;
+      current = prev;
     }
 }
 \f
@@ -308,9 +339,9 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
 }
 
 /* Create new basic block consisting of instructions in between HEAD and END
-   and place it to the BB chain after block AFTER.  END can be NULL in to
-   create new empty basic block before HEAD.  Both END and HEAD can be NULL to
-   create basic block at the end of INSN chain.  */
+   and place it to the BB chain after block AFTER.  END can be NULL to
+   create a new empty basic block before HEAD.  Both END and HEAD can be
+   NULL to create basic block at the end of INSN chain.  */
 
 static basic_block
 rtl_create_basic_block (void *headp, void *endp, basic_block after)
@@ -357,8 +388,6 @@ rtl_delete_block (basic_block b)
      label for an exception handler which can't be reached.  We need
      to remove the label from the exception_handler_label list.  */
   insn = BB_HEAD (b);
-  if (LABEL_P (insn))
-    maybe_remove_eh_handler (insn);
 
   end = get_last_bb_insn (b);
 
@@ -405,21 +434,41 @@ free_bb_for_insn (void)
   return 0;
 }
 
-struct tree_opt_pass pass_free_cfg =
+static unsigned int
+rest_of_pass_free_cfg (void)
+{
+#ifdef DELAY_SLOTS
+  /* The resource.c machinery uses DF but the CFG isn't guaranteed to be
+     valid at that point so it would be too late to call df_analyze.  */
+  if (optimize > 0 && flag_delayed_branch)
+    {
+      df_note_add_problem ();
+      df_analyze ();
+    }
+#endif
+
+  free_bb_for_insn ();
+  return 0;
+}
+
+struct rtl_opt_pass pass_free_cfg =
 {
-  NULL,                                 /* name */
+ {
+  RTL_PASS,
+  "*free_cfg",                          /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
   NULL,                                 /* gate */
-  free_bb_for_insn,                     /* execute */
+  rest_of_pass_free_cfg,                /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   PROP_cfg,                             /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+ }
 };
 
 /* Return RTX to emit after when we want to emit code on the entry of function.  */
@@ -443,25 +492,158 @@ emit_insn_at_entry (rtx insn)
   commit_edge_insertions ();
 }
 
-/* Update insns block within BB.  */
+/* Update BLOCK_FOR_INSN of insns between BEGIN and END
+   (or BARRIER if found) and notify df of the bb change.
+   The insn chain range is inclusive
+   (i.e. both BEGIN and END will be updated. */
+
+static void
+update_bb_for_insn_chain (rtx begin, rtx end, basic_block bb)
+{
+  rtx insn;
+
+  end = NEXT_INSN (end);
+  for (insn = begin; insn != end; insn = NEXT_INSN (insn))
+    if (!BARRIER_P (insn))
+      df_insn_change_bb (insn, bb);
+}
+
+/* Update BLOCK_FOR_INSN of insns in BB to BB,
+   and notify df of the change.  */
 
 void
 update_bb_for_insn (basic_block bb)
 {
+  update_bb_for_insn_chain (BB_HEAD (bb), BB_END (bb), bb);
+}
+
+\f
+/* Like active_insn_p, except keep the return value clobber around
+   even after reload.  */
+
+static bool
+flow_active_insn_p (const_rtx insn)
+{
+  if (active_insn_p (insn))
+    return true;
+
+  /* A clobber of the function return value exists for buggy
+     programs that fail to return a value.  Its effect is to
+     keep the return value from being live across the entire
+     function.  If we allow it to be skipped, we introduce the
+     possibility for register lifetime confusion.  */
+  if (GET_CODE (PATTERN (insn)) == CLOBBER
+      && REG_P (XEXP (PATTERN (insn), 0))
+      && REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))
+    return true;
+
+  return false;
+}
+
+/* Return true if the block has no effect and only forwards control flow to
+   its single destination.  */
+
+bool
+contains_no_active_insn_p (const_basic_block bb)
+{
   rtx insn;
 
-  for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
+  if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR
+      || !single_succ_p (bb))
+    return false;
+
+  for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = NEXT_INSN (insn))
+    if (INSN_P (insn) && flow_active_insn_p (insn))
+      return false;
+
+  return (!INSN_P (insn)
+         || (JUMP_P (insn) && simplejump_p (insn))
+         || !flow_active_insn_p (insn));
+}
+
+/* Likewise, but protect loop latches, headers and preheaders.  */
+/* FIXME: Make this a cfg hook.  */
+
+bool
+forwarder_block_p (const_basic_block bb)
+{
+  if (!contains_no_active_insn_p (bb))
+    return false;
+
+  /* Protect loop latches, headers and preheaders.  */
+  if (current_loops)
     {
-      if (!BARRIER_P (insn))
-       {
-         set_block_for_insn (insn, bb);
-         df_insn_change_bb (insn);
-       }
-      if (insn == BB_END (bb))
-       break;
+      basic_block dest;
+      if (bb->loop_father->header == bb)
+       return false;
+      dest = EDGE_SUCC (bb, 0)->dest;
+      if (dest->loop_father->header == dest)
+       return false;
     }
+
+  return true;
+}
+
+/* Return nonzero if we can reach target from src by falling through.  */
+/* FIXME: Make this a cfg hook.  */
+
+bool
+can_fallthru (basic_block src, basic_block target)
+{
+  rtx insn = BB_END (src);
+  rtx insn2;
+  edge e;
+  edge_iterator ei;
+
+  if (target == EXIT_BLOCK_PTR)
+    return true;
+  if (src->next_bb != target)
+    return 0;
+  FOR_EACH_EDGE (e, ei, src->succs)
+    if (e->dest == EXIT_BLOCK_PTR
+       && e->flags & EDGE_FALLTHRU)
+      return 0;
+
+  insn2 = BB_HEAD (target);
+  if (insn2 && !active_insn_p (insn2))
+    insn2 = next_active_insn (insn2);
+
+  /* ??? Later we may add code to move jump tables offline.  */
+  return next_active_insn (insn) == insn2;
+}
+
+/* Return nonzero if we could reach target from src by falling through,
+   if the target was made adjacent.  If we already have a fall-through
+   edge to the exit block, we can't do that.  */
+static bool
+could_fall_through (basic_block src, basic_block target)
+{
+  edge e;
+  edge_iterator ei;
+
+  if (target == EXIT_BLOCK_PTR)
+    return true;
+  FOR_EACH_EDGE (e, ei, src->succs)
+    if (e->dest == EXIT_BLOCK_PTR
+       && e->flags & EDGE_FALLTHRU)
+      return 0;
+  return true;
 }
 \f
+/* Return the NOTE_INSN_BASIC_BLOCK of BB.  */
+rtx
+bb_note (basic_block bb)
+{
+  rtx note;
+
+  note = BB_HEAD (bb);
+  if (LABEL_P (note))
+    note = NEXT_INSN (note);
+
+  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (note));
+  return note;
+}
+
 /* Return the INSN immediately following the NOTE_INSN_BASIC_BLOCK
    note associated with the BLOCK.  */
 
@@ -498,7 +680,26 @@ rtl_split_block (basic_block bb, void *insnp)
       insn = first_insn_after_basic_block_note (bb);
 
       if (insn)
-       insn = PREV_INSN (insn);
+       {
+         rtx next = insn;
+
+         insn = PREV_INSN (insn);
+
+         /* If the block contains only debug insns, insn would have
+            been NULL in a non-debug compilation, and then we'd end
+            up emitting a DELETED note.  For -fcompare-debug
+            stability, emit the note too.  */
+         if (insn != BB_END (bb)
+             && DEBUG_INSN_P (next)
+             && DEBUG_INSN_P (BB_END (bb)))
+           {
+             while (next != BB_END (bb) && DEBUG_INSN_P (next))
+               next = NEXT_INSN (next);
+
+             if (next == BB_END (bb))
+               emit_note_after (NOTE_INSN_DELETED, next);
+           }
+       }
       else
        insn = get_last_insn ();
     }
@@ -525,6 +726,56 @@ rtl_split_block (basic_block bb, void *insnp)
   return new_bb;
 }
 
+/* Return true if the single edge between blocks A and B is the only place
+   in RTL which holds some unique locus.  */
+
+static bool
+unique_locus_on_edge_between_p (basic_block a, basic_block b)
+{
+  const location_t goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+  rtx insn, end;
+
+  if (LOCATION_LOCUS (goto_locus) == UNKNOWN_LOCATION)
+    return false;
+
+  /* First scan block A backward.  */
+  insn = BB_END (a);
+  end = PREV_INSN (BB_HEAD (a));
+  while (insn != end && (!NONDEBUG_INSN_P (insn) || !INSN_HAS_LOCATION (insn)))
+    insn = PREV_INSN (insn);
+
+  if (insn != end && INSN_LOCATION (insn) == goto_locus)
+    return false;
+
+  /* Then scan block B forward.  */
+  insn = BB_HEAD (b);
+  if (insn)
+    {
+      end = NEXT_INSN (BB_END (b));
+      while (insn != end && !NONDEBUG_INSN_P (insn))
+       insn = NEXT_INSN (insn);
+
+      if (insn != end && INSN_HAS_LOCATION (insn)
+         && INSN_LOCATION (insn) == goto_locus)
+       return false;
+    }
+
+  return true;
+}
+
+/* If the single edge between blocks A and B is the only place in RTL which
+   holds some unique locus, emit a nop with that locus between the blocks.  */
+
+static void
+emit_nop_for_unique_locus_between (basic_block a, basic_block b)
+{
+  if (!unique_locus_on_edge_between_p (a, b))
+    return;
+
+  BB_END (a) = emit_insn_after_noloc (gen_nop (), BB_END (a), a);
+  INSN_LOCATION (BB_END (a)) = EDGE_SUCC (a, 0)->goto_locus;
+}
+
 /* Blocks A and B are to be merged into a single block A.  The insns
    are already contiguous.  */
 
@@ -533,18 +784,20 @@ rtl_merge_blocks (basic_block a, basic_block b)
 {
   rtx b_head = BB_HEAD (b), b_end = BB_END (b), a_end = BB_END (a);
   rtx del_first = NULL_RTX, del_last = NULL_RTX;
+  rtx b_debug_start = b_end, b_debug_end = b_end;
+  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
   int b_empty = 0;
 
   if (dump_file)
-    fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+    fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+            a->index);
+
+  while (DEBUG_INSN_P (b_end))
+    b_end = PREV_INSN (b_debug_start = b_end);
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (b_head))
     {
-      /* This might have been an EH label that no longer has incoming
-        EH edges.  Update data structures to match.  */
-      maybe_remove_eh_handler (b_head);
-
       /* Detect basic blocks with nothing but a label.  This can happen
         in particular at the end of a function.  */
       if (b_head == b_end)
@@ -601,28 +854,47 @@ rtl_merge_blocks (basic_block a, basic_block b)
 
   /* Delete everything marked above as well as crap that might be
      hanging out between the two blocks.  */
-  BB_HEAD (b) = NULL;
+  BB_END (a) = a_end;
+  BB_HEAD (b) = b_empty ? NULL_RTX : b_head;
   delete_insn_chain (del_first, del_last, true);
 
+  /* When not optimizing CFG and the edge is the only place in RTL which holds
+     some unique locus, emit a nop with that locus in between.  */
+  if (!optimize)
+    {
+      emit_nop_for_unique_locus_between (a, b);
+      a_end = BB_END (a);
+    }
+
   /* Reassociate the insns of B with A.  */
   if (!b_empty)
     {
-      rtx x;
-
-      for (x = a_end; x != b_end; x = NEXT_INSN (x))
-       {
-         set_block_for_insn (x, a);
-         df_insn_change_bb (x);
-       }
+      update_bb_for_insn_chain (a_end, b_debug_end, a);
 
-      set_block_for_insn (b_end, a);
-      df_insn_change_bb (b_end);
-
-      a_end = b_end;
+      BB_END (a) = b_debug_end;
+      BB_HEAD (b) = NULL_RTX;
+    }
+  else if (b_end != b_debug_end)
+    {
+      /* Move any deleted labels and other notes between the end of A
+        and the debug insns that make up B after the debug insns,
+        bringing the debug insns into A while keeping the notes after
+        the end of A.  */
+      if (NEXT_INSN (a_end) != b_debug_start)
+       reorder_insns_nobb (NEXT_INSN (a_end), PREV_INSN (b_debug_start),
+                           b_debug_end);
+      update_bb_for_insn_chain (b_debug_start, b_debug_end, a);
+      BB_END (a) = b_debug_end;
     }
 
   df_bb_delete (b->index);
-  BB_END (a) = a_end;
+
+  /* If B was a forwarder block, propagate the locus on the edge.  */
+  if (forwarder_p && !EDGE_SUCC (b, 0)->goto_locus)
+    EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
+  if (dump_file)
+    fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
 }
 
 
@@ -644,6 +916,10 @@ rtl_can_merge_blocks (basic_block a, basic_block b)
   if (BB_PARTITION (a) != BB_PARTITION (b))
     return false;
 
+  /* Protect the loop latches.  */
+  if (current_loops && b->loop_father->latch == b)
+    return false;
+
   /* There must be exactly one edge in between the blocks.  */
   return (single_succ_p (a)
          && single_succ (a) == b
@@ -743,7 +1019,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
       /* Selectively unlink whole insn chain.  */
       if (in_cfglayout)
        {
-         rtx insn = src->il.rtl->footer;
+         rtx insn = BB_FOOTER (src);
 
          delete_insn_chain (kill_from, BB_END (src), false);
 
@@ -755,7 +1031,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
                  if (PREV_INSN (insn))
                    NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
                  else
-                   src->il.rtl->footer = NEXT_INSN (insn);
+                   BB_FOOTER (src) = NEXT_INSN (insn);
                  if (NEXT_INSN (insn))
                    PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
                }
@@ -793,7 +1069,6 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
     {
       rtx target_label = block_label (target);
       rtx barrier, label, table;
-      bool jump_p;
 
       emit_jump_insn_after_noloc (gen_jump (target_label), insn);
       JUMP_LABEL (BB_END (src)) = target_label;
@@ -803,14 +1078,13 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
                 INSN_UID (insn), INSN_UID (BB_END (src)));
 
 
+      delete_insn_chain (kill_from, insn, false);
+
       /* Recognize a tablejump that we are converting to a
         simple jump and remove its associated CODE_LABEL
         and ADDR_VEC or ADDR_DIFF_VEC.  */
-      jump_p = tablejump_p (insn, &label, &table);
-
-      delete_insn_chain (kill_from, insn, false);
-      if (jump_p)
-        delete_insn_chain (label, table, false);
+      if (tablejump_p (insn, &label, &table))
+       delete_insn_chain (label, table, false);
 
       barrier = next_nonnote_insn (BB_END (src));
       if (!barrier || !BARRIER_P (barrier))
@@ -823,14 +1097,9 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
                 which originally were or were created before jump table are
                 inside the basic block.  */
              rtx new_insn = BB_END (src);
-             rtx tmp;
 
-             for (tmp = NEXT_INSN (BB_END (src)); tmp != barrier;
-                  tmp = NEXT_INSN (tmp))
-               {
-                 set_block_for_insn (tmp, src);
-                 df_insn_change_bb (tmp);
-               }
+             update_bb_for_insn_chain (NEXT_INSN (BB_END (src)),
+                                       PREV_INSN (barrier), src);
 
              NEXT_INSN (PREV_INSN (new_insn)) = NEXT_INSN (new_insn);
              PREV_INSN (NEXT_INSN (new_insn)) = PREV_INSN (new_insn);
@@ -863,31 +1132,25 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   return e;
 }
 
-/* Redirect edge representing branch of (un)conditional jump or tablejump,
-   NULL on failure  */
-static edge
-redirect_branch_edge (edge e, basic_block target)
+/* Subroutine of redirect_branch_edge that tries to patch the jump
+   instruction INSN so that it reaches block NEW.  Do this
+   only when it originally reached block OLD.  Return true if this
+   worked or the original target wasn't OLD, return false if redirection
+   doesn't work.  */
+
+static bool
+patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb)
 {
   rtx tmp;
-  rtx old_label = BB_HEAD (e->dest);
-  basic_block src = e->src;
-  rtx insn = BB_END (src);
-
-  /* We can only redirect non-fallthru edges of jump insn.  */
-  if (e->flags & EDGE_FALLTHRU)
-    return NULL;
-  else if (!JUMP_P (insn))
-    return NULL;
-
   /* Recognize a tablejump and adjust all matching cases.  */
   if (tablejump_p (insn, NULL, &tmp))
     {
       rtvec vec;
       int j;
-      rtx new_label = block_label (target);
+      rtx new_label = block_label (new_bb);
 
-      if (target == EXIT_BLOCK_PTR)
-       return NULL;
+      if (new_bb == EXIT_BLOCK_PTR)
+       return false;
       if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
        vec = XVEC (PATTERN (tmp), 0);
       else
@@ -914,6 +1177,48 @@ redirect_branch_edge (edge e, basic_block target)
          ++LABEL_NUSES (new_label);
        }
     }
+  else if ((tmp = extract_asm_operands (PATTERN (insn))) != NULL)
+    {
+      int i, n = ASM_OPERANDS_LABEL_LENGTH (tmp);
+      rtx new_label, note;
+
+      if (new_bb == EXIT_BLOCK_PTR)
+       return false;
+      new_label = block_label (new_bb);
+
+      for (i = 0; i < n; ++i)
+       {
+         rtx old_ref = ASM_OPERANDS_LABEL (tmp, i);
+         gcc_assert (GET_CODE (old_ref) == LABEL_REF);
+         if (XEXP (old_ref, 0) == old_label)
+           {
+             ASM_OPERANDS_LABEL (tmp, i)
+               = gen_rtx_LABEL_REF (Pmode, new_label);
+             --LABEL_NUSES (old_label);
+             ++LABEL_NUSES (new_label);
+           }
+       }
+
+      if (JUMP_LABEL (insn) == old_label)
+       {
+         JUMP_LABEL (insn) = new_label;
+         note = find_reg_note (insn, REG_LABEL_TARGET, new_label);
+         if (note)
+           remove_note (insn, note);
+       }
+      else
+       {
+         note = find_reg_note (insn, REG_LABEL_TARGET, old_label);
+         if (note)
+           remove_note (insn, note);
+         if (JUMP_LABEL (insn) != new_label
+             && !find_reg_note (insn, REG_LABEL_TARGET, new_label))
+           add_reg_note (insn, REG_LABEL_TARGET, new_label);
+       }
+      while ((note = find_reg_note (insn, REG_LABEL_OPERAND, old_label))
+            != NULL_RTX)
+       XEXP (note, 0) = new_label;
+    }
   else
     {
       /* ?? We may play the games with moving the named labels from
@@ -922,20 +1227,54 @@ redirect_branch_edge (edge e, basic_block target)
       if (computed_jump_p (insn)
          /* A return instruction can't be redirected.  */
          || returnjump_p (insn))
-       return NULL;
+       return false;
 
-      /* If the insn doesn't go where we think, we're confused.  */
-      gcc_assert (JUMP_LABEL (insn) == old_label);
-
-      /* If the substitution doesn't succeed, die.  This can happen
-        if the back end emitted unrecognizable instructions or if
-        target is exit block on some arches.  */
-      if (!redirect_jump (insn, block_label (target), 0))
+      if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label)
        {
-         gcc_assert (target == EXIT_BLOCK_PTR);
-         return NULL;
+         /* If the insn doesn't go where we think, we're confused.  */
+         gcc_assert (JUMP_LABEL (insn) == old_label);
+
+         /* If the substitution doesn't succeed, die.  This can happen
+            if the back end emitted unrecognizable instructions or if
+            target is exit block on some arches.  */
+         if (!redirect_jump (insn, block_label (new_bb), 0))
+           {
+             gcc_assert (new_bb == EXIT_BLOCK_PTR);
+             return false;
+           }
        }
     }
+  return true;
+}
+
+
+/* Redirect edge representing branch of (un)conditional jump or tablejump,
+   NULL on failure  */
+static edge
+redirect_branch_edge (edge e, basic_block target)
+{
+  rtx old_label = BB_HEAD (e->dest);
+  basic_block src = e->src;
+  rtx insn = BB_END (src);
+
+  /* We can only redirect non-fallthru edges of jump insn.  */
+  if (e->flags & EDGE_FALLTHRU)
+    return NULL;
+  else if (!JUMP_P (insn) && !currently_expanding_to_rtl)
+    return NULL;
+
+  if (!currently_expanding_to_rtl)
+    {
+      if (!patch_jump_insn (insn, old_label, target))
+       return NULL;
+    }
+  else
+    /* When expanding this BB might actually contain multiple
+       jumps (i.e. not yet split by find_many_sub_basic_blocks).
+       Redirect all of those that match our label.  */
+    FOR_BB_INSNS (src, insn)
+      if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target))
+       return NULL;
 
   if (dump_file)
     fprintf (dump_file, "Edge %i->%i redirected to %i\n",
@@ -985,15 +1324,20 @@ rtl_redirect_edge_and_branch (edge e, basic_block target)
 }
 
 /* Like force_nonfallthru below, but additionally performs redirection
-   Used by redirect_edge_and_branch_force.  */
+   Used by redirect_edge_and_branch_force.  JUMP_LABEL is used only
+   when redirecting to the EXIT_BLOCK, it is either ret_rtx or
+   simple_return_rtx, indicating which kind of returnjump to create.
+   It should be NULL otherwise.  */
 
-static basic_block
-force_nonfallthru_and_redirect (edge e, basic_block target)
+basic_block
+force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
 {
   basic_block jump_block, new_bb = NULL, src = e->src;
   rtx note;
   edge new_edge;
   int abnormal_edge_flags = 0;
+  bool asm_goto_edge = false;
+  int loc;
 
   /* In the case the last instruction is conditional jump to the next
      instruction, first redirect the jump itself and then continue
@@ -1033,8 +1377,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
         one and create separate abnormal edge to original destination.
         This allows bb-reorder to make such edge non-fallthru.  */
       gcc_assert (e->dest == target);
-      abnormal_edge_flags = e->flags & ~(EDGE_FALLTHRU | EDGE_CAN_FALLTHRU);
-      e->flags &= EDGE_FALLTHRU | EDGE_CAN_FALLTHRU;
+      abnormal_edge_flags = e->flags & ~EDGE_FALLTHRU;
+      e->flags &= EDGE_FALLTHRU;
     }
   else
     {
@@ -1072,8 +1416,28 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
        }
     }
 
-  if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags)
+  /* If e->src ends with asm goto, see if any of the ASM_OPERANDS_LABELs
+     don't point to the target or fallthru label.  */
+  if (JUMP_P (BB_END (e->src))
+      && target != EXIT_BLOCK_PTR
+      && (e->flags & EDGE_FALLTHRU)
+      && (note = extract_asm_operands (PATTERN (BB_END (e->src)))))
+    {
+      int i, n = ASM_OPERANDS_LABEL_LENGTH (note);
+
+      for (i = 0; i < n; ++i)
+       {
+         if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (e->dest))
+           XEXP (ASM_OPERANDS_LABEL (note, i), 0) = block_label (target);
+         if (XEXP (ASM_OPERANDS_LABEL (note, i), 0) == BB_HEAD (target))
+           asm_goto_edge = true;
+       }
+    }
+
+  if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
     {
+      gcov_type count = e->count;
+      int probability = e->probability;
       /* Create the new structures.  */
 
       /* If the old block ended with a tablejump, skip its table
@@ -1084,51 +1448,75 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
       note = NEXT_INSN (note);
 
       jump_block = create_basic_block (note, NULL, e->src);
-      jump_block->count = e->count;
+      jump_block->count = count;
       jump_block->frequency = EDGE_FREQUENCY (e);
-      jump_block->loop_depth = target->loop_depth;
 
       /* Make sure new block ends up in correct hot/cold section.  */
 
       BB_COPY_PARTITION (jump_block, e->src);
       if (flag_reorder_blocks_and_partition
-         && targetm.have_named_sections
+         && targetm_common.have_named_sections
          && JUMP_P (BB_END (jump_block))
          && !any_condjump_p (BB_END (jump_block))
          && (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING))
-       REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
-                                                            NULL_RTX,
-                                                            REG_NOTES
-                                                            (BB_END
-                                                             (jump_block)));
+       add_reg_note (BB_END (jump_block), REG_CROSSING_JUMP, NULL_RTX);
 
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
-      new_edge->probability = e->probability;
-      new_edge->count = e->count;
+      new_edge->probability = probability;
+      new_edge->count = count;
 
       /* Redirect old edge.  */
       redirect_edge_pred (e, jump_block);
       e->probability = REG_BR_PROB_BASE;
 
+      /* If asm goto has any label refs to target's label,
+        add also edge from asm goto bb to target.  */
+      if (asm_goto_edge)
+       {
+         new_edge->probability /= 2;
+         new_edge->count /= 2;
+         jump_block->count /= 2;
+         jump_block->frequency /= 2;
+         new_edge = make_edge (new_edge->src, target,
+                               e->flags & ~EDGE_FALLTHRU);
+         new_edge->probability = probability - probability / 2;
+         new_edge->count = count - count / 2;
+       }
+
       new_bb = jump_block;
     }
   else
     jump_block = e->src;
 
+  loc = e->goto_locus;
   e->flags &= ~EDGE_FALLTHRU;
   if (target == EXIT_BLOCK_PTR)
     {
+      if (jump_label == ret_rtx)
+       {
 #ifdef HAVE_return
-       emit_jump_insn_after_noloc (gen_return (), BB_END (jump_block));
+         emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc);
 #else
-       gcc_unreachable ();
+         gcc_unreachable ();
 #endif
+       }
+      else
+       {
+         gcc_assert (jump_label == simple_return_rtx);
+#ifdef HAVE_simple_return
+         emit_jump_insn_after_setloc (gen_simple_return (),
+                                      BB_END (jump_block), loc);
+#else
+         gcc_unreachable ();
+#endif
+       }
+      set_return_jump_label (BB_END (jump_block));
     }
   else
     {
       rtx label = block_label (target);
-      emit_jump_insn_after_noloc (gen_jump (label), BB_END (jump_block));
+      emit_jump_insn_after_setloc (gen_jump (label), BB_END (jump_block), loc);
       JUMP_LABEL (BB_END (jump_block)) = label;
       LABEL_NUSES (label)++;
     }
@@ -1139,7 +1527,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   if (abnormal_edge_flags)
     make_edge (src, target, abnormal_edge_flags);
 
-  df_mark_solutions_dirty (); 
+  df_mark_solutions_dirty ();
   return new_bb;
 }
 
@@ -1147,10 +1535,10 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
    (and possibly create new basic block) to make edge non-fallthru.
    Return newly created BB or NULL if none.  */
 
-basic_block
-force_nonfallthru (edge e)
+static basic_block
+rtl_force_nonfallthru (edge e)
 {
-  return force_nonfallthru_and_redirect (e, e->dest);
+  return force_nonfallthru_and_redirect (e, e->dest, NULL_RTX);
 }
 
 /* Redirect edge even at the expense of creating new jump insn or
@@ -1167,7 +1555,7 @@ rtl_redirect_edge_and_branch_force (edge e, basic_block target)
   /* In case the edge redirection failed, try to force it to be non-fallthru
      and redirect newly created simplejump.  */
   df_set_bb_dirty (e->src);
-  return force_nonfallthru_and_redirect (e, target);
+  return force_nonfallthru_and_redirect (e, target, NULL_RTX);
 }
 
 /* The given edge should potentially be a fallthru edge.  If that is in
@@ -1248,12 +1636,7 @@ rtl_split_edge (edge edge_in)
      Avoid existence of fallthru predecessors.  */
   if ((edge_in->flags & EDGE_FALLTHRU) == 0)
     {
-      edge e;
-      edge_iterator ei;
-
-      FOR_EACH_EDGE (e, ei, edge_in->dest->preds)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
+      edge e = find_fallthru_edge (edge_in->dest->preds);
 
       if (e)
        force_nonfallthru (e);
@@ -1266,8 +1649,8 @@ rtl_split_edge (edge edge_in)
     before = NULL_RTX;
 
   /* If this is a fall through edge to the exit block, the blocks might be
-     not adjacent, and the right place is the after the source.  */
-  if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR)
+     not adjacent, and the right place is after the source.  */
+  if ((edge_in->flags & EDGE_FALLTHRU) && edge_in->dest == EXIT_BLOCK_PTR)
     {
       before = NEXT_INSN (BB_END (edge_in->src));
       bb = create_basic_block (before, NULL, edge_in->src);
@@ -1290,10 +1673,25 @@ rtl_split_edge (edge edge_in)
       gcc_assert (redirected);
     }
   else
-    redirect_edge_succ (edge_in, bb);
-
-  return bb;
-}
+    {
+      if (edge_in->src != ENTRY_BLOCK_PTR)
+       {
+         /* For asm goto even splitting of fallthru edge might
+            need insn patching, as other labels might point to the
+            old label.  */
+         rtx last = BB_END (edge_in->src);
+         if (last
+             && JUMP_P (last)
+             && edge_in->dest != EXIT_BLOCK_PTR
+             && extract_asm_operands (PATTERN (last)) != NULL_RTX
+             && patch_jump_insn (last, before, bb))
+           df_set_bb_dirty (edge_in->src);
+       }
+      redirect_edge_succ (edge_in, bb);
+    }
+
+  return bb;
+}
 
 /* Queue instructions for insertion on an edge between two basic blocks.
    The new instructions and basic blocks (if any) will not appear in the
@@ -1319,98 +1717,80 @@ insert_insn_on_edge (rtx pattern, edge e)
 
 /* Update the CFG for the instructions queued on edge E.  */
 
-static void
+void
 commit_one_edge_insertion (edge e)
 {
   rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
-  basic_block bb = NULL;
+  basic_block bb;
 
   /* Pull the insns off the edge now since the edge might go away.  */
   insns = e->insns.r;
   e->insns.r = NULL_RTX;
 
-  if (!before && !after)
-    {
-      /* Figure out where to put these things.  If the destination has
-        one predecessor, insert there.  Except for the exit block.  */
-      if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
-       {
-         bb = e->dest;
-
-         /* Get the location correct wrt a code label, and "nice" wrt
-            a basic block note, and before everything else.  */
-         tmp = BB_HEAD (bb);
-         if (LABEL_P (tmp))
-           tmp = NEXT_INSN (tmp);
-         if (NOTE_INSN_BASIC_BLOCK_P (tmp))
-           tmp = NEXT_INSN (tmp);
-         if (tmp == BB_HEAD (bb))
-           before = tmp;
-         else if (tmp)
-           after = PREV_INSN (tmp);
-         else
-           after = get_last_insn ();
-       }
-
-      /* If the source has one successor and the edge is not abnormal,
-        insert there.  Except for the entry block.  */
-      else if ((e->flags & EDGE_ABNORMAL) == 0
-              && single_succ_p (e->src)
-              && e->src != ENTRY_BLOCK_PTR)
-       {
-         bb = e->src;
+  /* Figure out where to put these insns.  If the destination has
+     one predecessor, insert there.  Except for the exit block.  */
+  if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
+    {
+      bb = e->dest;
+
+      /* Get the location correct wrt a code label, and "nice" wrt
+        a basic block note, and before everything else.  */
+      tmp = BB_HEAD (bb);
+      if (LABEL_P (tmp))
+       tmp = NEXT_INSN (tmp);
+      if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+       tmp = NEXT_INSN (tmp);
+      if (tmp == BB_HEAD (bb))
+       before = tmp;
+      else if (tmp)
+       after = PREV_INSN (tmp);
+      else
+       after = get_last_insn ();
+    }
 
-         /* It is possible to have a non-simple jump here.  Consider a target
-            where some forms of unconditional jumps clobber a register.  This
-            happens on the fr30 for example.
+  /* If the source has one successor and the edge is not abnormal,
+     insert there.  Except for the entry block.  */
+  else if ((e->flags & EDGE_ABNORMAL) == 0
+          && single_succ_p (e->src)
+          && e->src != ENTRY_BLOCK_PTR)
+    {
+      bb = e->src;
 
-            We know this block has a single successor, so we can just emit
-            the queued insns before the jump.  */
-         if (JUMP_P (BB_END (bb)))
-           before = BB_END (bb);
-         else
-           {
-             /* We'd better be fallthru, or we've lost track of
-                what's what.  */
-             gcc_assert (e->flags & EDGE_FALLTHRU);
+      /* It is possible to have a non-simple jump here.  Consider a target
+        where some forms of unconditional jumps clobber a register.  This
+        happens on the fr30 for example.
 
-             after = BB_END (bb);
-           }
-       }
-      /* Otherwise we must split the edge.  */
+        We know this block has a single successor, so we can just emit
+        the queued insns before the jump.  */
+      if (JUMP_P (BB_END (bb)))
+       before = BB_END (bb);
       else
        {
-         bb = split_edge (e);
+         /* We'd better be fallthru, or we've lost track of what's what.  */
+         gcc_assert (e->flags & EDGE_FALLTHRU);
+
          after = BB_END (bb);
+       }
+    }
 
-         if (flag_reorder_blocks_and_partition
-             && targetm.have_named_sections
-             && e->src != ENTRY_BLOCK_PTR
-             && BB_PARTITION (e->src) == BB_COLD_PARTITION
-             && !(e->flags & EDGE_CROSSING))
-           {
-             rtx bb_note, cur_insn;
-
-             bb_note = NULL_RTX;
-             for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
-                  cur_insn = NEXT_INSN (cur_insn))
-               if (NOTE_INSN_BASIC_BLOCK_P (cur_insn))
-                 {
-                   bb_note = cur_insn;
-                   break;
-                 }
+  /* Otherwise we must split the edge.  */
+  else
+    {
+      bb = split_edge (e);
+      after = BB_END (bb);
 
-             if (JUMP_P (BB_END (bb))
-                 && !any_condjump_p (BB_END (bb))
-                 && (single_succ_edge (bb)->flags & EDGE_CROSSING))
-               REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
-                 (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
-           }
-       }
+      if (flag_reorder_blocks_and_partition
+         && targetm_common.have_named_sections
+         && e->src != ENTRY_BLOCK_PTR
+         && BB_PARTITION (e->src) == BB_COLD_PARTITION
+         && !(e->flags & EDGE_CROSSING)
+         && JUMP_P (after)
+         && !any_condjump_p (after)
+         && (single_succ_edge (bb)->flags & EDGE_CROSSING))
+       add_reg_note (after, REG_CROSSING_JUMP, NULL_RTX);
     }
 
   /* Now that we've found the spot, do the insertion.  */
-
   if (before)
     {
       emit_insn_before_noloc (insns, before, bb);
@@ -1438,10 +1818,6 @@ commit_one_edge_insertion (edge e)
     }
   else
     gcc_assert (!JUMP_P (last));
-
-  /* Mark the basic block for find_many_sub_basic_blocks.  */
-  if (current_ir_type () != IR_RTL_CFGLAYOUT)
-    bb->aux = &bb->aux;
 }
 
 /* Update the CFG for all queued instructions.  */
@@ -1450,8 +1826,6 @@ void
 commit_edge_insertions (void)
 {
   basic_block bb;
-  sbitmap blocks;
-  bool changed = false;
 
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
@@ -1464,43 +1838,17 @@ commit_edge_insertions (void)
 
       FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->insns.r)
-         {
-           changed = true;
-           commit_one_edge_insertion (e);
-         }
+         commit_one_edge_insertion (e);
     }
-
-  if (!changed)
-    return;
-
-  /* In the old rtl CFG API, it was OK to insert control flow on an
-     edge, apparently?  In cfglayout mode, this will *not* work, and
-     the caller is responsible for making sure that control flow is
-     valid at all times.  */
-  if (current_ir_type () == IR_RTL_CFGLAYOUT)
-    return;
-
-  blocks = sbitmap_alloc (last_basic_block);
-  sbitmap_zero (blocks);
-  FOR_EACH_BB (bb)
-    if (bb->aux)
-      {
-       SET_BIT (blocks, bb->index);
-       /* Check for forgotten bb->aux values before commit_edge_insertions
-          call.  */
-       gcc_assert (bb->aux == &bb->aux);
-       bb->aux = NULL;
-      }
-  find_many_sub_basic_blocks (blocks);
-  sbitmap_free (blocks);
 }
 \f
 
 /* Print out RTL-specific basic block information (live information
-   at start and end).  */
+   at start and end with TDF_DETAILS).  FLAGS are the TDF_* masks
+   documented in dumpfile.h.  */
 
 static void
-rtl_dump_bb (basic_block bb, FILE *outf, int indent)
+rtl_dump_bb (FILE *outf, basic_block bb, int indent, int flags)
 {
   rtx insn;
   rtx last;
@@ -1509,18 +1857,28 @@ rtl_dump_bb (basic_block bb, FILE *outf, int indent)
   s_indent = (char *) alloca ((size_t) indent + 1);
   memset (s_indent, ' ', (size_t) indent);
   s_indent[indent] = '\0';
-  
-  if (df)
+
+  if (df && (flags & TDF_DETAILS))
     {
       df_dump_top (bb, outf);
       putc ('\n', outf);
     }
 
-  for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
-       insn = NEXT_INSN (insn))
-    print_rtl_single (outf, insn);
+  if (bb->index != ENTRY_BLOCK && bb->index != EXIT_BLOCK)
+    for (insn = BB_HEAD (bb), last = NEXT_INSN (BB_END (bb)); insn != last;
+        insn = NEXT_INSN (insn))
+      {
+       if (flags & TDF_DETAILS)
+         df_dump_insn_top (insn, outf);
+       if (! (flags & TDF_SLIM))
+         print_rtl_single (outf, insn);
+       else
+         dump_insn_slim (outf, insn);
+       if (flags & TDF_DETAILS)
+         df_dump_insn_bottom (insn, outf);
+      }
 
-  if (df)
+  if (df && (flags & TDF_DETAILS))
     {
       df_dump_bottom (bb, outf);
       putc ('\n', outf);
@@ -1528,11 +1886,12 @@ rtl_dump_bb (basic_block bb, FILE *outf, int indent)
 
 }
 \f
-/* Like print_rtl, but also print out live information for the start of each
-   basic block.  */
+/* Like dump_function_to_file, but for RTL.  Print out dataflow information
+   for the start of each basic block.  FLAGS are the TDF_* masks documented
+   in dumpfile.h.  */
 
 void
-print_rtl_with_bb (FILE *outf, const_rtx rtx_first)
+print_rtl_with_bb (FILE *outf, const_rtx rtx_first, int flags)
 {
   const_rtx tmp_rtx;
   if (rtx_first == 0)
@@ -1544,91 +1903,79 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first)
       basic_block *start = XCNEWVEC (basic_block, max_uid);
       basic_block *end = XCNEWVEC (basic_block, max_uid);
       enum bb_state *in_bb_p = XCNEWVEC (enum bb_state, max_uid);
-
       basic_block bb;
 
+      /* After freeing the CFG, we still have BLOCK_FOR_INSN set on most
+        insns, but the CFG is not maintained so the basic block info
+        is not reliable.  Therefore it's omitted from the dumps.  */
+      if (! (cfun->curr_properties & PROP_cfg))
+        flags &= ~TDF_BLOCKS;
+
       if (df)
        df_dump_start (outf);
 
-      FOR_EACH_BB_REVERSE (bb)
+      if (flags & TDF_BLOCKS)
        {
-         rtx x;
-
-         start[INSN_UID (BB_HEAD (bb))] = bb;
-         end[INSN_UID (BB_END (bb))] = bb;
-         for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+         FOR_EACH_BB_REVERSE (bb)
            {
-             enum bb_state state = IN_MULTIPLE_BB;
+             rtx x;
+
+             start[INSN_UID (BB_HEAD (bb))] = bb;
+             end[INSN_UID (BB_END (bb))] = bb;
+             for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
+               {
+                 enum bb_state state = IN_MULTIPLE_BB;
 
-             if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
-               state = IN_ONE_BB;
-             in_bb_p[INSN_UID (x)] = state;
+                 if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
+                   state = IN_ONE_BB;
+                 in_bb_p[INSN_UID (x)] = state;
 
-             if (x == BB_END (bb))
-               break;
+                 if (x == BB_END (bb))
+                   break;
+               }
            }
        }
 
       for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
        {
-         int did_output;
-         if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
+         if (flags & TDF_BLOCKS)
            {
-             edge e;
-             edge_iterator ei;
-             
-             fprintf (outf, ";; Start of basic block (");
-             FOR_EACH_EDGE (e, ei, bb->preds)
-               fprintf (outf, " %d", e->src->index);
-             fprintf (outf, ") -> %d\n", bb->index);
-
-             if (df)
-               {
-                 df_dump_top (bb, outf);
-                 putc ('\n', outf);
-               }
-             FOR_EACH_EDGE (e, ei, bb->preds)
+             bb = start[INSN_UID (tmp_rtx)];
+             if (bb != NULL)
                {
-                 fputs (";; Pred edge ", outf);
-                 dump_edge_info (outf, e, 0);
-                 fputc ('\n', outf);
+                 dump_bb_info (outf, bb, 0, dump_flags | TDF_COMMENT, true, false);
+                 if (df && (flags & TDF_DETAILS))
+                   df_dump_top (bb, outf);
                }
-           }
 
-         if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
-             && !NOTE_P (tmp_rtx)
-             && !BARRIER_P (tmp_rtx))
-           fprintf (outf, ";; Insn is not within a basic block\n");
-         else if (in_bb_p[INSN_UID (tmp_rtx)] == IN_MULTIPLE_BB)
-           fprintf (outf, ";; Insn is in multiple basic blocks\n");
+             if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
+                 && !NOTE_P (tmp_rtx)
+                 && !BARRIER_P (tmp_rtx))
+               fprintf (outf, ";; Insn is not within a basic block\n");
+             else if (in_bb_p[INSN_UID (tmp_rtx)] == IN_MULTIPLE_BB)
+               fprintf (outf, ";; Insn is in multiple basic blocks\n");
+           }
 
-         did_output = print_rtl_single (outf, tmp_rtx);
+         if (flags & TDF_DETAILS)
+           df_dump_insn_top (tmp_rtx, outf);
+         if (! (flags & TDF_SLIM))
+           print_rtl_single (outf, tmp_rtx);
+         else
+           dump_insn_slim (outf, tmp_rtx);
+         if (flags & TDF_DETAILS)
+           df_dump_insn_bottom (tmp_rtx, outf);
 
-         if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
+         if (flags & TDF_BLOCKS)
            {
-             edge e;
-             edge_iterator ei;
-
-             fprintf (outf, ";; End of basic block %d -> (", bb->index);
-             FOR_EACH_EDGE (e, ei, bb->succs)
-               fprintf (outf, " %d", e->dest->index);
-             fprintf (outf, ")\n");
-
-             if (df)
+             bb = end[INSN_UID (tmp_rtx)];
+             if (bb != NULL)
                {
-                 df_dump_bottom (bb, outf);
+                 dump_bb_info (outf, bb, 0, dump_flags | TDF_COMMENT, false, true);
+                 if (df && (flags & TDF_DETAILS))
+                   df_dump_bottom (bb, outf);
                  putc ('\n', outf);
                }
-             putc ('\n', outf);
-             FOR_EACH_EDGE (e, ei, bb->succs)
-               {
-                 fputs (";; Succ edge ", outf);
-                 dump_edge_info (outf, e, 1);
-                 fputc ('\n', outf);
-               }
            }
-         if (did_output)
-           putc ('\n', outf);
        }
 
       free (start);
@@ -1636,15 +1983,17 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first)
       free (in_bb_p);
     }
 
-  if (current_function_epilogue_delay_list != 0)
+  if (crtl->epilogue_delay_list != 0)
     {
       fprintf (outf, "\n;; Insns in epilogue delay list:\n\n");
-      for (tmp_rtx = current_function_epilogue_delay_list; tmp_rtx != 0;
+      for (tmp_rtx = crtl->epilogue_delay_list; tmp_rtx != 0;
           tmp_rtx = XEXP (tmp_rtx, 1))
        print_rtl_single (outf, XEXP (tmp_rtx, 0));
     }
 }
 \f
+/* Update the branch probability of BB if a REG_BR_PROB is present.  */
+
 void
 update_br_prob_note (basic_block bb)
 {
@@ -1670,11 +2019,11 @@ get_last_bb_insn (basic_block bb)
     end = tmp;
 
   /* Include any barriers that may follow the basic block.  */
-  tmp = next_nonnote_insn (end);
+  tmp = next_nonnote_insn_bb (end);
   while (tmp && BARRIER_P (tmp))
     {
       end = tmp;
-      tmp = next_nonnote_insn (end);
+      tmp = next_nonnote_insn_bb (end);
     }
 
   return end;
@@ -1725,7 +2074,7 @@ rtl_verify_flow_info_1 (void)
            err = 1;
          }
 
-      for (insn = bb->il.rtl->header; insn; insn = NEXT_INSN (insn))
+      for (insn = BB_HEADER (bb); insn; insn = NEXT_INSN (insn))
        if (!BARRIER_P (insn)
            && BLOCK_FOR_INSN (insn) != NULL)
          {
@@ -1733,7 +2082,7 @@ rtl_verify_flow_info_1 (void)
                   INSN_UID (insn), bb->index);
            err = 1;
          }
-      for (insn = bb->il.rtl->footer; insn; insn = NEXT_INSN (insn))
+      for (insn = BB_FOOTER (bb); insn; insn = NEXT_INSN (insn))
        if (!BARRIER_P (insn)
            && BLOCK_FOR_INSN (insn) != NULL)
          {
@@ -1766,25 +2115,46 @@ rtl_verify_flow_info_1 (void)
        }
       FOR_EACH_EDGE (e, ei, bb->succs)
        {
+         bool is_crossing;
+
          if (e->flags & EDGE_FALLTHRU)
+           n_fallthru++, fallthru = e;
+
+         is_crossing = (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
+                        && e->src != ENTRY_BLOCK_PTR
+                        && e->dest != EXIT_BLOCK_PTR);
+         if (e->flags & EDGE_CROSSING)
            {
-             n_fallthru++, fallthru = e;
-             if ((e->flags & EDGE_CROSSING)
-                 || (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
-                     && e->src != ENTRY_BLOCK_PTR
-                     && e->dest != EXIT_BLOCK_PTR))
-           {
+             if (!is_crossing)
+               {
+                 error ("EDGE_CROSSING incorrectly set across same section");
+                 err = 1;
+               }
+             if (e->flags & EDGE_FALLTHRU)
+               {
                  error ("fallthru edge crosses section boundary (bb %i)",
                         e->src->index);
                  err = 1;
                }
+             if (e->flags & EDGE_EH)
+               {
+                 error ("EH edge crosses section boundary (bb %i)",
+                        e->src->index);
+                 err = 1;
+               }
+           }
+         else if (is_crossing)
+           {
+             error ("EDGE_CROSSING missing across section boundary");
+             err = 1;
            }
 
          if ((e->flags & ~(EDGE_DFS_BACK
                            | EDGE_CAN_FALLTHRU
                            | EDGE_IRREDUCIBLE_LOOP
                            | EDGE_LOOP_EXIT
-                           | EDGE_CROSSING)) == 0)
+                           | EDGE_CROSSING
+                           | EDGE_PRESERVE)) == 0)
            n_branch++;
 
          if (e->flags & EDGE_ABNORMAL_CALL)
@@ -1796,12 +2166,16 @@ rtl_verify_flow_info_1 (void)
            n_abnormal++;
        }
 
-      if (n_eh && GET_CODE (PATTERN (BB_END (bb))) != RESX
-         && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
+      if (n_eh && !find_reg_note (BB_END (bb), REG_EH_REGION, NULL_RTX))
        {
          error ("missing REG_EH_REGION note in the end of bb %i", bb->index);
          err = 1;
        }
+      if (n_eh > 1)
+       {
+         error ("too many eh edges %i", bb->index);
+         err = 1;
+       }
       if (n_branch
          && (!JUMP_P (BB_END (bb))
              || (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
@@ -1817,7 +2191,8 @@ rtl_verify_flow_info_1 (void)
        }
       if (n_branch != 1 && any_uncondjump_p (BB_END (bb)))
        {
-         error ("wrong amount of branch edges after unconditional jump %i", bb->index);
+         error ("wrong number of branch edges after unconditional jump %i",
+                bb->index);
          err = 1;
        }
       if (n_branch != 1 && any_condjump_p (BB_END (bb))
@@ -1940,7 +2315,6 @@ rtl_verify_flow_info (void)
   FOR_EACH_BB_REVERSE (bb)
     {
       edge e;
-      edge_iterator ei;
       rtx head = BB_HEAD (bb);
       rtx end = BB_END (bb);
 
@@ -1994,23 +2368,23 @@ rtl_verify_flow_info (void)
 
       last_head = PREV_INSN (x);
 
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
+      e = find_fallthru_edge (bb->succs);
       if (!e)
        {
          rtx insn;
 
          /* Ensure existence of barrier in BB with no fallthru edges.  */
-         for (insn = BB_END (bb); !insn || !BARRIER_P (insn);
-              insn = NEXT_INSN (insn))
-           if (!insn
-               || NOTE_INSN_BASIC_BLOCK_P (insn))
+         for (insn = NEXT_INSN (BB_END (bb)); ; insn = NEXT_INSN (insn))
+           {
+             if (!insn || NOTE_INSN_BASIC_BLOCK_P (insn))
                {
                  error ("missing barrier after block %i", bb->index);
                  err = 1;
                  break;
                }
+             if (BARRIER_P (insn))
+               break;
+           }
        }
       else if (e->src != ENTRY_BLOCK_PTR
               && e->dest != EXIT_BLOCK_PTR)
@@ -2078,9 +2452,7 @@ rtl_verify_flow_info (void)
            case CODE_LABEL:
              /* An addr_vec is placed outside any basic block.  */
              if (NEXT_INSN (x)
-                 && JUMP_P (NEXT_INSN (x))
-                 && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
-                     || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
+                 && JUMP_TABLE_DATA_P (NEXT_INSN (x)))
                x = NEXT_INSN (x);
 
              /* But in any case, non-deletable labels can appear anywhere.  */
@@ -2120,6 +2492,11 @@ purge_dead_edges (basic_block bb)
   bool found;
   edge_iterator ei;
 
+  if (DEBUG_INSN_P (insn) && insn != BB_HEAD (bb))
+    do
+      insn = PREV_INSN (insn);
+    while ((DEBUG_INSN_P (insn) || NOTE_P (insn)) && insn != BB_HEAD (bb));
+
   /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
   if (NONJUMP_INSN_P (insn)
       && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
@@ -2135,39 +2512,35 @@ purge_dead_edges (basic_block bb)
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
   for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
+      bool remove = false;
+
       /* There are three types of edges we need to handle correctly here: EH
         edges, abnormal call EH edges, and abnormal call non-EH edges.  The
         latter can appear when nonlocal gotos are used.  */
-      if (e->flags & EDGE_EH)
+      if (e->flags & EDGE_ABNORMAL_CALL)
        {
-         if (can_throw_internal (BB_END (bb))
-             /* If this is a call edge, verify that this is a call insn.  */
-             && (! (e->flags & EDGE_ABNORMAL_CALL)
-                 || CALL_P (BB_END (bb))))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         if (!CALL_P (insn))
+           remove = true;
+         else if (can_nonlocal_goto (insn))
+           ;
+         else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
+           ;
+         else if (flag_tm && find_reg_note (insn, REG_TM, NULL))
+           ;
+         else
+           remove = true;
        }
-      else if (e->flags & EDGE_ABNORMAL_CALL)
+      else if (e->flags & EDGE_EH)
+       remove = !can_throw_internal (insn);
+
+      if (remove)
        {
-         if (CALL_P (BB_END (bb))
-             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
-                 || INTVAL (XEXP (note, 0)) >= 0))
-           {
-             ei_next (&ei);
-             continue;
-           }
+         remove_edge (e);
+         df_set_bb_dirty (bb);
+         purged = true;
        }
       else
-       {
-         ei_next (&ei);
-         continue;
-       }
-
-      remove_edge (e);
-      df_set_bb_dirty (bb);
-      purged = true;
+       ei_next (&ei);
     }
 
   if (JUMP_P (insn))
@@ -2344,138 +2717,1197 @@ purge_all_dead_edges (void)
   return purged;
 }
 
-/* Same as split_block but update cfg_layout structures.  */
+/* This is used by a few passes that emit some instructions after abnormal
+   calls, moving the basic block's end, while they in fact do want to emit
+   them on the fallthru edge.  Look for abnormal call edges, find backward
+   the call in the block and insert the instructions on the edge instead.
 
-static basic_block
-cfg_layout_split_block (basic_block bb, void *insnp)
+   Similarly, handle instructions throwing exceptions internally.
+
+   Return true when instructions have been found and inserted on edges.  */
+
+bool
+fixup_abnormal_edges (void)
 {
-  rtx insn = (rtx) insnp;
-  basic_block new_bb = rtl_split_block (bb, insn);
+  bool inserted = false;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      edge e;
+      edge_iterator ei;
 
-  new_bb->il.rtl->footer = bb->il.rtl->footer;
-  bb->il.rtl->footer = NULL;
+      /* Look for cases we are interested in - calls or instructions causing
+         exceptions.  */
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if ((e->flags & EDGE_ABNORMAL_CALL)
+           || ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
+               == (EDGE_ABNORMAL | EDGE_EH)))
+         break;
 
-  return new_bb;
-}
+      if (e && !CALL_P (BB_END (bb)) && !can_throw_internal (BB_END (bb)))
+       {
+         rtx insn;
 
-/* Redirect Edge to DEST.  */
-static edge
-cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
-{
-  basic_block src = e->src;
-  edge ret;
+         /* Get past the new insns generated.  Allow notes, as the insns
+            may be already deleted.  */
+         insn = BB_END (bb);
+         while ((NONJUMP_INSN_P (insn) || NOTE_P (insn))
+                && !can_throw_internal (insn)
+                && insn != BB_HEAD (bb))
+           insn = PREV_INSN (insn);
 
-  if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
-    return NULL;
+         if (CALL_P (insn) || can_throw_internal (insn))
+           {
+             rtx stop, next;
 
-  if (e->dest == dest)
-    return e;
+             e = find_fallthru_edge (bb->succs);
 
-  if (e->src != ENTRY_BLOCK_PTR
-      && (ret = try_redirect_by_replacing_jump (e, dest, true)))
-    {
-      df_set_bb_dirty (src);
-      return ret;
-    }
+             stop = NEXT_INSN (BB_END (bb));
+             BB_END (bb) = insn;
 
-  if (e->src == ENTRY_BLOCK_PTR
-      && (e->flags & EDGE_FALLTHRU) && !(e->flags & EDGE_COMPLEX))
-    {
-      if (dump_file)
-       fprintf (dump_file, "Redirecting entry edge from bb %i to %i\n",
-                e->src->index, dest->index);
+             for (insn = NEXT_INSN (insn); insn != stop; insn = next)
+               {
+                 next = NEXT_INSN (insn);
+                 if (INSN_P (insn))
+                   {
+                     delete_insn (insn);
+
+                     /* Sometimes there's still the return value USE.
+                        If it's placed after a trapping call (i.e. that
+                        call is the last insn anyway), we have no fallthru
+                        edge.  Simply delete this use and don't try to insert
+                        on the non-existent edge.  */
+                     if (GET_CODE (PATTERN (insn)) != USE)
+                       {
+                         /* We're not deleting it, we're moving it.  */
+                         INSN_DELETED_P (insn) = 0;
+                         PREV_INSN (insn) = NULL_RTX;
+                         NEXT_INSN (insn) = NULL_RTX;
+
+                         insert_insn_on_edge (insn, e);
+                         inserted = true;
+                       }
+                   }
+                 else if (!BARRIER_P (insn))
+                   set_block_for_insn (insn, NULL);
+               }
+           }
 
-      df_set_bb_dirty (e->src);
-      redirect_edge_succ (e, dest);
-      return e;
+         /* It may be that we don't find any trapping insn.  In this
+            case we discovered quite late that the insn that had been
+            marked as can_throw_internal in fact couldn't trap at all.
+            So we should in fact delete the EH edges out of the block.  */
+         else
+           purge_dead_edges (bb);
+       }
     }
 
-  /* Redirect_edge_and_branch may decide to turn branch into fallthru edge
-     in the case the basic block appears to be in sequence.  Avoid this
-     transformation.  */
+  return inserted;
+}
+\f
+/* Cut the insns from FIRST to LAST out of the insns stream.  */
 
-  if (e->flags & EDGE_FALLTHRU)
+rtx
+unlink_insn_chain (rtx first, rtx last)
+{
+  rtx prevfirst = PREV_INSN (first);
+  rtx nextlast = NEXT_INSN (last);
+
+  PREV_INSN (first) = NULL;
+  NEXT_INSN (last) = NULL;
+  if (prevfirst)
+    NEXT_INSN (prevfirst) = nextlast;
+  if (nextlast)
+    PREV_INSN (nextlast) = prevfirst;
+  else
+    set_last_insn (prevfirst);
+  if (!prevfirst)
+    set_first_insn (nextlast);
+  return first;
+}
+\f
+/* Skip over inter-block insns occurring after BB which are typically
+   associated with BB (e.g., barriers). If there are any such insns,
+   we return the last one. Otherwise, we return the end of BB.  */
+
+static rtx
+skip_insns_after_block (basic_block bb)
+{
+  rtx insn, last_insn, next_head, prev;
+
+  next_head = NULL_RTX;
+  if (bb->next_bb != EXIT_BLOCK_PTR)
+    next_head = BB_HEAD (bb->next_bb);
+
+  for (last_insn = insn = BB_END (bb); (insn = NEXT_INSN (insn)) != 0; )
     {
-      /* Redirect any branch edges unified with the fallthru one.  */
-      if (JUMP_P (BB_END (src))
-         && label_is_jump_target_p (BB_HEAD (e->dest),
-                                    BB_END (src)))
-       {
-         edge redirected;
+      if (insn == next_head)
+       break;
 
-         if (dump_file)
-           fprintf (dump_file, "Fallthru edge unified with branch "
-                    "%i->%i redirected to %i\n",
-                    e->src->index, e->dest->index, dest->index);
-         e->flags &= ~EDGE_FALLTHRU;
-         redirected = redirect_branch_edge (e, dest);
-         gcc_assert (redirected);
-         e->flags |= EDGE_FALLTHRU;
-         df_set_bb_dirty (e->src);
-         return e;
-       }
-      /* In case we are redirecting fallthru edge to the branch edge
-        of conditional jump, remove it.  */
-      if (EDGE_COUNT (src->succs) == 2)
+      switch (GET_CODE (insn))
        {
-         /* Find the edge that is different from E.  */
-         edge s = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e);
+       case BARRIER:
+         last_insn = insn;
+         continue;
 
-         if (s->dest == dest
-             && any_condjump_p (BB_END (src))
-             && onlyjump_p (BB_END (src)))
-           delete_insn (BB_END (src));
+       case NOTE:
+         switch (NOTE_KIND (insn))
+           {
+           case NOTE_INSN_BLOCK_END:
+             gcc_unreachable ();
+             continue;
+           default:
+             continue;
+             break;
+           }
+         break;
+
+       case CODE_LABEL:
+         if (NEXT_INSN (insn)
+             && JUMP_TABLE_DATA_P (NEXT_INSN (insn)))
+           {
+             insn = NEXT_INSN (insn);
+             last_insn = insn;
+             continue;
+           }
+         break;
+
+       default:
+         break;
        }
-      ret = redirect_edge_succ_nodup (e, dest);
-      if (dump_file)
-       fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n",
-                e->src->index, e->dest->index, dest->index);
+
+      break;
     }
-  else
-    ret = redirect_branch_edge (e, dest);
 
-  /* We don't want simplejumps in the insn stream during cfglayout.  */
-  gcc_assert (!simplejump_p (BB_END (src)));
+  /* It is possible to hit contradictory sequence.  For instance:
 
-  df_set_bb_dirty (src);
-  return ret;
-}
+     jump_insn
+     NOTE_INSN_BLOCK_BEG
+     barrier
 
-/* Simple wrapper as we always can redirect fallthru edges.  */
-static basic_block
-cfg_layout_redirect_edge_and_branch_force (edge e, basic_block dest)
-{
-  edge redirected = cfg_layout_redirect_edge_and_branch (e, dest);
+     Where barrier belongs to jump_insn, but the note does not.  This can be
+     created by removing the basic block originally following
+     NOTE_INSN_BLOCK_BEG.  In such case reorder the notes.  */
 
-  gcc_assert (redirected);
-  return NULL;
+  for (insn = last_insn; insn != BB_END (bb); insn = prev)
+    {
+      prev = PREV_INSN (insn);
+      if (NOTE_P (insn))
+       switch (NOTE_KIND (insn))
+         {
+         case NOTE_INSN_BLOCK_END:
+           gcc_unreachable ();
+           break;
+         case NOTE_INSN_DELETED:
+         case NOTE_INSN_DELETED_LABEL:
+         case NOTE_INSN_DELETED_DEBUG_LABEL:
+           continue;
+         default:
+           reorder_insns (insn, insn, last_insn);
+         }
+    }
+
+  return last_insn;
 }
 
-/* Same as delete_basic_block but update cfg_layout structures.  */
+/* Locate or create a label for a given basic block.  */
 
-static void
-cfg_layout_delete_block (basic_block bb)
+static rtx
+label_for_bb (basic_block bb)
 {
-  rtx insn, next, prev = PREV_INSN (BB_HEAD (bb)), *to, remaints;
+  rtx label = BB_HEAD (bb);
 
-  if (bb->il.rtl->header)
+  if (!LABEL_P (label))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Emitting label for block %d\n", bb->index);
+
+      label = block_label (bb);
+    }
+
+  return label;
+}
+
+/* Locate the effective beginning and end of the insn chain for each
+   block, as defined by skip_insns_after_block above.  */
+
+static void
+record_effective_endpoints (void)
+{
+  rtx next_insn;
+  basic_block bb;
+  rtx insn;
+
+  for (insn = get_insns ();
+       insn
+       && NOTE_P (insn)
+       && NOTE_KIND (insn) != NOTE_INSN_BASIC_BLOCK;
+       insn = NEXT_INSN (insn))
+    continue;
+  /* No basic blocks at all?  */
+  gcc_assert (insn);
+
+  if (PREV_INSN (insn))
+    cfg_layout_function_header =
+           unlink_insn_chain (get_insns (), PREV_INSN (insn));
+  else
+    cfg_layout_function_header = NULL_RTX;
+
+  next_insn = get_insns ();
+  FOR_EACH_BB (bb)
+    {
+      rtx end;
+
+      if (PREV_INSN (BB_HEAD (bb)) && next_insn != BB_HEAD (bb))
+       BB_HEADER (bb) = unlink_insn_chain (next_insn,
+                                             PREV_INSN (BB_HEAD (bb)));
+      end = skip_insns_after_block (bb);
+      if (NEXT_INSN (BB_END (bb)) && BB_END (bb) != end)
+       BB_FOOTER (bb) = unlink_insn_chain (NEXT_INSN (BB_END (bb)), end);
+      next_insn = NEXT_INSN (BB_END (bb));
+    }
+
+  cfg_layout_function_footer = next_insn;
+  if (cfg_layout_function_footer)
+    cfg_layout_function_footer = unlink_insn_chain (cfg_layout_function_footer, get_last_insn ());
+}
+\f
+static unsigned int
+into_cfg_layout_mode (void)
+{
+  cfg_layout_initialize (0);
+  return 0;
+}
+
+static unsigned int
+outof_cfg_layout_mode (void)
+{
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    if (bb->next_bb != EXIT_BLOCK_PTR)
+      bb->aux = bb->next_bb;
+
+  cfg_layout_finalize ();
+
+  return 0;
+}
+
+struct rtl_opt_pass pass_into_cfg_layout_mode =
+{
+ {
+  RTL_PASS,
+  "into_cfglayout",                     /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
+  NULL,                                 /* gate */
+  into_cfg_layout_mode,                 /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_CFG,                               /* tv_id */
+  0,                                    /* properties_required */
+  PROP_cfglayout,                       /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0                                     /* todo_flags_finish */
+ }
+};
+
+struct rtl_opt_pass pass_outof_cfg_layout_mode =
+{
+ {
+  RTL_PASS,
+  "outof_cfglayout",                    /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
+  NULL,                                 /* gate */
+  outof_cfg_layout_mode,                /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_CFG,                               /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  PROP_cfglayout,                       /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0                                     /* todo_flags_finish */
+ }
+};
+\f
+
+/* Link the basic blocks in the correct order, compacting the basic
+   block queue while at it.  If STAY_IN_CFGLAYOUT_MODE is false, this
+   function also clears the basic block header and footer fields.
+
+   This function is usually called after a pass (e.g. tracer) finishes
+   some transformations while in cfglayout mode.  The required sequence
+   of the basic blocks is in a linked list along the bb->aux field.
+   This functions re-links the basic block prev_bb and next_bb pointers
+   accordingly, and it compacts and renumbers the blocks.
+
+   FIXME: This currently works only for RTL, but the only RTL-specific
+   bits are the STAY_IN_CFGLAYOUT_MODE bits.  The tracer pass was moved
+   to GIMPLE a long time ago, but it doesn't relink the basic block
+   chain.  It could do that (to give better initial RTL) if this function
+   is made IR-agnostic (and moved to cfganal.c or cfg.c while at it).  */
+
+void
+relink_block_chain (bool stay_in_cfglayout_mode)
+{
+  basic_block bb, prev_bb;
+  int index;
+
+  /* Maybe dump the re-ordered sequence.  */
+  if (dump_file)
+    {
+      fprintf (dump_file, "Reordered sequence:\n");
+      for (bb = ENTRY_BLOCK_PTR->next_bb, index = NUM_FIXED_BLOCKS;
+          bb;
+          bb = (basic_block) bb->aux, index++)
+       {
+         fprintf (dump_file, " %i ", index);
+         if (get_bb_original (bb))
+           fprintf (dump_file, "duplicate of %i ",
+                    get_bb_original (bb)->index);
+         else if (forwarder_block_p (bb)
+                  && !LABEL_P (BB_HEAD (bb)))
+           fprintf (dump_file, "compensation ");
+         else
+           fprintf (dump_file, "bb %i ", bb->index);
+         fprintf (dump_file, " [%i]\n", bb->frequency);
+       }
+    }
+
+  /* Now reorder the blocks.  */
+  prev_bb = ENTRY_BLOCK_PTR;
+  bb = ENTRY_BLOCK_PTR->next_bb;
+  for (; bb; prev_bb = bb, bb = (basic_block) bb->aux)
+    {
+      bb->prev_bb = prev_bb;
+      prev_bb->next_bb = bb;
+    }
+  prev_bb->next_bb = EXIT_BLOCK_PTR;
+  EXIT_BLOCK_PTR->prev_bb = prev_bb;
+
+  /* Then, clean up the aux fields.  */
+  FOR_ALL_BB (bb)
+    {
+      bb->aux = NULL;
+      if (!stay_in_cfglayout_mode)
+       BB_HEADER (bb) = BB_FOOTER (bb) = NULL;
+    }
+
+  /* Maybe reset the original copy tables, they are not valid anymore
+     when we renumber the basic blocks in compact_blocks.  If we are
+     are going out of cfglayout mode, don't re-allocate the tables.  */
+  free_original_copy_tables ();
+  if (stay_in_cfglayout_mode)
+    initialize_original_copy_tables ();
+
+  /* Finally, put basic_block_info in the new order.  */
+  compact_blocks ();
+}
+\f
+
+/* Given a reorder chain, rearrange the code to match.  */
+
+static void
+fixup_reorder_chain (void)
+{
+  basic_block bb;
+  rtx insn = NULL;
+
+  if (cfg_layout_function_header)
+    {
+      set_first_insn (cfg_layout_function_header);
+      insn = cfg_layout_function_header;
+      while (NEXT_INSN (insn))
+       insn = NEXT_INSN (insn);
+    }
+
+  /* First do the bulk reordering -- rechain the blocks without regard to
+     the needed changes to jumps and labels.  */
+
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = (basic_block) bb->aux)
+    {
+      if (BB_HEADER (bb))
+       {
+         if (insn)
+           NEXT_INSN (insn) = BB_HEADER (bb);
+         else
+           set_first_insn (BB_HEADER (bb));
+         PREV_INSN (BB_HEADER (bb)) = insn;
+         insn = BB_HEADER (bb);
+         while (NEXT_INSN (insn))
+           insn = NEXT_INSN (insn);
+       }
+      if (insn)
+       NEXT_INSN (insn) = BB_HEAD (bb);
+      else
+       set_first_insn (BB_HEAD (bb));
+      PREV_INSN (BB_HEAD (bb)) = insn;
+      insn = BB_END (bb);
+      if (BB_FOOTER (bb))
+       {
+         NEXT_INSN (insn) = BB_FOOTER (bb);
+         PREV_INSN (BB_FOOTER (bb)) = insn;
+         while (NEXT_INSN (insn))
+           insn = NEXT_INSN (insn);
+       }
+    }
+
+  NEXT_INSN (insn) = cfg_layout_function_footer;
+  if (cfg_layout_function_footer)
+    PREV_INSN (cfg_layout_function_footer) = insn;
+
+  while (NEXT_INSN (insn))
+    insn = NEXT_INSN (insn);
+
+  set_last_insn (insn);
+#ifdef ENABLE_CHECKING
+  verify_insn_chain ();
+#endif
+
+  /* Now add jumps and labels as needed to match the blocks new
+     outgoing edges.  */
+
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = (basic_block) bb->aux)
+    {
+      edge e_fall, e_taken, e;
+      rtx bb_end_insn;
+      rtx ret_label = NULL_RTX;
+      basic_block nb, src_bb;
+      edge_iterator ei;
+
+      if (EDGE_COUNT (bb->succs) == 0)
+       continue;
+
+      /* Find the old fallthru edge, and another non-EH edge for
+        a taken jump.  */
+      e_taken = e_fall = NULL;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (e->flags & EDGE_FALLTHRU)
+         e_fall = e;
+       else if (! (e->flags & EDGE_EH))
+         e_taken = e;
+
+      bb_end_insn = BB_END (bb);
+      if (JUMP_P (bb_end_insn))
+       {
+         ret_label = JUMP_LABEL (bb_end_insn);
+         if (any_condjump_p (bb_end_insn))
+           {
+             /* This might happen if the conditional jump has side
+                effects and could therefore not be optimized away.
+                Make the basic block to end with a barrier in order
+                to prevent rtl_verify_flow_info from complaining.  */
+             if (!e_fall)
+               {
+                 gcc_assert (!onlyjump_p (bb_end_insn)
+                             || returnjump_p (bb_end_insn));
+                 BB_FOOTER (bb) = emit_barrier_after (bb_end_insn);
+                 continue;
+               }
+
+             /* If the old fallthru is still next, nothing to do.  */
+             if (bb->aux == e_fall->dest
+                 || e_fall->dest == EXIT_BLOCK_PTR)
+               continue;
+
+             /* The degenerated case of conditional jump jumping to the next
+                instruction can happen for jumps with side effects.  We need
+                to construct a forwarder block and this will be done just
+                fine by force_nonfallthru below.  */
+             if (!e_taken)
+               ;
+
+             /* There is another special case: if *neither* block is next,
+                such as happens at the very end of a function, then we'll
+                need to add a new unconditional jump.  Choose the taken
+                edge based on known or assumed probability.  */
+             else if (bb->aux != e_taken->dest)
+               {
+                 rtx note = find_reg_note (bb_end_insn, REG_BR_PROB, 0);
+
+                 if (note
+                     && INTVAL (XEXP (note, 0)) < REG_BR_PROB_BASE / 2
+                     && invert_jump (bb_end_insn,
+                                     (e_fall->dest == EXIT_BLOCK_PTR
+                                      ? NULL_RTX
+                                      : label_for_bb (e_fall->dest)), 0))
+                   {
+                     e_fall->flags &= ~EDGE_FALLTHRU;
+                     gcc_checking_assert (could_fall_through
+                                          (e_taken->src, e_taken->dest));
+                     e_taken->flags |= EDGE_FALLTHRU;
+                     update_br_prob_note (bb);
+                     e = e_fall, e_fall = e_taken, e_taken = e;
+                   }
+               }
+
+             /* If the "jumping" edge is a crossing edge, and the fall
+                through edge is non-crossing, leave things as they are.  */
+             else if ((e_taken->flags & EDGE_CROSSING)
+                      && !(e_fall->flags & EDGE_CROSSING))
+               continue;
+
+             /* Otherwise we can try to invert the jump.  This will
+                basically never fail, however, keep up the pretense.  */
+             else if (invert_jump (bb_end_insn,
+                                   (e_fall->dest == EXIT_BLOCK_PTR
+                                    ? NULL_RTX
+                                    : label_for_bb (e_fall->dest)), 0))
+               {
+                 e_fall->flags &= ~EDGE_FALLTHRU;
+                 gcc_checking_assert (could_fall_through
+                                      (e_taken->src, e_taken->dest));
+                 e_taken->flags |= EDGE_FALLTHRU;
+                 update_br_prob_note (bb);
+                 if (LABEL_NUSES (ret_label) == 0
+                     && single_pred_p (e_taken->dest))
+                   delete_insn (ret_label);
+                 continue;
+               }
+           }
+         else if (extract_asm_operands (PATTERN (bb_end_insn)) != NULL)
+           {
+             /* If the old fallthru is still next or if
+                asm goto doesn't have a fallthru (e.g. when followed by
+                __builtin_unreachable ()), nothing to do.  */
+             if (! e_fall
+                 || bb->aux == e_fall->dest
+                 || e_fall->dest == EXIT_BLOCK_PTR)
+               continue;
+
+             /* Otherwise we'll have to use the fallthru fixup below.  */
+           }
+         else
+           {
+             /* Otherwise we have some return, switch or computed
+                jump.  In the 99% case, there should not have been a
+                fallthru edge.  */
+             gcc_assert (returnjump_p (bb_end_insn) || !e_fall);
+             continue;
+           }
+       }
+      else
+       {
+         /* No fallthru implies a noreturn function with EH edges, or
+            something similarly bizarre.  In any case, we don't need to
+            do anything.  */
+         if (! e_fall)
+           continue;
+
+         /* If the fallthru block is still next, nothing to do.  */
+         if (bb->aux == e_fall->dest)
+           continue;
+
+         /* A fallthru to exit block.  */
+         if (e_fall->dest == EXIT_BLOCK_PTR)
+           continue;
+       }
+
+      /* We got here if we need to add a new jump insn. 
+        Note force_nonfallthru can delete E_FALL and thus we have to
+        save E_FALL->src prior to the call to force_nonfallthru.  */
+      src_bb = e_fall->src;
+      nb = force_nonfallthru_and_redirect (e_fall, e_fall->dest, ret_label);
+      if (nb)
+       {
+         nb->aux = bb->aux;
+         bb->aux = nb;
+         /* Don't process this new block.  */
+         bb = nb;
+
+         /* Make sure new bb is tagged for correct section (same as
+            fall-thru source, since you cannot fall-thru across
+            section boundaries).  */
+         BB_COPY_PARTITION (src_bb, single_pred (bb));
+         if (flag_reorder_blocks_and_partition
+             && targetm_common.have_named_sections
+             && JUMP_P (BB_END (bb))
+             && !any_condjump_p (BB_END (bb))
+             && (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING))
+           add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX);
+       }
+    }
+
+  relink_block_chain (/*stay_in_cfglayout_mode=*/false);
+
+  /* Annoying special case - jump around dead jumptables left in the code.  */
+  FOR_EACH_BB (bb)
+    {
+      edge e = find_fallthru_edge (bb->succs);
+
+      if (e && !can_fallthru (e->src, e->dest))
+       force_nonfallthru (e);
+    }
+
+  /* Ensure goto_locus from edges has some instructions with that locus
+     in RTL.  */
+  if (!optimize)
+    FOR_EACH_BB (bb)
+      {
+        edge e;
+        edge_iterator ei;
+
+        FOR_EACH_EDGE (e, ei, bb->succs)
+         if (LOCATION_LOCUS (e->goto_locus) != UNKNOWN_LOCATION
+             && !(e->flags & EDGE_ABNORMAL))
+           {
+             edge e2;
+             edge_iterator ei2;
+             basic_block dest, nb;
+             rtx end;
+
+             insn = BB_END (e->src);
+             end = PREV_INSN (BB_HEAD (e->src));
+             while (insn != end
+                    && (!NONDEBUG_INSN_P (insn) || !INSN_HAS_LOCATION (insn)))
+               insn = PREV_INSN (insn);
+             if (insn != end
+                 && INSN_LOCATION (insn) == e->goto_locus)
+               continue;
+             if (simplejump_p (BB_END (e->src))
+                 && !INSN_HAS_LOCATION (BB_END (e->src)))
+               {
+                 INSN_LOCATION (BB_END (e->src)) = e->goto_locus;
+                 continue;
+               }
+             dest = e->dest;
+             if (dest == EXIT_BLOCK_PTR)
+               {
+                 /* Non-fallthru edges to the exit block cannot be split.  */
+                 if (!(e->flags & EDGE_FALLTHRU))
+                   continue;
+               }
+             else
+               {
+                 insn = BB_HEAD (dest);
+                 end = NEXT_INSN (BB_END (dest));
+                 while (insn != end && !NONDEBUG_INSN_P (insn))
+                   insn = NEXT_INSN (insn);
+                 if (insn != end && INSN_HAS_LOCATION (insn)
+                     && INSN_LOCATION (insn) == e->goto_locus)
+                   continue;
+               }
+             nb = split_edge (e);
+             if (!INSN_P (BB_END (nb)))
+               BB_END (nb) = emit_insn_after_noloc (gen_nop (), BB_END (nb),
+                                                    nb);
+             INSN_LOCATION (BB_END (nb)) = e->goto_locus;
+
+             /* If there are other incoming edges to the destination block
+                with the same goto locus, redirect them to the new block as
+                well, this can prevent other such blocks from being created
+                in subsequent iterations of the loop.  */
+             for (ei2 = ei_start (dest->preds); (e2 = ei_safe_edge (ei2)); )
+               if (LOCATION_LOCUS (e2->goto_locus) != UNKNOWN_LOCATION
+                   && !(e2->flags & (EDGE_ABNORMAL | EDGE_FALLTHRU))
+                   && e->goto_locus == e2->goto_locus)
+                 redirect_edge_and_branch (e2, nb);
+               else
+                 ei_next (&ei2);
+           }
+      }
+}
+\f
+/* Perform sanity checks on the insn chain.
+   1. Check that next/prev pointers are consistent in both the forward and
+      reverse direction.
+   2. Count insns in chain, going both directions, and check if equal.
+   3. Check that get_last_insn () returns the actual end of chain.  */
+
+DEBUG_FUNCTION void
+verify_insn_chain (void)
+{
+  rtx x, prevx, nextx;
+  int insn_cnt1, insn_cnt2;
+
+  for (prevx = NULL, insn_cnt1 = 1, x = get_insns ();
+       x != 0;
+       prevx = x, insn_cnt1++, x = NEXT_INSN (x))
+    gcc_assert (PREV_INSN (x) == prevx);
+
+  gcc_assert (prevx == get_last_insn ());
+
+  for (nextx = NULL, insn_cnt2 = 1, x = get_last_insn ();
+       x != 0;
+       nextx = x, insn_cnt2++, x = PREV_INSN (x))
+    gcc_assert (NEXT_INSN (x) == nextx);
+
+  gcc_assert (insn_cnt1 == insn_cnt2);
+}
+\f
+/* If we have assembler epilogues, the block falling through to exit must
+   be the last one in the reordered chain when we reach final.  Ensure
+   that this condition is met.  */
+static void
+fixup_fallthru_exit_predecessor (void)
+{
+  edge e;
+  basic_block bb = NULL;
+
+  /* This transformation is not valid before reload, because we might
+     separate a call from the instruction that copies the return
+     value.  */
+  gcc_assert (reload_completed);
+
+  e = find_fallthru_edge (EXIT_BLOCK_PTR->preds);
+  if (e)
+    bb = e->src;
+
+  if (bb && bb->aux)
+    {
+      basic_block c = ENTRY_BLOCK_PTR->next_bb;
+
+      /* If the very first block is the one with the fall-through exit
+        edge, we have to split that block.  */
+      if (c == bb)
+       {
+         bb = split_block (bb, NULL)->dest;
+         bb->aux = c->aux;
+         c->aux = bb;
+         BB_FOOTER (bb) = BB_FOOTER (c);
+         BB_FOOTER (c) = NULL;
+       }
+
+      while (c->aux != bb)
+       c = (basic_block) c->aux;
+
+      c->aux = bb->aux;
+      while (c->aux)
+       c = (basic_block) c->aux;
+
+      c->aux = bb;
+      bb->aux = NULL;
+    }
+}
+
+/* In case there are more than one fallthru predecessors of exit, force that
+   there is only one.  */
+
+static void
+force_one_exit_fallthru (void)
+{
+  edge e, predecessor = NULL;
+  bool more = false;
+  edge_iterator ei;
+  basic_block forwarder, bb;
+
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    if (e->flags & EDGE_FALLTHRU)
+      {
+       if (predecessor == NULL)
+         predecessor = e;
+       else
+         {
+           more = true;
+           break;
+         }
+      }
+
+  if (!more)
+    return;
+
+  /* Exit has several fallthru predecessors.  Create a forwarder block for
+     them.  */
+  forwarder = split_edge (predecessor);
+  for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); )
+    {
+      if (e->src == forwarder
+         || !(e->flags & EDGE_FALLTHRU))
+       ei_next (&ei);
+      else
+       redirect_edge_and_branch_force (e, forwarder);
+    }
+
+  /* Fix up the chain of blocks -- make FORWARDER immediately precede the
+     exit block.  */
+  FOR_EACH_BB (bb)
+    {
+      if (bb->aux == NULL && bb != forwarder)
+       {
+         bb->aux = forwarder;
+         break;
+       }
+    }
+}
+\f
+/* Return true in case it is possible to duplicate the basic block BB.  */
+
+static bool
+cfg_layout_can_duplicate_bb_p (const_basic_block bb)
+{
+  /* Do not attempt to duplicate tablejumps, as we need to unshare
+     the dispatch table.  This is difficult to do, as the instructions
+     computing jump destination may be hoisted outside the basic block.  */
+  if (tablejump_p (BB_END (bb), NULL, NULL))
+    return false;
+
+  /* Do not duplicate blocks containing insns that can't be copied.  */
+  if (targetm.cannot_copy_insn_p)
+    {
+      rtx insn = BB_HEAD (bb);
+      while (1)
+       {
+         if (INSN_P (insn) && targetm.cannot_copy_insn_p (insn))
+           return false;
+         if (insn == BB_END (bb))
+           break;
+         insn = NEXT_INSN (insn);
+       }
+    }
+
+  return true;
+}
+
+rtx
+duplicate_insn_chain (rtx from, rtx to)
+{
+  rtx insn, last, copy;
+
+  /* Avoid updating of boundaries of previous basic block.  The
+     note will get removed from insn stream in fixup.  */
+  last = emit_note (NOTE_INSN_DELETED);
+
+  /* Create copy at the end of INSN chain.  The chain will
+     be reordered later.  */
+  for (insn = from; insn != NEXT_INSN (to); insn = NEXT_INSN (insn))
+    {
+      switch (GET_CODE (insn))
+       {
+       case DEBUG_INSN:
+         /* Don't duplicate label debug insns.  */
+         if (TREE_CODE (INSN_VAR_LOCATION_DECL (insn)) == LABEL_DECL)
+           break;
+         /* FALLTHRU */
+       case INSN:
+       case CALL_INSN:
+       case JUMP_INSN:
+         /* Avoid copying of dispatch tables.  We never duplicate
+            tablejumps, so this can hit only in case the table got
+            moved far from original jump.  */
+         if (GET_CODE (PATTERN (insn)) == ADDR_VEC
+             || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+           {
+             /* Avoid copying following barrier as well if any
+                (and debug insns in between).  */
+             rtx next;
+
+             for (next = NEXT_INSN (insn);
+                  next != NEXT_INSN (to);
+                  next = NEXT_INSN (next))
+               if (!DEBUG_INSN_P (next))
+                 break;
+             if (next != NEXT_INSN (to) && BARRIER_P (next))
+               insn = next;
+             break;
+           }
+         copy = emit_copy_of_insn_after (insn, get_last_insn ());
+         if (JUMP_P (insn) && JUMP_LABEL (insn) != NULL_RTX
+             && ANY_RETURN_P (JUMP_LABEL (insn)))
+           JUMP_LABEL (copy) = JUMP_LABEL (insn);
+          maybe_copy_prologue_epilogue_insn (insn, copy);
+         break;
+
+       case CODE_LABEL:
+         break;
+
+       case BARRIER:
+         emit_barrier ();
+         break;
+
+       case NOTE:
+         switch (NOTE_KIND (insn))
+           {
+             /* In case prologue is empty and function contain label
+                in first BB, we may want to copy the block.  */
+           case NOTE_INSN_PROLOGUE_END:
+
+           case NOTE_INSN_DELETED:
+           case NOTE_INSN_DELETED_LABEL:
+           case NOTE_INSN_DELETED_DEBUG_LABEL:
+             /* No problem to strip these.  */
+           case NOTE_INSN_FUNCTION_BEG:
+             /* There is always just single entry to function.  */
+           case NOTE_INSN_BASIC_BLOCK:
+             break;
+
+           case NOTE_INSN_EPILOGUE_BEG:
+           case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+             emit_note_copy (insn);
+             break;
+
+           default:
+             /* All other notes should have already been eliminated.  */
+             gcc_unreachable ();
+           }
+         break;
+       default:
+         gcc_unreachable ();
+       }
+    }
+  insn = NEXT_INSN (last);
+  delete_insn (last);
+  return insn;
+}
+
+/* Create a duplicate of the basic block BB.  */
+
+static basic_block
+cfg_layout_duplicate_bb (basic_block bb)
+{
+  rtx insn;
+  basic_block new_bb;
+
+  insn = duplicate_insn_chain (BB_HEAD (bb), BB_END (bb));
+  new_bb = create_basic_block (insn,
+                              insn ? get_last_insn () : NULL,
+                              EXIT_BLOCK_PTR->prev_bb);
+
+  BB_COPY_PARTITION (new_bb, bb);
+  if (BB_HEADER (bb))
+    {
+      insn = BB_HEADER (bb);
+      while (NEXT_INSN (insn))
+       insn = NEXT_INSN (insn);
+      insn = duplicate_insn_chain (BB_HEADER (bb), insn);
+      if (insn)
+       BB_HEADER (new_bb) = unlink_insn_chain (insn, get_last_insn ());
+    }
+
+  if (BB_FOOTER (bb))
+    {
+      insn = BB_FOOTER (bb);
+      while (NEXT_INSN (insn))
+       insn = NEXT_INSN (insn);
+      insn = duplicate_insn_chain (BB_FOOTER (bb), insn);
+      if (insn)
+       BB_FOOTER (new_bb) = unlink_insn_chain (insn, get_last_insn ());
+    }
+
+  return new_bb;
+}
+
+\f
+/* Main entry point to this module - initialize the datastructures for
+   CFG layout changes.  It keeps LOOPS up-to-date if not null.
+
+   FLAGS is a set of additional flags to pass to cleanup_cfg().  */
+
+void
+cfg_layout_initialize (unsigned int flags)
+{
+  rtx x;
+  basic_block bb;
+
+  initialize_original_copy_tables ();
+
+  cfg_layout_rtl_register_cfg_hooks ();
+
+  record_effective_endpoints ();
+
+  /* Make sure that the targets of non local gotos are marked.  */
+  for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
+    {
+      bb = BLOCK_FOR_INSN (XEXP (x, 0));
+      bb->flags |= BB_NON_LOCAL_GOTO_TARGET;
+    }
+
+  cleanup_cfg (CLEANUP_CFGLAYOUT | flags);
+}
+
+/* Splits superblocks.  */
+void
+break_superblocks (void)
+{
+  sbitmap superblocks;
+  bool need = false;
+  basic_block bb;
+
+  superblocks = sbitmap_alloc (last_basic_block);
+  bitmap_clear (superblocks);
+
+  FOR_EACH_BB (bb)
+    if (bb->flags & BB_SUPERBLOCK)
+      {
+       bb->flags &= ~BB_SUPERBLOCK;
+       bitmap_set_bit (superblocks, bb->index);
+       need = true;
+      }
+
+  if (need)
+    {
+      rebuild_jump_labels (get_insns ());
+      find_many_sub_basic_blocks (superblocks);
+    }
+
+  free (superblocks);
+}
+
+/* Finalize the changes: reorder insn list according to the sequence specified
+   by aux pointers, enter compensation code, rebuild scope forest.  */
+
+void
+cfg_layout_finalize (void)
+{
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+  force_one_exit_fallthru ();
+  rtl_register_cfg_hooks ();
+  if (reload_completed
+#ifdef HAVE_epilogue
+      && !HAVE_epilogue
+#endif
+      )
+    fixup_fallthru_exit_predecessor ();
+  fixup_reorder_chain ();
+
+  rebuild_jump_labels (get_insns ());
+  delete_dead_jumptables ();
+
+#ifdef ENABLE_CHECKING
+  verify_insn_chain ();
+  verify_flow_info ();
+#endif
+}
+
+
+/* Same as split_block but update cfg_layout structures.  */
+
+static basic_block
+cfg_layout_split_block (basic_block bb, void *insnp)
+{
+  rtx insn = (rtx) insnp;
+  basic_block new_bb = rtl_split_block (bb, insn);
+
+  BB_FOOTER (new_bb) = BB_FOOTER (bb);
+  BB_FOOTER (bb) = NULL;
+
+  return new_bb;
+}
+
+/* Redirect Edge to DEST.  */
+static edge
+cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
+{
+  basic_block src = e->src;
+  edge ret;
+
+  if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
+    return NULL;
+
+  if (e->dest == dest)
+    return e;
+
+  if (e->src != ENTRY_BLOCK_PTR
+      && (ret = try_redirect_by_replacing_jump (e, dest, true)))
+    {
+      df_set_bb_dirty (src);
+      return ret;
+    }
+
+  if (e->src == ENTRY_BLOCK_PTR
+      && (e->flags & EDGE_FALLTHRU) && !(e->flags & EDGE_COMPLEX))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Redirecting entry edge from bb %i to %i\n",
+                e->src->index, dest->index);
+
+      df_set_bb_dirty (e->src);
+      redirect_edge_succ (e, dest);
+      return e;
+    }
+
+  /* Redirect_edge_and_branch may decide to turn branch into fallthru edge
+     in the case the basic block appears to be in sequence.  Avoid this
+     transformation.  */
+
+  if (e->flags & EDGE_FALLTHRU)
+    {
+      /* Redirect any branch edges unified with the fallthru one.  */
+      if (JUMP_P (BB_END (src))
+         && label_is_jump_target_p (BB_HEAD (e->dest),
+                                    BB_END (src)))
+       {
+         edge redirected;
+
+         if (dump_file)
+           fprintf (dump_file, "Fallthru edge unified with branch "
+                    "%i->%i redirected to %i\n",
+                    e->src->index, e->dest->index, dest->index);
+         e->flags &= ~EDGE_FALLTHRU;
+         redirected = redirect_branch_edge (e, dest);
+         gcc_assert (redirected);
+         redirected->flags |= EDGE_FALLTHRU;
+         df_set_bb_dirty (redirected->src);
+         return redirected;
+       }
+      /* In case we are redirecting fallthru edge to the branch edge
+        of conditional jump, remove it.  */
+      if (EDGE_COUNT (src->succs) == 2)
+       {
+         /* Find the edge that is different from E.  */
+         edge s = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e);
+
+         if (s->dest == dest
+             && any_condjump_p (BB_END (src))
+             && onlyjump_p (BB_END (src)))
+           delete_insn (BB_END (src));
+       }
+      if (dump_file)
+       fprintf (dump_file, "Redirecting fallthru edge %i->%i to %i\n",
+                e->src->index, e->dest->index, dest->index);
+      ret = redirect_edge_succ_nodup (e, dest);
+    }
+  else
+    ret = redirect_branch_edge (e, dest);
+
+  /* We don't want simplejumps in the insn stream during cfglayout.  */
+  gcc_assert (!simplejump_p (BB_END (src)));
+
+  df_set_bb_dirty (src);
+  return ret;
+}
+
+/* Simple wrapper as we always can redirect fallthru edges.  */
+static basic_block
+cfg_layout_redirect_edge_and_branch_force (edge e, basic_block dest)
+{
+  edge redirected = cfg_layout_redirect_edge_and_branch (e, dest);
+
+  gcc_assert (redirected);
+  return NULL;
+}
+
+/* Same as delete_basic_block but update cfg_layout structures.  */
+
+static void
+cfg_layout_delete_block (basic_block bb)
+{
+  rtx insn, next, prev = PREV_INSN (BB_HEAD (bb)), *to, remaints;
+
+  if (BB_HEADER (bb))
     {
       next = BB_HEAD (bb);
       if (prev)
-       NEXT_INSN (prev) = bb->il.rtl->header;
+       NEXT_INSN (prev) = BB_HEADER (bb);
       else
-       set_first_insn (bb->il.rtl->header);
-      PREV_INSN (bb->il.rtl->header) = prev;
-      insn = bb->il.rtl->header;
+       set_first_insn (BB_HEADER (bb));
+      PREV_INSN (BB_HEADER (bb)) = prev;
+      insn = BB_HEADER (bb);
       while (NEXT_INSN (insn))
        insn = NEXT_INSN (insn);
       NEXT_INSN (insn) = next;
       PREV_INSN (next) = insn;
     }
   next = NEXT_INSN (BB_END (bb));
-  if (bb->il.rtl->footer)
+  if (BB_FOOTER (bb))
     {
-      insn = bb->il.rtl->footer;
+      insn = BB_FOOTER (bb);
       while (insn)
        {
          if (BARRIER_P (insn))
@@ -2483,7 +3915,7 @@ cfg_layout_delete_block (basic_block bb)
              if (PREV_INSN (insn))
                NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
              else
-               bb->il.rtl->footer = NEXT_INSN (insn);
+               BB_FOOTER (bb) = NEXT_INSN (insn);
              if (NEXT_INSN (insn))
                PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
            }
@@ -2491,11 +3923,11 @@ cfg_layout_delete_block (basic_block bb)
            break;
          insn = NEXT_INSN (insn);
        }
-      if (bb->il.rtl->footer)
+      if (BB_FOOTER (bb))
        {
          insn = BB_END (bb);
-         NEXT_INSN (insn) = bb->il.rtl->footer;
-         PREV_INSN (bb->il.rtl->footer) = insn;
+         NEXT_INSN (insn) = BB_FOOTER (bb);
+         PREV_INSN (BB_FOOTER (bb)) = insn;
          while (NEXT_INSN (insn))
            insn = NEXT_INSN (insn);
          NEXT_INSN (insn) = next;
@@ -2506,7 +3938,7 @@ cfg_layout_delete_block (basic_block bb)
        }
     }
   if (bb->next_bb != EXIT_BLOCK_PTR)
-    to = &bb->next_bb->il.rtl->header;
+    to = &BB_HEADER (bb->next_bb);
   else
     to = &cfg_layout_function_footer;
 
@@ -2552,6 +3984,20 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
   if (BB_PARTITION (a) != BB_PARTITION (b))
     return false;
 
+  /* Protect the loop latches.  */
+  if (current_loops && b->loop_father->latch == b)
+    return false;
+
+  /* If we would end up moving B's instructions, make sure it doesn't fall
+     through into the exit block, since we cannot recover from a fallthrough
+     edge into the exit block occurring in the middle of a function.  */
+  if (NEXT_INSN (BB_END (a)) != BB_HEAD (b))
+    {
+      edge e = find_fallthru_edge (b->succs);
+      if (e && e->dest == EXIT_BLOCK_PTR)
+       return false;
+    }
+
   /* There must be exactly one edge in between the blocks.  */
   return (single_succ_p (a)
          && single_succ (a) == b
@@ -2573,20 +4019,18 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
 static void
 cfg_layout_merge_blocks (basic_block a, basic_block b)
 {
-#ifdef ENABLE_CHECKING
-  gcc_assert (cfg_layout_can_merge_blocks_p (a, b));
-#endif
+  bool forwarder_p = (b->flags & BB_FORWARDER_BLOCK) != 0;
+  rtx insn;
+
+  gcc_checking_assert (cfg_layout_can_merge_blocks_p (a, b));
 
   if (dump_file)
-    fprintf (dump_file, "merging block %d into block %d\n", b->index, a->index);
+    fprintf (dump_file, "Merging block %d into block %d...\n", b->index,
+                        a->index);
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (BB_HEAD (b)))
     {
-      /* This might have been an EH label that no longer has incoming
-        EH edges.  Update data structures to match.  */
-      maybe_remove_eh_handler (BB_HEAD (b));
-
       delete_insn (BB_HEAD (b));
     }
 
@@ -2596,74 +4040,77 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
     try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true);
   gcc_assert (!JUMP_P (BB_END (a)));
 
+  /* When not optimizing CFG and the edge is the only place in RTL which holds
+     some unique locus, emit a nop with that locus in between.  */
+  if (!optimize)
+    emit_nop_for_unique_locus_between (a, b);
+
   /* Possible line number notes should appear in between.  */
-  if (b->il.rtl->header)
+  if (BB_HEADER (b))
     {
       rtx first = BB_END (a), last;
 
-      last = emit_insn_after_noloc (b->il.rtl->header, BB_END (a), a);
+      last = emit_insn_after_noloc (BB_HEADER (b), BB_END (a), a);
+      /* The above might add a BARRIER as BB_END, but as barriers
+        aren't valid parts of a bb, remove_insn doesn't update
+        BB_END if it is a barrier.  So adjust BB_END here.  */
+      while (BB_END (a) != first && BARRIER_P (BB_END (a)))
+       BB_END (a) = PREV_INSN (BB_END (a));
       delete_insn_chain (NEXT_INSN (first), last, false);
-      b->il.rtl->header = NULL;
+      BB_HEADER (b) = NULL;
     }
 
   /* In the case basic blocks are not adjacent, move them around.  */
   if (NEXT_INSN (BB_END (a)) != BB_HEAD (b))
     {
-      rtx first = unlink_insn_chain (BB_HEAD (b), BB_END (b));
+      insn = unlink_insn_chain (BB_HEAD (b), BB_END (b));
 
-      emit_insn_after_noloc (first, BB_END (a), a);
-      /* Skip possible DELETED_LABEL insn.  */
-      if (!NOTE_INSN_BASIC_BLOCK_P (first))
-       first = NEXT_INSN (first);
-      gcc_assert (NOTE_INSN_BASIC_BLOCK_P (first));
-      BB_HEAD (b) = NULL;
-      delete_insn (first);
+      emit_insn_after_noloc (insn, BB_END (a), a);
     }
   /* Otherwise just re-associate the instructions.  */
   else
     {
-      rtx insn;
-
-      for (insn = BB_HEAD (b);
-          insn != NEXT_INSN (BB_END (b));
-          insn = NEXT_INSN (insn))
-       {
-         set_block_for_insn (insn, a);
-         df_insn_change_bb (insn);
-       }
-
       insn = BB_HEAD (b);
-      /* Skip possible DELETED_LABEL insn.  */
-      if (!NOTE_INSN_BASIC_BLOCK_P (insn))
-       insn = NEXT_INSN (insn);
-      gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
-      BB_HEAD (b) = NULL;
       BB_END (a) = BB_END (b);
-      delete_insn (insn);
     }
 
+  /* emit_insn_after_noloc doesn't call df_insn_change_bb.
+     We need to explicitly call. */
+  update_bb_for_insn_chain (insn, BB_END (b), a);
+
+  /* Skip possible DELETED_LABEL insn.  */
+  if (!NOTE_INSN_BASIC_BLOCK_P (insn))
+    insn = NEXT_INSN (insn);
+  gcc_assert (NOTE_INSN_BASIC_BLOCK_P (insn));
+  BB_HEAD (b) = NULL;
+  delete_insn (insn);
+
   df_bb_delete (b->index);
 
   /* Possible tablejumps and barriers should appear after the block.  */
-  if (b->il.rtl->footer)
+  if (BB_FOOTER (b))
     {
-      if (!a->il.rtl->footer)
-       a->il.rtl->footer = b->il.rtl->footer;
+      if (!BB_FOOTER (a))
+       BB_FOOTER (a) = BB_FOOTER (b);
       else
        {
-         rtx last = a->il.rtl->footer;
+         rtx last = BB_FOOTER (a);
 
          while (NEXT_INSN (last))
            last = NEXT_INSN (last);
-         NEXT_INSN (last) = b->il.rtl->footer;
-         PREV_INSN (b->il.rtl->footer) = last;
+         NEXT_INSN (last) = BB_FOOTER (b);
+         PREV_INSN (BB_FOOTER (b)) = last;
        }
-      b->il.rtl->footer = NULL;
+      BB_FOOTER (b) = NULL;
     }
 
+  /* If B was a forwarder block, propagate the locus on the edge.  */
+  if (forwarder_p
+      && LOCATION_LOCUS (EDGE_SUCC (b, 0)->goto_locus) != UNKNOWN_LOCATION)
+    EDGE_SUCC (b, 0)->goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
   if (dump_file)
-    fprintf (dump_file, "Merged blocks %d and %d.\n",
-            a->index, b->index);
+    fprintf (dump_file, "Merged blocks %d and %d.\n", a->index, b->index);
 }
 
 /* Split edge E.  */
@@ -2676,6 +4123,10 @@ cfg_layout_split_edge (edge e)
                        ? NEXT_INSN (BB_END (e->src)) : get_insns (),
                        NULL_RTX, e->src);
 
+  if (e->dest == EXIT_BLOCK_PTR)
+    BB_COPY_PARTITION (new_bb, e->src);
+  else
+    BB_COPY_PARTITION (new_bb, e->dest);
   make_edge (new_bb, e->dest, EDGE_FALLTHRU);
   redirect_edge_and_branch_force (e, new_bb);
 
@@ -2689,6 +4140,51 @@ rtl_make_forwarder_block (edge fallthru ATTRIBUTE_UNUSED)
 {
 }
 
+/* Return true if BB contains only labels or non-executable
+   instructions.  */
+
+static bool
+rtl_block_empty_p (basic_block bb)
+{
+  rtx insn;
+
+  if (bb == ENTRY_BLOCK_PTR || bb == EXIT_BLOCK_PTR)
+    return true;
+
+  FOR_BB_INSNS (bb, insn)
+    if (NONDEBUG_INSN_P (insn) && !any_uncondjump_p (insn))
+      return false;
+
+  return true;
+}
+
+/* Split a basic block if it ends with a conditional branch and if
+   the other part of the block is not empty.  */
+
+static basic_block
+rtl_split_block_before_cond_jump (basic_block bb)
+{
+  rtx insn;
+  rtx split_point = NULL;
+  rtx last = NULL;
+  bool found_code = false;
+
+  FOR_BB_INSNS (bb, insn)
+    {
+      if (any_condjump_p (insn))
+       split_point = last;
+      else if (NONDEBUG_INSN_P (insn))
+       found_code = true;
+      last = insn;
+    }
+
+  /* Did not find everything.  */ 
+  if (found_code && split_point)
+    return split_block (bb, split_point)->dest;
+  else 
+    return NULL;
+}
+
 /* Return 1 if BB ends with a call, possibly followed by some
    instructions that must stay with the call, 0 otherwise.  */
 
@@ -2699,7 +4195,9 @@ rtl_block_ends_with_call_p (basic_block bb)
 
   while (!CALL_P (insn)
         && insn != BB_HEAD (bb)
-        && keep_with_call_p (insn))
+        && (keep_with_call_p (insn)
+            || NOTE_P (insn)
+            || DEBUG_INSN_P (insn)))
     insn = PREV_INSN (insn);
   return (CALL_P (insn));
 }
@@ -2724,7 +4222,7 @@ need_fake_edge_p (const_rtx insn)
   if ((CALL_P (insn)
        && !SIBLING_CALL_P (insn)
        && !find_reg_note (insn, REG_NORETURN, NULL)
-       && !CONST_OR_PURE_CALL_P (insn)))
+       && !(RTL_CONST_OR_PURE_CALL_P (insn))))
     return true;
 
   return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
@@ -2757,7 +4255,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
   if (! blocks)
     check_last_block = true;
   else
-    check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index);
+    check_last_block = bitmap_bit_p (blocks, EXIT_BLOCK_PTR->prev_bb->index);
 
   /* In the last basic block, before epilogue generation, there will be
      a fallthru edge to EXIT.  Special care is required if the last insn
@@ -2788,7 +4286,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
          e = find_edge (bb, EXIT_BLOCK_PTR);
          if (e)
            {
-             insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+             insert_insn_on_edge (gen_use (const0_rtx), e);
              commit_edge_insertions ();
            }
        }
@@ -2807,7 +4305,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
       if (!bb)
        continue;
 
-      if (blocks && !TEST_BIT (blocks, i))
+      if (blocks && !bitmap_bit_p (blocks, i))
        continue;
 
       for (insn = BB_END (bb); ; insn = prev_insn)
@@ -2887,7 +4385,7 @@ rtl_lv_add_condition_to_bb (basic_block first_head ,
   op0 = force_operand (op0, NULL_RTX);
   op1 = force_operand (op1, NULL_RTX);
   do_compare_rtx_and_jump (op0, op1, comp, 0,
-                          mode, NULL_RTX, NULL_RTX, label);
+                          mode, NULL_RTX, NULL_RTX, label, -1);
   jump = get_last_insn ();
   JUMP_LABEL (jump) = label;
   LABEL_NUSES (label)++;
@@ -2923,96 +4421,9 @@ rtl_extract_cond_bb_edges (basic_block b, edge *branch_edge,
 void
 init_rtl_bb_info (basic_block bb)
 {
-  gcc_assert (!bb->il.rtl);
-  bb->il.rtl = GGC_CNEW (struct rtl_bb_info);
-}
-
-
-/* Add EXPR to the end of basic block BB.  */
-
-rtx
-insert_insn_end_bb_new (rtx pat, basic_block bb)
-{
-  rtx insn = BB_END (bb);
-  rtx new_insn;
-  rtx pat_end = pat;
-
-  while (NEXT_INSN (pat_end) != NULL_RTX)
-    pat_end = NEXT_INSN (pat_end);
-
-  /* If the last insn is a jump, insert EXPR in front [taking care to
-     handle cc0, etc. properly].  Similarly we need to care trapping
-     instructions in presence of non-call exceptions.  */
-
-  if (JUMP_P (insn)
-      || (NONJUMP_INSN_P (insn)
-          && (!single_succ_p (bb)
-              || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
-    {
-#ifdef HAVE_cc0
-      rtx note;
-#endif
-      /* If this is a jump table, then we can't insert stuff here.  Since
-         we know the previous real insn must be the tablejump, we insert
-         the new instruction just before the tablejump.  */
-      if (GET_CODE (PATTERN (insn)) == ADDR_VEC
-          || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
-        insn = prev_real_insn (insn);
-
-#ifdef HAVE_cc0
-      /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
-         if cc0 isn't set.  */
-      note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-      if (note)
-        insn = XEXP (note, 0);
-      else
-        {
-          rtx maybe_cc0_setter = prev_nonnote_insn (insn);
-          if (maybe_cc0_setter
-              && INSN_P (maybe_cc0_setter)
-              && sets_cc0_p (PATTERN (maybe_cc0_setter)))
-            insn = maybe_cc0_setter;
-        }
-#endif
-      /* FIXME: What if something in cc0/jump uses value set in new
-         insn?  */
-      new_insn = emit_insn_before_noloc (pat, insn, bb);
-    }
-
-  /* Likewise if the last insn is a call, as will happen in the presence
-     of exception handling.  */
-  else if (CALL_P (insn)
-           && (!single_succ_p (bb)
-               || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
-    {
-      /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
-         we search backward and place the instructions before the first
-         parameter is loaded.  Do this for everyone for consistency and a
-         presumption that we'll get better code elsewhere as well.  */
-
-      /* Since different machines initialize their parameter registers
-         in different orders, assume nothing.  Collect the set of all
-         parameter registers.  */
-      insn = find_first_parameter_load (insn, BB_HEAD (bb));
-
-      /* If we found all the parameter loads, then we want to insert
-         before the first parameter load.
-
-         If we did not find all the parameter loads, then we might have
-         stopped on the head of the block, which could be a CODE_LABEL.
-         If we inserted before the CODE_LABEL, then we would be putting
-         the insn in the wrong basic block.  In that case, put the insn
-         after the CODE_LABEL.  Also, respect NOTE_INSN_BASIC_BLOCK.  */
-      while (LABEL_P (insn)
-             || NOTE_INSN_BASIC_BLOCK_P (insn))
-        insn = NEXT_INSN (insn);
-
-      new_insn = emit_insn_before_noloc (pat, insn, bb);
-    }
-  else
-    new_insn = emit_insn_after_noloc (pat, insn, bb);
-
-  return new_insn;
+  gcc_assert (!bb->il.x.rtl);
+  bb->il.x.head_ = NULL;
+  bb->il.x.rtl = ggc_alloc_cleared_rtl_bb_info ();
 }
 
 /* Returns true if it is possible to remove edge E by redirecting
@@ -3047,6 +4458,36 @@ rtl_can_remove_branch_p (const_edge e)
   return true;
 }
 
+static basic_block
+rtl_duplicate_bb (basic_block bb)
+{
+  bb = cfg_layout_duplicate_bb (bb);
+  bb->aux = NULL;
+  return bb;
+}
+
+/* Do book-keeping of basic block BB for the profile consistency checker.
+   If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
+   then do post-pass accounting.  Store the counting in RECORD.  */
+static void
+rtl_account_profile_record (basic_block bb, int after_pass,
+                           struct profile_record *record)
+{
+  rtx insn;
+  FOR_BB_INSNS (bb, insn)
+    if (INSN_P (insn))
+      {
+       record->size[after_pass]
+         += insn_rtx_cost (PATTERN (insn), false);
+       if (profile_status == PROFILE_READ)
+         record->time[after_pass]
+           += insn_rtx_cost (PATTERN (insn), true) * bb->count;
+       else if (profile_status == PROFILE_GUESSED)
+         record->time[after_pass]
+           += insn_rtx_cost (PATTERN (insn), true) * bb->frequency;
+      }
+}
+
 /* Implementation of CFG manipulation for linearized RTL.  */
 struct cfg_hooks rtl_cfg_hooks = {
   "rtl",
@@ -3063,11 +4504,12 @@ struct cfg_hooks rtl_cfg_hooks = {
   rtl_merge_blocks,
   rtl_predict_edge,
   rtl_predicted_by_p,
-  NULL, /* can_duplicate_block_p */
-  NULL, /* duplicate_block */
+  cfg_layout_can_duplicate_bb_p,
+  rtl_duplicate_bb,
   rtl_split_edge,
   rtl_make_forwarder_block,
   rtl_tidy_fallthru_edge,
+  rtl_force_nonfallthru,
   rtl_block_ends_with_call_p,
   rtl_block_ends_with_condjump_p,
   rtl_flow_call_edges_add,
@@ -3077,7 +4519,10 @@ struct cfg_hooks rtl_cfg_hooks = {
   NULL, /* lv_add_condition_to_bb */
   NULL, /* lv_adjust_loop_header_phi*/
   NULL, /* extract_cond_bb_edges */
-  NULL         /* flush_pending_stmts */
+  NULL, /* flush_pending_stmts */
+  rtl_block_empty_p, /* block_empty_p */
+  rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */
+  rtl_account_profile_record,
 };
 
 /* Implementation of CFG manipulation for cfg layout RTL, where
@@ -3085,13 +4530,6 @@ struct cfg_hooks rtl_cfg_hooks = {
    This representation will hopefully become the default one in future
    version of the compiler.  */
 
-/* We do not want to declare these functions in a header file, since they
-   should only be used through the cfghooks interface, and we do not want to
-   move them here since it would require also moving quite a lot of related
-   code.  They are in cfglayout.c.  */
-extern bool cfg_layout_can_duplicate_bb_p (const_basic_block);
-extern basic_block cfg_layout_duplicate_bb (basic_block);
-
 struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   "cfglayout mode",
   rtl_verify_flow_info_1,
@@ -3111,7 +4549,8 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   cfg_layout_duplicate_bb,
   cfg_layout_split_edge,
   rtl_make_forwarder_block,
-  NULL,
+  NULL, /* tidy_fallthru_edge */
+  rtl_force_nonfallthru,
   rtl_block_ends_with_call_p,
   rtl_block_ends_with_condjump_p,
   rtl_flow_call_edges_add,
@@ -3121,5 +4560,10 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   rtl_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
   NULL, /* lv_adjust_loop_header_phi*/
   rtl_extract_cond_bb_edges, /* extract_cond_bb_edges */
-  NULL         /* flush_pending_stmts */
+  NULL, /* flush_pending_stmts */  
+  rtl_block_empty_p, /* block_empty_p */
+  rtl_split_block_before_cond_jump, /* split_block_before_cond_jump */
+  rtl_account_profile_record,
 };
+
+#include "gt-cfgrtl.h"