OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index bdbff33..15beeab 100644 (file)
@@ -1,5 +1,5 @@
 /* Control flow functions for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
@@ -44,8 +44,9 @@ Boston, MA 02110-1301, 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.  */
@@ -68,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
@@ -132,15 +121,13 @@ init_empty_tree_cfg (void)
   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 (basic_block, gc, basic_block_info, initial_cfg_capacity);
-  memset (VEC_address (basic_block, basic_block_info), 0,
-         sizeof (basic_block) * 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.  */
   label_to_block_map = VEC_alloc (basic_block, gc, initial_cfg_capacity);
-  VEC_safe_grow (basic_block, gc, label_to_block_map, initial_cfg_capacity);
-  memset (VEC_address (basic_block, label_to_block_map),
-         0, sizeof (basic_block) * 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);
@@ -182,14 +169,7 @@ build_tree_cfg (tree *tp)
 
   /* Adjust the size of the array.  */
   if (VEC_length (basic_block, basic_block_info) < (size_t) n_basic_blocks)
-    {
-      size_t old_size = VEC_length (basic_block, basic_block_info);
-      basic_block *p;
-      VEC_safe_grow (basic_block, gc, basic_block_info, n_basic_blocks);
-      p = VEC_address (basic_block, basic_block_info);
-      memset (&p[old_size], 0,
-             sizeof (basic_block) * (n_basic_blocks - old_size));
-    }
+    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 ();
@@ -201,6 +181,7 @@ build_tree_cfg (tree *tp)
 
   /* Create the edges of the flowgraph.  */
   make_edges ();
+  cleanup_dead_labels ();
 
   /* Debugging dumps.  */
 
@@ -244,7 +225,7 @@ 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 */
 };
 
@@ -314,8 +295,8 @@ factor_computed_gotos (void)
            }
 
          /* Copy the original computed goto's destination into VAR.  */
-         assignment = build2 (MODIFY_EXPR, ptr_type_node,
-                              var, GOTO_DESTINATION (last));
+         assignment = build_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.  */
@@ -388,7 +369,8 @@ create_bb (void *h, void *e, basic_block after)
 
   bb->index = last_basic_block;
   bb->flags = BB_NEW;
-  bb->stmt_list = h ? (tree) h : alloc_stmt_list ();
+  bb->il.tree = GGC_CNEW (struct tree_bb_info);
+  set_bb_stmt_list (bb, h ? (tree) h : alloc_stmt_list ());
 
   /* Add the new block to the linked list of blocks.  */
   link_block (bb, after);
@@ -396,12 +378,8 @@ create_bb (void *h, void *e, basic_block after)
   /* Grow the basic block array if needed.  */
   if ((size_t) last_basic_block == VEC_length (basic_block, basic_block_info))
     {
-      size_t old_size = VEC_length (basic_block, basic_block_info);
       size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
-      basic_block *p;
-      VEC_safe_grow (basic_block, gc, basic_block_info, new_size);
-      p = VEC_address (basic_block, basic_block_info);
-      memset (&p[old_size], 0, sizeof (basic_block) * (new_size - old_size));
+      VEC_safe_grow_cleared (basic_block, gc, basic_block_info, new_size);
     }
 
   /* Add the newly created block to the array.  */
@@ -432,10 +410,20 @@ fold_cond_expr_cond (void)
       if (stmt
          && TREE_CODE (stmt) == COND_EXPR)
        {
-         tree cond = fold (COND_EXPR_COND (stmt));
-         if (integer_zerop (cond))
+         tree cond;
+         bool zerop, onep;
+
+         fold_defer_overflow_warnings ();
+         cond = fold (COND_EXPR_COND (stmt));
+         zerop = integer_zerop (cond);
+         onep = integer_onep (cond);
+         fold_undefer_overflow_warnings (((zerop || onep)
+                                          && !TREE_NO_WARNING (stmt)),
+                                         stmt,
+                                         WARN_STRICT_OVERFLOW_CONDITIONAL);
+         if (zerop)
            COND_EXPR_COND (stmt) = boolean_false_node;
-         else if (integer_onep (cond))
+         else if (onep)
            COND_EXPR_COND (stmt) = boolean_true_node;
        }
     }
@@ -501,11 +489,14 @@ make_edges (void)
              break;
 
            case MODIFY_EXPR:
+             gcc_unreachable ();
+
+           case GIMPLE_MODIFY_STMT:
              if (is_ctrl_altering_stmt (last))
                {
-                 /* 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.  */
+                 /* 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);  
 
@@ -587,9 +578,6 @@ make_edges (void)
 
   /* Fold COND_EXPR_COND of each COND_EXPR.  */
   fold_cond_expr_cond ();
-
-  /* Clean up the graph and warn for unreachable code.  */
-  cleanup_tree_cfg ();
 }
 
 
