OSDN Git Service

* config/i386/i386.c (x86_schedule): Fix typo, m_K6 intead of m_K8.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 9452dff..f9be0b3 100644 (file)
@@ -43,6 +43,8 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "except.h"
 #include "cfgloop.h"
+#include "cfglayout.h"
+#include "hashtab.h"
 
 /* This file contains functions for building the Control Flow Graph (CFG)
    for a function tree.  */
@@ -56,6 +58,30 @@ static const int initial_cfg_capacity = 20;
    building of the CFG in code with lots of gotos.  */
 static GTY(()) varray_type label_to_block_map;
 
+/* This hash table allows us to efficiently lookup the one and only one
+   CASE_LABEL_EXPR which contains the LABEL_DECL for the target block
+   of one or more case statements.  Efficient access to this node
+   allows us to efficiently update the case vector in response to
+   edge redirections and similar operations. 
+
+   Right now this is only used to set up case label leaders.  In the
+   future we hope to make this table more persistent and use it to
+   more efficiently update case labels.  */
+
+struct edge_to_case_leader_elt
+{
+  /* The edge itself.  Necessary for hashing and equality tests.  */
+  edge e;
+
+  /* The "leader" for all the CASE_LABEL_EXPRs which transfer control
+     to E->dest.  When we change the destination of E, we will need to
+     update the CASE_LEADER_OR_LABEL of this CASE_LABEL_EXPR (and no
+     others).  */
+  tree case_label;
+};
+
+static htab_t edge_to_case_leader;
+
 /* CFG statistics.  */
 struct cfg_stats_d
 {
@@ -92,7 +118,6 @@ static int tree_verify_flow_info (void);
 static void tree_make_forwarder_block (edge);
 static bool thread_jumps (void);
 static bool tree_forwarder_block_p (basic_block);
-static void bsi_commit_edge_inserts_1 (edge e);
 static void tree_cfg2vcg (FILE *);
 
 /* Flowgraph optimization and cleanup.  */
@@ -149,7 +174,7 @@ build_tree_cfg (tree *tp)
   if (found_computed_goto)
     factor_computed_gotos ();
 
-  /* Make sure there is always at least one block, even if its empty.  */
+  /* Make sure there is always at least one block, even if it's empty.  */
   if (n_basic_blocks == 0)
     create_empty_bb (ENTRY_BLOCK_PTR);
 
@@ -375,9 +400,10 @@ create_bb (void *h, void *e, basic_block after)
 
   gcc_assert (!e);
 
-  /* Create and initialize a new basic block.  */
+  /* Create and initialize a new basic block.  Since alloc_block uses
+     ggc_alloc_cleared to allocate a basic block, we do not have to
+     clear the newly allocated basic block here.  */
   bb = alloc_block ();
-  memset (bb, 0, sizeof (*bb));
 
   bb->index = last_basic_block;
   bb->flags = BB_NEW;
@@ -440,7 +466,7 @@ make_edges (void)
 
       /* Finally, if no edges were created above, this is a regular
         basic block that only needs a fallthru edge.  */
-      if (bb->succ == NULL)
+      if (EDGE_COUNT (bb->succs) == 0)
        make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
     }
 
@@ -482,7 +508,7 @@ make_ctrl_stmt_edges (basic_block bb)
     case RESX_EXPR:
       make_eh_edges (last);
       /* Yet another NORETURN hack.  */
-      if (bb->succ == NULL)
+      if (EDGE_COUNT (bb->succs) == 0)
        make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
       break;
 
@@ -575,6 +601,122 @@ make_cond_expr_edges (basic_block bb)
   make_edge (bb, else_bb, EDGE_FALSE_VALUE);
 }
 
+/* Hashing routine for EDGE_TO_CASE_LEADER.  */
+
+static hashval_t
+edge_to_case_leader_hash (const void *p)
+{
+  edge e = ((struct edge_to_case_leader_elt *)p)->e;
+
+  /* Hash on the edge itself (which is a pointer).  */
+  return htab_hash_pointer (e);
+}
+
+/* Equality routine for EDGE_TO_CASE_LEADER, edges are unique, so testing
+   for equality is just a pointer comparison.  */
+
+static int
+edge_to_case_leader_eq (const void *p1, const void *p2)
+{
+  edge e1 = ((struct edge_to_case_leader_elt *)p1)->e;
+  edge e2 = ((struct edge_to_case_leader_elt *)p2)->e;
+
+  return e1 == e2;
+}
+
+/* Record that CASE_LABEL (a CASE_LABEL_EXPR) references edge E.  */
+
+static void
+record_switch_edge (edge e, tree case_label)
+{
+  struct edge_to_case_leader_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_case_leader_elt));
+  elt->e = e;
+  elt->case_label = case_label;
+
+  slot = htab_find_slot (edge_to_case_leader, 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_case_leader_elt *) *slot;
+
+      /* Make ELT->case_label the leader for CASE_LABEL.  */
+      CASE_LEADER_OR_LABEL (case_label) = elt->case_label;
+    }
+}
+
+/* Subroutine of get_case_leader_for_edge; returns the case leader for the
+   chain of CASE_LABEL_EXPRs associated with E using a hash table lookup.  */
+
+static tree
+get_case_leader_for_edge_hash (edge e)
+{
+  struct edge_to_case_leader_elt elt, *elt_p;
+  void **slot;
+
+  elt.e = e;
+  elt.case_label = NULL;
+  slot = htab_find_slot (edge_to_case_leader, &elt, NO_INSERT);
+
+  if (slot)
+    {
+      tree t;
+
+      elt_p = (struct edge_to_case_leader_elt *)*slot;
+      t = elt_p->case_label;
+
+      while (TREE_CODE (CASE_LEADER_OR_LABEL (t)) == CASE_LABEL_EXPR)
+       t = CASE_LEADER_OR_LABEL (t);
+      return t;
+    }
+
+  return NULL;
+}
+
+/* Given an edge E, return the case leader for the chain of CASE_LABEL_EXPRs
+   which use E.  */
+
+static tree
+get_case_leader_for_edge (edge e)
+{
+  tree vec, stmt;
+  size_t i, n;
+
+  /* If we have a hash table, then use it as it's significantly faster.  */
+  if (edge_to_case_leader)
+    return get_case_leader_for_edge_hash (e);
+
+  /* No hash table.  We have to walk the case vector.  */
+  stmt = bsi_stmt (bsi_last (e->src));
+  vec = SWITCH_LABELS (stmt);
+  n = TREE_VEC_LENGTH (vec);
+
+  for (i = 0; i < n; i++)
+    {
+      tree elt = TREE_VEC_ELT (vec, i);
+      tree t = CASE_LEADER_OR_LABEL (elt);
+
+      if (TREE_CODE (t) == LABEL_DECL
+         && label_to_block (t) == e->dest)
+       return elt;
+    }
+
+  abort ();
+}
 
 /* Create the edges for a SWITCH_EXPR starting at block BB.
    At this point, the switch body has been lowered and the
@@ -590,12 +732,22 @@ make_switch_expr_edges (basic_block bb)
   vec = SWITCH_LABELS (entry);
   n = TREE_VEC_LENGTH (vec);
 
+  edge_to_case_leader
+    = htab_create (n, edge_to_case_leader_hash, edge_to_case_leader_eq, free);
+
   for (i = 0; i < n; ++i)
     {
       tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
       basic_block label_bb = label_to_block (lab);
-      make_edge (bb, label_bb, 0);
+      edge e = make_edge (bb, label_bb, 0);
+
+      if (!e)
+       e = find_edge (bb, label_bb);
+
+      record_switch_edge (e, TREE_VEC_ELT (vec, i));
     }
+  htab_delete (edge_to_case_leader);
+  edge_to_case_leader = NULL;
 }
 
 
@@ -606,8 +758,8 @@ label_to_block (tree dest)
 {
   int uid = LABEL_DECL_UID (dest);
 
-  /* We would die hard when faced by undefined label.  Emit label to
-     very first basic block.  This will hopefully make even the dataflow
+  /* We would die hard when faced by an undefined label.  Emit a label to
+     the very first basic block.  This will hopefully make even the dataflow
      and undefined variable warnings quite right.  */
   if ((errorcount || sorrycount) && uid < 0)
     {
@@ -697,7 +849,7 @@ make_goto_expr_edges (basic_block bb)
     }
 
   /* Degenerate case of computed goto with no labels.  */
-  if (!for_call && !bb->succ)
+  if (!for_call && EDGE_COUNT (bb->succs) == 0)
     make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
 }
 
@@ -711,20 +863,22 @@ make_goto_expr_edges (basic_block bb)
 bool
 cleanup_tree_cfg (void)
 {
-  bool something_changed = true;
   bool retval = false;
 
   timevar_push (TV_TREE_CLEANUP_CFG);
 
-  /* These three transformations can cascade, so we iterate on them until
-     nothing changes.  */
-  while (something_changed)
+  retval = cleanup_control_flow ();
+  retval |= delete_unreachable_blocks ();
+  retval |= thread_jumps ();
+
+#ifdef ENABLE_CHECKING
+  if (retval)
     {
-      something_changed = cleanup_control_flow ();
-      something_changed |= delete_unreachable_blocks ();
-      something_changed |= thread_jumps ();
-      retval |= something_changed;
+      gcc_assert (!cleanup_control_flow ());
+      gcc_assert (!delete_unreachable_blocks ());
+      gcc_assert (!thread_jumps ());
     }
+#endif
 
   /* Merging the blocks creates no new opportunities for the other
      optimizations, so do it here.  */
@@ -783,7 +937,7 @@ main_block_label (tree label)
   return label_for_bb[bb->index];
 }
 
-/* Cleanup redundant labels.  This is a three-steo process:
+/* Cleanup redundant labels.  This is a three-step process:
      1) Find the leading label for each block.
      2) Redirect all references to labels to the leading labels.
      3) Cleanup all useless labels.  */
