Eliminate basic_block_info macro.
[platform/upstream/gcc.git] / gcc / tree-cfg.c
index af277b7..9558546 100644 (file)
@@ -1,6 +1,5 @@
 /* Control flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011, 2012  Free Software Foundation, Inc.
+   Copyright (C) 2001-2013 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -22,15 +21,41 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "hash-table.h"
 #include "tm.h"
 #include "tree.h"
+#include "trans-mem.h"
+#include "stor-layout.h"
+#include "print-tree.h"
 #include "tm_p.h"
 #include "basic-block.h"
 #include "flags.h"
 #include "function.h"
-#include "ggc.h"
 #include "gimple-pretty-print.h"
-#include "tree-flow.h"
+#include "pointer-set.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-walk.h"
+#include "gimple-ssa.h"
+#include "cgraph.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-into-ssa.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "tree-dump.h"
 #include "tree-pass.h"
 #include "diagnostic-core.h"
@@ -38,9 +63,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "tree-ssa-propagate.h"
 #include "value-prof.h"
-#include "pointer-set.h"
 #include "tree-inline.h"
 #include "target.h"
+#include "tree-ssa-live.h"
+#include "omp-low.h"
+#include "tree-cfgcleanup.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -88,7 +115,36 @@ struct locus_discrim_map
   location_t locus;
   int discriminator;
 };
-static htab_t discriminator_per_locus;
+
+/* Hashtable helpers.  */
+
+struct locus_discrim_hasher : typed_free_remove <locus_discrim_map>
+{
+  typedef locus_discrim_map value_type;
+  typedef locus_discrim_map compare_type;
+  static inline hashval_t hash (const value_type *);
+  static inline bool equal (const value_type *, const compare_type *);
+};
+
+/* Trivial hash function for a location_t.  ITEM is a pointer to
+   a hash table entry that maps a location_t to a discriminator.  */
+
+inline hashval_t
+locus_discrim_hasher::hash (const value_type *item)
+{
+  return LOCATION_LINE (item->locus);
+}
+
+/* Equality function for the locus-to-discriminator map.  A and B
+   point to the two hash table entries to compare.  */
+
+inline bool
+locus_discrim_hasher::equal (const value_type *a, const compare_type *b)
+{
+  return LOCATION_LINE (a->locus) == LOCATION_LINE (b->locus);
+}
+
+static hash_table <locus_discrim_hasher> discriminator_per_locus;
 
 /* Basic blocks and flowgraphs.  */
 static void make_blocks (gimple_seq);
@@ -96,13 +152,11 @@ static void factor_computed_gotos (void);
 
 /* Edges.  */
 static void make_edges (void);
+static void assign_discriminators (void);
 static void make_cond_expr_edges (basic_block);
 static void make_gimple_switch_edges (basic_block);
 static void make_goto_expr_edges (basic_block);
 static void make_gimple_asm_edges (basic_block);
-static unsigned int locus_map_hash (const void *);
-static int locus_map_eq (const void *, const void *);
-static void assign_discriminator (location_t, basic_block);
 static edge gimple_redirect_edge_and_branch (edge, basic_block);
 static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
 static unsigned int split_critical_edges (void);
@@ -111,7 +165,6 @@ static unsigned int split_critical_edges (void);
 static inline bool stmt_starts_bb_p (gimple, gimple);
 static int gimple_verify_flow_info (void);
 static void gimple_make_forwarder_block (edge);
-static void gimple_cfg2vcg (FILE *);
 static gimple first_non_label_stmt (basic_block);
 static bool verify_gimple_transaction (gimple);
 
@@ -129,31 +182,25 @@ init_empty_tree_cfg_for_function (struct function *fn)
 {
   /* Initialize the basic block array.  */
   init_flow (fn);
-  profile_status_for_function (fn) = PROFILE_ABSENT;
-  n_basic_blocks_for_function (fn) = NUM_FIXED_BLOCKS;
-  last_basic_block_for_function (fn) = NUM_FIXED_BLOCKS;
-  basic_block_info_for_function (fn)
-    = VEC_alloc (basic_block, gc, initial_cfg_capacity);
-  VEC_safe_grow_cleared (basic_block, gc,
-                        basic_block_info_for_function (fn),
+  profile_status_for_fn (fn) = PROFILE_ABSENT;
+  n_basic_blocks_for_fn (fn) = NUM_FIXED_BLOCKS;
+  last_basic_block_for_fn (fn) = NUM_FIXED_BLOCKS;
+  vec_alloc (basic_block_info_for_fn (fn), initial_cfg_capacity);
+  vec_safe_grow_cleared (basic_block_info_for_fn (fn),
                         initial_cfg_capacity);
 
   /* Build a mapping of labels to their associated blocks.  */
-  label_to_block_map_for_function (fn)
-    = VEC_alloc (basic_block, gc, initial_cfg_capacity);
-  VEC_safe_grow_cleared (basic_block, gc,
-                        label_to_block_map_for_function (fn),
+  vec_alloc (label_to_block_map_for_fn (fn), initial_cfg_capacity);
+  vec_safe_grow_cleared (label_to_block_map_for_fn (fn),
                         initial_cfg_capacity);
 
-  SET_BASIC_BLOCK_FOR_FUNCTION (fn, ENTRY_BLOCK,
-                               ENTRY_BLOCK_PTR_FOR_FUNCTION (fn));
-  SET_BASIC_BLOCK_FOR_FUNCTION (fn, EXIT_BLOCK,
-                  EXIT_BLOCK_PTR_FOR_FUNCTION (fn));
+  SET_BASIC_BLOCK_FOR_FN (fn, ENTRY_BLOCK, ENTRY_BLOCK_PTR_FOR_FN (fn));
+  SET_BASIC_BLOCK_FOR_FN (fn, EXIT_BLOCK, EXIT_BLOCK_PTR_FOR_FN (fn));
 
-  ENTRY_BLOCK_PTR_FOR_FUNCTION (fn)->next_bb
-    = EXIT_BLOCK_PTR_FOR_FUNCTION (fn);
-  EXIT_BLOCK_PTR_FOR_FUNCTION (fn)->prev_bb
-    = ENTRY_BLOCK_PTR_FOR_FUNCTION (fn);
+  ENTRY_BLOCK_PTR_FOR_FN (fn)->next_bb
+    = EXIT_BLOCK_PTR_FOR_FN (fn);
+  EXIT_BLOCK_PTR_FOR_FN (fn)->prev_bb
+    = ENTRY_BLOCK_PTR_FOR_FN (fn);
 }
 
 void
@@ -191,12 +238,14 @@ build_gimple_cfg (gimple_seq seq)
     factor_computed_gotos ();
 
   /* Make sure there is always at least one block, even if it's empty.  */
-  if (n_basic_blocks == NUM_FIXED_BLOCKS)
-    create_empty_bb (ENTRY_BLOCK_PTR);
+  if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS)
+    create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
   /* Adjust the size of the array.  */
-  if (VEC_length (basic_block, basic_block_info) < (size_t) n_basic_blocks)
-    VEC_safe_grow_cleared (basic_block, gc, basic_block_info, n_basic_blocks);
+  if (basic_block_info_for_fn (cfun)->length ()
+      < (size_t) n_basic_blocks_for_fn (cfun))
+    vec_safe_grow_cleared (basic_block_info_for_fn (cfun),
+                          n_basic_blocks_for_fn (cfun));
 
   /* To speed up statement iterator walks, we first purge dead labels.  */
   cleanup_dead_labels ();
@@ -207,26 +256,78 @@ build_gimple_cfg (gimple_seq seq)
   group_case_labels ();
 
   /* Create the edges of the flowgraph.  */
-  discriminator_per_locus = htab_create (13, locus_map_hash, locus_map_eq,
-                                         free);
+  discriminator_per_locus.create (13);
   make_edges ();
+  assign_discriminators ();
   cleanup_dead_labels ();
-  htab_delete (discriminator_per_locus);
+  discriminator_per_locus.dispose ();
+}
 
-  /* Debugging dumps.  */
 
-  /* Write the flowgraph to a VCG file.  */
-  {
-    int local_dump_flags;
-    FILE *vcg_file = dump_begin (TDI_vcg, &local_dump_flags);
-    if (vcg_file)
-      {
-       gimple_cfg2vcg (vcg_file);
-       dump_end (TDI_vcg, vcg_file);
-      }
-  }
+/* Search for ANNOTATE call with annot_expr_ivdep_kind; if found, remove
+   it and set loop->safelen to INT_MAX.  We assume that the annotation
+   comes immediately before the condition.  */
+
+static void
+replace_loop_annotate ()
+{
+  struct loop *loop;
+  basic_block bb;
+  gimple_stmt_iterator gsi;
+  gimple stmt;
+
+  FOR_EACH_LOOP (loop, 0)
+    {
+      gsi = gsi_last_bb (loop->header);
+      stmt = gsi_stmt (gsi);
+      if (stmt && gimple_code (stmt) == GIMPLE_COND)
+       {
+         gsi_prev_nondebug (&gsi);
+         if (gsi_end_p (gsi))
+           continue;
+         stmt = gsi_stmt (gsi);
+         if (gimple_code (stmt) != GIMPLE_CALL)
+               continue;
+         if (!gimple_call_internal_p (stmt)
+                 || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
+           continue;
+         if ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1))
+             != annot_expr_ivdep_kind)
+           continue;
+         stmt = gimple_build_assign (gimple_call_lhs (stmt),
+                                     gimple_call_arg (stmt, 0));
+         gsi_replace (&gsi, stmt, true);
+         loop->safelen = INT_MAX;
+       }
+    }
+
+  /* Remove IFN_ANNOTATE. Safeguard for the case loop->latch == NULL.  */
+  FOR_EACH_BB (bb)
+    {
+      gsi = gsi_last_bb (bb);
+      stmt = gsi_stmt (gsi);
+      if (stmt && gimple_code (stmt) == GIMPLE_COND)
+       gsi_prev_nondebug (&gsi);
+      if (gsi_end_p (gsi))
+       continue;
+      stmt = gsi_stmt (gsi);
+      if (gimple_code (stmt) != GIMPLE_CALL)
+       continue;
+      if (!gimple_call_internal_p (stmt)
+         || gimple_call_internal_fn (stmt) != IFN_ANNOTATE)
+       continue;
+      if ((annot_expr_kind) tree_to_shwi (gimple_call_arg (stmt, 1))
+         != annot_expr_ivdep_kind)
+       continue;
+      warning_at (gimple_location (stmt), 0, "ignoring %<GCC ivdep%> "
+                 "annotation");
+      stmt = gimple_build_assign (gimple_call_lhs (stmt),
+                                 gimple_call_arg (stmt, 0));
+      gsi_replace (&gsi, stmt, true);
+    }
 }
 
+
 static unsigned int
 execute_build_cfg (void)
 {
@@ -239,28 +340,49 @@ execute_build_cfg (void)
       fprintf (dump_file, "Scope blocks:\n");
       dump_scope_blocks (dump_file, dump_flags);
     }
+  cleanup_tree_cfg ();
+  loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+  replace_loop_annotate ();
   return 0;
 }
 
