OSDN Git Service

* tree-cfg.c (bsi_replace): Shortcut when replacing the statement with
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index c141982..e3e2134 100644 (file)
@@ -1,5 +1,6 @@
 /* Control flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -16,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -29,7 +30,6 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "output.h"
-#include "errors.h"
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
@@ -44,7 +44,9 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "cfgloop.h"
 #include "cfglayout.h"
-#include "hashtab.h"
+#include "tree-ssa-propagate.h"
+#include "value-prof.h"
+#include "pointer-set.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -67,19 +69,7 @@ static const int initial_cfg_capacity = 20;
    more persistent.  The key is getting notification of changes to
    the CFG (particularly edge removal, creation and redirection).  */
 
-struct edge_to_cases_elt
-{
-  /* The edge itself.  Necessary for hashing and equality tests.  */
-  edge e;
-
-  /* The case labels associated with this edge.  We link these up via
-     their TREE_CHAIN field, then we wipe out the TREE_CHAIN fields
-     when we destroy the hash table.  This prevents problems when copying
-     SWITCH_EXPRs.  */
-  tree case_labels;
-};
-
-static htab_t edge_to_cases;
+static struct pointer_map_t *edge_to_cases;
 
 /* CFG statistics.  */
 struct cfg_stats_d
@@ -94,43 +84,33 @@ static bool found_computed_goto;
 
 /* Basic blocks and flowgraphs.  */
 static basic_block create_bb (void *, void *, basic_block);
-static void create_block_annotation (basic_block);
-static void free_blocks_annotations (void);
-static void clear_blocks_annotations (void);
 static void make_blocks (tree);
 static void factor_computed_gotos (void);
 
 /* Edges.  */
 static void make_edges (void);
-static void make_ctrl_stmt_edges (basic_block);
-static void make_exit_edges (basic_block);
 static void make_cond_expr_edges (basic_block);
 static void make_switch_expr_edges (basic_block);
 static void make_goto_expr_edges (basic_block);
 static edge tree_redirect_edge_and_branch (edge, basic_block);
 static edge tree_try_redirect_by_replacing_jump (edge, basic_block);
-static void split_critical_edges (void);
-static bool remove_fallthru_edge (VEC(edge,gc) *);
+static unsigned int split_critical_edges (void);
 
 /* Various helpers.  */
 static inline bool stmt_starts_bb_p (tree, tree);
 static int tree_verify_flow_info (void);
 static void tree_make_forwarder_block (edge);
-static bool tree_forwarder_block_p (basic_block, bool);
 static void tree_cfg2vcg (FILE *);
+static inline void change_bb_for_stmt (tree t, basic_block bb);
 
 /* Flowgraph optimization and cleanup.  */
 static void tree_merge_blocks (basic_block, basic_block);
 static bool tree_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
-static bool cleanup_control_flow (void);
-static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator);
 static edge find_taken_edge_computed_goto (basic_block, tree);
 static edge find_taken_edge_cond_expr (basic_block, tree);
 static edge find_taken_edge_switch_expr (basic_block, tree);
 static tree find_case_label_for_value (tree, tree);
-static bool phi_alternatives_equal (basic_block, edge, edge);
-static bool cleanup_forwarder_blocks (void);
 
 void
 init_empty_tree_cfg (void)
@@ -138,19 +118,21 @@ init_empty_tree_cfg (void)
   /* Initialize the basic block array.  */
   init_flow ();
   profile_status = PROFILE_ABSENT;
-  n_basic_blocks = 0;
-  last_basic_block = 0;
-  VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info");
+  n_basic_blocks = NUM_FIXED_BLOCKS;
+  last_basic_block = NUM_FIXED_BLOCKS;
+  basic_block_info = VEC_alloc (basic_block, gc, initial_cfg_capacity);
+  VEC_safe_grow_cleared (basic_block, gc, basic_block_info,
+                        initial_cfg_capacity);
 
   /* Build a mapping of labels to their associated blocks.  */
-  VARRAY_BB_INIT (label_to_block_map, initial_cfg_capacity,
-                 "label to block map");
+  label_to_block_map = VEC_alloc (basic_block, gc, initial_cfg_capacity);
+  VEC_safe_grow_cleared (basic_block, gc, label_to_block_map,
+                        initial_cfg_capacity);
 
+  SET_BASIC_BLOCK (ENTRY_BLOCK, ENTRY_BLOCK_PTR);
+  SET_BASIC_BLOCK (EXIT_BLOCK, EXIT_BLOCK_PTR);
   ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
   EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
-
-  create_block_annotation (ENTRY_BLOCK_PTR);
-  create_block_annotation (EXIT_BLOCK_PTR);
 }
 
 /*---------------------------------------------------------------------------
@@ -182,11 +164,12 @@ build_tree_cfg (tree *tp)
     factor_computed_gotos ();
 
   /* Make sure there is always at least one block, even if it's empty.  */
-  if (n_basic_blocks == 0)
+  if (n_basic_blocks == NUM_FIXED_BLOCKS)
     create_empty_bb (ENTRY_BLOCK_PTR);
 
   /* Adjust the size of the array.  */
-  VARRAY_GROW (basic_block_info, n_basic_blocks);
+  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);
 
   /* To speed up statement iterator walks, we first purge dead labels.  */
   cleanup_dead_labels ();
@@ -204,11 +187,11 @@ build_tree_cfg (tree *tp)
   /* Write the flowgraph to a VCG file.  */
   {
     int local_dump_flags;
-    FILE *dump_file = dump_begin (TDI_vcg, &local_dump_flags);
-    if (dump_file)
+    FILE *vcg_file = dump_begin (TDI_vcg, &local_dump_flags);
+    if (vcg_file)
       {
-       tree_cfg2vcg (dump_file);
-       dump_end (TDI_vcg, dump_file);
+       tree_cfg2vcg (vcg_file);
+       dump_end (TDI_vcg, vcg_file);
       }
   }
 
@@ -221,10 +204,11 @@ build_tree_cfg (tree *tp)
     dump_tree_cfg (dump_file, dump_flags);
 }
 
-static void
+static unsigned int
 execute_build_cfg (void)
 {
   build_tree_cfg (&DECL_SAVED_TREE (current_function_decl));
+  return 0;
 }
 
 struct tree_opt_pass pass_build_cfg =
@@ -240,13 +224,13 @@ struct tree_opt_pass pass_build_cfg =
   PROP_cfg,                            /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_verify_stmts,                   /* todo_flags_finish */
+  TODO_verify_stmts | TODO_cleanup_cfg,        /* todo_flags_finish */
   0                                    /* letter */
 };
 
-/* Search the CFG for any computed gotos.  If found, factor them to a 
+/* 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
-   that we can un-factor the gotos after we have converted back to 
+   that we can un-factor the gotos after we have converted back to
    normal form.  */
 
 static void
@@ -261,7 +245,7 @@ factor_computed_gotos (void)
   /* We know there are one or more computed gotos in this function.
      Examine the last statement in each basic block to see if the block
      ends with a computed goto.  */
-       
+
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator bsi = bsi_last (bb);
@@ -310,8 +294,8 @@ factor_computed_gotos (void)
            }
 
          /* Copy the original computed goto's destination into VAR.  */
-         assignment = build (MODIFY_EXPR, ptr_type_node,
-                             var, GOTO_DESTINATION (last));
+         assignment = build2_gimple (GIMPLE_MODIFY_STMT,
+                                     var, GOTO_DESTINATION (last));
          bsi_insert_before (&bsi, assignment, BSI_SAME_STMT);
 
          /* And re-vector the computed goto to the new destination.  */
@@ -321,37 +305,6 @@ factor_computed_gotos (void)
 }
 
 
-/* Create annotations for a single basic block.  */
-
-static void
-create_block_annotation (basic_block bb)
-{
-  /* Verify that the tree_annotations field is clear.  */
-  gcc_assert (!bb->tree_annotations);
-  bb->tree_annotations = ggc_alloc_cleared (sizeof (struct bb_ann_d));
-}
-
-
-/* Free the annotations for all the basic blocks.  */
-
-static void free_blocks_annotations (void)
-{
-  clear_blocks_annotations ();  
-}
-
-
-/* Clear the annotations for all the basic blocks.  */
-
-static void
-clear_blocks_annotations (void)
-{
-  basic_block bb;
-
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
-    bb->tree_annotations = NULL;
-}
-
-
 /* Build a flowgraph for the statement_list STMT_LIST.  */
 
 static void
@@ -415,27 +368,24 @@ create_bb (void *h, void *e, basic_block after)
 
   bb->index = last_basic_block;
   bb->flags = BB_NEW;
-  bb->stmt_list = h ? h : alloc_stmt_list ();
+  bb->stmt_list = h ? (tree) h : alloc_stmt_list ();
 
   /* Add the new block to the linked list of blocks.  */
   link_block (bb, after);
 
   /* Grow the basic block array if needed.  */
-  if ((size_t) last_basic_block == VARRAY_SIZE (basic_block_info))
+  if ((size_t) last_basic_block == VEC_length (basic_block, basic_block_info))
     {
       size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
-      VARRAY_GROW (basic_block_info, new_size);
+      VEC_safe_grow_cleared (basic_block, gc, basic_block_info, new_size);
     }
 
   /* Add the newly created block to the array.  */
-  BASIC_BLOCK (last_basic_block) = bb;
-
-  create_block_annotation (bb);
+  SET_BASIC_BLOCK (last_basic_block, bb);
 
   n_basic_blocks++;
   last_basic_block++;
 
-  initialize_bb_rbi (bb);
   return bb;
 }
 
@@ -473,144 +423,149 @@ static void
 make_edges (void)
 {
   basic_block bb;
+  struct omp_region *cur_region = NULL;
 
   /* Create an edge from entry to the first block with executable
      statements in it.  */
-  make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (0), EDGE_FALLTHRU);
+  make_edge (ENTRY_BLOCK_PTR, BASIC_BLOCK (NUM_FIXED_BLOCKS), EDGE_FALLTHRU);
 
   /* Traverse the basic block array placing edges.  */
   FOR_EACH_BB (bb)
     {
-      tree first = first_stmt (bb);
       tree last = last_stmt (bb);
+      bool fallthru;
 
-      if (first)
+      if (last)
        {
-         /* Edges for statements that always alter flow control.  */
-         if (is_ctrl_stmt (last))
-           make_ctrl_stmt_edges (bb);
-
-         /* Edges for statements that sometimes alter flow control.  */
-         if (is_ctrl_altering_stmt (last))
-           make_exit_edges (bb);
-       }
-
-      /* Finally, if no edges were created above, this is a regular
-        basic block that only needs a fallthru edge.  */
-      if (EDGE_COUNT (bb->succs) == 0)
-       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-    }
-
-  /* We do not care about fake edges, so remove any that the CFG
-     builder inserted for completeness.  */
-  remove_fake_exit_edges ();
-
-  /* Fold COND_EXPR_COND of each COND_EXPR.  */
-  fold_cond_expr_cond ();
-
-  /* Clean up the graph and warn for unreachable code.  */
-  cleanup_tree_cfg ();
-}
-
+         enum tree_code code = TREE_CODE (last);
+         switch (code)
+           {
+           case GOTO_EXPR:
+             make_goto_expr_edges (bb);
+             fallthru = false;
+             break;
+           case RETURN_EXPR:
+             make_edge (bb, EXIT_BLOCK_PTR, 0);
+             fallthru = false;
+             break;
+           case COND_EXPR:
+             make_cond_expr_edges (bb);
+             fallthru = false;
+             break;
+           case SWITCH_EXPR:
+             make_switch_expr_edges (bb);
+             fallthru = false;
+             break;
+           case RESX_EXPR:
+             make_eh_edges (last);
+             fallthru = false;
+             break;
 
-/* Create edges for control statement at basic block BB.  */
+           case CALL_EXPR:
+             /* If this function receives a nonlocal goto, then we need to
+                make edges from this call site to all the nonlocal goto
+                handlers.  */
+             if (tree_can_make_abnormal_goto (last))
+               make_abnormal_goto_edges (bb, true);
 
-static void
-make_ctrl_stmt_edges (basic_block bb)
-{
-  tree last = last_stmt (bb);
+             /* If this statement has reachable exception handlers, then
+                create abnormal edges to them.  */
+             make_eh_edges (last);
 
-  gcc_assert (last);
-  switch (TREE_CODE (last))
-    {
-    case GOTO_EXPR:
-      make_goto_expr_edges (bb);
-      break;
+             /* Some calls are known not to return.  */
+             fallthru = !(call_expr_flags (last) & ECF_NORETURN);
+             break;
 
-    case RETURN_EXPR:
-      make_edge (bb, EXIT_BLOCK_PTR, 0);
-      break;
+           case MODIFY_EXPR:
+             gcc_unreachable ();
 
-    case COND_EXPR:
-      make_cond_expr_edges (bb);
-      break;
+           case GIMPLE_MODIFY_STMT:
+             if (is_ctrl_altering_stmt (last))
+               {
+                 /* A GIMPLE_MODIFY_STMT may have a CALL_EXPR on its RHS and
+                    the CALL_EXPR may have an abnormal edge.  Search the RHS
+                    for this case and create any required edges.  */
+                 if (tree_can_make_abnormal_goto (last))
+                   make_abnormal_goto_edges (bb, true);  
 
-    case SWITCH_EXPR:
-      make_switch_expr_edges (bb);
-      break;
+                 make_eh_edges (last);
+               }
+             fallthru = true;
+             break;
 
-    case RESX_EXPR:
-      make_eh_edges (last);
-      /* Yet another NORETURN hack.  */
-      if (EDGE_COUNT (bb->succs) == 0)
-       make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
-      break;
+           case OMP_PARALLEL:
+           case OMP_FOR:
+           case OMP_SINGLE:
+           case OMP_MASTER:
+           case OMP_ORDERED:
+           case OMP_CRITICAL:
+           case OMP_SECTION:
+             cur_region = new_omp_region (bb, code, cur_region);
+             fallthru = true;
+             break;
 
-    default:
-      gcc_unreachable ();
-    }
-}
+           case OMP_SECTIONS:
+             cur_region = new_omp_region (bb, code, cur_region);
+             fallthru = false;
+             break;
 
+           case OMP_RETURN:
+             /* In the case of an 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 != OMP_SECTION;
+             cur_region = cur_region->outer;
+             break;
 
-/* Create exit edges for statements in block BB that alter the flow of
-   control.  Statements that alter the control flow are 'goto', 'return'
-   and calls to non-returning functions.  */
+           case OMP_CONTINUE:
+             cur_region->cont = bb;
+             switch (cur_region->type)
+               {
+               case OMP_FOR:
+                 /* ??? Technically there should be a some sort of loopback
+                    edge here, but it goes to a block that doesn't exist yet,
+                    and without it, updating the ssa form would be a real
+                    bear.  Fortunately, we don't yet do ssa before expanding
+                    these nodes.  */
+                 break;
+
+               case OMP_SECTIONS:
+                 /* Wire up the edges into and out of the nested sections.  */
+                 /* ??? Similarly wrt loopback.  */
+                 {
+                   struct omp_region *i;
+                   for (i = cur_region->inner; i ; i = i->next)
+                     {
+                       gcc_assert (i->type == OMP_SECTION);
+                       make_edge (cur_region->entry, i->entry, 0);
+                       make_edge (i->exit, bb, EDGE_FALLTHRU);
+                     }
+                 }
+                 break;
 
-static void
-make_exit_edges (basic_block bb)
-{
-  tree last = last_stmt (bb), op;
+               default:
+                 gcc_unreachable ();
+               }
+             fallthru = true;
+             break;
 
-  gcc_assert (last);
-  switch (TREE_CODE (last))
-    {
-    case RESX_EXPR:
-      break;
-    case CALL_EXPR:
-      /* If this function receives a nonlocal goto, then we need to
-        make edges from this call site to all the nonlocal goto
-        handlers.  */
-      if (TREE_SIDE_EFFECTS (last)
-         && current_function_has_nonlocal_label)
-       make_goto_expr_edges (bb);
-
-      /* If this statement has reachable exception handlers, then
-        create abnormal edges to them.  */
-      make_eh_edges (last);
-
-      /* Some calls are known not to return.  For such calls we create
-        a fake edge.
-
-        We really need to revamp how we build edges so that it's not
-        such a bloody pain to avoid creating edges for this case since
-        all we do is remove these edges when we're done building the
-        CFG.  */
-      if (call_expr_flags (last) & ECF_NORETURN)
-       {
-         make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
-         return;
+           default:
+             gcc_assert (!stmt_ends_bb_p (last));
+             fallthru = true;
+           }
        }
+      else
+       fallthru = true;
 
-      /* Don't forget the fall-thru edge.  */
-      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
+      if (fallthru)
+       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+    }
 
-    case MODIFY_EXPR:
-      /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the CALL_EXPR
-        may have an abnormal edge.  Search the RHS for this case and
-        create any required edges.  */
-      op = get_call_expr_in (last);
-      if (op && TREE_SIDE_EFFECTS (op)
-         && current_function_has_nonlocal_label)
-       make_goto_expr_edges (bb);
-
-      make_eh_edges (last);
-      make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
-      break;
+  if (root_omp_region)
+    free_omp_regions ();
 
-    default:
-      gcc_unreachable ();
-    }
+  /* Fold COND_EXPR_COND of each COND_EXPR.  */
+  fold_cond_expr_cond ();
 }
 
 
@@ -623,6 +578,7 @@ make_cond_expr_edges (basic_block bb)
   tree entry = last_stmt (bb);
   basic_block then_bb, else_bb;
   tree then_label, else_label;
+  edge e;
 
   gcc_assert (entry);
   gcc_assert (TREE_CODE (entry) == COND_EXPR);