@@ -628,30 +616,12 @@ make_cond_expr_edges (basic_block bb)
       e->goto_locus = EXPR_LOCUS (COND_EXPR_ELSE (entry));
 #endif
     }
-}
-
-/* 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);
+  /* We do not need the gotos anymore.  */
+  COND_EXPR_THEN (entry) = NULL_TREE;
+  COND_EXPR_ELSE (entry) = NULL_TREE;
 }
 
-/* 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.
@@ -660,18 +630,20 @@ edge_to_cases_eq (const void *p1, const void *p2)
    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 = (struct edge_to_cases_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.  */
@@ -680,11 +652,7 @@ 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.  */
@@ -700,46 +668,11 @@ recording_case_labels_p (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 = XNEW (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.
 
@@ -748,7 +681,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;
@@ -758,16 +690,9 @@ get_cases_for_edge (edge e, tree t)
   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
@@ -777,11 +702,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.
@@ -898,11 +831,19 @@ make_goto_expr_edges (basic_block bb)
    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
    all passes later on.
-   We only run this pass once, running it more than once is probably not
-   profitable.  */
+   We rerun this pass after CFG is created, to get rid of the labels that
+   are no longer referenced.  After then we do not run it any more, since
+   (almost) no new labels should be created.  */
 
 /* A map from basic block index to the leading label of that block.  */
-static tree *label_for_bb;
+static struct label_record
+{
+  /* The label.  */
+  tree label;
+
+  /* True if the label is referenced from somewhere.  */
+  bool used;
+} *label_for_bb;
 
 /* Callback for for_each_eh_region.  Helper for cleanup_dead_labels.  */
 static void
@@ -920,7 +861,8 @@ update_eh_label (struct eh_region *region)
       if (! bb)
        return;
 
-      new_label = label_for_bb[bb->index];
+      new_label = label_for_bb[bb->index].label;
+      label_for_bb[bb->index].used = true;
       set_eh_region_tree_label (region, new_label);
     }
 }
@@ -930,11 +872,17 @@ static tree
 main_block_label (tree label)
 {
   basic_block bb = label_to_block (label);
+  tree main_label = label_for_bb[bb->index].label;
 
   /* label_to_block possibly inserted undefined label into the chain.  */
-  if (!label_for_bb[bb->index])
-    label_for_bb[bb->index] = label;
-  return label_for_bb[bb->index];
+  if (!main_label)
+    {
+      label_for_bb[bb->index].label = label;
+      main_label = label;
+    }
+
+  label_for_bb[bb->index].used = true;
+  return main_label;
 }
 
 /* Cleanup redundant labels.  This is a three-step process:
@@ -946,7 +894,7 @@ void
 cleanup_dead_labels (void)
 {
   basic_block bb;
-  label_for_bb = XCNEWVEC (tree, last_basic_block);
+  label_for_bb = XCNEWVEC (struct label_record, 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.  */
@@ -965,19 +913,19 @@ cleanup_dead_labels (void)
 
          /* If we have not yet seen a label for the current block,
             remember this one and see if there are more labels.  */
-         if (! label_for_bb[bb->index])
+         if (!label_for_bb[bb->index].label)
            {
-             label_for_bb[bb->index] = label;
+             label_for_bb[bb->index].label = label;
              continue;
            }
 
          /* If we did see a label for the current block already, but it
             is an artificially created label, replace it if the current
             label is a user defined label.  */
-         if (! DECL_ARTIFICIAL (label)
-             && DECL_ARTIFICIAL (label_for_bb[bb->index]))
+         if (!DECL_ARTIFICIAL (label)
+             && DECL_ARTIFICIAL (label_for_bb[bb->index].label))
            {
-             label_for_bb[bb->index] = label;
+             label_for_bb[bb->index].label = label;
              break;
            }
        }
@@ -1000,10 +948,12 @@ cleanup_dead_labels (void)
            true_branch = COND_EXPR_THEN (stmt);
            false_branch = COND_EXPR_ELSE (stmt);
 
-           GOTO_DESTINATION (true_branch)
-             = main_block_label (GOTO_DESTINATION (true_branch));
-           GOTO_DESTINATION (false_branch)
-             = main_block_label (GOTO_DESTINATION (false_branch));
+           if (true_branch)
+             GOTO_DESTINATION (true_branch)
+                     = main_block_label (GOTO_DESTINATION (true_branch));
+           if (false_branch)
+             GOTO_DESTINATION (false_branch)
+                     = main_block_label (GOTO_DESTINATION (false_branch));
 
            break;
          }
@@ -1047,11 +997,15 @@ cleanup_dead_labels (void)
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator i;
-      tree label_for_this_bb = label_for_bb[bb->index];
+      tree label_for_this_bb = label_for_bb[bb->index].label;
 
