tree-ssa-dce.c (remove_dead_stmt): Update profile.
[gcc.git] / gcc / tree-cfg.c
index f6bb8e01b60b9b2a89e8df78244860d2dde30f70..14f7d1da8bd90c1b5946c9176e2bb8d70a78e49b 100644 (file)
@@ -99,8 +99,6 @@ static void tree_cfg2vcg (FILE *);
 static void tree_merge_blocks (basic_block, basic_block);
 static bool tree_can_merge_blocks_p (basic_block, basic_block);
 static void remove_bb (basic_block);
-static void group_case_labels (void);
-static void cleanup_dead_labels (void);
 static bool cleanup_control_flow (void);
 static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator);
 static edge find_taken_edge_cond_expr (basic_block, tree);
@@ -127,6 +125,7 @@ build_tree_cfg (tree *tp)
 
   /* Initialize the basic block array.  */
   init_flow ();
+  profile_status = PROFILE_ABSENT;
   n_basic_blocks = 0;
   last_basic_block = 0;
   VARRAY_BB_INIT (basic_block_info, initial_cfg_capacity, "basic_block_info");
@@ -208,7 +207,8 @@ 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_flags_finish */
+  0                                    /* letter */
 };
 
 /* Search the CFG for any computed gotos.  If found, factor them to a 
@@ -294,8 +294,7 @@ static void
 create_block_annotation (basic_block bb)
 {
   /* Verify that the tree_annotations field is clear.  */
-  if (bb->tree_annotations)
-    abort ();
+  gcc_assert (!bb->tree_annotations);
   bb->tree_annotations = ggc_alloc_cleared (sizeof (struct bb_ann_d));
 }
 
