OSDN Git Service

* flow.c (try_redirect_by_replacing_jump): Remove cc0 setter.
[pf3gnuchains/gcc-fork.git] / gcc / flow.c
index b3d4327..391b4b4 100644 (file)
@@ -364,12 +364,10 @@ typedef struct depth_first_search_dsS *depth_first_search_ds;
 static int count_basic_blocks          PARAMS ((rtx));
 static void find_basic_blocks_1                PARAMS ((rtx));
 static rtx find_label_refs             PARAMS ((rtx, rtx));
-static void clear_edges                        PARAMS ((void));
 static void make_edges                 PARAMS ((rtx));
 static void make_label_edge            PARAMS ((sbitmap *, basic_block,
                                                 rtx, int));
 static void make_eh_edge               PARAMS ((sbitmap *, basic_block, rtx));
-static void mark_critical_edges                PARAMS ((void));
 
 static void commit_one_edge_insertion  PARAMS ((edge));
 
@@ -383,7 +381,12 @@ static int merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
 static int merge_blocks_move_successor_nojumps PARAMS ((basic_block,
                                                        basic_block));
 static int merge_blocks                        PARAMS ((edge,basic_block,basic_block));
-static void try_merge_blocks           PARAMS ((void));
+static bool try_optimize_cfg           PARAMS ((void));
+static bool forwarder_block_p          PARAMS ((basic_block));
+static bool can_fallthru               PARAMS ((basic_block, basic_block));
+static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
+static bool try_simplify_condjump      PARAMS ((basic_block));
+static bool try_forward_edges          PARAMS ((basic_block));
 static void tidy_fallthru_edges                PARAMS ((void));
 static int verify_wide_reg_1           PARAMS ((rtx *, void *));
 static void verify_wide_reg            PARAMS ((int, rtx, rtx));
@@ -434,7 +437,6 @@ static void mark_used_regs          PARAMS ((struct propagate_block_info *,
                                                 rtx, rtx, rtx));
 void dump_flow_info                    PARAMS ((FILE *));
 void debug_flow_info                   PARAMS ((void));
-static void dump_edge_info             PARAMS ((FILE *, edge, int));
 static void print_rtl_and_abort_fcn    PARAMS ((const char *, int,
                                                 const char *))
                                        ATTRIBUTE_NORETURN;
@@ -456,7 +458,6 @@ static int flow_loop_entry_edges_find       PARAMS ((basic_block, const sbitmap,
                                                 edge **));
 static int flow_loop_exit_edges_find   PARAMS ((const sbitmap, edge **));
 static int flow_loop_nodes_find        PARAMS ((basic_block, basic_block, sbitmap));
-static int flow_depth_first_order_compute PARAMS ((int *, int *));
 static void flow_dfs_compute_reverse_init
   PARAMS ((depth_first_search_ds));
 static void flow_dfs_compute_reverse_add_bb
@@ -474,6 +475,8 @@ static int flow_loop_level_compute  PARAMS ((struct loop *, int));
 static int flow_loops_level_compute    PARAMS ((struct loops *));
 static void allocate_bb_life_data      PARAMS ((void));
 static void find_sub_basic_blocks      PARAMS ((basic_block));
+static bool redirect_edge_and_branch   PARAMS ((edge, basic_block));
+static rtx block_label                 PARAMS ((basic_block));
 \f
 /* Find basic blocks of the current function.
    F is the first insn of the function and NREGS the number of register
@@ -1011,7 +1014,8 @@ void
 cleanup_cfg ()
 {
   delete_unreachable_blocks ();
-  try_merge_blocks ();
+  if (try_optimize_cfg ())
+    delete_unreachable_blocks ();
   mark_critical_edges ();
 
   /* Kill the data we won't maintain.  */
@@ -1118,7 +1122,7 @@ compute_bb_for_insn (max)
 
 /* Free the memory associated with the edge structures.  */
 