-      if (! label_for_this_bb)
+      if (!label_for_this_bb)
        continue;
 
+      /* If the main label of the block is unused, we may still remove it.  */
+      if (!label_for_bb[bb->index].used)
+       label_for_this_bb = NULL;
+
       for (i = bsi_start (bb); !bsi_end_p (i); )
        {
          tree label, stmt = bsi_stmt (i);
@@ -1242,10 +1196,12 @@ replace_uses_by (tree name, tree val)
   use_operand_p use;
   tree stmt;
   edge e;
-  unsigned i;
 
   FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
+      if (TREE_CODE (stmt) != PHI_NODE)
+       push_stmt_changes (&stmt);
+
       FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
         {
          replace_exp (use, val);
@@ -1263,32 +1219,37 @@ replace_uses_by (tree name, tree val)
                }
            }
        }
+
       if (TREE_CODE (stmt) != PHI_NODE)
        {
          tree rhs;
 
          fold_stmt_inplace (stmt);
+         if (cfgcleanup_altered_bbs)
+           bitmap_set_bit (cfgcleanup_altered_bbs, bb_for_stmt (stmt)->index);
+
+         /* 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);
-         mark_new_vars_to_rename (stmt);
+
+         pop_stmt_changes (&stmt);
        }
     }
 
-  gcc_assert (num_imm_uses (name) == 0);
+  gcc_assert (has_zero_uses (name));
 
   /* Also update the trees stored in loop structures.  */
   if (current_loops)
     {
       struct loop *loop;
+      loop_iterator li;
 
-      for (i = 0; i < current_loops->num; i++)
+      FOR_EACH_LOOP (li, loop, 0)
        {
-         loop = current_loops->parray[i];
-         if (loop)
-           substitute_in_loop_info (loop, name, val);
+         substitute_in_loop_info (loop, name, val);
        }
     }
 }
@@ -1330,15 +1291,16 @@ tree_merge_blocks (basic_block a, basic_block b)
             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 = build_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.  */
@@ -1375,9 +1337,12 @@ tree_merge_blocks (basic_block a, basic_block b)
     }
 
   /* Merge the chains.  */
-  last = tsi_last (a->stmt_list);
-  tsi_link_after (&last, b->stmt_list, TSI_NEW_STMT);
-  b->stmt_list = NULL;
+  last = tsi_last (bb_stmt_list (a));
+  tsi_link_after (&last, bb_stmt_list (b), TSI_NEW_STMT);
+  set_bb_stmt_list (b, NULL_TREE);
+
+  if (cfgcleanup_altered_bbs)
+    bitmap_set_bit (cfgcleanup_altered_bbs, a->index);
 }
 
 
@@ -1559,9 +1524,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)
@@ -1576,9 +1541,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 ();
        }
     }
@@ -1871,6 +1836,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);
@@ -1966,7 +1934,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;
     }
 
@@ -2010,57 +1978,60 @@ remove_bb (basic_block bb)
     }
 
   /* Remove all the instructions in the block.  */
-  for (i = bsi_start (bb); !bsi_end_p (i);)
+  if (bb_stmt_list (bb) != NULL_TREE)
     {
-      tree stmt = bsi_stmt (i);
-      if (TREE_CODE (stmt) == LABEL_EXPR
-          && (FORCED_LABEL (LABEL_EXPR_LABEL (stmt))
-             || DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))))
+      for (i = bsi_start (bb); !bsi_end_p (i);)
        {
-         basic_block new_bb;
-         block_stmt_iterator new_bsi;
+         tree stmt = bsi_stmt (i);
+         if (TREE_CODE (stmt) == LABEL_EXPR
+             && (FORCED_LABEL (LABEL_EXPR_LABEL (stmt))
+                 || DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt))))
+           {
+             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)))
+             /* 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
            {
-             DECL_NONLOCAL (LABEL_EXPR_LABEL (stmt)) = 0;
-             FORCED_LABEL (LABEL_EXPR_LABEL (stmt)) = 1;
+             /* 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);
            }
 
-         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 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
-        jump threading, thus resulting in bogus warnings.  Not great,
-        since this way we lose warnings for gotos in the original
-        program that are indeed unreachable.  */
-      if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_HAS_LOCATION (stmt) && !loc)
-       {
+         /* Don't warn for removed gotos.  Gotos are often removed due to
+            jump threading, thus resulting in bogus warnings.  Not great,
+            since this way we lose warnings for gotos in the original
+            program that are indeed unreachable.  */
+         if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_HAS_LOCATION (stmt) && !loc)
+           {
 #ifdef USE_MAPPED_LOCATION
-         if (EXPR_HAS_LOCATION (stmt))
-           loc = EXPR_LOCATION (stmt);
+             if (EXPR_HAS_LOCATION (stmt))
+               loc = EXPR_LOCATION (stmt);
 #else
-         source_locus t;
-         t = EXPR_LOCUS (stmt);
-         if (t && LOCATION_LINE (*t) > 0)
-           loc = t;
+             source_locus t;
+             t = EXPR_LOCUS (stmt);
+             if (t && LOCATION_LINE (*t) > 0)
+               loc = t;
 #endif
+           }
        }
     }
 