-struct gimple_opt_pass pass_build_cfg =
-{
- {
-  GIMPLE_PASS,
-  "cfg",                               /* name */
-  NULL,                                        /* gate */
-  execute_build_cfg,                   /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_CFG,                         /* tv_id */
-  PROP_gimple_leh,                     /* properties_required */
-  PROP_cfg,                            /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_verify_stmts | TODO_cleanup_cfg  /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_build_cfg =
+{
+  GIMPLE_PASS, /* type */
+  "cfg", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_TREE_CFG, /* tv_id */
+  PROP_gimple_leh, /* properties_required */
+  ( PROP_cfg | PROP_loops ), /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_verify_stmts, /* todo_flags_finish */
 };
 
+class pass_build_cfg : public gimple_opt_pass
+{
+public:
+  pass_build_cfg (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_build_cfg, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  unsigned int execute () { return execute_build_cfg (); }
+
+}; // class pass_build_cfg
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_build_cfg (gcc::context *ctxt)
+{
+  return new pass_build_cfg (ctxt);
+}
+
 
 /* Return true if T is a computed goto.  */
 
@@ -271,6 +393,50 @@ computed_goto_p (gimple t)
          && TREE_CODE (gimple_goto_dest (t)) != LABEL_DECL);
 }
 
+/* Returns true for edge E where e->src ends with a GIMPLE_COND and
+   the other edge points to a bb with just __builtin_unreachable ().
+   I.e. return true for C->M edge in:
+   <bb C>:
+   ...
+   if (something)
+     goto <bb N>;
+   else
+     goto <bb M>;
+   <bb N>:
+   __builtin_unreachable ();
+   <bb M>:  */
+
+bool
+assert_unreachable_fallthru_edge_p (edge e)
+{
+  basic_block pred_bb = e->src;
+  gimple last = last_stmt (pred_bb);
+  if (last && gimple_code (last) == GIMPLE_COND)
+    {
+      basic_block other_bb = EDGE_SUCC (pred_bb, 0)->dest;
+      if (other_bb == e->dest)
+       other_bb = EDGE_SUCC (pred_bb, 1)->dest;
+      if (EDGE_COUNT (other_bb->succs) == 0)
+       {
+         gimple_stmt_iterator gsi = gsi_after_labels (other_bb);
+         gimple stmt;
+
+         if (gsi_end_p (gsi))
+           return false;
+         stmt = gsi_stmt (gsi);
+         if (is_gimple_debug (stmt))
+           {
+             gsi_next_nondebug (&gsi);
+             if (gsi_end_p (gsi))
+               return false;
+             stmt = gsi_stmt (gsi);
+           }
+         return gimple_call_builtin_p (stmt, BUILT_IN_UNREACHABLE);
+       }
+    }
+  return false;
+}
+
 
 /* Search the CFG for any computed gotos.  If found, factor them to a
    common computed goto site.  Also record the location of that site so
@@ -357,7 +523,7 @@ make_blocks (gimple_seq seq)
   gimple stmt = NULL;
   bool start_new_block = true;
   bool first_stmt_of_seq = true;
-  basic_block bb = ENTRY_BLOCK_PTR;
+  basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
 
   while (!gsi_end_p (i))
     {
@@ -439,16 +605,16 @@ create_bb (void *h, void *e, basic_block after)
   link_block (bb, after);
 
   /* Grow the basic block array if needed.  */
-  if ((size_t) last_basic_block == VEC_length (basic_block, basic_block_info))
+  if ((size_t) last_basic_block == basic_block_info_for_fn (cfun)->length ())
     {
       size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
-      VEC_safe_grow_cleared (basic_block, gc, basic_block_info, new_size);
+      vec_safe_grow_cleared (basic_block_info_for_fn (cfun), new_size);
     }
 
   /* Add the newly created block to the array.  */
-  SET_BASIC_BLOCK (last_basic_block, bb);
+  SET_BASIC_BLOCK_FOR_FN (cfun, last_basic_block, bb);
 
-  n_basic_blocks++;
+  n_basic_blocks_for_fn (cfun)++;
   last_basic_block++;
 
   return bb;
@@ -508,7 +674,9 @@ make_edges (void)
 
   /* Create an edge from entry to the first block with executable
      statements in it.  */
-  make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (NUM_FIXED_BLOCKS), EDGE_FALLTHRU);
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun),
+            BASIC_BLOCK_FOR_FN (cfun, NUM_FIXED_BLOCKS),
+            EDGE_FALLTHRU);
 
   /* Traverse the basic block array placing edges.  */
   FOR_EACH_BB (bb)
@@ -526,7 +694,7 @@ make_edges (void)
              fallthru = false;
              break;
            case GIMPLE_RETURN:
-             make_edge (bb, EXIT_BLOCK_PTR, 0);
+             make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
              fallthru = false;
              break;
            case GIMPLE_COND:
@@ -558,7 +726,8 @@ make_edges (void)
 
              /* BUILTIN_RETURN is really a return statement.  */
              if (gimple_call_builtin_p (last, BUILT_IN_RETURN))
-               make_edge (bb, EXIT_BLOCK_PTR, 0), fallthru = false;
+               make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0), fallthru =
+            false;
              /* Some calls are known not to return.  */
              else
                fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
@@ -577,95 +746,15 @@ make_edges (void)
              fallthru = true;
              break;
 
-           case GIMPLE_OMP_PARALLEL:
-           case GIMPLE_OMP_TASK:
-           case GIMPLE_OMP_FOR:
-           case GIMPLE_OMP_SINGLE:
-           case GIMPLE_OMP_MASTER:
-           case GIMPLE_OMP_ORDERED:
-           case GIMPLE_OMP_CRITICAL:
-           case GIMPLE_OMP_SECTION:
-             cur_region = new_omp_region (bb, code, cur_region);
-             fallthru = true;
-             break;
-
-           case GIMPLE_OMP_SECTIONS:
-             cur_region = new_omp_region (bb, code, cur_region);
-             fallthru = true;
-             break;
-
-           case GIMPLE_OMP_SECTIONS_SWITCH:
-             fallthru = false;
-             break;
-
-            case GIMPLE_OMP_ATOMIC_LOAD:
-            case GIMPLE_OMP_ATOMIC_STORE:
-               fallthru = true;
-               break;
-
-           case GIMPLE_OMP_RETURN:
-             /* In the case of a GIMPLE_OMP_SECTION, the edge will go
-                somewhere other than the next block.  This will be
-                created later.  */
-             cur_region->exit = bb;
-             fallthru = cur_region->type != GIMPLE_OMP_SECTION;
-             cur_region = cur_region->outer;
-             break;
-
-           case GIMPLE_OMP_CONTINUE:
-             cur_region->cont = bb;
-             switch (cur_region->type)
-               {
-               case GIMPLE_OMP_FOR:
-                 /* Mark all GIMPLE_OMP_FOR and GIMPLE_OMP_CONTINUE
-                    succs edges as abnormal to prevent splitting
-                    them.  */
-                 single_succ_edge (cur_region->entry)->flags |= EDGE_ABNORMAL;
-                 /* Make the loopback edge.  */
-                 make_edge (bb, single_succ (cur_region->entry),
-                            EDGE_ABNORMAL);
-
-                 /* Create an edge from GIMPLE_OMP_FOR to exit, which
-                    corresponds to the case that the body of the loop
-                    is not executed at all.  */
-                 make_edge (cur_region->entry, bb->next_bb, EDGE_ABNORMAL);
-                 make_edge (bb, bb->next_bb, EDGE_FALLTHRU | EDGE_ABNORMAL);
-                 fallthru = false;
-                 break;
-
-               case GIMPLE_OMP_SECTIONS:
-                 /* Wire up the edges into and out of the nested sections.  */
-                 {
-                   basic_block switch_bb = single_succ (cur_region->entry);
-
-                   struct omp_region *i;
-                   for (i = cur_region->inner; i ; i = i->next)
-                     {
-                       gcc_assert (i->type == GIMPLE_OMP_SECTION);
-                       make_edge (switch_bb, i->entry, 0);
-                       make_edge (i->exit, bb, EDGE_FALLTHRU);
-                     }
-
-                   /* Make the loopback edge to the block with
-                      GIMPLE_OMP_SECTIONS_SWITCH.  */
-                   make_edge (bb, switch_bb, 0);
-
-                   /* Make the edge from the switch to exit.  */
-                   make_edge (switch_bb, bb->next_bb, 0);
-                   fallthru = false;
-                 }
-                 break;
-
-               default:
-                 gcc_unreachable ();
-               }
+           CASE_GIMPLE_OMP:
+             fallthru = make_gimple_omp_edges (bb, &cur_region);
              break;
 
            case GIMPLE_TRANSACTION:
              {
                tree abort_label = gimple_transaction_label (last);
                if (abort_label)
-                 make_edge (bb, label_to_block (abort_label), 0);
+                 make_edge (bb, label_to_block (abort_label), EDGE_TM_ABORT);
                fallthru = true;
              }
              break;
@@ -679,40 +768,15 @@ make_edges (void)
        fallthru = true;
 
       if (fallthru)
-        {
-         make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-         if (last)
-            assign_discriminator (gimple_location (last), bb->next_bb);
-       }
+       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
     }
 
-  if (root_omp_region)
-    free_omp_regions ();
+  free_omp_regions ();
 
   /* Fold COND_EXPR_COND of each COND_EXPR.  */
   fold_cond_expr_cond ();
 }
 
-/* Trivial hash function for a location_t.  ITEM is a pointer to
-   a hash table entry that maps a location_t to a discriminator.  */
-
-static unsigned int
-locus_map_hash (const void *item)
-{
-  return ((const struct locus_discrim_map *) item)->locus;
-}
-
-/* Equality function for the locus-to-discriminator map.  VA and VB
-   point to the two hash table entries to compare.  */
-
-static int
-locus_map_eq (const void *va, const void *vb)
-{
-  const struct locus_discrim_map *a = (const struct locus_discrim_map *) va;
-  const struct locus_discrim_map *b = (const struct locus_discrim_map *) vb;
-  return a->locus == b->locus;
-}
-
 /* Find the next available discriminator value for LOCUS.  The
    discriminator distinguishes among several basic blocks that
    share a common locus, allowing for more accurate sample-based
@@ -726,9 +790,8 @@ next_discriminator_for_locus (location_t locus)
 
   item.locus = locus;
   item.discriminator = 0;
-  slot = (struct locus_discrim_map **)
-      htab_find_slot_with_hash (discriminator_per_locus, (void *) &item,
-                                (hashval_t) locus, INSERT);
+  slot = discriminator_per_locus.find_slot_with_hash (
+      &item, LOCATION_LINE (locus), INSERT);
   gcc_assert (slot);
   if (*slot == HTAB_EMPTY_ENTRY)
     {
@@ -763,22 +826,37 @@ same_line_p (location_t locus1, location_t locus2)
           && filename_cmp (from.file, to.file) == 0);
 }
 
-/* Assign a unique discriminator value to block BB if it begins at the same
-   LOCUS as its predecessor block.  */
+/* Assign discriminators to each basic block.  */
 
 static void
-assign_discriminator (location_t locus, basic_block bb)
+assign_discriminators (void)
 {
-  gimple first_in_to_bb, last_in_to_bb;
+  basic_block bb;
 
-  if (locus == 0 || bb->discriminator != 0)
-    return;
+  FOR_EACH_BB (bb)
+    {
+      edge e;
+      edge_iterator ei;
+      gimple last = last_stmt (bb);
+      location_t locus = last ? gimple_location (last) : UNKNOWN_LOCATION;
+
+      if (locus == UNKNOWN_LOCATION)
+       continue;
 
-  first_in_to_bb = first_non_label_stmt (bb);
-  last_in_to_bb = last_stmt (bb);
-  if ((first_in_to_bb && same_line_p (locus, gimple_location (first_in_to_bb)))
-      || (last_in_to_bb && same_line_p (locus, gimple_location (last_in_to_bb))))
-    bb->discriminator = next_discriminator_for_locus (locus);
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       {
+         gimple first = first_non_label_stmt (e->dest);
+         gimple last = last_stmt (e->dest);
+         if ((first && same_line_p (locus, gimple_location (first)))
+             || (last && same_line_p (locus, gimple_location (last))))
+           {
+             if (e->dest->discriminator != 0 && bb->discriminator == 0)
+               bb->discriminator = next_discriminator_for_locus (locus);
+             else
+               e->dest->discriminator = next_discriminator_for_locus (locus);
+           }
+       }
+    }
 }
 
 /* Create the edges for a GIMPLE_COND starting at block BB.  */
@@ -791,13 +869,10 @@ make_cond_expr_edges (basic_block bb)
   basic_block then_bb, else_bb;
   tree then_label, else_label;
   edge e;
-  location_t entry_locus;
 
   gcc_assert (entry);
   gcc_assert (gimple_code (entry) == GIMPLE_COND);
 
-  entry_locus = gimple_location (entry);
-
   /* Entry basic blocks for each component.  */
   then_label = gimple_cond_true_label (entry);
   else_label = gimple_cond_false_label (entry);
@@ -807,14 +882,10 @@ make_cond_expr_edges (basic_block bb)
   else_stmt = first_stmt (else_bb);
 
   e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
-  assign_discriminator (entry_locus, then_bb);
   e->goto_locus = gimple_location (then_stmt);
   e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
   if (e)
-    {
-      assign_discriminator (entry_locus, else_bb);
-      e->goto_locus = gimple_location (else_stmt);
-    }
+    e->goto_locus = gimple_location (else_stmt);
 
   /* We do not need the labels anymore.  */
   gimple_cond_set_true_label (entry, NULL_TREE);