-static void
+void
 clear_edges ()
 {
   int i;
@@ -1432,7 +1436,7 @@ make_eh_edge (edge_cache, src, insn)
 
 /* Identify critical edges and set the bits appropriately.  */
 
-static void
+void
 mark_critical_edges ()
 {
   int i, n = n_basic_blocks;
@@ -1577,6 +1581,266 @@ split_block (bb, insn)
   return new_edge;
 }
 
+/* Return label in the head of basic block.  Create one if it doesn't exist.  */
+static rtx
+block_label (block)
+     basic_block block;
+{
+  if (GET_CODE (block->head) != CODE_LABEL)
+    block->head = emit_label_before (gen_label_rtx (), block->head);
+  return block->head;
+}
+
+/* Return true if the block has no effect and only forwards control flow to
+   its single destination.  */
+static bool
+forwarder_block_p (bb)
+     basic_block bb;
+{
+  rtx insn = bb->head;
+  if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR
+      || !bb->succ || bb->succ->succ_next)
+    return false;
+
+  while (insn != bb->end)
+    {
+      if (active_insn_p (insn))
+       return false;
+      insn = NEXT_INSN (insn);
+    }
+  return (!active_insn_p (insn)
+         || (GET_CODE (insn) == JUMP_INSN && onlyjump_p (insn)));
+}
+
+/* Return nonzero if we can reach target from src by falling trought.  */
+static bool
+can_fallthru (src, target)
+     basic_block src, target;
+{
+  rtx insn = src->end;
+  rtx insn2 = target->head;
+
+  if (!active_insn_p (insn2))
+    insn2 = next_active_insn (insn2);
+  /* ??? Later we may add code to move jump tables offline.  */
+  return next_active_insn (insn) == insn2;
+}
+
+/* Attempt to perform edge redirection by replacing possibly complex jump
+   instruction by unconditional jump or removing jump completely.
+   This can apply only if all edges now point to the same block. 
+
+   The parameters and return values are equivalent to redirect_edge_and_branch.
+ */
+static bool
+try_redirect_by_replacing_jump (e, target)
+     edge e;
+     basic_block target;
+{
+  basic_block src = e->src;
+  rtx insn = src->end;
+  edge tmp;
+  rtx set;
+  int fallthru = 0;
+  rtx barrier;
+
+  /* Verify that all targets will be TARGET.  */
+  for (tmp = src->succ; tmp; tmp = tmp->succ_next)
+    if (tmp->dest != target && tmp != e)
+      break;
+  if (tmp || GET_CODE (insn) != JUMP_INSN)
+    return false;
+
+  /* Avoid removing branch with side effects.  */
+  set = single_set (insn);
+  if (!set || side_effects_p (set))
+    return false;
+
+  /* See if we can create the fallthru edge.  */
+  if (can_fallthru (src, target))
+    {
+      src->end = PREV_INSN (insn);
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Removing jump %i.\n", INSN_UID (insn));
+      flow_delete_insn (insn);
+      fallthru = 1;
+      insn = src->end;
+    }
+  /* If this already is simplejump, redirect it.  */
+  else if (simplejump_p (insn))
+    {
+      if (e->dest == target)
+       return false;
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Redirecting jump %i from %i to %i.\n",
+                INSN_UID (insn), e->dest->index, target->index);
+      redirect_jump (insn, block_label (target), 0);
+    }
+  /* Or replace possibly complicated jump insn by simple jump insn.  */
+  else
+    {
+      rtx target_label = block_label (target);
+
+      src->end = PREV_INSN (insn);
+      src->end = emit_jump_insn_after (gen_jump (target_label), src->end);
+      JUMP_LABEL (src->end) = target_label;
+      LABEL_NUSES (target_label)++;
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Replacing insn %i by jump %i\n",
+                INSN_UID (insn), INSN_UID (src->end));
+      flow_delete_insn (insn);
+      insn = src->end;
+    }
+
+  /* Keep only one edge out and set proper flags.  */
+  while (src->succ->succ_next)
+    remove_edge (src->succ);
+  e = src->succ;
+  if (fallthru)
+    e->flags = EDGE_FALLTHRU;
+  else
+    e->flags = 0;
+  e->probability = REG_BR_PROB_BASE;
+  e->count = src->count;
+
+  /* Fixup barriers.  */
+  barrier = next_nonnote_insn (insn);
+  if (fallthru && GET_CODE (barrier) == BARRIER)
+    flow_delete_insn (barrier);
+  else if (!fallthru && GET_CODE (barrier) != BARRIER)
+    emit_barrier_after (insn);
+
+  /* In case we've zapped an conditional jump, we need to kill the cc0
+     setter too if available.  */
+#ifdef HAVE_cc0
+  insn = src->end;
+  if (GET_CODE (insn) == JUMP_INSN)
+    insn = prev_nonnote_insn (insn);
+  if (sets_cc0_p (insn))
+    {
+      if (insn == src->end)
+       src->end = PREV_INSN (insn);
+      flow_delete_insn (insn);
+    }
+#endif
+
+  if (e->dest != target)
+    redirect_edge_succ (e, target);
+  return true;
+}
+
+/* Attempt to change code to redirect edge E to TARGET.
+   Don't do that on expense of adding new instructions or reordering
+   basic blocks.
+
+   Function can be also called with edge destionation equivalent to the
+   TARGET.  Then it should try the simplifications and do nothing if
+   none is possible.
+
+   Return true if transformation suceeded.  We still return flase in case
+   E already destinated TARGET and we didn't managed to simplify instruction
+   stream.  */
+static bool
+redirect_edge_and_branch (e, target)
+     edge e;
+     basic_block target;
+{
+  rtx tmp;
+  rtx old_label = e->dest->head;
+  basic_block src = e->src;
+  rtx insn = src->end;
+
+  if (try_redirect_by_replacing_jump (e, target))
+    return true;
+  /* Do this fast path late, as we want above code to simplify for cases
+     where called on single edge leaving basic block containing nontrivial
+     jump insn.  */
+  else if (e->dest == target)
+    return false;
+
+  /* We can only redirect non-fallthru edges of jump insn.  */
+  if (e->flags & EDGE_FALLTHRU)
+    return false;
+  if (GET_CODE (insn) != JUMP_INSN)
+    return false;
+
+  /* Recognize a tablejump and adjust all matching cases.  */
+  if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
+      && (tmp = NEXT_INSN (tmp)) != NULL_RTX
+      && GET_CODE (tmp) == JUMP_INSN
+      && (GET_CODE (PATTERN (tmp)) == ADDR_VEC
+         || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
+    {
+      rtvec vec;
+      int j;
+      rtx new_label = block_label (target);
+
+      if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
+       vec = XVEC (PATTERN (tmp), 0);
+      else
+       vec = XVEC (PATTERN (tmp), 1);
+
+      for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
+       if (XEXP (RTVEC_ELT (vec, j), 0) == old_label)
+         {
+           RTVEC_ELT (vec, j) = gen_rtx_LABEL_REF (Pmode, new_label);
+           --LABEL_NUSES (old_label);
+           ++LABEL_NUSES (new_label);
+         }
+
+      /* Handle casesi dispatch insns */
+      if ((tmp = single_set (insn)) != NULL
+         && SET_DEST (tmp) == pc_rtx
+         && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
+         && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
+         && XEXP (XEXP (SET_SRC (tmp), 2), 0) == old_label)
+       {
+         XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (VOIDmode,
+                                                      new_label);
+         --LABEL_NUSES (old_label);
+         ++LABEL_NUSES (new_label);
+       }
+    }
+  else
+    {
+      /* ?? We may play the games with moving the named labels from
+        one basic block to the other in case only one computed_jump is
+        available.  */
+      if (computed_jump_p (insn))
+       return false;
+
+      /* A return instruction can't be redirected.  */
+      if (returnjump_p (insn))
+       return false;
+
+      /* If the insn doesn't go where we think, we're confused.  */
+      if (JUMP_LABEL (insn) != old_label)
+       abort ();
+      redirect_jump (insn, block_label (target), 0);
+    }
+
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Edge %i->%i redirected to %i\n",
+            e->src->index, e->dest->index, target->index);
+  if (e->dest != target)
+    {
+      edge s;
+      /* Check whether the edge is already present.  */
+      for (s = src->succ; s; s=s->succ_next)
+       if (s->dest == target)
+         break;
+      if (s)
+       {
+         s->flags |= e->flags;
+         s->probability += e->probability;
+         s->count += e->count;
+         remove_edge (e);
+       }
+      else
+       redirect_edge_succ (e, target);
+    }
+  return true;
+}
 
 /* Split a (typically critical) edge.  Return the new block.
    Abort on abnormal edges.
@@ -1601,15 +1865,6 @@ split_edge (edge_in)
   old_pred = edge_in->src;
   old_succ = edge_in->dest;
 
-  /* Remove the existing edge from the destination's pred list.  */
-  {
-    edge *pp;
-    for (pp = &old_succ->pred; *pp != edge_in; pp = &(*pp)->pred_next)
-      continue;
-    *pp = edge_in->pred_next;
-    edge_in->pred_next = NULL;
-  }
-
   /* Create the new structures.  */
   bb = (basic_block) obstack_alloc (&flow_obstack, sizeof (*bb));
   edge_out = (edge) xcalloc (1, sizeof (*edge_out));