@@ -633,65 +589,54 @@ make_cond_expr_edges (basic_block bb)
   then_bb = label_to_block (then_label);
   else_bb = label_to_block (else_label);
 
-  make_edge (bb, then_bb, EDGE_TRUE_VALUE);
-  make_edge (bb, else_bb, EDGE_FALSE_VALUE);
-}
-
-/* Hashing routine for EDGE_TO_CASES.  */
-
-static hashval_t
-edge_to_cases_hash (const void *p)
-{
-  edge e = ((struct edge_to_cases_elt *)p)->e;
-
-  /* Hash on the edge itself (which is a pointer).  */
-  return htab_hash_pointer (e);
+  e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
+#ifdef USE_MAPPED_LOCATION
+  e->goto_locus = EXPR_LOCATION (COND_EXPR_THEN (entry));
+#else
+  e->goto_locus = EXPR_LOCUS (COND_EXPR_THEN (entry));
+#endif
+  e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
+  if (e)
+    {
+#ifdef USE_MAPPED_LOCATION
+      e->goto_locus = EXPR_LOCATION (COND_EXPR_ELSE (entry));
+#else
+      e->goto_locus = EXPR_LOCUS (COND_EXPR_ELSE (entry));
+#endif
+    }
 }
 
-/* Equality routine for EDGE_TO_CASES, edges are unique, so testing
-   for equality is just a pointer comparison.  */
-
-static int
-edge_to_cases_eq (const void *p1, const void *p2)
-{
-  edge e1 = ((struct edge_to_cases_elt *)p1)->e;
-  edge e2 = ((struct edge_to_cases_elt *)p2)->e;
-
-  return e1 == e2;
-}
 
 /* Called for each element in the hash table (P) as we delete the
    edge to cases hash table.
 
-   Clear all the TREE_CHAINs to prevent problems with copying of 
+   Clear all the TREE_CHAINs to prevent problems with copying of
    SWITCH_EXPRs and structure sharing rules, then free the hash table
    element.  */
 
-static void
-edge_to_cases_cleanup (void *p)
+static bool
+edge_to_cases_cleanup (void *key ATTRIBUTE_UNUSED, void **value,
+                      void *data ATTRIBUTE_UNUSED)
 {
-  struct edge_to_cases_elt *elt = p;
   tree t, next;
 
-  for (t = elt->case_labels; t; t = next)
+  for (t = (tree) *value; t; t = next)
     {
       next = TREE_CHAIN (t);
       TREE_CHAIN (t) = NULL;
     }
-  free (p);
+
+  *value = NULL;
+  return false;
 }
 
 /* Start recording information mapping edges to case labels.  */
 
-static void
+void
 start_recording_case_labels (void)
 {
   gcc_assert (edge_to_cases == NULL);
-
-  edge_to_cases = htab_create (37,
-                              edge_to_cases_hash,
-                              edge_to_cases_eq,
-                              edge_to_cases_cleanup);
+  edge_to_cases = pointer_map_create ();
 }
 
 /* Return nonzero if we are recording information for case labels.  */
@@ -704,49 +649,14 @@ recording_case_labels_p (void)
 
 /* Stop recording information mapping edges to case labels and
    remove any information we have recorded.  */
-static void
+void
 end_recording_case_labels (void)
 {
-  htab_delete (edge_to_cases);
+  pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL);
+  pointer_map_destroy (edge_to_cases);
   edge_to_cases = NULL;
 }
 
-/* Record that CASE_LABEL (a CASE_LABEL_EXPR) references edge E.  */
-
-static void
-record_switch_edge (edge e, tree case_label)
-{
-  struct edge_to_cases_elt *elt;
-  void **slot;
-
-  /* Build a hash table element so we can see if E is already
-     in the table.  */
-  elt = xmalloc (sizeof (struct edge_to_cases_elt));
-  elt->e = e;
-  elt->case_labels = case_label;
-
-  slot = htab_find_slot (edge_to_cases, elt, INSERT);
-
-  if (*slot == NULL)
-    {
-      /* E was not in the hash table.  Install E into the hash table.  */
-      *slot = (void *)elt;
-    }
-  else
-    {
-      /* E was already in the hash table.  Free ELT as we do not need it
-        anymore.  */
-      free (elt);
-
-      /* Get the entry stored in the hash table.  */
-      elt = (struct edge_to_cases_elt *) *slot;
-
-      /* Add it to the chain of CASE_LABEL_EXPRs referencing E.  */
-      TREE_CHAIN (case_label) = elt->case_labels;
-      elt->case_labels = case_label;
-    }
-}
-
 /* If we are inside a {start,end}_recording_cases block, then return
    a chain of CASE_LABEL_EXPRs from T which reference E.
 
@@ -755,7 +665,6 @@ record_switch_edge (edge e, tree case_label)
 static tree
 get_cases_for_edge (edge e, tree t)
 {
-  struct edge_to_cases_elt elt, *elt_p;
   void **slot;
   size_t i, n;
   tree vec;
@@ -764,17 +673,10 @@ get_cases_for_edge (edge e, tree t)
      chains available.  Return NULL so the caller can detect this case.  */
   if (!recording_case_labels_p ())
     return NULL;
-  
-restart:
-  elt.e = e;
-  elt.case_labels = NULL;
-  slot = htab_find_slot (edge_to_cases, &elt, NO_INSERT);
 
+  slot = pointer_map_contains (edge_to_cases, e);
   if (slot)
-    {
-      elt_p = (struct edge_to_cases_elt *)*slot;
-      return elt_p->case_labels;
-    }
+    return (tree) *slot;
 
   /* If we did not find E in the hash table, then this must be the first
      time we have been queried for information about E & T.  Add all the
@@ -784,11 +686,19 @@ restart:
   n = TREE_VEC_LENGTH (vec);
   for (i = 0; i < n; i++)
     {
-      tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
+      tree elt = TREE_VEC_ELT (vec, i);
+      tree lab = CASE_LABEL (elt);
       basic_block label_bb = label_to_block (lab);
-      record_switch_edge (find_edge (e->src, label_bb), TREE_VEC_ELT (vec, i));
+      edge this_edge = find_edge (e->src, label_bb);
+
+      /* Add it to the chain of CASE_LABEL_EXPRs referencing E, or create
+        a new chain.  */
+      slot = pointer_map_insert (edge_to_cases, this_edge);
+      TREE_CHAIN (elt) = (tree) *slot;
+      *slot = elt;
     }
-  goto restart;
+
+  return (tree) *pointer_map_contains (edge_to_cases, e);
 }
 
 /* Create the edges for a SWITCH_EXPR starting at block BB.
@@ -826,16 +736,48 @@ label_to_block_fn (struct function *ifun, tree dest)
      and undefined variable warnings quite right.  */
   if ((errorcount || sorrycount) && uid < 0)
     {
-      block_stmt_iterator bsi = bsi_start (BASIC_BLOCK (0));
+      block_stmt_iterator bsi =
+       bsi_start (BASIC_BLOCK (NUM_FIXED_BLOCKS));
       tree stmt;
 
       stmt = build1 (LABEL_EXPR, void_type_node, dest);
       bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
       uid = LABEL_DECL_UID (dest);
     }
-  if (VARRAY_SIZE (ifun->cfg->x_label_to_block_map) <= (unsigned int)uid)
+  if (VEC_length (basic_block, ifun->cfg->x_label_to_block_map)
+      <= (unsigned int) uid)
     return NULL;
-  return VARRAY_BB (ifun->cfg->x_label_to_block_map, uid);
+  return VEC_index (basic_block, ifun->cfg->x_label_to_block_map, uid);
+}
+
+/* Create edges for an abnormal goto statement at block BB.  If FOR_CALL
+   is true, the source statement is a CALL_EXPR instead of a GOTO_EXPR.  */
+
+void
+make_abnormal_goto_edges (basic_block bb, bool for_call)
+{
+  basic_block target_bb;
+  block_stmt_iterator bsi;
+
+  FOR_EACH_BB (target_bb)
+    for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       tree target = bsi_stmt (bsi);
+
+       if (TREE_CODE (target) != LABEL_EXPR)
+         break;
+
+       target = LABEL_EXPR_LABEL (target);
+
+       /* 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;
+         }
+      }
 }
 
 /* Create edges for a goto statement at block BB.  */
@@ -843,75 +785,25 @@ label_to_block_fn (struct function *ifun, tree dest)
 static void
 make_goto_expr_edges (basic_block bb)
 {
-  tree goto_t;
-  basic_block target_bb;
-  int for_call;
   block_stmt_iterator last = bsi_last (bb);
+  tree goto_t = bsi_stmt (last);
 
-  goto_t = bsi_stmt (last);
-
-  /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
-     CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
-     from a nonlocal goto.  */
-  if (TREE_CODE (goto_t) != GOTO_EXPR)
-    for_call = 1;
-  else
+  /* A simple GOTO creates normal edges.  */
+  if (simple_goto_p (goto_t))
     {
       tree dest = GOTO_DESTINATION (goto_t);
-      for_call = 0;
-
-      /* A GOTO to a local label creates normal edges.  */
-      if (simple_goto_p (goto_t))
-       {
-         edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+      edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
 #ifdef USE_MAPPED_LOCATION
-         e->goto_locus = EXPR_LOCATION (goto_t);
+      e->goto_locus = EXPR_LOCATION (goto_t);
 #else
-         e->goto_locus = EXPR_LOCUS (goto_t);
+      e->goto_locus = EXPR_LOCUS (goto_t);
 #endif
-         bsi_remove (&last);
-         return;
-       }
-
-      /* Nothing more to do for nonlocal gotos.  */
-      if (TREE_CODE (dest) == LABEL_DECL)
-       return;
-
-      /* Computed gotos remain.  */
-    }
-
-  /* Look for the block starting with the destination label.  In the
-     case of a computed goto, make an edge to any label block we find
-     in the CFG.  */
-  FOR_EACH_BB (target_bb)
-    {
-      block_stmt_iterator bsi;
-
-      for (bsi = bsi_start (target_bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       {
-         tree target = bsi_stmt (bsi);
-
-         if (TREE_CODE (target) != LABEL_EXPR)
-           break;
-
-         if (
-             /* Computed GOTOs.  Make an edge to every label block that has
-                been marked as a potential target for a computed goto.  */
-             (FORCED_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 0)
-             /* Nonlocal GOTO target.  Make an edge to every label block
-                that has been marked as a potential target for a nonlocal
-                goto.  */
-             || (DECL_NONLOCAL (LABEL_EXPR_LABEL (target)) && for_call == 1))
-           {
-             make_edge (bb, target_bb, EDGE_ABNORMAL);
-             break;
-           }
-       }
+      bsi_remove (&last, true);
+      return;
     }
 
-  /* Degenerate case of computed goto with no labels.  */
-  if (!for_call && EDGE_COUNT (bb->succs) == 0)
-    make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+  /* A computed GOTO creates abnormal edges.  */
+  make_abnormal_goto_edges (bb, false);
 }
 
 
@@ -919,73 +811,6 @@ make_goto_expr_edges (basic_block bb)
                               Flowgraph analysis
 ---------------------------------------------------------------------------*/
 
-/* Remove unreachable blocks and other miscellaneous clean up work.  */
-
-bool
-cleanup_tree_cfg (void)
-{
-  bool retval = false;
-
-  timevar_push (TV_TREE_CLEANUP_CFG);
-
-  retval = cleanup_control_flow ();
-  retval |= delete_unreachable_blocks ();
-
-  /* cleanup_forwarder_blocks can redirect edges out of SWITCH_EXPRs,
-     which can get expensive.  So we want to enable recording of edge
-     to CASE_LABEL_EXPR mappings around the call to
-     cleanup_forwarder_blocks.  */
-  start_recording_case_labels ();
-  retval |= cleanup_forwarder_blocks ();
-  end_recording_case_labels ();
-
-#ifdef ENABLE_CHECKING
-  if (retval)
-    {
-      gcc_assert (!cleanup_control_flow ());
-      gcc_assert (!delete_unreachable_blocks ());
-      gcc_assert (!cleanup_forwarder_blocks ());
-    }
-#endif
-
-  /* Merging the blocks creates no new opportunities for the other
-     optimizations, so do it here.  */
-  retval |= merge_seq_blocks ();
-
-  compact_blocks ();
-
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
-  timevar_pop (TV_TREE_CLEANUP_CFG);
-  return retval;
-}
-
-
-/* Cleanup cfg and repair loop structures.  */
-
-void
-cleanup_tree_cfg_loop (void)
-{
-  bitmap changed_bbs = BITMAP_ALLOC (NULL);
-
-  cleanup_tree_cfg ();
-
-  fix_loop_structure (current_loops, changed_bbs);
-  calculate_dominance_info (CDI_DOMINATORS);
-
-  /* This usually does nothing.  But sometimes parts of cfg that originally
-     were inside a loop get out of it due to edge removal (since they
-     become unreachable by back edges from latch).  */
-  rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa);
-
-  BITMAP_FREE (changed_bbs);
-
-#ifdef ENABLE_CHECKING
-  verify_loop_structure (current_loops);
-#endif
-}
-
 /* Cleanup useless labels in basic blocks.  This is something we wish
    to do early because it allows us to group case labels before creating
    the edges for the CFG, and it speeds up block statement iterators in
@@ -1038,7 +863,7 @@ void
 cleanup_dead_labels (void)
 {
   basic_block bb;
-  label_for_bb = xcalloc (last_basic_block, sizeof (tree));
+  label_for_bb = XCNEWVEC (tree, last_basic_block);
 
   /* Find a suitable label for each block.  We use the first user-defined
      label if there is one, or otherwise just the first label we see.  */
@@ -1099,13 +924,13 @@ cleanup_dead_labels (void)
 
            break;
          }
-  
+
        case SWITCH_EXPR:
          {
            size_t i;
            tree vec = SWITCH_LABELS (stmt);
            size_t n = TREE_VEC_LENGTH (vec);
-  
+
            /* Replace all destination labels.  */
            for (i = 0; i < n; ++i)
              {
@@ -1134,7 +959,8 @@ cleanup_dead_labels (void)
   for_each_eh_region (update_eh_label);
 
   /* Finally, purge dead labels.  All user-defined labels and labels that
-     can be the target of non-local gotos are preserved.  */
+     can be the target of non-local gotos and labels which have their
+     address taken are preserved.  */
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator i;
@@ -1154,10 +980,11 @@ cleanup_dead_labels (void)
 
          if (label == label_for_this_bb
              || ! DECL_ARTIFICIAL (label)
-             || DECL_NONLOCAL (label))
+             || DECL_NONLOCAL (label)
+             || FORCED_LABEL (label))
            bsi_next (&i);
          else
-           bsi_remove (&i);
+           bsi_remove (&i, true);
        }
     }
 
@@ -1183,7 +1010,7 @@ group_case_labels (void)
          int old_size = TREE_VEC_LENGTH (labels);
          int i, j, new_size = old_size;
          tree default_case = TREE_VEC_ELT (labels, old_size - 1);
-         tree default_label;
+         tree default_label;
 
          /* The default label is always the last case in a switch
             statement after gimplification.  */
@@ -1277,7 +1104,7 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
 
   if (b == EXIT_BLOCK_PTR)
     return false;
-  
+
   /* If A ends by a statement causing exceptions or something similar, we
      cannot merge the blocks.  */
   stmt = last_stmt (a);
@@ -1290,11 +1117,13 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
     return false;
 
   /* It must be possible to eliminate all phi nodes in B.  If ssa form
-     is not up-to-date, we cannot eliminate any phis.  */
+     is not up-to-date, we cannot eliminate any phis; however, if only
+     some symbols as whole are marked for renaming, this is not a problem,
+     as phi nodes for those symbols are irrelevant in updating anyway.  */
   phi = phi_nodes (b);
   if (phi)
     {
-      if (need_ssa_update_p ())
+      if (name_mappings_registered_p ())
        return false;
 
       for (; phi; phi = PHI_CHAIN (phi))
@@ -1330,45 +1159,60 @@ replace_uses_by (tree name, tree val)
   use_operand_p use;
   tree stmt;
   edge e;
-  unsigned i;
-  VEC(tree,heap) *stmts = VEC_alloc (tree, heap, 20);
 
-  FOR_EACH_IMM_USE_SAFE (use, imm_iter, name)
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
-      stmt = USE_STMT (use);
+      if (TREE_CODE (stmt) != PHI_NODE)
+       push_stmt_changes (&stmt);
 
-      SET_USE (use, val);
+      FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
+        {
+         replace_exp (use, val);
 
-      if (TREE_CODE (stmt) == PHI_NODE)
-       {
-         e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
-         if (e->flags & EDGE_ABNORMAL)
+         if (TREE_CODE (stmt) == PHI_NODE)
            {
-             /* This can only occur for virtual operands, since
-                for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
-                would prevent replacement.  */
-             gcc_assert (!is_gimple_reg (name));
-             SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+             e = PHI_ARG_EDGE (stmt, PHI_ARG_INDEX_FROM_USE (use));
+             if (e->flags & EDGE_ABNORMAL)
+               {
+                 /* This can only occur for virtual operands, since
+                    for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+                    would prevent replacement.  */
+                 gcc_assert (!is_gimple_reg (name));
+                 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+               }
            }
        }
-      else
-       VEC_safe_push (tree, heap, stmts, stmt);
+
+      if (TREE_CODE (stmt) != PHI_NODE)
+       {
+         tree rhs;
+
+         fold_stmt_inplace (stmt);
+
+         /* FIXME.  This should go in pop_stmt_changes.  */
+         rhs = get_rhs (stmt);
+         if (TREE_CODE (rhs) == ADDR_EXPR)
+           recompute_tree_invariant_for_addr_expr (rhs);
+
+         maybe_clean_or_replace_eh_stmt (stmt, stmt);
+
+         pop_stmt_changes (&stmt);
+       }
     }
-  /* We do not update the statements in the loop above.  Consider
-     x = w * w;
-
-     If we performed the update in the first loop, the statement
-     would be rescanned after first occurence of w is replaced,
-     the new uses would be placed to the beginning of the list,
-     and we would never process them.  */
-  for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++)
+
+  gcc_assert (zero_imm_uses_p (name));
+
+  /* Also update the trees stored in loop structures.  */
+  if (current_loops)
     {
-      fold_stmt_inplace (stmt);
-      update_stmt (stmt);
-    }
+      struct loop *loop;
+      loop_iterator li;
 