@@ -875,7 +946,7 @@ end_recording_case_labels (void)
   edge_to_cases = NULL;
   EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
       if (bb)
        {
          gimple stmt = last_stmt (bb);
@@ -934,11 +1005,8 @@ static void
 make_gimple_switch_edges (basic_block bb)
 {
   gimple entry = last_stmt (bb);
-  location_t entry_locus;
   size_t i, n;
 
-  entry_locus = gimple_location (entry);
-
   n = gimple_switch_num_labels (entry);
 
   for (i = 0; i < n; ++i)
@@ -946,7 +1014,6 @@ make_gimple_switch_edges (basic_block bb)
       tree lab = CASE_LABEL (gimple_switch_label (entry, i));
       basic_block label_bb = label_to_block (lab);
       make_edge (bb, label_bb, 0);
-      assign_discriminator (entry_locus, label_bb);
     }
 }
 
@@ -963,17 +1030,17 @@ label_to_block_fn (struct function *ifun, tree dest)
      and undefined variable warnings quite right.  */
   if (seen_error () && uid < 0)
     {
-      gimple_stmt_iterator gsi = gsi_start_bb (BASIC_BLOCK (NUM_FIXED_BLOCKS));
+      gimple_stmt_iterator gsi =
+       gsi_start_bb (BASIC_BLOCK_FOR_FN (cfun, NUM_FIXED_BLOCKS));
       gimple stmt;
 
       stmt = gimple_build_label (dest);
       gsi_insert_before (&gsi, stmt, GSI_NEW_STMT);
       uid = LABEL_DECL_UID (dest);
     }
-  if (VEC_length (basic_block, ifun->cfg->x_label_to_block_map)
-      <= (unsigned int) uid)
+  if (vec_safe_length (ifun->cfg->x_label_to_block_map) <= (unsigned int) uid)
     return NULL;
-  return VEC_index (basic_block, ifun->cfg->x_label_to_block_map, uid);
+  return (*ifun->cfg->x_label_to_block_map)[uid];
 }
 
 /* Create edges for an abnormal goto statement at block BB.  If FOR_CALL
@@ -986,25 +1053,38 @@ make_abnormal_goto_edges (basic_block bb, bool for_call)
   gimple_stmt_iterator gsi;
 
   FOR_EACH_BB (target_bb)
-    for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
-      {
-       gimple label_stmt = gsi_stmt (gsi);
-       tree target;
+    {
+      for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple label_stmt = gsi_stmt (gsi);
+         tree target;
 
-       if (gimple_code (label_stmt) != GIMPLE_LABEL)
-         break;
+         if (gimple_code (label_stmt) != GIMPLE_LABEL)
+           break;
 
-       target = gimple_label_label (label_stmt);
+         target = gimple_label_label (label_stmt);
 
-       /* Make an edge to every label block that has been marked as a
-          potential target for a computed goto or a non-local goto.  */
-       if ((FORCED_LABEL (target) && !for_call)
-           || (DECL_NONLOCAL (target) && for_call))
-         {
+         /* Make an edge to every label block that has been marked as a
+            potential target for a computed goto or a non-local goto.  */
+         if ((FORCED_LABEL (target) && !for_call)
+             || (DECL_NONLOCAL (target) && for_call))
+           {
+             make_edge (bb, target_bb, EDGE_ABNORMAL);
+             break;
+           }
+       }
+      if (!gsi_end_p (gsi)
+         && is_gimple_debug (gsi_stmt (gsi)))
+       gsi_next_nondebug (&gsi);
+      if (!gsi_end_p (gsi))
+       {
+         /* Make an edge to every setjmp-like call.  */
+         gimple call_stmt = gsi_stmt (gsi);
+         if (is_gimple_call (call_stmt)
+             && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE))
            make_edge (bb, target_bb, EDGE_ABNORMAL);
-           break;
-         }
-      }
+       }
+    }
 }
 
 /* Create edges for a goto statement at block BB.  */
@@ -1022,7 +1102,6 @@ make_goto_expr_edges (basic_block bb)
       basic_block label_bb = label_to_block (dest);
       edge e = make_edge (bb, label_bb, EDGE_FALLTHRU);
       e->goto_locus = gimple_location (goto_t);
-      assign_discriminator (e->goto_locus, label_bb);
       gsi_remove (&last, true);
       return;
     }
@@ -1037,7 +1116,6 @@ static void
 make_gimple_asm_edges (basic_block bb)
 {
   gimple stmt = last_stmt (bb);
-  location_t stmt_loc = gimple_location (stmt);
   int i, n = gimple_asm_nlabels (stmt);
 
   for (i = 0; i < n; ++i)
@@ -1045,7 +1123,6 @@ make_gimple_asm_edges (basic_block bb)
       tree label = TREE_VALUE (gimple_asm_label_op (stmt, i));
       basic_block label_bb = label_to_block (label);
       make_edge (bb, label_bb, 0);
-      assign_discriminator (stmt_loc, label_bb);
     }
 }
 
@@ -1103,7 +1180,7 @@ cleanup_dead_labels_eh (void)
   if (cfun->eh == NULL)
     return;
 
-  for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i)
+  for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
     if (lp && lp->post_landing_pad)
       {
        lab = main_block_label (lp->post_landing_pad);
@@ -1435,7 +1512,7 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
   if (!single_pred_p (b))
     return false;
 
-  if (b == EXIT_BLOCK_PTR)
+  if (b == EXIT_BLOCK_PTR_FOR_FN (cfun))
     return false;
 
   /* If A ends by a statement causing exceptions or something similar, we
@@ -1499,49 +1576,6 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
   return true;
 }
 
-/* Return true if the var whose chain of uses starts at PTR has no
-   nondebug uses.  */
-bool
-has_zero_uses_1 (const ssa_use_operand_t *head)
-{
-  const ssa_use_operand_t *ptr;
-
-  for (ptr = head->next; ptr != head; ptr = ptr->next)
-    if (!is_gimple_debug (USE_STMT (ptr)))
-      return false;
-
-  return true;
-}
-
-/* Return true if the var whose chain of uses starts at PTR has a
-   single nondebug use.  Set USE_P and STMT to that single nondebug
-   use, if so, or to NULL otherwise.  */
-bool
-single_imm_use_1 (const ssa_use_operand_t *head,
-                 use_operand_p *use_p, gimple *stmt)
-{
-  ssa_use_operand_t *ptr, *single_use = 0;
-
-  for (ptr = head->next; ptr != head; ptr = ptr->next)
-    if (!is_gimple_debug (USE_STMT (ptr)))
-      {
-       if (single_use)
-         {
-           single_use = NULL;
-           break;
-         }
-       single_use = ptr;
-      }
-
-  if (use_p)
-    *use_p = single_use;
-
-  if (stmt)
-    *stmt = single_use ? single_use->loc.stmt : NULL;
-
-  return !!single_use;
-}
-
 /* Replaces all uses of NAME by VAL.  */
 
 void
@@ -1614,9 +1648,8 @@ replace_uses_by (tree name, tree val)
   if (current_loops)
     {
       struct loop *loop;
-      loop_iterator li;
 
-      FOR_EACH_LOOP (li, loop, 0)
+      FOR_EACH_LOOP (loop, 0)
        {
          substitute_in_loop_info (loop, name, val);
        }
@@ -2053,15 +2086,15 @@ gimple_debug_bb (basic_block bb)
 basic_block
 gimple_debug_bb_n (int n)
 {
-  gimple_debug_bb (BASIC_BLOCK (n));
-  return BASIC_BLOCK (n);
+  gimple_debug_bb (BASIC_BLOCK_FOR_FN (cfun, n));
+  return BASIC_BLOCK_FOR_FN (cfun, n);
 }
 
 
 /* Dump the CFG on stderr.
 
    FLAGS are the same used by the tree dumping functions
-   (see TDF_* in tree-pass.h).  */
+   (see TDF_* in dumpfile.h).  */
 
 void
 gimple_debug_cfg (int flags)
@@ -2082,7 +2115,8 @@ gimple_dump_cfg (FILE *file, int flags)
     {
       dump_function_header (file, current_function_decl, flags);
       fprintf (file, ";; \n%d basic blocks, %d edges, last basic block %d.\n\n",
-              n_basic_blocks, n_edges, last_basic_block);
+              n_basic_blocks_for_fn (cfun), n_edges_for_fn (cfun),
+              last_basic_block);
 
       brief_dump_cfg (file, flags | TDF_COMMENT);
       fprintf (file, "\n");
@@ -2117,9 +2151,9 @@ dump_cfg_stats (FILE *file)
   fprintf (file, fmt_str, "", "  instances  ", "used ");
   fprintf (file, "---------------------------------------------------------\n");
 
-  size = n_basic_blocks * sizeof (struct basic_block_def);
+  size = n_basic_blocks_for_fn (cfun) * sizeof (struct basic_block_def);
   total += size;
-  fprintf (file, fmt_str_1, "Basic blocks", n_basic_blocks,
+  fprintf (file, fmt_str_1, "Basic blocks", n_basic_blocks_for_fn (cfun),
           SCALE (size), LABEL (size));
 
   num_edges = 0;
@@ -2154,92 +2188,6 @@ debug_cfg_stats (void)
   dump_cfg_stats (stderr);
 }
 
-
-/* Dump the flowgraph to a .vcg FILE.  */
-
-static void
-gimple_cfg2vcg (FILE *file)
-{
-  edge e;
-  edge_iterator ei;
-  basic_block bb;
-  const char *funcname = current_function_name ();
-
-  /* Write the file header.  */
-  fprintf (file, "graph: { title: \"%s\"\n", funcname);
-  fprintf (file, "node: { title: \"ENTRY\" label: \"ENTRY\" }\n");
-  fprintf (file, "node: { title: \"EXIT\" label: \"EXIT\" }\n");
-
-  /* Write blocks and edges.  */
-  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
-    {
-      fprintf (file, "edge: { sourcename: \"ENTRY\" targetname: \"%d\"",
-              e->dest->index);
-
-      if (e->flags & EDGE_FAKE)
-       fprintf (file, " linestyle: dotted priority: 10");
-      else
-       fprintf (file, " linestyle: solid priority: 100");
-
-      fprintf (file, " }\n");
-    }
-  fputc ('\n', file);
-
-  FOR_EACH_BB (bb)
-    {
-      enum gimple_code head_code, end_code;
-      const char *head_name, *end_name;
-      int head_line = 0;
-      int end_line = 0;
-      gimple first = first_stmt (bb);
-      gimple last = last_stmt (bb);
-
-      if (first)
-       {
-         head_code = gimple_code (first);
-         head_name = gimple_code_name[head_code];
-         head_line = get_lineno (first);
-       }
-      else
-       head_name = "no-statement";
-
-      if (last)
-       {
-         end_code = gimple_code (last);
-         end_name = gimple_code_name[end_code];
-         end_line = get_lineno (last);
-       }
-      else
-       end_name = "no-statement";
-
-      fprintf (file, "node: { title: \"%d\" label: \"#%d\\n%s (%d)\\n%s (%d)\"}\n",
-              bb->index, bb->index, head_name, head_line, end_name,
-              end_line);
-
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       {
-         if (e->dest == EXIT_BLOCK_PTR)
-           fprintf (file, "edge: { sourcename: \"%d\" targetname: \"EXIT\"", bb->index);
-         else
-           fprintf (file, "edge: { sourcename: \"%d\" targetname: \"%d\"", bb->index, e->dest->index);
-
-         if (e->flags & EDGE_FAKE)
-           fprintf (file, " priority: 10 linestyle: dotted");
-         else
-           fprintf (file, " priority: 100 linestyle: solid");
-
-         fprintf (file, " }\n");
-       }
-
-      if (bb->next_bb != EXIT_BLOCK_PTR)
-       fputc ('\n', file);
-    }
-
-  fputs ("}\n\n", file);
-}
-
-
-
 /*---------------------------------------------------------------------------
                             Miscellaneous helpers
 ---------------------------------------------------------------------------*/
@@ -2252,7 +2200,8 @@ call_can_make_abnormal_goto (gimple t)
 {
   /* If the function has no non-local labels, then a call cannot make an
      abnormal transfer of control.  */
-  if (!cfun->has_nonlocal_label)
+  if (!cfun->has_nonlocal_label
+      && !cfun->calls_setjmp)
    return false;
 
   /* Likewise if the call has no side effects.  */
@@ -2407,6 +2356,11 @@ stmt_starts_bb_p (gimple stmt, gimple prev_stmt)
       else
        return true;
     }
+  else if (gimple_code (stmt) == GIMPLE_CALL
+          && gimple_call_flags (stmt) & ECF_RETURNS_TWICE)
+    /* setjmp acts similar to a nonlocal GOTO target and thus should
+       start a new block.  */
+    return true;
 
   return false;
 }
@@ -2425,7 +2379,7 @@ stmt_ends_bb_p (gimple t)
 void
 delete_tree_cfg_annotations (void)
 {
-  label_to_block_map = NULL;
+  vec_free (label_to_block_map);
 }
 
 
@@ -2509,7 +2463,7 @@ last_and_only_stmt (basic_block bb)
 static void
 reinstall_phi_args (edge new_edge, edge old_edge)
 {
-  edge_var_map_vector v;
+  edge_var_map_vector *v;
   edge_var_map *vm;
   int i;
   gimple_stmt_iterator phis;
@@ -2519,7 +2473,7 @@ reinstall_phi_args (edge new_edge, edge old_edge)
     return;
 
   for (i = 0, phis = gsi_start_phis (new_edge->dest);
-       VEC_iterate (edge_var_map, v, i, vm) && !gsi_end_p (phis);
+       v->iterate (i, &vm) && !gsi_end_p (phis);
        i++, gsi_next (&phis))
     {
       gimple phi = gsi_stmt (phis);
@@ -2751,10 +2705,56 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
+    case BIT_FIELD_REF:
+      if (!is_gimple_reg_type (TREE_TYPE (t)))
+       {
+         error ("non-scalar BIT_FIELD_REF, IMAGPART_EXPR or REALPART_EXPR");
+         return t;
+       }
+
+      if (TREE_CODE (t) == BIT_FIELD_REF)
+       {
+         tree t0 = TREE_OPERAND (t, 0);
+         tree t1 = TREE_OPERAND (t, 1);
+         tree t2 = TREE_OPERAND (t, 2);
+         if (!tree_fits_uhwi_p (t1)
+             || !tree_fits_uhwi_p (t2))
+           {
+             error ("invalid position or size operand to BIT_FIELD_REF");
+             return t;
+           }
+         if (INTEGRAL_TYPE_P (TREE_TYPE (t))
+             && (TYPE_PRECISION (TREE_TYPE (t))
+                 != tree_to_uhwi (t1)))
+           {
+             error ("integral result type precision does not match "
+                    "field size of BIT_FIELD_REF");
+             return t;
+           }
+         else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+                  && TYPE_MODE (TREE_TYPE (t)) != BLKmode
+                  && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
+                      != tree_to_uhwi (t1)))
+           {
+             error ("mode precision of non-integral result does not "
+                    "match field size of BIT_FIELD_REF");
+             return t;
+           }
+         if (!AGGREGATE_TYPE_P (TREE_TYPE (t0))
+             && (tree_to_uhwi (t1) + tree_to_uhwi (t2)
+                 > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (t0)))))
+           {
+             error ("position plus size exceeds size of referenced object in "
+                    "BIT_FIELD_REF");
+             return t;
+           }
+       }
+      t = TREE_OPERAND (t, 0);
+
+      /* Fall-through.  */
     case COMPONENT_REF:
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
-    case BIT_FIELD_REF:
     case VIEW_CONVERT_EXPR:
       /* We have a nest of references.  Verify that each of the operands
         that determine where to reference is either a constant or a variable,
@@ -2773,32 +2773,13 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
              if (TREE_OPERAND (t, 3))
                CHECK_OP (3, "invalid array stride");
            }
-         else if (TREE_CODE (t) == BIT_FIELD_REF)
+         else if (TREE_CODE (t) == BIT_FIELD_REF
+                  || TREE_CODE (t) == REALPART_EXPR
+                  || TREE_CODE (t) == IMAGPART_EXPR)
            {
-             if (!host_integerp (TREE_OPERAND (t, 1), 1)
-                 || !host_integerp (TREE_OPERAND (t, 2), 1))
-               {
-                 error ("invalid position or size operand to BIT_FIELD_REF");
-                 return t;
-               }
-             if (INTEGRAL_TYPE_P (TREE_TYPE (t))
-                 && (TYPE_PRECISION (TREE_TYPE (t))
-                     != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
-               {
-                 error ("integral result type precision does not match "
-                        "field size of BIT_FIELD_REF");
-                 return t;
-               }
-             else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-                      && !AGGREGATE_TYPE_P (TREE_TYPE (t))
-                      && TYPE_MODE (TREE_TYPE (t)) != BLKmode
-                      && (GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (t)))
-                          != TREE_INT_CST_LOW (TREE_OPERAND (t, 1))))
-               {
-                 error ("mode precision of non-integral result does not "
-                        "match field size of BIT_FIELD_REF");
-                 return t;
-               }
+             error ("non-top-level BIT_FIELD_REF, IMAGPART_EXPR or "
+                    "REALPART_EXPR");
+             return t;
            }
 
          t = TREE_OPERAND (t, 0);
@@ -3270,7 +3251,16 @@ verify_gimple_comparison (tree type, tree op0, tree op1)
   if (INTEGRAL_TYPE_P (type)
       && (TREE_CODE (type) == BOOLEAN_TYPE
          || TYPE_PRECISION (type) == 1))
-    ;
+    {
+      if (TREE_CODE (op0_type) == VECTOR_TYPE
+         || TREE_CODE (op1_type) == VECTOR_TYPE)
+        {
+          error ("vector comparison returning a boolean");
+          debug_generic_expr (op0_type);
+          debug_generic_expr (op1_type);
+          return true;
+        }
+    }
   /* Or an integer vector type with the same size and element count
      as the comparison operand types.  */
   else if (TREE_CODE (type) == VECTOR_TYPE
@@ -3287,7 +3277,10 @@ verify_gimple_comparison (tree type, tree op0, tree op1)
 
       if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)
          || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (type)))