@@ -1627,12 +1882,11 @@ split_edge (edge_in)
     }
 
   /* Wire them up.  */
-  bb->pred = edge_in;
   bb->succ = edge_out;
   bb->count = edge_in->count;
-  /* ??? Set bb->frequency.  */
+  bb->frequency = (edge_in->probability * edge_in->src->frequency
+                  / REG_BR_PROB_BASE);
 
-  edge_in->dest = bb;
   edge_in->flags &= ~EDGE_CRITICAL;
 
   edge_out->pred_next = old_succ->pred;
@@ -1745,73 +1999,15 @@ split_edge (edge_in)
   NOTE_BASIC_BLOCK (bb_note) = bb;
   bb->head = bb->end = bb_note;
 
-  /* Not quite simple -- for non-fallthru edges, we must adjust the
-     predecessor's jump instruction to target our new block.  */
+  /* For non-fallthry edges, we must adjust the predecessor's
+     jump instruction to target our new block.  */
   if ((edge_in->flags & EDGE_FALLTHRU) == 0)
     {
-      rtx tmp, insn = old_pred->end;
-      rtx old_label = old_succ->head;
-      rtx new_label = gen_label_rtx ();
-
-      if (GET_CODE (insn) != JUMP_INSN)
+      if (!redirect_edge_and_branch (edge_in, bb))
        abort ();
-
-      /* ??? Recognize a tablejump and adjust all matching cases.  */
-      if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
-         && (tmp = NEXT_INSN (tmp)) != NULL_RTX
-         && GET_CODE (tmp) == JUMP_INSN
-         && (GET_CODE (PATTERN (tmp)) == ADDR_VEC
-             || GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC))
-       {
-         rtvec vec;
-         int j;
-
-         if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
-           vec = XVEC (PATTERN (tmp), 0);
-         else
-           vec = XVEC (PATTERN (tmp), 1);
-
-         for (j = GET_NUM_ELEM (vec) - 1; j >= 0; --j)
-           if (XEXP (RTVEC_ELT (vec, j), 0) == old_label)
-             {
-               RTVEC_ELT (vec, j) = gen_rtx_LABEL_REF (VOIDmode, new_label);
-               --LABEL_NUSES (old_label);
-               ++LABEL_NUSES (new_label);
-             }
-
-         /* Handle casesi dispatch insns */
-         if ((tmp = single_set (insn)) != NULL
-             && SET_DEST (tmp) == pc_rtx
-             && GET_CODE (SET_SRC (tmp)) == IF_THEN_ELSE
-             && GET_CODE (XEXP (SET_SRC (tmp), 2)) == LABEL_REF
-             && XEXP (XEXP (SET_SRC (tmp), 2), 0) == old_label)
-           {
-             XEXP (SET_SRC (tmp), 2) = gen_rtx_LABEL_REF (VOIDmode,
-                                                          new_label);
-             --LABEL_NUSES (old_label);
-             ++LABEL_NUSES (new_label);
-           }
-       }
-      else
-       {
-         /* This would have indicated an abnormal edge.  */
-         if (computed_jump_p (insn))
-           abort ();
-
-         /* A return instruction can't be redirected.  */
-         if (returnjump_p (insn))
-           abort ();
-
-         /* If the insn doesn't go where we think, we're confused.  */
-         if (JUMP_LABEL (insn) != old_label)
-           abort ();
-
-         redirect_jump (insn, new_label, 0);
-       }
-
-      emit_label_before (new_label, bb_note);
-      bb->head = new_label;
     }