-  VEC_free (tree, heap, stmts);
+      FOR_EACH_LOOP (li, loop, 0)
+       {
+         substitute_in_loop_info (loop, name, val);
+       }
+    }
 }
 
 /* Merge block B into block A.  */
@@ -1383,33 +1227,41 @@ tree_merge_blocks (basic_block a, basic_block b)
   if (dump_file)
     fprintf (dump_file, "Merging blocks %d and %d\n", a->index, b->index);
 
-  /* Remove the phi nodes.  */
+  /* Remove all single-valued PHI nodes from block B of the form
+     V_i = PHI <V_j> by propagating V_j to all the uses of V_i.  */
   bsi = bsi_last (a);
   for (phi = phi_nodes (b); phi; phi = phi_nodes (b))
     {
       tree def = PHI_RESULT (phi), use = PHI_ARG_DEF (phi, 0);
       tree copy;
-      
-      if (!may_propagate_copy (def, use)
-         /* Propagating pointers might cause the set of vops for statements
-            to be changed, and thus require ssa form update.  */
-         || (is_gimple_reg (def)
-             && POINTER_TYPE_P (TREE_TYPE (def))))
+      bool may_replace_uses = may_propagate_copy (def, use);
+
+      /* In case we have loops to care about, do not propagate arguments of
+        loop closed ssa phi nodes.  */
+      if (current_loops
+         && is_gimple_reg (def)
+         && TREE_CODE (use) == SSA_NAME
+         && a->loop_father != b->loop_father)
+       may_replace_uses = false;
+
+      if (!may_replace_uses)
        {
          gcc_assert (is_gimple_reg (def));
 
-         /* Note that just emiting the copies is fine -- there is no problem
+         /* Note that just emitting the copies is fine -- there is no problem
             with ordering of phi nodes.  This is because A is the single
             predecessor of B, therefore results of the phi nodes cannot
             appear as arguments of the phi nodes.  */
-         copy = build2 (MODIFY_EXPR, void_type_node, def, use);
+         copy = build2_gimple (GIMPLE_MODIFY_STMT, def, use);
          bsi_insert_after (&bsi, copy, BSI_NEW_STMT);
-         SET_PHI_RESULT (phi, NULL_TREE);
          SSA_NAME_DEF_STMT (def) = copy;
+          remove_phi_node (phi, NULL, false);
        }
       else
-       replace_uses_by (def, use);
-      remove_phi_node (phi, NULL);
+        {
+          replace_uses_by (def, use);
+          remove_phi_node (phi, NULL, true);
+        }
     }
 
   /* Ensure that B follows A.  */
@@ -1425,7 +1277,7 @@ tree_merge_blocks (basic_block a, basic_block b)
        {
          tree label = bsi_stmt (bsi);
 
-         bsi_remove (&bsi);
+         bsi_remove (&bsi, false);
          /* Now that we can thread computed gotos, we might have
             a situation where we have a forced label in block B
             However, the label at the start of block B might still be
@@ -1440,7 +1292,7 @@ tree_merge_blocks (basic_block a, basic_block b)
        }
       else
        {
-         set_bb_for_stmt (bsi_stmt (bsi), a);
+         change_bb_for_stmt (bsi_stmt (bsi), a);
          bsi_next (&bsi);
        }
     }
@@ -1452,13 +1304,36 @@ tree_merge_blocks (basic_block a, basic_block b)
 }
 
 
-/* Walk the function tree removing unnecessary statements.
+/* Return the one of two successors of BB that is not reachable by a
+   reached by a complex edge, if there is one.  Else, return BB.  We use
+   this in optimizations that use post-dominators for their heuristics,
+   to catch the cases in C++ where function calls are involved.  */
 
-     * Empty statement nodes are removed
+basic_block
+single_noncomplex_succ (basic_block bb)
+{
+  edge e0, e1;
+  if (EDGE_COUNT (bb->succs) != 2)
+    return bb;
 
-     * Unnecessary TRY_FINALLY and TRY_CATCH blocks are removed
+  e0 = EDGE_SUCC (bb, 0);
+  e1 = EDGE_SUCC (bb, 1);
+  if (e0->flags & EDGE_COMPLEX)
+    return e1->dest;
+  if (e1->flags & EDGE_COMPLEX)
+    return e0->dest;
 
-     * Unnecessary COND_EXPRs are removed
+  return bb;
+}
+
+
+/* Walk the function tree removing unnecessary statements.
+
+     * Empty statement nodes are removed
+
+     * Unnecessary TRY_FINALLY and TRY_CATCH blocks are removed
+
+     * Unnecessary COND_EXPRs are removed
 
      * Some unnecessary BIND_EXPRs are removed
 
@@ -1607,9 +1482,9 @@ remove_useless_stmts_cond (tree *stmt_p, struct rus_data *data)
       else if (TREE_CODE (cond) == VAR_DECL || TREE_CODE (cond) == PARM_DECL)
        {
          if (else_stmt
-             && TREE_CODE (else_stmt) == MODIFY_EXPR
-             && TREE_OPERAND (else_stmt, 0) == cond
-             && integer_zerop (TREE_OPERAND (else_stmt, 1)))
+             && TREE_CODE (else_stmt) == GIMPLE_MODIFY_STMT
+             && GIMPLE_STMT_OPERAND (else_stmt, 0) == cond
+             && integer_zerop (GIMPLE_STMT_OPERAND (else_stmt, 1)))
            COND_EXPR_ELSE (*stmt_p) = alloc_stmt_list ();
        }
       else if ((TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
@@ -1624,9 +1499,9 @@ remove_useless_stmts_cond (tree *stmt_p, struct rus_data *data)
                            : &COND_EXPR_ELSE (*stmt_p));
 
          if (stmt
-             && TREE_CODE (stmt) == MODIFY_EXPR
-             && TREE_OPERAND (stmt, 0) == TREE_OPERAND (cond, 0)
-             && TREE_OPERAND (stmt, 1) == TREE_OPERAND (cond, 1))
+             && TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+             && GIMPLE_STMT_OPERAND (stmt, 0) == TREE_OPERAND (cond, 0)
+             && GIMPLE_STMT_OPERAND (stmt, 1) == TREE_OPERAND (cond, 1))
            *location = alloc_stmt_list ();
        }
     }
@@ -1828,7 +1703,7 @@ remove_useless_stmts_label (tree *stmt_p, struct rus_data *data)
 
 /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
    decl.  This allows us to eliminate redundant or useless
-   calls to "const" functions. 
+   calls to "const" functions.
 
    Gimplifier already does the same operation, but we may notice functions
    being const and pure once their calls has been gimplified, so we need
@@ -1919,6 +1794,9 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
       break;
 
     case MODIFY_EXPR:
+      gcc_unreachable ();
+
+    case GIMPLE_MODIFY_STMT:
       data->last_goto = NULL;
       fold_stmt (tp);
       op = get_call_expr_in (t);
@@ -1942,7 +1820,7 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
                tsi_delink (&i);
                continue;
              }
-           
+
            remove_useless_stmts_1 (tsi_stmt_ptr (i), data);
 
            t = tsi_stmt (i);
@@ -1967,7 +1845,7 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
     }
 }
 
-static void
+static unsigned int
 remove_useless_stmts (void)
 {
   struct rus_data data;
@@ -1980,10 +1858,11 @@ remove_useless_stmts (void)
       remove_useless_stmts_1 (&DECL_SAVED_TREE (current_function_decl), &data);
     }
   while (data.repeat);
+  return 0;
 }
 
 
-struct tree_opt_pass pass_remove_useless_stmts = 
+struct tree_opt_pass pass_remove_useless_stmts =
 {
   "useless",                           /* name */
   NULL,                                        /* gate */
@@ -2013,7 +1892,7 @@ remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
   while (phi)
     {
       tree next = PHI_CHAIN (phi);
-      remove_phi_node (phi, NULL_TREE);
+      remove_phi_node (phi, NULL_TREE, true);
       phi = next;
     }
 
@@ -2045,18 +1924,15 @@ remove_bb (basic_block bb)
        }
     }
 
-  /* If we remove the header or the latch of a loop, mark the loop for
-     removal by setting its header and latch to NULL.  */
   if (current_loops)
     {
       struct loop *loop = bb->loop_father;
 
+      /* If a loop gets removed, clean up the information associated
+        with it.  */
       if (loop->latch == bb
          || loop->header == bb)
-       {
-         loop->latch = NULL;
-         loop->header = NULL;
-       }
+       free_numbers_of_iterations_estimates_loop (loop);
     }
 
   /* Remove all the instructions in the block.  */
@@ -2064,19 +1940,36 @@ remove_bb (basic_block bb)
     {
       tree stmt = bsi_stmt (i);
       if (TREE_CODE (stmt) == LABEL_EXPR
-          && FORCED_LABEL (LABEL_EXPR_LABEL (stmt)))
+          && (FORCED_LABEL (LABEL_EXPR_LABEL (stmt))
+             || DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))))
        {
-         basic_block new_bb = bb->prev_bb;
-         block_stmt_iterator new_bsi = bsi_start (new_bb);
-                 
-         bsi_remove (&i);
+         basic_block new_bb;
+         block_stmt_iterator new_bsi;
+
+         /* A non-reachable non-local label may still be referenced.
+            But it no longer needs to carry the extra semantics of
+            non-locality.  */
+         if (DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
+           {
+             DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)) = 0;
+             FORCED_LABEL (LABEL_EXPR_LABEL (stmt)) = 1;
+           }
+
+         new_bb = bb->prev_bb;
+         new_bsi = bsi_start (new_bb);
+         bsi_remove (&i, false);
          bsi_insert_before (&new_bsi, stmt, BSI_NEW_STMT);
        }
       else
         {
-         release_defs (stmt);
-
-         bsi_remove (&i);
+         /* Release SSA definitions if we are in SSA.  Note that we
+            may be called when not in SSA.  For example,
+            final_cleanup calls this function via
+            cleanup_tree_cfg.  */
+         if (gimple_in_ssa_p (cfun))
+           release_defs (stmt);
+
+         bsi_remove (&i, true);
        }
 
       /* Don't warn for removed gotos.  Gotos are often removed due to
@@ -2102,192 +1995,16 @@ remove_bb (basic_block bb)
      loop above, so the last statement we process is the first statement
      in the block.  */
 #ifdef USE_MAPPED_LOCATION
-  if (warn_notreached && loc > BUILTINS_LOCATION)
-    warning (0, "%Hwill never be executed", &loc);
+  if (loc > BUILTINS_LOCATION)
+    warning (OPT_Wunreachable_code, "%Hwill never be executed", &loc);
 #else
-  if (warn_notreached && loc)
-    warning (0, "%Hwill never be executed", loc);
+  if (loc)
+    warning (OPT_Wunreachable_code, "%Hwill never be executed", loc);
 #endif
 
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
 }
 
-/* A list of all the noreturn calls passed to modify_stmt.
-   cleanup_control_flow uses it to detect cases where a mid-block
-   indirect call has been turned into a noreturn call.  When this
-   happens, all the instructions after the call are no longer
-   reachable and must be deleted as dead.  */
-
-VEC(tree,gc) *modified_noreturn_calls;
-
-/* Try to remove superfluous control structures.  */
-
-static bool
-cleanup_control_flow (void)
-{
-  basic_block bb;
-  block_stmt_iterator bsi;
-  bool retval = false;
-  tree stmt;
-
-  /* Detect cases where a mid-block call is now known not to return.  */
-  while (VEC_length (tree, modified_noreturn_calls))
-    {
-      stmt = VEC_pop (tree, modified_noreturn_calls);
-      bb = bb_for_stmt (stmt);
-      if (bb != NULL && last_stmt (bb) != stmt && noreturn_call_p (stmt))
-       split_block (bb, stmt);
-    }
-
-  FOR_EACH_BB (bb)
-    {
-      bsi = bsi_last (bb);
-
-      if (bsi_end_p (bsi))
-       continue;
-      
-      stmt = bsi_stmt (bsi);
-      if (TREE_CODE (stmt) == COND_EXPR
-         || TREE_CODE (stmt) == SWITCH_EXPR)
-       retval |= cleanup_control_expr_graph (bb, bsi);
-
-      /* If we had a computed goto which has a compile-time determinable
-        destination, then we can eliminate the goto.  */
-      if (TREE_CODE (stmt) == GOTO_EXPR
-         && TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR
-         && TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0)) == LABEL_DECL)
-       {
-         edge e;
-         tree label;
-         edge_iterator ei;
-         basic_block target_block;
-         bool removed_edge = false;
-
-         /* First look at all the outgoing edges.  Delete any outgoing
-            edges which do not go to the right block.  For the one
-            edge which goes to the right block, fix up its flags.  */
-         label = TREE_OPERAND (GOTO_DESTINATION (stmt), 0);
-         target_block = label_to_block (label);
-         for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
-           {
-             if (e->dest != target_block)
-               {
-                 removed_edge = true;
-                 remove_edge (e);
-               }
-             else
-               {
-                 /* Turn off the EDGE_ABNORMAL flag.  */
-                 e->flags &= ~EDGE_ABNORMAL;
-
-                 /* And set EDGE_FALLTHRU.  */
-                 e->flags |= EDGE_FALLTHRU;
-                 ei_next (&ei);
-               }
-           }
-
-         /* If we removed one or more edges, then we will need to fix the
-            dominators.  It may be possible to incrementally update them.  */
-         if (removed_edge)
-           free_dominance_info (CDI_DOMINATORS);
-
-         /* Remove the GOTO_EXPR as it is not needed.  The CFG has all the
-            relevant information we need.  */
-         bsi_remove (&bsi);
-         retval = true;
-       }
-
-      /* Check for indirect calls that have been turned into
-        noreturn calls.  */
-      if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs))
-       {
-         free_dominance_info (CDI_DOMINATORS);
-         retval = true;
-       }
-    }
-  return retval;
-}
-
-
-/* Disconnect an unreachable block in the control expression starting
-   at block BB.  */
-
-static bool
-cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
-{
-  edge taken_edge;
-  bool retval = false;
-  tree expr = bsi_stmt (bsi), val;
-
-  if (!single_succ_p (bb))
-    {
-      edge e;
-      edge_iterator ei;
-
-      switch (TREE_CODE (expr))
-       {
-       case COND_EXPR:
-         val = COND_EXPR_COND (expr);
-         break;
-
-       case SWITCH_EXPR:
-         val = SWITCH_COND (expr);
-         if (TREE_CODE (val) != INTEGER_CST)
-           return false;
-         break;
-
-       default:
-         gcc_unreachable ();
-       }
-
-      taken_edge = find_taken_edge (bb, val);
-      if (!taken_edge)
-       return false;
-
-      /* Remove all the edges except the one that is always executed.  */
-      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
-       {
-         if (e != taken_edge)
-           {
-             taken_edge->probability += e->probability;
-             taken_edge->count += e->count;
-             remove_edge (e);
-             retval = true;
-           }
-         else
-           ei_next (&ei);
-       }
-      if (taken_edge->probability > REG_BR_PROB_BASE)
-       taken_edge->probability = REG_BR_PROB_BASE;
-    }
-  else
-    taken_edge = single_succ_edge (bb);
-
-  bsi_remove (&bsi);
-  taken_edge->flags = EDGE_FALLTHRU;
-
-  /* We removed some paths from the cfg.  */
-  free_dominance_info (CDI_DOMINATORS);
-
-  return retval;
-}
-
-/* Remove any fallthru edge from EV.  Return true if an edge was removed.  */
-
-static bool
-remove_fallthru_edge (VEC(edge,gc) *ev)
-{
-  edge_iterator ei;
-  edge e;
-
-  FOR_EACH_EDGE (e, ei, ev)
-    if ((e->flags & EDGE_FALLTHRU) != 0)
-      {
-       remove_edge (e);
-       return true;
-      }
-  return false;
-}
 
 /* Given a basic block BB ending with COND_EXPR or SWITCH_EXPR, and a
    predicate VAL, return the edge that will be taken out of the block.
@@ -2349,9 +2066,9 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
   edge true_edge, false_edge;
 
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
-  
+
   gcc_assert (TREE_CODE (val) == INTEGER_CST);
-  return (zero_p (val) ? false_edge : true_edge);
+  return (integer_zerop (val) ? false_edge : true_edge);
 }
 
 /* Given an INTEGER_CST VAL and the entry block BB to a SWITCH_EXPR
@@ -2418,31 +2135,6 @@ find_case_label_for_value (tree switch_expr, tree val)
 }
 
 
-/* If all the PHI nodes in DEST have alternatives for E1 and E2 and
-   those alternatives are equal in each of the PHI nodes, then return
-   true, else return false.  */
-
-static bool
-phi_alternatives_equal (basic_block dest, edge e1, edge e2)
-{
-  int n1 = e1->dest_idx;
-  int n2 = e2->dest_idx;
-  tree phi;
-
-  for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
-    {
-      tree val1 = PHI_ARG_DEF (phi, n1);
-      tree val2 = PHI_ARG_DEF (phi, n2);
-
-      gcc_assert (val1 != NULL_TREE);
-      gcc_assert (val2 != NULL_TREE);
-
-      if (!operand_equal_for_phi_arg_p (val1, val2))
-       return false;
-    }
-
-  return true;
-}
 
 
 /*---------------------------------------------------------------------------
@@ -2454,7 +2146,7 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
 void
 tree_dump_bb (basic_block bb, FILE *outf, int indent)
 {
-  dump_generic_bb (outf, bb, indent, TDF_VOPS);
+  dump_generic_bb (outf, bb, indent, TDF_VOPS|TDF_MEMSYMS);
 }
 
 
@@ -2474,13 +2166,13 @@ debug_tree_bb_n (int n)
 {
   debug_tree_bb (BASIC_BLOCK (n));
   return BASIC_BLOCK (n);
-}       
+}
 
 
 /* Dump the CFG on stderr.
 
    FLAGS are the same used by the tree dumping functions
-   (see TDF_* in tree.h).  */
+   (see TDF_* in tree-pass.h).  */
 
 void
 debug_tree_cfg (int flags)
