OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index f49eceb..ea39f35 100644 (file)
@@ -64,8 +64,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 static int can_delete_note_p (rtx);
 static int can_delete_label_p (rtx);
 static void commit_one_edge_insertion (edge, int);
-static rtx last_loop_beg_note (rtx);
-static bool back_edge_of_syntactic_loop_p (basic_block, basic_block);
 static basic_block rtl_split_edge (edge);
 static bool rtl_move_block_after (basic_block, basic_block);
 static int rtl_verify_flow_info (void);
@@ -79,7 +77,6 @@ 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);
-static void mark_killed_regs (rtx, rtx, void *);
 static void rtl_make_forwarder_block (edge);
 \f
 /* Return true if NOTE is not one of the ones that must be kept paired,
@@ -115,8 +112,8 @@ delete_insn (rtx insn)
   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.
-         Convert them to the special NOTE_INSN_DELETED_LABEL note.  */
+        might be references via variables, constant pool etc.
+        Convert them to the special NOTE_INSN_DELETED_LABEL note.  */
       if (! can_delete_label_p (insn))
        {
          const char *name = LABEL_NAME (insn);
@@ -305,7 +302,7 @@ create_basic_block_structure (rtx head, rtx end, rtx bb_note, basic_block after)
   bb->index = last_basic_block++;
   bb->flags = BB_NEW | BB_RTL;
   link_block (bb, after);
-  BASIC_BLOCK (bb->index) = bb;
+  SET_BASIC_BLOCK (bb->index, bb);
   update_bb_for_insn (bb);
   BB_SET_PARTITION (bb, BB_UNPARTITIONED);
 
@@ -328,10 +325,14 @@ rtl_create_basic_block (void *headp, void *endp, basic_block after)
   basic_block bb;
 
   /* Grow the basic block array if needed.  */
-  if ((size_t) last_basic_block >= VARRAY_SIZE (basic_block_info))
+  if ((size_t) last_basic_block >= VEC_length (basic_block, basic_block_info))
     {
+      size_t old_size = VEC_length (basic_block, basic_block_info);
       size_t new_size = last_basic_block + (last_basic_block + 3) / 4;
-      VARRAY_GROW (basic_block_info, new_size);
+      basic_block *p;
+      VEC_safe_grow (basic_block, gc, basic_block_info, new_size);
+      p = VEC_address (basic_block, basic_block_info);
+      memset (&p[old_size], 0, sizeof (basic_block) * (new_size - old_size));
     }
 
   n_basic_blocks++;
@@ -385,6 +386,13 @@ rtl_delete_block (basic_block b)
   /* Selectively delete the entire chain.  */
   BB_HEAD (b) = NULL;
   delete_insn_chain (insn, end);
+  if (b->il.rtl->global_live_at_start)
+    {
+      FREE_REG_SET (b->il.rtl->global_live_at_start);
+      FREE_REG_SET (b->il.rtl->global_live_at_end);
+      b->il.rtl->global_live_at_start = NULL;
+      b->il.rtl->global_live_at_end = NULL;
+    }
 }
 \f
 /* Records the basic block struct in BLOCK_FOR_INSN for every insn.  */
@@ -410,13 +418,14 @@ compute_bb_for_insn (void)
 
 /* Release the basic_block_for_insn array.  */
 
-void
+unsigned int
 free_bb_for_insn (void)
 {
   rtx insn;
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (!BARRIER_P (insn))
       BLOCK_FOR_INSN (insn) = NULL;
+  return 0;
 }
 
 struct tree_opt_pass pass_free_cfg =