+  else
+    redirect_edge_succ (edge_in, bb);
 
   return bb;
 }
@@ -2314,6 +2510,19 @@ flow_delete_insn (insn)
           && GET_CODE (XEXP (note, 0)) == CODE_LABEL)
     LABEL_NUSES (XEXP (note, 0))--;
 
+  if (GET_CODE (insn) == JUMP_INSN
+      && (GET_CODE (PATTERN (insn)) == ADDR_VEC
+         || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
+    {
+      rtx pat = PATTERN (insn);
+      int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
+      int len = XVECLEN (pat, diff_vec_p);
+      int i;
+
+      for (i = 0; i < len; i++)
+       LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
+    }
+
   return next;
 }
 
@@ -2651,37 +2860,211 @@ merge_blocks (e, b, c)
     }
 }
 
-/* Top level driver for merge_blocks.  */
+/* Simplify conditional jump around an jump.  
+   Return nonzero in case optimization matched.  */
 
-static void
-try_merge_blocks ()
+static bool
+try_simplify_condjump (src)
+     basic_block src;
+{
+  basic_block final_block, next_block;
+  rtx insn = src->end;
+  edge branch, fallthru;
+
+  if (!any_condjump_p (insn))
+    return false;
+
+  fallthru = FALLTHRU_EDGE (src);
+
+  /* Following block must be simple forwarder block with single
+     entry and must not be last in the stream.  */
+  next_block = fallthru->dest;
+  if (!forwarder_block_p (next_block)
+      || next_block->pred->pred_next
+      || next_block->index == n_basic_blocks - 1)
+    return false;
+
+  /* The branch must target to block afterwards.  */
+  final_block = BASIC_BLOCK (next_block->index + 1);
+
+  branch = BRANCH_EDGE (src);
+
+  if (branch->dest != final_block)
+    return false;
+
+  /* Avoid jump.c from being overactive on removin ureachable insns.  */
+  LABEL_NUSES (JUMP_LABEL (insn))++;
+  if (!invert_jump (insn, block_label (next_block->succ->dest), 1))
+    {
+      LABEL_NUSES (JUMP_LABEL (insn))--;
+      return false;
+    }
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Simplifying condjump %i around jump %i\n",
+            INSN_UID (insn), INSN_UID (next_block->end));
+
+  redirect_edge_succ (branch, final_block);
+  redirect_edge_succ (fallthru, next_block->succ->dest);
+
+  branch->flags |= EDGE_FALLTHRU;
+  fallthru->flags &= ~EDGE_FALLTHRU;
+  
+  flow_delete_block (next_block);
+  return true;
+}
+
+/* Attempt to forward edges leaving basic block B.
+   Return nonzero if sucessfull.  */
+
+static bool
+try_forward_edges (b)
+     basic_block b;
+{
+  bool changed = 0;
+  edge e;
+  for (e = b->succ; e; e = e->succ_next)
+    {
+      basic_block target = e->dest, first = e->dest;
+      int counter = 0;
+
+      /* Look for the real destination of jump.
+         Avoid inifinite loop in the infinite empty loop by counting
+         up to n_basic_blocks.  */
+      while (forwarder_block_p (target)
+            && target->succ->dest != EXIT_BLOCK_PTR
+            && counter < n_basic_blocks)
+       {
+         /* Bypass trivial infinite loops.  */
+         if (target == target->succ->dest)
+           counter = n_basic_blocks;
+         target = target->succ->dest, counter++;
+       }
+
+      if (target != first && counter < n_basic_blocks
+         && redirect_edge_and_branch (e, target))
+       {
+         while (first != target)
+           {
+             first->count -= e->count;
+             first->succ->count -= e->count;
+             first->frequency -= ((e->probability * b->frequency
+                                   + REG_BR_PROB_BASE / 2)
+                                  / REG_BR_PROB_BASE);
+             first = first->succ->dest;
+           }
+         /* We've possibly removed the edge.  */
+         changed = 1;
+         e = b->succ;
+       }
+      else if (rtl_dump_file && counter == n_basic_blocks)
+       fprintf (rtl_dump_file, "Infinite loop in BB %i.\n", target->index);
+      else if (rtl_dump_file && first != target)
+       fprintf (rtl_dump_file,
+                "Forwarding edge %i->%i to %i failed.\n", b->index,
+                e->dest->index, target->index);
+    }
+  return changed;
+}
+
+/* Do simple CFG optimizations - basic block merging, simplifying of jump
+   instructions etc.
+
+   Return nonzero in case some optimizations matched.  */
+
+static bool
+try_optimize_cfg ()
 {
   int i;
+  bool changed_overall = 0;
+  bool changed;
 
   /* Attempt to merge blocks as made possible by edge removal.  If a block
      has only one successor, and the successor has only one predecessor,
      they may be combined.  */
 
-  for (i = 0; i < n_basic_blocks;)
+  do
     {
-      basic_block c, b = BASIC_BLOCK (i);
-      edge s;
+      changed = 0;
+      for (i = 0; i < n_basic_blocks;)
+       {
+         basic_block c, b = BASIC_BLOCK (i);
+         edge s;
+         int changed_here = 0;
 
-      /* A loop because chains of blocks might be combineable.  */
-      while ((s = b->succ) != NULL
-            && s->succ_next == NULL
-            && (s->flags & EDGE_EH) == 0
-            && (c = s->dest) != EXIT_BLOCK_PTR
-            && c->pred->pred_next == NULL
-            /* If the jump insn has side effects, we can't kill the edge.  */
-            && (GET_CODE (b->end) != JUMP_INSN
-                || onlyjump_p (b->end))
-            && merge_blocks (s, b, c))
-       continue;
+         /* Delete trivially dead basic block.  */
+         if (b->pred == NULL)
+           {
+             c = BASIC_BLOCK (i - 1);
+             if (rtl_dump_file)
+               fprintf (rtl_dump_file, "Deleting block %i.\n", b->index);
+             flow_delete_block (b);
+             changed = 1;
+             b = c;
+           }
+         /* The fallthru forwarder block can be deleted.  */
+         if (b->pred->pred_next == NULL
+             && forwarder_block_p (b)
+             && (b->pred->flags & EDGE_FALLTHRU)
+             && (b->succ->flags & EDGE_FALLTHRU))
+           {
+             if (rtl_dump_file)
+               fprintf (rtl_dump_file, "Deleting fallthru block %i.\n",
+                        b->index);
+             c = BASIC_BLOCK (i ? i - 1 : i + 1);
+             redirect_edge_succ (b->pred, b->succ->dest);
+             flow_delete_block (b);
+             changed = 1;
+             b = c;
+           }
 
-      /* Don't get confused by the index shift caused by deleting blocks.  */
-      i = b->index + 1;
+         /* A loop because chains of blocks might be combineable.  */
+         while ((s = b->succ) != NULL
+                && s->succ_next == NULL
+                && (s->flags & EDGE_EH) == 0
+                && (c = s->dest) != EXIT_BLOCK_PTR
+                && c->pred->pred_next == NULL
+                /* If the jump insn has side effects, we can't kill the edge.  */
+                && (GET_CODE (b->end) != JUMP_INSN
+                    || onlyjump_p (b->end)) && merge_blocks (s, b, c))
+           changed_here = 1;
+
+         if (try_simplify_condjump (b))
+           changed_here = 1;
+
+         /* In the case basic blocks has single outgoing edge, but over by the
+            non-trivial jump instruction, we can replace it by unconditional
+            jump, or delete the jump completely.  Use logic of
+            redirect_edge_and_branch to do the dirty job for us.  
+
+            We match cases as conditional jumps jumping to the next block or
+            dispatch tables.  */
+
+         if (b->succ
+             && b->succ->succ_next == NULL
+             && GET_CODE (b->end) == JUMP_INSN
+             && b->succ->dest != EXIT_BLOCK_PTR
+             && redirect_edge_and_branch (b->succ, b->succ->dest))
+           changed_here = 1;
+
+         if (try_forward_edges (b))
+           changed_here = 1;
+
+         /* Don't get confused by the index shift caused by deleting
+            blocks.  */
+         if (!changed_here)
+           i = b->index + 1;
+         else
+           changed = 1;
+       }
+      changed_overall |= changed;
+      changed = 0;
     }
+  while (changed);
+#ifdef ENABLE_CHECKING
+  if (changed)
+    verify_flow_info ();
+#endif
+  return changed_overall;
 }
 
 /* The given edge should potentially be a fallthru edge.  If that is in
@@ -3094,8 +3477,11 @@ free_basic_block_vars (keep_head_end_p)
 
   if (! keep_head_end_p)
     {
-      clear_edges ();
-      VARRAY_FREE (basic_block_info);
+      if (basic_block_info)
+       {
+         clear_edges ();
+         VARRAY_FREE (basic_block_info);
+       }
       n_basic_blocks = 0;
 
       ENTRY_BLOCK_PTR->aux = NULL;
@@ -4857,7 +5243,8 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
                     register twice if it is modified, but that is correct.  */
                  REG_N_SETS (i) += 1;
                  REG_N_REFS (i) += 1;