@@ -2529,6 +2221,7 @@ dump_cfg_stats (FILE *file)
   basic_block bb;
   const char * const fmt_str   = "%-30s%-13s%12s\n";
   const char * const fmt_str_1 = "%-30s%13d%11lu%c\n";
+  const char * const fmt_str_2 = "%-30s%13ld%11lu%c\n";
   const char * const fmt_str_3 = "%-43s%11lu%c\n";
   const char *funcname
     = lang_hooks.decl_printable_name (current_function_decl, 2);
@@ -2551,12 +2244,7 @@ dump_cfg_stats (FILE *file)
     num_edges += EDGE_COUNT (bb->succs);
   size = num_edges * sizeof (struct edge_def);
   total += size;
-  fprintf (file, fmt_str_1, "Edges", num_edges, SCALE (size), LABEL (size));
-
-  size = n_basic_blocks * sizeof (struct bb_ann_d);
-  total += size;
-  fprintf (file, fmt_str_1, "Basic block annotations", n_basic_blocks,
-          SCALE (size), LABEL (size));
+  fprintf (file, fmt_str_2, "Edges", num_edges, SCALE (size), LABEL (size));
 
   fprintf (file, "---------------------------------------------------------\n");
   fprintf (file, fmt_str_3, "Total memory used by CFG data", SCALE (total),
@@ -2709,6 +2397,10 @@ is_ctrl_altering_stmt (tree t)
        return true;
     }
 
+  /* OpenMP directives alter control flow.  */
+  if (OMP_DIRECTIVE_P (t))
+    return true;
+
   /* If a statement can throw, it alters control flow.  */
   return tree_can_throw_internal (t);
 }
@@ -2724,13 +2416,31 @@ computed_goto_p (tree t)
 }
 
 
-/* Checks whether EXPR is a simple local goto.  */
+/* Return true if T is a simple local goto.  */
 
 bool
-simple_goto_p (tree expr)
+simple_goto_p (tree t)
 {
-  return (TREE_CODE (expr) == GOTO_EXPR
-         && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL);
+  return (TREE_CODE (t) == GOTO_EXPR
+         && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL);
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+   Transfers of control flow associated with EH are excluded.  */
+
+bool
+tree_can_make_abnormal_goto (tree t)
+{
+  if (computed_goto_p (t))
+    return true;
+  if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
+    t = GIMPLE_STMT_OPERAND (t, 1);
+  if (TREE_CODE (t) == WITH_SIZE_EXPR)
+    t = TREE_OPERAND (t, 0);
+  if (TREE_CODE (t) == CALL_EXPR)
+    return TREE_SIDE_EFFECTS (t) && current_function_has_nonlocal_label;
+  return false;
 }
 
 
@@ -2829,7 +2539,7 @@ disband_implicit_edges (void)
          if (bb->next_bb == EXIT_BLOCK_PTR
              && !TREE_OPERAND (stmt, 0))
            {
-             bsi_remove (&last);
+             bsi_remove (&last, true);
              single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
            }
          continue;
@@ -2868,12 +2578,17 @@ void
 delete_tree_cfg_annotations (void)
 {
   basic_block bb;
-  if (n_basic_blocks > 0)
-    free_blocks_annotations ();
+  block_stmt_iterator bsi;
 
-  label_to_block_map = NULL;
+  /* Remove annotations from every tree in the function.  */
   FOR_EACH_BB (bb)
-    bb->rbi = NULL;
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       tree stmt = bsi_stmt (bsi);
+       ggc_free (stmt->base.ann);
+       stmt->base.ann = NULL;
+      }
+  label_to_block_map = NULL;
 }
 
 
@@ -2897,16 +2612,6 @@ last_stmt (basic_block bb)
 }
 
 
-/* Return a pointer to the last statement in block BB.  */
-
-tree *
-last_stmt_ptr (basic_block bb)
-{
-  block_stmt_iterator last = bsi_last (bb);
-  return !bsi_end_p (last) ? bsi_stmt_ptr (last) : NULL;
-}
-
-
 /* Return the last statement of an otherwise empty block.  Return NULL
    if the block is totally empty, or if it contains more than one
    statement.  */
@@ -2959,7 +2664,7 @@ set_bb_for_stmt (tree t, basic_block bb)
       ann->bb = bb;
 
       /* If the statement is a label, add the label to block-to-labels map
-        so that we can speed up edge creation for GOTO_EXPRs.  */
+        so that we can speed up edge creation for GOTO_EXPRs.  */
       if (TREE_CODE (t) == LABEL_EXPR)
        {
          int uid;
@@ -2968,19 +2673,40 @@ set_bb_for_stmt (tree t, basic_block bb)
          uid = LABEL_DECL_UID (t);
          if (uid == -1)
            {
+             unsigned old_len = VEC_length (basic_block, label_to_block_map);
              LABEL_DECL_UID (t) = uid = cfun->last_label_uid++;
-             if (VARRAY_SIZE (label_to_block_map) <= (unsigned) uid)
-               VARRAY_GROW (label_to_block_map, 3 * uid / 2);
+             if (old_len <= (unsigned) uid)
+               {
+                 unsigned new_len = 3 * uid / 2;
+
+                 VEC_safe_grow_cleared (basic_block, gc, label_to_block_map,
+                                        new_len);
+               }
            }
          else
            /* We're moving an existing label.  Make sure that we've
                removed it from the old block.  */
-           gcc_assert (!bb || !VARRAY_BB (label_to_block_map, uid));
-         VARRAY_BB (label_to_block_map, uid) = bb;
+           gcc_assert (!bb
+                       || !VEC_index (basic_block, label_to_block_map, uid));
+         VEC_replace (basic_block, label_to_block_map, uid, bb);
        }
     }
 }
 
+/* Faster version of set_bb_for_stmt that assume that statement is being moved
+   from one basic block to another.  
+   For BB splitting we can run into quadratic case, so performance is quite
+   important and knowing that the tables are big enough, change_bb_for_stmt
+   can inline as leaf function.  */
+static inline void
+change_bb_for_stmt (tree t, basic_block bb)
+{
+  get_stmt_ann (t)->bb = bb;
+  if (TREE_CODE (t) == LABEL_EXPR)
+    VEC_replace (basic_block, label_to_block_map,
+                LABEL_DECL_UID (LABEL_EXPR_LABEL (t)), bb);
+}
+
 /* Finds iterator for STMT.  */
 
 extern block_stmt_iterator
@@ -2999,6 +2725,8 @@ bsi_for_stmt (tree stmt)
 static inline void
 update_modified_stmts (tree t)
 {
+  if (!ssa_operands_active ())
+    return;
   if (TREE_CODE (t) == STATEMENT_LIST)
     {
       tree_stmt_iterator i;
@@ -3040,37 +2768,49 @@ bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 
 
 /* Remove the statement pointed to by iterator I.  The iterator is updated
-   to the next statement.  */
+   to the next statement.
+
+   When REMOVE_EH_INFO is true we remove the statement pointed to by
+   iterator I from the EH tables.  Otherwise we do not modify the EH
+   tables.
+
+   Generally, REMOVE_EH_INFO should be true when the statement is going to
+   be removed from the IL and not reinserted elsewhere.  */
 
 void
-bsi_remove (block_stmt_iterator *i)
+bsi_remove (block_stmt_iterator *i, bool remove_eh_info)
 {
   tree t = bsi_stmt (*i);
   set_bb_for_stmt (t, NULL);
   delink_stmt_imm_use (t);
   tsi_delink (&i->tsi);
   mark_stmt_modified (t);
+  if (remove_eh_info)
+    {
+      remove_stmt_from_eh_region (t);
+      gimple_remove_stmt_histograms (cfun, t);
+    }
 }
 
 
 /* Move the statement at FROM so it comes right after the statement at TO.  */
 
-void 
+void
 bsi_move_after (block_stmt_iterator *from, block_stmt_iterator *to)
 {
   tree stmt = bsi_stmt (*from);
-  bsi_remove (from);
+  bsi_remove (from, false);
   bsi_insert_after (to, stmt, BSI_SAME_STMT);
-} 
+}
 
 
 /* Move the statement at FROM so it comes right before the statement at TO.  */
 
-void 
+void
 bsi_move_before (block_stmt_iterator *from, block_stmt_iterator *to)
 {
   tree stmt = bsi_stmt (*from);
-  bsi_remove (from);
+  bsi_remove (from, false);
   bsi_insert_before (to, stmt, BSI_SAME_STMT);
 }
 
@@ -3081,7 +2821,7 @@ void
 bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb)
 {
   block_stmt_iterator last = bsi_last (bb);
-  
+
   /* Have to check bsi_end_p because it could be an empty block.  */
   if (!bsi_end_p (last) && is_ctrl_stmt (bsi_stmt (last)))
     bsi_move_before (from, &last);
@@ -3091,27 +2831,34 @@ bsi_move_to_bb_end (block_stmt_iterator *from, basic_block bb)
 
 
 /* Replace the contents of the statement pointed to by iterator BSI
-   with STMT.  If PRESERVE_EH_INFO is true, the exception handling
-   information of the original statement is preserved.  */
+   with STMT.  If UPDATE_EH_INFO is true, the exception handling
+   information of the original statement is moved to the new statement.  */
 
 void
-bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool preserve_eh_info)
+bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool update_eh_info)
 {
   int eh_region;
   tree orig_stmt = bsi_stmt (*bsi);
 
+  if (stmt == orig_stmt)
+    return;
   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (orig_stmt));
   set_bb_for_stmt (stmt, bsi->bb);
 
   /* Preserve EH region information from the original statement, if
      requested by the caller.  */
-  if (preserve_eh_info)
+  if (update_eh_info)
     {
       eh_region = lookup_stmt_eh_region (orig_stmt);
       if (eh_region >= 0)
-       add_stmt_to_eh_region (stmt, eh_region);
+       {
+         remove_stmt_from_eh_region (orig_stmt);
+         add_stmt_to_eh_region (stmt, eh_region);
+       }
     }
 
+  gimple_duplicate_stmt_histograms (cfun, stmt, cfun, orig_stmt);
+  gimple_remove_stmt_histograms (cfun, orig_stmt);
   delink_stmt_imm_use (orig_stmt);
   *bsi_stmt_ptr (*bsi) = stmt;
   mark_stmt_modified (stmt);