@@ -2077,6 +2048,7 @@ remove_bb (basic_block bb)
 #endif
 
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
+  bb->il.tree = NULL;
 }
 
 
@@ -2105,7 +2077,18 @@ find_taken_edge (basic_block bb, tree val)
     return find_taken_edge_switch_expr (bb, val);
 
   if (computed_goto_p (stmt))
-    return find_taken_edge_computed_goto (bb, TREE_OPERAND( val, 0));
+    {
+      /* Only optimize if the argument is a label, if the argument is
+        not a label then we can not construct a proper CFG.
+
+         It may be the case that we only need to allow the LABEL_REF to
+         appear inside an ADDR_EXPR, but we also allow the LABEL_REF to
+         appear inside a LABEL_EXPR just to be safe.  */
+      if ((TREE_CODE (val) == ADDR_EXPR || TREE_CODE (val) == LABEL_EXPR)
+         && TREE_CODE (TREE_OPERAND (val, 0)) == LABEL_DECL)
+       return find_taken_edge_computed_goto (bb, TREE_OPERAND (val, 0));
+      return NULL;
+    }
 
   gcc_unreachable ();
 }
@@ -2142,7 +2125,7 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
   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
@@ -2220,7 +2203,7 @@ find_case_label_for_value (tree switch_expr, tree val)
 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);
 }
 
 
@@ -2508,8 +2491,8 @@ tree_can_make_abnormal_goto (tree t)
 {
   if (computed_goto_p (t))
     return true;
-  if (TREE_CODE (t) == MODIFY_EXPR)
-    t = TREE_OPERAND (t, 1);
+  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)
@@ -2565,92 +2548,22 @@ stmt_ends_bb_p (tree t)
   return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t);
 }
 
-
-/* Add gotos that used to be represented implicitly in the CFG.  */
+/* Remove block annotations and other datastructures.  */
 
 void
-disband_implicit_edges (void)
+delete_tree_cfg_annotations (void)
 {
   basic_block bb;
-  block_stmt_iterator last;
-  edge e;
-  edge_iterator ei;
-  tree stmt, label;
+  block_stmt_iterator bsi;
 
+  /* Remove annotations from every tree in the function.  */
   FOR_EACH_BB (bb)
-    {
-      last = bsi_last (bb);
-      stmt = last_stmt (bb);
-
-      if (stmt && TREE_CODE (stmt) == COND_EXPR)
-       {
-         /* Remove superfluous gotos from COND_EXPR branches.  Moved
-            from cfg_remove_useless_stmts here since it violates the
-            invariants for tree--cfg correspondence and thus fits better
-            here where we do it anyway.  */
-         e = find_edge (bb, bb->next_bb);
-         if (e)
-           {
-             if (e->flags & EDGE_TRUE_VALUE)
-               COND_EXPR_THEN (stmt) = build_empty_stmt ();
-             else if (e->flags & EDGE_FALSE_VALUE)
-               COND_EXPR_ELSE (stmt) = build_empty_stmt ();
-             else
-               gcc_unreachable ();
-             e->flags |= EDGE_FALLTHRU;
-           }
-
-         continue;
-       }
-
-      if (stmt && TREE_CODE (stmt) == RETURN_EXPR)
-       {
-         /* Remove the RETURN_EXPR if we may fall though to the exit
-            instead.  */
-         gcc_assert (single_succ_p (bb));
-         gcc_assert (single_succ (bb) == EXIT_BLOCK_PTR);
-
-         if (bb->next_bb == EXIT_BLOCK_PTR
-             && !TREE_OPERAND (stmt, 0))
-           {
-             bsi_remove (&last, true);
-             single_succ_edge (bb)->flags |= EDGE_FALLTHRU;
-           }
-         continue;
-       }
-
-      /* There can be no fallthru edge if the last statement is a control
-        one.  */
-      if (stmt && is_ctrl_stmt (stmt))
-       continue;
-
-      /* Find a fallthru edge and emit the goto if necessary.  */
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
-
-      if (!e || e->dest == bb->next_bb)
-       continue;
-
-      gcc_assert (e->dest != EXIT_BLOCK_PTR);
-      label = tree_block_label (e->dest);
-
-      stmt = build1 (GOTO_EXPR, void_type_node, label);
-#ifdef USE_MAPPED_LOCATION
-      SET_EXPR_LOCATION (stmt, e->goto_locus);
-#else
-      SET_EXPR_LOCUS (stmt, e->goto_locus);
-#endif
-      bsi_insert_after (&last, stmt, BSI_NEW_STMT);
-      e->flags &= ~EDGE_FALLTHRU;
-    }
-}
-
-/* Remove block annotations and other datastructures.  */
-
-void
-delete_tree_cfg_annotations (void)
-{
+    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;
 }
 