-                 REG_FREQ (i) += (optimize_size ? 1 : pbi->bb->loop_depth + 1);
+                 REG_FREQ (i) += (optimize_size || !pbi->bb->frequency
+                                  ? 1 : pbi->bb->frequency);
 
                  /* The insns where a reg is live are normally counted
                     elsewhere, but we want the count to include the insn
@@ -5524,7 +5911,8 @@ attempt_auto_inc (pbi, inc, insn, mem, incr, incr_reg)
       /* Count an extra reference to the reg.  When a reg is
         incremented, spilling it is worse, so we want to make
         that less likely.  */
-      REG_FREQ (regno) += (optimize_size ? 1 : pbi->bb->loop_depth + 1);
+      REG_FREQ (regno) += (optimize_size || !pbi->bb->frequency
+                          ? 1 : pbi->bb->frequency);
 
       /* Count the increment as a setting of the register,
         even though it isn't a SET in rtl.  */
@@ -5690,7 +6078,7 @@ mark_used_reg (pbi, reg, cond, insn)
 
          /* Count (weighted) number of uses of each reg.  */
          REG_FREQ (regno_first)
-           += (optimize_size ? 1 : pbi->bb->loop_depth + 1);
+           += (optimize_size || !pbi->bb->frequency ? 1 : pbi->bb->frequency);
          REG_N_REFS (regno_first)++;
        }
     }