@@ -3140,7 +2887,7 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
  restart:
 
   /* If the destination has one predecessor which has no PHI nodes,
-     insert there.  Except for the exit block. 
+     insert there.  Except for the exit block.
 
      The requirement for no PHI nodes could be relaxed.  Basically we
      would have to examine the PHIs to prove that none of them used
@@ -3194,11 +2941,11 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
       if (TREE_CODE (tmp) == RETURN_EXPR)
         {
          tree op = TREE_OPERAND (tmp, 0);
-         if (!is_gimple_val (op))
+         if (op && !is_gimple_val (op))
            {
-             gcc_assert (TREE_CODE (op) == MODIFY_EXPR);
+             gcc_assert (TREE_CODE (op) == GIMPLE_MODIFY_STMT);
              bsi_insert_before (bsi, op, BSI_NEW_STMT);
-             TREE_OPERAND (tmp, 0) = TREE_OPERAND (op, 0);
+             TREE_OPERAND (tmp, 0) = GIMPLE_STMT_OPERAND (op, 0);
            }
          bsi_prev (bsi);
          return true;
@@ -3296,7 +3043,7 @@ reinstall_phi_args (edge new_edge, edge old_edge)
 
   if (!PENDING_STMT (old_edge))
     return;
-  
+
   for (var = PENDING_STMT (old_edge), phi = phi_nodes (new_edge->dest);
        var && phi;
        var = TREE_CHAIN (var), phi = PHI_CHAIN (phi))
@@ -3312,28 +3059,37 @@ reinstall_phi_args (edge new_edge, edge old_edge)
   PENDING_STMT (old_edge) = NULL;
 }
 
+/* Returns the basic block after which the new basic block created
+   by splitting edge EDGE_IN should be placed.  Tries to keep the new block
+   near its "logical" location.  This is of most help to humans looking
+   at debugging dumps.  */
+
+static basic_block
+split_edge_bb_loc (edge edge_in)
+{
+  basic_block dest = edge_in->dest;
+
+  if (dest->prev_bb && find_edge (dest->prev_bb, dest))
+    return edge_in->src;
+  else
+    return dest->prev_bb;
+}
+
 /* Split a (typically critical) edge EDGE_IN.  Return the new block.
    Abort on abnormal edges.  */
 
 static basic_block
 tree_split_edge (edge edge_in)
 {
-  basic_block new_bb, after_bb, dest, src;
+  basic_block new_bb, after_bb, dest;
   edge new_edge, e;
 
   /* Abnormal edges cannot be split.  */
   gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
 
-  src = edge_in->src;
   dest = edge_in->dest;
 
-  /* Place the new block in the block list.  Try to keep the new block
-     near its "logical" location.  This is of most help to humans looking
-     at debugging dumps.  */
-  if (dest->prev_bb && find_edge (dest->prev_bb, dest))
-    after_bb = edge_in->src;
-  else
-    after_bb = dest->prev_bb;
+  after_bb = split_edge_bb_loc (edge_in);
 
   new_bb = create_empty_bb (after_bb);
   new_bb->frequency = EDGE_FREQUENCY (edge_in);
@@ -3382,13 +3138,10 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
   if (TYPE_P (t))
     *walk_subtrees = 0;
-  
-  /* Check operand N for being valid GIMPLE and give error MSG if not. 
-     We check for constants explicitly since they are not considered
-     gimple invariants if they overflowed.  */
+
+  /* Check operand N for being valid GIMPLE and give error MSG if not.  */
 #define CHECK_OP(N, MSG) \
-  do { if (!CONSTANT_CLASS_P (TREE_OPERAND (t, N))             \
-         && !is_gimple_val (TREE_OPERAND (t, N)))              \
+  do { if (!is_gimple_val (TREE_OPERAND (t, N)))               \
        { error (MSG); return TREE_OPERAND (t, N); }} while (0)
 
   switch (TREE_CODE (t))
@@ -3411,7 +3164,10 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case MODIFY_EXPR:
-      x = TREE_OPERAND (t, 0);
+      gcc_unreachable ();
+
+    case GIMPLE_MODIFY_STMT:
+      x = GIMPLE_STMT_OPERAND (t, 0);
       if (TREE_CODE (x) == BIT_FIELD_REF
          && is_gimple_reg (TREE_OPERAND (x, 0)))
        {
@@ -3421,32 +3177,67 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case ADDR_EXPR:
-      /* ??? tree-ssa-alias.c may have overlooked dead PHI nodes, missing
-        dead PHIs that take the address of something.  But if the PHI
-        result is dead, the fact that it takes the address of anything
-        is irrelevant.  Because we can not tell from here if a PHI result
-        is dead, we just skip this check for PHIs altogether.  This means
-        we may be missing "valid" checks, but what can you do?
-        This was PR19217.  */
-      if (in_phi)
-       break;
+      {
+       bool old_invariant;
+       bool old_constant;
+       bool old_side_effects;
+       bool new_invariant;
+       bool new_constant;
+       bool new_side_effects;
+
+        /* ??? tree-ssa-alias.c may have overlooked dead PHI nodes, missing
+          dead PHIs that take the address of something.  But if the PHI
+          result is dead, the fact that it takes the address of anything
+          is irrelevant.  Because we can not tell from here if a PHI result
+          is dead, we just skip this check for PHIs altogether.  This means
+          we may be missing "valid" checks, but what can you do?
+          This was PR19217.  */
+        if (in_phi)
+         break;
 
-      /* Skip any references (they will be checked when we recurse down the
-        tree) and ensure that any variable used as a prefix is marked
-        addressable.  */
-      for (x = TREE_OPERAND (t, 0);
-          handled_component_p (x);
-          x = TREE_OPERAND (x, 0))
-       ;
-
-      if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
-       return NULL;
-      if (!TREE_ADDRESSABLE (x))
-       {
-         error ("address taken, but ADDRESSABLE bit not set");
-         return x;
-       }
-      break;
+       old_invariant = TREE_INVARIANT (t);
+       old_constant = TREE_CONSTANT (t);
+       old_side_effects = TREE_SIDE_EFFECTS (t);
+
+       recompute_tree_invariant_for_addr_expr (t);
+       new_invariant = TREE_INVARIANT (t);
+       new_side_effects = TREE_SIDE_EFFECTS (t);
+       new_constant = TREE_CONSTANT (t);
+
+       if (old_invariant != new_invariant)
+         {
+           error ("invariant not recomputed when ADDR_EXPR changed");
+           return t;
+         }
+
+        if (old_constant != new_constant)
+         {
+           error ("constant not recomputed when ADDR_EXPR changed");
+           return t;
+         }
+       if (old_side_effects != new_side_effects)
+         {
+           error ("side effects not recomputed when ADDR_EXPR changed");
+           return t;
+         }
+
+       /* Skip any references (they will be checked when we recurse down the
+          tree) and ensure that any variable used as a prefix is marked
+          addressable.  */
+       for (x = TREE_OPERAND (t, 0);
+            handled_component_p (x);
+            x = TREE_OPERAND (x, 0))
+         ;
+
+       if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
+         return NULL;
+       if (!TREE_ADDRESSABLE (x))
+         {
+           error ("address taken, but ADDRESSABLE bit not set");
+           return x;
+         }
+       break;
+      }
 
     case COND_EXPR:
       x = COND_EXPR_COND (t);
@@ -3455,21 +3246,23 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
          error ("non-boolean used in condition");
          return x;
        }
+      if (!is_gimple_condexpr (x))
+        {
+         error ("invalid conditional operand");
+         return x;
+       }
       break;
 
     case NOP_EXPR:
     case CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
-    case FIX_CEIL_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_ROUND_EXPR:
     case FLOAT_EXPR:
     case NEGATE_EXPR:
     case ABS_EXPR:
     case BIT_NOT_EXPR:
     case NON_LVALUE_EXPR:
     case TRUTH_NOT_EXPR:
-      CHECK_OP (0, "Invalid operand to unary operator");
+      CHECK_OP (0, "invalid operand to unary operator");
       break;
 
     case REALPART_EXPR:
@@ -3486,20 +3279,20 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       while (handled_component_p (t))
        {
          if (TREE_CODE (t) == COMPONENT_REF && TREE_OPERAND (t, 2))
-           CHECK_OP (2, "Invalid COMPONENT_REF offset operator");
+           CHECK_OP (2, "invalid COMPONENT_REF offset operator");
          else if (TREE_CODE (t) == ARRAY_REF
                   || TREE_CODE (t) == ARRAY_RANGE_REF)
            {
-             CHECK_OP (1, "Invalid array index.");
+             CHECK_OP (1, "invalid array index");
              if (TREE_OPERAND (t, 2))
-               CHECK_OP (2, "Invalid array lower bound.");
+               CHECK_OP (2, "invalid array lower bound");
              if (TREE_OPERAND (t, 3))
-               CHECK_OP (3, "Invalid array stride.");
+               CHECK_OP (3, "invalid array stride");
            }
          else if (TREE_CODE (t) == BIT_FIELD_REF)
            {
-             CHECK_OP (1, "Invalid operand to BIT_FIELD_REF");
-             CHECK_OP (2, "Invalid operand to BIT_FIELD_REF");
+             CHECK_OP (1, "invalid operand to BIT_FIELD_REF");
+             CHECK_OP (2, "invalid operand to BIT_FIELD_REF");
            }
 
          t = TREE_OPERAND (t, 0);
@@ -3507,7 +3300,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
       if (!CONSTANT_CLASS_P (t) && !is_gimple_lvalue (t))
        {
-         error ("Invalid reference prefix.");
+         error ("invalid reference prefix");
          return t;
        }
       *walk_subtrees = 0;
@@ -3549,8 +3342,13 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
-      CHECK_OP (0, "Invalid operand to binary operator");
-      CHECK_OP (1, "Invalid operand to binary operator");
+      CHECK_OP (0, "invalid operand to binary operator");
+      CHECK_OP (1, "invalid operand to binary operator");
+      break;
+
+    case CONSTRUCTOR:
+      if (TREE_CONSTANT (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+       *walk_subtrees = 0;
       break;
 
     default:
@@ -3570,9 +3368,20 @@ verify_stmt (tree stmt, bool last_in_block)
 {
   tree addr;
 
+  if (OMP_DIRECTIVE_P (stmt))
+    {
+      /* OpenMP directives are validated by the FE and never operated
+        on by the optimizers.  Furthermore, OMP_FOR may contain
+        non-gimple expressions when the main index variable has had
+        its address taken.  This does not affect the loop itself
+        because the header of an OMP_FOR is merely used to determine
+        how to setup the parallel iteration.  */
+      return false;
+    }
+
   if (!is_gimple_stmt (stmt))
     {
-      error ("Is not a valid GIMPLE statement.");
+      error ("is not a valid GIMPLE statement");
       goto fail;
     }
 
@@ -3592,12 +3401,12 @@ verify_stmt (tree stmt, bool last_in_block)
     {
       if (!tree_could_throw_p (stmt))
        {
-         error ("Statement marked for throw, but doesn%'t.");
+         error ("statement marked for throw, but doesn%'t");
          goto fail;
        }
       if (!last_in_block && tree_can_throw_internal (stmt))
        {
-         error ("Statement marked for throw in middle of block.");
+         error ("statement marked for throw in middle of block");
          goto fail;
        }
     }
@@ -3616,25 +3425,20 @@ static bool
 tree_node_can_be_shared (tree t)
 {
   if (IS_TYPE_OR_DECL_P (t)
-      /* We check for constants explicitly since they are not considered
-        gimple invariants if they overflowed.  */
-      || CONSTANT_CLASS_P (t)
       || is_gimple_min_invariant (t)
       || TREE_CODE (t) == SSA_NAME
-      || t == error_mark_node)
+      || t == error_mark_node
+      || TREE_CODE (t) == IDENTIFIER_NODE)
     return true;
 
   if (TREE_CODE (t) == CASE_LABEL_EXPR)
     return true;
 
   while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
-         /* We check for constants explicitly since they are not considered
-            gimple invariants if they overflowed.  */
-         && (CONSTANT_CLASS_P (TREE_OPERAND (t, 1))
-             || is_gimple_min_invariant (TREE_OPERAND (t, 1))))
-        || (TREE_CODE (t) == COMPONENT_REF
-            || TREE_CODE (t) == REALPART_EXPR
-            || TREE_CODE (t) == IMAGPART_EXPR))
+          && 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))
@@ -3649,8 +3453,7 @@ tree_node_can_be_shared (tree t)
 static tree
 verify_node_sharing (tree * tp, int *walk_subtrees, void *data)
 {
-  htab_t htab = (htab_t) data;
-  void **slot;
+  struct pointer_set_t *visited = (struct pointer_set_t *) data;
 
   if (tree_node_can_be_shared (*tp))
     {
@@ -3658,15 +3461,58 @@ verify_node_sharing (tree * tp, int *walk_subtrees, void *data)
       return NULL;
     }
 
-  slot = htab_find_slot (htab, *tp, INSERT);
-  if (*slot)
-    return *slot;
-  *slot = *tp;
+  if (pointer_set_insert (visited, *tp))
+    return *tp;
 
   return NULL;
 }
 
 
+/* Helper function for verify_gimple_tuples.  */
+
+static tree
+verify_gimple_tuples_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+                        void *data ATTRIBUTE_UNUSED)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case MODIFY_EXPR:
+      error ("unexpected non-tuple");
+      debug_tree (*tp);
+      gcc_unreachable ();
+      return NULL_TREE;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Verify that there are no trees that should have been converted to
+   gimple tuples.  Return true if T contains a node that should have
+   been converted to a gimple tuple, but hasn't.  */
+
+static bool
+verify_gimple_tuples (tree t)
+{
+  return walk_tree (&t, verify_gimple_tuples_1, NULL, NULL) != NULL;
+}
+
+static bool eh_error_found;
+static int
+verify_eh_throw_stmt_node (void **slot, void *data)
+{
+  struct throw_stmt_node *node = (struct throw_stmt_node *)*slot;
+  struct pointer_set_t *visited = (struct pointer_set_t *) data;
+
+  if (!pointer_set_contains (visited, node->stmt))
+    {
+      error ("Dead STMT in EH table");
+      debug_generic_stmt (node->stmt);
+      eh_error_found = true;
+    }
+  return 0;
+}
+
 /* Verify the GIMPLE statement chain.  */
 
 void
@@ -3675,11 +3521,12 @@ verify_stmts (void)
   basic_block bb;
   block_stmt_iterator bsi;
   bool err = false;
-  htab_t htab;
+  struct pointer_set_t *visited, *visited_stmts;
   tree addr;
 
   timevar_push (TV_TREE_STMT_VERIFY);
-  htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
+  visited = pointer_set_create ();
+  visited_stmts = pointer_set_create ();
 
   FOR_EACH_BB (bb)
     {
@@ -3690,9 +3537,10 @@ verify_stmts (void)
        {
          int phi_num_args = PHI_NUM_ARGS (phi);
 
+         pointer_set_insert (visited_stmts, phi);
          if (bb_for_stmt (phi) != bb)
            {
-             error ("bb_for_stmt (phi) is set to a wrong basic block\n");
+             error ("bb_for_stmt (phi) is set to a wrong basic block");
              err |= true;
            }
 
@@ -3720,10 +3568,10 @@ verify_stmts (void)
                  err |= true;
                }
 
-             addr = walk_tree (&t, verify_node_sharing, htab, NULL);
+             addr = walk_tree (&t, verify_node_sharing, visited, NULL);
              if (addr)
                {
-                 error ("Incorrect sharing of tree nodes");
+                 error ("incorrect sharing of tree nodes");
                  debug_generic_stmt (phi);
                  debug_generic_stmt (addr);
                  err |= true;
@@ -3735,29 +3583,39 @@ verify_stmts (void)
        {
          tree stmt = bsi_stmt (bsi);
 
+         pointer_set_insert (visited_stmts, stmt);
+         err |= verify_gimple_tuples (stmt);
+
          if (bb_for_stmt (stmt) != bb)
            {
-             error ("bb_for_stmt (stmt) is set to a wrong basic block\n");
+             error ("bb_for_stmt (stmt) is set to a wrong basic block");
              err |= true;
            }
 
          bsi_next (&bsi);
          err |= verify_stmt (stmt, bsi_end_p (bsi));
-         addr = walk_tree (&stmt, verify_node_sharing, htab, NULL);
+         addr = walk_tree (&stmt, verify_node_sharing, visited, NULL);
          if (addr)
            {
-             error ("Incorrect sharing of tree nodes");
+             error ("incorrect sharing of tree nodes");
              debug_generic_stmt (stmt);
              debug_generic_stmt (addr);
              err |= true;
            }
        }
     }
-
-  if (err)
-    internal_error ("verify_stmts failed.");
-
-  htab_delete (htab);
+  eh_error_found = false;
+  if (get_eh_throw_stmt_table (cfun))
+    htab_traverse (get_eh_throw_stmt_table (cfun),
+                  verify_eh_throw_stmt_node,
+                  visited_stmts);
+
+  if (err | eh_error_found)
+    internal_error ("verify_stmts failed");
+
+  pointer_set_destroy (visited);
+  pointer_set_destroy (visited_stmts);
+  verify_histograms ();
   timevar_pop (TV_TREE_STMT_VERIFY);
 }
 
@@ -3776,20 +3634,20 @@ tree_verify_flow_info (void)
 
   if (ENTRY_BLOCK_PTR->stmt_list)
     {
-      error ("ENTRY_BLOCK has a statement list associated with it\n");
+      error ("ENTRY_BLOCK has a statement list associated with it");
       err = 1;
     }
 
   if (EXIT_BLOCK_PTR->stmt_list)
     {
-      error ("EXIT_BLOCK has a statement list associated with it\n");
+      error ("EXIT_BLOCK has a statement list associated with it");
       err = 1;
     }
 
   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
     if (e->flags & EDGE_FALLTHRU)
       {
-       error ("Fallthru to exit from bb %d\n", e->src->index);
+       error ("fallthru to exit from bb %d", e->src->index);
        err = 1;
       }
 
@@ -3811,27 +3669,29 @@ tree_verify_flow_info (void)
 
          if (prev_stmt && DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
            {
-             error ("Nonlocal label %s is not first "
-                    "in a sequence of labels in bb %d",
-                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
-                    bb->index);
+             error ("nonlocal label ");
+             print_generic_expr (stderr, LABEL_EXPR_LABEL (stmt), 0);
+             fprintf (stderr, " is not first in a sequence of labels in bb %d",
+                      bb->index);
              err = 1;
            }
 
          if (label_to_block (LABEL_EXPR_LABEL (stmt)) != bb)
            {
-             error ("Label %s to block does not match in bb %d\n",
-                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
-                    bb->index);
+             error ("label ");
+             print_generic_expr (stderr, LABEL_EXPR_LABEL (stmt), 0);
+             fprintf (stderr, " to block does not match in bb %d",
+                      bb->index);
              err = 1;
            }
 
          if (decl_function_context (LABEL_EXPR_LABEL (stmt))
              != current_function_decl)
            {
-             error ("Label %s has incorrect context in bb %d\n",
-                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
-                    bb->index);
+             error ("label ");
+             print_generic_expr (stderr, LABEL_EXPR_LABEL (stmt), 0);
+             fprintf (stderr, " has incorrect context in bb %d",
+                      bb->index);
              err = 1;
            }
        }
@@ -3843,7 +3703,7 @@ tree_verify_flow_info (void)
 
          if (found_ctrl_stmt)
            {
-             error ("Control flow in the middle of basic block %d\n",
+             error ("control flow in the middle of basic block %d",
                     bb->index);
              err = 1;
            }
@@ -3853,12 +3713,13 @@ tree_verify_flow_info (void)
 
          if (TREE_CODE (stmt) == LABEL_EXPR)
            {
-             error ("Label %s in the middle of basic block %d\n",
-                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
-                    bb->index);
+             error ("label ");
+             print_generic_expr (stderr, LABEL_EXPR_LABEL (stmt), 0);
+             fprintf (stderr, " in the middle of basic block %d", bb->index);
              err = 1;
            }
        }
+
       bsi = bsi_last (bb);
       if (bsi_end_p (bsi))
        continue;
@@ -3872,7 +3733,20 @@ tree_verify_flow_info (void)
          FOR_EACH_EDGE (e, ei, bb->succs)
            if (e->flags & EDGE_FALLTHRU)
              {
-               error ("Fallthru edge after a control statement in bb %d \n",
+               error ("fallthru edge after a control statement in bb %d",
+                      bb->index);
+               err = 1;
+             }
+       }
+
+      if (TREE_CODE (stmt) != COND_EXPR)
+       {
+         /* Verify that there are no edges with EDGE_TRUE/FALSE_FLAG set
+            after anything else but if statement.  */
+         FOR_EACH_EDGE (e, ei, bb->succs)
+           if (e->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
+             {
+               error ("true/false edge after a non-COND_EXPR in bb %d",
                       bb->index);
                err = 1;
              }
@@ -3887,7 +3761,7 @@ tree_verify_flow_info (void)
            if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
                || TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
              {
-               error ("Structured COND_EXPR at the end of bb %d\n", bb->index);
+               error ("structured COND_EXPR at the end of bb %d", bb->index);
                err = 1;
              }
 
@@ -3900,7 +3774,7 @@ tree_verify_flow_info (void)
                || (false_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
                || EDGE_COUNT (bb->succs) >= 3)
              {
-               error ("Wrong outgoing edge flags at end of bb %d\n",
+               error ("wrong outgoing edge flags at end of bb %d",
                       bb->index);
                err = 1;
              }
@@ -3908,7 +3782,7 @@ tree_verify_flow_info (void)
            if (!has_label_p (true_edge->dest,
                              GOTO_DESTINATION (COND_EXPR_THEN (stmt))))
              {
-               error ("%<then%> label does not match edge at end of bb %d\n",
+               error ("%<then%> label does not match edge at end of bb %d",
                       bb->index);
                err = 1;
              }
@@ -3916,7 +3790,7 @@ tree_verify_flow_info (void)
            if (!has_label_p (false_edge->dest,
                              GOTO_DESTINATION (COND_EXPR_ELSE (stmt))))
              {
-               error ("%<else%> label does not match edge at end of bb %d\n",
+               error ("%<else%> label does not match edge at end of bb %d",
                       bb->index);
                err = 1;
              }
@@ -3926,19 +3800,19 @@ tree_verify_flow_info (void)
        case GOTO_EXPR:
          if (simple_goto_p (stmt))
            {
-             error ("Explicit goto at end of bb %d\n", bb->index);
-             err = 1;
+             error ("explicit goto at end of bb %d", bb->index);
+             err = 1;
            }
          else
            {
-             /* FIXME.  We should double check that the labels in the 
+             /* FIXME.  We should double check that the labels in the
                 destination blocks have their address taken.  */
              FOR_EACH_EDGE (e, ei, bb->succs)
                if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE
                                 | EDGE_FALSE_VALUE))
                    || !(e->flags & EDGE_ABNORMAL))
                  {
-                   error ("Wrong outgoing edge flags at end of bb %d\n",
+                   error ("wrong outgoing edge flags at end of bb %d",
                           bb->index);
                    err = 1;
                  }
@@ -3951,12 +3825,12 @@ tree_verify_flow_info (void)
                  & (EDGE_FALLTHRU | EDGE_ABNORMAL
                     | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
            {
-             error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
+             error ("wrong outgoing edge flags at end of bb %d", bb->index);
              err = 1;
            }
          if (single_succ (bb) != EXIT_BLOCK_PTR)
            {
-             error ("Return edge does not point to exit in bb %d\n",
+             error ("return edge does not point to exit in bb %d",
                     bb->index);
              err = 1;
            }
@@ -3989,13 +3863,13 @@ tree_verify_flow_info (void)
                tree c = TREE_VEC_ELT (vec, i);
                if (! CASE_LOW (c))
                  {
-                   error ("Found default case not at end of case vector");
+                   error ("found default case not at end of case vector");
                    err = 1;
                    continue;
                  }
                if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c)))
                  {
-                   error ("Case labels not sorted:\n ");
+                   error ("case labels not sorted: ");
                    print_generic_expr (stderr, prev, 0);
                    fprintf (stderr," is greater than ");
                    print_generic_expr (stderr, c, 0);
@@ -4006,7 +3880,7 @@ tree_verify_flow_info (void)
              }
            if (CASE_LOW (TREE_VEC_ELT (vec, n - 1)))
              {
-               error ("No default case found at end of case vector");
+               error ("no default case found at end of case vector");
                err = 1;
              }
 
@@ -4014,7 +3888,7 @@ tree_verify_flow_info (void)
              {
                if (!e->dest->aux)
                  {
-                   error ("Extra outgoing edge %d->%d\n",
+                   error ("extra outgoing edge %d->%d",
                           bb->index, e->dest->index);
                    err = 1;
                  }
@@ -4022,7 +3896,7 @@ tree_verify_flow_info (void)
                if ((e->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
                                 | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
                  {
-                   error ("Wrong outgoing edge flags at end of bb %d\n",
+                   error ("wrong outgoing edge flags at end of bb %d",
                           bb->index);
                    err = 1;
                  }
@@ -4036,7 +3910,7 @@ tree_verify_flow_info (void)
 
                if (label_bb->aux != (void *)2)
                  {
-                   error ("Missing edge %i->%i",
+                   error ("missing edge %i->%i",
                           bb->index, label_bb->index);
                    err = 1;
                  }
@@ -4068,477 +3942,36 @@ tree_make_forwarder_block (edge fallthru)
   basic_block dummy, bb;
   tree phi, new_phi, var;
 
-  dummy = fallthru->src;
-  bb = fallthru->dest;
-
-  if (single_pred_p (bb))
-    return;
-
-  /* If we redirected a branch we must create new phi nodes at the
-     start of BB.  */
-  for (phi = phi_nodes (dummy); phi; phi = PHI_CHAIN (phi))
-    {
-      var = PHI_RESULT (phi);
-      new_phi = create_phi_node (var, bb);
-      SSA_NAME_DEF_STMT (var) = new_phi;
-      SET_PHI_RESULT (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
-      add_phi_arg (new_phi, PHI_RESULT (phi), fallthru);
-    }
-
-  /* Ensure that the PHI node chain is in the same order.  */
-  set_phi_nodes (bb, phi_reverse (phi_nodes (bb)));
-
-  /* Add the arguments we have stored on edges.  */
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    {
-      if (e == fallthru)
-       continue;
-
-      flush_pending_stmts (e);
-    }
-}
-
-
-/* Return true if basic block BB does nothing except pass control
-   flow to another block and that we can safely insert a label at
-   the start of the successor block.
-
-   As a precondition, we require that BB be not equal to
-   ENTRY_BLOCK_PTR.  */
-
-static bool
-tree_forwarder_block_p (basic_block bb, bool phi_wanted)
-{
-  block_stmt_iterator bsi;
-
-  /* BB must have a single outgoing edge.  */
-  if (single_succ_p (bb) != 1
-      /* If PHI_WANTED is false, BB must not have any PHI nodes.
-        Otherwise, BB must have PHI nodes.  */
-      || (phi_nodes (bb) != NULL_TREE) != phi_wanted
-      /* BB may not be a predecessor of EXIT_BLOCK_PTR.  */
-      || single_succ (bb) == EXIT_BLOCK_PTR
-      /* Nor should this be an infinite loop.  */
-      || single_succ (bb) == bb
-      /* BB may not have an abnormal outgoing edge.  */
-      || (single_succ_edge (bb)->flags & EDGE_ABNORMAL))
-    return false; 
-
-#if ENABLE_CHECKING
-  gcc_assert (bb != ENTRY_BLOCK_PTR);
-#endif
-
-  /* Now walk through the statements backward.  We can ignore labels,
-     anything else means this is not a forwarder block.  */
-  for (bsi = bsi_last (bb); !bsi_end_p (bsi); bsi_prev (&bsi))
-    {
-      tree stmt = bsi_stmt (bsi);
-      switch (TREE_CODE (stmt))
-       {
-       case LABEL_EXPR:
-         if (DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)))
-           return false;
-         break;
-
-       default:
-         return false;
-       }
-    }
-
-  if (find_edge (ENTRY_BLOCK_PTR, bb))
-    return false;
-
-  if (current_loops)
-    { 
-      basic_block dest;
-      /* Protect loop latches, headers and preheaders.  */
-      if (bb->loop_father->header == bb)
-       return false;
-      dest = EDGE_SUCC (bb, 0)->dest;
-      if (dest->loop_father->header == dest)
-       return false;
-    }
-
-  return true;
-}
-
-/* Return true if BB has at least one abnormal incoming edge.  */
-
-static inline bool
-has_abnormal_incoming_edge_p (basic_block bb)
-{
-  edge e;
-  edge_iterator ei;
-
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    if (e->flags & EDGE_ABNORMAL)
-      return true;
-
-  return false;
-}
-
-/* Removes forwarder block BB.  Returns false if this failed.  If a new
-   forwarder block is created due to redirection of edges, it is
-   stored to worklist.  */
-
-static bool
-remove_forwarder_block (basic_block bb, basic_block **worklist)
-{
-  edge succ = single_succ_edge (bb), e, s;
-  basic_block dest = succ->dest;
-  tree label;
-  tree phi;
-  edge_iterator ei;
-  block_stmt_iterator bsi, bsi_to;
-  bool seen_abnormal_edge = false;
-
-  /* We check for infinite loops already in tree_forwarder_block_p.
-     However it may happen that the infinite loop is created
-     afterwards due to removal of forwarders.  */
-  if (dest == bb)
-    return false;
-
-  /* If the destination block consists of a nonlocal label, do not merge
-     it.  */
-  label = first_stmt (dest);
-  if (label
-      && TREE_CODE (label) == LABEL_EXPR
-      && DECL_NONLOCAL (LABEL_EXPR_LABEL (label)))
-    return false;
-
-  /* If there is an abnormal edge to basic block BB, but not into
-     dest, problems might occur during removal of the phi node at out
-     of ssa due to overlapping live ranges of registers.
-
-     If there is an abnormal edge in DEST, the problems would occur
-     anyway since cleanup_dead_labels would then merge the labels for
-     two different eh regions, and rest of exception handling code
-     does not like it.
-     
-     So if there is an abnormal edge to BB, proceed only if there is
-     no abnormal edge to DEST and there are no phi nodes in DEST.  */
-  if (has_abnormal_incoming_edge_p (bb))
-    {
-      seen_abnormal_edge = true;
-
-      if (has_abnormal_incoming_edge_p (dest)
-         || phi_nodes (dest) != NULL_TREE)
-       return false;
-    }
-
-  /* If there are phi nodes in DEST, and some of the blocks that are
-     predecessors of BB are also predecessors of DEST, check that the
-     phi node arguments match.  */
-  if (phi_nodes (dest))
-    {
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       {
-         s = find_edge (e->src, dest);
-         if (!s)
-           continue;
-
-         if (!phi_alternatives_equal (dest, succ, s))
-           return false;
-       }
-    }
-
-  /* Redirect the edges.  */
-  for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
-    {
-      if (e->flags & EDGE_ABNORMAL)
-       {
-         /* If there is an abnormal edge, redirect it anyway, and
-            move the labels to the new block to make it legal.  */
-         s = redirect_edge_succ_nodup (e, dest);
-       }
-      else
-       s = redirect_edge_and_branch (e, dest);
-
-      if (s == e)
-       {
-         /* Create arguments for the phi nodes, since the edge was not
-            here before.  */
-         for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
-           add_phi_arg (phi, PHI_ARG_DEF (phi, succ->dest_idx), s);
-       }
-      else
-       {
-         /* The source basic block might become a forwarder.  We know
-            that it was not a forwarder before, since it used to have
-            at least two outgoing edges, so we may just add it to
-            worklist.  */
-         if (tree_forwarder_block_p (s->src, false))
-           *(*worklist)++ = s->src;
-       }
-    }
-
-  if (seen_abnormal_edge)
-    {
-      /* Move the labels to the new block, so that the redirection of
-        the abnormal edges works.  */
-
-      bsi_to = bsi_start (dest);
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
-       {
-         label = bsi_stmt (bsi);
-         gcc_assert (TREE_CODE (label) == LABEL_EXPR);
-         bsi_remove (&bsi);
-         bsi_insert_before (&bsi_to, label, BSI_CONTINUE_LINKING);
-       }
-    }
-
-  /* Update the dominators.  */
-  if (dom_info_available_p (CDI_DOMINATORS))
-    {
-      basic_block dom, dombb, domdest;
-
-      dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
-      domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
-      if (domdest == bb)
-       {
-         /* Shortcut to avoid calling (relatively expensive)
-            nearest_common_dominator unless necessary.  */
-         dom = dombb;
-       }
-      else
-       dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
-
-      set_immediate_dominator (CDI_DOMINATORS, dest, dom);
-    }
-
-  /* And kill the forwarder block.  */
-  delete_basic_block (bb);
-
-  return true;
-}
-
-/* Removes forwarder blocks.  */
-
-static bool
-cleanup_forwarder_blocks (void)
-{
-  basic_block bb;
-  bool changed = false;
-  basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks);
-  basic_block *current = worklist;
-
-  FOR_EACH_BB (bb)
-    {
-      if (tree_forwarder_block_p (bb, false))
-       *current++ = bb;
-    }
-
-  while (current != worklist)
-    {
-      bb = *--current;
-      changed |= remove_forwarder_block (bb, &current);
-    }
-
-  free (worklist);
-  return changed;
-}
-
-/* Merge the PHI nodes at BB into those at BB's sole successor.  */
-
-static void
-remove_forwarder_block_with_phi (basic_block bb)
-{
-  edge succ = single_succ_edge (bb);
-  basic_block dest = succ->dest;
-  tree label;
-  basic_block dombb, domdest, dom;
-
-  /* We check for infinite loops already in tree_forwarder_block_p.
-     However it may happen that the infinite loop is created
-     afterwards due to removal of forwarders.  */
-  if (dest == bb)
-    return;
-
-  /* If the destination block consists of a nonlocal label, do not
-     merge it.  */
-  label = first_stmt (dest);
-  if (label
-      && TREE_CODE (label) == LABEL_EXPR
-      && DECL_NONLOCAL (LABEL_EXPR_LABEL (label)))
-    return;
-
-  /* Redirect each incoming edge to BB to DEST.  */
-  while (EDGE_COUNT (bb->preds) > 0)
-    {
-      edge e = EDGE_PRED (bb, 0), s;
-      tree phi;
-
-      s = find_edge (e->src, dest);
-      if (s)
-       {
-         /* We already have an edge S from E->src to DEST.  If S and
-            E->dest's sole successor edge have the same PHI arguments
-            at DEST, redirect S to DEST.  */
-         if (phi_alternatives_equal (dest, s, succ))
-           {
-             e = redirect_edge_and_branch (e, dest);
-             PENDING_STMT (e) = NULL_TREE;
-             continue;
-           }
-
-         /* PHI arguments are different.  Create a forwarder block by
-            splitting E so that we can merge PHI arguments on E to
-            DEST.  */
-         e = single_succ_edge (split_edge (e));
-       }
-
-      s = redirect_edge_and_branch (e, dest);
-
-      /* redirect_edge_and_branch must not create a new edge.  */
-      gcc_assert (s == e);
-
-      /* Add to the PHI nodes at DEST each PHI argument removed at the
-        destination of E.  */
-      for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
-       {
-         tree def = PHI_ARG_DEF (phi, succ->dest_idx);
-
-         if (TREE_CODE (def) == SSA_NAME)
-           {
-             tree var;
-
-             /* If DEF is one of the results of PHI nodes removed during
-                redirection, replace it with the PHI argument that used
-                to be on E.  */
-             for (var = PENDING_STMT (e); var; var = TREE_CHAIN (var))
-               {
-                 tree old_arg = TREE_PURPOSE (var);
-                 tree new_arg = TREE_VALUE (var);
-
-                 if (def == old_arg)
-                   {
-                     def = new_arg;
-                     break;
-                   }
-               }
-           }
-
-         add_phi_arg (phi, def, s);
-       }
-
-      PENDING_STMT (e) = NULL;
-    }
-
-  /* Update the dominators.  */
-  dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
-  domdest = get_immediate_dominator (CDI_DOMINATORS, dest);
-  if (domdest == bb)
-    {
-      /* Shortcut to avoid calling (relatively expensive)
-        nearest_common_dominator unless necessary.  */
-      dom = dombb;
-    }
-  else
-    dom = nearest_common_dominator (CDI_DOMINATORS, domdest, dombb);
-
-  set_immediate_dominator (CDI_DOMINATORS, dest, dom);
-  
-  /* Remove BB since all of BB's incoming edges have been redirected
-     to DEST.  */
-  delete_basic_block (bb);
-}
-
-/* This pass merges PHI nodes if one feeds into another.  For example,
-   suppose we have the following:
-
-  goto <bb 9> (<L9>);
-
-<L8>:;
-  tem_17 = foo ();
-
-  # tem_6 = PHI <tem_17(8), tem_23(7)>;
-<L9>:;
-
-  # tem_3 = PHI <tem_6(9), tem_2(5)>;
-<L10>:;
-
-  Then we merge the first PHI node into the second one like so:
-
-  goto <bb 9> (<L10>);
-
-<L8>:;
-  tem_17 = foo ();
-
-  # tem_3 = PHI <tem_23(7), tem_2(5), tem_17(8)>;
-<L10>:;
-*/
-
-static void
-merge_phi_nodes (void)
-{
-  basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks);
-  basic_block *current = worklist;
-  basic_block bb;
-
-  calculate_dominance_info (CDI_DOMINATORS);
-
-  /* Find all PHI nodes that we may be able to merge.  */
-  FOR_EACH_BB (bb)
-    {
-      basic_block dest;
-
-      /* Look for a forwarder block with PHI nodes.  */
-      if (!tree_forwarder_block_p (bb, true))
-       continue;
-
-      dest = single_succ (bb);
+  dummy = fallthru->src;
+  bb = fallthru->dest;
 
-      /* We have to feed into another basic block with PHI
-        nodes.  */
-      if (!phi_nodes (dest)
-         /* We don't want to deal with a basic block with
-            abnormal edges.  */
-         || has_abnormal_incoming_edge_p (bb))
-       continue;
+  if (single_pred_p (bb))
+    return;
 
-      if (!dominated_by_p (CDI_DOMINATORS, dest, bb))
-       {
-         /* If BB does not dominate DEST, then the PHI nodes at
-            DEST must be the only users of the results of the PHI
-            nodes at BB.  */
-         *current++ = bb;
-       }
+  /* If we redirected a branch we must create new PHI nodes at the
+     start of BB.  */
+  for (phi = phi_nodes (dummy); phi; phi = PHI_CHAIN (phi))
+    {
+      var = PHI_RESULT (phi);
+      new_phi = create_phi_node (var, bb);
+      SSA_NAME_DEF_STMT (var) = new_phi;
+      SET_PHI_RESULT (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
+      add_phi_arg (new_phi, PHI_RESULT (phi), fallthru);
     }
 
-  /* Now let's drain WORKLIST.  */
-  while (current != worklist)
+  /* Ensure that the PHI node chain is in the same order.  */
+  set_phi_nodes (bb, phi_reverse (phi_nodes (bb)));
+
+  /* Add the arguments we have stored on edges.  */
+  FOR_EACH_EDGE (e, ei, bb->preds)
     {
-      bb = *--current;
-      remove_forwarder_block_with_phi (bb);
-    }
+      if (e == fallthru)
+       continue;
 
-  free (worklist);
+      flush_pending_stmts (e);
+    }
 }
 
-static bool
-gate_merge_phi (void)
-{
-  return 1;
-}
-
-struct tree_opt_pass pass_merge_phi = {
-  "mergephi",                  /* name */
-  gate_merge_phi,              /* gate */
-  merge_phi_nodes,             /* execute */
-  NULL,                                /* sub */
-  NULL,                                /* next */
-  0,                           /* static_pass_number */
-  TV_TREE_MERGE_PHI,           /* tv_id */
-  PROP_cfg | PROP_ssa,         /* properties_required */
-  0,                           /* properties_provided */
-  0,                           /* properties_destroyed */
-  0,                           /* todo_flags_start */
-  TODO_dump_func | TODO_ggc_collect    /* todo_flags_finish */
-  | TODO_verify_ssa,
-  0                            /* letter */
-};
 
 /* Return a non-special label in the head of basic block BLOCK.
    Create one if it doesn't exist.  */
@@ -4600,7 +4033,7 @@ tree_try_redirect_by_replacing_jump (edge e, basic_block target)
   if (TREE_CODE (stmt) == COND_EXPR
       || TREE_CODE (stmt) == SWITCH_EXPR)
     {
-      bsi_remove (&b);
+      bsi_remove (&b, true);
       e = ssa_redirect_edge (e, target);
       e->flags = EDGE_FALLTHRU;
       return e;
@@ -4621,10 +4054,10 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
   edge ret;
   tree label, stmt;
 
-  if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
+  if (e->flags & EDGE_ABNORMAL)
     return NULL;
 
-  if (e->src != ENTRY_BLOCK_PTR 
+  if (e->src != ENTRY_BLOCK_PTR
       && (ret = tree_try_redirect_by_replacing_jump (e, dest)))
     return ret;
 
@@ -4697,7 +4130,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
       }
 
     case RETURN_EXPR:
-      bsi_remove (&bsi);
+      bsi_remove (&bsi, true);
       e->flags |= EDGE_FALLTHRU;
       break;
 
@@ -4716,6 +4149,17 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
   return e;
 }
 
+/* Returns true if it is possible to remove edge E by redirecting
+   it to the destination of the other edge from E->src.  */
+
+static bool
+tree_can_remove_branch_p (edge e)
+{
+  if (e->flags & EDGE_ABNORMAL)
+    return false;
+
+  return true;
+}
 
 /* Simple wrapper, as we can always redirect fallthru edges.  */
 
@@ -4735,7 +4179,8 @@ tree_redirect_edge_and_branch_force (edge e, basic_block dest)
 static basic_block
 tree_split_block (basic_block bb, void *stmt)
 {
-  block_stmt_iterator bsi, bsi_tgt;
+  block_stmt_iterator bsi;
+  tree_stmt_iterator tsi_tgt;
   tree act;
   basic_block new_bb;
   edge e;
@@ -4769,13 +4214,17 @@ tree_split_block (basic_block bb, void *stmt)
        }
     }
 
-  bsi_tgt = bsi_start (new_bb);
-  while (!bsi_end_p (bsi))
-    {
-      act = bsi_stmt (bsi);
-      bsi_remove (&bsi);
-      bsi_insert_after (&bsi_tgt, act, BSI_NEW_STMT);
-    }
+  if (bsi_end_p (bsi))
+    return new_bb;
+
+  /* Split the statement list - avoid re-creating new containers as this
+     brings ugly quadratic memory consumption in the inliner.  
+     (We are still quadratic since we need to update stmt BB pointers,
+     sadly.)  */
+  new_bb->stmt_list = tsi_split_statement_list_before (&bsi.tsi);
+  for (tsi_tgt = tsi_start (new_bb->stmt_list);
+       !tsi_end_p (tsi_tgt); tsi_next (&tsi_tgt))
+    change_bb_for_stmt (tsi_stmt (tsi_tgt), new_bb);
 
   return new_bb;
 }
@@ -4849,6 +4298,7 @@ tree_duplicate_bb (basic_block bb)
       region = lookup_stmt_eh_region (stmt);
       if (region >= 0)
        add_stmt_to_eh_region (copy, region);
+      gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
 
       /* Create new names for all the definitions created by COPY and
         add replacement mappings for each new name.  */
@@ -4862,7 +4312,7 @@ tree_duplicate_bb (basic_block bb)
 
 /* Basic block BB_COPY was created by code duplication.  Add phi node
    arguments for edges going out of BB_COPY.  The blocks that were
-   duplicated have rbi->duplicated set to one.  */
+   duplicated have BB_DUPLICATED set.  */
 
 void
 add_phi_args_after_copy_bb (basic_block bb_copy)
@@ -4871,16 +4321,16 @@ add_phi_args_after_copy_bb (basic_block bb_copy)
   edge e, e_copy;
   edge_iterator ei;
   tree phi, phi_copy, phi_next, def;
-      
-  bb = bb_copy->rbi->original;
+
+  bb = get_bb_original (bb_copy);
 
   FOR_EACH_EDGE (e_copy, ei, bb_copy->succs)
     {
       if (!phi_nodes (e_copy->dest))
        continue;
 
-      if (e_copy->dest->rbi->duplicated)
-       dest = e_copy->dest->rbi->original;
+      if (e_copy->dest->flags & BB_DUPLICATED)
+       dest = get_bb_original (e_copy->dest);
       else
        dest = e_copy->dest;
 
@@ -4891,8 +4341,8 @@ add_phi_args_after_copy_bb (basic_block bb_copy)
             In this case we are not looking for edge to dest, but to
             duplicated block whose original was dest.  */
          FOR_EACH_EDGE (e, ei, bb->succs)
-           if (e->dest->rbi->duplicated
-               && e->dest->rbi->original == dest)
+           if ((e->dest->flags & BB_DUPLICATED)
+               && get_bb_original (e->dest) == dest)
              break;
 
          gcc_assert (e != NULL);
@@ -4919,13 +4369,13 @@ add_phi_args_after_copy (basic_block *region_copy, unsigned n_region)
   unsigned i;
 
   for (i = 0; i < n_region; i++)
-    region_copy[i]->rbi->duplicated = 1;
+    region_copy[i]->flags |= BB_DUPLICATED;
 
   for (i = 0; i < n_region; i++)
     add_phi_args_after_copy_bb (region_copy[i]);
 
   for (i = 0; i < n_region; i++)
-    region_copy[i]->rbi->duplicated = 0;
+    region_copy[i]->flags &= ~BB_DUPLICATED;
 }
 
 /* Duplicates a REGION (set of N_REGION basic blocks) with just a single
@@ -4949,7 +4399,8 @@ tree_duplicate_sese_region (edge entry, edge exit,
   edge exit_copy;
   basic_block *doms;
   edge redirected;
-  int total_freq, entry_freq;
+  int total_freq = 0, entry_freq = 0;
+  gcov_type total_count = 0, entry_count = 0;
 
   if (!can_copy_bbs_p (region, n_region))
     return false;
@@ -4990,7 +4441,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
 
   if (!region_copy)
     {
-      region_copy = xmalloc (sizeof (basic_block) * n_region);
+      region_copy = XNEWVEC (basic_block, n_region);
       free_region_copy = true;
     }
 
@@ -4998,22 +4449,48 @@ tree_duplicate_sese_region (edge entry, edge exit,
 
   /* Record blocks outside the region that are dominated by something
      inside.  */
-  doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  doms = XNEWVEC (basic_block, n_basic_blocks);
+  initialize_original_copy_tables ();
+
   n_doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region, doms);
 
-  total_freq = entry->dest->frequency;
-  entry_freq = EDGE_FREQUENCY (entry);
-  /* Fix up corner cases, to avoid division by zero or creation of negative
-     frequencies.  */
-  if (total_freq == 0)
-    total_freq = 1;
-  else if (entry_freq > total_freq)
-    entry_freq = total_freq;
+  if (entry->dest->count)
+    {
+      total_count = entry->dest->count;
+      entry_count = entry->count;
+      /* Fix up corner cases, to avoid division by zero or creation of negative
+        frequencies.  */
+      if (entry_count > total_count)
+       entry_count = total_count;
+    }
+  else
+    {
+      total_freq = entry->dest->frequency;
+      entry_freq = EDGE_FREQUENCY (entry);
+      /* Fix up corner cases, to avoid division by zero or creation of negative
+        frequencies.  */
+      if (total_freq == 0)
+       total_freq = 1;
+      else if (entry_freq > total_freq)
+       entry_freq = total_freq;
+    }
 
-  copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop);
-  scale_bbs_frequencies_int (region, n_region, total_freq - entry_freq,
-                            total_freq);
-  scale_bbs_frequencies_int (region_copy, n_region, entry_freq, total_freq);
+  copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop,
+           split_edge_bb_loc (entry));
+  if (total_count)
+    {
+      scale_bbs_frequencies_gcov_type (region, n_region,
+                                      total_count - entry_count,
+                                      total_count);
+      scale_bbs_frequencies_gcov_type (region_copy, n_region, entry_count,
+                                      total_count);
+    }
+  else
+    {
+      scale_bbs_frequencies_int (region, n_region, total_freq - entry_freq,
+                                total_freq);
+      scale_bbs_frequencies_int (region_copy, n_region, entry_freq, total_freq);
+    }
 
   if (copying_header)
     {
@@ -5022,7 +4499,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
     }
 
   /* Redirect the entry and add the phi node arguments.  */
-  redirected = redirect_edge_and_branch (entry, entry->dest->rbi->copy);
+  redirected = redirect_edge_and_branch (entry, get_bb_copy (entry->dest));
   gcc_assert (redirected != NULL);
   flush_pending_stmts (entry);
 
@@ -5031,7 +4508,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
      region, but was dominated by something inside needs recounting as
      well.  */
   set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
-  doms[n_doms++] = entry->dest->rbi->original;
+  doms[n_doms++] = get_bb_original (entry->dest);
   iterate_fix_dominators (CDI_DOMINATORS, doms, n_doms);
   free (doms);
 
@@ -5044,9 +4521,468 @@ tree_duplicate_sese_region (edge entry, edge exit,
   if (free_region_copy)
     free (region_copy);
 
+  free_original_copy_tables ();
   return true;
 }
 
+/*
+DEF_VEC_P(basic_block);
+DEF_VEC_ALLOC_P(basic_block,heap);
+*/
+
+/* Add all the blocks dominated by ENTRY to the array BBS_P.  Stop
+   adding blocks when the dominator traversal reaches EXIT.  This
+   function silently assumes that ENTRY strictly dominates EXIT.  */
+
+static void
+gather_blocks_in_sese_region (basic_block entry, basic_block exit,
+                             VEC(basic_block,heap) **bbs_p)
+{
+  basic_block son;
+
+  for (son = first_dom_son (CDI_DOMINATORS, entry);
+       son;
+       son = next_dom_son (CDI_DOMINATORS, son))
+    {
+      VEC_safe_push (basic_block, heap, *bbs_p, son);
+      if (son != exit)
+       gather_blocks_in_sese_region (son, exit, bbs_p);
+    }
+}
+
+
+struct move_stmt_d
+{
+  tree block;
+  tree from_context;
+  tree to_context;
+  bitmap vars_to_remove;
+  htab_t new_label_map;
+  bool remap_decls_p;
+};
+
+/* Helper for move_block_to_fn.  Set TREE_BLOCK in every expression
+   contained in *TP and change the DECL_CONTEXT of every local
+   variable referenced in *TP.  */
+
+static tree
+move_stmt_r (tree *tp, int *walk_subtrees, void *data)
+{
+  struct move_stmt_d *p = (struct move_stmt_d *) data;
+  tree t = *tp;
+
+  if (p->block
+      && (EXPR_P (t) || GIMPLE_STMT_P (t)))
+    TREE_BLOCK (t) = p->block;
+
+  if (OMP_DIRECTIVE_P (t)
+      && TREE_CODE (t) != OMP_RETURN
+      && TREE_CODE (t) != OMP_CONTINUE)
+    {
+      /* Do not remap variables inside OMP directives.  Variables
+        referenced in clauses and directive header belong to the
+        parent function and should not be moved into the child
+        function.  */
+      bool save_remap_decls_p = p->remap_decls_p;
+      p->remap_decls_p = false;
+      *walk_subtrees = 0;
+
+      walk_tree (&OMP_BODY (t), move_stmt_r, p, NULL);
+
+      p->remap_decls_p = save_remap_decls_p;
+    }
+  else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context)
+    {
+      if (TREE_CODE (t) == LABEL_DECL)
+       {
+         if (p->new_label_map)
+           {
+             struct tree_map in, *out;
+             in.from = t;
+             out = htab_find_with_hash (p->new_label_map, &in, DECL_UID (t));
+             if (out)
+               *tp = t = out->to;
+           }
+
+         DECL_CONTEXT (t) = p->to_context;
+       }
+      else if (p->remap_decls_p)
+       {
+         DECL_CONTEXT (t) = p->to_context;
+
+         if (TREE_CODE (t) == VAR_DECL)
+           {
+             struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
+             f->unexpanded_var_list
+               = tree_cons (0, t, f->unexpanded_var_list);
+
+             /* Mark T to be removed from the original function,
+                otherwise it will be given a DECL_RTL when the
+                original function is expanded.  */
+             bitmap_set_bit (p->vars_to_remove, DECL_UID (t));
+           }
+       }
+    }
+  else if (TYPE_P (t))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
+}
+
+
+/* Move basic block BB from function CFUN to function DEST_FN.  The
+   block is moved out of the original linked list and placed after
+   block AFTER in the new list.  Also, the block is removed from the
+   original array of blocks and placed in DEST_FN's array of blocks.
+   If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
+   updated to reflect the moved edges.
+
+   On exit, local variables that need to be removed from
+   CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE.  */
+
+static void
+move_block_to_fn (struct function *dest_cfun, basic_block bb,
+                 basic_block after, bool update_edge_count_p,
+                 bitmap vars_to_remove, htab_t new_label_map, int eh_offset)
+{
+  struct control_flow_graph *cfg;
+  edge_iterator ei;
+  edge e;
+  block_stmt_iterator si;
+  struct move_stmt_d d;
+  unsigned old_len, new_len;
+
+  /* Link BB to the new linked list.  */
+  move_block_after (bb, after);
+
+  /* Update the edge count in the corresponding flowgraphs.  */
+  if (update_edge_count_p)
+    FOR_EACH_EDGE (e, ei, bb->succs)
+      {
+       cfun->cfg->x_n_edges--;
+       dest_cfun->cfg->x_n_edges++;
+      }
+
+  /* Remove BB from the original basic block array.  */
+  VEC_replace (basic_block, cfun->cfg->x_basic_block_info, bb->index, NULL);
+  cfun->cfg->x_n_basic_blocks--;
+
+  /* Grow DEST_CFUN's basic block array if needed.  */
+  cfg = dest_cfun->cfg;
+  cfg->x_n_basic_blocks++;
+  if (bb->index > cfg->x_last_basic_block)
+    cfg->x_last_basic_block = bb->index;
+
+  old_len = VEC_length (basic_block, 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_replace (basic_block, cfg->x_basic_block_info,
+               cfg->x_last_basic_block, bb);
+
+  /* The statements in BB need to be associated with a new TREE_BLOCK.
+     Labels need to be associated with a new label-to-block map.  */
+  memset (&d, 0, sizeof (d));
+  d.vars_to_remove = vars_to_remove;
+
+  for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+    {
+      tree stmt = bsi_stmt (si);
+      int region;
+
+      d.from_context = cfun->decl;
+      d.to_context = dest_cfun->decl;
+      d.remap_decls_p = true;
+      d.new_label_map = new_label_map;
+      if (TREE_BLOCK (stmt))
+       d.block = DECL_INITIAL (dest_cfun->decl);
+
+      walk_tree (&stmt, move_stmt_r, &d, NULL);
+
+      if (TREE_CODE (stmt) == LABEL_EXPR)
+       {
+         tree label = LABEL_EXPR_LABEL (stmt);
+         int uid = LABEL_DECL_UID (label);
+
+         gcc_assert (uid > -1);
+
+         old_len = VEC_length (basic_block, cfg->x_label_to_block_map);
+         if (old_len <= (unsigned) uid)
+           {
+             new_len = 3 * uid / 2;
+             VEC_safe_grow_cleared (basic_block, gc,
+                                    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);
+
+         gcc_assert (DECL_CONTEXT (label) == dest_cfun->decl);
+
+         if (uid >= dest_cfun->last_label_uid)
+           dest_cfun->last_label_uid = uid + 1;
+       }
+      else if (TREE_CODE (stmt) == RESX_EXPR && eh_offset != 0)
+       TREE_OPERAND (stmt, 0) =
+         build_int_cst (NULL_TREE,
+                        TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0))
+                        + eh_offset);
+
+      region = lookup_stmt_eh_region (stmt);
+      if (region >= 0)
+       {
+         add_stmt_to_eh_region_fn (dest_cfun, stmt, region + eh_offset);
+         remove_stmt_from_eh_region (stmt);
+         gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt);
+          gimple_remove_stmt_histograms (cfun, stmt);
+       }
+    }
+}
+
+/* Examine the statements in BB (which is in SRC_CFUN); find and return
+   the outermost EH region.  Use REGION as the incoming base EH region.  */
+
+static int
+find_outermost_region_in_block (struct function *src_cfun,
+                               basic_block bb, int region)
+{
+  block_stmt_iterator si;
+
+  for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+    {
+      tree stmt = bsi_stmt (si);
+      int stmt_region;
+
+      if (TREE_CODE (stmt) == RESX_EXPR)
+       stmt_region = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
+      else
+       stmt_region = lookup_stmt_eh_region_fn (src_cfun, stmt);
+      if (stmt_region > 0)
+       {
+         if (region < 0)
+           region = stmt_region;
+         else if (stmt_region != region)
+           {
+             region = eh_region_outermost (src_cfun, stmt_region, region);
+             gcc_assert (region != -1);
+           }
+       }
+    }
+
+  return region;
+}
+
+static tree
+new_label_mapper (tree decl, void *data)
+{
+  htab_t hash = (htab_t) data;
+  struct tree_map *m;
+  void **slot;
+
+  gcc_assert (TREE_CODE (decl) == LABEL_DECL);
+
+  m = xmalloc (sizeof (struct tree_map));
+  m->hash = DECL_UID (decl);
+  m->from = decl;
+  m->to = create_artificial_label ();
+  LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
+
+  slot = htab_find_slot_with_hash (hash, m, m->hash, INSERT);
+  gcc_assert (*slot == NULL);
+
+  *slot = m;
+
+  return m->to;
+}
+
+/* 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
+   returned.  DEST_CFUN must not have a CFG yet.
+
+   Note that the region need not be a pure SESE region.  Blocks inside
+   the region may contain calls to abort/exit.  The only restriction
+   is that ENTRY_BB should be the only entry point and it must
+   dominate EXIT_BB.
+
+   All local variables referenced in the region are assumed to be in
+   the corresponding BLOCK_VARS and unexpanded variable lists
+   associated with DEST_CFUN.  */
+
+basic_block
+move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
+                       basic_block exit_bb)
+{
+  VEC(basic_block,heap) *bbs;
+  basic_block after, bb, *entry_pred, *exit_succ;
+  struct function *saved_cfun;
+  int *entry_flag, *exit_flag, eh_offset;
+  unsigned i, num_entry_edges, num_exit_edges;
+  edge e;
+  edge_iterator ei;
+  bitmap vars_to_remove;
+  htab_t new_label_map;
+
+  saved_cfun = cfun;
+
+  /* Collect all the blocks in the region.  Manually add ENTRY_BB
+     because it won't be added by dfs_enumerate_from.  */
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
+     region.  */
+  gcc_assert (entry_bb != exit_bb
+              && (!exit_bb
+                 || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)));
+
+  bbs = NULL;
+  VEC_safe_push (basic_block, heap, bbs, entry_bb);
+  gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs);
+
+  /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
+     the predecessor edges to ENTRY_BB and the successor edges to
+     EXIT_BB so that we can re-attach them to the new basic block that
+     will replace the region.  */
+  num_entry_edges = EDGE_COUNT (entry_bb->preds);
+  entry_pred = (basic_block *) xcalloc (num_entry_edges, sizeof (basic_block));
+  entry_flag = (int *) xcalloc (num_entry_edges, sizeof (int));
+  i = 0;
+  for (ei = ei_start (entry_bb->preds); (e = ei_safe_edge (ei)) != NULL;)
+    {
+      entry_flag[i] = e->flags;
+      entry_pred[i++] = e->src;
+      remove_edge (e);
+    }
+
+  if (exit_bb)
+    {
+      num_exit_edges = EDGE_COUNT (exit_bb->succs);
+      exit_succ = (basic_block *) xcalloc (num_exit_edges,
+                                          sizeof (basic_block));
+      exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
+      i = 0;
+      for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
+       {
+         exit_flag[i] = e->flags;
+         exit_succ[i++] = e->dest;
+         remove_edge (e);
+       }
+    }
+  else
+    {
+      num_exit_edges = 0;
+      exit_succ = NULL;
+      exit_flag = NULL;
+    }
+
+  /* Switch context to the child function to initialize DEST_FN's CFG.  */
+  gcc_assert (dest_cfun->cfg == NULL);
+  cfun = dest_cfun;
+
+  init_empty_tree_cfg ();
+
+  /* Initialize EH information for the new function.  */
+  eh_offset = 0;
+  new_label_map = NULL;
+  if (saved_cfun->eh)
+    {
+      int region = -1;
+
+      for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+       region = find_outermost_region_in_block (saved_cfun, bb, region);
+
+      init_eh_for_function ();
+      if (region != -1)
+       {
+         new_label_map = htab_create (17, tree_map_hash, tree_map_eq, free);
+         eh_offset = duplicate_eh_regions (saved_cfun, new_label_mapper,
+                                           new_label_map, region, 0);
+       }
+    }
+
+  cfun = saved_cfun;
+
+  /* Move blocks from BBS into DEST_CFUN.  */
+  gcc_assert (VEC_length (basic_block, bbs) >= 2);
+  after = dest_cfun->cfg->x_entry_block_ptr;
+  vars_to_remove = BITMAP_ALLOC (NULL);
+  for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+    {
+      /* No need to update edge counts on the last block.  It has
+        already been updated earlier when we detached the region from
+        the original CFG.  */
+      move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove,
+                       new_label_map, eh_offset);
+      after = bb;
+    }
+
+  if (new_label_map)
+    htab_delete (new_label_map);
+
+  /* Remove the variables marked in VARS_TO_REMOVE from
+     CFUN->UNEXPANDED_VAR_LIST.  Otherwise, they will be given a
+     DECL_RTL in the context of CFUN.  */
+  if (!bitmap_empty_p (vars_to_remove))
+    {
+      tree *p;
+
+      for (p = &cfun->unexpanded_var_list; *p; )
+       {
+         tree var = TREE_VALUE (*p);
+         if (bitmap_bit_p (vars_to_remove, DECL_UID (var)))
+           {
+             *p = TREE_CHAIN (*p);
+             continue;
+           }
+
+         p = &TREE_CHAIN (*p);
+       }
+    }
+
+  BITMAP_FREE (vars_to_remove);
+
+  /* Rewire the entry and exit blocks.  The successor to the entry
+     block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in
+     the child function.  Similarly, the predecessor of DEST_FN's
+     EXIT_BLOCK_PTR turns into the predecessor of EXIT_BLOCK_PTR.  We
+     need to switch CFUN between DEST_CFUN and SAVED_CFUN so that the
+     various CFG manipulation function get to the right CFG.
+
+     FIXME, this is silly.  The CFG ought to become a parameter to
+     these helpers.  */
+  cfun = dest_cfun;
+  make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
+  if (exit_bb)
+    make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
+  cfun = saved_cfun;
+
+  /* Back in the original function, the SESE region has disappeared,
+     create a new basic block in its place.  */
+  bb = create_empty_bb (entry_pred[0]);
+  for (i = 0; i < num_entry_edges; i++)
+    make_edge (entry_pred[i], bb, entry_flag[i]);
+
+  for (i = 0; i < num_exit_edges; i++)
+    make_edge (bb, exit_succ[i], exit_flag[i]);
+
+  if (exit_bb)
+    {
+      free (exit_flag);
+      free (exit_succ);
+    }
+  free (entry_flag);
+  free (entry_pred);
+  free_dominance_info (CDI_DOMINATORS);
+  free_dominance_info (CDI_POST_DOMINATORS);
+  VEC_free (basic_block, heap, bbs);
+
+  return bb;
+}
+
 
 /* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h)  */
 