@@ -2675,16 +2588,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.  */
@@ -2750,14 +2653,10 @@ set_bb_for_stmt (tree t, basic_block bb)
              LABEL_DECL_UID (t) = uid = cfun->last_label_uid++;
              if (old_len <= (unsigned) uid)
                {
-                 basic_block *addr;
                  unsigned new_len = 3 * uid / 2;
 
-                 VEC_safe_grow (basic_block, gc, label_to_block_map,
-                                new_len);
-                 addr = VEC_address (basic_block, label_to_block_map);
-                 memset (&addr[old_len],
-                         0, sizeof (basic_block) * (new_len - old_len));
+                 VEC_safe_grow_cleared (basic_block, gc, label_to_block_map,
+                                        new_len);
                }
            }
          else
@@ -2802,6 +2701,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;
@@ -2861,7 +2762,10 @@ bsi_remove (block_stmt_iterator *i, bool remove_eh_info)
   tsi_delink (&i->tsi);
   mark_stmt_modified (t);
   if (remove_eh_info)
-    remove_stmt_from_eh_region (t);
+    {
+      remove_stmt_from_eh_region (t);
+      gimple_remove_stmt_histograms (cfun, t);
+    }
 }
 
 
@@ -2912,6 +2816,8 @@ 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);
 
@@ -2927,6 +2833,8 @@ bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool update_eh_info)
        }
     }
 
+  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);
@@ -3011,9 +2919,9 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
          tree op = TREE_OPERAND (tmp, 0);
          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;
@@ -3167,33 +3075,12 @@ tree_split_edge (edge edge_in)
   new_edge->count = edge_in->count;
 
   e = redirect_edge_and_branch (edge_in, new_bb);
-  gcc_assert (e);
+  gcc_assert (e == edge_in);
   reinstall_phi_args (new_edge, e);
 
   return new_bb;
 }
 
-
-/* Return true when BB has label LABEL in it.  */
-
-static bool
-has_label_p (basic_block bb, tree label)
-{
-  block_stmt_iterator bsi;
-
-  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-    {
-      tree stmt = bsi_stmt (bsi);
-
-      if (TREE_CODE (stmt) != LABEL_EXPR)
-       return false;
-      if (LABEL_EXPR_LABEL (stmt) == label)
-       return true;
-    }
-  return false;
-}
-
-
 /* Callback for walk_tree, check that all elements with address taken are
    properly noticed as such.  The DATA is an int* that is 1 if TP was seen
    inside a PHI node.  */
@@ -3232,7 +3119,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)))
        {
@@ -3518,8 +3408,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))
     {
@@ -3527,15 +3416,58 @@ verify_node_sharing (tree * tp, int *walk_subtrees, void *data)
       return NULL;
     }
 
-  slot = htab_find_slot (htab, *tp, INSERT);
-  if (*slot)
-    return (tree) *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
@@ -3544,11 +3476,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)
     {
@@ -3559,6 +3492,7 @@ 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");
@@ -3589,7 +3523,7 @@ 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");
@@ -3604,6 +3538,9 @@ 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");
@@ -3612,7 +3549,7 @@ verify_stmts (void)
 
          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");
@@ -3622,11 +3559,18 @@ verify_stmts (void)
            }
        }
     }
+  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)
+  if (err | eh_error_found)
     internal_error ("verify_stmts failed");
 
-  htab_delete (htab);
+  pointer_set_destroy (visited);
+  pointer_set_destroy (visited_stmts);
+  verify_histograms ();
   timevar_pop (TV_TREE_STMT_VERIFY);
 }
 
@@ -3643,15 +3587,15 @@ tree_verify_flow_info (void)
   edge e;
   edge_iterator ei;
 
-  if (ENTRY_BLOCK_PTR->stmt_list)
+  if (ENTRY_BLOCK_PTR->il.tree)
     {
-      error ("ENTRY_BLOCK has a statement list associated with it");
+      error ("ENTRY_BLOCK has IL associated with it");
       err = 1;
     }
 
-  if (EXIT_BLOCK_PTR->stmt_list)
+  if (EXIT_BLOCK_PTR->il.tree)
     {
-      error ("EXIT_BLOCK has a statement list associated with it");
+      error ("EXIT_BLOCK has IL associated with it");
       err = 1;
     }
 