@@ -440,7 +449,21 @@ struct tree_opt_pass pass_free_cfg =
 rtx
 entry_of_function (void)
 {
-  return (n_basic_blocks ? BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+  return (n_basic_blocks > NUM_FIXED_BLOCKS ?
+         BB_HEAD (ENTRY_BLOCK_PTR->next_bb) : get_insns ());
+}
+
+/* Emit INSN at the entry point of the function, ensuring that it is only
+   executed once per function.  */
+void
+emit_insn_at_entry (rtx insn)
+{
+  edge_iterator ei = ei_start (ENTRY_BLOCK_PTR->succs);
+  edge e = ei_safe_edge (ei);
+  gcc_assert (e->flags & EDGE_FALLTHRU);
+
+  insert_insn_on_edge (insn, e);
+  commit_edge_insertions ();
 }
 
 /* Update insns block within BB.  */
@@ -542,7 +565,7 @@ rtl_merge_blocks (basic_block a, basic_block b)
       /* This might have been an EH label that no longer has incoming
         EH edges.  Update data structures to match.  */
       maybe_remove_eh_handler (b_head);
+
       /* Detect basic blocks with nothing but a label.  This can happen
         in particular at the end of a function.  */
       if (b_head == b_end)
@@ -628,9 +651,9 @@ rtl_can_merge_blocks (basic_block a,basic_block b)
      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 
+     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 (BB_PARTITION (a) != BB_PARTITION (b))
@@ -687,11 +710,11 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
      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 
+     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 (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
       || BB_PARTITION (src) != BB_PARTITION (target))
     return NULL;
@@ -736,7 +759,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
        {
          rtx insn = src->il.rtl->footer;
 
-          delete_insn_chain (kill_from, BB_END (src));
+         delete_insn_chain (kill_from, BB_END (src));
 
          /* Remove barriers but keep jumptables.  */
          while (insn)
@@ -756,7 +779,7 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
            }
        }
       else
-        delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)));
+       delete_insn_chain (kill_from, PREV_INSN (BB_HEAD (target)));
     }
 
   /* If this already is simplejump, redirect it.  */
@@ -855,28 +878,6 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   return e;
 }
 
-/* Return last loop_beg note appearing after INSN, before start of next
-   basic block.  Return INSN if there are no such notes.
-
-   When emitting jump to redirect a fallthru edge, it should always appear
-   after the LOOP_BEG notes, as loop optimizer expect loop to either start by
-   fallthru edge or jump following the LOOP_BEG note jumping to the loop exit
-   test.  */
-
-static rtx
-last_loop_beg_note (rtx insn)
-{
-  rtx last = insn;
-
-  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)
-      last = insn;
-
-  return last;
-}
-
 /* Redirect edge representing branch of (un)conditional jump or tablejump,
    NULL on failure  */
 static edge
@@ -1013,9 +1014,6 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
      by creating a basic block afterwards to redirect fallthru edge.  */
   if (e->src != ENTRY_BLOCK_PTR && e->dest != EXIT_BLOCK_PTR
       && any_condjump_p (BB_END (e->src))
-      /* When called from cfglayout, fallthru edges do not
-         necessarily go to the next block.  */
-      && e->src->next_bb == e->dest
       && JUMP_LABEL (BB_END (e->src)) == BB_HEAD (e->dest))
     {
       rtx note;
@@ -1024,7 +1022,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
 
       redirected = redirect_jump (BB_END (e->src), block_label (target), 0);
       gcc_assert (redirected);
-      
+
       note = find_reg_note (BB_END (e->src), REG_BR_PROB, NULL_RTX);
       if (note)
        {
@@ -1063,9 +1061,9 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
          edge tmp;
          edge_iterator ei;
          bool found = false;
-         
+
          basic_block bb = create_basic_block (BB_HEAD (e->dest), NULL, ENTRY_BLOCK_PTR);
-         
+
          /* Change the existing edge's source to be the new block, and add
             a new edge from the entry block to the new block.  */
          e->src = bb;
@@ -1080,9 +1078,9 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
              else
                ei_next (&ei);
            }
-         
+
          gcc_assert (found);
-         
+
          VEC_safe_push (edge, gc, bb->succs, e);
          make_single_succ_edge (ENTRY_BLOCK_PTR, bb, EDGE_FALLTHRU);
        }
@@ -1097,9 +1095,6 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
         forward from the last instruction of the old block.  */
       if (!tablejump_p (BB_END (e->src), NULL, &note))
        note = BB_END (e->src);
-
-      /* Position the new block correctly relative to loop notes.  */
-      note = last_loop_beg_note (note);
       note = NEXT_INSN (note);
 
       jump_block = create_basic_block (note, NULL, e->src);
@@ -1129,8 +1124,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
                                                             NULL_RTX,
                                                             REG_NOTES
                                                             (BB_END
-                                                              (jump_block)));
-      
+                                                             (jump_block)));
+
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
       new_edge->probability = e->probability;