@@ -5057,6 +4993,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
   tree chain;
+  struct function *saved_cfun;
 
   fprintf (file, "%s (", lang_hooks.decl_printable_name (fn, 2));
 
@@ -5078,6 +5015,10 @@ dump_function_to_file (tree fn, FILE *file, int flags)
       return;
     }
 
+  /* Switch CFUN to point to FN.  */
+  saved_cfun = cfun;
+  cfun = DECL_STRUCT_FUNCTION (fn);
+
   /* When GIMPLE is lowered, the variables are no longer available in
      BIND_EXPRs, so display them separately.  */
   if (cfun && cfun->decl == fn && cfun->unexpanded_var_list)
@@ -5108,7 +5049,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
 
       FOR_EACH_BB (bb)
        dump_generic_bb (file, bb, 2, flags);
-       
+
       fprintf (file, "}\n");
       check_bb_profile (EXIT_BLOCK_PTR, file);
     }
@@ -5119,7 +5060,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
       /* Make a tree based dump.  */
       chain = DECL_SAVED_TREE (fn);
 
-      if (TREE_CODE (chain) == BIND_EXPR)
+      if (chain && TREE_CODE (chain) == BIND_EXPR)
        {
          if (ignore_topmost_bind)
            {
@@ -5145,6 +5086,18 @@ dump_function_to_file (tree fn, FILE *file, int flags)
     }
 
   fprintf (file, "\n\n");
+
+  /* Restore CFUN.  */
+  cfun = saved_cfun;
+}
+
+
+/* Dump FUNCTION_DECL FN to stderr using FLAGS (see TDF_* in tree.h)  */
+
+void
+debug_function (tree fn, int flags)
+{
+  dump_function_to_file (fn, stderr, flags);
 }
 
 