@@ -795,7 +949,7 @@ cleanup_dead_labels (void)
   label_for_bb = xcalloc (last_basic_block, sizeof (tree));
 
   /* Find a suitable label for each block.  We use the first user-defined
-     label is there is one, or otherwise just the first label we see.  */
+     label if there is one, or otherwise just the first label we see.  */
   FOR_EACH_BB (bb)
     {
       block_stmt_iterator i;
@@ -862,9 +1016,11 @@ cleanup_dead_labels (void)
   
            /* Replace all destination labels.  */
            for (i = 0; i < n; ++i)
-             CASE_LABEL (TREE_VEC_ELT (vec, i))
-               = main_block_label (CASE_LABEL (TREE_VEC_ELT (vec, i)));
-  
+             {
+               tree elt = TREE_VEC_ELT (vec, i);
+               tree label = main_block_label (CASE_LABEL (elt));
+               CASE_LEADER_OR_LABEL (elt) = label;
+             }
            break;
          }
 
@@ -934,13 +1090,18 @@ group_case_labels (void)
          tree labels = SWITCH_LABELS (stmt);
          int old_size = TREE_VEC_LENGTH (labels);
          int i, j, new_size = old_size;
-         tree default_label = TREE_VEC_ELT (labels, old_size - 1);
+         tree default_case = TREE_VEC_ELT (labels, old_size - 1);
+         tree default_label;
+
+         /* The default label is always the last case in a switch
+            statement after gimplification.  */
+         default_label = CASE_LABEL (default_case);
 
          /* Look for possible opportunities to merge cases.
             Ignore the last element of the label vector because it
             must be the default case.  */
           i = 0;
-         while (i < old_size - 2)
+         while (i < old_size - 1)
            {
              tree base_case, base_label, base_high, type;
              base_case = TREE_VEC_ELT (labels, i);
@@ -954,19 +1115,20 @@ group_case_labels (void)
                {
                  TREE_VEC_ELT (labels, i) = NULL_TREE;
                  i++;
+                 new_size--;
                  continue;
                }
 
              type = TREE_TYPE (CASE_LOW (base_case));
              base_high = CASE_HIGH (base_case) ?
                CASE_HIGH (base_case) : CASE_LOW (base_case);
-
+             i++;
              /* Try to merge case labels.  Break out when we reach the end
                 of the label vector or when we cannot merge the next case
                 label with the current one.  */
-             while (i < old_size - 2)
+             while (i < old_size - 1)
                {
-                 tree merge_case = TREE_VEC_ELT (labels, ++i);
+                 tree merge_case = TREE_VEC_ELT (labels, i);
                  tree merge_label = CASE_LABEL (merge_case);
                  tree t = int_const_binop (PLUS_EXPR, base_high,
                                            integer_one_node, 1);
@@ -981,6 +1143,7 @@ group_case_labels (void)
                      CASE_HIGH (base_case) = base_high;
                      TREE_VEC_ELT (labels, i) = NULL_TREE;
                      new_size--;
+                     i++;
                    }
                  else
                    break;
@@ -1008,20 +1171,19 @@ tree_can_merge_blocks_p (basic_block a, basic_block b)
   tree stmt;
   block_stmt_iterator bsi;
 
-  if (!a->succ
-      || a->succ->succ_next)
+  if (EDGE_COUNT (a->succs) != 1)
     return false;
 
-  if (a->succ->flags & EDGE_ABNORMAL)
+  if (EDGE_SUCC (a, 0)->flags & EDGE_ABNORMAL)
     return false;
 
-  if (a->succ->dest != b)
+  if (EDGE_SUCC (a, 0)->dest != b)
     return false;
 
   if (b == EXIT_BLOCK_PTR)
     return false;
   
-  if (b->pred->pred_next)
+  if (EDGE_COUNT (b->preds) > 1)
     return false;
 
   /* If A ends by a statement causing exceptions or something similar, we
@@ -1068,7 +1230,7 @@ tree_merge_blocks (basic_block a, basic_block b)
   /* Ensure that B follows A.  */
   move_block_after (b, a);
 
-  gcc_assert (a->succ->flags & EDGE_FALLTHRU);
+  gcc_assert (EDGE_SUCC (a, 0)->flags & EDGE_FALLTHRU);
   gcc_assert (!last_stmt (a) || !stmt_ends_bb_p (last_stmt (a)));
 
   /* Remove labels from B and set bb_for_stmt to A for other statements.  */
@@ -1192,7 +1354,6 @@ remove_useless_stmts_cond (tree *stmt_p, struct rus_data *data)
   else_has_label = data->has_label;
   data->has_label = save_has_label | then_has_label | else_has_label;
 
-  fold_stmt (stmt_p);
   then_clause = COND_EXPR_THEN (*stmt_p);
   else_clause = COND_EXPR_ELSE (*stmt_p);
   cond = COND_EXPR_COND (*stmt_p);
@@ -1592,7 +1753,7 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
          }
       }
       break;
-    case SWITCH_EXPR:
+    case ASM_EXPR:
       fold_stmt (tp);
       data->last_goto = NULL;
       break;
@@ -1649,17 +1810,16 @@ cfg_remove_useless_stmts_bb (basic_block bb)
 
   /* Check whether we come here from a condition, and if so, get the
      condition.  */
