OSDN Git Service

* tree-ssa-loop-ivopts.c: New file.
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index 20de625..6dba6c1 100644 (file)
@@ -56,18 +56,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "insn-config.h"
 #include "cfglayout.h"
 #include "expr.h"
+#include "target.h"
 
-/* Stubs in case we don't have a return insn.  */
-#ifndef HAVE_return
-#define HAVE_return 0
-#define gen_return() NULL_RTX
-#endif
 
 /* The labels mentioned in non-jump rtl.  Valid during find_basic_blocks.  */
 /* ??? Should probably be using LABEL_NUSES instead.  It would take a
    bit of surgery to be able to use or co-opt the routines in jump.  */
 rtx label_value_list;
-rtx tail_recursion_label_list;
 
 static int can_delete_note_p (rtx);
 static int can_delete_label_p (rtx);
@@ -79,12 +74,12 @@ static basic_block rtl_split_edge (edge);
 static bool rtl_move_block_after (basic_block, basic_block);
 static int rtl_verify_flow_info (void);
 static basic_block cfg_layout_split_block (basic_block, void *);
-static bool cfg_layout_redirect_edge_and_branch (edge, basic_block);
+static edge cfg_layout_redirect_edge_and_branch (edge, basic_block);
 static basic_block cfg_layout_redirect_edge_and_branch_force (edge, basic_block);
 static void cfg_layout_delete_block (basic_block);
 static void rtl_delete_block (basic_block);
 static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
-static bool rtl_redirect_edge_and_branch (edge, basic_block);
+static edge rtl_redirect_edge_and_branch (edge, basic_block);
 static basic_block rtl_split_block (basic_block, void *);
 static void rtl_dump_bb (basic_block, FILE *, int);
 static int rtl_verify_flow_info_1 (void);
@@ -99,7 +94,7 @@ can_delete_note_p (rtx note)
 {
   return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
          || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
-         || NOTE_LINE_NUMBER (note) == NOTE_INSN_PREDICTION);
+         || NOTE_LINE_NUMBER (note) == NOTE_INSN_UNLIKELY_EXECUTED_CODE);
 }
 
 /* True if a given label can be deleted.  */
@@ -123,7 +118,7 @@ delete_insn (rtx insn)
   rtx note;
   bool really_delete = true;
 
-  if (GET_CODE (insn) == CODE_LABEL)
+  if (LABEL_P (insn))
     {
       /* Some labels can't be directly removed from the INSN chain, as they
          might be references via variables, constant pool etc.
@@ -135,7 +130,7 @@ delete_insn (rtx insn)
          really_delete = false;
          PUT_CODE (insn, NOTE);
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
-         NOTE_SOURCE_FILE (insn) = name;
+         NOTE_DELETED_LABEL_NAME (insn) = name;
        }
 
       remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
@@ -152,23 +147,23 @@ delete_insn (rtx insn)
 
   /* If deleting a jump, decrement the use count of the label.  Deleting
      the label itself should happen in the normal course of block merging.  */
-  if (GET_CODE (insn) == JUMP_INSN
+  if (JUMP_P (insn)
       && JUMP_LABEL (insn)
-      && GET_CODE (JUMP_LABEL (insn)) == CODE_LABEL)
+      && LABEL_P (JUMP_LABEL (insn)))
     LABEL_NUSES (JUMP_LABEL (insn))--;
 
   /* Also if deleting an insn that references a label.  */
   else
     {
       while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
-            && GET_CODE (XEXP (note, 0)) == CODE_LABEL)
+            && LABEL_P (XEXP (note, 0)))
        {
          LABEL_NUSES (XEXP (note, 0))--;
          remove_note (insn, note);
        }
     }
 