@@ -6112,7 +6500,8 @@ try_pre_increment_1 (pbi, insn)
         so we want to make that less likely.  */
       if (regno >= FIRST_PSEUDO_REGISTER)
        {
-         REG_FREQ (regno) += (optimize_size ? 1 : pbi->bb->loop_depth + 1);
+         REG_FREQ (regno) += (optimize_size || !pbi->bb->frequency
+                              ? 1 : pbi->bb->frequency);
          REG_N_SETS (regno)++;
        }
 
@@ -6390,7 +6779,7 @@ debug_flow_info ()
   dump_flow_info (stderr);
 }
 
-static void
+void
 dump_edge_info (file, e, do_succ)
      FILE *file;
      edge e;
@@ -6405,6 +6794,9 @@ dump_edge_info (file, e, do_succ)
   else
     fprintf (file, " %d", side->index);
 
+  if (e->probability)
+    fprintf (file, " [%.1f%%] ", e->probability * 100.0 / REG_BR_PROB_BASE);
+
   if (e->count)
     {
       fprintf (file, " count:");
@@ -6450,7 +6842,7 @@ dump_bb (bb, outf)
   edge e;
 
   fprintf (outf, ";; Basic block %d, loop depth %d, count ",
-          bb->index, bb->loop_depth, bb->count);
+          bb->index, bb->loop_depth);
   fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
   putc ('\n', outf);
 
@@ -7849,7 +8241,7 @@ flow_loop_nodes_find (header, latch, nodes)
   tries to get as far away from the starting point as quickly as
   possible.  */
 
-static int
+int
 flow_depth_first_order_compute (dfs_order, rc_order)
      int *dfs_order;
      int *rc_order;