@@ -374,8 +373,7 @@ create_bb (void *h, void *e, basic_block after)
 {
   basic_block bb;
 
-  if (e)
-    abort ();
+  gcc_assert (!e);
 
   /* Create and initialize a new basic block.  */
   bb = alloc_block ();
@@ -461,17 +459,8 @@ static void
 make_ctrl_stmt_edges (basic_block bb)
 {
   tree last = last_stmt (bb);
-  tree first = first_stmt (bb);
-
-#if defined ENABLE_CHECKING
-  if (last == NULL_TREE)
-    abort();
-#endif
-
-  if (TREE_CODE (first) == LABEL_EXPR
-      && DECL_NONLOCAL (LABEL_EXPR_LABEL (first)))
-    make_edge (ENTRY_BLOCK_PTR, bb, EDGE_ABNORMAL);
 
+  gcc_assert (last);
   switch (TREE_CODE (last))
     {
     case GOTO_EXPR:
@@ -498,7 +487,7 @@ make_ctrl_stmt_edges (basic_block bb)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -512,9 +501,7 @@ make_exit_edges (basic_block bb)
 {
   tree last = last_stmt (bb), op;
 
-  if (last == NULL_TREE)
-    abort ();
-
+  gcc_assert (last);
   switch (TREE_CODE (last))
     {
     case CALL_EXPR:
@@ -560,7 +547,7 @@ make_exit_edges (basic_block bb)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -575,10 +562,8 @@ make_cond_expr_edges (basic_block bb)
   basic_block then_bb, else_bb;
   tree then_label, else_label;
 
-#if defined ENABLE_CHECKING
-  if (entry == NULL_TREE || TREE_CODE (entry) != COND_EXPR)
-    abort ();
-#endif
+  gcc_assert (entry);
+  gcc_assert (TREE_CODE (entry) == COND_EXPR);
 
   /* Entry basic blocks for each component.  */
   then_label = GOTO_DESTINATION (COND_EXPR_THEN (entry));
@@ -723,10 +708,11 @@ make_goto_expr_edges (basic_block bb)
 
 /* Remove unreachable blocks and other miscellaneous clean up work.  */
 
-void
+bool
 cleanup_tree_cfg (void)
 {
   bool something_changed = true;
+  bool retval = false;
 
   timevar_push (TV_TREE_CLEANUP_CFG);
 
@@ -735,8 +721,9 @@ cleanup_tree_cfg (void)
   while (something_changed)
     {
       something_changed = cleanup_control_flow ();
-      something_changed |= thread_jumps ();
       something_changed |= delete_unreachable_blocks ();
+      something_changed |= thread_jumps ();
+      retval |= something_changed;
     }
 
   /* Merging the blocks creates no new opportunities for the other
@@ -749,6 +736,7 @@ cleanup_tree_cfg (void)
   verify_flow_info ();
 #endif
   timevar_pop (TV_TREE_CLEANUP_CFG);
+  return retval;
 }
 
 
@@ -769,7 +757,16 @@ update_eh_label (struct eh_region *region)
   tree old_label = get_eh_region_tree_label (region);
   if (old_label)
     {
-      tree new_label = label_for_bb[label_to_block (old_label)->index];
+      tree new_label;
+      basic_block bb = label_to_block (old_label);
+
+      /* ??? After optimizing, there may be EH regions with labels
+        that have already been removed from the function body, so
+        there is no basic block for them.  */
+      if (! bb)
+       return;
+
+      new_label = label_for_bb[bb->index];
       set_eh_region_tree_label (region, new_label);
     }
 }
@@ -791,7 +788,7 @@ main_block_label (tree label)
      2) Redirect all references to labels to the leading labels.
      3) Cleanup all useless labels.  */
 
-static void
+void
 cleanup_dead_labels (void)
 {
   basic_block bb;
@@ -924,7 +921,7 @@ cleanup_dead_labels (void)
    same label.
    Eg. three separate entries 1: 2: 3: become one entry 1..3:  */
 
-static void
+void
 group_case_labels (void)
 {
   basic_block bb;
@@ -948,9 +945,7 @@ group_case_labels (void)
              tree base_case, base_label, base_high, type;
              base_case = TREE_VEC_ELT (labels, i);
 
-             if (! base_case)
-               abort ();
-
+             gcc_assert (base_case);
              base_label = CASE_LABEL (base_case);
 
              /* Discard cases that have the same destination as the
@@ -1073,12 +1068,8 @@ tree_merge_blocks (basic_block a, basic_block b)
   /* Ensure that B follows A.  */
   move_block_after (b, a);
 
-  if (!(a->succ->flags & EDGE_FALLTHRU))
-    abort ();
-
-  if (last_stmt (a)
-      && stmt_ends_bb_p (last_stmt (a)))
-    abort ();
+  gcc_assert (a->succ->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.  */
   for (bsi = bsi_start (b); !bsi_end_p (bsi);)
@@ -1641,7 +1632,8 @@ struct tree_opt_pass pass_remove_useless_stmts =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 
@@ -1732,13 +1724,14 @@ cfg_remove_useless_stmts_bb (basic_block bb)
          continue;
        }
 
-      /* Invalidate the var if we encounter something that could modify it.  */
+      /* Invalidate the var if we encounter something that could modify it.
+        Likewise for the value it was previously set to.  Note that we only
+        consider values that are either a VAR_DECL or PARM_DECL so we
+        can test for conflict very simply.  */
       if (TREE_CODE (stmt) == ASM_EXPR
-         || TREE_CODE (stmt) == VA_ARG_EXPR
          || (TREE_CODE (stmt) == MODIFY_EXPR
              && (TREE_OPERAND (stmt, 0) == var
-                 || TREE_OPERAND (stmt, 0) == val
-                 || TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
+                 || TREE_OPERAND (stmt, 0) == val)))
        return;
   
       bsi_next (&bsi);
@@ -1955,7 +1948,7 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       taken_edge = find_taken_edge (bb, val);
@@ -1993,7 +1986,7 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
 
 /* 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. */
+   edge, NULL is returned.  */
 
 edge
 find_taken_edge (basic_block bb, tree val)
@@ -2002,10 +1995,8 @@ find_taken_edge (basic_block bb, tree val)
 
   stmt = last_stmt (bb);
 
-#if defined ENABLE_CHECKING
-  if (stmt == NULL_TREE || !is_ctrl_stmt (stmt))
-    abort ();
-#endif
+  gcc_assert (stmt);
+  gcc_assert (is_ctrl_stmt (stmt));
 
   /* 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
@@ -2088,8 +2079,7 @@ find_taken_edge_switch_expr (basic_block bb, tree val)
   dest_bb = label_to_block (CASE_LABEL (taken_case));
 
   e = find_edge (bb, dest_bb);
-  if (!e)
-    abort ();
+  gcc_assert (e);
   return e;
 }
 
@@ -2152,10 +2142,8 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
       n1 = phi_arg_from_edge (phi, e1);
       n2 = phi_arg_from_edge (phi, e2);
 
-#ifdef ENABLE_CHECKING
-      if (n1 < 0 || n2 < 0)
-       abort ();
-#endif
+      gcc_assert (n1 >= 0);
+      gcc_assert (n2 >= 0);
 
       val1 = PHI_ARG_DEF (phi, n1);
       val2 = PHI_ARG_DEF (phi, n2);
@@ -2168,84 +2156,6 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
 }
 
 
-/* Computing the Dominance Frontier:
-
-   As described in Morgan, section 3.5, this may be done simply by
-   walking the dominator tree bottom-up, computing the frontier for
-   the children before the parent.  When considering a block B,
-   there are two cases:
-
-   (1) A flow graph edge leaving B that does not lead to a child
-   of B in the dominator tree must be a block that is either equal
-   to B or not dominated by B.  Such blocks belong in the frontier
-   of B.
-
-   (2) Consider a block X in the frontier of one of the children C
-   of B.  If X is not equal to B and is not dominated by B, it
-   is in the frontier of B.  */
-
-static void
-compute_dominance_frontiers_1 (bitmap *frontiers, basic_block bb, sbitmap done)
-{
-  edge e;
-  basic_block c;
-
-  SET_BIT (done, bb->index);
-
-  /* Do the frontier of the children first.  Not all children in the
-     dominator tree (blocks dominated by this one) are children in the
-     CFG, so check all blocks.  */
-  for (c = first_dom_son (CDI_DOMINATORS, bb);
-       c;
-       c = next_dom_son (CDI_DOMINATORS, c))
-    {
-      if (! TEST_BIT (done, c->index))
-       compute_dominance_frontiers_1 (frontiers, c, done);
-    }
-      
-  /* Find blocks conforming to rule (1) above.  */
-  for (e = bb->succ; e; e = e->succ_next)
-    {
-      if (e->dest == EXIT_BLOCK_PTR)
-       continue;
-      if (get_immediate_dominator (CDI_DOMINATORS, e->dest) != bb)
-       bitmap_set_bit (frontiers[bb->index], e->dest->index);
-    }
-
-  /* Find blocks conforming to rule (2).  */
-  for (c = first_dom_son (CDI_DOMINATORS, bb);
-       c;
-       c = next_dom_son (CDI_DOMINATORS, c))
-    {
-      int x;
-
-      EXECUTE_IF_SET_IN_BITMAP (frontiers[c->index], 0, x,
-       {
-         if (get_immediate_dominator (CDI_DOMINATORS, BASIC_BLOCK (x)) != bb)
-           bitmap_set_bit (frontiers[bb->index], x);
-       });
-    }
-}
-
-
-void
-compute_dominance_frontiers (bitmap *frontiers)
-{
-  sbitmap done = sbitmap_alloc (last_basic_block);
-
-  timevar_push (TV_DOM_FRONTIERS);
-
-  sbitmap_zero (done);
-
-  compute_dominance_frontiers_1 (frontiers, ENTRY_BLOCK_PTR->succ->dest, done);
-
-  sbitmap_free (done);
-
-  timevar_pop (TV_DOM_FRONTIERS);
-}
-
-
-
 /*---------------------------------------------------------------------------
                              Debugging functions
 ---------------------------------------------------------------------------*/
@@ -2499,11 +2409,7 @@ is_ctrl_altering_stmt (tree t)
 {
   tree call;
 
-#if defined ENABLE_CHECKING
-  if (t == NULL)
-    abort ();
-#endif
-
+  gcc_assert (t);
   call = get_call_expr_in (t);
   if (call)
     {
@@ -2537,10 +2443,8 @@ computed_goto_p (tree t)
 bool
 simple_goto_p (tree expr)
 {
-  return  (TREE_CODE (expr) == GOTO_EXPR
-          && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL
-          && (decl_function_context (GOTO_DESTINATION (expr))
-              == current_function_decl));
+  return (TREE_CODE (expr) == GOTO_EXPR
+         && TREE_CODE (GOTO_DESTINATION (expr)) == LABEL_DECL);
 }
 
 
@@ -2627,7 +2531,7 @@ disband_implicit_edges (void)
              else if (e->flags & EDGE_FALSE_VALUE)
                COND_EXPR_ELSE (stmt) = build_empty_stmt ();
              else
-               abort ();
+               gcc_unreachable ();
              e->flags |= EDGE_FALLTHRU;
            }
 
@@ -2638,10 +2542,9 @@ disband_implicit_edges (void)
        {
          /* Remove the RETURN_EXPR if we may fall though to the exit
             instead.  */
-         if (!bb->succ
-             || bb->succ->succ_next
-             || bb->succ->dest != EXIT_BLOCK_PTR)
-           abort ();
+         gcc_assert (bb->succ);
+         gcc_assert (!bb->succ->succ_next);
+         gcc_assert (bb->succ->dest == EXIT_BLOCK_PTR);
 
          if (bb->next_bb == EXIT_BLOCK_PTR
              && !TREE_OPERAND (stmt, 0))
@@ -2665,9 +2568,7 @@ disband_implicit_edges (void)
       if (!e || e->dest == bb->next_bb)
        continue;
 
-      if (e->dest == EXIT_BLOCK_PTR)
-       abort ();
-
+      gcc_assert (e->dest != EXIT_BLOCK_PTR);
       label = tree_block_label (e->dest);
 
       stmt = build1 (GOTO_EXPR, void_type_node, label);
@@ -2791,19 +2692,27 @@ set_bb_for_stmt (tree t, basic_block bb)
                VARRAY_GROW (label_to_block_map, 3 * uid / 2);
            }
          else
-           {
-#ifdef ENABLE_CHECKING
-             /* We're moving an existing label.  Make sure that we've
-                removed it from the old block.  */
-             if (bb && VARRAY_BB (label_to_block_map, uid))
-               abort ();
-#endif
-           }
+           /* We're moving an existing label.  Make sure that we've
+               removed it from the old block.  */
+           gcc_assert (!bb || !VARRAY_BB (label_to_block_map, uid));
          VARRAY_BB (label_to_block_map, uid) = bb;
        }
     }
 }
 
+/* Finds iterator for STMT.  */
+
+extern block_stmt_iterator
+stmt_for_bsi (tree stmt)
+{
+  block_stmt_iterator bsi;
+
+  for (bsi = bsi_start (bb_for_stmt (stmt)); !bsi_end_p (bsi); bsi_next (&bsi))
+    if (bsi_stmt (bsi) == stmt)
+      return bsi;
+
+  gcc_unreachable ();
+}
 
 /* Insert statement (or statement list) T before the statement
    pointed-to by iterator I.  M specifies how to update iterator I
@@ -2813,8 +2722,8 @@ void
 bsi_insert_before (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 {
   set_bb_for_stmt (t, i->bb);
-  modify_stmt (t);
   tsi_link_before (&i->tsi, t, m);
+  modify_stmt (t);
 }
 
 
@@ -2826,8 +2735,8 @@ void
 bsi_insert_after (block_stmt_iterator *i, tree t, enum bsi_iterator_update m)
 {
   set_bb_for_stmt (t, i->bb);
-  modify_stmt (t);
   tsi_link_after (&i->tsi, t, m);
+  modify_stmt (t);
 }
 
 
@@ -2839,7 +2748,6 @@ bsi_remove (block_stmt_iterator *i)
 {
   tree t = bsi_stmt (*i);
   set_bb_for_stmt (t, NULL);
-  modify_stmt (t);
   tsi_delink (&i->tsi);
 }
 
@@ -2915,10 +2823,12 @@ bsi_replace (const block_stmt_iterator *bsi, tree stmt, bool preserve_eh_info)
 
    In all cases, the returned *BSI points to the correct location.  The
    return value is true if insertion should be done after the location,
-   or false if it should be done before the location.  */
+   or false if it should be done before the location.  If new basic block
+   has to be created, it is stored in *NEW_BB.  */
 
 static bool
-tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
+tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi,
+                          basic_block *new_bb)
 {
   basic_block dest, src;
   tree tmp;
@@ -2983,8 +2893,7 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
          tree op = TREE_OPERAND (tmp, 0);
          if (!is_gimple_val (op))
            {
-             if (TREE_CODE (op) != MODIFY_EXPR)
-               abort ();
+             gcc_assert (TREE_CODE (op) == MODIFY_EXPR);
              bsi_insert_before (bsi, op, BSI_NEW_STMT);
              TREE_OPERAND (tmp, 0) = TREE_OPERAND (op, 0);
            }
@@ -2995,6 +2904,8 @@ tree_find_edge_insert_loc (edge e, block_stmt_iterator *bsi)
 
   /* Otherwise, create a new basic block, and split this edge.  */
   dest = split_edge (e);
+  if (new_bb)
+    *new_bb = dest;
   e = dest->pred;
   goto restart;
 }
@@ -3038,7 +2949,7 @@ bsi_commit_edge_inserts_1 (edge e)
 
       PENDING_STMT (e) = NULL_TREE;
 
-      if (tree_find_edge_insert_loc (e, &bsi))
+      if (tree_find_edge_insert_loc (e, &bsi, NULL))
        bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
       else
        bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
@@ -3055,6 +2966,24 @@ bsi_insert_on_edge (edge e, tree stmt)
   append_to_statement_list (stmt, &PENDING_STMT (e));
 }
 