@@ -5154,7 +5107,7 @@ static void print_pred_bbs (FILE *, basic_block bb);
 static void print_succ_bbs (FILE *, basic_block bb);
 
 
-/* Print the predecessors indexes of edge E on FILE.  */
+/* Print on FILE the indexes for the predecessors of basic_block BB.  */
 
 static void
 print_pred_bbs (FILE *file, basic_block bb)
@@ -5163,11 +5116,11 @@ print_pred_bbs (FILE *file, basic_block bb)
   edge_iterator ei;
 
   FOR_EACH_EDGE (e, ei, bb->preds)
-    fprintf (file, "bb_%d", e->src->index);
+    fprintf (file, "bb_%d ", e->src->index);
 }
 
 
-/* Print the successors indexes of edge E on FILE.  */
+/* Print on FILE the indexes for the successors of basic_block BB.  */
 
 static void
 print_succ_bbs (FILE *file, basic_block bb)
@@ -5176,7 +5129,7 @@ print_succ_bbs (FILE *file, basic_block bb)
   edge_iterator ei;
 
   FOR_EACH_EDGE (e, ei, bb->succs)
-    fprintf (file, "bb_%d", e->src->index);
+    fprintf (file, "bb_%d ", e->dest->index);
 }
 
 
@@ -5187,7 +5140,7 @@ print_loop (FILE *file, struct loop *loop, int indent)
 {
   char *s_indent;
   basic_block bb;
-  
+
   if (loop == NULL)
     return;
 
@@ -5197,7 +5150,7 @@ print_loop (FILE *file, struct loop *loop, int indent)
 
   /* Print the loop's header.  */
   fprintf (file, "%sloop_%d\n", s_indent, loop->num);
-  
+
   /* Print the loop's body.  */
   fprintf (file, "%s{\n", s_indent);
   FOR_EACH_BB (bb)
@@ -5209,13 +5162,13 @@ print_loop (FILE *file, struct loop *loop, int indent)
        fprintf (file, "}, succs = {");
        print_succ_bbs (file, bb);
        fprintf (file, "})\n");
-       
+
        /* Print the basic_block's body.  */
        fprintf (file, "%s  {\n", s_indent);
        tree_dump_bb (bb, file, indent + 4);
        fprintf (file, "%s  }\n", s_indent);
       }