-  if (!bb->pred
-      || bb->pred->pred_next
-      || !(bb->pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
+  if (EDGE_COUNT (bb->preds) != 1
+      || !(EDGE_PRED (bb, 0)->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
     return;
 
-  cond = COND_EXPR_COND (last_stmt (bb->pred->src));
+  cond = COND_EXPR_COND (last_stmt (EDGE_PRED (bb, 0)->src));
 
   if (TREE_CODE (cond) == VAR_DECL || TREE_CODE (cond) == PARM_DECL)
     {
       var = cond;
-      val = (bb->pred->flags & EDGE_FALSE_VALUE
+      val = (EDGE_PRED (bb, 0)->flags & EDGE_FALSE_VALUE
             ? boolean_false_node : boolean_true_node);
     }
   else if (TREE_CODE (cond) == TRUTH_NOT_EXPR
@@ -1667,12 +1827,12 @@ cfg_remove_useless_stmts_bb (basic_block bb)
               || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL))
     {
       var = TREE_OPERAND (cond, 0);
-      val = (bb->pred->flags & EDGE_FALSE_VALUE
+      val = (EDGE_PRED (bb, 0)->flags & EDGE_FALSE_VALUE
             ? boolean_true_node : boolean_false_node);
     }
   else
     {
-      if (bb->pred->flags & EDGE_FALSE_VALUE)
+      if (EDGE_PRED (bb, 0)->flags & EDGE_FALSE_VALUE)
        cond = invert_truthvalue (cond);
       if (TREE_CODE (cond) == EQ_EXPR
          && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL
@@ -1775,8 +1935,8 @@ remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
     }
 
   /* Remove edges to BB's successors.  */
-  while (bb->succ != NULL)
-    ssa_remove_edge (bb->succ);
+  while (EDGE_COUNT (bb->succs) > 0)
+    ssa_remove_edge (EDGE_SUCC (bb, 0));
 }
 
 
@@ -1799,11 +1959,25 @@ remove_bb (basic_block bb)
     }
 
   /* Remove all the instructions in the block.  */
-  for (i = bsi_start (bb); !bsi_end_p (i); bsi_remove (&i))
+  for (i = bsi_start (bb); !bsi_end_p (i);)
     {
       tree stmt = bsi_stmt (i);
+      if (TREE_CODE (stmt) == LABEL_EXPR
+          && FORCED_LABEL (LABEL_EXPR_LABEL (stmt)))
+       {
+         basic_block new_bb = bb->prev_bb;
+         block_stmt_iterator new_bsi = bsi_after_labels (new_bb);
+                 
+         bsi_remove (&i);
+         bsi_insert_after (&new_bsi, stmt, BSI_NEW_STMT);
+       }
+      else
+        {
+         release_defs (stmt);
 
-      set_bb_for_stmt (stmt, NULL);
+         set_bb_for_stmt (stmt, NULL);
+         bsi_remove (&i);
+       }
 
       /* Don't warn for removed gotos.  Gotos are often removed due to
         jump threading, thus resulting in bogus warnings.  Not great,
@@ -1831,70 +2005,6 @@ remove_bb (basic_block bb)
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
 }
 
-
-/* Examine BB to determine if it is a forwarding block (a block which only
-   transfers control to a new destination).  If BB is a forwarding block,
-   then return the edge leading to the ultimate destination.  */
-
-edge
-tree_block_forwards_to (basic_block bb)
-{
-  block_stmt_iterator bsi;
-  bb_ann_t ann = bb_ann (bb);
-  tree stmt;
-
-  /* If this block is not forwardable, then avoid useless work.  */
-  if (! ann->forwardable)
-    return NULL;
-
-  /* Set this block to not be forwardable.  This prevents infinite loops since
-     any block currently under examination is considered non-forwardable.  */
-  ann->forwardable = 0;
-
-  /* No forwarding is possible if this block is a special block (ENTRY/EXIT),
-     this block has more than one successor, this block's single successor is
-     reached via an abnormal edge, this block has phi nodes, or this block's
-     single successor has phi nodes.  */
-  if (bb == EXIT_BLOCK_PTR
-      || bb == ENTRY_BLOCK_PTR
-      || !bb->succ
-      || bb->succ->succ_next
-      || bb->succ->dest == EXIT_BLOCK_PTR
-      || (bb->succ->flags & EDGE_ABNORMAL) != 0
-      || phi_nodes (bb)
-      || phi_nodes (bb->succ->dest))
-    return NULL;
-
-  /* Walk past any labels at the start of this block.  */
-  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-    {
-      stmt = bsi_stmt (bsi);
-      if (TREE_CODE (stmt) != LABEL_EXPR)
-       break;
-    }
-
-  /* If we reached the end of this block we may be able to optimize this
-     case.  */
-  if (bsi_end_p (bsi))
-    {
-      edge dest;
-
-      /* Recursive call to pick up chains of forwarding blocks.  */
-      dest = tree_block_forwards_to (bb->succ->dest);
-
-      /* If none found, we forward to bb->succ at minimum.  */
-      if (!dest)
-       dest = bb->succ;
-
-      ann->forwardable = 1;
-      return dest;
-    }
-
-  /* No forwarding possible.  */
-  return NULL;
-}
-
-
 /* Try to remove superfluous control structures.  */
 
 static bool
@@ -1931,9 +2041,10 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
   bool retval = false;
   tree expr = bsi_stmt (bsi), val;
 
-  if (bb->succ->succ_next)
+  if (EDGE_COUNT (bb->succs) > 1)
     {
-      edge e, next;
+      edge e;
+      edge_iterator ei;
 
       switch (TREE_CODE (expr))
        {
@@ -1956,9 +2067,8 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
        return false;
 
       /* Remove all the edges except the one that is always executed.  */
-      for (e = bb->succ; e; e = next)
+      for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
        {
-         next = e->succ_next;
          if (e != taken_edge)
            {
              taken_edge->probability += e->probability;
@@ -1966,27 +2076,28 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
              ssa_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 = bb->succ;
+    taken_edge = EDGE_SUCC (bb, 0);
 
   bsi_remove (&bsi);
   taken_edge->flags = EDGE_FALLTHRU;
 
   /* We removed some paths from the cfg.  */
-  if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
-    dom_computed[CDI_DOMINATORS] = DOM_CONS_OK;
+  free_dominance_info (CDI_DOMINATORS);
 
   return retval;
 }
 
 
-/* Given a control block BB and a predicate VAL, return the edge that
-   will be taken out of the block.  If VAL does not match a unique
-   edge, NULL is returned.  */
+/* 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.
+   If VAL does not match a unique edge, NULL is returned.  */
 
 edge
 find_taken_edge (basic_block bb, tree val)
@@ -1997,28 +2108,16 @@ find_taken_edge (basic_block bb, tree val)
 
   gcc_assert (stmt);
   gcc_assert (is_ctrl_stmt (stmt));
+  gcc_assert (val);
 
   /* If VAL is a predicate of the form N RELOP N, where N is an
-     SSA_NAME, we can always determine its truth value (except when
-     doing floating point comparisons that may involve NaNs).  */
-  if (val
-      && TREE_CODE_CLASS (TREE_CODE (val)) == '<'
-      && TREE_OPERAND (val, 0) == TREE_OPERAND (val, 1)
-      && TREE_CODE (TREE_OPERAND (val, 0)) == SSA_NAME
-      && (TREE_CODE (TREE_TYPE (TREE_OPERAND (val, 0))) != REAL_TYPE
-         || !HONOR_NANS (TYPE_MODE (TREE_TYPE (TREE_OPERAND (val, 0))))))
-    {
-      enum tree_code code = TREE_CODE (val);
-
-      if (code == EQ_EXPR || code == LE_EXPR || code == GE_EXPR)
-       val = boolean_true_node;
-      else if (code == LT_EXPR || code == GT_EXPR || code == NE_EXPR)
-       val = boolean_false_node;
-    }
+     SSA_NAME, we can usually determine its truth value.  */
+  if (COMPARISON_CLASS_P (val))
+    val = fold (val);
 
   /* If VAL is not a constant, we can't determine which edge might
      be taken.  */
-  if (val == NULL || !really_constant_p (val))
+  if (!really_constant_p (val))
     return NULL;
 
   if (TREE_CODE (stmt) == COND_EXPR)
@@ -2027,7 +2126,7 @@ find_taken_edge (basic_block bb, tree val)
   if (TREE_CODE (stmt) == SWITCH_EXPR)
     return find_taken_edge_switch_expr (bb, val);
 
-  return bb->succ;
+  gcc_unreachable ();
 }
 
 
@@ -2042,11 +2141,6 @@ find_taken_edge_cond_expr (basic_block bb, tree val)
 
   extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
-  /* If both edges of the branch lead to the same basic block, it doesn't
-     matter which edge is taken.  */
-  if (true_edge->dest == false_edge->dest)
-    return true_edge;
-
   /* Otherwise, try to determine which branch of the if() will be taken.
      If VAL is a constant but it can't be reduced to a 0 or a 1, then
      we don't really know which edge will be taken at runtime.  This
@@ -2259,11 +2353,7 @@ dump_cfg_stats (FILE *file)
 
   n_edges = 0;
   FOR_EACH_BB (bb)
-    {
-      edge e;
-      for (e = bb->succ; e; e = e->succ_next)
-       n_edges++;
-    }
+    n_edges += EDGE_COUNT (bb->succs);
   size = n_edges * sizeof (struct edge_def);
   total += size;
   fprintf (file, fmt_str_1, "Edges", n_edges, SCALE (size), LABEL (size));
@@ -2305,6 +2395,7 @@ static void
 tree_cfg2vcg (FILE *file)
 {
   edge e;
+  edge_iterator ei;
   basic_block bb;
   const char *funcname
     = lang_hooks.decl_printable_name (current_function_decl, 2);
@@ -2315,7 +2406,7 @@ tree_cfg2vcg (FILE *file)
   fprintf (file, "node: { title: \"EXIT\" label: \"EXIT\" }\n");
 
   /* Write blocks and edges.  */
-  for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
     {
       fprintf (file, "edge: { sourcename: \"ENTRY\" targetname: \"%d\"",
               e->dest->index);
@@ -2360,7 +2451,7 @@ tree_cfg2vcg (FILE *file)
               bb->index, bb->index, head_name, head_line, end_name,
               end_line);
 
-      for (e = bb->succ; e; e = e->succ_next)
+      FOR_EACH_EDGE (e, ei, bb->succs)
        {
          if (e->dest == EXIT_BLOCK_PTR)
            fprintf (file, "edge: { sourcename: \"%d\" targetname: \"EXIT\"", bb->index);
@@ -2508,6 +2599,7 @@ disband_implicit_edges (void)
   basic_block bb;
   block_stmt_iterator last;
   edge e;
+  edge_iterator ei;
   tree stmt, label;
 
   FOR_EACH_BB (bb)
@@ -2521,7 +2613,7 @@ disband_implicit_edges (void)
             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.  */
-         for (e = bb->succ; e; e = e->succ_next)
+         FOR_EACH_EDGE (e, ei, bb->succs)
            {
              if (e->dest != bb->next_bb)
                continue;
@@ -2542,15 +2634,14 @@ disband_implicit_edges (void)
        {
          /* Remove the RETURN_EXPR if we may fall though to the exit
             instead.  */
-         gcc_assert (bb->succ);
-         gcc_assert (!bb->succ->succ_next);
-         gcc_assert (bb->succ->dest == EXIT_BLOCK_PTR);
+         gcc_assert (EDGE_COUNT (bb->succs) == 1);
+         gcc_assert (EDGE_SUCC (bb, 0)->dest == EXIT_BLOCK_PTR);
 
          if (bb->next_bb == EXIT_BLOCK_PTR
              && !TREE_OPERAND (stmt, 0))
            {
              bsi_remove (&last);
-             bb->succ->flags |= EDGE_FALLTHRU;
+             EDGE_SUCC (bb, 0)->flags |= EDGE_FALLTHRU;
            }
          continue;
        }
@@ -2561,7 +2652,7 @@ disband_implicit_edges (void)
        continue;
 
       /* Find a fallthru edge and emit the goto if necessary.  */
-      for (e = bb->succ; e; e = e->succ_next)
+      FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->flags & EDGE_FALLTHRU)
          break;
 
@@ -2666,7 +2757,9 @@ last_and_only_stmt (basic_block bb)
 void
 set_bb_for_stmt (tree t, basic_block bb)
 {
-  if (TREE_CODE (t) == STATEMENT_LIST)
+  if (TREE_CODE (t) == PHI_NODE)
+    PHI_BB (t) = bb;
+  else if (TREE_CODE (t) == STATEMENT_LIST)
     {
       tree_stmt_iterator i;
       for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
@@ -2703,7 +2796,7 @@ set_bb_for_stmt (tree t, basic_block bb)
 /* Finds iterator for STMT.  */
 
 extern block_stmt_iterator
-stmt_for_bsi (tree stmt)
+bsi_for_stmt (tree stmt)
 {
   block_stmt_iterator bsi;
 
@@ -2841,9 +2934,9 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
 
      The requirement for no PHI nodes could be relaxed.  Basically we
      would have to examine the PHIs to prove that none of them used
-     the value set by the statement we want to insert on E.   That
+     the value set by the statement we want to insert on E.  That
      hardly seems worth the effort.  */
-  if (dest->pred->pred_next == NULL
+  if (EDGE_COUNT (dest->preds) == 1
       && ! phi_nodes (dest)
       && dest != EXIT_BLOCK_PTR)
     {
@@ -2875,7 +2968,7 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
      Except for the entry block.  */
   src = e->src;
   if ((e->flags & EDGE_ABNORMAL) == 0
-      && src->succ->succ_next == NULL
+      && EDGE_COUNT (src->succs) == 1
       && src != ENTRY_BLOCK_PTR)
     {
       *bsi = bsi_last (src);
@@ -2906,42 +2999,37 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
   dest = split_edge (e);
   if (new_bb)
     *new_bb = dest;
-  e = dest->pred;
+  e = EDGE_PRED (dest, 0);
   goto restart;
 }
 
 
 /* This routine will commit all pending edge insertions, creating any new
-   basic blocks which are necessary.
-
-   If specified, NEW_BLOCKS returns a count of the number of new basic
-   blocks which were created.  */
+   basic blocks which are necessary.  */
 
 void
-bsi_commit_edge_inserts (int *new_blocks)
+bsi_commit_edge_inserts (void)
 {
   basic_block bb;
   edge e;
-  int blocks;
-
-  blocks = n_basic_blocks;
+  edge_iterator ei;
 
-  bsi_commit_edge_inserts_1 (ENTRY_BLOCK_PTR->succ);
+  bsi_commit_one_edge_insert (EDGE_SUCC (ENTRY_BLOCK_PTR, 0), NULL);
 
   FOR_EACH_BB (bb)
-    for (e = bb->succ; e; e = e->succ_next)
-      bsi_commit_edge_inserts_1 (e);
-
-  if (new_blocks)
-    *new_blocks = n_basic_blocks - blocks;
+    FOR_EACH_EDGE (e, ei, bb->succs)
+      bsi_commit_one_edge_insert (e, NULL);
 }
 
 
-/* Commit insertions pending at edge E.  */
+/* Commit insertions pending at edge E. If a new block is created, set NEW_BB
+   to this block, otherwise set it to NULL.  */
 
-static void
-bsi_commit_edge_inserts_1 (edge e)
+void
+bsi_commit_one_edge_insert (edge e, basic_block *new_bb)
 {
+  if (new_bb)
+    *new_bb = NULL;
   if (PENDING_STMT (e))
     {
       block_stmt_iterator bsi;
@@ -2949,7 +3037,7 @@ bsi_commit_edge_inserts_1 (edge e)
 
       PENDING_STMT (e) = NULL_TREE;
 
-      if (tree_find_edge_insert_loc (e, &bsi, NULL))
+      if (tree_find_edge_insert_loc (e, &bsi, new_bb))
        bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
       else
        bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
@@ -2999,6 +3087,7 @@ tree_split_edge (edge edge_in)
   edge new_edge, e;
   tree phi;
   int i, num_elem;
+  edge_iterator ei;
 
   /* Abnormal edges cannot be split.  */
   gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
@@ -3009,7 +3098,7 @@ tree_split_edge (edge edge_in)
   /* 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.  */
-  for (e = dest->pred; e; e = e->pred_next)
+  FOR_EACH_EDGE (e, ei, dest->preds)
     if (e->src->next_bb == dest)
       break;
   if (!e)
@@ -3018,7 +3107,11 @@ tree_split_edge (edge edge_in)
     after_bb = edge_in->src;
 
   new_bb = create_empty_bb (after_bb);
+  new_bb->frequency = EDGE_FREQUENCY (edge_in);
+  new_bb->count = edge_in->count;
   new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
+  new_edge->probability = REG_BR_PROB_BASE;
+  new_edge->count = edge_in->count;
 
   /* Find all the PHI arguments on the original edge, and change them to
      the new edge.  Do it before redirection, so that the argument does not
@@ -3077,8 +3170,8 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
      We check for constants explicitly since they are not considered
      gimple invariants if they overflowed.  */
 #define CHECK_OP(N, MSG) \
-  do { if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, N))) != 'c'    \
-         && !is_gimple_val (TREE_OPERAND (t, N)))                      \
+  do { if (!CONSTANT_CLASS_P (TREE_OPERAND (t, N))             \
+         && !is_gimple_val (TREE_OPERAND (t, N)))              \
        { error (MSG); return TREE_OPERAND (t, N); }} while (0)
 
   switch (TREE_CODE (t))
@@ -3122,7 +3215,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       break;
 
     case COND_EXPR:
-      x = TREE_OPERAND (t, 0);
+      x = COND_EXPR_COND (t);
       if (TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE)
        {
          error ("non-boolean used in condition");
@@ -3179,8 +3272,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
          t = TREE_OPERAND (t, 0);
        }
 
-      if (TREE_CODE_CLASS (TREE_CODE (t)) != 'c'
-         && !is_gimple_lvalue (t))
+      if (!CONSTANT_CLASS_P (t) && !is_gimple_lvalue (t))
        {
          error ("Invalid reference prefix.");
          return t;
@@ -3267,7 +3359,7 @@ 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))
@@ -3290,18 +3382,21 @@ verify_stmt (tree stmt, bool last_in_block)
 static bool
 tree_node_can_be_shared (tree t)
 {
-  if (TYPE_P (t) || DECL_P (t)
+  if (IS_TYPE_OR_DECL_P (t)
       /* We check for constants explicitly since they are not considered
         gimple invariants if they overflowed.  */
-      || TREE_CODE_CLASS (TREE_CODE (t)) == 'c'
+      || CONSTANT_CLASS_P (t)
       || is_gimple_min_invariant (t)
       || TREE_CODE (t) == SSA_NAME)
     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.  */
-         && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
+         && (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
@@ -3430,6 +3525,7 @@ tree_verify_flow_info (void)
   block_stmt_iterator bsi;
   tree stmt;
   edge e;
+  edge_iterator ei;
 
   if (ENTRY_BLOCK_PTR->stmt_list)
     {
@@ -3443,7 +3539,7 @@ tree_verify_flow_info (void)
       err = 1;
     }
 
-  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+  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);
@@ -3462,8 +3558,9 @@ tree_verify_flow_info (void)
 
          if (label_to_block (LABEL_EXPR_LABEL (bsi_stmt (bsi))) != bb)
            {
+             tree stmt = bsi_stmt (bsi);
              error ("Label %s to block does not match in bb %d\n",
-                    IDENTIFIER_POINTER (DECL_NAME (bsi_stmt (bsi))),
+                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
                     bb->index);
              err = 1;
            }
@@ -3471,8 +3568,9 @@ tree_verify_flow_info (void)
          if (decl_function_context (LABEL_EXPR_LABEL (bsi_stmt (bsi)))
              != current_function_decl)
            {
+             tree stmt = bsi_stmt (bsi);
              error ("Label %s has incorrect context in bb %d\n",
-                    IDENTIFIER_POINTER (DECL_NAME (bsi_stmt (bsi))),
+                    IDENTIFIER_POINTER (DECL_NAME (LABEL_EXPR_LABEL (stmt))),
                     bb->index);
              err = 1;
            }
@@ -3509,7 +3607,7 @@ tree_verify_flow_info (void)
 
       if (is_ctrl_stmt (stmt))
        {
-         for (e = bb->succ; e; e = e->succ_next)
+         FOR_EACH_EDGE (e, ei, bb->succs)
            if (e->flags & EDGE_FALLTHRU)
              {
                error ("Fallthru edge after a control statement in bb %d \n",
@@ -3538,7 +3636,7 @@ tree_verify_flow_info (void)
                || !(false_edge->flags & EDGE_FALSE_VALUE)
                || (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
                || (false_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
-               || bb->succ->succ_next->succ_next)
+               || EDGE_COUNT (bb->succs) >= 3)
              {
                error ("Wrong outgoing edge flags at end of bb %d\n",
                       bb->index);
@@ -3548,7 +3646,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\n",
                       bb->index);
                err = 1;
              }
@@ -3556,7 +3654,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\n",
                       bb->index);
                err = 1;
              }
@@ -3573,7 +3671,7 @@ tree_verify_flow_info (void)
            {
              /* FIXME.  We should double check that the labels in the 
                 destination blocks have their address taken.  */
-             for (e = bb->succ; e; e = e->succ_next)
+             FOR_EACH_EDGE (e, ei, bb->succs)
                if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE
                                 | EDGE_FALSE_VALUE))
                    || !(e->flags & EDGE_ABNORMAL))
@@ -3586,14 +3684,14 @@ tree_verify_flow_info (void)
          break;
 
        case RETURN_EXPR:
-         if (!bb->succ || bb->succ->succ_next
-             || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
+         if (EDGE_COUNT (bb->succs) != 1
+             || (EDGE_SUCC (bb, 0)->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
                                     | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
            {
              error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
              err = 1;
            }
-         if (bb->succ->dest != EXIT_BLOCK_PTR)
+         if (EDGE_SUCC (bb, 0)->dest != EXIT_BLOCK_PTR)
            {
              error ("Return edge does not point to exit in bb %d\n",
                     bb->index);
@@ -3649,7 +3747,7 @@ tree_verify_flow_info (void)
                err = 1;
              }
 
-           for (e = bb->succ; e; e = e->succ_next)
+           FOR_EACH_EDGE (e, ei, bb->succs)
              {
                if (!e->dest->aux)
                  {
@@ -3681,7 +3779,7 @@ tree_verify_flow_info (void)
                  }
              }
 
-           for (e = bb->succ; e; e = e->succ_next)
+           FOR_EACH_EDGE (e, ei, bb->succs)
              e->dest->aux = (void *)0;
          }
 
@@ -3696,20 +3794,21 @@ tree_verify_flow_info (void)
 }
 
 
-/* Updates phi nodes after creating forwarder block joined
+/* Updates phi nodes after creating forwarder block joined
    by edge FALLTHRU.  */
 
 static void
 tree_make_forwarder_block (edge fallthru)
 {
   edge e;
+  edge_iterator ei;
   basic_block dummy, bb;
-  tree phi, new_phi, var, prev, next;
+  tree phi, new_phi, var;
 
   dummy = fallthru->src;
   bb = fallthru->dest;
 
-  if (!bb->pred->pred_next)
+  if (EDGE_COUNT (bb->preds) == 1)
     return;
 
   /* If we redirected a branch we must create new phi nodes at the
@@ -3724,74 +3823,53 @@ tree_make_forwarder_block (edge fallthru)
     }
 
   /* Ensure that the PHI node chain is in the same order.  */
-  prev = NULL;
-  for (phi = phi_nodes (bb); phi; phi = next)
-    {
-      next = PHI_CHAIN (phi);
-      PHI_CHAIN (phi) = prev;
-      prev = phi;
-    }
-  set_phi_nodes (bb, prev);
+  set_phi_nodes (bb, phi_reverse (phi_nodes (bb)));
 
   /* Add the arguments we have stored on edges.  */
-  for (e = bb->pred; e; e = e->pred_next)
+  FOR_EACH_EDGE (e, ei, bb->preds)
     {
       if (e == fallthru)
        continue;
 
-      for (phi = phi_nodes (bb), var = PENDING_STMT (e);
-          phi;
-          phi = PHI_CHAIN (phi), var = TREE_CHAIN (var))
-       add_phi_arg (&phi, TREE_VALUE (var), e);
-
-      PENDING_STMT (e) = NULL;
+      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.  */
+   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)
 {
   block_stmt_iterator bsi;
   edge e;
+  edge_iterator ei;
 
-  /* If we have already determined that this block is not forwardable,
-     then no further checks are necessary.  */
-  if (! bb_ann (bb)->forwardable)
-    return false;
-
-  /* BB must have a single outgoing normal edge.  Otherwise it can not be
-     a forwarder block.  */
-  if (!bb->succ
-      || bb->succ->succ_next
-      || bb->succ->dest == EXIT_BLOCK_PTR
-      || (bb->succ->flags & EDGE_ABNORMAL)
-      || bb == ENTRY_BLOCK_PTR)
-    {
-      bb_ann (bb)->forwardable = 0;
-      return false; 
-    }
+  /* BB must have a single outgoing edge.  */
+  if (EDGE_COUNT (bb->succs) != 1
+      /* BB can not have any PHI nodes.  This could potentially be
+        relaxed early in compilation if we re-rewrote the variables
+        appearing in any PHI nodes in forwarder blocks.  */
+      || phi_nodes (bb)
+      /* BB may not be a predecessor of EXIT_BLOCK_PTR.  */
+      || EDGE_SUCC (bb, 0)->dest == EXIT_BLOCK_PTR
+      /* BB may not have an abnormal outgoing edge.  */
+      || (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL))
+    return false; 
+
+#if ENABLE_CHECKING
+  gcc_assert (bb != ENTRY_BLOCK_PTR);
+#endif
 
   /* Successors of the entry block are not forwarders.  */
-  for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
     if (e->dest == bb)
-      {
-       bb_ann (bb)->forwardable = 0;
-       return false;
-      }
-
-  /* BB can not have any PHI nodes.  This could potentially be relaxed
-     early in compilation if we re-rewrote the variables appearing in
-     any PHI nodes in forwarder blocks.  */
-  if (phi_nodes (bb))
-    {
-      bb_ann (bb)->forwardable = 0;
-      return false; 
-    }
+      return false;
 
   /* Now walk through the statements.  We can ignore labels, anything else
      means this is not a forwarder block.  */
@@ -3807,7 +3885,6 @@ tree_forwarder_block_p (basic_block bb)
          break;
 
        default:
-         bb_ann (bb)->forwardable = 0;
          return false;
        }
     }
@@ -3815,168 +3892,277 @@ tree_forwarder_block_p (basic_block bb)
   return true;
 }
 
+/* Thread jumps from BB.  */
 
-/* Thread jumps over empty statements.
-
-   This code should _not_ thread over obviously equivalent conditions
-   as that requires nontrivial updates to the SSA graph.  */
-   
 static bool
-thread_jumps (void)
+thread_jumps_from_bb (basic_block bb)
 {
-  edge e, next, last, old;
-  basic_block bb, dest, tmp, old_dest, dom;
-  tree phi;
-  int arg;
+  edge_iterator ei;
+  edge e;
   bool retval = false;
 
-  FOR_EACH_BB (bb)
-    bb_ann (bb)->forwardable = 1;
-
-  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
+  /* Examine each of our block's successors to see if it is
+     forwardable.  */
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      /* Don't waste time on unreachable blocks.  */
-      if (!bb->pred)
-       continue;
+      int freq;
+      gcov_type count;
+      edge last, old;
+      basic_block dest, tmp, curr, old_dest;
+      tree phi;
+      int arg;
 
-      /* Nor on forwarders.  */
-      if (tree_forwarder_block_p (bb))
-       continue;
-      
-      /* This block is now part of a forwarding path, mark it as not
-        forwardable so that we can detect loops.  This bit will be
-        reset below.  */
-      bb_ann (bb)->forwardable = 0;
-
-      /* Examine each of our block's successors to see if it is
-        forwardable.  */
-      for (e = bb->succ; e; e = next)
+      /* If the edge is abnormal or its destination is not
+        forwardable, then there's nothing to do.  */
+      if ((e->flags & EDGE_ABNORMAL)
+         || !bb_ann (e->dest)->forwardable)
        {
-         next = e->succ_next;
-
-         /* If the edge is abnormal or its destination is not
-            forwardable, then there's nothing to do.  */
-         if ((e->flags & EDGE_ABNORMAL)
-             || !tree_forwarder_block_p (e->dest))
-           continue;
-
-         /* Now walk through as many forwarder block as possible to
-            find the ultimate destination we want to thread our jump
-            to.  */
-         last = e->dest->succ;
-         bb_ann (e->dest)->forwardable = 0;
-         for (dest = e->dest->succ->dest;
-              tree_forwarder_block_p (dest);
-              last = dest->succ,
-              dest = dest->succ->dest)
-           {
-             /* An infinite loop detected.  We redirect the edge anyway, so
-                that the loop is shrunk into single basic block.  */
-             if (!bb_ann (dest)->forwardable)
-               break;
-
-             if (dest->succ->dest == EXIT_BLOCK_PTR)
-               break;
+         ei_next (&ei);
+         continue;
+       }
 
-             bb_ann (dest)->forwardable = 0;
-           }
+      /* Now walk through as many forwarder blocks as possible to find
+        the ultimate destination we want to thread our jump to.  */
+      last = EDGE_SUCC (e->dest, 0);
+      bb_ann (e->dest)->forwardable = 0;
+      for (dest = EDGE_SUCC (e->dest, 0)->dest;
+          bb_ann (dest)->forwardable;
+          last = EDGE_SUCC (dest, 0),
+            dest = EDGE_SUCC (dest, 0)->dest)
+       bb_ann (dest)->forwardable = 0;
+
+      /* Reset the forwardable marks to 1.  */
+      for (tmp = e->dest;
+          tmp != dest;
+          tmp = EDGE_SUCC (tmp, 0)->dest)
+       bb_ann (tmp)->forwardable = 1;
+
+      if (dest == e->dest)
+       {
+         ei_next (&ei);
+         continue;
+       }
 
-         /* Reset the forwardable marks to 1.  */
-         for (tmp = e->dest;
-              tmp != dest;
-              tmp = tmp->succ->dest)
-           bb_ann (tmp)->forwardable = 1;
-
-         if (dest == e->dest)
-           continue;
-             
-         old = find_edge (bb, dest);
-         if (old)
+      old = find_edge (bb, dest);
+      if (old)
+       {
+         /* If there already is an edge, check whether the values in
+            phi nodes differ.  */
+         if (!phi_alternatives_equal (dest, last, old))
            {
-             /* If there already is an edge, check whether the values
-                in phi nodes differ.  */
-             if (!phi_alternatives_equal (dest, last, old))
+             /* The previous block is forwarder.  Redirect our jump
+                to that target instead since we know it has no PHI
+                nodes that will need updating.  */
+             dest = last->src;
+
+             /* That might mean that no forwarding at all is
+                possible.  */
+             if (dest == e->dest)
                {
-                 /* The previous block is forwarder.  Redirect our jump
-                    to that target instead since we know it has no PHI
-                    nodes that will need updating.  */
-                 dest = last->src;
-         
-                 /* That might mean that no forwarding at all is possible.  */
-                 if (dest == e->dest)
-                   continue;
-
-                 old = find_edge (bb, dest);
+                 ei_next (&ei);
+                 continue;
                }
+
+             old = find_edge (bb, dest);
            }
+       }
 
-         /* Perform the redirection.  */
-         retval = true;
-         old_dest = e->dest;
-         e = redirect_edge_and_branch (e, dest);
+      /* Perform the redirection.  */
+      retval = true;
+      count = e->count;
+      freq = EDGE_FREQUENCY (e);
+      old_dest = e->dest;
+      e = redirect_edge_and_branch (e, dest);
+
+      /* Update the profile.  */
+      if (profile_status != PROFILE_ABSENT)
+       for (curr = old_dest;
+            curr != dest;
+            curr = EDGE_SUCC (curr, 0)->dest)
+         {
+           curr->frequency -= freq;
+           if (curr->frequency < 0)
+             curr->frequency = 0;
+           curr->count -= count;
+           if (curr->count < 0)
+             curr->count = 0;
+           EDGE_SUCC (curr, 0)->count -= count;
+           if (EDGE_SUCC (curr, 0)->count < 0)
+             EDGE_SUCC (curr, 0)->count = 0;
+         }
+
+      if (!old)
+       {
+         /* Update PHI nodes.  We know that the new argument should
+            have the same value as the argument associated with LAST.
+            Otherwise we would have changed our target block
+            above.  */
+         for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
+           {
+             arg = phi_arg_from_edge (phi, last);
+             gcc_assert (arg >= 0);
+             add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e);
+           }
+       }
+
+      /* Remove the unreachable blocks (observe that if all blocks
+        were reachable before, only those in the path we threaded
+        over and did not have any predecessor outside of the path
+        become unreachable).  */
+      for (; old_dest != dest; old_dest = tmp)
+       {
+         tmp = EDGE_SUCC (old_dest, 0)->dest;
+
+         if (EDGE_COUNT (old_dest->preds) > 0)
+           break;
 
-         if (!old)
+         delete_basic_block (old_dest);
+       }
+
+      /* Update the dominators.  */
+      if (dom_info_available_p (CDI_DOMINATORS))
+       {
+         /* If the dominator of the destination was in the
+            path, set its dominator to the start of the
+            redirected edge.  */
+         if (get_immediate_dominator (CDI_DOMINATORS, old_dest) == NULL)
+           set_immediate_dominator (CDI_DOMINATORS, old_dest, bb);
+
+         /* Now proceed like if we forwarded just over one edge at a
+            time.  Algorithm for forwarding edge S --> A over
+            edge A --> B then is
+
+            if (idom (B) == A
+                && !dominated_by (S, B))
+              idom (B) = idom (A);
+            recount_idom (A);  */
+
+         for (; old_dest != dest; old_dest = tmp)
            {
-             /* Update PHI nodes.   We know that the new argument should
-                have the same value as the argument associated with LAST.
-                Otherwise we would have changed our target block above.  */
-             for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
+             basic_block dom;
+
+             tmp = EDGE_SUCC (old_dest, 0)->dest;
+
+             if (get_immediate_dominator (CDI_DOMINATORS, tmp) == old_dest
+                 && !dominated_by_p (CDI_DOMINATORS, bb, tmp))
                {
-                 arg = phi_arg_from_edge (phi, last);
-                 gcc_assert (arg >= 0);
-                 add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e);
+                 dom = get_immediate_dominator (CDI_DOMINATORS, old_dest);
+                 set_immediate_dominator (CDI_DOMINATORS, tmp, dom);
                }
+
+             dom = recount_dominator (CDI_DOMINATORS, old_dest);
+             set_immediate_dominator (CDI_DOMINATORS, old_dest, dom);
            }
+       }
+    }
+
+  return retval;
+}
+
+
+/* Thread jumps over empty statements.
+
+   This code should _not_ thread over obviously equivalent conditions
+   as that requires nontrivial updates to the SSA graph.
+
+   As a precondition, we require that all basic blocks be reachable.
+   That is, there should be no opportunities left for
+   delete_unreachable_blocks.  */
+
+static bool
+thread_jumps (void)
+{
+  basic_block bb;
+  bool retval = false;
+  basic_block *worklist = xmalloc (sizeof (basic_block) * last_basic_block);
+  basic_block *current = worklist;
 
-         /* Update the dominators.  */
-         if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+  FOR_EACH_BB (bb)
+    {
+      bb_ann (bb)->forwardable = tree_forwarder_block_p (bb);
+      bb->flags &= ~BB_VISITED;
+    }
+
+  /* We pretend to have ENTRY_BLOCK_PTR in WORKLIST.  This way,
+     ENTRY_BLOCK_PTR will never be entered into WORKLIST.  */
+  ENTRY_BLOCK_PTR->flags |= BB_VISITED;
+
+  /* Initialize WORKLIST by putting non-forwarder blocks that
+     immediately precede forwarder blocks because those are the ones
+     that we know we can thread jumps from.  We use BB_VISITED to
+     indicate whether a given basic block is in WORKLIST or not,
+     thereby avoiding duplicates in WORKLIST.  */
+  FOR_EACH_BB (bb)
+    {
+      edge_iterator ei;
+      edge e;
+
+      /* We are not interested in finding non-forwarder blocks
+        directly.  We want to find non-forwarder blocks as
+        predecessors of a forwarder block.  */
+      if (!bb_ann (bb)->forwardable)
+       continue;
+
+      /* Now we know BB is a forwarder block.  Visit each of its
+        incoming edges and add to WORKLIST all non-forwarder blocks
+        among BB's predecessors.  */
+      FOR_EACH_EDGE (e, ei, bb->preds)
+       {
+         /* We don't want to put a duplicate into WORKLIST.  */
+         if ((e->src->flags & BB_VISITED) == 0
+             /* We are not interested in threading jumps from a forwarder
+                block.  */
+             && !bb_ann (e->src)->forwardable)
            {
-             /* Remove the unreachable blocks (observe that if all blocks
-                were reachable before, only those in the path we threaded
-                over and did not have any predecessor outside of the path
-                become unreachable).  */
-             for (; old_dest != dest; old_dest = tmp)
-               {
-                 tmp = old_dest->succ->dest;
+             e->src->flags |= BB_VISITED;
+             *current++ = e->src;
+           }
+       }
+    }
 
-                 if (old_dest->pred)
-                   break;
+  /* Now let's drain WORKLIST.  */
+  while (worklist != current)
+    {
+      bb = *--current;
 
-                 delete_basic_block (old_dest);
-               }
-             /* If the dominator of the destination was in the path, set its
-                dominator to the start of the redirected edge.  */
-             if (get_immediate_dominator (CDI_DOMINATORS, old_dest) == NULL)
-               set_immediate_dominator (CDI_DOMINATORS, old_dest, bb);
+      /* BB is no longer in WORKLIST, so clear BB_VISITED.  */
+      bb->flags &= ~BB_VISITED;
 
-             /* Now proceed like if we forwarded just over one edge at a time.
-                Algorithm for forwarding over edge A --> B then is
+      if (thread_jumps_from_bb (bb))
+       {
+         retval = true;
 
-                if (idom (B) == A)
-                  idom (B) = idom (A);
-                recount_idom (A);  */
+         if (tree_forwarder_block_p (bb))
+           {
+             edge_iterator ej;
+             edge f;
 
-             for (; old_dest != dest; old_dest = tmp)
-               {
-                 tmp = old_dest->succ->dest;
+             bb_ann (bb)->forwardable = true;
 
-                 if (get_immediate_dominator (CDI_DOMINATORS, tmp) == old_dest)
+             /* Attempts to thread through BB may have been blocked
+                because BB was not a forwarder block before.  Now
+                that BB is a forwarder block, we should revisit BB's
+                predecessors.  */
+             FOR_EACH_EDGE (f, ej, bb->preds)
+               {
+                 /* We don't want to put a duplicate into WORKLIST.  */
+                 if ((f->src->flags & BB_VISITED) == 0
+                     /* We are not interested in threading jumps from a
+                        forwarder block.  */
+                     && !bb_ann (f->src)->forwardable)
                    {
-                     dom = get_immediate_dominator (CDI_DOMINATORS, old_dest);
-                     set_immediate_dominator (CDI_DOMINATORS, tmp, dom);
+                     f->src->flags |= BB_VISITED;
+                     *current++ = f->src;
                    }
-
-                 dom = recount_dominator (CDI_DOMINATORS, old_dest);
-                 set_immediate_dominator (CDI_DOMINATORS, old_dest, dom);
                }
            }
        }
-
-      /* Reset the forwardable bit on our block since it's no longer in
-        a forwarding chain path.  */
-      bb_ann (bb)->forwardable = 1;
     }
 
+  ENTRY_BLOCK_PTR->flags &= ~BB_VISITED;
+
+  free (worklist);
+
   return retval;
 }
 
@@ -4025,9 +4211,10 @@ tree_try_redirect_by_replacing_jump (edge e, basic_block target)
   edge tmp;
   block_stmt_iterator b;
   tree stmt;
+  edge_iterator ei;
 
   /* Verify that all targets will be TARGET.  */
-  for (tmp = src->succ; tmp; tmp = tmp->succ_next)
+  FOR_EACH_EDGE (tmp, ei, src->succs)
     if (tmp->dest != target && tmp != e)
       break;
 
@@ -4094,17 +4281,32 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
 
     case SWITCH_EXPR:
       {
-       tree vec = SWITCH_LABELS (stmt);
-       size_t i, n = TREE_VEC_LENGTH (vec);
+       edge e2;
 
-       for (i = 0; i < n; ++i)
+        /* We need to update the LABEL_DECL in the switch vector to
+          reflect the edge redirection.
+
+          There is precisely one CASE_LABEL_EXPR in the switch vector
+          which needs updating.  Either its label needs to be updated
+          or it needs to be directed to a new case leader.  */
+       e2 = find_edge (e->src, dest);
+       if (e2)
          {
-           tree elt = TREE_VEC_ELT (vec, i);
-           if (label_to_block (CASE_LABEL (elt)) == e->dest)
-             CASE_LABEL (elt) = label;
+           /* In this case we need to change the case leader for the
+              current leader of E to be the case leader for E2.  */
+           tree e_leader = get_case_leader_for_edge (e);
+           tree e2_leader = get_case_leader_for_edge (e2);
+           CASE_LEADER_OR_LABEL (e_leader) = e2_leader;
          }
+       else
+         {
+           /* No edge exists from E->src to DEST, so we will simply
+              change E->dest.  The case leader does not change, but
+              the LABEL_DECL for the leader does change.  */
+           CASE_LEADER_OR_LABEL (get_case_leader_for_edge (e)) = label;
+         }
+       break;
       }
-      break;
 
     case RETURN_EXPR:
       bsi_remove (&bsi);
@@ -4149,13 +4351,14 @@ tree_split_block (basic_block bb, void *stmt)
   tree act;
   basic_block new_bb;
   edge e;
+  edge_iterator ei;
 
   new_bb = create_empty_bb (bb);
 
   /* Redirect the outgoing edges.  */
-  new_bb->succ = bb->succ;
-  bb->succ = NULL;
-  for (e = new_bb->succ; e; e = e->succ_next)
+  new_bb->succs = bb->succs;
+  bb->succs = NULL;
+  FOR_EACH_EDGE (e, ei, new_bb->succs)
     e->src = new_bb;
 
   if (stmt && TREE_CODE ((tree) stmt) == LABEL_EXPR)
@@ -4213,7 +4416,6 @@ tree_can_duplicate_bb_p (basic_block bb ATTRIBUTE_UNUSED)
   return true;
 }
 
-
 /* Create a duplicate of the basic block BB.  NOTE: This does not
    preserve SSA form.  */
 
@@ -4227,10 +4429,15 @@ tree_duplicate_bb (basic_block bb)
 
   new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
 
-  for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+  /* First copy the phi nodes.  We do not copy phi node arguments here,
+     since the edges are not ready yet.  Keep the chain of phi nodes in
+     the same order, so that we can add them later.  */
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
     {
       mark_for_rewrite (PHI_RESULT (phi));
+      create_phi_node (PHI_RESULT (phi), new_bb);
     }
+  set_phi_nodes (new_bb, phi_reverse (phi_nodes (new_bb)));
 
   bsi_tgt = bsi_start (new_bb);
   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
@@ -4259,6 +4466,398 @@ tree_duplicate_bb (basic_block bb)
   return new_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.  */
+
+void
+add_phi_args_after_copy_bb (basic_block bb_copy)
+{
+  basic_block bb, dest;
+  edge e, e_copy;
+  edge_iterator ei;
+  tree phi, phi_copy, phi_next, def;
+      
+  bb = bb_copy->rbi->original;
+
+  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;
+      else
+       dest = e_copy->dest;
+
+      e = find_edge (bb, dest);
+      if (!e)
+       {
+         /* During loop unrolling the target of the latch edge is copied.
+            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)
+             break;
+
+         gcc_assert (e != NULL);
+       }
+
+      for (phi = phi_nodes (e->dest), phi_copy = phi_nodes (e_copy->dest);
+          phi;
+          phi = phi_next, phi_copy = PHI_CHAIN (phi_copy))
+       {
+         phi_next = PHI_CHAIN (phi);
+
+         gcc_assert (PHI_RESULT (phi) == PHI_RESULT (phi_copy));
+         def = PHI_ARG_DEF_FROM_EDGE (phi, e);
+         add_phi_arg (&phi_copy, def, e_copy);
+       }
+    }
+}
+
+/* Blocks in REGION_COPY array of length N_REGION were created by
+   duplication of basic blocks.  Add phi node arguments for edges
+   going from these blocks.  */
+
+void
+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;
+
+  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;
+}
+
+/* Maps the old ssa name FROM_NAME to TO_NAME.  */
+
+struct ssa_name_map_entry
+{
+  tree from_name;
+  tree to_name;
+};
+
+/* Hash function for ssa_name_map_entry.  */
+
+static hashval_t
+ssa_name_map_entry_hash (const void *entry)
+{
+  const struct ssa_name_map_entry *en = entry;
+  return SSA_NAME_VERSION (en->from_name);
+}
+
+/* Equality function for ssa_name_map_entry.  */
+
+static int
+ssa_name_map_entry_eq (const void *in_table, const void *ssa_name)
+{
+  const struct ssa_name_map_entry *en = in_table;
+
+  return en->from_name == ssa_name;
+}
+
+/* Allocate duplicates of ssa names in list DEFINITIONS and store the mapping
+   to MAP.  */
+
+void
+allocate_ssa_names (bitmap definitions, htab_t *map)
+{
+  tree name;
+  struct ssa_name_map_entry *entry;
+  PTR *slot;
+  unsigned ver;
+  bitmap_iterator bi;
+
+  if (!*map)
+    *map = htab_create (10, ssa_name_map_entry_hash,
+                       ssa_name_map_entry_eq, free);
+  EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver, bi)
+    {
+      name = ssa_name (ver);
+      slot = htab_find_slot_with_hash (*map, name, SSA_NAME_VERSION (name),
+                                      INSERT);
+      if (*slot)
+       entry = *slot;
+      else
+       {
+         entry = xmalloc (sizeof (struct ssa_name_map_entry));
+         entry->from_name = name;
+         *slot = entry;
+       }
+      entry->to_name = duplicate_ssa_name (name, SSA_NAME_DEF_STMT (name));
+    }
+}
+
+/* Rewrite the definition DEF in statement STMT to new ssa name as specified
+   by the mapping MAP.  */
+
+static void
+rewrite_to_new_ssa_names_def (def_operand_p def, tree stmt, htab_t map)
+{
+  tree name = DEF_FROM_PTR (def);
+  struct ssa_name_map_entry *entry;
+
+  gcc_assert (TREE_CODE (name) == SSA_NAME);
+
+  entry = htab_find_with_hash (map, name, SSA_NAME_VERSION (name));
+  if (!entry)
+    return;
+
+  SET_DEF (def, entry->to_name);
+  SSA_NAME_DEF_STMT (entry->to_name) = stmt;
+}
+
+/* Rewrite the USE to new ssa name as specified by the mapping MAP.  */
+
+static void
+rewrite_to_new_ssa_names_use (use_operand_p use, htab_t map)
+{
+  tree name = USE_FROM_PTR (use);
+  struct ssa_name_map_entry *entry;
+
+  if (TREE_CODE (name) != SSA_NAME)
+    return;
+
+  entry = htab_find_with_hash (map, name, SSA_NAME_VERSION (name));
+  if (!entry)
+    return;
+
+  SET_USE (use, entry->to_name);
+}
+
+/* Rewrite the ssa names in basic block BB to new ones as specified by the
+   mapping MAP.  */
+
+void
+rewrite_to_new_ssa_names_bb (basic_block bb, htab_t map)
+{
+  unsigned i;
+  edge e;
+  edge_iterator ei;
+  tree phi, stmt;
+  block_stmt_iterator bsi;
+  use_optype uses;
+  vuse_optype vuses;
+  def_optype defs;
+  v_may_def_optype v_may_defs;
+  v_must_def_optype v_must_defs;
+  stmt_ann_t ann;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (e->flags & EDGE_ABNORMAL)
+      break;
+
+  for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+    {
+      rewrite_to_new_ssa_names_def (PHI_RESULT_PTR (phi), phi, map);
+      if (e)
+       SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1;
+    }
+
+  for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+    {
+      stmt = bsi_stmt (bsi);
+      get_stmt_operands (stmt);
+      ann = stmt_ann (stmt);
+
+      uses = USE_OPS (ann);
+      for (i = 0; i < NUM_USES (uses); i++)
+       rewrite_to_new_ssa_names_use (USE_OP_PTR (uses, i), map);
+
+      defs = DEF_OPS (ann);
+      for (i = 0; i < NUM_DEFS (defs); i++)
+       rewrite_to_new_ssa_names_def (DEF_OP_PTR (defs, i), stmt, map);
+
+      vuses = VUSE_OPS (ann);
+      for (i = 0; i < NUM_VUSES (vuses); i++)
+       rewrite_to_new_ssa_names_use (VUSE_OP_PTR (vuses, i), map);
+
+      v_may_defs = V_MAY_DEF_OPS (ann);
+      for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+       {
+         rewrite_to_new_ssa_names_use
+                 (V_MAY_DEF_OP_PTR (v_may_defs, i), map);
+         rewrite_to_new_ssa_names_def
+                 (V_MAY_DEF_RESULT_PTR (v_may_defs, i), stmt, map);
+       }
+
+      v_must_defs = V_MUST_DEF_OPS (ann);
+      for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
+       {
+         rewrite_to_new_ssa_names_def
+           (V_MUST_DEF_RESULT_PTR (v_must_defs, i), stmt, map);
+         rewrite_to_new_ssa_names_use
+           (V_MUST_DEF_KILL_PTR (v_must_defs, i),  map);
+       }
+    }
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
+      {
+       rewrite_to_new_ssa_names_use
+               (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), map);
+
+       if (e->flags & EDGE_ABNORMAL)
+         {
+           tree op = PHI_ARG_DEF_FROM_EDGE (phi, e);
+           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op) = 1;
+         }
+      }
+}
+
+/* Rewrite the ssa names in N_REGION blocks REGION to the new ones as specified
+   by the mapping MAP.  */
+
+void
+rewrite_to_new_ssa_names (basic_block *region, unsigned n_region, htab_t map)
+{
+  unsigned r;
+
+  for (r = 0; r < n_region; r++)
+    rewrite_to_new_ssa_names_bb (region[r], map);
+}
+
+/* Duplicates a REGION (set of N_REGION basic blocks) with just a single
+   important exit edge EXIT.  By important we mean that no SSA name defined
+   inside region is live over the other exit edges of the region.  All entry
+   edges to the region must go to ENTRY->dest.  The edge ENTRY is redirected
+   to the duplicate of the region.  SSA form, dominance and loop information
+   is updated.  The new basic blocks are stored to REGION_COPY in the same
+   order as they had in REGION, provided that REGION_COPY is not NULL.
+   The function returns false if it is unable to copy the region,
+   true otherwise.  */
+
+bool
+tree_duplicate_sese_region (edge entry, edge exit,
+                           basic_block *region, unsigned n_region,
+                           basic_block *region_copy)
+{
+  unsigned i, n_doms, ver;
+  bool free_region_copy = false, copying_header = false;
+  struct loop *loop = entry->dest->loop_father;
+  edge exit_copy;
+  bitmap definitions;
+  tree phi;
+  basic_block *doms;
+  htab_t ssa_name_map = NULL;
+  edge redirected;
+  bitmap_iterator bi;
+
+  if (!can_copy_bbs_p (region, n_region))
+    return false;
+
+  /* Some sanity checking.  Note that we do not check for all possible
+     missuses of the functions.  I.e. if you ask to copy something weird,
+     it will work, but the state of structures probably will not be
+     correct.  */
+
+  for (i = 0; i < n_region; i++)
+    {
+      /* We do not handle subloops, i.e. all the blocks must belong to the
+        same loop.  */
+      if (region[i]->loop_father != loop)
+       return false;
+
+      if (region[i] != entry->dest
+         && region[i] == loop->header)
+       return false;
+    }
+
+  loop->copy = loop;
+
+  /* In case the function is used for loop header copying (which is the primary
+     use), ensure that EXIT and its copy will be new latch and entry edges.  */
+  if (loop->header == entry->dest)
+    {
+      copying_header = true;
+      loop->copy = loop->outer;
+
+      if (!dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src))
+       return false;
+
+      for (i = 0; i < n_region; i++)
+       if (region[i] != exit->src
+           && dominated_by_p (CDI_DOMINATORS, region[i], exit->src))
+         return false;
+    }
+
+  if (!region_copy)
+    {
+      region_copy = xmalloc (sizeof (basic_block) * n_region);
+      free_region_copy = true;
+    }
+
+  gcc_assert (!any_marked_for_rewrite_p ());
+
+  /* Record blocks outside the region that are duplicated by something
+     inside.  */
+  doms = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  n_doms = get_dominated_by_region (CDI_DOMINATORS, region, n_region, doms);
+
+  copy_bbs (region, n_region, region_copy, &exit, 1, &exit_copy, loop);
+  definitions = marked_ssa_names ();
+
+  if (copying_header)
+    {
+      loop->header = exit->dest;
+      loop->latch = exit->src;
+    }
+
+  /* Redirect the entry and add the phi node arguments.  */
+  redirected = redirect_edge_and_branch (entry, entry->dest->rbi->copy);
+  gcc_assert (redirected != NULL);
+  flush_pending_stmts (entry);
+
+  /* Concerning updating of dominators:  We must recount dominators
+     for entry block and its copy.  Anything that is outside of the region, but
+     was dominated by something inside needs recounting as well.  */
+  set_immediate_dominator (CDI_DOMINATORS, entry->dest, entry->src);
+  doms[n_doms++] = entry->dest->rbi->original;
+  iterate_fix_dominators (CDI_DOMINATORS, doms, n_doms);
+  free (doms);
+
+  /* Add the other phi node arguments.  */
+  add_phi_args_after_copy (region_copy, n_region);
+
+  /* Add phi nodes for definitions at exit.  TODO -- once we have immediate
+     uses, it should be possible to emit phi nodes just for definitions that
+     are used outside region.  */
+  EXECUTE_IF_SET_IN_BITMAP (definitions, 0, ver, bi)
+    {
+      tree name = ssa_name (ver);
+
+      phi = create_phi_node (name, exit->dest);
+      add_phi_arg (&phi, name, exit);
+      add_phi_arg (&phi, name, exit_copy);
+
+      SSA_NAME_DEF_STMT (name) = phi;
+    }
+
+  /* And create new definitions inside region and its copy.  TODO -- once we
+     have immediate uses, it might be better to leave definitions in region
+     unchanged, create new ssa names for phi nodes on exit, and rewrite
+     the uses, to avoid changing the copied region.  */
+  allocate_ssa_names (definitions, &ssa_name_map);
+  rewrite_to_new_ssa_names (region, n_region, ssa_name_map);
+  allocate_ssa_names (definitions, &ssa_name_map);
+  rewrite_to_new_ssa_names (region_copy, n_region, ssa_name_map);
+  htab_delete (ssa_name_map);
+
+  if (free_region_copy)
+    free (region_copy);
+
+  unmark_all_for_rewrite ();
+  BITMAP_XFREE (definitions);
+
+  return true;
+}
 
 /* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h)  */
 
@@ -4360,43 +4959,33 @@ dump_function_to_file (tree fn, FILE *file, int flags)
 
 /* Pretty print of the loops intermediate representation.  */
 static void print_loop (FILE *, struct loop *, int);
-static void print_pred_bbs (FILE *, edge);
-static void print_succ_bbs (FILE *, edge);
+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.  */
 
 static void
-print_pred_bbs (FILE *file, edge e)
+print_pred_bbs (FILE *file, basic_block bb)
 {
-  if (e == NULL)
-    return;
-  
-  else if (e->pred_next == NULL)
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
     fprintf (file, "bb_%d", e->src->index);
-  
-  else
-    {
-      fprintf (file, "bb_%d, ", e->src->index);
-      print_pred_bbs (file, e->pred_next);
-    }
 }
 
 
 /* Print the successors indexes of edge E on FILE.  */
 
 static void
-print_succ_bbs (FILE *file, edge e)
+print_succ_bbs (FILE *file, basic_block bb)
 {
-  if (e == NULL)
-    return;
-  else if (e->succ_next == NULL)
-    fprintf (file, "bb_%d", e->dest->index);
-  else
-    {
-      fprintf (file, "bb_%d, ", e->dest->index);
-      print_succ_bbs (file, e->succ_next);
-    }
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    fprintf (file, "bb_%d", e->src->index);
 }
 
 
@@ -4425,9 +5014,9 @@ print_loop (FILE *file, struct loop *loop, int indent)
       {
        /* Print the basic_block's header.  */
        fprintf (file, "%s  bb_%d (preds = {", s_indent, bb->index);
-       print_pred_bbs (file, bb->pred);
+       print_pred_bbs (file, bb);
        fprintf (file, "}, succs = {");
-       print_succ_bbs (file, bb->succ);
+       print_succ_bbs (file, bb);
        fprintf (file, "})\n");
        
        /* Print the basic_block's body.  */
@@ -4555,6 +5144,7 @@ tree_flow_call_edges_add (sbitmap blocks)
      Handle this by adding a dummy instruction in a new last basic block.  */
   if (check_last_block)
     {
+      edge_iterator ei;
       basic_block bb = EXIT_BLOCK_PTR->prev_bb;
       block_stmt_iterator bsi = bsi_last (bb);
       tree t = NULL_TREE;
@@ -4565,11 +5155,11 @@ tree_flow_call_edges_add (sbitmap blocks)
        {
          edge e;
 
-         for (e = bb->succ; e; e = e->succ_next)
+         FOR_EACH_EDGE (e, ei, bb->succs)
            if (e->dest == EXIT_BLOCK_PTR)
              {
                bsi_insert_on_edge (e, build_empty_stmt ());
-               bsi_commit_edge_inserts ((int *)NULL);
+               bsi_commit_edge_inserts ();
                break;
              }
        }
@@ -4607,8 +5197,11 @@ tree_flow_call_edges_add (sbitmap blocks)
                     mark that edge as fake and remove it later.  */
 #ifdef ENABLE_CHECKING
                  if (stmt == last_stmt)
-                   for (e = bb->succ; e; e = e->succ_next)
-                     gcc_assert (e->dest != EXIT_BLOCK_PTR);
+                   {
+                     edge_iterator ei;
+                     FOR_EACH_EDGE (e, ei, bb->succs)
+                       gcc_assert (e->dest != EXIT_BLOCK_PTR);
+                   }
 #endif
 
                  /* Note that the following may create a new basic block
@@ -4637,22 +5230,44 @@ bool
 tree_purge_dead_eh_edges (basic_block bb)
 {
   bool changed = false;
-  edge e, next;
+  edge e;
+  edge_iterator ei;
   tree stmt = last_stmt (bb);
 
   if (stmt && tree_can_throw_internal (stmt))
     return false;
 
-  for (e = bb->succ; e ; e = next)
+  for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      next = e->succ_next;
       if (e->flags & EDGE_EH)
        {
          ssa_remove_edge (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;
 }
 
@@ -4660,10 +5275,13 @@ bool
 tree_purge_all_dead_eh_edges (bitmap blocks)
 {
   bool changed = false;
-  size_t i;
+  unsigned i;
+  bitmap_iterator bi;
 
-  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i,
-    { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); });
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi)
+    {
+      changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i));
+    }
 
   return changed;
 }
@@ -4700,10 +5318,11 @@ split_critical_edges (void)
 {
   basic_block bb;
   edge e;
+  edge_iterator ei;
 
   FOR_ALL_BB (bb)
     {
-      for (e = bb->succ; e ; e = e->succ_next)
+      FOR_EACH_EDGE (e, ei, bb->succs)
        if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
          {
            split_edge (e);
@@ -4813,24 +5432,26 @@ execute_warn_function_return (void)
 #endif
   tree last;
   edge e;
+  edge_iterator ei;
 
   if (warn_missing_noreturn
       && !TREE_THIS_VOLATILE (cfun->decl)
-      && EXIT_BLOCK_PTR->pred == NULL
+      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
       && !lang_hooks.function.missing_noreturn_ok_p (cfun->decl))
-    warning ("%Jfunction might be possible candidate for attribute `noreturn'",
+    warning ("%Jfunction might be possible candidate for "
+            "attribute %<noreturn%>",
             cfun->decl);
 
   /* If we have a path to EXIT, then we do return.  */
   if (TREE_THIS_VOLATILE (cfun->decl)
-      && EXIT_BLOCK_PTR->pred != NULL)
+      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0)
     {
 #ifdef USE_MAPPED_LOCATION
       location = UNKNOWN_LOCATION;
 #else
       locus = NULL;
 #endif
-      for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
        {
          last = last_stmt (e->src);
          if (TREE_CODE (last) == RETURN_EXPR
@@ -4844,21 +5465,21 @@ execute_warn_function_return (void)
 #ifdef USE_MAPPED_LOCATION
       if (location == UNKNOWN_LOCATION)
        location = cfun->function_end_locus;
-      warning ("%H`noreturn' function does return", &location);
+      warning ("%H%<noreturn%> function does return", &location);
 #else
       if (!locus)
        locus = &cfun->function_end_locus;
-      warning ("%H`noreturn' function does return", locus);
+      warning ("%H%<noreturn%> function does return", locus);
 #endif
     }
 
   /* If we see "return;" in some basic block, then we do reach the end
      without returning a value.  */
   else if (warn_return_type
-          && EXIT_BLOCK_PTR->pred != NULL
+          && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0
           && !VOID_TYPE_P (TREE_TYPE (TREE_TYPE (cfun->decl))))
     {
-      for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
        {
          tree last = last_stmt (e->src);
          if (TREE_CODE (last) == RETURN_EXPR
@@ -4892,17 +5513,17 @@ extract_true_false_edges_from_block (basic_block b,
                                     edge *true_edge,
                                     edge *false_edge)
 {
-  edge e = b->succ;
+  edge e = EDGE_SUCC (b, 0);
 
   if (e->flags & EDGE_TRUE_VALUE)
     {
       *true_edge = e;
-      *false_edge = e->succ_next;
+      *false_edge = EDGE_SUCC (b, 1);
     }
   else
     {
       *false_edge = e;
-      *true_edge = e->succ_next;
+      *true_edge = EDGE_SUCC (b, 1);
     }
 }