@@ -3769,10 +3713,12 @@ tree_verify_flow_info (void)
          {
            edge true_edge;
            edge false_edge;
-           if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
-               || TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
+  
+           if (COND_EXPR_THEN (stmt) != NULL_TREE
+               || COND_EXPR_ELSE (stmt) != NULL_TREE)
              {
-               error ("structured COND_EXPR at the end of bb %d", bb->index);
+               error ("COND_EXPR with code in branches at the end of bb %d",
+                      bb->index);
                err = 1;
              }
 
@@ -3789,22 +3735,6 @@ tree_verify_flow_info (void)
                       bb->index);
                err = 1;
              }
-
-           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",
-                      bb->index);
-               err = 1;
-             }
-
-           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",
-                      bb->index);
-               err = 1;
-             }
          }
          break;
 
@@ -3935,7 +3865,7 @@ tree_verify_flow_info (void)
        }
     }
 
-  if (dom_computed[CDI_DOMINATORS] >= DOM_NO_FAST_QUERY)
+  if (dom_info_state (CDI_DOMINATORS) >= DOM_NO_FAST_QUERY)
     verify_dominators (CDI_DOMINATORS);
 
   return err;
@@ -3959,7 +3889,7 @@ tree_make_forwarder_block (edge fallthru)
   if (single_pred_p (bb))
     return;
 
-  /* If we redirected a branch we must create new phi nodes at the
+  /* 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))
     {
@@ -4083,10 +4013,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
   switch (stmt ? TREE_CODE (stmt) : ERROR_MARK)
     {
     case COND_EXPR:
-      stmt = (e->flags & EDGE_TRUE_VALUE
-             ? COND_EXPR_THEN (stmt)
-             : COND_EXPR_ELSE (stmt));
-      GOTO_DESTINATION (stmt) = label;
+      /* For COND_EXPR, we only need to redirect the edge.  */
       break;
 
     case GOTO_EXPR:
@@ -4160,6 +4087,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.  */
 
@@ -4181,7 +4119,7 @@ tree_split_block (basic_block bb, void *stmt)
 {
   block_stmt_iterator bsi;
   tree_stmt_iterator tsi_tgt;
-  tree act;
+  tree act, list;
   basic_block new_bb;
   edge e;
   edge_iterator ei;
@@ -4221,8 +4159,9 @@ tree_split_block (basic_block bb, void *stmt)
      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);
+  list = tsi_split_statement_list_before (&bsi.tsi);
+  set_bb_stmt_list (new_bb, list);
+  for (tsi_tgt = tsi_start (list);
        !tsi_end_p (tsi_tgt); tsi_next (&tsi_tgt))
     change_bb_for_stmt (tsi_stmt (tsi_tgt), new_bb);
 
@@ -4298,6 +4237,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.  */
@@ -4427,7 +4367,7 @@ tree_duplicate_sese_region (edge entry, edge exit,
   if (loop->header == entry->dest)
     {
       copying_header = true;
-      loop->copy = loop->outer;
+      loop->copy = loop_outer (loop);
 
       if (!dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src))
        return false;
@@ -4570,7 +4510,8 @@ 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 && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))))
+  if (p->block
+      && (EXPR_P (t) || GIMPLE_STMT_P (t)))
     TREE_BLOCK (t) = p->block;
 
   if (OMP_DIRECTIVE_P (t)
@@ -4596,7 +4537,7 @@ move_stmt_r (tree *tp, int *walk_subtrees, void *data)
          if (p->new_label_map)
            {
              struct tree_map in, *out;
-             in.from = t;
+             in.base.from = t;
              out = htab_find_with_hash (p->new_label_map, &in, DECL_UID (t));
              if (out)
                *tp = t = out->to;
@@ -4649,7 +4590,9 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
   block_stmt_iterator si;
   struct move_stmt_d d;
   unsigned old_len, new_len;
-  basic_block *addr;
+
+  /* Remove BB from dominance structures.  */
+  delete_from_dominance_info (CDI_DOMINATORS, bb);
 
   /* Link BB to the new linked list.  */
   move_block_after (bb, after);
@@ -4669,20 +4612,19 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
   /* 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;
+  if (bb->index >= cfg->x_last_basic_block)
+    cfg->x_last_basic_block = bb->index + 1;
 
   old_len = VEC_length (basic_block, cfg->x_basic_block_info);
   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 (basic_block, gc, cfg->x_basic_block_info, new_len);
-      addr = VEC_address (basic_block, cfg->x_basic_block_info);
-      memset (&addr[old_len], 0, sizeof (basic_block) * (new_len - old_len));
+      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);
+               bb->index, 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.  */
@@ -4714,11 +4656,8 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
          if (old_len <= (unsigned) uid)
            {
              new_len = 3 * uid / 2;
-             VEC_safe_grow (basic_block, gc, cfg->x_label_to_block_map,
-                            new_len);
-             addr = VEC_address (basic_block, cfg->x_label_to_block_map);
-             memset (&addr[old_len], 0,
-                     sizeof (basic_block) * (new_len - old_len));
+             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);
@@ -4740,6 +4679,8 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb,
        {
          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);
        }
     }
 }