@@ -1194,6 +1189,7 @@ rtl_redirect_edge_and_branch_force (edge e, basic_block target)
 
   /* In case the edge redirection failed, try to force it to be non-fallthru
      and redirect newly created simplejump.  */
+  e->src->flags |= BB_DIRTY;
   return force_nonfallthru_and_redirect (e, target);
 }
 
@@ -1251,40 +1247,6 @@ rtl_tidy_fallthru_edge (edge e)
   e->flags |= EDGE_FALLTHRU;
 }
 \f
-/* Helper function for split_edge.  Return true in case edge BB2 to BB1
-   is back edge of syntactic loop.  */
-
-static bool
-back_edge_of_syntactic_loop_p (basic_block bb1, basic_block bb2)
-{
-  rtx insn;
-  int count = 0;
-  basic_block bb;
-
-  if (bb1 == bb2)
-    return true;
-
-  /* ??? Could we guarantee that bb indices are monotone, so that we could
-     just compare them?  */
-  for (bb = bb1; bb && bb != bb2; bb = bb->next_bb)
-    continue;
-
-  if (!bb)
-    return false;
-
-  for (insn = BB_END (bb1); insn != BB_HEAD (bb2) && count >= 0;
-       insn = NEXT_INSN (insn))
-    if (NOTE_P (insn))
-      {
-       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-         count++;
-       else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-         count--;
-      }
-
-  return count >= 0;
-}
-
 /* Should move basic block BB after basic block AFTER.  NIY.  */
 
 static bool
@@ -1325,32 +1287,8 @@ rtl_split_edge (edge edge_in)
        force_nonfallthru (e);
     }
 
-  /* Create the basic block note.
-
-     Where we place the note can have a noticeable impact on the generated
-     code.  Consider this cfg:
-
-                       E
-                       |
-                       0
-                      / \
-                  +->1-->2--->E
-                   |  |
-                  +--+
-
-      If we need to insert an insn on the edge from block 0 to block 1,
-      we want to ensure the instructions we insert are outside of any
-      loop notes that physically sit between block 0 and block 1.  Otherwise
-      we confuse the loop optimizer into thinking the loop is a phony.  */
-
-  if (edge_in->dest != EXIT_BLOCK_PTR
-      && PREV_INSN (BB_HEAD (edge_in->dest))
-      && 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))
-    before = PREV_INSN (BB_HEAD (edge_in->dest));
-  else if (edge_in->dest != EXIT_BLOCK_PTR)
+  /* Create the basic block note.  */
+  if (edge_in->dest != EXIT_BLOCK_PTR)
     before = BB_HEAD (edge_in->dest);
   else
     before = NULL_RTX;
@@ -1360,10 +1298,6 @@ rtl_split_edge (edge edge_in)
   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);
     }
@@ -1422,108 +1356,6 @@ insert_insn_on_edge (rtx pattern, edge e)
   end_sequence ();
 }
 