-  if (GET_CODE (insn) == JUMP_INSN
+  if (JUMP_P (insn)
       && (GET_CODE (PATTERN (insn)) == ADDR_VEC
          || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
     {
@@ -184,7 +179,7 @@ delete_insn (rtx insn)
          /* When deleting code in bulk (e.g. removing many unreachable
             blocks) we can delete a label that's a target of the vector
             before deleting the vector itself.  */
-         if (GET_CODE (label) != NOTE)
+         if (!NOTE_P (label))
            LABEL_NUSES (label)--;
        }
     }
@@ -223,7 +218,7 @@ delete_insn_chain (rtx start, rtx finish)
   while (1)
     {
       next = NEXT_INSN (start);
-      if (GET_CODE (start) == NOTE && !can_delete_note_p (start))
+      if (NOTE_P (start) && !can_delete_note_p (start))
        ;
       else
        next = delete_insn (start);
@@ -263,7 +258,6 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
   basic_block bb;
 
   if (bb_note
-      && ! RTX_INTEGRATED_P (bb_note)
       && (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL
       && bb->aux == NULL)
     {
@@ -271,7 +265,7 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
 
       rtx after;
 
-      if (GET_CODE (head) == CODE_LABEL)
+      if (LABEL_P (head))
        after = head;
       else
        {
@@ -291,7 +285,7 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
       if (!head && !end)
        head = end = bb_note
          = emit_note_after (NOTE_INSN_BASIC_BLOCK, get_last_insn ());
-      else if (GET_CODE (head) == CODE_LABEL && end)
+      else if (LABEL_P (head) && end)
        {
          bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK, head);
          if (head == end)
@@ -319,6 +313,7 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
   link_block (bb, after);
   BASIC_BLOCK (bb->index) = bb;
   update_bb_for_insn (bb);
+  BB_SET_PARTITION (bb, BB_UNPARTITIONED);
 
   /* Tag the block so that we know it has been used when considering
      other basic block notes.  */
@@ -357,7 +352,7 @@ cfg_layout_create_basic_block (void *head, void *end, basic_block after)
 {
   basic_block newbb = rtl_create_basic_block (head, end, after);
 
-  cfg_layout_initialize_rbi (newbb);
+  initialize_bb_rbi (newbb);
   return newbb;
 }
 \f
@@ -381,23 +376,9 @@ rtl_delete_block (basic_block b)
      and remove the associated NOTE_INSN_EH_REGION_BEG and
      NOTE_INSN_EH_REGION_END notes.  */
 
-  /* Get rid of all NOTE_INSN_PREDICTIONs and NOTE_INSN_LOOP_CONTs
-     hanging before the block.  */
-
-  for (insn = PREV_INSN (BB_HEAD (b)); insn; insn = PREV_INSN (insn))
-    {
-      if (GET_CODE (insn) != NOTE)
-       break;
-      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION
-         || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
-       NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-    }
-
   insn = BB_HEAD (b);
 
-  never_reached_warning (insn, BB_END (b));
-
-  if (GET_CODE (insn) == CODE_LABEL)
+  if (LABEL_P (insn))
     maybe_remove_eh_handler (insn);
 
   /* Include any jump table following the basic block.  */
@@ -407,7 +388,7 @@ rtl_delete_block (basic_block b)
 
   /* Include any barrier that may follow the basic block.  */
   tmp = next_nonnote_insn (end);
-  if (tmp && GET_CODE (tmp) == BARRIER)
+  if (tmp && BARRIER_P (tmp))
     end = tmp;
 
   /* Selectively delete the entire chain.  */
@@ -443,10 +424,17 @@ free_bb_for_insn (void)
 {
   rtx insn;
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) != BARRIER)
+    if (!BARRIER_P (insn))
       BLOCK_FOR_INSN (insn) = NULL;
 }
 
+/* Return RTX to emit after when we want to emit code on the entry of function.  */
+rtx
+entry_of_function (void)
+{
+  return (n_basic_blocks ? BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+}
+
 /* Update insns block within BB.  */
 
 void
@@ -456,7 +444,7 @@ update_bb_for_insn (basic_block bb)
 
   for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) != BARRIER)
+      if (!BARRIER_P (insn))
        set_block_for_insn (insn, bb);
       if (insn == BB_END (bb))
        break;
@@ -491,6 +479,7 @@ rtl_split_block (basic_block bb, void *insnp)
 
   /* Create the new basic block.  */
   new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
+  BB_COPY_PARTITION (new_bb, bb);
   BB_END (bb) = insn;
 
   /* Redirect the outgoing edges.  */
@@ -539,7 +528,7 @@ rtl_merge_blocks (basic_block a, basic_block b)
   int b_empty = 0;
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
-  if (GET_CODE (b_head) == CODE_LABEL)
+  if (LABEL_P (b_head))
     {
       /* Detect basic blocks with nothing but a label.  This can happen
         in particular at the end of a function.  */
@@ -564,12 +553,12 @@ rtl_merge_blocks (basic_block a, basic_block b)
     }
 
   /* If there was a jump out of A, delete it.  */
-  if (GET_CODE (a_end) == JUMP_INSN)
+  if (JUMP_P (a_end))
     {
       rtx prev;
 
       for (prev = PREV_INSN (a_end); ; prev = PREV_INSN (prev))
-       if (GET_CODE (prev) != NOTE
+       if (!NOTE_P (prev)
            || NOTE_LINE_NUMBER (prev) == NOTE_INSN_BASIC_BLOCK
            || prev == BB_HEAD (a))
          break;
@@ -592,7 +581,7 @@ rtl_merge_blocks (basic_block a, basic_block b)
 
       a_end = PREV_INSN (del_first);
     }
-  else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
+  else if (BARRIER_P (NEXT_INSN (a_end)))
     del_first = NEXT_INSN (a_end);
 
   /* Delete everything marked above as well as crap that might be
@@ -620,6 +609,22 @@ rtl_merge_blocks (basic_block a, basic_block b)
 static bool
 rtl_can_merge_blocks (basic_block a,basic_block b)
 {
+  /* If we are partitioning hot/cold basic blocks, we don't want to
+     mess up unconditional or indirect jumps that cross between hot
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really 
+     must be left untouched (they are required to make it safely across 
+     partition boundaries).  See  the comments at the top of 
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (flag_reorder_blocks_and_partition
+      && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
+         || find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
+         || BB_PARTITION (a) != BB_PARTITION (b)))
+    return false;
+
   /* There must be exactly one edge in between the blocks.  */
   return (a->succ && !a->succ->succ_next && a->succ->dest == b
          && !b->pred->pred_next && a != b
@@ -629,7 +634,7 @@ rtl_can_merge_blocks (basic_block a,basic_block b)
          && a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
          /* If the jump insn has side effects,
             we can't kill the edge.  */
-         && (GET_CODE (BB_END (a)) != JUMP_INSN
+         && (!JUMP_P (BB_END (a))
              || (reload_completed
                  ? simplejump_p (BB_END (a)) : onlyjump_p (BB_END (a)))));
 }
@@ -643,7 +648,7 @@ block_label (basic_block block)
   if (block == EXIT_BLOCK_PTR)
     return NULL_RTX;
 
-  if (GET_CODE (BB_HEAD (block)) != CODE_LABEL)
+  if (!LABEL_P (BB_HEAD (block)))
     {
       BB_HEAD (block) = emit_label_before (gen_label_rtx (), BB_HEAD (block));
     }
@@ -656,7 +661,7 @@ block_label (basic_block block)
    apply only if all edges now point to the same block.  The parameters and
    return values are equivalent to redirect_edge_and_branch.  */
 
-bool
+edge
 try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
 {
   basic_block src = e->src;
@@ -665,20 +670,36 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   rtx set;
   int fallthru = 0;
 
+
+  /* If we are partitioning hot/cold basic blocks, we don't want to
+     mess up unconditional or indirect jumps that cross between hot
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really 
+     must be left untouched (they are required to make it safely across 
+     partition boundaries).  See  the comments at the top of 
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+  
+  if (flag_reorder_blocks_and_partition
+      && (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
+         || BB_PARTITION (src) != BB_PARTITION (target)))
+    return NULL;
+
   /* 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 || !onlyjump_p (insn))
-    return false;
+    return NULL;
   if ((!optimize || reload_completed) && tablejump_p (insn, NULL, NULL))
-    return false;
+    return NULL;
 
   /* Avoid removing branch with side effects.  */
   set = single_set (insn);
   if (!set || side_effects_p (set))
-    return false;
+    return NULL;
 
   /* In case we zap a conditional jump, we'll need to kill
      the cc0 setter too.  */
@@ -705,7 +726,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
          /* Remove barriers but keep jumptables.  */
          while (insn)
            {
-             if (GET_CODE (insn) == BARRIER)
+             if (BARRIER_P (insn))
                {
                  if (PREV_INSN (insn))
                    NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
@@ -714,7 +735,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
                  if (NEXT_INSN (insn))
                    PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
                }
-             if (GET_CODE (insn) == CODE_LABEL)
+             if (LABEL_P (insn))
                break;
              insn = NEXT_INSN (insn);
            }
@@ -727,21 +748,21 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   else if (simplejump_p (insn))
     {
       if (e->dest == target)
-       return false;
+       return NULL;
       if (dump_file)
        fprintf (dump_file, "Redirecting jump %i from %i to %i.\n",
                 INSN_UID (insn), e->dest->index, target->index);
       if (!redirect_jump (insn, block_label (target), 0))
        {
          if (target == EXIT_BLOCK_PTR)
-           return false;
+           return NULL;
          abort ();
        }
     }
 
   /* Cannot do anything for target exit block.  */
   else if (target == EXIT_BLOCK_PTR)
-    return false;
+    return NULL;
 
   /* Or replace possibly complicated jump insn by simple jump insn.  */
   else
@@ -766,7 +787,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
        delete_insn_chain (label, table);
 
       barrier = next_nonnote_insn (BB_END (src));
-      if (!barrier || GET_CODE (barrier) != BARRIER)
+      if (!barrier || !BARRIER_P (barrier))
        emit_barrier_after (BB_END (src));
       else
        {
@@ -808,14 +829,14 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
 
   /* We don't want a block to end on a line-number note since that has
      the potential of changing the code between -g and not -g.  */
-  while (GET_CODE (BB_END (e->src)) == NOTE
+  while (NOTE_P (BB_END (e->src))
         && NOTE_LINE_NUMBER (BB_END (e->src)) >= 0)
     delete_insn (BB_END (e->src));
 
   if (e->dest != target)
     redirect_edge_succ (e, target);
 
-  return true;
+  return e;
 }
 
 /* Return last loop_beg note appearing after INSN, before start of next
@@ -831,7 +852,7 @@ last_loop_beg_note (rtx insn)
 {
   rtx last = insn;
 
-  for (insn = NEXT_INSN (insn); insn && GET_CODE (insn) == NOTE
+  for (insn = NEXT_INSN (insn); insn && NOTE_P (insn)
        && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK;
        insn = NEXT_INSN (insn))
     if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
@@ -840,8 +861,9 @@ last_loop_beg_note (rtx insn)
   return last;
 }
 
-/* Redirect edge representing branch of (un)conditional jump or tablejump.  */
-static bool
+/* Redirect edge representing branch of (un)conditional jump or tablejump,
+   NULL on failure  */
+static edge
 redirect_branch_edge (edge e, basic_block target)
 {
   rtx tmp;
@@ -851,9 +873,9 @@ redirect_branch_edge (edge e, basic_block target)
 
   /* We can only redirect non-fallthru edges of jump insn.  */
   if (e->flags & EDGE_FALLTHRU)
-    return false;
-  else if (GET_CODE (insn) != JUMP_INSN)
-    return false;
+    return NULL;
+  else if (!JUMP_P (insn))
+    return NULL;
 
   /* Recognize a tablejump and adjust all matching cases.  */
   if (tablejump_p (insn, NULL, &tmp))
@@ -863,7 +885,7 @@ redirect_branch_edge (edge e, basic_block target)
       rtx new_label = block_label (target);
 
       if (target == EXIT_BLOCK_PTR)
-       return false;
+       return NULL;
       if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
        vec = XVEC (PATTERN (tmp), 0);
       else
@@ -898,7 +920,7 @@ redirect_branch_edge (edge e, basic_block target)
       if (computed_jump_p (insn)
          /* A return instruction can't be redirected.  */
          || returnjump_p (insn))
-       return false;
+       return NULL;
 
       /* If the insn doesn't go where we think, we're confused.  */
       if (JUMP_LABEL (insn) != old_label)
@@ -910,7 +932,7 @@ redirect_branch_edge (edge e, basic_block target)
       if (!redirect_jump (insn, block_label (target), 0))
        {
          if (target == EXIT_BLOCK_PTR)
-           return false;
+           return NULL;
          abort ();
        }
     }
@@ -920,8 +942,8 @@ redirect_branch_edge (edge e, basic_block target)
             e->src->index, e->dest->index, target->index);
 
   if (e->dest != target)
-    redirect_edge_succ_nodup (e, target);
-  return true;
+    e = redirect_edge_succ_nodup (e, target);
+  return e;
 }
 
 /* Attempt to change code to redirect edge E to TARGET.  Don't do that on
@@ -930,32 +952,35 @@ redirect_branch_edge (edge e, basic_block target)
    Function can be also called with edge destination equivalent to the TARGET.
    Then it should try the simplifications and do nothing if none is possible.
 
-   Return true if transformation succeeded.  We still return false in case E
-   already destinated TARGET and we didn't managed to simplify instruction
-   stream.  */
+   Return edge representing the branch if transformation succeeded.  Return NULL
+   on failure.
+   We still return NULL in case E already destinated TARGET and we didn't
+   managed to simplify instruction stream.  */
 
-static bool
+static edge
 rtl_redirect_edge_and_branch (edge e, basic_block target)
 {
+  edge ret;
   basic_block src = e->src;
 
   if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
-    return false;
+    return NULL;
 
   if (e->dest == target)
-    return true;
+    return e;
 
-  if (try_redirect_by_replacing_jump (e, target, false))
+  if ((ret = try_redirect_by_replacing_jump (e, target, false)) != NULL)
     {
       src->flags |= BB_DIRTY;
-      return true;
+      return ret;
     }
 
-  if (!redirect_branch_edge (e, target))
-    return false;
+  ret = redirect_branch_edge (e, target);
+  if (!ret)
+    return NULL;
 
   src->flags |= BB_DIRTY;
-  return true;
+  return ret;
 }
 
 /* Like force_nonfallthru below, but additionally performs redirection
@@ -1066,6 +1091,33 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
                        target->global_live_at_start);
        }
 
+      /* Make sure new block ends up in correct hot/cold section.  */
+
+      BB_COPY_PARTITION (jump_block, e->src);
+      if (flag_reorder_blocks_and_partition
+         && targetm.have_named_sections)
+       {
+         if (BB_PARTITION (jump_block) == BB_COLD_PARTITION)
+           {
+             rtx bb_note, new_note;
+             for (bb_note = BB_HEAD (jump_block); 
+                  bb_note && bb_note != NEXT_INSN (BB_END (jump_block));
+                  bb_note = NEXT_INSN (bb_note))
+               if (NOTE_P (bb_note)
+                   && NOTE_LINE_NUMBER (bb_note) == NOTE_INSN_BASIC_BLOCK)
+                 break;
+             new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
+                                         bb_note);
+             NOTE_BASIC_BLOCK (new_note) = jump_block; 
+           }
+         if (JUMP_P (BB_END (jump_block))
+             && !any_condjump_p (BB_END (jump_block))
+             && (jump_block->succ->flags & EDGE_CROSSING))
+           REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST 
+             (REG_CROSSING_JUMP, NULL_RTX, 
+              REG_NOTES (BB_END (jump_block)));
+       }
+
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
       new_edge->probability = e->probability;
@@ -1083,10 +1135,11 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   e->flags &= ~EDGE_FALLTHRU;
   if (target == EXIT_BLOCK_PTR)
     {
-      if (HAVE_return)
+#ifdef HAVE_return
        emit_jump_insn_after (gen_return (), BB_END (jump_block));
-      else
+#else
        abort ();
+#endif
     }
   else
     {
@@ -1158,7 +1211,7 @@ rtl_tidy_fallthru_edge (edge e)
      If block B consisted only of this single jump, turn it into a deleted
      note.  */
   q = BB_END (b);
-  if (GET_CODE (q) == JUMP_INSN
+  if (JUMP_P (q)
       && onlyjump_p (q)
       && (any_uncondjump_p (q)
          || (b->succ == e && e->succ_next == NULL)))
@@ -1174,7 +1227,7 @@ rtl_tidy_fallthru_edge (edge e)
 
       /* We don't want a block to end on a line-number note since that has
         the potential of changing the code between -g and not -g.  */
-      while (GET_CODE (q) == NOTE && NOTE_LINE_NUMBER (q) >= 0)
+      while (NOTE_P (q) && NOTE_LINE_NUMBER (q) >= 0)
        q = PREV_INSN (q);
     }
 
@@ -1208,7 +1261,7 @@ back_edge_of_syntactic_loop_p (basic_block bb1, basic_block bb2)
 
   for (insn = BB_END (bb1); insn != BB_HEAD (bb2) && count >= 0;
        insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == NOTE)
+    if (NOTE_P (insn))
       {
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
          count++;
@@ -1279,7 +1332,7 @@ rtl_split_edge (edge edge_in)
 
   if (edge_in->dest != EXIT_BLOCK_PTR
       && PREV_INSN (BB_HEAD (edge_in->dest))
-      && GET_CODE (PREV_INSN (BB_HEAD (edge_in->dest))) == NOTE
+      && NOTE_P (PREV_INSN (BB_HEAD (edge_in->dest)))
       && (NOTE_LINE_NUMBER (PREV_INSN (BB_HEAD (edge_in->dest)))
          == NOTE_INSN_LOOP_BEG)
       && !back_edge_of_syntactic_loop_p (edge_in->dest, edge_in->src))
@@ -1289,7 +1342,24 @@ rtl_split_edge (edge edge_in)
   else
     before = NULL_RTX;
 
-  bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
+  /* If this is a fall through edge to the exit block, the blocks might be
+     not adjacent, and the right place is the after the source.  */
+  if (edge_in->flags & EDGE_FALLTHRU && edge_in->dest == EXIT_BLOCK_PTR)
+    {
+      before = NEXT_INSN (BB_END (edge_in->src));
+      if (before
+         && NOTE_P (before)
+         && NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END)
+       before = NEXT_INSN (before);
+      bb = create_basic_block (before, NULL, edge_in->src);
+      BB_COPY_PARTITION (bb, edge_in->src);
+    }
+  else
+    {
+      bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
+      /* ??? Why not edge_in->dest->prev_bb here?  */
+      BB_COPY_PARTITION (bb, edge_in->dest);
+    }
 
   /* ??? This info is likely going to be out of date very soon.  */
   if (edge_in->dest->global_live_at_start)
@@ -1329,14 +1399,14 @@ insert_insn_on_edge (rtx pattern, edge e)
   if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
     abort ();
 
-  if (e->insns == NULL_RTX)
+  if (e->insns.r == NULL_RTX)
     start_sequence ();
   else
-    push_to_sequence (e->insns);
+    push_to_sequence (e->insns.r);
 
   emit_insn (pattern);
 
-  e->insns = get_insns ();
+  e->insns.r = get_insns ();
   end_sequence ();
 }
 
@@ -1444,14 +1514,14 @@ commit_one_edge_insertion (edge e, int watch_calls)
   basic_block bb = NULL;
 
   /* Pull the insns off the edge now since the edge might go away.  */
-  insns = e->insns;
-  e->insns = NULL_RTX;
+  insns = e->insns.r;
+  e->insns.r = NULL_RTX;
 
   /* Special case -- avoid inserting code between call and storing
      its return value.  */
   if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next
       && e->src != ENTRY_BLOCK_PTR
-      && GET_CODE (BB_END (e->src)) == CALL_INSN)
+      && CALL_P (BB_END (e->src)))
     {
       rtx next = next_nonnote_insn (BB_END (e->src));
 
@@ -1476,10 +1546,14 @@ commit_one_edge_insertion (edge e, int watch_calls)
          /* Get the location correct wrt a code label, and "nice" wrt
             a basic block note, and before everything else.  */
          tmp = BB_HEAD (bb);
-         if (GET_CODE (tmp) == CODE_LABEL)
+         if (LABEL_P (tmp))
            tmp = NEXT_INSN (tmp);
          if (NOTE_INSN_BASIC_BLOCK_P (tmp))
            tmp = NEXT_INSN (tmp);
+         if (tmp 
+             && NOTE_P (tmp)
+             && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
+           tmp = NEXT_INSN (tmp);
          if (tmp == BB_HEAD (bb))
            before = tmp;
          else if (tmp)
@@ -1502,9 +1576,9 @@ commit_one_edge_insertion (edge e, int watch_calls)
 
             We know this block has a single successor, so we can just emit
             the queued insns before the jump.  */
-         if (GET_CODE (BB_END (bb)) == JUMP_INSN)
+         if (JUMP_P (BB_END (bb)))
            for (before = BB_END (bb);
-                GET_CODE (PREV_INSN (before)) == NOTE
+                NOTE_P (PREV_INSN (before))
                 && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
                 NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
              ;
@@ -1522,6 +1596,36 @@ commit_one_edge_insertion (edge e, int watch_calls)
        {
          bb = split_edge (e);
          after = BB_END (bb);
+
+         if (flag_reorder_blocks_and_partition
+             && targetm.have_named_sections
+             && e->src != ENTRY_BLOCK_PTR
+             && BB_PARTITION (e->src) == BB_COLD_PARTITION
+             && !(e->flags & EDGE_CROSSING))
+           {
+             rtx bb_note, new_note, cur_insn;
+
+             bb_note = NULL_RTX;
+             for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
+                  cur_insn = NEXT_INSN (cur_insn))
+               if (NOTE_P (cur_insn)
+                   && NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_BASIC_BLOCK)
+                 {
+                   bb_note = cur_insn;
+                   break;
+                 }
+
+             new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
+                                         bb_note);
+             NOTE_BASIC_BLOCK (new_note) = bb;
+             if (JUMP_P (BB_END (bb))
+                 && !any_condjump_p (BB_END (bb))
+                 && (bb->succ->flags & EDGE_CROSSING))
+               REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST 
+                 (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
+             if (after == bb_note)
+               after = new_note;
+           }
        }
     }
 
@@ -1553,7 +1657,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
       if (before)
        delete_insn (before);
     }
-  else if (GET_CODE (last) == JUMP_INSN)
+  else if (JUMP_P (last))
     abort ();
 
   /* Mark the basic block for find_sub_basic_blocks.  */
@@ -1580,10 +1684,10 @@ commit_edge_insertions (void)
       for (e = bb->succ; e; e = next)
        {
          next = e->succ_next;
-         if (e->insns)
+         if (e->insns.r)
            {
-              changed = true;
-              commit_one_edge_insertion (e, false);
+             changed = true;
+             commit_one_edge_insertion (e, false);
            }
        }
     }
@@ -1628,7 +1732,7 @@ commit_edge_insertions_watch_calls (void)
       for (e = bb->succ; e; e = next)
        {
          next = e->succ_next;
-         if (e->insns)
+         if (e->insns.r)
            {
              changed = true;
              commit_one_edge_insertion (e, true);
@@ -1734,8 +1838,8 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first)
            }
 
          if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
-             && GET_CODE (tmp_rtx) != NOTE
-             && GET_CODE (tmp_rtx) != BARRIER)
+             && !NOTE_P (tmp_rtx)
+             && !BARRIER_P (tmp_rtx))
            fprintf (outf, ";; Insn is not within a basic block\n");
          else if (in_bb_p[INSN_UID (tmp_rtx)] == IN_MULTIPLE_BB)
            fprintf (outf, ";; Insn is in multiple basic blocks\n");