-             != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0_type)))))
+             != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0_type))))
+         /* The result of a vector comparison is of signed
+            integral type.  */
+         || TYPE_UNSIGNED (TREE_TYPE (type)))
         {
           error ("invalid vector comparison resulting type");
           debug_generic_expr (type);
@@ -3398,7 +3391,7 @@ verify_gimple_assign_unary (gimple stmt)
       {
        if ((!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type))
            && (!VECTOR_INTEGER_TYPE_P (rhs1_type)
-               || !VECTOR_FLOAT_TYPE_P(lhs_type)))
+               || !VECTOR_FLOAT_TYPE_P (lhs_type)))
          {
            error ("invalid types in conversion to floating point");
            debug_generic_expr (lhs_type);
@@ -3413,7 +3406,7 @@ verify_gimple_assign_unary (gimple stmt)
       {
         if ((!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type))
             && (!VECTOR_INTEGER_TYPE_P (lhs_type)
-                || !VECTOR_FLOAT_TYPE_P(rhs1_type)))
+                || !VECTOR_FLOAT_TYPE_P (rhs1_type)))
          {
            error ("invalid types in conversion to integer");
            debug_generic_expr (lhs_type);
@@ -3609,11 +3602,10 @@ verify_gimple_assign_binary (gimple stmt)
     case PLUS_EXPR:
     case MINUS_EXPR:
       {
-       /* We use regular PLUS_EXPR and MINUS_EXPR for vectors.
-          ???  This just makes the checker happy and may not be what is
-          intended.  */
-       if (TREE_CODE (lhs_type) == VECTOR_TYPE
-           && POINTER_TYPE_P (TREE_TYPE (lhs_type)))
+       tree lhs_etype = lhs_type;
+       tree rhs1_etype = rhs1_type;
+       tree rhs2_etype = rhs2_type;
+       if (TREE_CODE (lhs_type) == VECTOR_TYPE)
          {
            if (TREE_CODE (rhs1_type) != VECTOR_TYPE
                || TREE_CODE (rhs2_type) != VECTOR_TYPE)
@@ -3621,22 +3613,13 @@ verify_gimple_assign_binary (gimple stmt)
                error ("invalid non-vector operands to vector valued plus");
                return true;
              }
-           lhs_type = TREE_TYPE (lhs_type);
-           rhs1_type = TREE_TYPE (rhs1_type);
-           rhs2_type = TREE_TYPE (rhs2_type);
-           /* PLUS_EXPR is commutative, so we might end up canonicalizing
-              the pointer to 2nd place.  */
-           if (POINTER_TYPE_P (rhs2_type))
-             {
-               tree tem = rhs1_type;
-               rhs1_type = rhs2_type;
-               rhs2_type = tem;
-             }
-           goto do_pointer_plus_expr_check;
+           lhs_etype = TREE_TYPE (lhs_type);
+           rhs1_etype = TREE_TYPE (rhs1_type);
+           rhs2_etype = TREE_TYPE (rhs2_type);
          }
-       if (POINTER_TYPE_P (lhs_type)
-           || POINTER_TYPE_P (rhs1_type)
-           || POINTER_TYPE_P (rhs2_type))
+       if (POINTER_TYPE_P (lhs_etype)
+           || POINTER_TYPE_P (rhs1_etype)
+           || POINTER_TYPE_P (rhs2_etype))
          {
            error ("invalid (pointer) operands to plus/minus");
            return true;
@@ -3648,7 +3631,6 @@ verify_gimple_assign_binary (gimple stmt)
 
     case POINTER_PLUS_EXPR:
       {
-do_pointer_plus_expr_check:
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
            || !ptrofftype_p (rhs2_type))
@@ -3908,9 +3890,9 @@ verify_gimple_assign_single (gimple stmt)
     }
 
   if (gimple_clobber_p (stmt)
-      && !DECL_P (lhs))
+      && !(DECL_P (lhs) || TREE_CODE (lhs) == MEM_REF))
     {
-      error ("non-decl LHS in clobber statement");
+      error ("non-decl/MEM_REF LHS in clobber statement");
       debug_generic_expr (lhs);
       return true;
     }
@@ -4290,12 +4272,16 @@ verify_gimple_label (gimple stmt)
 
   if (TREE_CODE (decl) != LABEL_DECL)
     return true;
+  if (!DECL_NONLOCAL (decl) && !FORCED_LABEL (decl)
+      && DECL_CONTEXT (decl) != current_function_decl)
+    {
+      error ("label's context is not the current function decl");
+      err |= true;
+    }
 
   uid = LABEL_DECL_UID (decl);
   if (cfun->cfg
-      && (uid == -1
-         || VEC_index (basic_block,
-                       label_to_block_map, uid) != gimple_bb (stmt)))
+      && (uid == -1 || (*label_to_block_map)[uid] != gimple_bb (stmt)))
     {
       error ("incorrect entry in label_to_block_map");
       err |= true;
@@ -4534,7 +4520,7 @@ verify_gimple_in_seq (gimple_seq stmts)
 
 /* Return true when the T can be shared.  */
 
-bool
+static bool
 tree_node_can_be_shared (tree t)
 {
   if (IS_TYPE_OR_DECL_P (t)
@@ -4547,26 +4533,18 @@ tree_node_can_be_shared (tree t)
   if (TREE_CODE (t) == CASE_LABEL_EXPR)
     return true;
 
-  while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
-          && is_gimple_min_invariant (TREE_OPERAND (t, 1)))
-        || TREE_CODE (t) == COMPONENT_REF
-        || TREE_CODE (t) == REALPART_EXPR
-        || TREE_CODE (t) == IMAGPART_EXPR)
-    t = TREE_OPERAND (t, 0);
-
   if (DECL_P (t))
     return true;
 
   return false;
 }
 
-/* Called via walk_gimple_stmt.  Verify tree sharing.  */
+/* Called via walk_tree.  Verify tree sharing.  */
 
 static tree
-verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
+verify_node_sharing_1 (tree *tp, int *walk_subtrees, void *data)
 {
-  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
-  struct pointer_set_t *visited = (struct pointer_set_t *) wi->info;
+  struct pointer_set_t *visited = (struct pointer_set_t *) data;
 
   if (tree_node_can_be_shared (*tp))
     {
@@ -4580,6 +4558,15 @@ verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
   return NULL;
 }
 
+/* Called via walk_gimple_stmt.  Verify tree sharing.  */
+
+static tree
+verify_node_sharing (tree *tp, int *walk_subtrees, void *data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  return verify_node_sharing_1 (tp, walk_subtrees, wi->info);
+}
+
 static bool eh_error_found;
 static int
 verify_eh_throw_stmt_node (void **slot, void *data)
@@ -4596,6 +4583,102 @@ verify_eh_throw_stmt_node (void **slot, void *data)
   return 1;
 }
 