-/* Called from safe_insert_insn_on_edge through note_stores, marks live
-   registers that are killed by the store.  */
-static void
-mark_killed_regs (rtx reg, rtx set ATTRIBUTE_UNUSED, void *data)
-{
-  regset killed = data;
-  int regno, i;
-
-  if (GET_CODE (reg) == SUBREG)
-    reg = SUBREG_REG (reg);
-  if (!REG_P (reg))
-    return;
-  regno = REGNO (reg);
-  if (regno >= FIRST_PSEUDO_REGISTER)
-    SET_REGNO_REG_SET (killed, regno);
-  else
-    {
-      for (i = 0; i < (int) hard_regno_nregs[regno][GET_MODE (reg)]; i++)
-       SET_REGNO_REG_SET (killed, regno + i);
-    }
-}
-
-/* Similar to insert_insn_on_edge, tries to put INSN to edge E.  Additionally
-   it checks whether this will not clobber the registers that are live on the
-   edge (i.e. it requires liveness information to be up-to-date) and if there
-   are some, then it tries to save and restore them.  Returns true if
-   successful.  */
-bool
-safe_insert_insn_on_edge (rtx insn, edge e)
-{
-  rtx x;
-  regset killed;
-  rtx save_regs = NULL_RTX;
-  unsigned regno;
-  enum machine_mode mode;
-  reg_set_iterator rsi;
-
-  killed = ALLOC_REG_SET (&reg_obstack);
-
-  for (x = insn; x; x = NEXT_INSN (x))
-    if (INSN_P (x))
-      note_stores (PATTERN (x), mark_killed_regs, killed);
-
-  /* Mark all hard registers as killed.  Register allocator/reload cannot
-     cope with the situation when life range of hard register spans operation
-     for that the appropriate register is needed, i.e. it would be unsafe to
-     extend the life ranges of hard registers.  */
-  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-    if (!fixed_regs[regno]
-       && !REGNO_PTR_FRAME_P (regno))
-      SET_REGNO_REG_SET (killed, regno);
-
-  bitmap_and_into (killed, e->dest->il.rtl->global_live_at_start);
-
-  EXECUTE_IF_SET_IN_REG_SET (killed, 0, regno, rsi)
-    {
-      mode = regno < FIRST_PSEUDO_REGISTER
-             ? reg_raw_mode[regno]
-             : GET_MODE (regno_reg_rtx[regno]);
-      if (mode == VOIDmode)
-       return false;
-
-      /* Avoid copying in CCmode if we can't.  */
-      if (!can_copy_p (mode))
-       return false;
-       
-      save_regs = alloc_EXPR_LIST (0,
-                                  alloc_EXPR_LIST (0,
-                                                   gen_reg_rtx (mode),
-                                                   gen_raw_REG (mode, regno)),
-                                  save_regs);
-    }
-
-  if (save_regs)
-    {
-      rtx from, to;
-
-      start_sequence ();
-      for (x = save_regs; x; x = XEXP (x, 1))
-       {
-         from = XEXP (XEXP (x, 0), 1);
-         to = XEXP (XEXP (x, 0), 0);
-         emit_move_insn (to, from);
-       }
-      emit_insn (insn);
-      for (x = save_regs; x; x = XEXP (x, 1))
-       {
-         from = XEXP (XEXP (x, 0), 0);
-         to = XEXP (XEXP (x, 0), 1);
-         emit_move_insn (to, from);
-       }
-      insn = get_insns ();
-      end_sequence ();
-      free_EXPR_LIST_list (&save_regs);
-    }
-  insert_insn_on_edge (insn, e);
-  
-  FREE_REG_SET (killed);
-
-  return true;
-}
-
 /* Update the CFG for the instructions queued on edge E.  */
 
 static void