@@ -1772,7 +1876,7 @@ void
 update_br_prob_note (basic_block bb)
 {
   rtx note;
-  if (GET_CODE (BB_END (bb)) != JUMP_INSN)
+  if (!JUMP_P (BB_END (bb)))
     return;
   note = find_reg_note (BB_END (bb), REG_BR_PROB, NULL_RTX);
   if (!note || INTVAL (XEXP (note, 0)) == BRANCH_EDGE (bb)->probability)
@@ -1791,6 +1895,7 @@ update_br_prob_note (basic_block bb)
    - tails of basic blocks (ensure that boundary is necessary)
    - scans body of the basic block for JUMP_INSN, CODE_LABEL
      and NOTE_INSN_BASIC_BLOCK
+   - verify that no fall_thru edge crosses hot/cold partition boundaries
 
    In future it can be extended check a lot of other stuff as well
    (reachability of basic blocks, life information, etc. etc.).  */
@@ -1878,7 +1983,18 @@ rtl_verify_flow_info_1 (void)
       for (e = bb->succ; e; e = e->succ_next)
        {
          if (e->flags & EDGE_FALLTHRU)
-           n_fallthru++, fallthru = e;
+           {
+             n_fallthru++, fallthru = e;
+             if ((e->flags & EDGE_CROSSING)
+                 || (BB_PARTITION (e->src) != BB_PARTITION (e->dest)
+                     && e->src != ENTRY_BLOCK_PTR
+                     && e->dest != EXIT_BLOCK_PTR))
+           { 
+                 error ("Fallthru edge crosses section boundary (bb %i)",
+                        e->src->index);
+                 err = 1;
+               }
+           }
 
          if ((e->flags & ~(EDGE_DFS_BACK
                            | EDGE_CAN_FALLTHRU
@@ -1902,7 +2018,7 @@ rtl_verify_flow_info_1 (void)
          err = 1;
        }
       if (n_branch
-         && (GET_CODE (BB_END (bb)) != JUMP_INSN
+         && (!JUMP_P (BB_END (bb))
              || (n_branch > 1 && (any_uncondjump_p (BB_END (bb))
                                   || any_condjump_p (BB_END (bb))))))
        {
@@ -1925,14 +2041,14 @@ rtl_verify_flow_info_1 (void)
          error ("Wrong amount of branch edges after conditional jump %i", bb->index);
          err = 1;
        }
-      if (n_call && GET_CODE (BB_END (bb)) != CALL_INSN)
+      if (n_call && !CALL_P (BB_END (bb)))
        {
          error ("Call edges for non-call insn in bb %i", bb->index);
          err = 1;
        }
       if (n_abnormal
-         && (GET_CODE (BB_END (bb)) != CALL_INSN && n_call != n_abnormal)
-         && (GET_CODE (BB_END (bb)) != JUMP_INSN
+         && (!CALL_P (BB_END (bb)) && n_call != n_abnormal)
+         && (!JUMP_P (BB_END (bb))
              || any_condjump_p (BB_END (bb))
              || any_uncondjump_p (BB_END (bb))))
        {
@@ -1960,7 +2076,7 @@ rtl_verify_flow_info_1 (void)
          block.  It ought to contain optional CODE_LABEL followed
         by NOTE_BASIC_BLOCK.  */
       x = BB_HEAD (bb);
-      if (GET_CODE (x) == CODE_LABEL)
+      if (LABEL_P (x))
        {
          if (BB_END (bb) == x)
            {
@@ -2038,10 +2154,10 @@ rtl_verify_flow_info (void)
          rtx insn;
 
          /* Ensure existence of barrier in BB with no fallthru edges.  */
-         for (insn = BB_END (bb); !insn || GET_CODE (insn) != BARRIER;
+         for (insn = BB_END (bb); !insn || !BARRIER_P (insn);
               insn = NEXT_INSN (insn))
            if (!insn
-               || (GET_CODE (insn) == NOTE
+               || (NOTE_P (insn)
                    && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK))
                {
                  error ("missing barrier after block %i", bb->index);
@@ -2064,7 +2180,7 @@ rtl_verify_flow_info (void)
          else
            for (insn = NEXT_INSN (BB_END (e->src)); insn != BB_HEAD (e->dest);
                 insn = NEXT_INSN (insn))
-             if (GET_CODE (insn) == BARRIER
+             if (BARRIER_P (insn)
 #ifndef CASE_DROPS_THROUGH
                  || INSN_P (insn)
 #else
@@ -2105,9 +2221,9 @@ rtl_verify_flow_info (void)
              break;
 
            case CODE_LABEL:
-             /* An addr_vec is placed outside any block block.  */
+             /* An addr_vec is placed outside any basic block.  */
              if (NEXT_INSN (x)
-                 && GET_CODE (NEXT_INSN (x)) == JUMP_INSN
+                 && JUMP_P (NEXT_INSN (x))
                  && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
                      || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
                x = NEXT_INSN (x);
@@ -2121,9 +2237,9 @@ rtl_verify_flow_info (void)
        }
 
       if (INSN_P (x)
-         && GET_CODE (x) == JUMP_INSN
+         && JUMP_P (x)
          && returnjump_p (x) && ! condjump_p (x)
-         && ! (NEXT_INSN (x) && GET_CODE (NEXT_INSN (x)) == BARRIER))
+         && ! (NEXT_INSN (x) && BARRIER_P (NEXT_INSN (x))))
            fatal_insn ("return not followed by barrier", x);
       if (curr_bb && x == BB_END (curr_bb))
        curr_bb = NULL;
@@ -2149,7 +2265,7 @@ purge_dead_edges (basic_block bb)
   bool purged = false;
 
   /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
-  if (GET_CODE (insn) == INSN
+  if (NONJUMP_INSN_P (insn)
       && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
     {
       rtx eqnote;
@@ -2171,7 +2287,7 @@ purge_dead_edges (basic_block bb)
        }
       else if (e->flags & EDGE_ABNORMAL_CALL)
        {
-         if (GET_CODE (BB_END (bb)) == CALL_INSN
+         if (CALL_P (BB_END (bb))
              && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
                  || INTVAL (XEXP (note, 0)) >= 0))
            continue;
@@ -2184,7 +2300,7 @@ purge_dead_edges (basic_block bb)
       purged = true;
     }
 
-  if (GET_CODE (insn) == JUMP_INSN)
+  if (JUMP_P (insn))
     {
       rtx note;
       edge b,f;
@@ -2275,7 +2391,7 @@ purge_dead_edges (basic_block bb)
 
       return purged;
     }
-  else if (GET_CODE (insn) == CALL_INSN && SIBLING_CALL_P (insn))
+  else if (CALL_P (insn) && SIBLING_CALL_P (insn))
     {
       /* First, there should not be any EH or ABCALL edges resulting
         from non-local gotos and the like.  If there were, we shouldn't
@@ -2375,23 +2491,23 @@ cfg_layout_split_block (basic_block bb, void *insnp)
 
 
 /* Redirect Edge to DEST.  */
-static bool
+static edge
 cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
 {
   basic_block src = e->src;
-  bool ret;
+  edge ret;
 
   if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
-    return false;
+    return NULL;
 
   if (e->dest == dest)
-    return true;
+    return e;
 
   if (e->src != ENTRY_BLOCK_PTR
-      && try_redirect_by_replacing_jump (e, dest, true))
+      && (ret = try_redirect_by_replacing_jump (e, dest, true)))
     {
       src->flags |= BB_DIRTY;
-      return true;
+      return ret;
     }
 
   if (e->src == ENTRY_BLOCK_PTR
@@ -2403,7 +2519,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
 
       e->src->flags |= BB_DIRTY;
       redirect_edge_succ (e, dest);
-      return true;
+      return e;
     }
 
   /* Redirect_edge_and_branch may decide to turn branch into fallthru edge
@@ -2413,7 +2529,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->flags & EDGE_FALLTHRU)
     {
       /* Redirect any branch edges unified with the fallthru one.  */
-      if (GET_CODE (BB_END (src)) == JUMP_INSN
+      if (JUMP_P (BB_END (src))
          && label_is_jump_target_p (BB_HEAD (e->dest),
                                     BB_END (src)))
        {
@@ -2426,7 +2542,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
            abort ();
          e->flags |= EDGE_FALLTHRU;
           e->src->flags |= BB_DIRTY;
-         return true;
+         return e;
        }
       /* In case we are redirecting fallthru edge to the branch edge
          of conditional jump, remove it.  */
@@ -2439,13 +2555,10 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
              && onlyjump_p (BB_END (src)))
            delete_insn (BB_END (src));
        }
-
+      ret = redirect_edge_succ_nodup (e, dest);
       if (dump_file)
        fprintf (dump_file, "Fallthru edge %i->%i redirected to %i\n",
                 e->src->index, e->dest->index, dest->index);
-      redirect_edge_succ_nodup (e, dest);
-
-      ret = true;
     }
   else
     ret = redirect_branch_edge (e, dest);
@@ -2494,7 +2607,7 @@ cfg_layout_delete_block (basic_block bb)
       insn = bb->rbi->footer;
       while (insn)
        {
-         if (GET_CODE (insn) == BARRIER)
+         if (BARRIER_P (insn))
            {
              if (PREV_INSN (insn))
                NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
@@ -2503,7 +2616,7 @@ cfg_layout_delete_block (basic_block bb)
              if (NEXT_INSN (insn))
                PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
            }
-         if (GET_CODE (insn) == CODE_LABEL)
+         if (LABEL_P (insn))
            break;
          insn = NEXT_INSN (insn);
        }
@@ -2553,6 +2666,22 @@ cfg_layout_delete_block (basic_block bb)
 static bool
 cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
 {
+  /* If we are partitioning hot/cold basic blocks, we don't want to
+     mess up unconditional or indirect jumps that cross between hot
+     and cold sections.
+
+     Basic block partitioning may result in some jumps that appear to
+     be optimizable (or blocks that appear to be mergeable), but which really 
+     must be left untouched (they are required to make it safely across 
+     partition boundaries).  See  the comments at the top of 
+     bb-reorder.c:partition_hot_cold_basic_blocks for complete details.  */
+
+  if (flag_reorder_blocks_and_partition
+      && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
+         || find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
+         || BB_PARTITION (a) != BB_PARTITION (b)))
+    return false;
+
   /* There must be exactly one edge in between the blocks.  */
   return (a->succ && !a->succ->succ_next && a->succ->dest == b
          && !b->pred->pred_next && a != b
@@ -2561,7 +2690,7 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
          && a != ENTRY_BLOCK_PTR && b != EXIT_BLOCK_PTR
          /* If the jump insn has side effects,
             we can't kill the edge.  */
-         && (GET_CODE (BB_END (a)) != JUMP_INSN
+         && (!JUMP_P (BB_END (a))
              || (reload_completed
                  ? simplejump_p (BB_END (a)) : onlyjump_p (BB_END (a)))));
 }
@@ -2576,14 +2705,14 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
 #endif
 
   /* If there was a CODE_LABEL beginning B, delete it.  */
-  if (GET_CODE (BB_HEAD (b)) == CODE_LABEL)
+  if (LABEL_P (BB_HEAD (b)))
     delete_insn (BB_HEAD (b));
 
   /* We should have fallthru edge in a, or we can do dummy redirection to get
      it cleaned up.  */
-  if (GET_CODE (BB_END (a)) == JUMP_INSN)
+  if (JUMP_P (BB_END (a)))
     try_redirect_by_replacing_jump (a->succ, b, true);
-  if (GET_CODE (BB_END (a)) == JUMP_INSN)
+  if (JUMP_P (BB_END (a)))
     abort ();
 
   /* Possible line number notes should appear in between.  */
@@ -2663,6 +2792,18 @@ cfg_layout_split_edge (edge e)
                        ? NEXT_INSN (BB_END (e->src)) : get_insns (),
                        NULL_RTX, e->src);
 
+  /* ??? This info is likely going to be out of date very soon, but we must
+     create it to avoid getting an ICE later.  */
+  if (e->dest->global_live_at_start)
+    {
+      new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      COPY_REG_SET (new_bb->global_live_at_start,
+                   e->dest->global_live_at_start);
+      COPY_REG_SET (new_bb->global_live_at_end,
+                   e->dest->global_live_at_start);
+    }
+
   new_e = make_edge (new_bb, e->dest, EDGE_FALLTHRU);
   redirect_edge_and_branch_force (e, new_bb);
 
@@ -2676,6 +2817,179 @@ rtl_make_forwarder_block (edge fallthru ATTRIBUTE_UNUSED)
 {
 }
 
+/* Return 1 if BB ends with a call, possibly followed by some
+   instructions that must stay with the call, 0 otherwise.  */
+
+static bool
+rtl_block_ends_with_call_p (basic_block bb)
+{
+  rtx insn = BB_END (bb);
+
+  while (!CALL_P (insn)
+        && insn != BB_HEAD (bb)
+        && keep_with_call_p (insn))
+    insn = PREV_INSN (insn);
+  return (CALL_P (insn));
+}
+
+/* Return 1 if BB ends with a conditional branch, 0 otherwise.  */
+
+static bool
+rtl_block_ends_with_condjump_p (basic_block bb)
+{
+  return any_condjump_p (BB_END (bb));
+}
+
+/* Return true if we need to add fake edge to exit.
+   Helper function for rtl_flow_call_edges_add.  */
+
+static bool
+need_fake_edge_p (rtx insn)
+{
+  if (!INSN_P (insn))
+    return false;
+
+  if ((CALL_P (insn)
+       && !SIBLING_CALL_P (insn)
+       && !find_reg_note (insn, REG_NORETURN, NULL)
+       && !find_reg_note (insn, REG_ALWAYS_RETURN, NULL)
+       && !CONST_OR_PURE_CALL_P (insn)))
+    return true;
+
+  return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
+          && MEM_VOLATILE_P (PATTERN (insn)))
+         || (GET_CODE (PATTERN (insn)) == PARALLEL
+             && asm_noperands (insn) != -1
+             && MEM_VOLATILE_P (XVECEXP (PATTERN (insn), 0, 0)))
+         || GET_CODE (PATTERN (insn)) == ASM_INPUT);
+}
+
+/* Add fake edges to the function exit for any non constant and non noreturn
+   calls, volatile inline assembly in the bitmap of blocks specified by
+   BLOCKS or to the whole CFG if BLOCKS is zero.  Return the number of blocks
+   that were split.
+
+   The goal is to expose cases in which entering a basic block does not imply
+   that all subsequent instructions must be executed.  */
+
+static int
+rtl_flow_call_edges_add (sbitmap blocks)
+{
+  int i;
+  int blocks_split = 0;
+  int last_bb = last_basic_block;
+  bool check_last_block = false;
+
+  if (n_basic_blocks == 0)
+    return 0;
+
+  if (! blocks)
+    check_last_block = true;
+  else
+    check_last_block = TEST_BIT (blocks, EXIT_BLOCK_PTR->prev_bb->index);
+
+  /* In the last basic block, before epilogue generation, there will be
+     a fallthru edge to EXIT.  Special care is required if the last insn
+     of the last basic block is a call because make_edge folds duplicate
+     edges, which would result in the fallthru edge also being marked
+     fake, which would result in the fallthru edge being removed by
+     remove_fake_edges, which would result in an invalid CFG.
+
+     Moreover, we can't elide the outgoing fake edge, since the block
+     profiler needs to take this into account in order to solve the minimal
+     spanning tree in the case that the call doesn't return.
+
+     Handle this by adding a dummy instruction in a new last basic block.  */
+  if (check_last_block)
+    {
+      basic_block bb = EXIT_BLOCK_PTR->prev_bb;
+      rtx insn = BB_END (bb);
+
+      /* Back up past insns that must be kept in the same block as a call.  */
+      while (insn != BB_HEAD (bb)
+            && keep_with_call_p (insn))
+       insn = PREV_INSN (insn);
+
+      if (need_fake_edge_p (insn))
+       {
+         edge e;
+
+         for (e = bb->succ; e; e = e->succ_next)
+           if (e->dest == EXIT_BLOCK_PTR)
+             {
+               insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+               commit_edge_insertions ();
+               break;
+             }
+       }
+    }
+
+  /* Now add fake edges to the function exit for any non constant
+     calls since there is no way that we can determine if they will
+     return or not...  */
+
+  for (i = 0; i < last_bb; i++)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      rtx insn;
+      rtx prev_insn;
+
+      if (!bb)
+       continue;
+
+      if (blocks && !TEST_BIT (blocks, i))
+       continue;
+
+      for (insn = BB_END (bb); ; insn = prev_insn)
+       {
+         prev_insn = PREV_INSN (insn);
+         if (need_fake_edge_p (insn))
+           {
+             edge e;
+             rtx split_at_insn = insn;
+
+             /* Don't split the block between a call and an insn that should
+                remain in the same block as the call.  */
+             if (CALL_P (insn))
+               while (split_at_insn != BB_END (bb)
+                      && keep_with_call_p (NEXT_INSN (split_at_insn)))
+                 split_at_insn = NEXT_INSN (split_at_insn);
+
+             /* The handling above of the final block before the epilogue
+                should be enough to verify that there is no edge to the exit
+                block in CFG already.  Calling make_edge in such case would
+                cause us to mark that edge as fake and remove it later.  */
+
+#ifdef ENABLE_CHECKING
+             if (split_at_insn == BB_END (bb))
+               for (e = bb->succ; e; e = e->succ_next)
+                 if (e->dest == EXIT_BLOCK_PTR)
+                   abort ();
+#endif
+
+             /* Note that the following may create a new basic block
+                and renumber the existing basic blocks.  */
+             if (split_at_insn != BB_END (bb))
+               {
+                 e = split_block (bb, split_at_insn);
+                 if (e)
+                   blocks_split++;
+               }
+
+             make_edge (bb, EXIT_BLOCK_PTR, EDGE_FAKE);
+           }
+
+         if (insn == BB_HEAD (bb))
+           break;
+       }
+    }
+
+  if (blocks_split)
+    verify_flow_info ();
+
+  return blocks_split;
+}
+
 /* Implementation of CFG manipulation for linearized RTL.  */
 struct cfg_hooks rtl_cfg_hooks = {
   "rtl",
@@ -2689,15 +3003,30 @@ struct cfg_hooks rtl_cfg_hooks = {
   rtl_move_block_after,
   rtl_can_merge_blocks,  /* can_merge_blocks_p */
   rtl_merge_blocks,
+  rtl_predict_edge,
+  rtl_predicted_by_p,
+  NULL, /* can_duplicate_block_p */
+  NULL, /* duplicate_block */
   rtl_split_edge,
   rtl_make_forwarder_block,
-  rtl_tidy_fallthru_edge
+  rtl_tidy_fallthru_edge,
+  rtl_block_ends_with_call_p,
+  rtl_block_ends_with_condjump_p,
+  rtl_flow_call_edges_add
 };
 
 /* Implementation of CFG manipulation for cfg layout RTL, where
    basic block connected via fallthru edges does not have to be adjacent.
    This representation will hopefully become the default one in future
    version of the compiler.  */
+
+/* We do not want to declare these functions in a header file, since they
+   should only be used through the cfghooks interface, and we do not want to
+   move them here since it would require also moving quite a lot of related
+   code.  */
+extern bool cfg_layout_can_duplicate_bb_p (basic_block);
+extern basic_block cfg_layout_duplicate_bb (basic_block);
+
 struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   "cfglayout mode",
   rtl_verify_flow_info_1,
@@ -2710,7 +3039,15 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   rtl_move_block_after,
   cfg_layout_can_merge_blocks_p,
   cfg_layout_merge_blocks,
+  rtl_predict_edge,
+  rtl_predicted_by_p,
+  cfg_layout_can_duplicate_bb_p,
+  cfg_layout_duplicate_bb,
   cfg_layout_split_edge,
   rtl_make_forwarder_block,
-  NULL
+  NULL,
+  rtl_block_ends_with_call_p,
+  rtl_block_ends_with_condjump_p,
+  rtl_flow_call_edges_add
 };
+