+/* Verify if the location LOCs block is in BLOCKS.  */
+
+static bool
+verify_location (pointer_set_t *blocks, location_t loc)
+{
+  tree block = LOCATION_BLOCK (loc);
+  if (block != NULL_TREE
+      && !pointer_set_contains (blocks, block))
+    {
+      error ("location references block not in block tree");
+      return true;
+    }
+  if (block != NULL_TREE)
+    return verify_location (blocks, BLOCK_SOURCE_LOCATION (block));
+  return false;
+}
+
+/* Called via walk_tree.  Verify that expressions have no blocks.  */
+
+static tree
+verify_expr_no_block (tree *tp, int *walk_subtrees, void *)
+{
+  if (!EXPR_P (*tp))
+    {
+      *walk_subtrees = false;
+      return NULL;
+    }
+
+  location_t loc = EXPR_LOCATION (*tp);
+  if (LOCATION_BLOCK (loc) != NULL)
+    return *tp;
+
+  return NULL;
+}
+
+/* Called via walk_tree.  Verify locations of expressions.  */
+
+static tree
+verify_expr_location_1 (tree *tp, int *walk_subtrees, void *data)
+{
+  struct pointer_set_t *blocks = (struct pointer_set_t *) data;
+
+  if (TREE_CODE (*tp) == VAR_DECL
+      && DECL_HAS_DEBUG_EXPR_P (*tp))
+    {
+      tree t = DECL_DEBUG_EXPR (*tp);
+      tree addr = walk_tree (&t, verify_expr_no_block, NULL, NULL);
+      if (addr)
+       return addr;
+    }
+  if ((TREE_CODE (*tp) == VAR_DECL
+       || TREE_CODE (*tp) == PARM_DECL
+       || TREE_CODE (*tp) == RESULT_DECL)
+      && DECL_HAS_VALUE_EXPR_P (*tp))
+    {
+      tree t = DECL_VALUE_EXPR (*tp);
+      tree addr = walk_tree (&t, verify_expr_no_block, NULL, NULL);
+      if (addr)
+       return addr;
+    }
+
+  if (!EXPR_P (*tp))
+    {
+      *walk_subtrees = false;
+      return NULL;
+    }
+
+  location_t loc = EXPR_LOCATION (*tp);
+  if (verify_location (blocks, loc))
+    return *tp;
+
+  return NULL;
+}
+
+/* Called via walk_gimple_op.  Verify locations of expressions.  */
+
+static tree
+verify_expr_location (tree *tp, int *walk_subtrees, void *data)
+{
+  struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
+  return verify_expr_location_1 (tp, walk_subtrees, wi->info);
+}
+
+/* Insert all subblocks of BLOCK into BLOCKS and recurse.  */
+
+static void
+collect_subblocks (pointer_set_t *blocks, tree block)
+{
+  tree t;
+  for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t))
+    {
+      pointer_set_insert (blocks, t);
+      collect_subblocks (blocks, t);
+    }
+}
+
 /* Verify the GIMPLE statements in the CFG of FN.  */
 
 DEBUG_FUNCTION void
@@ -4603,12 +4686,20 @@ verify_gimple_in_cfg (struct function *fn)
 {
   basic_block bb;
   bool err = false;
-  struct pointer_set_t *visited, *visited_stmts;
+  struct pointer_set_t *visited, *visited_stmts, *blocks;
 
   timevar_push (TV_TREE_STMT_VERIFY);
   visited = pointer_set_create ();
   visited_stmts = pointer_set_create ();
 
+  /* Collect all BLOCKs referenced by the BLOCK tree of FN.  */
+  blocks = pointer_set_create ();
+  if (DECL_INITIAL (fn->decl))
+    {
+      pointer_set_insert (blocks, DECL_INITIAL (fn->decl));
+      collect_subblocks (blocks, DECL_INITIAL (fn->decl));
+    }
+
   FOR_EACH_BB_FN (bb, fn)
     {
       gimple_stmt_iterator gsi;
@@ -4629,16 +4720,38 @@ verify_gimple_in_cfg (struct function *fn)
 
          err2 |= verify_gimple_phi (phi);
 
+         /* Only PHI arguments have locations.  */
+         if (gimple_location (phi) != UNKNOWN_LOCATION)
+           {
+             error ("PHI node with location");
+             err2 = true;
+           }
+
          for (i = 0; i < gimple_phi_num_args (phi); i++)
            {
              tree arg = gimple_phi_arg_def (phi, i);
-             tree addr = walk_tree (&arg, verify_node_sharing, visited, NULL);
+             tree addr = walk_tree (&arg, verify_node_sharing_1,
+                                    visited, NULL);
              if (addr)
                {
                  error ("incorrect sharing of tree nodes");
                  debug_generic_expr (addr);
                  err2 |= true;
                }
+             location_t loc = gimple_phi_arg_location (phi, i);
+             if (virtual_operand_p (gimple_phi_result (phi))
+                 && loc != UNKNOWN_LOCATION)
+               {
+                 error ("virtual PHI with argument locations");
+                 err2 = true;
+               }
+             addr = walk_tree (&arg, verify_expr_location_1, blocks, NULL);
+             if (addr)
+               {
+                 debug_generic_expr (addr);
+                 err2 = true;
+               }
+             err2 |= verify_location (blocks, loc);
            }
 
          if (err2)
@@ -4663,6 +4776,7 @@ verify_gimple_in_cfg (struct function *fn)
            }
 
          err2 |= verify_gimple_stmt (stmt);
+         err2 |= verify_location (blocks, gimple_location (stmt));
 
          memset (&wi, 0, sizeof (wi));
          wi.info = (void *) visited;
@@ -4674,6 +4788,15 @@ verify_gimple_in_cfg (struct function *fn)
              err2 |= true;
            }
 
+         memset (&wi, 0, sizeof (wi));
+         wi.info = (void *) blocks;
+         addr = walk_gimple_op (stmt, verify_expr_location, &wi);
+         if (addr)
+           {
+             debug_generic_expr (addr);
+             err2 |= true;
+           }
+
          /* ???  Instead of not checking these stmts at all the walker
             should know its context via wi.  */
          if (!is_gimple_debug (stmt)
@@ -4728,6 +4851,7 @@ verify_gimple_in_cfg (struct function *fn)
 
   pointer_set_destroy (visited);
   pointer_set_destroy (visited_stmts);
+  pointer_set_destroy (blocks);
   verify_histograms ();
   timevar_pop (TV_TREE_STMT_VERIFY);
 }
@@ -4745,19 +4869,21 @@ gimple_verify_flow_info (void)
   edge e;
   edge_iterator ei;
 
-  if (ENTRY_BLOCK_PTR->il.gimple.seq || ENTRY_BLOCK_PTR->il.gimple.phi_nodes)
+  if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->il.gimple.seq
+      || ENTRY_BLOCK_PTR_FOR_FN (cfun)->il.gimple.phi_nodes)
     {
       error ("ENTRY_BLOCK has IL associated with it");
       err = 1;
     }
 
-  if (EXIT_BLOCK_PTR->il.gimple.seq || EXIT_BLOCK_PTR->il.gimple.phi_nodes)
+  if (EXIT_BLOCK_PTR_FOR_FN (cfun)->il.gimple.seq
+      || EXIT_BLOCK_PTR_FOR_FN (cfun)->il.gimple.phi_nodes)
     {
       error ("EXIT_BLOCK has IL associated with it");
       err = 1;
     }
 
-  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
     if (e->flags & EDGE_FALLTHRU)
       {
        error ("fallthru to exit from bb %d", e->src->index);
@@ -4937,7 +5063,7 @@ gimple_verify_flow_info (void)
              error ("wrong outgoing edge flags at end of bb %d", bb->index);
              err = 1;
            }
-         if (single_succ (bb) != EXIT_BLOCK_PTR)
+         if (single_succ (bb) != EXIT_BLOCK_PTR_FOR_FN (cfun))
            {
              error ("return edge does not point to exit in bb %d",
                     bb->index);
@@ -5177,7 +5303,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->flags & EDGE_EH)
     return redirect_eh_edge (e, dest);
 