+/* Similar to bsi_insert_on_edge+bsi_commit_edge_inserts.  If new block has to
+   be created, it is returned.  */
+
+basic_block
+bsi_insert_on_edge_immediate (edge e, tree stmt)
+{
+  block_stmt_iterator bsi;
+  basic_block new_bb = NULL;
+
+  gcc_assert (!PENDING_STMT (e));
+
+  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);
+
+  return new_bb;
+}
 
 /*---------------------------------------------------------------------------
             Tree specific functions for CFG manipulation
@@ -3072,8 +3001,7 @@ tree_split_edge (edge edge_in)
   int i, num_elem;
 
   /* Abnormal edges cannot be split.  */
-  if (edge_in->flags & EDGE_ABNORMAL)
-    abort ();
+  gcc_assert (!(edge_in->flags & EDGE_ABNORMAL));
 
   src = edge_in->src;
   dest = edge_in->dest;
@@ -3090,7 +3018,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
@@ -3106,11 +3038,9 @@ tree_split_edge (edge edge_in)
          }
     }
 
-  if (!redirect_edge_and_branch (edge_in, new_bb))
-    abort ();
-
-  if (PENDING_STMT (edge_in))
-    abort ();
+  e = redirect_edge_and_branch (edge_in, new_bb);
+  gcc_assert (e);
+  gcc_assert (!PENDING_STMT (edge_in));
 
   return new_bb;
 }