@@ -4788,7 +4729,7 @@ new_label_mapper (tree decl, void *data)
 
   m = xmalloc (sizeof (struct tree_map));
   m->hash = DECL_UID (decl);
-  m->from = decl;
+  m->base.from = decl;
   m->to = create_artificial_label ();
   LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
 
@@ -4991,6 +4932,7 @@ void
 dump_function_to_file (tree fn, FILE *file, int flags)
 {
   tree arg, vars, var;
+  struct function *dsf;
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
   tree chain;
@@ -5008,8 +4950,10 @@ dump_function_to_file (tree fn, FILE *file, int flags)
     }
   fprintf (file, ")\n");
 
-  if (flags & TDF_DETAILS)
-    dump_eh_tree (file, DECL_STRUCT_FUNCTION (fn));
+  dsf = DECL_STRUCT_FUNCTION (fn);
+  if (dsf && (flags & TDF_DETAILS))
+    dump_eh_tree (file, dsf);
+
   if (flags & TDF_RAW)
     {
       dump_node (fn, TDF_SLIM | flags, file);
@@ -5400,6 +5344,144 @@ tree_purge_dead_abnormal_call_edges (basic_block bb)
   return changed;
 }
 
+/* Stores all basic blocks dominated by BB to DOM_BBS.  */
+
+static void
+get_all_dominated_blocks (basic_block bb, VEC (basic_block, heap) **dom_bbs)
+{
+  basic_block son;
+
+  VEC_safe_push (basic_block, heap, *dom_bbs, bb);
+  for (son = first_dom_son (CDI_DOMINATORS, bb);
+       son;
+       son = next_dom_son (CDI_DOMINATORS, son))
+    get_all_dominated_blocks (son, dom_bbs);
+}
+
+/* Removes edge E and all the blocks dominated by it, and updates dominance
+   information.  The IL in E->src needs to be updated separately.
+   If dominance info is not available, only the edge E is removed.*/
+
+void
+remove_edge_and_dominated_blocks (edge e)
+{
+  VEC (basic_block, heap) *bbs_to_remove = NULL;
+  VEC (basic_block, heap) *bbs_to_fix_dom = NULL;
+  bitmap df, df_idom;
+  edge f;
+  edge_iterator ei;
+  bool none_removed = false;
+  unsigned i;
+  basic_block bb, dbb;
+  bitmap_iterator bi;
+
+  if (!dom_info_available_p (CDI_DOMINATORS))
+    {
+      remove_edge (e);
+      return;
+    }
+
+  /* No updating is needed for edges to exit.  */
+  if (e->dest == EXIT_BLOCK_PTR)
+    {
+      if (cfgcleanup_altered_bbs)
+       bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
+      remove_edge (e);
+      return;
+    }
+
+  /* First, we find the basic blocks to remove.  If E->dest has a predecessor
+     that is not dominated by E->dest, then this set is empty.  Otherwise,
+     all the basic blocks dominated by E->dest are removed.
+
+     Also, to DF_IDOM we store the immediate dominators of the blocks in
+     the dominance frontier of E (i.e., of the successors of the
+     removed blocks, if there are any, and of E->dest otherwise).  */
+  FOR_EACH_EDGE (f, ei, e->dest->preds)
+    {
+      if (f == e)
+       continue;
+
+      if (!dominated_by_p (CDI_DOMINATORS, f->src, e->dest))
+       {
+         none_removed = true;
+         break;
+       }
+    }
+
+  df = BITMAP_ALLOC (NULL);
+  df_idom = BITMAP_ALLOC (NULL);
+
+  if (none_removed)
+    bitmap_set_bit (df_idom,
+                   get_immediate_dominator (CDI_DOMINATORS, e->dest)->index);
+  else
+    {
+      get_all_dominated_blocks (e->dest, &bbs_to_remove);
+      for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
+       {
+         FOR_EACH_EDGE (f, ei, bb->succs)
+           {
+             if (f->dest != EXIT_BLOCK_PTR)
+               bitmap_set_bit (df, f->dest->index);
+           }
+       }
+      for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
+       bitmap_clear_bit (df, bb->index);
+
+      EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi)
+       {
+         bb = BASIC_BLOCK (i);
+         bitmap_set_bit (df_idom,
+                         get_immediate_dominator (CDI_DOMINATORS, bb)->index);
+       }
+    }
+
+  if (cfgcleanup_altered_bbs)
+    {
+      /* Record the set of the altered basic blocks.  */
+      bitmap_set_bit (cfgcleanup_altered_bbs, e->src->index);
+      bitmap_ior_into (cfgcleanup_altered_bbs, df);
+    }
+
+  /* Remove E and the cancelled blocks.  */
+  if (none_removed)
+    remove_edge (e);
+  else
+    {
+      for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
+       delete_basic_block (bb);
+    }
+
+  /* Update the dominance information.  The immediate dominator may change only
+     for blocks whose immediate dominator belongs to DF_IDOM:
+   
+     Suppose that idom(X) = Y before removal of E and idom(X) != Y after the
+     removal.  Let Z the arbitrary block such that idom(Z) = Y and
+     Z dominates X after the removal.  Before removal, there exists a path P
+     from Y to X that avoids Z.  Let F be the last edge on P that is
+     removed, and let W = F->dest.  Before removal, idom(W) = Y (since Y
+     dominates W, and because of P, Z does not dominate W), and W belongs to
+     the dominance frontier of E.  Therefore, Y belongs to DF_IDOM.  */ 
+  EXECUTE_IF_SET_IN_BITMAP (df_idom, 0, i, bi)
+    {
+      bb = BASIC_BLOCK (i);
+      for (dbb = first_dom_son (CDI_DOMINATORS, bb);
+          dbb;
+          dbb = next_dom_son (CDI_DOMINATORS, dbb))
+       VEC_safe_push (basic_block, heap, bbs_to_fix_dom, dbb);
+    }
+
+  iterate_fix_dominators (CDI_DOMINATORS,
+                         VEC_address (basic_block, bbs_to_fix_dom),
+                         VEC_length (basic_block, bbs_to_fix_dom));
+
+  BITMAP_FREE (df);
+  BITMAP_FREE (df_idom);
+  VEC_free (basic_block, heap, bbs_to_remove);
+  VEC_free (basic_block, heap, bbs_to_fix_dom);
+}
+
 /* Purge dead EH edges from basic block BB.  */
 
 bool