-  if (e->src != ENTRY_BLOCK_PTR)
+  if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
     {
       ret = gimple_try_redirect_by_replacing_jump (e, dest);
       if (ret)
@@ -5406,7 +5532,7 @@ gimple_move_block_after (basic_block bb, basic_block after)
 /* Return TRUE if block BB has no executable statements, otherwise return
    FALSE.  */
 
-bool
+static bool
 gimple_empty_block_p (basic_block bb)
 {
   /* BB must have no executable statements.  */
@@ -5460,7 +5586,7 @@ gimple_duplicate_bb (basic_block bb)
   gimple_seq phis = phi_nodes (bb);
   gimple phi, stmt, copy;
 
-  new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
+  new_bb = create_empty_bb (EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb);
 
   /* Copy the PHI nodes.  We ignore PHI node arguments here because
      the incoming edges have not been setup yet.  */
@@ -5470,6 +5596,7 @@ gimple_duplicate_bb (basic_block bb)
       copy = create_phi_node (NULL_TREE, new_bb);
       create_new_def_for (gimple_phi_result (phi), copy,
                          gimple_phi_result_ptr (copy));
+      gimple_set_uid (copy, gimple_uid (phi));
     }
 
   gsi_tgt = gsi_start_bb (new_bb);
@@ -5620,22 +5747,25 @@ add_phi_args_after_copy (basic_block *region_copy, unsigned n_region,
    inside region is live over the other exit edges of the region.  All entry
    edges to the region must go to ENTRY->dest.  The edge ENTRY is redirected
    to the duplicate of the region.  Dominance and loop information is
-   updated, but not the SSA web.  The new basic blocks are stored to
-   REGION_COPY in the same order as they had in REGION, provided that
-   REGION_COPY is not NULL.
+   updated if UPDATE_DOMINANCE is true, but not the SSA web.  If
+   UPDATE_DOMINANCE is false then we assume that the caller will update the
+   dominance information after calling this function.  The new basic
+   blocks are stored to REGION_COPY in the same order as they had in REGION,
+   provided that REGION_COPY is not NULL.
    The function returns false if it is unable to copy the region,
    true otherwise.  */
 
 bool
 gimple_duplicate_sese_region (edge entry, edge exit,
                            basic_block *region, unsigned n_region,
-                           basic_block *region_copy)
+                           basic_block *region_copy,
+                           bool update_dominance)
 {
   unsigned i;
   bool free_region_copy = false, copying_header = false;
   struct loop *loop = entry->dest->loop_father;
   edge exit_copy;
-  VEC (basic_block, heap) *doms;
+  vec<basic_block> doms;
   edge redirected;
   int total_freq = 0, entry_freq = 0;
   gcov_type total_count = 0, entry_count = 0;
@@ -5683,12 +5813,15 @@ gimple_duplicate_sese_region (edge entry, edge exit,
       free_region_copy = true;
     }
 
-  /* Record blocks outside the region that are dominated by something
-     inside.  */
-  doms = NULL;
   initialize_original_copy_tables ();
 
-  doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
+  /* Record blocks outside the region that are dominated by something
+     inside.  */
+  if (update_dominance)
+    {
+      doms.create (0);
+      doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region);
+    }
 
   if (entry->dest->count)
     {
@@ -5712,7 +5845,7 @@ gimple_duplicate_sese_region (edge entry, edge exit,
     }
 
   copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop,
-           split_edge_bb_loc (entry));
+           split_edge_bb_loc (entry), update_dominance);
   if (total_count)
     {
       scale_bbs_frequencies_gcov_type (region, n_region,
@@ -5743,10 +5876,13 @@ gimple_duplicate_sese_region (edge entry, edge exit,
      for entry block and its copy.  Anything that is outside of the
      region, but was dominated by something inside needs recounting as
      well.  */
-  set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
-  VEC_safe_push (basic_block, heap, doms, get_bb_original (entry->dest));
-  iterate_fix_dominators (CDI_DOMINATORS, doms, false);
-  VEC_free (basic_block, heap, doms);
+  if (update_dominance)
+    {
+      set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
+      doms.safe_push (get_bb_original (entry->dest));
+      iterate_fix_dominators (CDI_DOMINATORS, doms, false);
+      doms.release ();
+    }
 
   /* Add the other PHI node arguments.  */
   add_phi_args_after_copy (region_copy, n_region, NULL);
@@ -5811,7 +5947,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   struct loop *loop = exit->dest->loop_father;
   struct loop *orig_loop = entry->dest->loop_father;
   basic_block switch_bb, entry_bb, nentry_bb;
-  VEC (basic_block, heap) *doms;
+  vec<basic_block> doms;
   int total_freq = 0, exit_freq = 0;
   gcov_type total_count = 0, exit_count = 0;
   edge exits[2], nexits[2], e;
@@ -5878,7 +6014,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
     }
 
   copy_bbs (region, n_region, region_copy, exits, 2, nexits, orig_loop,
-           split_edge_bb_loc (exit));
+           split_edge_bb_loc (exit), true);
   if (total_count)
     {
       scale_bbs_frequencies_gcov_type (region, n_region,
@@ -5951,7 +6087,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
   /* Anything that is outside of the region, but was dominated by something
      inside needs to update dominance info.  */
   iterate_fix_dominators (CDI_DOMINATORS, doms, false);
-  VEC_free (basic_block, heap, doms);
+  doms.release ();
   /* Update the SSA web.  */
   update_ssa (TODO_update_ssa);
 
@@ -5968,7 +6104,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU
 
 void
 gather_blocks_in_sese_region (basic_block entry, basic_block exit,
-                             VEC(basic_block,heap) **bbs_p)
+                             vec<basic_block> *bbs_p)
 {
   basic_block son;
 
@@ -5976,7 +6112,7 @@ gather_blocks_in_sese_region (basic_block entry, basic_block exit,
        son;
        son = next_dom_son (CDI_DOMINATORS, son))
     {
-      VEC_safe_push (basic_block, heap, *bbs_p, son);
+      bbs_p->safe_push (son);
       if (son != exit)
        gather_blocks_in_sese_region (son, exit, bbs_p);
     }
@@ -6087,10 +6223,19 @@ move_stmt_op (tree *tp, int *walk_subtrees, void *data)
 
   if (EXPR_P (t))
     {
-      if (TREE_BLOCK (t) == p->orig_block
+      tree block = TREE_BLOCK (t);
+      if (block == p->orig_block
          || (p->orig_block == NULL_TREE
-         && TREE_BLOCK (t) == NULL_TREE))
+             && block != NULL_TREE))
        TREE_SET_BLOCK (t, p->new_block);
+#ifdef ENABLE_CHECKING
+      else if (block != NULL_TREE)
+       {
+         while (block && TREE_CODE (block) == BLOCK && block != p->orig_block)
+           block = BLOCK_SUPERCONTEXT (block);
+         gcc_assert (block == p->orig_block);
+       }
+#endif
     }
   else if (DECL_P (t) || TREE_CODE (t) == SSA_NAME)
     {
@@ -6154,7 +6299,7 @@ move_stmt_eh_region_tree_nr (tree old_t_nr, struct move_stmt_d *p)
 {
   int old_nr, new_nr;
 
-  old_nr = tree_low_cst (old_t_nr, 0);
+  old_nr = tree_to_shwi (old_t_nr);
   new_nr = move_stmt_eh_region_nr (old_nr, p);
 
   return build_int_cst (integer_type_node, new_nr);
@@ -6175,18 +6320,10 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
   gimple stmt = gsi_stmt (*gsi_p);
   tree block = gimple_block (stmt);
 
-  if (p->orig_block == NULL_TREE
-      || block == p->orig_block
-      || block == NULL_TREE)
+  if (block == p->orig_block
+      || (p->orig_block == NULL_TREE
+         && block != NULL_TREE))
     gimple_set_block (stmt, p->new_block);
-#ifdef ENABLE_CHECKING
-  else if (block != p->new_block)
-    {
-      while (block && block != p->orig_block)
-       block = BLOCK_SUPERCONTEXT (block);
-      gcc_assert (block);
-    }
-#endif
 
   switch (gimple_code (stmt))
     {
@@ -6280,8 +6417,14 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 
   /* Remove BB from dominance structures.  */
   delete_from_dominance_info (CDI_DOMINATORS, bb);
+
+  /* Move BB from its current loop to the copy in the new function.  */
   if (current_loops)
-    remove_bb_from_loops (bb);
+    {
+      struct loop *new_loop = (struct loop *)bb->loop_father->aux;
+      if (new_loop)
+       bb->loop_father = new_loop;
+    }
 
   /* Link BB to the new linked list.  */
   move_block_after (bb, after);
@@ -6295,7 +6438,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
       }
 
   /* Remove BB from the original basic block array.  */
-  VEC_replace (basic_block, cfun->cfg->x_basic_block_info, bb->index, NULL);
+  (*cfun->cfg->x_basic_block_info)[bb->index] = NULL;
   cfun->cfg->x_n_basic_blocks--;
 
   /* Grow DEST_CFUN's basic block array if needed.  */
@@ -6304,16 +6447,14 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
   if (bb->index >= cfg->x_last_basic_block)
     cfg->x_last_basic_block = bb->index + 1;
 
-  old_len = VEC_length (basic_block, cfg->x_basic_block_info);
+  old_len = vec_safe_length (cfg->x_basic_block_info);
   if ((unsigned) cfg->x_last_basic_block >= old_len)
     {
       new_len = cfg->x_last_basic_block + (cfg->x_last_basic_block + 3) / 4;
-      VEC_safe_grow_cleared (basic_block, gc, cfg->x_basic_block_info,
-                            new_len);
+      vec_safe_grow_cleared (cfg->x_basic_block_info, new_len);
     }
 
-  VEC_replace (basic_block, cfg->x_basic_block_info,
-               bb->index, bb);
+  (*cfg->x_basic_block_info)[bb->index] = bb;
 
   /* Remap the variables in phi nodes.  */
   for (si = gsi_start_phis (bb); !gsi_end_p (si); )
@@ -6377,16 +6518,15 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 
          gcc_assert (uid > -1);
 
-         old_len = VEC_length (basic_block, cfg->x_label_to_block_map);
+         old_len = vec_safe_length (cfg->x_label_to_block_map);
          if (old_len <= (unsigned) uid)
            {
              new_len = 3 * uid / 2 + 1;
-             VEC_safe_grow_cleared (basic_block, gc,
-                                    cfg->x_label_to_block_map, new_len);
+             vec_safe_grow_cleared (cfg->x_label_to_block_map, new_len);
            }
 
-         VEC_replace (basic_block, cfg->x_label_to_block_map, uid, bb);
-         VEC_replace (basic_block, cfun->cfg->x_label_to_block_map, uid, NULL);
+         (*cfg->x_label_to_block_map)[uid] = bb;
+         (*cfun->cfg->x_label_to_block_map)[uid] = NULL;
 
          gcc_assert (DECL_CONTEXT (label) == dest_cfun->decl);
 
@@ -6402,7 +6542,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
 
       /* We cannot leave any operands allocated from the operand caches of
         the current function.  */
-      free_stmt_operands (stmt);
+      free_stmt_operands (cfun, stmt);
       push_cfun (dest_cfun);
       update_stmt (stmt);
       pop_cfun ();
@@ -6417,14 +6557,6 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
          e->goto_locus = d->new_block ?
              COMBINE_LOCATION_DATA (line_table, e->goto_locus, d->new_block) :
              LOCATION_LOCUS (e->goto_locus);
-#ifdef ENABLE_CHECKING
-       else if (block != d->new_block)
-         {
-           while (block && block != d->orig_block)
-             block = BLOCK_SUPERCONTEXT (block);
-           gcc_assert (block);
-         }
-#endif
       }
 }
 
@@ -6516,6 +6648,25 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map,
     replace_block_vars_by_duplicates (block, vars_map, to_context);
 }
 
+/* Fixup the loop arrays and numbers after moving LOOP and its subloops
+   from FN1 to FN2.  */
+
+static void
+fixup_loop_arrays_after_move (struct function *fn1, struct function *fn2,
+                             struct loop *loop)
+{
+  /* Discard it from the old loop array.  */
+  (*get_loops (fn1))[loop->num] = NULL;
+
+  /* Place it in the new loop array, assigning it a new number.  */
+  loop->num = number_of_loops (fn2);
+  vec_safe_push (loops_for_fn (fn2)->larray, loop);
+
+  /* Recurse to children.  */
+  for (loop = loop->inner; loop; loop = loop->next)
+    fixup_loop_arrays_after_move (fn1, fn2, loop);
+}
+
 /* Move a single-entry, single-exit region delimited by ENTRY_BB and
    EXIT_BB to function DEST_CFUN.  The whole region is replaced by a
    single basic block in the original CFG and the new basic block is
@@ -6538,18 +6689,19 @@ basic_block
 move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
                        basic_block exit_bb, tree orig_block)
 {
-  VEC(basic_block,heap) *bbs, *dom_bbs;
+  vec<basic_block> bbs, dom_bbs;
   basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
   basic_block after, bb, *entry_pred, *exit_succ, abb;
   struct function *saved_cfun = cfun;
   int *entry_flag, *exit_flag;
   unsigned *entry_prob, *exit_prob;
-  unsigned i, num_entry_edges, num_exit_edges;
+  unsigned i, num_entry_edges, num_exit_edges, num_nodes;
   edge e;
   edge_iterator ei;
   htab_t new_label_map;
   struct pointer_map_t *vars_map, *eh_map;
   struct loop *loop = entry_bb->loop_father;
+  struct loop *loop0 = get_loop (saved_cfun, 0);
   struct move_stmt_d d;
 
   /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
@@ -6560,15 +6712,15 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
 
   /* Collect all the blocks in the region.  Manually add ENTRY_BB
      because it won't be added by dfs_enumerate_from.  */
-  bbs = NULL;
-  VEC_safe_push (basic_block, heap, bbs, entry_bb);
+  bbs.create (0);
+  bbs.safe_push (entry_bb);
   gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs);
 
   /* The blocks that used to be dominated by something in BBS will now be
      dominated by the new block.  */
   dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
-                                    VEC_address (basic_block, bbs),
-                                    VEC_length (basic_block, bbs));
+                                    bbs.address (),
+                                    bbs.length ());
 
   /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
      the predecessor edges to ENTRY_BB and the successor edges to
@@ -6623,7 +6775,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     {
       eh_region region = NULL;
 
-      FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
+      FOR_EACH_VEC_ELT (bbs, i, bb)
        region = find_outermost_region_in_block (saved_cfun, bb, region);
 
       init_eh_for_function ();
@@ -6635,10 +6787,61 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
        }
     }
 
+  /* Initialize an empty loop tree.  */
+  struct loops *loops = ggc_alloc_cleared_loops ();
+  init_loops_structure (dest_cfun, loops, 1);
+  loops->state = LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
+  set_loops_for_fn (dest_cfun, loops);
+
+  /* Move the outlined loop tree part.  */
+  num_nodes = bbs.length ();
+  FOR_EACH_VEC_ELT (bbs, i, bb)
+    {
+      if (bb->loop_father->header == bb)
+       {
+         struct loop *this_loop = bb->loop_father;
+         struct loop *outer = loop_outer (this_loop);
+         if (outer == loop
+             /* If the SESE region contains some bbs ending with
+                a noreturn call, those are considered to belong
+                to the outermost loop in saved_cfun, rather than
+                the entry_bb's loop_father.  */
+             || outer == loop0)
+           {
+             if (outer != loop)
+               num_nodes -= this_loop->num_nodes;
+             flow_loop_tree_node_remove (bb->loop_father);
+             flow_loop_tree_node_add (get_loop (dest_cfun, 0), this_loop);
+             fixup_loop_arrays_after_move (saved_cfun, cfun, this_loop);
+           }
+       }
+      else if (bb->loop_father == loop0 && loop0 != loop)
+       num_nodes--;
+
+      /* Remove loop exits from the outlined region.  */
+      if (loops_for_fn (saved_cfun)->exits)
+       FOR_EACH_EDGE (e, ei, bb->succs)
+         {
+           void **slot = htab_find_slot_with_hash
+               (loops_for_fn (saved_cfun)->exits, e,
+                htab_hash_pointer (e), NO_INSERT);
+           if (slot)
+             htab_clear_slot (loops_for_fn (saved_cfun)->exits, slot);
+         }
+    }
+
+
+  /* Adjust the number of blocks in the tree root of the outlined part.  */
+  get_loop (dest_cfun, 0)->num_nodes = bbs.length () + 2;
+
+  /* Setup a mapping to be used by move_block_to_fn.  */
+  loop->aux = current_loops->tree_root;
+  loop0->aux = current_loops->tree_root;
+
   pop_cfun ();
 
   /* Move blocks from BBS into DEST_CFUN.  */