@@ -3691,8 +3621,7 @@ tree_verify_flow_info (void)
                tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
                basic_block label_bb = label_to_block (lab);
 
-               if (label_bb->aux && label_bb->aux != (void *)1)
-                 abort ();
+               gcc_assert (!label_bb->aux || label_bb->aux == (void *)1);
                label_bb->aux = (void *)1;
              }
 
@@ -3900,7 +3829,7 @@ static bool
 thread_jumps (void)
 {
   edge e, next, last, old;
-  basic_block bb, dest, tmp;
+  basic_block bb, dest, tmp, old_dest, dom;
   tree phi;
   int arg;
   bool retval = false;
@@ -3927,6 +3856,8 @@ thread_jumps (void)
         forwardable.  */
       for (e = bb->succ; e; e = next)
        {
+         int freq;
+         gcov_type count;
          next = e->succ_next;
 
          /* If the edge is abnormal or its destination is not
@@ -3935,6 +3866,9 @@ thread_jumps (void)
              || !tree_forwarder_block_p (e->dest))
            continue;
 
+         count = e->count;
+         freq = EDGE_FREQUENCY (e);
+
          /* Now walk through as many forwarder block as possible to
             find the ultimate destination we want to thread our jump
             to.  */
@@ -3954,6 +3888,15 @@ thread_jumps (void)
                break;
 
              bb_ann (dest)->forwardable = 0;
+             dest->frequency -= freq;
+             if (dest->frequency < 0)
+               dest->frequency = 0;
+             dest->count -= count;
+             if (dest->count < 0)
+               dest->count = 0;
+             dest->succ->count -= count;
+             if (dest->succ->count < 0)
+               dest->succ->count = 0;
            }
 
          /* Reset the forwardable marks to 1.  */
@@ -3987,11 +3930,9 @@ thread_jumps (void)
 
          /* Perform the redirection.  */
          retval = true;
+         old_dest = e->dest;
          e = redirect_edge_and_branch (e, dest);
 
-         /* TODO -- updating dominators in this case is simple.  */
-         free_dominance_info (CDI_DOMINATORS);
-
          if (!old)
            {
              /* Update PHI nodes.   We know that the new argument should
@@ -4000,11 +3941,53 @@ thread_jumps (void)
              for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
                {
                  arg = phi_arg_from_edge (phi, last);
-                 if (arg < 0)
-                   abort ();
+                 gcc_assert (arg >= 0);
                  add_phi_arg (&phi, PHI_ARG_DEF (phi, arg), e);
                }
            }
+
+         /* Update the dominators.  */
+         if (dom_computed[CDI_DOMINATORS] >= DOM_CONS_OK)
+           {
+             /* 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;
+
+                 if (old_dest->pred)
+                   break;
+
+                 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);
+
+             /* Now proceed like if we forwarded just over one edge at a time.
+                Algorithm for forwarding over edge A --> B then is
+
+                if (idom (B) == A)
+                  idom (B) = idom (A);
+                recount_idom (A);  */
+
+             for (; old_dest != dest; old_dest = tmp)
+               {
+                 tmp = old_dest->succ->dest;
+
+                 if (get_immediate_dominator (CDI_DOMINATORS, tmp) == old_dest)
+                   {
+                     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);
+               }
+           }
        }
 
       /* Reset the forwardable bit on our block since it's no longer in
@@ -4125,7 +4108,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
     case GOTO_EXPR:
       /* No non-abnormal edges should lead from a non-simple goto, and
         simple ones should be represented implicitly.  */
-      abort ();
+      gcc_unreachable ();
 
     case SWITCH_EXPR:
       {
@@ -4149,8 +4132,7 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
     default:
       /* Otherwise it must be a fallthru edge, and we don't need to
         do anything besides redirecting it.  */
-      if (!(e->flags & EDGE_FALLTHRU))
-       abort ();
+      gcc_assert (e->flags & EDGE_FALLTHRU);
       break;
     }
 
@@ -4169,8 +4151,7 @@ static basic_block
 tree_redirect_edge_and_branch_force (edge e, basic_block dest)
 {
   e = tree_redirect_edge_and_branch (e, dest);
-  if (!e)
-    abort ();
+  gcc_assert (e);
 
   return NULL;
 }
@@ -4259,8 +4240,16 @@ tree_duplicate_bb (basic_block bb)
 {
   basic_block new_bb;
   block_stmt_iterator bsi, bsi_tgt;
+  tree phi, val;
+  ssa_op_iter op_iter;
 
   new_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb);
+
+  for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+    {
+      mark_for_rewrite (PHI_RESULT (phi));
+    }
+
   bsi_tgt = bsi_start (new_bb);
   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
     {
@@ -4270,6 +4259,12 @@ tree_duplicate_bb (basic_block bb)
       if (TREE_CODE (stmt) == LABEL_EXPR)
        continue;
 
+      /* Record the definitions.  */
+      get_stmt_operands (stmt);
+
+      FOR_EACH_SSA_TREE_OPERAND (val, stmt, op_iter, SSA_OP_ALL_DEFS)
+       mark_for_rewrite (val);
+
       copy = unshare_expr (stmt);
 
       /* Copy also the virtual operands.  */
@@ -4332,6 +4327,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
   if (basic_block_info)
     {
       /* Make a CFG based dump.  */
+      check_bb_profile (ENTRY_BLOCK_PTR, file);
       if (!ignore_topmost_bind)
        fprintf (file, "{\n");
 
@@ -4342,6 +4338,7 @@ dump_function_to_file (tree fn, FILE *file, int flags)
        dump_generic_bb (file, bb, 2, flags);
        
       fprintf (file, "}\n");
+      check_bb_profile (EXIT_BLOCK_PTR, file);
     }
   else
     {
@@ -4629,8 +4626,7 @@ tree_flow_call_edges_add (sbitmap blocks)
 #ifdef ENABLE_CHECKING
                  if (stmt == last_stmt)
                    for (e = bb->succ; e; e = e->succ_next)
-                     if (e->dest == EXIT_BLOCK_PTR)
-                       abort ();
+                     gcc_assert (e->dest != EXIT_BLOCK_PTR);
 #endif
 
                  /* Note that the following may create a new basic block
@@ -4746,8 +4742,82 @@ struct tree_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  TODO_dump_func,                             /* todo_flags_finish */
+  TODO_dump_func,                /* todo_flags_finish */
+  0                              /* letter */
 };
+
+\f
+/* Return EXP if it is a valid GIMPLE rvalue, else gimplify it into
+   a temporary, make sure and register it to be renamed if necessary,
+   and finally return the temporary.  Put the statements to compute
+   EXP before the current statement in BSI.  */
+
+tree
+gimplify_val (block_stmt_iterator *bsi, tree type, tree exp)
+{
+  tree t, new_stmt, orig_stmt;
+
+  if (is_gimple_val (exp))
+    return exp;
+
+  t = make_rename_temp (type, NULL);
+  new_stmt = build (MODIFY_EXPR, type, t, exp);
+
+  orig_stmt = bsi_stmt (*bsi);
+  SET_EXPR_LOCUS (new_stmt, EXPR_LOCUS (orig_stmt));
+  TREE_BLOCK (new_stmt) = TREE_BLOCK (orig_stmt);
+
+  bsi_insert_before (bsi, new_stmt, BSI_SAME_STMT);
+
+  return t;
+}
+
+/* Build a ternary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build3 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b, tree c)
+{
+  tree ret;
+
+  ret = fold (build3 (code, type, a, b, c));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a binary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build2 (block_stmt_iterator *bsi, enum tree_code code,
+                tree type, tree a, tree b)
+{
+  tree ret;
+
+  ret = fold (build2 (code, type, a, b));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+/* Build a unary operation and gimplify it.  Emit code before BSI.
+   Return the gimple_val holding the result.  */
+
+tree
+gimplify_build1 (block_stmt_iterator *bsi, enum tree_code code, tree type,
+                tree a)
+{
+  tree ret;
+
+  ret = fold (build1 (code, type, a));
+  STRIP_NOPS (ret);
+
+  return gimplify_val (bsi, type, ret);
+}
+
+
 \f
 /* Emit return warnings.  */
 
@@ -4867,7 +4937,8 @@ struct tree_opt_pass pass_warn_function_return =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0                                    /* todo_flags_finish */
+  0,                                   /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 #include "gt-tree-cfg.h"