OSDN Git Service

Prevent sharing of commit calls among transactions.
[pf3gnuchains/gcc-fork.git] / gcc / cfglayout.c
index ef085fc..22d3d87 100644 (file)
@@ -1,11 +1,12 @@
 /* Basic block reordering routines for the GNU compiler.
 /* Basic block reordering routines for the GNU compiler.
-   Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -14,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -33,11 +33,14 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "cfglayout.h"
 #include "cfgloop.h"
 #include "target.h"
 #include "cfglayout.h"
 #include "cfgloop.h"
 #include "target.h"
+#include "common/common-target.h"
 #include "ggc.h"
 #include "alloc-pool.h"
 #include "flags.h"
 #include "tree-pass.h"
 #include "ggc.h"
 #include "alloc-pool.h"
 #include "flags.h"
 #include "tree-pass.h"
+#include "df.h"
 #include "vecprim.h"
 #include "vecprim.h"
+#include "emit-rtl.h"
 
 /* Holds the interesting trailing notes for the function.  */
 rtx cfg_layout_function_footer;
 
 /* Holds the interesting trailing notes for the function.  */
 rtx cfg_layout_function_footer;
@@ -48,12 +51,10 @@ static void record_effective_endpoints (void);
 static rtx label_for_bb (basic_block);
 static void fixup_reorder_chain (void);
 
 static rtx label_for_bb (basic_block);
 static void fixup_reorder_chain (void);
 
-static void set_block_levels (tree, int);
 static void change_scope (rtx, tree, tree);
 
 void verify_insn_chain (void);
 static void fixup_fallthru_exit_predecessor (void);
 static void change_scope (rtx, tree, tree);
 
 void verify_insn_chain (void);
 static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (rtx);
 \f
 rtx
 unlink_insn_chain (rtx first, rtx last)
 \f
 rtx
 unlink_insn_chain (rtx first, rtx last)
@@ -99,15 +100,11 @@ skip_insns_after_block (basic_block bb)
          continue;
 
        case NOTE:
          continue;
 
        case NOTE:
-         switch (NOTE_LINE_NUMBER (insn))
+         switch (NOTE_KIND (insn))
            {
            case NOTE_INSN_BLOCK_END:
            {
            case NOTE_INSN_BLOCK_END:
-             last_insn = insn;
+             gcc_unreachable ();
              continue;
              continue;
-           case NOTE_INSN_DELETED:
-           case NOTE_INSN_DELETED_LABEL:
-             continue;
-
            default:
              continue;
              break;
            default:
              continue;
              break;
@@ -116,9 +113,7 @@ skip_insns_after_block (basic_block bb)
 
        case CODE_LABEL:
          if (NEXT_INSN (insn)
 
        case CODE_LABEL:
          if (NEXT_INSN (insn)
-             && JUMP_P (NEXT_INSN (insn))
-             && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC
-                 || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC))
+             && JUMP_TABLE_DATA_P (NEXT_INSN (insn)))
            {
              insn = NEXT_INSN (insn);
              last_insn = insn;
            {
              insn = NEXT_INSN (insn);
              last_insn = insn;
@@ -147,11 +142,14 @@ skip_insns_after_block (basic_block bb)
     {
       prev = PREV_INSN (insn);
       if (NOTE_P (insn))
     {
       prev = PREV_INSN (insn);
       if (NOTE_P (insn))
-       switch (NOTE_LINE_NUMBER (insn))
+       switch (NOTE_KIND (insn))
          {
          case NOTE_INSN_BLOCK_END:
          {
          case NOTE_INSN_BLOCK_END:
+           gcc_unreachable ();
+           break;
          case NOTE_INSN_DELETED:
          case NOTE_INSN_DELETED_LABEL:
          case NOTE_INSN_DELETED:
          case NOTE_INSN_DELETED_LABEL:
+         case NOTE_INSN_DELETED_DEBUG_LABEL:
            continue;
          default:
            reorder_insns (insn, insn, last_insn);
            continue;
          default:
            reorder_insns (insn, insn, last_insn);
@@ -192,7 +190,7 @@ record_effective_endpoints (void)
   for (insn = get_insns ();
        insn
        && NOTE_P (insn)
   for (insn = get_insns ();
        insn
        && NOTE_P (insn)
-       && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK;
+       && NOTE_KIND (insn) != NOTE_INSN_BASIC_BLOCK;
        insn = NEXT_INSN (insn))
     continue;
   /* No basic blocks at all?  */
        insn = NEXT_INSN (insn))
     continue;
   /* No basic blocks at all?  */
@@ -232,120 +230,119 @@ record_effective_endpoints (void)
    than the following one.  Similarly for the other properties.  */
 static VEC(int,heap) *block_locators_locs;
 static GTY(()) VEC(tree,gc) *block_locators_blocks;
    than the following one.  Similarly for the other properties.  */
 static VEC(int,heap) *block_locators_locs;
 static GTY(()) VEC(tree,gc) *block_locators_blocks;
-static VEC(int,heap) *line_locators_locs;
-static VEC(int,heap) *line_locators_lines;
-static VEC(int,heap) *file_locators_locs;
-static GTY(()) varray_type file_locators_files;
+static VEC(int,heap) *locations_locators_locs;
+DEF_VEC_O(location_t);
+DEF_VEC_ALLOC_O(location_t,heap);
+static VEC(location_t,heap) *locations_locators_vals;
 int prologue_locator;
 int epilogue_locator;
 
 int prologue_locator;
 int epilogue_locator;
 
-/* During the RTL expansion the lexical blocks and line numbers are
-   represented via INSN_NOTEs.  Replace them by representation using
-   INSN_LOCATORs.  */
+/* Hold current location information and last location information, so the
+   datastructures are built lazily only when some instructions in given
+   place are needed.  */
+static location_t curr_location, last_location;
+static tree curr_block, last_block;
+static int curr_rtl_loc = -1;
 
 
-unsigned int
-insn_locators_initialize (void)
+/* Allocate insn locator datastructure.  */
+void
+insn_locators_alloc (void)
 {
 {
-  tree block = NULL;
-  tree last_block = NULL;
-  rtx insn, next;
-  int loc = 0;
-  int line_number = 0, last_line_number = 0;
-  const char *file_name = NULL, *last_file_name = NULL;
-
   prologue_locator = epilogue_locator = 0;
 
   block_locators_locs = VEC_alloc (int, heap, 32);
   block_locators_blocks = VEC_alloc (tree, gc, 32);
   prologue_locator = epilogue_locator = 0;
 
   block_locators_locs = VEC_alloc (int, heap, 32);
   block_locators_blocks = VEC_alloc (tree, gc, 32);
-  line_locators_locs = VEC_alloc (int, heap, 32);
-  line_locators_lines = VEC_alloc (int, heap, 32);
-  file_locators_locs = VEC_alloc (int, heap, 32);
-  VARRAY_CHAR_PTR_INIT (file_locators_files, 32, "file_locators_files");
+  locations_locators_locs = VEC_alloc (int, heap, 32);
+  locations_locators_vals = VEC_alloc (location_t, heap, 32);
+
+  curr_location = UNKNOWN_LOCATION;
+  last_location = UNKNOWN_LOCATION;
+  curr_block = NULL;
+  last_block = NULL;
+  curr_rtl_loc = 0;
+}
 
 
-  for (insn = get_insns (); insn; insn = next)
-    {
-      int active = 0;
+/* At the end of emit stage, clear current location.  */
+void
+insn_locators_finalize (void)
+{
+  if (curr_rtl_loc >= 0)
+    epilogue_locator = curr_insn_locator ();
+  curr_rtl_loc = -1;
+}
 
 
-      next = NEXT_INSN (insn);
+/* Allocate insn locator datastructure.  */
+void
+insn_locators_free (void)
+{
+  prologue_locator = epilogue_locator = 0;
 
 
-      if (NOTE_P (insn))
-       {
-         gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_BEG
-                     && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BLOCK_END);
-         if (NOTE_LINE_NUMBER (insn) > 0)
-           {
-             expanded_location xloc;
-             NOTE_EXPANDED_LOCATION (xloc, insn);
-             line_number = xloc.line;
-             file_name = xloc.file;
-             delete_insn (insn);
-           }
-       }
-      else
-       active = (active_insn_p (insn)
-                 && GET_CODE (PATTERN (insn)) != ADDR_VEC
-                 && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC);
+  VEC_free (int, heap, block_locators_locs);
+  VEC_free (tree,gc, block_locators_blocks);
+  VEC_free (int, heap, locations_locators_locs);
+  VEC_free (location_t, heap, locations_locators_vals);
+}
 
 
-      check_block_change (insn, &block);
 
 
-      if (active
-         || !next
-         || (!prologue_locator && file_name))
-       {
-         if (last_block != block)
-           {
-             loc++;
-             VEC_safe_push (int, heap, block_locators_locs, loc);
-             VEC_safe_push (tree, gc, block_locators_blocks, block);
-             last_block = block;
-           }
-         if (last_line_number != line_number)
-           {
-             loc++;
-             VEC_safe_push (int, heap, line_locators_locs, loc);
-             VEC_safe_push (int, heap, line_locators_lines, line_number);
-             last_line_number = line_number;
-           }
-         if (last_file_name != file_name)
-           {
-             loc++;
-             VEC_safe_push (int, heap, file_locators_locs, loc);
-             VARRAY_PUSH_CHAR_PTR (file_locators_files, (char *) file_name);
-             last_file_name = file_name;
-           }
-         if (!prologue_locator && file_name)
-           prologue_locator = loc;
-         if (!next)
-           epilogue_locator = loc;
-         if (active)
-           INSN_LOCATOR (insn) = loc;
-       }
-    }
+/* Set current location.  */
+void
+set_curr_insn_source_location (location_t location)
+{
+  /* IV opts calls into RTL expansion to compute costs of operations.  At this
+     time locators are not initialized.  */
+  if (curr_rtl_loc == -1)
+    return;
+  curr_location = location;
+}
 
 
-  /* Tag the blocks with a depth number so that change_scope can find
-     the common parent easily.  */
-  set_block_levels (DECL_INITIAL (cfun->decl), 0);
+/* Get current location.  */
+location_t
+get_curr_insn_source_location (void)
+{
+  return curr_location;
+}
 
 
-  free_block_changes ();
-  return 0;
+/* Set current scope block.  */
+void
+set_curr_insn_block (tree b)
+{
+  /* IV opts calls into RTL expansion to compute costs of operations.  At this
+     time locators are not initialized.  */
+  if (curr_rtl_loc == -1)
+    return;
+  if (b)
+    curr_block = b;
 }
 
 }
 
-struct tree_opt_pass pass_insn_locators_initialize =
+/* Get current scope block.  */
+tree
+get_curr_insn_block (void)
 {
 {
-  "locators",                           /* name */
-  NULL,                                 /* gate */
-  insn_locators_initialize,             /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
-};
+  return curr_block;
+}
+
+/* Return current insn locator.  */
+int
+curr_insn_locator (void)
+{
+  if (curr_rtl_loc == -1 || curr_location == UNKNOWN_LOCATION)
+    return 0;
+  if (last_block != curr_block)
+    {
+      curr_rtl_loc++;
+      VEC_safe_push (int, heap, block_locators_locs, curr_rtl_loc);
+      VEC_safe_push (tree, gc, block_locators_blocks, curr_block);
+      last_block = curr_block;
+    }
+  if (last_location != curr_location)
+    {
+      curr_rtl_loc++;
+      VEC_safe_push (int, heap, locations_locators_locs, curr_rtl_loc);
+      VEC_safe_push (location_t, heap, locations_locators_vals, &curr_location);
+      last_location = curr_location;
+    }
+  return curr_rtl_loc;
+}
 
 static unsigned int
 into_cfg_layout_mode (void)
 
 static unsigned int
 into_cfg_layout_mode (void)
@@ -368,55 +365,45 @@ outof_cfg_layout_mode (void)
   return 0;
 }
 
   return 0;
 }
 
-struct tree_opt_pass pass_into_cfg_layout_mode =
+struct rtl_opt_pass pass_into_cfg_layout_mode =
 {
 {
+ {
+  RTL_PASS,
   "into_cfglayout",                     /* name */
   NULL,                                 /* gate */
   into_cfg_layout_mode,                 /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   "into_cfglayout",                     /* name */
   NULL,                                 /* gate */
   into_cfg_layout_mode,                 /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_CFG,                               /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_required */
-  0,                                    /* properties_provided */
+  PROP_cfglayout,                       /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 
 };
 
-struct tree_opt_pass pass_outof_cfg_layout_mode =
+struct rtl_opt_pass pass_outof_cfg_layout_mode =
 {
 {
+ {
+  RTL_PASS,
   "outof_cfglayout",                    /* name */
   NULL,                                 /* gate */
   outof_cfg_layout_mode,                /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   "outof_cfglayout",                    /* name */
   NULL,                                 /* gate */
   outof_cfg_layout_mode,                /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_CFG,                               /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
+  PROP_cfglayout,                       /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 };
-
-/* For each lexical block, set BLOCK_NUMBER to the depth at which it is
-   found in the block tree.  */
-
-static void
-set_block_levels (tree block, int level)
-{
-  while (block)
-    {
-      BLOCK_NUMBER (block) = level;
-      set_block_levels (BLOCK_SUBBLOCKS (block), level + 1);
-      block = BLOCK_CHAIN (block);
-    }
-}
 \f
 \f
-/* Return sope resulting from combination of S1 and S2.  */
+/* Return scope resulting from combination of S1 and S2.  */
 static tree
 choose_inner_scope (tree s1, tree s2)
 {
 static tree
 choose_inner_scope (tree s1, tree s2)
 {
@@ -473,13 +460,12 @@ change_scope (rtx orig_insn, tree s1, tree s2)
     }
 }
 
     }
 }
 
-/* Return lexical scope block insn belong to.  */
+/* Return lexical scope block locator belongs to.  */
 static tree
 static tree
-insn_scope (rtx insn)
+locator_scope (int loc)
 {
   int max = VEC_length (int, block_locators_locs);
   int min = 0;
 {
   int max = VEC_length (int, block_locators_locs);
   int min = 0;
-  int loc = INSN_LOCATOR (insn);
 
   /* When block_locators_locs was initialized, the pro- and epilogue
      insns didn't exist yet and can therefore not be found this way.
 
   /* When block_locators_locs was initialized, the pro- and epilogue
      insns didn't exist yet and can therefore not be found this way.
@@ -513,19 +499,24 @@ insn_scope (rtx insn)
   return VEC_index (tree, block_locators_blocks, min);
 }
 
   return VEC_index (tree, block_locators_blocks, min);
 }
 
+/* Return lexical scope block insn belongs to.  */
+tree
+insn_scope (const_rtx insn)
+{
+  return locator_scope (INSN_LOCATOR (insn));
+}
+
 /* Return line number of the statement specified by the locator.  */
 /* Return line number of the statement specified by the locator.  */
-int
-locator_line (int loc)
+location_t
+locator_location (int loc)
 {
 {
-  int max = VEC_length (int, line_locators_locs);
+  int max = VEC_length (int, locations_locators_locs);
   int min = 0;
 
   int min = 0;
 
-  if (!max || !loc)
-    return 0;
   while (1)
     {
       int pos = (min + max) / 2;
   while (1)
     {
       int pos = (min + max) / 2;
-      int tmp = VEC_index (int, line_locators_locs, pos);
+      int tmp = VEC_index (int, locations_locators_locs, pos);
 
       if (tmp <= loc && min != pos)
        min = pos;
 
       if (tmp <= loc && min != pos)
        min = pos;
@@ -537,12 +528,24 @@ locator_line (int loc)
          break;
        }
     }
          break;
        }
     }
-  return VEC_index (int, line_locators_lines, min);
+  return *VEC_index (location_t, locations_locators_vals, min);
+}
+
+/* Return source line of the statement that produced this insn.  */
+int
+locator_line (int loc)
+{
+  expanded_location xloc;
+  if (!loc)
+    return 0;
+  else
+    xloc = expand_location (locator_location (loc));
+  return xloc.line;
 }
 
 /* Return line number of the statement that produced this insn.  */
 int
 }
 
 /* Return line number of the statement that produced this insn.  */
 int
-insn_line (rtx insn)
+insn_line (const_rtx insn)
 {
   return locator_line (INSN_LOCATOR (insn));
 }
 {
   return locator_line (INSN_LOCATOR (insn));
 }
@@ -551,36 +554,32 @@ insn_line (rtx insn)
 const char *
 locator_file (int loc)
 {
 const char *
 locator_file (int loc)
 {
-  int max = VEC_length (int, file_locators_locs);
-  int min = 0;
-
-  if (!max || !loc)
-    return NULL;
-  while (1)
-    {
-      int pos = (min + max) / 2;
-      int tmp = VEC_index (int, file_locators_locs, pos);
-
-      if (tmp <= loc && min != pos)
-       min = pos;
-      else if (tmp > loc && max != pos)
-       max = pos;
-      else
-       {
-         min = pos;
-         break;
-       }
-    }
-   return VARRAY_CHAR_PTR (file_locators_files, min);
+  expanded_location xloc;
+  if (!loc)
+    return 0;
+  else
+    xloc = expand_location (locator_location (loc));
+  return xloc.file;
 }
 
 /* Return source file of the statement that produced this insn.  */
 const char *
 }
 
 /* Return source file of the statement that produced this insn.  */
 const char *
-insn_file (rtx insn)
+insn_file (const_rtx insn)
 {
   return locator_file (INSN_LOCATOR (insn));
 }
 
 {
   return locator_file (INSN_LOCATOR (insn));
 }
 
+/* Return true if LOC1 and LOC2 locators have the same location and scope.  */
+bool
+locator_eq (int loc1, int loc2)
+{
+  if (loc1 == loc2)
+    return true;
+  if (locator_location (loc1) != locator_location (loc2))
+    return false;
+  return locator_scope (loc1) == locator_scope (loc2);
+}
+
 /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
    on the scope tree and the newly reordered instructions.  */
 
 /* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
    on the scope tree and the newly reordered instructions.  */
 
@@ -598,9 +597,7 @@ reemit_insn_block_notes (void)
       tree this_block;
 
       /* Avoid putting scope notes between jump table and its label.  */
       tree this_block;
 
       /* Avoid putting scope notes between jump table and its label.  */
-      if (JUMP_P (insn)
-         && (GET_CODE (PATTERN (insn)) == ADDR_VEC
-             || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+      if (JUMP_TABLE_DATA_P (insn))
        continue;
 
       this_block = insn_scope (insn);
        continue;
 
       this_block = insn_scope (insn);
@@ -634,13 +631,83 @@ reemit_insn_block_notes (void)
   reorder_blocks ();
 }
 \f
   reorder_blocks ();
 }
 \f
+
+/* Link the basic blocks in the correct order, compacting the basic
+   block queue while at it.  This also clears the visited flag on
+   all basic blocks.  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.  */
+
+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 and visited fields.  */
+  FOR_ALL_BB (bb)
+    {
+      bb->aux = NULL;
+      bb->il.rtl->visited = 0;
+      if (!stay_in_cfglayout_mode)
+       bb->il.rtl->header = bb->il.rtl->footer = 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)
 {
 /* Given a reorder chain, rearrange the code to match.  */
 
 static void
 fixup_reorder_chain (void)
 {
-  basic_block bb, prev_bb;
-  int index;
+  basic_block bb;
   rtx insn = NULL;
 
   if (cfg_layout_function_header)
   rtx insn = NULL;
 
   if (cfg_layout_function_header)
@@ -654,9 +721,7 @@ fixup_reorder_chain (void)
   /* First do the bulk reordering -- rechain the blocks without regard to
      the needed changes to jumps and labels.  */
 
   /* 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, index = NUM_FIXED_BLOCKS;
-       bb != 0;
-       bb = bb->aux, index++)
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = (basic_block) bb->aux)
     {
       if (bb->il.rtl->header)
        {
     {
       if (bb->il.rtl->header)
        {
@@ -684,8 +749,6 @@ fixup_reorder_chain (void)
        }
     }
 
        }
     }
 
-  gcc_assert (index == n_basic_blocks);
-
   NEXT_INSN (insn) = cfg_layout_function_footer;
   if (cfg_layout_function_footer)
     PREV_INSN (cfg_layout_function_footer) = insn;
   NEXT_INSN (insn) = cfg_layout_function_footer;
   if (cfg_layout_function_footer)
     PREV_INSN (cfg_layout_function_footer) = insn;
@@ -701,11 +764,12 @@ fixup_reorder_chain (void)
   /* Now add jumps and labels as needed to match the blocks new
      outgoing edges.  */
 
   /* Now add jumps and labels as needed to match the blocks new
      outgoing edges.  */
 
-  for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = bb->aux)
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = (basic_block) bb->aux)
     {
       edge e_fall, e_taken, e;
       rtx bb_end_insn;
     {
       edge e_fall, e_taken, e;
       rtx bb_end_insn;
-      basic_block nb;
+      rtx ret_label = NULL_RTX;
+      basic_block nb, src_bb;
       edge_iterator ei;
 
       if (EDGE_COUNT (bb->succs) == 0)
       edge_iterator ei;
 
       if (EDGE_COUNT (bb->succs) == 0)
@@ -724,8 +788,21 @@ fixup_reorder_chain (void)
       bb_end_insn = BB_END (bb);
       if (JUMP_P (bb_end_insn))
        {
       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))
            {
          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->il.rtl->footer = 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)
              /* If the old fallthru is still next, nothing to do.  */
              if (bb->aux == e_fall->dest
                  || e_fall->dest == EXIT_BLOCK_PTR)
@@ -754,10 +831,8 @@ fixup_reorder_chain (void)
                                       : label_for_bb (e_fall->dest)), 0))
                    {
                      e_fall->flags &= ~EDGE_FALLTHRU;
                                       : label_for_bb (e_fall->dest)), 0))
                    {
                      e_fall->flags &= ~EDGE_FALLTHRU;
-#ifdef ENABLE_CHECKING
-                     gcc_assert (could_fall_through
-                                 (e_taken->src, e_taken->dest));
-#endif
+                     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;
                      e_taken->flags |= EDGE_FALLTHRU;
                      update_br_prob_note (bb);
                      e = e_fall, e_fall = e_taken, e_taken = e;
@@ -778,15 +853,25 @@ fixup_reorder_chain (void)
                                     : label_for_bb (e_fall->dest)), 0))
                {
                  e_fall->flags &= ~EDGE_FALLTHRU;
                                     : label_for_bb (e_fall->dest)), 0))
                {
                  e_fall->flags &= ~EDGE_FALLTHRU;
-#ifdef ENABLE_CHECKING
-                 gcc_assert (could_fall_through
-                             (e_taken->src, e_taken->dest));
-#endif
+                 gcc_checking_assert (could_fall_through
+                                      (e_taken->src, e_taken->dest));
                  e_taken->flags |= EDGE_FALLTHRU;
                  update_br_prob_note (bb);
                  continue;
                }
            }
                  e_taken->flags |= EDGE_FALLTHRU;
                  update_br_prob_note (bb);
                  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
          else
            {
              /* Otherwise we have some return, switch or computed
@@ -813,8 +898,11 @@ fixup_reorder_chain (void)
            continue;
        }
 
            continue;
        }
 
-      /* We got here if we need to add a new jump insn.  */
-      nb = force_nonfallthru (e_fall);
+      /* 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->il.rtl->visited = 1;
       if (nb)
        {
          nb->il.rtl->visited = 1;
@@ -824,69 +912,95 @@ fixup_reorder_chain (void)
          bb = nb;
 
          /* Make sure new bb is tagged for correct section (same as
          bb = nb;
 
          /* Make sure new bb is tagged for correct section (same as
-            fall-thru source, since you cannot fall-throu across
+            fall-thru source, since you cannot fall-thru across
             section boundaries).  */
             section boundaries).  */