-  gcc_assert (VEC_length (basic_block, bbs) >= 2);
+  gcc_assert (bbs.length () >= 2);
   after = dest_cfun->cfg->x_entry_block_ptr;
   vars_map = pointer_map_create ();
 
@@ -6652,7 +6855,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   d.eh_map = eh_map;
   d.remap_decls_p = true;
 
-  FOR_EACH_VEC_ELT (basic_block, bbs, i, bb)
+  FOR_EACH_VEC_ELT (bbs, i, bb)
     {
       /* No need to update edge counts on the last block.  It has
         already been updated earlier when we detached the region from
@@ -6661,6 +6864,32 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
       after = bb;
     }
 
+  loop->aux = NULL;
+  loop0->aux = NULL;
+  /* Loop sizes are no longer correct, fix them up.  */
+  loop->num_nodes -= num_nodes;
+  for (struct loop *outer = loop_outer (loop);
+       outer; outer = loop_outer (outer))
+    outer->num_nodes -= num_nodes;
+  loop0->num_nodes -= bbs.length () - num_nodes;
+
+  if (saved_cfun->has_simduid_loops || saved_cfun->has_force_vect_loops)
+    {
+      struct loop *aloop;
+      for (i = 0; vec_safe_iterate (loops->larray, i, &aloop); i++)
+       if (aloop != NULL)
+         {
+           if (aloop->simduid)
+             {
+               replace_by_duplicate_decl (&aloop->simduid, d.vars_map,
+                                          d.to_context);
+               dest_cfun->has_simduid_loops = true;
+             }
+           if (aloop->force_vect)
+             dest_cfun->has_force_vect_loops = true;
+         }
+    }
+
   /* Rewire BLOCK_SUBBLOCKS of orig_block.  */
   if (orig_block)
     {
@@ -6694,9 +6923,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
      FIXME, this is silly.  The CFG ought to become a parameter to
      these helpers.  */
   push_cfun (dest_cfun);
-  make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
+  make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), entry_bb, EDGE_FALLTHRU);
   if (exit_bb)
-    make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
+    make_edge (exit_bb,  EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
   pop_cfun ();
 
   /* Back in the original function, the SESE region has disappeared,
@@ -6717,9 +6946,9 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
     }
 
   set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
-  FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, abb)
+  FOR_EACH_VEC_ELT (dom_bbs, i, abb)
     set_immediate_dominator (CDI_DOMINATORS, abb, bb);
-  VEC_free (basic_block, heap, dom_bbs);
+  dom_bbs.release ();
 
   if (exit_bb)
     {
@@ -6730,13 +6959,13 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
   free (entry_prob);
   free (entry_flag);
   free (entry_pred);
-  VEC_free (basic_block, heap, bbs);
+  bbs.release ();
 
   return bb;
 }
 
 
-/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree-pass.h)
+/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in dumpfile.h)
    */
 
 void
@@ -6790,7 +7019,7 @@ dump_function_to_file (tree fndecl, FILE *file, int flags)
       ignore_topmost_bind = true;
 
       fprintf (file, "{\n");
-      if (!VEC_empty (tree, fun->local_decls))
+      if (!vec_safe_is_empty (fun->local_decls))
        FOR_EACH_LOCAL_DECL (fun, ix, var)
          {
            print_generic_decl (file, var, flags);
@@ -6817,14 +7046,15 @@ dump_function_to_file (tree fndecl, FILE *file, int flags)
          }
     }
 
-  if (fun && fun->decl == fndecl && fun->cfg
-      && basic_block_info_for_function (fun))
+  if (fun && fun->decl == fndecl
+      && fun->cfg
+      && basic_block_info_for_fn (fun))
     {
       /* If the CFG has been built, emit a CFG-based dump.  */
       if (!ignore_topmost_bind)
        fprintf (file, "{\n");
 
-      if (any_var && n_basic_blocks_for_function (fun))
+      if (any_var && n_basic_blocks_for_fn (fun))
        fprintf (file, "\n");
 
       FOR_EACH_BB_FN (bb, fun)
@@ -7021,7 +7251,8 @@ print_loop (FILE *file, struct loop *loop, int indent, int verbosity)
    loop, or just its structure.  */
 
 static void
-print_loop_and_siblings (FILE *file, struct loop *loop, int indent, int verbosity)
+print_loop_and_siblings (FILE *file, struct loop *loop, int indent,
+                        int verbosity)
 {
   if (loop == NULL)
     return;
@@ -7038,11 +7269,45 @@ print_loops (FILE *file, int verbosity)
 {
   basic_block bb;
 
-  bb = ENTRY_BLOCK_PTR;
+  bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
   if (bb && bb->loop_father)
     print_loop_and_siblings (file, bb->loop_father, 0, verbosity);
 }
 
+/* Dump a loop.  */
+
+DEBUG_FUNCTION void
+debug (struct loop &ref)
+{
+  print_loop (stderr, &ref, 0, /*verbosity*/0);
+}
+
+DEBUG_FUNCTION void
+debug (struct loop *ptr)
+{
+  if (ptr)
+    debug (*ptr);
+  else
+    fprintf (stderr, "<nil>\n");
+}
+
+/* Dump a loop verbosely.  */
+
+DEBUG_FUNCTION void
+debug_verbose (struct loop &ref)
+{
+  print_loop (stderr, &ref, 0, /*verbosity*/3);
+}
+
+DEBUG_FUNCTION void
+debug_verbose (struct loop *ptr)
+{
+  if (ptr)
+    debug (*ptr);
+  else
+    fprintf (stderr, "<nil>\n");
+}
+
 
 /* Debugging loops structure at tree level, at some VERBOSITY level.  */
 
@@ -7066,7 +7331,7 @@ debug_loop (struct loop *loop, int verbosity)
 DEBUG_FUNCTION void
 debug_loop_num (unsigned num, int verbosity)
 {
-  debug_loop (get_loop (num), verbosity);
+  debug_loop (get_loop (cfun, num), verbosity);
 }
 
 /* Return true if BB ends with a call, possibly followed by some
@@ -7167,13 +7432,14 @@ gimple_flow_call_edges_add (sbitmap blocks)
   int last_bb = last_basic_block;
   bool check_last_block = false;
 
-  if (n_basic_blocks == NUM_FIXED_BLOCKS)
+  if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS)
     return 0;
 
   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_FOR_FN (cfun)->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
@@ -7189,7 +7455,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
      Handle this by adding a dummy instruction in a new last basic block.  */
   if (check_last_block)
     {
-      basic_block bb = EXIT_BLOCK_PTR->prev_bb;
+      basic_block bb = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
       gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
       gimple t = NULL;
 
@@ -7200,7 +7466,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
        {
          edge e;
 
-         e = find_edge (bb, EXIT_BLOCK_PTR);
+         e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
          if (e)
            {
              gsi_insert_on_edge (e, gimple_build_nop ());
@@ -7214,14 +7480,14 @@ gimple_flow_call_edges_add (sbitmap blocks)
      return or not...  */
   for (i = 0; i < last_bb; i++)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
       gimple_stmt_iterator gsi;
       gimple stmt, last_stmt;
 
       if (!bb)
        continue;
 
-      if (blocks && !TEST_BIT (blocks, i))
+      if (blocks && !bitmap_bit_p (blocks, i))
        continue;
 
       gsi = gsi_last_nondebug_bb (bb);
@@ -7243,7 +7509,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
 #ifdef ENABLE_CHECKING
                  if (stmt == last_stmt)
                    {
-                     e = find_edge (bb, EXIT_BLOCK_PTR);
+                     e = find_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun));
                      gcc_assert (e == NULL);
                    }
 #endif
@@ -7256,7 +7522,7 @@ gimple_flow_call_edges_add (sbitmap blocks)
                      if (e)
                        blocks_split++;
                    }
-                 make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+                 make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
                }
              gsi_prev (&gsi);
            }
@@ -7277,8 +7543,8 @@ gimple_flow_call_edges_add (sbitmap blocks)
 void
 remove_edge_and_dominated_blocks (edge e)
 {
-  VEC (basic_block, heap) *bbs_to_remove = NULL;
-  VEC (basic_block, heap) *bbs_to_fix_dom = NULL;
+  vec<basic_block> bbs_to_remove = vNULL;
+  vec<basic_block> bbs_to_fix_dom = vNULL;
   bitmap df, df_idom;
   edge f;
   edge_iterator ei;
@@ -7294,7 +7560,7 @@ remove_edge_and_dominated_blocks (edge e)
     }
 
   /* No updating is needed for edges to exit.  */
-  if (e->dest == EXIT_BLOCK_PTR)
+  if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
     {
       if (cfgcleanup_altered_bbs)
        bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
@@ -7330,20 +7596,20 @@ remove_edge_and_dominated_blocks (edge e)
   else
     {
       bbs_to_remove = get_all_dominated_blocks (CDI_DOMINATORS, e->dest);
-      FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb)
+      FOR_EACH_VEC_ELT (bbs_to_remove, i, bb)
        {
          FOR_EACH_EDGE (f, ei, bb->succs)
            {
-             if (f->dest != EXIT_BLOCK_PTR)
+             if (f->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
                bitmap_set_bit (df, f->dest->index);
            }
        }
-      FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb)
+      FOR_EACH_VEC_ELT (bbs_to_remove, i, bb)
        bitmap_clear_bit (df, bb->index);
 
       EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi)
        {
-         bb = BASIC_BLOCK (i);
+         bb = BASIC_BLOCK_FOR_FN (cfun, i);
          bitmap_set_bit (df_idom,
                          get_immediate_dominator (CDI_DOMINATORS, bb)->index);
        }
@@ -7365,8 +7631,8 @@ remove_edge_and_dominated_blocks (edge e)
         released DEFs into debug stmts.  See
         eliminate_unnecessary_stmts() in tree-ssa-dce.c for more
         details.  */
-      for (i = VEC_length (basic_block, bbs_to_remove); i-- > 0; )
-       delete_basic_block (VEC_index (basic_block, bbs_to_remove, i));
+      for (i = bbs_to_remove.length (); i-- > 0; )
+       delete_basic_block (bbs_to_remove[i]);
     }
 
   /* Update the dominance information.  The immediate dominator may change only
@@ -7381,19 +7647,19 @@ remove_edge_and_dominated_blocks (edge e)
      the dominance frontier of E.  Therefore, Y belongs to DF_IDOM.  */
   EXECUTE_IF_SET_IN_BITMAP (df_idom, 0, i, bi)
     {
-      bb = BASIC_BLOCK (i);
+      bb = BASIC_BLOCK_FOR_FN (cfun, i);
       for (dbb = first_dom_son (CDI_DOMINATORS, bb);
           dbb;
           dbb = next_dom_son (CDI_DOMINATORS, dbb))
-       VEC_safe_push (basic_block, heap, bbs_to_fix_dom, dbb);
+       bbs_to_fix_dom.safe_push (dbb);
     }
 
   iterate_fix_dominators (CDI_DOMINATORS, bbs_to_fix_dom, true);
 
   BITMAP_FREE (df);
   BITMAP_FREE (df_idom);
-  VEC_free (basic_block, heap, bbs_to_remove);
-  VEC_free (basic_block, heap, bbs_to_fix_dom);
+  bbs_to_remove.release ();
+  bbs_to_fix_dom.release ();
 }
 
 /* Purge dead EH edges from basic block BB.  */
@@ -7434,7 +7700,7 @@ gimple_purge_all_dead_eh_edges (const_bitmap blocks)
 
   EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
 
       /* Earlier gimple_purge_dead_eh_edges could have removed
         this basic block already.  */
@@ -7456,7 +7722,8 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb)
   edge_iterator ei;
   gimple stmt = last_stmt (bb);
 
-  if (!cfun->has_nonlocal_label)
+  if (!cfun->has_nonlocal_label
+      && !cfun->calls_setjmp)
     return false;
 
   if (stmt && stmt_can_make_abnormal_goto (stmt))