-  
+
   print_loop (file, loop->inner, indent + 2);
   fprintf (file, "%s}\n", s_indent);
   print_loop (file, loop->next, indent);
@@ -5225,12 +5178,12 @@ print_loop (FILE *file, struct loop *loop, int indent)
 /* Follow a CFG edge from the entry point of the program, and on entry
    of a loop, pretty print the loop structure on FILE.  */
 
-void 
+void
 print_loop_ir (FILE *file)
 {
   basic_block bb;
-  
-  bb = BASIC_BLOCK (0);
+
+  bb = BASIC_BLOCK (NUM_FIXED_BLOCKS);
   if (bb && bb->loop_father)
     print_loop (file, bb->loop_father, 0);
 }
@@ -5238,7 +5191,7 @@ print_loop_ir (FILE *file)
 
 /* Debugging loops structure at tree level.  */
 
-void 
+void
 debug_loop_ir (void)
 {
   print_loop_ir (stderr);
@@ -5312,7 +5265,7 @@ tree_flow_call_edges_add (sbitmap blocks)
   int last_bb = last_basic_block;
   bool check_last_block = false;
 
-  if (n_basic_blocks == 0)
+  if (n_basic_blocks == NUM_FIXED_BLOCKS)
     return 0;
 
   if (! blocks)
@@ -5340,7 +5293,7 @@ tree_flow_call_edges_add (sbitmap blocks)
       if (!bsi_end_p (bsi))
        t = bsi_stmt (bsi);
 
-      if (need_fake_edge_p (t))
+      if (t && need_fake_edge_p (t))
        {
          edge e;
 
@@ -5413,6 +5366,41 @@ tree_flow_call_edges_add (sbitmap blocks)
   return blocks_split;
 }
 
+/* Purge dead abnormal call edges from basic block BB.  */
+
+bool
+tree_purge_dead_abnormal_call_edges (basic_block bb)
+{
+  bool changed = tree_purge_dead_eh_edges (bb);
+
+  if (current_function_has_nonlocal_label)
+    {
+      tree stmt = last_stmt (bb);
+      edge_iterator ei;
+      edge e;
+
+      if (!(stmt && tree_can_make_abnormal_goto (stmt)))
+       for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
+         {
+           if (e->flags & EDGE_ABNORMAL)
+             {
+               remove_edge (e);
+               changed = true;
+             }
+           else
+             ei_next (&ei);
+         }
+
+      /* See tree_purge_dead_eh_edges below.  */
+      if (changed)
+       free_dominance_info (CDI_DOMINATORS);
+    }
+
+  return changed;
+}
+
+/* Purge dead EH edges from basic block BB.  */
+
 bool
 tree_purge_dead_eh_edges (basic_block bb)
 {
@@ -5503,8 +5491,8 @@ tree_execute_on_shrinking_pred (edge e)
    of 'first'. Both of them are dominated by 'new_head' basic block. When
    'new_head' was created by 'second's incoming edge it received phi arguments
    on the edge by split_edge(). Later, additional edge 'e' was created to
-   connect 'new_head' and 'first'. Now this routine adds phi args on this 
-   additional edge 'e' that new_head to second edge received as part of edge 
+   connect 'new_head' and 'first'. Now this routine adds phi args on this
+   additional edge 'e' that new_head to second edge received as part of edge
    splitting.
 */
 
@@ -5522,8 +5510,8 @@ tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
   /* Browse all 'second' basic block phi nodes and add phi args to
      edge 'e' for 'first' head. PHI args are always in correct order.  */
 
-  for (phi2 = phi_nodes (second), phi1 = phi_nodes (first); 
-       phi2 && phi1; 
+  for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
+       phi2 && phi1;
        phi2 = PHI_CHAIN (phi2),  phi1 = PHI_CHAIN (phi1))
     {
       tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
@@ -5531,8 +5519,8 @@ tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
     }
 }
 
-/* Adds a if else statement to COND_BB with condition COND_EXPR.  
-   SECOND_HEAD is the destination of the THEN and FIRST_HEAD is 
+/* Adds a if else statement to COND_BB with condition COND_EXPR.
+   SECOND_HEAD is the destination of the THEN and FIRST_HEAD is
    the destination of the ELSE part.  */
 static void
 tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
@@ -5550,8 +5538,8 @@ tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
   goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head));
   new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
 
-  /* Add new cond in cond_bb.  */ 
-  bsi = bsi_start (cond_bb); 
+  /* Add new cond in cond_bb.  */
+  bsi = bsi_start (cond_bb);
   bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
   /* Adjust edges appropriately to connect new head with first head
      as well as second head.  */
@@ -5567,6 +5555,7 @@ struct cfg_hooks tree_cfg_hooks = {
   create_bb,                   /* create_basic_block  */
   tree_redirect_edge_and_branch,/* redirect_edge_and_branch  */
   tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force  */
+  tree_can_remove_branch_p,    /* can_remove_branch_p  */
   remove_bb,                   /* delete_basic_block  */
   tree_split_block,            /* split_block  */
   tree_move_block_after,       /* move_block_after  */
@@ -5588,13 +5577,13 @@ struct cfg_hooks tree_cfg_hooks = {
   tree_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
   tree_lv_adjust_loop_header_phi, /* lv_adjust_loop_header_phi*/
   extract_true_false_edges_from_block, /* extract_cond_bb_edges */
-  flush_pending_stmts          /* flush_pending_stmts */  
+  flush_pending_stmts          /* flush_pending_stmts */
 };
 
 
 /* Split all critical edges.  */
 
-static void
+static unsigned int
 split_critical_edges (void)
 {
   basic_block bb;
@@ -5614,9 +5603,10 @@ split_critical_edges (void)
          }
     }
   end_recording_case_labels ();
+  return 0;
 }
 
-struct tree_opt_pass pass_split_crit_edges = 
+struct tree_opt_pass pass_split_crit_edges =
 {
   "crited",                          /* name */
   NULL,                          /* gate */
@@ -5648,13 +5638,15 @@ gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
     return exp;
 
   t = make_rename_temp (type, NULL);
-  new_stmt = build (MODIFY_EXPR, type, t, exp);
+  new_stmt = build2_gimple (GIMPLE_MODIFY_STMT, t, exp);
 
   orig_stmt = bsi_stmt (*bsi);
   SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
   TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
 
   bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+  if (gimple_in_ssa_p (cfun))
+    mark_symbols_for_renaming (new_stmt);
 
   return t;
 }
@@ -5668,7 +5660,7 @@ gimplify_build3 (block_stmt_iterator *bsi, enum tree_code code,
 {
   tree ret;
 
-  ret = fold (build3 (code, type, a, b, c));
+  ret = fold_build3 (code, type, a, b, c);
   STRIP_NOPS (ret);
 
   return gimplify_val (bsi, type, ret);
@@ -5683,7 +5675,7 @@ gimplify_build2 (block_stmt_iterator *bsi, enum tree_code code,
 {
   tree ret;
 
-  ret = fold (build2 (code, type, a, b));
+  ret = fold_build2 (code, type, a, b);
   STRIP_NOPS (ret);
 
   return gimplify_val (bsi, type, ret);
@@ -5698,7 +5690,7 @@ gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
 {
   tree ret;
 
-  ret = fold (build1 (code, type, a));
+  ret = fold_build1 (code, type, a);
   STRIP_NOPS (ret);
 
   return gimplify_val (bsi, type, ret);
@@ -5708,7 +5700,7 @@ gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
 \f
 /* Emit return warnings.  */
 
-static void
+static unsigned int
 execute_warn_function_return (void)
 {
 #ifdef USE_MAPPED_LOCATION
@@ -5762,7 +5754,8 @@ execute_warn_function_return (void)
        {
          tree last = last_stmt (e->src);
          if (TREE_CODE (last) == RETURN_EXPR
-             && TREE_OPERAND (last, 0) == NULL)
+             && TREE_OPERAND (last, 0) == NULL
+             && !TREE_NO_WARNING (last))
            {
 #ifdef USE_MAPPED_LOCATION
              location = EXPR_LOCATION (last);
@@ -5780,6 +5773,7 @@ execute_warn_function_return (void)
            }
        }
     }
+  return 0;
 }
 
 
@@ -5826,16 +5820,17 @@ struct tree_opt_pass pass_warn_function_return =
 
 /* Emit noreturn warnings.  */
 
-static void
+static unsigned int
 execute_warn_function_noreturn (void)
 {
   if (warn_missing_noreturn
       && !TREE_THIS_VOLATILE (cfun->decl)
       && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
       && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl))
-    warning (0, "%Jfunction might be possible candidate for "
-            "attribute %<noreturn%>",
+    warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+            "for attribute %<noreturn%>",
             cfun->decl);
+  return 0;
 }
 
 struct tree_opt_pass pass_warn_function_noreturn =