-         BB_COPY_PARTITION (e_fall->src, single_pred (bb));
+         BB_COPY_PARTITION (src_bb, single_pred (bb));
          if (flag_reorder_blocks_and_partition
          if (flag_reorder_blocks_and_partition
-             && targetm.have_named_sections
+             && targetm_common.have_named_sections
              && JUMP_P (BB_END (bb))
              && !any_condjump_p (BB_END (bb))
              && (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING))
              && JUMP_P (BB_END (bb))
              && !any_condjump_p (BB_END (bb))
              && (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING))
-           REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
-             (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
-       }
-    }
-
-  /* Put basic_block_info in the new order.  */
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "Reordered sequence:\n");
-      for (bb = ENTRY_BLOCK_PTR->next_bb, index = NUM_FIXED_BLOCKS;
-          bb;
-          bb = 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);
+           add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX);
        }
     }
 
        }
     }
 
-  prev_bb = ENTRY_BLOCK_PTR;
-  bb = ENTRY_BLOCK_PTR->next_bb;
-  index = NUM_FIXED_BLOCKS;
-
-  for (; bb; prev_bb = bb, bb = bb->aux, index ++)
-    {
-      bb->index = index;
-      SET_BASIC_BLOCK (index, bb);
-
-      bb->prev_bb = prev_bb;
-      prev_bb->next_bb = bb;
-    }
-  prev_bb->next_bb = EXIT_BLOCK_PTR;
-  EXIT_BLOCK_PTR->prev_bb = prev_bb;
+  relink_block_chain (/*stay_in_cfglayout_mode=*/false);
 
   /* Annoying special case - jump around dead jumptables left in the code.  */
   FOR_EACH_BB (bb)
     {
 
   /* Annoying special case - jump around dead jumptables left in the code.  */
   FOR_EACH_BB (bb)
     {
-      edge e;
-      edge_iterator ei;
-
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
+      edge e = find_fallthru_edge (bb->succs);
 
       if (e && !can_fallthru (e->src, e->dest))
        force_nonfallthru (e);
     }
 
       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 (e->goto_locus && !(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_LOCATOR (insn) == 0))
+               insn = PREV_INSN (insn);
+             if (insn != end
+                 && locator_eq (INSN_LOCATOR (insn), (int) e->goto_locus))
+               continue;
+             if (simplejump_p (BB_END (e->src))
+                 && INSN_LOCATOR (BB_END (e->src)) == 0)
+               {
+                 INSN_LOCATOR (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_LOCATOR (insn)
+                     && locator_eq (INSN_LOCATOR (insn), (int) 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_LOCATOR (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 (e2->goto_locus
+                   && !(e2->flags & (EDGE_ABNORMAL | EDGE_FALLTHRU))
+                   && locator_eq (e->goto_locus, e2->goto_locus))
+                 redirect_edge_and_branch (e2, nb);
+               else
+                 ei_next (&ei2);
+           }
+      }
 }
 \f
 /* Perform sanity checks on the insn chain.
 }
 \f
 /* Perform sanity checks on the insn chain.
@@ -895,7 +1009,7 @@ fixup_reorder_chain (void)
    2. Count insns in chain, going both directions, and check if equal.
    3. Check that get_last_insn () returns the actual end of chain.  */
 
    2. Count insns in chain, going both directions, and check if equal.
    3. Check that get_last_insn () returns the actual end of chain.  */
 
-void
+DEBUG_FUNCTION void
 verify_insn_chain (void)
 {
   rtx x, prevx, nextx;
 verify_insn_chain (void)
 {
   rtx x, prevx, nextx;
@@ -923,7 +1037,6 @@ static void
 fixup_fallthru_exit_predecessor (void)
 {
   edge e;
 fixup_fallthru_exit_predecessor (void)
 {
   edge e;
-  edge_iterator ei;
   basic_block bb = NULL;
 
   /* This transformation is not valid before reload, because we might
   basic_block bb = NULL;
 
   /* This transformation is not valid before reload, because we might
@@ -931,9 +1044,9 @@ fixup_fallthru_exit_predecessor (void)
      value.  */
   gcc_assert (reload_completed);
 
      value.  */
   gcc_assert (reload_completed);
 
-  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
-    if (e->flags & EDGE_FALLTHRU)
-      bb = e->src;
+  e = find_fallthru_edge (EXIT_BLOCK_PTR->preds);
+  if (e)
+    bb = e->src;
 
   if (bb && bb->aux)
     {
 
   if (bb && bb->aux)
     {
@@ -951,16 +1064,66 @@ fixup_fallthru_exit_predecessor (void)
        }
 
       while (c->aux != bb)
        }
 
       while (c->aux != bb)
-       c = c->aux;
+       c = (basic_block) c->aux;
 
       c->aux = bb->aux;
       while (c->aux)
 
       c->aux = bb->aux;
       while (c->aux)
-       c = c->aux;
+       c = (basic_block) c->aux;
 
       c->aux = bb;
       bb->aux = NULL;
     }
 }
 
       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.  */
 
 \f
 /* Return true in case it is possible to duplicate the basic block BB.  */
 
@@ -968,10 +1131,10 @@ fixup_fallthru_exit_predecessor (void)
    only be used through the cfghooks interface, and we do not want to move
    it to cfgrtl.c since it would require also moving quite a lot of related
    code.  */
    only be used through the cfghooks interface, and we do not want to move
    it to cfgrtl.c since it would require also moving quite a lot of related
    code.  */
-extern bool cfg_layout_can_duplicate_bb_p (basic_block);
+extern bool cfg_layout_can_duplicate_bb_p (const_basic_block);
 
 bool
 
 bool
-cfg_layout_can_duplicate_bb_p (basic_block bb)
+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
 {
   /* Do not attempt to duplicate tablejumps, as we need to unshare
      the dispatch table.  This is difficult to do, as the instructions
@@ -999,7 +1162,7 @@ cfg_layout_can_duplicate_bb_p (basic_block bb)
 rtx
 duplicate_insn_chain (rtx from, rtx to)
 {
 rtx
 duplicate_insn_chain (rtx from, rtx to)
 {
-  rtx insn, last;
+  rtx insn, last, copy;
 
   /* Avoid updating of boundaries of previous basic block.  The
      note will get removed from insn stream in fixup.  */
 
   /* Avoid updating of boundaries of previous basic block.  The
      note will get removed from insn stream in fixup.  */
@@ -1011,6 +1174,11 @@ duplicate_insn_chain (rtx from, rtx to)
     {
       switch (GET_CODE (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:
        case INSN:
        case CALL_INSN:
        case JUMP_INSN:
@@ -1019,8 +1187,25 @@ duplicate_insn_chain (rtx from, rtx to)
             moved far from original jump.  */
          if (GET_CODE (PATTERN (insn)) == ADDR_VEC
              || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
             moved far from original jump.  */
          if (GET_CODE (PATTERN (insn)) == ADDR_VEC
              || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
-           break;
-         emit_copy_of_insn_after (insn, get_last_insn ());
+           {
+             /* 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 CODE_LABEL:
@@ -1031,7 +1216,7 @@ duplicate_insn_chain (rtx from, rtx to)
          break;
 
        case NOTE:
          break;
 
        case NOTE:
-         switch (NOTE_LINE_NUMBER (insn))
+         switch (NOTE_KIND (insn))
            {
              /* In case prologue is empty and function contain label
                 in first BB, we may want to copy the block.  */
            {
              /* In case prologue is empty and function contain label
                 in first BB, we may want to copy the block.  */
@@ -1039,29 +1224,21 @@ duplicate_insn_chain (rtx from, rtx to)
 
            case NOTE_INSN_DELETED:
            case NOTE_INSN_DELETED_LABEL:
 
            case NOTE_INSN_DELETED:
            case NOTE_INSN_DELETED_LABEL:
+           case NOTE_INSN_DELETED_DEBUG_LABEL:
              /* No problem to strip these.  */
              /* No problem to strip these.  */
-           case NOTE_INSN_EPILOGUE_BEG:
-             /* Debug code expect these notes to exist just once.
-                Keep them in the master copy.
-                ??? It probably makes more sense to duplicate them for each
-                epilogue copy.  */
            case NOTE_INSN_FUNCTION_BEG:
              /* There is always just single entry to function.  */
            case NOTE_INSN_BASIC_BLOCK:
              break;
 
            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:
            case NOTE_INSN_SWITCH_TEXT_SECTIONS:
              emit_note_copy (insn);
              break;
 
            default:
-             /* All other notes should have already been eliminated.
-              */
-             gcc_assert (NOTE_LINE_NUMBER (insn) >= 0);
-
-             /* It is possible that no_line_number is set and the note
-                won't be emitted.  */
-             emit_note_copy (insn);
+             /* All other notes should have already been eliminated.  */
+             gcc_unreachable ();
            }
          break;
        default:
            }
          break;
        default:
@@ -1112,35 +1289,34 @@ cfg_layout_duplicate_bb (basic_block bb)
        new_bb->il.rtl->footer = unlink_insn_chain (insn, get_last_insn ());
     }
 
        new_bb->il.rtl->footer = unlink_insn_chain (insn, get_last_insn ());
     }
 
-  if (bb->il.rtl->global_live_at_start)
-    {
-      new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
-      new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
-      COPY_REG_SET (new_bb->il.rtl->global_live_at_start,
-                   bb->il.rtl->global_live_at_start);
-      COPY_REG_SET (new_bb->il.rtl->global_live_at_end,
-                   bb->il.rtl->global_live_at_end);
-    }
-
   return new_bb;
 }
   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.
 
 \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().  It should
-   include CLEANUP_UPDATE_LIFE if liveness information must be kept up
-   to date.  */
+   FLAGS is a set of additional flags to pass to cleanup_cfg().  */
 
 void
 cfg_layout_initialize (unsigned int flags)
 {
 
 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 ();
 
   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);
 }
 
   cleanup_cfg (CLEANUP_CFGLAYOUT | flags);
 }
 
@@ -1178,11 +1354,10 @@ break_superblocks (void)
 void
 cfg_layout_finalize (void)
 {
 void
 cfg_layout_finalize (void)
 {
-  basic_block bb;
-
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
+  force_one_exit_fallthru ();
   rtl_register_cfg_hooks ();
   if (reload_completed
 #ifdef HAVE_epilogue
   rtl_register_cfg_hooks ();
   if (reload_completed
 #ifdef HAVE_epilogue
@@ -1197,19 +1372,8 @@ cfg_layout_finalize (void)
 
 #ifdef ENABLE_CHECKING
   verify_insn_chain ();
 
 #ifdef ENABLE_CHECKING
   verify_insn_chain ();
-#endif
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-  {
-    bb->il.rtl->header = bb->il.rtl->footer = NULL;
-    bb->aux = NULL;
-    bb->il.rtl->visited = 0;
-  }
-
-#ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
   verify_flow_info ();
 #endif
-
-  free_original_copy_tables ();
 }
 
 /* Checks whether all N blocks in BBS array can be copied.  */
 }
 
 /* Checks whether all N blocks in BBS array can be copied.  */