@@ -7466,7 +7733,10 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb)
     {
       if (e->flags & EDGE_ABNORMAL)
        {
-         remove_edge_and_dominated_blocks (e);
+         if (e->flags & EDGE_FALLTHRU)
+           e->flags &= ~EDGE_ABNORMAL;
+         else
+           remove_edge_and_dominated_blocks (e);
          changed = true;
        }
       else
@@ -7487,7 +7757,7 @@ gimple_purge_all_dead_abnormal_call_edges (const_bitmap blocks)
 
   EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
 
       /* Earlier gimple_purge_dead_abnormal_call_edges could have removed
         this basic block already.  */
@@ -7591,10 +7861,35 @@ gimple_lv_add_condition_to_bb (basic_block first_head ATTRIBUTE_UNUSED,
   e0->flags |= EDGE_FALSE_VALUE;
 }
 
+
+/* 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
+gimple_account_profile_record (basic_block bb, int after_pass,
+                              struct profile_record *record)
+{
+  gimple_stmt_iterator i;
+  for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
+    {
+      record->size[after_pass]
+       += estimate_num_insns (gsi_stmt (i), &eni_size_weights);
+      if (profile_status == PROFILE_READ)
+       record->time[after_pass]
+         += estimate_num_insns (gsi_stmt (i),
+                                &eni_time_weights) * bb->count;
+      else if (profile_status == PROFILE_GUESSED)
+       record->time[after_pass]
+         += estimate_num_insns (gsi_stmt (i),
+                                &eni_time_weights) * bb->frequency;
+    }
+}
+
 struct cfg_hooks gimple_cfg_hooks = {
   "gimple",
   gimple_verify_flow_info,
   gimple_dump_bb,              /* dump_bb  */
+  gimple_dump_bb_for_graph,    /* dump_bb_for_graph  */
   create_bb,                   /* create_basic_block  */
   gimple_redirect_edge_and_branch, /* redirect_edge_and_branch  */
   gimple_redirect_edge_and_branch_force, /* redirect_edge_and_branch_force  */
@@ -7624,6 +7919,7 @@ struct cfg_hooks gimple_cfg_hooks = {
   flush_pending_stmts,                 /* flush_pending_stmts */  
   gimple_empty_block_p,           /* block_empty_p */
   gimple_split_block_before_cond_jump, /* split_block_before_cond_jump */
+  gimple_account_profile_record,
 };
 
 
@@ -7655,8 +7951,8 @@ split_critical_edges (void)
             gimple_find_edge_insert_loc.  */
          else if ((!single_pred_p (e->dest)
                    || !gimple_seq_empty_p (phi_nodes (e->dest))
-                   || e->dest == EXIT_BLOCK_PTR)
-                  && e->src != ENTRY_BLOCK_PTR
+                   || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+                  && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun)
                   && !(e->flags & EDGE_ABNORMAL))
            {
              gimple_stmt_iterator gsi;
@@ -7675,25 +7971,44 @@ split_critical_edges (void)
   return 0;
 }
 
-struct gimple_opt_pass pass_split_crit_edges =
-{
- {
-  GIMPLE_PASS,
-  "crited",                          /* name */
-  NULL,                          /* gate */
-  split_critical_edges,          /* execute */
-  NULL,                          /* sub */
-  NULL,                          /* next */
-  0,                             /* static_pass_number */
-  TV_TREE_SPLIT_EDGES,           /* tv_id */
-  PROP_cfg,                      /* properties required */
-  PROP_no_crit_edges,            /* properties_provided */
-  0,                             /* properties_destroyed */
-  0,                             /* todo_flags_start */
-  TODO_verify_flow               /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_crit_edges =
+{
+  GIMPLE_PASS, /* type */
+  "crited", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_TREE_SPLIT_EDGES, /* tv_id */
+  PROP_cfg, /* properties_required */
+  PROP_no_crit_edges, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_verify_flow, /* todo_flags_finish */
 };
 
+class pass_split_crit_edges : public gimple_opt_pass
+{
+public:
+  pass_split_crit_edges (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_split_crit_edges, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  unsigned int execute () { return split_critical_edges (); }
+
+  opt_pass * clone () { return new pass_split_crit_edges (m_ctxt); }
+}; // class pass_split_crit_edges
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_split_crit_edges (gcc::context *ctxt)
+{
+  return new pass_split_crit_edges (ctxt);
+}
+
 
 /* Build a ternary operation and gimplify it.  Emit code before GSI.
    Return the gimple_val holding the result.  */
@@ -7761,10 +8076,10 @@ execute_warn_function_return (void)
 
   /* If we have a path to EXIT, then we do return.  */
   if (TREE_THIS_VOLATILE (cfun->decl)
-      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0)
+      && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) > 0)
     {
       location = UNKNOWN_LOCATION;
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
        {
          last = last_stmt (e->src);
          if ((gimple_code (last) == GIMPLE_RETURN
@@ -7781,10 +8096,10 @@ execute_warn_function_return (void)
      without returning a value.  */
   else if (warn_return_type
           && !TREE_NO_WARNING (cfun->decl)
-          && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0
+          && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) > 0
           && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
     {
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
        {
          gimple last = last_stmt (e->src);
          if (gimple_code (last) == GIMPLE_RETURN
@@ -7828,61 +8143,42 @@ extract_true_false_edges_from_block (basic_block b,
     }
 }
 
-struct gimple_opt_pass pass_warn_function_return =
-{
- {
-  GIMPLE_PASS,
-  "*warn_function_return",             /* name */
-  NULL,                                        /* gate */
-  execute_warn_function_return,                /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_NONE,                             /* tv_id */
-  PROP_cfg,                            /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
- }
-};
+namespace {
 
-/* Emit noreturn warnings.  */
+const pass_data pass_data_warn_function_return =
+{
+  GIMPLE_PASS, /* type */
+  "*warn_function_return", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_NONE, /* tv_id */
+  PROP_cfg, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
 
-static unsigned int
-execute_warn_function_noreturn (void)
+class pass_warn_function_return : public gimple_opt_pass
 {
-  if (!TREE_THIS_VOLATILE (current_function_decl)
-      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0)
-    warn_function_noreturn (current_function_decl);
-  return 0;
-}
+public:
+  pass_warn_function_return (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_warn_function_return, ctxt)
+  {}
 
-static bool
-gate_warn_function_noreturn (void)
-{
-  return warn_suggest_attribute_noreturn;
-}
-
-struct gimple_opt_pass pass_warn_function_noreturn =
-{
- {
-  GIMPLE_PASS,
-  "*warn_function_noreturn",           /* name */
-  gate_warn_function_noreturn,         /* gate */
-  execute_warn_function_noreturn,      /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_NONE,                             /* tv_id */
-  PROP_cfg,                            /* properties_required */
-  0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
- }
-};
+  /* opt_pass methods: */
+  unsigned int execute () { return execute_warn_function_return (); }
 
+}; // class pass_warn_function_return
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_warn_function_return (gcc::context *ctxt)
+{
+  return new pass_warn_function_return (ctxt);
+}
 
 /* Walk a gimplified function and warn for functions whose return value is
    ignored and attribute((warn_unused_result)) is set.  This is done before
@@ -7962,25 +8258,186 @@ gate_warn_unused_result (void)
   return flag_warn_unused_result;
 }
 
-struct gimple_opt_pass pass_warn_unused_result =
-{
-  {
-    GIMPLE_PASS,
-    "*warn_unused_result",             /* name */
-    gate_warn_unused_result,           /* gate */
-    run_warn_unused_result,            /* execute */
-    NULL,                              /* sub */
-    NULL,                              /* next */
-    0,                                 /* static_pass_number */
-    TV_NONE,                           /* tv_id */
-    PROP_gimple_any,                   /* properties_required */
-    0,                                 /* properties_provided */
-    0,                                 /* properties_destroyed */
-    0,                                 /* todo_flags_start */
-    0,                                 /* todo_flags_finish */
-  }
+namespace {
+
+const pass_data pass_data_warn_unused_result =
+{
+  GIMPLE_PASS, /* type */
+  "*warn_unused_result", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_NONE, /* tv_id */
+  PROP_gimple_any, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_warn_unused_result : public gimple_opt_pass
+{
+public:
+  pass_warn_unused_result (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_warn_unused_result, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_warn_unused_result (); }
+  unsigned int execute () { return run_warn_unused_result (); }
+
+}; // class pass_warn_unused_result
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_warn_unused_result (gcc::context *ctxt)
+{
+  return new pass_warn_unused_result (ctxt);
+}
+
+/* IPA passes, compilation of earlier functions or inlining
+   might have changed some properties, such as marked functions nothrow,
+   pure, const or noreturn.
+   Remove redundant edges and basic blocks, and create new ones if necessary.
+
+   This pass can't be executed as stand alone pass from pass manager, because
+   in between inlining and this fixup the verify_flow_info would fail.  */
+
+unsigned int
+execute_fixup_cfg (void)
+{
+  basic_block bb;
+  gimple_stmt_iterator gsi;
+  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;
+  gcov_type count_scale;
+  edge e;
+  edge_iterator ei;
+
+  count_scale
+      = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count,
+                           ENTRY_BLOCK_PTR_FOR_FN (cfun)->count);
+
+  ENTRY_BLOCK_PTR_FOR_FN (cfun)->count =
+                           cgraph_get_node (current_function_decl)->count;
+  EXIT_BLOCK_PTR_FOR_FN (cfun)->count =
+                           apply_scale (EXIT_BLOCK_PTR_FOR_FN (cfun)->count,
+                                       count_scale);
+
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
+    e->count = apply_scale (e->count, count_scale);
+
+  FOR_EACH_BB (bb)
+    {
+      bb->count = apply_scale (bb->count, count_scale);
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         tree decl = is_gimple_call (stmt)
+                     ? gimple_call_fndecl (stmt)
+                     : NULL;
+         if (decl)
+           {
+             int flags = gimple_call_flags (stmt);
+             if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE))
+               {
+                 if (gimple_purge_dead_abnormal_call_edges (bb))
+                   todo |= TODO_cleanup_cfg;
+
+                 if (gimple_in_ssa_p (cfun))
+                   {
+                     todo |= TODO_update_ssa | TODO_cleanup_cfg;
+                     update_stmt (stmt);
+                   }
+               }
+
+             if (flags & ECF_NORETURN
+                 && fixup_noreturn_call (stmt))
+               todo |= TODO_cleanup_cfg;
+            }
+
+         if (maybe_clean_eh_stmt (stmt)
+             && gimple_purge_dead_eh_edges (bb))
+           todo |= TODO_cleanup_cfg;
+       }
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+        e->count = apply_scale (e->count, count_scale);
+
+      /* If we have a basic block with no successors that does not
+        end with a control statement or a noreturn call end it with
+        a call to __builtin_unreachable.  This situation can occur
+        when inlining a noreturn call that does in fact return.  */
+      if (EDGE_COUNT (bb->succs) == 0)
+       {
+         gimple stmt = last_stmt (bb);
+         if (!stmt
+             || (!is_ctrl_stmt (stmt)
+                 && (!is_gimple_call (stmt)
+                     || (gimple_call_flags (stmt) & ECF_NORETURN) == 0)))
+           {
+             stmt = gimple_build_call
+                 (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
+             gimple_stmt_iterator gsi = gsi_last_bb (bb);
+             gsi_insert_after (&gsi, stmt, GSI_NEW_STMT);
+           }
+       }
+    }
+  if (count_scale != REG_BR_PROB_BASE)
+    compute_function_frequency ();
+
+  /* We just processed all calls.  */
+  if (cfun->gimple_df)
+    vec_free (MODIFIED_NORETURN_CALLS (cfun));
+
+  /* Dump a textual representation of the flowgraph.  */
+  if (dump_file)
+    gimple_dump_cfg (dump_file, dump_flags);
+
+  if (current_loops
+      && (todo & TODO_cleanup_cfg))
+    loops_state_set (LOOPS_NEED_FIXUP);
+
+  return todo;
+}
+
+namespace {
+
+const pass_data pass_data_fixup_cfg =
+{
+  GIMPLE_PASS, /* type */
+  "*free_cfg_annotations", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  false, /* has_gate */
+  true, /* has_execute */
+  TV_NONE, /* tv_id */
+  PROP_cfg, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_fixup_cfg : public gimple_opt_pass
+{
+public:
+  pass_fixup_cfg (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_fixup_cfg, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_fixup_cfg (m_ctxt); }
+  unsigned int execute () { return execute_fixup_cfg (); }
+
+}; // class pass_fixup_cfg
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_fixup_cfg (gcc::context *ctxt)
+{
+  return new pass_fixup_cfg (ctxt);
+}
 
 /* Garbage collection support for edge_def.  */