@@ -5417,33 +5499,13 @@ tree_purge_dead_eh_edges (basic_block bb)
     {
       if (e->flags & EDGE_EH)
        {
-         remove_edge (e);
+         remove_edge_and_dominated_blocks (e);
          changed = true;
        }
       else
        ei_next (&ei);
     }
 
-  /* Removal of dead EH edges might change dominators of not
-     just immediate successors.  E.g. when bb1 is changed so that
-     it no longer can throw and bb1->bb3 and bb1->bb4 are dead
-     eh edges purged by this function in:
-           0
-         / \
-        v   v
-        1-->2
-        / \  |
-       v   v |
-       3-->4 |
-        \    v
-        --->5
-            |
-            -
-     idom(bb5) must be recomputed.  For now just free the dominance
-     info.  */
-  if (changed)
-    free_dominance_info (CDI_DOMINATORS);
-
   return changed;
 }
 
@@ -5524,20 +5586,18 @@ tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
    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,
-                            basic_block cond_bb, void *cond_e)
+tree_lv_add_condition_to_bb (basic_block first_head ATTRIBUTE_UNUSED,
+                            basic_block second_head ATTRIBUTE_UNUSED,
+                            basic_block cond_bb, void *cond_e)
 {
   block_stmt_iterator bsi;
-  tree goto1 = NULL_TREE;
-  tree goto2 = NULL_TREE;
   tree new_cond_expr = NULL_TREE;
   tree cond_expr = (tree) cond_e;
   edge e0;
 
   /* Build new conditional expr */
-  goto1 = build1 (GOTO_EXPR, void_type_node, tree_block_label (first_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);
+  new_cond_expr = build3 (COND_EXPR, void_type_node, cond_expr,
+                         NULL_TREE, NULL_TREE);
 
   /* Add new cond in cond_bb.  */
   bsi = bsi_start (cond_bb);
@@ -5556,6 +5616,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  */
@@ -5638,7 +5699,7 @@ gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
     return exp;
 
   t = make_rename_temp (type, NULL);
-  new_stmt = build2 (MODIFY_EXPR, type, t, exp);
+  new_stmt = build_gimple_modify_stmt (t, exp);
 
   orig_stmt = bsi_stmt (*bsi);
   SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
@@ -5646,7 +5707,7 @@ gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
 
   bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
   if (gimple_in_ssa_p (cfun))
-    mark_new_vars_to_rename (new_stmt);
+    mark_symbols_for_renaming (new_stmt);
 
   return t;
 }