@@ -1558,7 +1390,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
   if (!before && !after)
     {
       /* Figure out where to put these things.  If the destination has
-         one predecessor, insert there.  Except for the exit block.  */
+        one predecessor, insert there.  Except for the exit block.  */
       if (single_pred_p (e->dest) && e->dest != EXIT_BLOCK_PTR)
        {
          bb = e->dest;
@@ -1579,7 +1411,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
        }
 
       /* If the source has one successor and the edge is not abnormal,
-         insert there.  Except for the entry block.  */
+        insert there.  Except for the entry block.  */
       else if ((e->flags & EDGE_ABNORMAL) == 0
               && single_succ_p (e->src)
               && e->src != ENTRY_BLOCK_PTR)
@@ -1593,11 +1425,7 @@ 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 (JUMP_P (BB_END (bb)))
-           for (before = BB_END (bb);
-                NOTE_P (PREV_INSN (before))
-                && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
-                NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
-             ;
+           before = BB_END (bb);
          else
            {
              /* We'd better be fallthru, or we've lost track of
@@ -1633,8 +1461,8 @@ commit_one_edge_insertion (edge e, int watch_calls)
 
              if (JUMP_P (BB_END (bb))
                  && !any_condjump_p (BB_END (bb))
-                 && (single_succ_edge (bb)->flags & EDGE_CROSSING))
-               REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST 
+                 && (single_succ_edge (bb)->flags & EDGE_CROSSING))
+               REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
                  (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
            }
        }
@@ -1653,9 +1481,9 @@ commit_one_edge_insertion (edge e, int watch_calls)
   if (returnjump_p (last))
     {
       /* ??? Remove all outgoing edges from BB and add one for EXIT.
-         This is not currently a problem because this only happens
-         for the (single) epilogue, which already has a fallthru edge
-         to EXIT.  */
+        This is not currently a problem because this only happens
+        for the (single) epilogue, which already has a fallthru edge
+        to EXIT.  */
 
       e = single_succ_edge (bb);
       gcc_assert (e->dest == EXIT_BLOCK_PTR
@@ -1708,7 +1536,7 @@ commit_edge_insertions (void)
   FOR_EACH_BB (bb)
     if (bb->aux)
       {
-        SET_BIT (blocks, bb->index);
+       SET_BIT (blocks, bb->index);
        /* Check for forgotten bb->aux values before commit_edge_insertions
           call.  */
        gcc_assert (bb->aux == &bb->aux);
@@ -1753,7 +1581,7 @@ commit_edge_insertions_watch_calls (void)
   FOR_EACH_BB (bb)
     if (bb->aux)
       {
-        SET_BIT (blocks, bb->index);
+       SET_BIT (blocks, bb->index);
        /* Check for forgotten bb->aux values before commit_edge_insertions
           call.  */
        gcc_assert (bb->aux == &bb->aux);
@@ -1804,9 +1632,9 @@ print_rtl_with_bb (FILE *outf, rtx rtx_first)
     {
       enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
       int max_uid = get_max_uid ();
-      basic_block *start = xcalloc (max_uid, sizeof (basic_block));
-      basic_block *end = xcalloc (max_uid, sizeof (basic_block));
-      enum bb_state *in_bb_p = xcalloc (max_uid, sizeof (enum bb_state));
+      basic_block *start = XCNEWVEC (basic_block, max_uid);
+      basic_block *end = XCNEWVEC (basic_block, max_uid);
+      enum bb_state *in_bb_p = XCNEWVEC (enum bb_state, max_uid);
 
       basic_block bb;
 
@@ -1914,7 +1742,7 @@ rtl_verify_flow_info_1 (void)
   int err = 0;
   basic_block bb;
 
-  bb_info = xcalloc (max_uid, sizeof (basic_block));
+  bb_info = XCNEWVEC (basic_block, max_uid);
 
   FOR_EACH_BB_REVERSE (bb)
     {
@@ -1998,7 +1826,7 @@ rtl_verify_flow_info_1 (void)
                  || (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;
@@ -2046,9 +1874,10 @@ rtl_verify_flow_info_1 (void)
          err = 1;
        }
       if (n_branch != 1 && any_condjump_p (BB_END (bb))
-         && JUMP_LABEL (BB_END (bb)) == BB_HEAD (fallthru->dest))
+         && JUMP_LABEL (BB_END (bb)) != BB_HEAD (fallthru->dest))
        {
-         error ("wrong amount of branch edges after conditional jump %i", bb->index);
+         error ("wrong amount of branch edges after conditional jump %i",
+                bb->index);
          err = 1;
        }
       if (n_call && !CALL_P (BB_END (bb)))
@@ -2085,7 +1914,7 @@ rtl_verify_flow_info_1 (void)
          }
 
       /* OK pointers are correct.  Now check the header of basic
-         block.  It ought to contain optional CODE_LABEL followed
+        block.  It ought to contain optional CODE_LABEL followed
         by NOTE_BASIC_BLOCK.  */
       x = BB_HEAD (bb);
       if (LABEL_P (x))
@@ -2187,7 +2016,7 @@ rtl_verify_flow_info (void)
        }
       else if (e->src != ENTRY_BLOCK_PTR
               && e->dest != EXIT_BLOCK_PTR)
-        {
+       {
          rtx insn;
 
          if (e->src->next_bb != e->dest)
@@ -2207,7 +2036,7 @@ rtl_verify_flow_info (void)
                  fatal_insn ("wrong insn in the fallthru edge", insn);
                  err = 1;
                }
-        }
+       }
     }
 
   num_bb_notes = 0;
@@ -2258,7 +2087,7 @@ rtl_verify_flow_info (void)
        curr_bb = NULL;
     }
 
-  if (num_bb_notes != n_basic_blocks)
+  if (num_bb_notes != n_basic_blocks - NUM_FIXED_BLOCKS)
     internal_error
       ("number of bb notes in insn chain (%d) != n_basic_blocks (%d)",
        num_bb_notes, n_basic_blocks);
@@ -2294,23 +2123,25 @@ purge_dead_edges (basic_block bb)
   /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
   for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
     {
-      /* We must check for the most restrictive condition first.  Since
-        an abnormal call edge is always an EH edge, but an EH edge is not
-        always an abnormal call edge, we must check for an abnormal call
-        edge first.  */
-      if (e->flags & EDGE_ABNORMAL_CALL)
+      /* There are three types of edges we need to handle correctly here: EH
+        edges, abnormal call EH edges, and abnormal call non-EH edges.  The
+        latter can appear when nonlocal gotos are used.  */
+      if (e->flags & EDGE_EH)
        {
-         if (CALL_P (BB_END (bb))
-             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
-                 || INTVAL (XEXP (note, 0)) >= 0))
+         if (can_throw_internal (BB_END (bb))
+             /* If this is a call edge, verify that this is a call insn.  */
+             && (! (e->flags & EDGE_ABNORMAL_CALL)
+                 || CALL_P (BB_END (bb))))
            {
              ei_next (&ei);
              continue;
            }
        }
-      else if (e->flags & EDGE_EH)
+      else if (e->flags & EDGE_ABNORMAL_CALL)
        {
-         if (can_throw_internal (BB_END (bb)))
+         if (CALL_P (BB_END (bb))
+             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
+                 || INTVAL (XEXP (note, 0)) >= 0))
            {
              ei_next (&ei);
              continue;
@@ -2560,7 +2391,7 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
                                     BB_END (src)))
        {
          edge redirected;
-         
+
          if (dump_file)
            fprintf (dump_file, "Fallthru edge unified with branch "
                     "%i->%i redirected to %i\n",
@@ -2569,11 +2400,11 @@ cfg_layout_redirect_edge_and_branch (edge e, basic_block dest)
          redirected = redirect_branch_edge (e, dest);
          gcc_assert (redirected);
          e->flags |= EDGE_FALLTHRU;
-          e->src->flags |= BB_DIRTY;
+         e->src->flags |= BB_DIRTY;
          return e;
        }
       /* In case we are redirecting fallthru edge to the branch edge
-         of conditional jump, remove it.  */
+        of conditional jump, remove it.  */
       if (EDGE_COUNT (src->succs) == 2)
        {
          /* Find the edge that is different from E.  */
@@ -2701,9 +2532,9 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
      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 
+     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 (BB_PARTITION (a) != BB_PARTITION (b))
@@ -2739,7 +2570,7 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
       /* This might have been an EH label that no longer has incoming
         EH edges.  Update data structures to match.  */
       maybe_remove_eh_handler (BB_HEAD (b));
+
       delete_insn (BB_HEAD (b));
     }
 
@@ -2911,7 +2742,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
   int last_bb = last_basic_block;
   bool check_last_block = false;
 
-  if (n_basic_blocks == 0)
+  if (n_basic_blocks == NUM_FIXED_BLOCKS)
     return 0;
 
   if (! blocks)
@@ -2958,7 +2789,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
      calls since there is no way that we can determine if they will
      return or not...  */
 
-  for (i = 0; i < last_bb; i++)
+  for (i = NUM_FIXED_BLOCKS; i < last_bb; i++)
     {
       basic_block bb = BASIC_BLOCK (i);
       rtx insn;
@@ -2979,14 +2810,14 @@ rtl_flow_call_edges_add (sbitmap blocks)
              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.  */
+                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
+                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.  */
 
@@ -3028,8 +2859,8 @@ rtl_flow_call_edges_add (sbitmap blocks)
    in trees, and this should be of the same type since it is a hook.  */
 static void
 rtl_lv_add_condition_to_bb (basic_block first_head ,
-                           basic_block second_head ATTRIBUTE_UNUSED, 
-                           basic_block cond_bb, void *comp_rtx)  
+                           basic_block second_head ATTRIBUTE_UNUSED,
+                           basic_block cond_bb, void *comp_rtx)
 {
   rtx label, seq, jump;
   rtx op0 = XEXP ((rtx)comp_rtx, 0);
@@ -3088,6 +2919,93 @@ init_rtl_bb_info (basic_block bb)
 }
 
 
+/* Add EXPR to the end of basic block BB.  */
+
+rtx
+insert_insn_end_bb_new (rtx pat, basic_block bb)
+{
+  rtx insn = BB_END (bb);
+  rtx new_insn;
+  rtx pat_end = pat;
+
+  while (NEXT_INSN (pat_end) != NULL_RTX)
+    pat_end = NEXT_INSN (pat_end);
+
+  /* If the last insn is a jump, insert EXPR in front [taking care to
+     handle cc0, etc. properly].  Similarly we need to care trapping
+     instructions in presence of non-call exceptions.  */
+
+  if (JUMP_P (insn)
+      || (NONJUMP_INSN_P (insn)
+          && (!single_succ_p (bb)
+              || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
+    {
+#ifdef HAVE_cc0
+      rtx note;
+#endif
+      /* If this is a jump table, then we can't insert stuff here.  Since
+         we know the previous real insn must be the tablejump, we insert
+         the new instruction just before the tablejump.  */
+      if (GET_CODE (PATTERN (insn)) == ADDR_VEC
+          || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+        insn = prev_real_insn (insn);
+
+#ifdef HAVE_cc0
+      /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
+         if cc0 isn't set.  */
+      note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
+      if (note)
+        insn = XEXP (note, 0);
+      else
+        {
+          rtx maybe_cc0_setter = prev_nonnote_insn (insn);
+          if (maybe_cc0_setter
+              && INSN_P (maybe_cc0_setter)
+              && sets_cc0_p (PATTERN (maybe_cc0_setter)))
+            insn = maybe_cc0_setter;
+        }
+#endif
+      /* FIXME: What if something in cc0/jump uses value set in new
+         insn?  */
+      new_insn = emit_insn_before_noloc (pat, insn);
+    }
+
+  /* Likewise if the last insn is a call, as will happen in the presence
+     of exception handling.  */
+  else if (CALL_P (insn)
+           && (!single_succ_p (bb)
+               || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
+    {
+      /* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
+         we search backward and place the instructions before the first
+         parameter is loaded.  Do this for everyone for consistency and a
+         presumption that we'll get better code elsewhere as well.  */
+
+      /* Since different machines initialize their parameter registers
+         in different orders, assume nothing.  Collect the set of all
+         parameter registers.  */
+      insn = find_first_parameter_load (insn, BB_HEAD (bb));
+
+      /* If we found all the parameter loads, then we want to insert
+         before the first parameter load.
+
+         If we did not find all the parameter loads, then we might have
+         stopped on the head of the block, which could be a CODE_LABEL.
+         If we inserted before the CODE_LABEL, then we would be putting
+         the insn in the wrong basic block.  In that case, put the insn
+         after the CODE_LABEL.  Also, respect NOTE_INSN_BASIC_BLOCK.  */
+      while (LABEL_P (insn)
+             || NOTE_INSN_BASIC_BLOCK_P (insn))
+        insn = NEXT_INSN (insn);
+
+      new_insn = emit_insn_before_noloc (pat, insn);
+    }
+  else
+    new_insn = emit_insn_after_noloc (pat, insn);
+
+  return new_insn;
+}
+
 /* Implementation of CFG manipulation for linearized RTL.  */
 struct cfg_hooks rtl_cfg_hooks = {
   "rtl",
@@ -3117,7 +3035,7 @@ struct cfg_hooks rtl_cfg_hooks = {
   NULL, /* lv_add_condition_to_bb */
   NULL, /* lv_adjust_loop_header_phi*/
   NULL, /* extract_cond_bb_edges */
-  NULL                 /* flush_pending_stmts */
+  NULL         /* flush_pending_stmts */
 };
 
 /* Implementation of CFG manipulation for cfg layout RTL, where
@@ -3160,6 +3078,5 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
   rtl_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
   NULL, /* lv_adjust_loop_header_phi*/
   rtl_extract_cond_bb_edges, /* extract_cond_bb_edges */
-  NULL                 /* flush_pending_stmts */  
+  NULL         /* flush_pending_stmts */
 };
-