OSDN Git Service

* flow.c (try_redirect_by_replacing_jump): Remove cc0 setter.
[pf3gnuchains/gcc-fork.git] / gcc / flow.c
index 2e76e3d..391b4b4 100644 (file)
@@ -133,7 +133,6 @@ Boston, MA 02111-1307, USA.  */
 #include "except.h"
 #include "toplev.h"
 #include "recog.h"
-#include "insn-flags.h"
 #include "expr.h"
 #include "ssa.h"
 
@@ -168,6 +167,12 @@ Boston, MA 02111-1307, USA.  */
 #define EPILOGUE_USES(REGNO)  0
 #endif
 
+#ifdef HAVE_conditional_execution
+#ifndef REVERSE_CONDEXEC_PREDICATES_P
+#define REVERSE_CONDEXEC_PREDICATES_P(x, y) ((x) == reverse_condition (y))
+#endif
+#endif
+
 /* The obstack on which the flow graph components are allocated.  */
 
 struct obstack flow_obstack;
@@ -199,8 +204,8 @@ struct basic_block_def entry_exit_blocks[2]
     NULL,                      /* aux */
     ENTRY_BLOCK,               /* index */
     0,                         /* loop_depth */
-    -1, -1,                    /* eh_beg, eh_end */
-    0                          /* count */
+    0,                         /* count */
+    0                          /* frequency */
   },
   {
     NULL,                      /* head */
@@ -214,8 +219,8 @@ struct basic_block_def entry_exit_blocks[2]
     NULL,                      /* aux */
     EXIT_BLOCK,                        /* index */
     0,                         /* loop_depth */
-    -1, -1,                    /* eh_beg, eh_end */
-    0                          /* count */
+    0,                         /* count */
+    0                          /* frequency */
   }
 };
 
@@ -270,8 +275,14 @@ static rtx tail_recursion_label_list;
 /* Holds information for tracking conditional register life information.  */
 struct reg_cond_life_info
 {
-  /* An EXPR_LIST of conditions under which a register is dead.  */
+  /* A boolean expression of conditions under which a register is dead.  */
   rtx condition;
+  /* Conditions under which a register is dead at the basic block end.  */
+  rtx orig_condition;
+
+  /* A boolean expression of conditions under which a register has been
+     stored into.  */
+  rtx stores;
 
   /* ??? Could store mask of bytes that are dead, so that we could finally
      track lifetimes of multi-word registers accessed via subregs.  */
@@ -344,24 +355,23 @@ struct depth_first_search_dsS {
 };
 typedef struct depth_first_search_dsS *depth_first_search_ds;
 
+/* Have print_rtl_and_abort give the same information that fancy_abort
+   does.  */
+#define print_rtl_and_abort() \
+  print_rtl_and_abort_fcn (__FILE__, __LINE__, __FUNCTION__)
+
 /* Forward declarations */
 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 *, eh_nesting_info *,
-                                                basic_block, rtx, int));
-static void mark_critical_edges                PARAMS ((void));
-static void move_stray_eh_region_notes PARAMS ((void));
-static void record_active_eh_regions   PARAMS ((rtx));
+static void make_eh_edge               PARAMS ((sbitmap *, basic_block, rtx));
 
 static void commit_one_edge_insertion  PARAMS ((edge));
 
 static void delete_unreachable_blocks  PARAMS ((void));
-static void delete_eh_regions          PARAMS ((void));
 static int can_delete_note_p           PARAMS ((rtx));
 static void expunge_block              PARAMS ((basic_block));
 static int can_delete_label_p          PARAMS ((rtx));
@@ -371,12 +381,16 @@ 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));
 static void verify_local_live_at_start PARAMS ((regset, basic_block));
-static int set_noop_p                  PARAMS ((rtx));
 static int noop_move_p                 PARAMS ((rtx));
 static void delete_noop_moves          PARAMS ((rtx));
 static void notice_stack_pointer_modification_1 PARAMS ((rtx, rtx, void *));
@@ -423,8 +437,9 @@ 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                PARAMS ((void));
+static void print_rtl_and_abort_fcn    PARAMS ((const char *, int,
+                                                const char *))
+                                       ATTRIBUTE_NORETURN;
 
 static void invalidate_mems_from_autoinc PARAMS ((struct propagate_block_info *,
                                                  rtx));
@@ -443,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
@@ -460,6 +474,9 @@ static void flow_loops_tree_build   PARAMS ((struct loops *));
 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
@@ -518,7 +535,6 @@ find_basic_blocks (f, nregs, file)
   compute_bb_for_insn (max_uid);
 
   /* Discover the edges of our cfg.  */
-  record_active_eh_regions (f);
   make_edges (label_value_list);
 
   /* Do very simple cleanup now, for the benefit of code that runs between
@@ -580,46 +596,45 @@ count_basic_blocks (f)
   register rtx insn;
   register RTX_CODE prev_code;
   register int count = 0;
-  int eh_region = 0;
-  int call_had_abnormal_edge = 0;
+  int saw_abnormal_edge = 0;
 
   prev_code = JUMP_INSN;
   for (insn = f; insn; insn = NEXT_INSN (insn))
     {
-      register RTX_CODE code = GET_CODE (insn);
+      enum rtx_code code = GET_CODE (insn);
 
       if (code == CODE_LABEL
          || (GET_RTX_CLASS (code) == 'i'
              && (prev_code == JUMP_INSN
                  || prev_code == BARRIER
-                 || (prev_code == CALL_INSN && call_had_abnormal_edge))))
-       count++;
+                 || saw_abnormal_edge)))
+       {
+         saw_abnormal_edge = 0;
+         count++;
+       }
 
-      /* Record whether this call created an edge.  */
+      /* Record whether this insn created an edge.  */
       if (code == CALL_INSN)
        {
-         rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-         int region = (note ? INTVAL (XEXP (note, 0)) : 1);
-
-         call_had_abnormal_edge = 0;
-
-         /* If there is an EH region or rethrow, we have an edge.  */
-         if ((eh_region && region > 0)
-             || find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
-           call_had_abnormal_edge = 1;
-         else if (nonlocal_goto_handler_labels && region >= 0)
-           /* If there is a nonlocal goto label and the specified
-              region number isn't -1, we have an edge. (0 means
-              no throw, but might have a nonlocal goto).  */
-           call_had_abnormal_edge = 1;
+         rtx note;
+
+         /* If there is a nonlocal goto label and the specified
+            region number isn't -1, we have an edge.  */
+         if (nonlocal_goto_handler_labels
+             && ((note = find_reg_note (insn, REG_EH_REGION, NULL_RTX)) == 0
+                 || INTVAL (XEXP (note, 0)) >= 0))
+           saw_abnormal_edge = 1;
+
+         else if (can_throw_internal (insn))
+           saw_abnormal_edge = 1;
        }
+      else if (flag_non_call_exceptions
+              && code == INSN
+              && can_throw_internal (insn))
+       saw_abnormal_edge = 1;
 
       if (code != NOTE)
        prev_code = code;
-      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
-       ++eh_region;
-      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
-       --eh_region;
     }
 
   /* The rest of the compiler works a bit smoother when we don't have to
@@ -653,9 +668,6 @@ find_label_refs (f, lvl)
           Make a special exception for labels followed by an ADDR*VEC,
           as this would be a part of the tablejump setup code.
 
-          Make a special exception for the eh_return_stub_label, which
-          we know isn't part of any otherwise visible control flow.
-
           Make a special exception to registers loaded with label
           values just before jump insns that use them.  */
 
@@ -664,9 +676,7 @@ find_label_refs (f, lvl)
            {
              rtx lab = XEXP (note, 0), next;
 
-             if (lab == eh_return_stub_label)
-               ;
-             else if ((next = next_nonnote_insn (lab)) != NULL
+             if ((next = next_nonnote_insn (lab)) != NULL
                       && GET_CODE (next) == JUMP_INSN
                       && (GET_CODE (PATTERN (next)) == ADDR_VEC
                           || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
@@ -684,6 +694,106 @@ find_label_refs (f, lvl)
   return lvl;
 }
 
+/* Assume that someone emitted code with control flow instructions to the
+   basic block.  Update the data structure.  */
+static void
+find_sub_basic_blocks (bb)
+     basic_block bb;
+{
+  rtx first_insn = bb->head, insn;
+  rtx end = bb->end;
+  edge succ_list = bb->succ;
+  rtx jump_insn = NULL_RTX;
+  int created = 0;
+  int barrier = 0;
+  edge falltru = 0;
+  basic_block first_bb = bb, last_bb;
+  int i;
+
+  if (GET_CODE (first_insn) == LABEL_REF)
+    first_insn = NEXT_INSN (first_insn);
+  first_insn = NEXT_INSN (first_insn);
+  bb->succ = NULL;
+
+  insn = first_insn;
+  /* Scan insn chain and try to find new basic block boundaries.  */
+  while (insn != end)
+    {
+      enum rtx_code code = GET_CODE (insn);
+      switch (code)
+       {
+       case JUMP_INSN:
+         /* We need some special care for those expressions.  */
+         if (GET_CODE (PATTERN (insn)) == ADDR_VEC
+             || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+           abort();
+         jump_insn = insn;
+         break;
+       case BARRIER:
+         if (!jump_insn)
+           abort ();
+         barrier = 1;
+         break;
+       /* On code label, split current basic block.  */
+       case CODE_LABEL:
+         falltru = split_block (bb, PREV_INSN (insn));
+         if (jump_insn)
+           bb->end = jump_insn;
+         bb = falltru->dest;
+         if (barrier)
+           remove_edge (falltru);
+         barrier = 0;
+         jump_insn = 0;
+         created = 1;
+         if (LABEL_ALTERNATE_NAME (insn))
+           make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+         break;
+       case INSN:
+         /* In case we've previously split insn on the JUMP_INSN, move the
+            block header to proper place.  */
+         if (jump_insn)
+           {
+             falltru = split_block (bb, PREV_INSN (insn));
+             bb->end = jump_insn;
+             bb = falltru->dest;
+             if (barrier)
+               abort ();
+             jump_insn = 0;
+           }
+       default:
+         break;
+       }
+      insn = NEXT_INSN (insn);
+    }
+  /* Last basic block must end in the original BB end.  */
+  if (jump_insn)
+    abort ();
+
+  /* Wire in the original edges for last basic block.  */
+  if (created)
+    {
+      bb->succ = succ_list;
+      while (succ_list)
+       succ_list->src = bb, succ_list = succ_list->succ_next;
+    }
+  else
+    bb->succ = succ_list;
+
+  /* Now re-scan and wire in all edges.  This expect simple (conditional)
+     jumps at the end of each new basic blocks.  */
+  last_bb = bb;
+  for (i = first_bb->index; i < last_bb->index; i++)
+    {
+      bb = BASIC_BLOCK (i);
+      if (GET_CODE (bb->end) == JUMP_INSN)
+       {
+         mark_jump_label (PATTERN (bb->end), bb->end, 0, 0);
+         make_label_edge (NULL, bb, JUMP_LABEL (bb->end), 0);
+       }
+      insn = NEXT_INSN (insn);
+    }
+}
+
 /* Find all basic blocks of the function whose first insn is F.
 
    Collect and return a list of labels whose addresses are taken.  This
@@ -696,7 +806,6 @@ find_basic_blocks_1 (f)
   register rtx insn, next;
   int i = 0;
   rtx bb_note = NULL_RTX;
-  rtx eh_list = NULL_RTX;
   rtx lvl = NULL_RTX;
   rtx trll = NULL_RTX;
   rtx head = NULL_RTX;
@@ -720,22 +829,11 @@ find_basic_blocks_1 (f)
          {
            int kind = NOTE_LINE_NUMBER (insn);
 
-           /* Keep a LIFO list of the currently active exception notes.  */
-           if (kind == NOTE_INSN_EH_REGION_BEG)
-             eh_list = alloc_INSN_LIST (insn, eh_list);
-           else if (kind == NOTE_INSN_EH_REGION_END)
-             {
-               rtx t = eh_list;
-
-               eh_list = XEXP (eh_list, 1);
-               free_INSN_LIST_node (t);
-             }
-
            /* Look for basic block notes with which to keep the
               basic_block_info pointers stable.  Unthread the note now;
               we'll put it back at the right place in create_basic_block.
               Or not at all if we've already found a note in this block.  */
-           else if (kind == NOTE_INSN_BASIC_BLOCK)
+           if (kind == NOTE_INSN_BASIC_BLOCK)
              {
                if (bb_note == NULL_RTX)
                  bb_note = insn;
@@ -819,8 +917,7 @@ find_basic_blocks_1 (f)
          {
            /* Record whether this call created an edge.  */
            rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-           int region = (note ? INTVAL (XEXP (note, 0)) : 1);
-           int call_has_abnormal_edge = 0;
+           int region = (note ? INTVAL (XEXP (note, 0)) : 0);
 
            if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
              {
@@ -833,19 +930,10 @@ find_basic_blocks_1 (f)
                  trll = alloc_EXPR_LIST (0, XEXP (PATTERN (insn), 3), trll);
              }
 
-           /* If there is an EH region or rethrow, we have an edge.  */
-           if ((eh_list && region > 0)
-               || find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
-             call_has_abnormal_edge = 1;
-           else if (nonlocal_goto_handler_labels && region >= 0)
-             /* If there is a nonlocal goto label and the specified
-                region number isn't -1, we have an edge. (0 means
-                no throw, but might have a nonlocal goto).  */
-             call_has_abnormal_edge = 1;
-
            /* A basic block ends at a call that can either throw or
               do a non-local goto.  */
-           if (call_has_abnormal_edge)
+           if ((nonlocal_goto_handler_labels && region >= 0)
+               || can_throw_internal (insn))
              {
              new_bb_inclusive:
                if (head == NULL_RTX)
@@ -861,18 +949,21 @@ find_basic_blocks_1 (f)
          }
          /* Fall through.  */
 
-       default:
-         if (GET_RTX_CLASS (code) == 'i')
-           {
-             if (head == NULL_RTX)
-               head = insn;
-             end = insn;
-           }
+       case INSN:
+         /* Non-call exceptions generate new blocks just like calls.  */
+         if (flag_non_call_exceptions && can_throw_internal (insn))
+           goto new_bb_inclusive;
+
+         if (head == NULL_RTX)
+           head = insn;
+         end = insn;
          break;
+
+       default:
+         abort ();
        }
 
-      if (GET_RTX_CLASS (code) == 'i'
-         && GET_CODE (insn) != JUMP_INSN)
+      if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
        {
          rtx note;
 
@@ -881,9 +972,6 @@ find_basic_blocks_1 (f)
             Make a special exception for labels followed by an ADDR*VEC,
             as this would be a part of the tablejump setup code.
 
-            Make a special exception for the eh_return_stub_label, which
-            we know isn't part of any otherwise visible control flow.
-
             Make a special exception to registers loaded with label
             values just before jump insns that use them.  */
 
@@ -892,9 +980,7 @@ find_basic_blocks_1 (f)
              {
                rtx lab = XEXP (note, 0), next;
 
-               if (lab == eh_return_stub_label)
-                 ;
-               else if ((next = next_nonnote_insn (lab)) != NULL
+               if ((next = next_nonnote_insn (lab)) != NULL
                         && GET_CODE (next) == JUMP_INSN
                         && (GET_CODE (PATTERN (next)) == ADDR_VEC
                             || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
@@ -925,13 +1011,11 @@ find_basic_blocks_1 (f)
 /* Tidy the CFG by deleting unreachable code and whatnot.  */
 
 void
-cleanup_cfg (f)
-     rtx f;
+cleanup_cfg ()
 {
   delete_unreachable_blocks ();
-  move_stray_eh_region_notes ();
-  record_active_eh_regions (f);
-  try_merge_blocks ();
+  if (try_optimize_cfg ())
+    delete_unreachable_blocks ();
   mark_critical_edges ();
 
   /* Kill the data we won't maintain.  */
@@ -1038,7 +1122,7 @@ compute_bb_for_insn (max)
 
 /* Free the memory associated with the edge structures.  */
 
-static void
+void
 clear_edges ()
 {
   int i;
@@ -1083,7 +1167,6 @@ make_edges (label_value_list)
      rtx label_value_list;
 {
   int i;
-  eh_nesting_info *eh_nest_info = init_eh_nesting_info ();
   sbitmap *edge_cache = NULL;
 
   /* Assume no computed jump; revise as we create edges.  */
@@ -1108,6 +1191,10 @@ make_edges (label_value_list)
       enum rtx_code code;
       int force_fallthru = 0;
 
+      if (GET_CODE (bb->head) == CODE_LABEL
+         && LABEL_ALTERNATE_NAME (bb->head))
+       make_edge (NULL, ENTRY_BLOCK_PTR, bb, 0);
+
       /* Examine the last instruction of the block, and discover the
         ways we can leave the block.  */
 
@@ -1119,9 +1206,13 @@ make_edges (label_value_list)
        {
          rtx tmp;
 
+         /* Recognize exception handling placeholders.  */
+         if (GET_CODE (PATTERN (insn)) == RESX)
+           make_eh_edge (edge_cache, bb, insn);
+
          /* Recognize a non-local goto as a branch outside the
             current function.  */
-         if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
+         else if (find_reg_note (insn, REG_NON_LOCAL_GOTO, NULL_RTX))
            ;
 
          /* ??? Recognize a tablejump and do the right thing.  */
@@ -1196,37 +1287,15 @@ make_edges (label_value_list)
                   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
 
       /* If this is a CALL_INSN, then mark it as reaching the active EH
-        handler for this CALL_INSN.  If we're handling asynchronous
+        handler for this CALL_INSN.  If we're handling non-call
         exceptions then any insn can reach any of the active handlers.
 
         Also mark the CALL_INSN as reaching any nonlocal goto handler.  */
 
-      else if (code == CALL_INSN || asynchronous_exceptions)
+      else if (code == CALL_INSN || flag_non_call_exceptions)
        {
-         /* Add any appropriate EH edges.  We do this unconditionally
-            since there may be a REG_EH_REGION or REG_EH_RETHROW note
-            on the call, and this needn't be within an EH region.  */
-         make_eh_edge (edge_cache, eh_nest_info, bb, insn, bb->eh_end);
-
-         /* If we have asynchronous exceptions, do the same for *all*
-            exception regions active in the block.  */
-         if (asynchronous_exceptions
-             && bb->eh_beg != bb->eh_end)
-           {
-             if (bb->eh_beg >= 0)
-               make_eh_edge (edge_cache, eh_nest_info, bb,
-                             NULL_RTX, bb->eh_beg);
-
-             for (x = bb->head; x != bb->end; x = NEXT_INSN (x))
-               if (GET_CODE (x) == NOTE
-                   && (NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_BEG
-                       || NOTE_LINE_NUMBER (x) == NOTE_INSN_EH_REGION_END))
-                 {
-                   int region = NOTE_EH_HANDLER (x);
-                   make_eh_edge (edge_cache, eh_nest_info, bb,
-                                 NULL_RTX, region);
-                 }
-           }
+         /* Add any appropriate EH edges.  */
+         make_eh_edge (edge_cache, bb, insn);
 
          if (code == CALL_INSN && nonlocal_goto_handler_labels)
            {
@@ -1247,14 +1316,6 @@ make_edges (label_value_list)
            }
        }
 
-      /* We know something about the structure of the function __throw in
-        libgcc2.c.  It is the only function that ever contains eh_stub
-        labels.  It modifies its return address so that the last block
-        returns to one of the eh_stub labels within it.  So we have to
-        make additional edges in the flow graph.  */
-      if (i + 1 == n_basic_blocks && eh_return_stub_label != 0)
-       make_label_edge (edge_cache, bb, eh_return_stub_label, EDGE_EH);
-
       /* Find out if we can drop through to the next block.  */
       insn = next_nonnote_insn (insn);
       if (!insn || (i + 1 == n_basic_blocks && force_fallthru))
@@ -1269,7 +1330,6 @@ make_edges (label_value_list)
        }
     }
 
-  free_eh_nesting_info (eh_nest_info);
   if (edge_cache)
     sbitmap_vector_free (edge_cache);
 }
@@ -1357,120 +1417,26 @@ make_label_edge (edge_cache, src, label, flags)
 /* Create the edges generated by INSN in REGION.  */
 
 static void
-make_eh_edge (edge_cache, eh_nest_info, src, insn, region)
+make_eh_edge (edge_cache, src, insn)
      sbitmap *edge_cache;
-     eh_nesting_info *eh_nest_info;
      basic_block src;
      rtx insn;
-     int region;
 {
-  handler_info **handler_list;
-  int num, is_call;
+  int is_call = (GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
+  rtx handlers, i;
 
-  is_call = (insn && GET_CODE (insn) == CALL_INSN ? EDGE_ABNORMAL_CALL : 0);
-  num = reachable_handlers (region, eh_nest_info, insn, &handler_list);
-  while (--num >= 0)
-    {
-      make_label_edge (edge_cache, src, handler_list[num]->handler_label,
-                      EDGE_ABNORMAL | EDGE_EH | is_call);
-    }
-}
+  handlers = reachable_handlers (insn);
 
-/* EH_REGION notes appearing between basic blocks is ambiguous, and even
-   dangerous if we intend to move basic blocks around.  Move such notes
-   into the following block.  */
+  for (i = handlers; i; i = XEXP (i, 1))
+    make_label_edge (edge_cache, src, XEXP (i, 0),
+                    EDGE_ABNORMAL | EDGE_EH | is_call);
 
-static void
-move_stray_eh_region_notes ()
-{
-  int i;
-  basic_block b1, b2;
-
-  if (n_basic_blocks < 2)
-    return;
-
-  b2 = BASIC_BLOCK (n_basic_blocks - 1);
-  for (i = n_basic_blocks - 2; i >= 0; --i, b2 = b1)
-    {
-      rtx insn, next, list = NULL_RTX;
-
-      b1 = BASIC_BLOCK (i);
-      for (insn = NEXT_INSN (b1->end); insn != b2->head; insn = next)
-       {
-         next = NEXT_INSN (insn);
-         if (GET_CODE (insn) == NOTE
-             && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
-                 || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
-           {
-             /* Unlink from the insn chain.  */
-             NEXT_INSN (PREV_INSN (insn)) = next;
-             PREV_INSN (next) = PREV_INSN (insn);
-
-             /* Queue it.  */
-             NEXT_INSN (insn) = list;
-             list = insn;
-           }
-       }
-
-      if (list == NULL_RTX)
-       continue;
-
-      /* Find where to insert these things.  */
-      insn = b2->head;
-      if (GET_CODE (insn) == CODE_LABEL)
-       insn = NEXT_INSN (insn);
-
-      while (list)
-       {
-         next = NEXT_INSN (list);
-         add_insn_after (list, insn);
-         list = next;
-       }
-    }
-}
-
-/* Recompute eh_beg/eh_end for each basic block.  */
-
-static void
-record_active_eh_regions (f)
-     rtx f;
-{
-  rtx insn, eh_list = NULL_RTX;
-  int i = 0;
-  basic_block bb = BASIC_BLOCK (0);
-
-  for (insn = f; insn; insn = NEXT_INSN (insn))
-    {
-      if (bb->head == insn)
-       bb->eh_beg = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1);
-
-      if (GET_CODE (insn) == NOTE)
-       {
-         int kind = NOTE_LINE_NUMBER (insn);
-         if (kind == NOTE_INSN_EH_REGION_BEG)
-           eh_list = alloc_INSN_LIST (insn, eh_list);
-         else if (kind == NOTE_INSN_EH_REGION_END)
-           {
-             rtx t = XEXP (eh_list, 1);
-             free_INSN_LIST_node (eh_list);
-             eh_list = t;
-           }
-       }
-
-      if (bb->end == insn)
-       {
-         bb->eh_end = (eh_list ? NOTE_EH_HANDLER (XEXP (eh_list, 0)) : -1);
-         i += 1;
-         if (i == n_basic_blocks)
-           break;
-         bb = BASIC_BLOCK (i);
-       }
-    }
+  free_INSN_LIST_list (&handlers);
 }
 
 /* Identify critical edges and set the bits appropriately.  */
 
-static void
+void
 mark_critical_edges ()
 {
   int i, n = n_basic_blocks;
@@ -1547,6 +1513,7 @@ split_block (bb, insn)
   bb->succ = new_edge;
   new_bb->pred = new_edge;
   new_bb->count = bb->count;
+  new_bb->frequency = bb->frequency;
   new_bb->loop_depth = bb->loop_depth;
 
   new_edge->src = bb;
@@ -1576,11 +1543,21 @@ split_block (bb, insn)
   BASIC_BLOCK (i) = new_bb;
   new_bb->index = i;
 
-  /* Create the basic block note.  */
-  bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK,
-                             new_bb->head);
-  NOTE_BASIC_BLOCK (bb_note) = new_bb;
-  new_bb->head = bb_note;
+  if (GET_CODE (new_bb->head) == CODE_LABEL)
+    {
+      /* Create the basic block note.  */
+      bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK,
+                                new_bb->head);
+      NOTE_BASIC_BLOCK (bb_note) = new_bb;
+    }
+  else
+    {
+      /* Create the basic block note.  */
+      bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK,
+                                 new_bb->head);
+      NOTE_BASIC_BLOCK (bb_note) = new_bb;
+      new_bb->head = bb_note;
+    }
 
   update_bb_for_insn (new_bb);
 
@@ -1604,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.
@@ -1628,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));
@@ -1654,11 +1882,11 @@ split_edge (edge_in)
     }
 
   /* Wire them up.  */
-  bb->pred = edge_in;
   bb->succ = edge_out;
   bb->count = edge_in->count;
+  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;
@@ -1771,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;
 }
@@ -1982,6 +2152,7 @@ commit_one_edge_insertion (e)
     }
   else if (GET_CODE (last) == JUMP_INSN)
     abort ();
+  find_sub_basic_blocks (bb);
 }
 
 /* Update the CFG for all queued instructions.  */
@@ -2084,15 +2255,15 @@ flow_call_edges_add (blocks)
   return blocks_split;
 }
 \f
-/* Delete all unreachable basic blocks.   */
+/* Find unreachable blocks.  An unreachable block will have NULL in
+   block->aux, a non-NULL value indicates the block is reachable.  */
 
-static void
-delete_unreachable_blocks ()
+void
+find_unreachable_blocks ()
 {
-  basic_block *worklist, *tos;
-  int deleted_handler;
   edge e;
   int i, n;
+  basic_block *tos, *worklist;
 
   n = n_basic_blocks;
   tos = worklist = (basic_block *) xmalloc (sizeof (basic_block) * n);
@@ -2128,12 +2299,22 @@ delete_unreachable_blocks ()
          }
     }
 
-  /* Delete all unreachable basic blocks.  Count down so that we don't
-     interfere with the block renumbering that happens in flow_delete_block.  */
+  free (worklist);
+}
+
+/* Delete all unreachable basic blocks.   */
+static void
+delete_unreachable_blocks ()
+{
+  int i;
 
-  deleted_handler = 0;
+  find_unreachable_blocks ();
 
-  for (i = n - 1; i >= 0; --i)
+  /* Delete all unreachable basic blocks.  Count down so that we
+     don't interfere with the block renumbering that happens in
+     flow_delete_block.  */
+
+  for (i = n_basic_blocks - 1; i >= 0; --i)
     {
       basic_block b = BASIC_BLOCK (i);
 
@@ -2141,44 +2322,10 @@ delete_unreachable_blocks ()
        /* This block was found.  Tidy up the mark.  */
        b->aux = NULL;
       else
-       deleted_handler |= flow_delete_block (b);
+       flow_delete_block (b);
     }
 
   tidy_fallthru_edges ();
-
-  /* If we deleted an exception handler, we may have EH region begin/end
-     blocks to remove as well.  */
-  if (deleted_handler)
-    delete_eh_regions ();
-
-  free (worklist);
-}
-
-/* Find EH regions for which there is no longer a handler, and delete them.  */
-
-static void
-delete_eh_regions ()
-{
-  rtx insn;
-
-  update_rethrow_references ();
-
-  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == NOTE)
-      {
-       if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
-           || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
-         {
-           int num = NOTE_EH_HANDLER (insn);
-           /* A NULL handler indicates a region is no longer needed,
-              as long as its rethrow label isn't used.  */
-           if (get_first_handler (num) == NULL && ! rethrow_used (num))
-             {
-               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (insn) = 0;
-             }
-         }
-      }
 }
 
 /* Return true if NOTE is not one of the ones that must be kept paired,
@@ -2254,26 +2401,7 @@ flow_delete_block (b)
   never_reached_warning (insn);
 
   if (GET_CODE (insn) == CODE_LABEL)
-    {
-      rtx x, *prev = &exception_handler_labels;
-
-      for (x = exception_handler_labels; x; x = XEXP (x, 1))
-       {
-         if (XEXP (x, 0) == insn)
-           {
-             /* Found a match, splice this label out of the EH label list.  */
-             *prev = XEXP (x, 1);
-             XEXP (x, 1) = NULL_RTX;
-             XEXP (x, 0) = NULL_RTX;
-
-             /* Remove the handler from all regions */
-             remove_handler (insn);
-             deleted_handler = 1;
-             break;
-           }
-         prev = &XEXP (x, 1);
-       }
-    }
+    maybe_remove_eh_handler (insn);
 
   /* Include any jump table following the basic block.  */
   end = b->end;
@@ -2382,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;
 }
 
@@ -2671,7 +2812,6 @@ merge_blocks (e, b, c)
   else
     {
       edge tmp_edge;
-      basic_block d;
       int c_has_outgoing_fallthru;
       int b_has_incoming_fallthru;
 
@@ -2699,73 +2839,232 @@ merge_blocks (e, b, c)
          break;
       b_has_incoming_fallthru = (tmp_edge != NULL);
 
-      /* If B does not have an incoming fallthru, and the exception regions
-        match, then it can be moved immediately before C without introducing
-        or modifying jumps.
-
-        C can not be the first block, so we do not have to worry about
+      /* If B does not have an incoming fallthru, then it can be moved
+        immediately before C without introducing or modifying jumps.
+        C cannot be the first block, so we do not have to worry about
         accessing a non-existent block.  */
-      d = BASIC_BLOCK (c->index - 1);
-      if (! b_has_incoming_fallthru
-         && d->eh_end == b->eh_beg
-         && b->eh_end == c->eh_beg)
+      if (! b_has_incoming_fallthru)
        return merge_blocks_move_predecessor_nojumps (b, c);
 
-      /* Otherwise, we're going to try to move C after B.  Make sure the
-        exception regions match.
+      /* Otherwise, we're going to try to move C after B.  If C does
+        not have an outgoing fallthru, then it can be moved
+        immediately after B without introducing or modifying jumps.  */
+      if (! c_has_outgoing_fallthru)
+       return merge_blocks_move_successor_nojumps (b, c);
+
+      /* Otherwise, we'll need to insert an extra jump, and possibly
+        a new block to contain it.  */
+      /* ??? Not implemented yet.  */
+
+      return 0;
+    }
+}
+
+/* Simplify conditional jump around an jump.  
+   Return nonzero in case optimization matched.  */
+
+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;
+}
 
-        If B is the last basic block, then we must not try to access the
-        block structure for block B + 1.  Luckily in that case we do not
-        need to worry about matching exception regions.  */
-      d = (b->index + 1 < n_basic_blocks ? BASIC_BLOCK (b->index + 1) : NULL);
-      if (b->eh_end == c->eh_beg
-         && (d == NULL || c->eh_end == d->eh_beg))
+/* 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)
        {
-         /* If C does not have an outgoing fallthru, then it can be moved
-            immediately after B without introducing or modifying jumps.  */
-         if (! c_has_outgoing_fallthru)
-           return merge_blocks_move_successor_nojumps (b, c);
-
-         /* Otherwise, we'll need to insert an extra jump, and possibly
-            a new block to contain it.  */
-         /* ??? Not implemented yet.  */
+         /* Bypass trivial infinite loops.  */
+         if (target == target->succ->dest)
+           counter = n_basic_blocks;
+         target = target->succ->dest, counter++;
        }
 
-      return 0;
+      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;
 }
 
-/* Top level driver for merge_blocks.  */
+/* Do simple CFG optimizations - basic block merging, simplifying of jump
+   instructions etc.
 
-static void
-try_merge_blocks ()
+   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
@@ -2814,7 +3113,14 @@ tidy_fallthru_edge (e, b, c)
          NOTE_SOURCE_FILE (q) = 0;
        }
       else
-       q = PREV_INSN (q);
+       {
+         q = PREV_INSN (q);
+
+         /* 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)
+           q = PREV_INSN (q);
+       }
 
       b->end = q;
     }
@@ -2854,6 +3160,7 @@ tidy_fallthru_edges ()
         merge the flags for the duplicate edges.  So we do not want to
         check that the edge is not a FALLTHRU edge.  */
       if ((s = b->succ) != NULL
+         && ! (s->flags & EDGE_COMPLEX)
          && s->succ_next == NULL
          && s->dest == c
          /* If the jump insn has side effects, we can't tidy the edge.  */
@@ -2944,6 +3251,21 @@ life_analysis (f, file, flags)
     dump_flow_info (file);
 
   free_basic_block_vars (1);
+
+#ifdef ENABLE_CHECKING
+  {
+    rtx insn;
+
+    /* Search for any REG_LABEL notes which reference deleted labels.  */
+    for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+      {
+       rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
+
+       if (inote && GET_CODE (inote) == NOTE_INSN_DELETED_LABEL)
+         abort ();
+      }
+  }
+#endif
 }
 
 /* A subroutine of verify_wide_reg, called through for_each_rtx.
@@ -3155,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;
@@ -3166,27 +3491,6 @@ free_basic_block_vars (keep_head_end_p)
     }
 }
 
-/* Return nonzero if the destination of SET equals the source.  */
-
-static int
-set_noop_p (set)
-     rtx set;
-{
-  rtx src = SET_SRC (set);
-  rtx dst = SET_DEST (set);
-
-  if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
-    {
-      if (SUBREG_WORD (src) != SUBREG_WORD (dst))
-       return 0;
-      src = SUBREG_REG (src);
-      dst = SUBREG_REG (dst);
-    }
-
-  return (GET_CODE (src) == REG && GET_CODE (dst) == REG
-         && REGNO (src) == REGNO (dst));
-}
-
 /* Return nonzero if an insn consists only of SETs, each of which only sets a
    value to itself.  */
 
@@ -3345,15 +3649,14 @@ mark_regs_live_at_end (set)
 #endif
     }
 
-#ifdef PIC_OFFSET_TABLE_REGNUM
 #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
   /* Many architectures have a GP register even without flag_pic.
      Assume the pic register is not in use, or will be handled by
      other means, if it is not fixed.  */
-  if (fixed_regs[PIC_OFFSET_TABLE_REGNUM])
+  if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+      && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
     SET_REGNO_REG_SET (set, PIC_OFFSET_TABLE_REGNUM);
 #endif
-#endif
 
   /* Mark all global registers, and all registers used by the epilogue
      as being live at the end of the function since they may be
@@ -3362,14 +3665,44 @@ mark_regs_live_at_end (set)
     if (global_regs[i] || EPILOGUE_USES (i))
       SET_REGNO_REG_SET (set, i);
 
-  /* Mark all call-saved registers that we actaully used.  */
   if (HAVE_epilogue && reload_completed)
     {
+      /* Mark all call-saved registers that we actually used.  */
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (regs_ever_live[i] && ! call_used_regs[i] && ! LOCAL_REGNO (i))
          SET_REGNO_REG_SET (set, i);
     }
 
+#ifdef EH_RETURN_DATA_REGNO
+  /* Mark the registers that will contain data for the handler.  */
+  if (reload_completed && current_function_calls_eh_return)
+    for (i = 0; ; ++i)
+      {
+       unsigned regno = EH_RETURN_DATA_REGNO(i);
+       if (regno == INVALID_REGNUM)
+         break;
+       SET_REGNO_REG_SET (set, regno);
+      }
+#endif
+#ifdef EH_RETURN_STACKADJ_RTX
+  if ((! HAVE_epilogue || ! reload_completed)
+      && current_function_calls_eh_return)
+    {
+      rtx tmp = EH_RETURN_STACKADJ_RTX;
+      if (tmp && REG_P (tmp))
+       mark_reg (tmp, set);
+    }
+#endif
+#ifdef EH_RETURN_HANDLER_RTX
+  if ((! HAVE_epilogue || ! reload_completed)
+      && current_function_calls_eh_return)
+    {
+      rtx tmp = EH_RETURN_HANDLER_RTX;
+      if (tmp && REG_P (tmp))
+       mark_reg (tmp, set);
+    }
+#endif
+
   /* Mark function return value.  */
   diddle_return_value (mark_reg, set);
 }
@@ -3402,13 +3735,19 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
      int flags;
 {
   basic_block *queue, *qhead, *qtail, *qend;
-  regset tmp, new_live_at_end;
-  regset_head tmp_head;
+  regset tmp, new_live_at_end, call_used;
+  regset_head tmp_head, call_used_head;
   regset_head new_live_at_end_head;
   int i;
 
   tmp = INITIALIZE_REG_SET (tmp_head);
   new_live_at_end = INITIALIZE_REG_SET (new_live_at_end_head);
+  call_used = INITIALIZE_REG_SET (call_used_head);
+
+  /* Inconveniently, this is only redily available in hard reg set form.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+    if (call_used_regs[i])
+      SET_REGNO_REG_SET (call_used, i);
 
   /* Create a worklist.  Allocate an extra slot for ENTRY_BLOCK, and one
      because the `head == tail' style test for an empty queue doesn't
@@ -3446,6 +3785,24 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
   if (blocks_out)
     sbitmap_zero (blocks_out);
 
+  /* We work through the queue until there are no more blocks.  What
+     is live at the end of this block is precisely the union of what
+     is live at the beginning of all its successors.  So, we set its
+     GLOBAL_LIVE_AT_END field based on the GLOBAL_LIVE_AT_START field
+     for its successors.  Then, we compute GLOBAL_LIVE_AT_START for
+     this block by walking through the instructions in this block in
+     reverse order and updating as we go.  If that changed
+     GLOBAL_LIVE_AT_START, we add the predecessors of the block to the
+     queue; they will now need to recalculate GLOBAL_LIVE_AT_END.
+
+     We are guaranteed to terminate, because GLOBAL_LIVE_AT_START
+     never shrinks.  If a register appears in GLOBAL_LIVE_AT_START, it
+     must either be live at the end of the block, or used within the
+     block.  In the latter case, it will certainly never disappear
+     from GLOBAL_LIVE_AT_START.  In the former case, the register
+     could go away only if it disappeared from GLOBAL_LIVE_AT_START
+     for one of the successor blocks.  By induction, that cannot
+     occur.  */
   while (qhead != qtail)
     {
       int rescan, changed;
@@ -3457,12 +3814,23 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
        qhead = queue;
       bb->aux = NULL;
 
-      /* Begin by propogating live_at_start from the successor blocks.  */
+      /* Begin by propagating live_at_start from the successor blocks.  */
       CLEAR_REG_SET (new_live_at_end);
       for (e = bb->succ; e; e = e->succ_next)
        {
          basic_block sb = e->dest;
-         IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
+
+         /* Call-clobbered registers die across exception and call edges.  */
+         /* ??? Abnormal call edges ignored for the moment, as this gets
+            confused by sibling call edges, which crashes reg-stack.  */
+         if (e->flags & EDGE_EH)
+           {
+             bitmap_operation (tmp, sb->global_live_at_start,
+                               call_used, BITMAP_AND_COMPL);
+             IOR_REG_SET (new_live_at_end, tmp);
+           }
+         else
+           IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
        }
 
       /* The all-important stack pointer must always be live.  */
@@ -3484,12 +3852,11 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
            SET_REGNO_REG_SET (new_live_at_end, ARG_POINTER_REGNUM);
 #endif
 
-#ifdef PIC_OFFSET_TABLE_REGNUM
          /* Any constant, or pseudo with constant equivalences, may
             require reloading from memory using the pic register.  */
-         if (fixed_regs[PIC_OFFSET_TABLE_REGNUM])
+         if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+             && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
            SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM);
-#endif
        }
 
       /* Regs used in phi nodes are not included in
@@ -3611,6 +3978,7 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
 
   FREE_REG_SET (tmp);
   FREE_REG_SET (new_live_at_end);
+  FREE_REG_SET (call_used);
 
   if (blocks_out)
     {
@@ -3696,14 +4064,26 @@ propagate_block_delete_insn (bb, insn)
   /* If the insn referred to a label, and that label was attached to
      an ADDR_VEC, it's safe to delete the ADDR_VEC.  In fact, it's
      pretty much mandatory to delete it, because the ADDR_VEC may be
-     referencing labels that no longer exist.  */
+     referencing labels that no longer exist.
+
+     INSN may reference a deleted label, particularly when a jump
+     table has been optimized into a direct jump.  There's no
+     real good way to fix up the reference to the deleted label
+     when the label is deleted, so we just allow it here.
+
+     After dead code elimination is complete, we do search for
+     any REG_LABEL notes which reference deleted labels as a
+     sanity check.  */
 
-  if (inote)
+  if (inote && GET_CODE (inote) == CODE_LABEL)
     {
       rtx label = XEXP (inote, 0);
       rtx next;
 
-      if (LABEL_NUSES (label) == 1
+      /* The label may be forced if it has been put in the constant
+        pool.  If that is the only use we must discard the table
+        jump following it, but not the label itself.  */
+      if (LABEL_NUSES (label) == 1 + LABEL_PRESERVE_P (label)
          && (next = next_nonnote_insn (label)) != NULL
          && GET_CODE (next) == JUMP_INSN
          && (GET_CODE (PATTERN (next)) == ADDR_VEC
@@ -3799,10 +4179,7 @@ propagate_one_insn (pbi, insn)
       pbi->cc0_live = 0;
 
       if (libcall_is_dead)
-       {
-         prev = propagate_block_delete_libcall (pbi->bb, insn, note);
-         insn = NEXT_INSN (prev);
-       }
+       prev = propagate_block_delete_libcall (pbi->bb, insn, note);
       else
        propagate_block_delete_insn (pbi->bb, insn);
 
@@ -4069,6 +4446,8 @@ init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
               else
                 cond = cond_true;
               rcli->condition = cond;
+              rcli->stores = const0_rtx;
+              rcli->orig_condition = cond;
 
               splay_tree_insert (pbi->reg_cond_dead, i,
                                  (splay_tree_value) rcli);
@@ -4090,20 +4469,29 @@ init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
       && (flags & PROP_SCAN_DEAD_CODE)
       && (bb->succ == NULL
          || (bb->succ->succ_next == NULL
-             && bb->succ->dest == EXIT_BLOCK_PTR)))
+             && bb->succ->dest == EXIT_BLOCK_PTR
+             && ! current_function_calls_eh_return)))
     {
-      rtx insn;
+      rtx insn, set;
       for (insn = bb->end; insn != bb->head; insn = PREV_INSN (insn))
        if (GET_CODE (insn) == INSN
-           && GET_CODE (PATTERN (insn)) == SET
-           && GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
+           && (set = single_set (insn))
+           && GET_CODE (SET_DEST (set)) == MEM)
          {
-           rtx mem = SET_DEST (PATTERN (insn));
+           rtx mem = SET_DEST (set);
+           rtx canon_mem = canon_rtx (mem);
+
+           /* This optimization is performed by faking a store to the
+              memory at the end of the block.  This doesn't work for
+              unchanging memories because multiple stores to unchanging
+              memory is illegal and alias analysis doesn't consider it.  */
+           if (RTX_UNCHANGING_P (canon_mem))
+             continue;
 
-           if (XEXP (mem, 0) == frame_pointer_rtx
-               || (GET_CODE (XEXP (mem, 0)) == PLUS
-                   && XEXP (XEXP (mem, 0), 0) == frame_pointer_rtx
-                   && GET_CODE (XEXP (XEXP (mem, 0), 1)) == CONST_INT))
+           if (XEXP (canon_mem, 0) == frame_pointer_rtx
+               || (GET_CODE (XEXP (canon_mem, 0)) == PLUS
+                   && XEXP (XEXP (canon_mem, 0), 0) == frame_pointer_rtx
+                   && GET_CODE (XEXP (XEXP (canon_mem, 0), 1)) == CONST_INT))
              {
 #ifdef AUTO_INC_DEC
                /* Store a copy of mem, otherwise the address may be scrogged
@@ -4278,27 +4666,28 @@ insn_dead_p (pbi, x, call_ok, notes)
          /* Walk the set of memory locations we are currently tracking
             and see if one is an identical match to this memory location.
             If so, this memory write is dead (remember, we're walking
-            backwards from the end of the block to the start).  */
-         temp = pbi->mem_set_list;
-         while (temp)
-           {
-             rtx mem = XEXP (temp, 0);
+            backwards from the end of the block to the start).  Since
+            rtx_equal_p does not check the alias set or flags, we also
+            must have the potential for them to conflict (anti_dependence). */
+         for (temp = pbi->mem_set_list; temp != 0; temp = XEXP (temp, 1))
+           if (anti_dependence (r, XEXP (temp, 0)))
+             {
+               rtx mem = XEXP (temp, 0);
 
-             if (rtx_equal_p (mem, r))
-               return 1;
+               if (rtx_equal_p (mem, r))
+                 return 1;
 #ifdef AUTO_INC_DEC
-             /* Check if memory reference matches an auto increment. Only
-                post increment/decrement or modify are valid.  */
-             if (GET_MODE (mem) == GET_MODE (r)
-                 && (GET_CODE (XEXP (mem, 0)) == POST_DEC
-                     || GET_CODE (XEXP (mem, 0)) == POST_INC
-                     || GET_CODE (XEXP (mem, 0)) == POST_MODIFY)
-                 && GET_MODE (XEXP (mem, 0)) == GET_MODE (r)
-                 && rtx_equal_p (XEXP (XEXP (mem, 0), 0), XEXP (r, 0)))
-               return 1;
+               /* Check if memory reference matches an auto increment. Only
+                  post increment/decrement or modify are valid.  */
+               if (GET_MODE (mem) == GET_MODE (r)
+                   && (GET_CODE (XEXP (mem, 0)) == POST_DEC
+                       || GET_CODE (XEXP (mem, 0)) == POST_INC
+                       || GET_CODE (XEXP (mem, 0)) == POST_MODIFY)
+                   && GET_MODE (XEXP (mem, 0)) == GET_MODE (r)
+                   && rtx_equal_p (XEXP (XEXP (mem, 0), 0), XEXP (r, 0)))
+                 return 1;
 #endif
-             temp = XEXP (temp, 1);
-           }
+             }
        }
       else
        {
@@ -4638,7 +5027,11 @@ mark_set_regs (pbi, x, insn)
     }
 }
 
-/* Process a single SET rtx, X.  */
+/* Process a single set, which appears in INSN.  REG (which may not
+   actually be a REG, it may also be a SUBREG, PARALLEL, etc.) is
+   being set using the CODE (which may be SET, CLOBBER, or COND_EXEC).
+   If the set is conditional (because it appear in a COND_EXEC), COND
+   will be the condition.  */
 
 static void
 mark_set_1 (pbi, code, reg, cond, insn, flags)
@@ -4648,7 +5041,7 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
      int flags;
 {
   int regno_first = -1, regno_last = -1;
-  int not_dead = 0;
+  unsigned long not_dead = 0;
   int i;
 
   /* Modifying just one hardware register of a multi-reg value or just a
@@ -4679,7 +5072,7 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
             || GET_CODE (reg) == STRICT_LOW_PART);
       if (GET_CODE (reg) == MEM)
        break;
-      not_dead = REGNO_REG_SET_P (pbi->reg_live, REGNO (reg));
+      not_dead = (unsigned long) REGNO_REG_SET_P (pbi->reg_live, REGNO (reg));
       /* Fall through.  */
 
     case REG:
@@ -4700,12 +5093,9 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
          regno_last = regno_first = REGNO (SUBREG_REG (reg));
          if (regno_first < FIRST_PSEUDO_REGISTER)
            {
-#ifdef ALTER_HARD_SUBREG
-             regno_first = ALTER_HARD_SUBREG (outer_mode, SUBREG_WORD (reg),
-                                              inner_mode, regno_first);
-#else
-             regno_first += SUBREG_WORD (reg);
-#endif
+             regno_first += subreg_regno_offset (regno_first, inner_mode,
+                                                 SUBREG_BYTE (reg),
+                                                 outer_mode);
              regno_last = (regno_first
                            + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
 
@@ -4727,7 +5117,8 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
                    + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
                  < ((GET_MODE_SIZE (inner_mode)
                      + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
-               not_dead = REGNO_REG_SET_P (pbi->reg_live, regno_first);
+               not_dead = (unsigned long) REGNO_REG_SET_P (pbi->reg_live,
+                                                           regno_first);
 
              reg = SUBREG_REG (reg);
            }
@@ -4823,7 +5214,7 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
        {
          for (i = regno_first; i <= regno_last; ++i)
            if (! mark_regno_cond_dead (pbi, i, cond))
-             not_dead = 1;
+             not_dead |= ((unsigned long) 1) << (i - regno_first);
        }
 #endif
 
@@ -4851,8 +5242,9 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
                  /* Count (weighted) references, stores, etc.  This counts a
                     register twice if it is modified, but that is correct.  */
                  REG_N_SETS (i) += 1;
-                 REG_N_REFS (i) += (optimize_size ? 1
-                                    : pbi->bb->loop_depth + 1);
+                 REG_N_REFS (i) += 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
@@ -4936,7 +5328,6 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
 
       /* Mark the register as being dead.  */
       if (some_was_live
-         && ! not_dead
          /* The stack pointer is never dead.  Well, not strictly true,
             but it's very difficult to tell from here.  Hopefully
             combine_stack_adjustments will fix up the most egregious
@@ -4944,7 +5335,8 @@ mark_set_1 (pbi, code, reg, cond, insn, flags)
          && regno_first != STACK_POINTER_REGNUM)
        {
          for (i = regno_first; i <= regno_last; ++i)
-           CLEAR_REGNO_REG_SET (pbi->reg_live, i);
+           if (!(not_dead & (((unsigned long) 1) << (i - regno_first))))
+             CLEAR_REGNO_REG_SET (pbi->reg_live, i);
        }
     }
   else if (GET_CODE (reg) == REG)
@@ -5003,6 +5395,8 @@ mark_regno_cond_dead (pbi, regno, cond)
             which it is dead.  */
          rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
          rcli->condition = cond;
+         rcli->stores = cond;
+         rcli->orig_condition = const0_rtx;
          splay_tree_insert (pbi->reg_cond_dead, regno,
                             (splay_tree_value) rcli);
 
@@ -5018,10 +5412,21 @@ mark_regno_cond_dead (pbi, regno, cond)
          rcli = (struct reg_cond_life_info *) node->value;
          ncond = rcli->condition;
          ncond = ior_reg_cond (ncond, cond, 1);
-
-         /* If the register is now unconditionally dead,
-            remove the entry in the splay_tree.  */
-         if (ncond == const1_rtx)
+         if (rcli->stores == const0_rtx)
+           rcli->stores = cond;
+         else if (rcli->stores != const1_rtx)
+           rcli->stores = ior_reg_cond (rcli->stores, cond, 1);
+
+         /* If the register is now unconditionally dead, remove the entry
+            in the splay_tree.  A register is unconditionally dead if the
+            dead condition ncond is true.  A register is also unconditionally
+            dead if the sum of all conditional stores is an unconditional
+            store (stores is true), and the dead condition is identically the
+            same as the original dead condition initialized at the end of
+            the block.  This is a pointer compare, not an rtx_equal_p
+            compare.  */
+         if (ncond == const1_rtx
+             || (ncond == rcli->orig_condition && rcli->stores == const1_rtx))
            splay_tree_remove (pbi->reg_cond_dead, regno);
          else
            {
@@ -5067,6 +5472,8 @@ flush_reg_cond_reg_1 (node, data)
   /* Splice out portions of the expression that refer to regno.  */
   rcli = (struct reg_cond_life_info *) node->value;
   rcli->condition = elim_reg_cond (rcli->condition, regno);
+  if (rcli->stores != const0_rtx && rcli->stores != const1_rtx)
+    rcli->stores = elim_reg_cond (rcli->stores, regno);
 
   /* If the entire condition is now false, signal the node to be removed.  */
   if (rcli->condition == const0_rtx)
@@ -5117,7 +5524,7 @@ ior_reg_cond (old, x, add)
   if (GET_RTX_CLASS (GET_CODE (old)) == '<')
     {
       if (GET_RTX_CLASS (GET_CODE (x)) == '<'
-         && GET_CODE (x) == reverse_condition (GET_CODE (old))
+         && REVERSE_CONDEXEC_PREDICATES_P (GET_CODE (x), GET_CODE (old))
          && REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
        return const1_rtx;
       if (GET_CODE (x) == GET_CODE (old)
@@ -5273,6 +5680,17 @@ and_reg_cond (old, x, add)
        }
       if (! add)
        return old;
+
+      /* If X is identical to one of the existing terms of the AND,
+        then just return what we already have.  */
+      /* ??? There really should be some sort of recursive check here in
+        case there are nested ANDs.  */
+      if ((GET_CODE (XEXP (old, 0)) == GET_CODE (x)
+          && REGNO (XEXP (XEXP (old, 0), 0)) == REGNO (XEXP (x, 0)))
+         || (GET_CODE (XEXP (old, 1)) == GET_CODE (x)
+             && REGNO (XEXP (XEXP (old, 1), 0)) == REGNO (XEXP (x, 0))))
+       return old;
+
       return gen_rtx_AND (0, old, x);
 
     case NOT:
@@ -5493,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_N_REFS (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.  */
@@ -5597,35 +6016,37 @@ mark_used_reg (pbi, reg, cond, insn)
      rtx cond ATTRIBUTE_UNUSED;
      rtx insn;
 {
-  int regno = REGNO (reg);
-  int some_was_live = REGNO_REG_SET_P (pbi->reg_live, regno);
-  int some_was_dead = ! some_was_live;
-  int some_not_set;
-  int n;
+  unsigned int regno_first, regno_last, i;
+  int some_was_live, some_was_dead, some_not_set;
 
-  /* A hard reg in a wide mode may really be multiple registers.
-     If so, mark all of them just like the first.  */
-  if (regno < FIRST_PSEUDO_REGISTER)
+  regno_last = regno_first = REGNO (reg);
+  if (regno_first < FIRST_PSEUDO_REGISTER)
+    regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
+
+  /* Find out if any of this register is live after this instruction.  */
+  some_was_live = some_was_dead = 0;
+  for (i = regno_first; i <= regno_last; ++i)
     {
-      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-      while (--n > 0)
-       {
-         int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno + n);
-         some_was_live |= needed_regno;
-         some_was_dead |= ! needed_regno;
-       }
+      int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
+      some_was_live |= needed_regno;
+      some_was_dead |= ! needed_regno;
     }
 
+  /* Find out if any of the register was set this insn.  */
+  some_not_set = 0;
+  for (i = regno_first; i <= regno_last; ++i)
+    some_not_set |= ! REGNO_REG_SET_P (pbi->new_set, i);
+
   if (pbi->flags & (PROP_LOG_LINKS | PROP_AUTOINC))
     {
       /* Record where each reg is used, so when the reg is set we know
         the next insn that uses it.  */
-      pbi->reg_next_use[regno] = insn;
+      pbi->reg_next_use[regno_first] = insn;
     }
 
   if (pbi->flags & PROP_REG_INFO)
     {
-      if (regno < FIRST_PSEUDO_REGISTER)
+      if (regno_first < FIRST_PSEUDO_REGISTER)
        {
          /* If this is a register we are going to try to eliminate,
             don't mark it live here.  If we are successful in
@@ -5639,41 +6060,29 @@ mark_used_reg (pbi, reg, cond, insn)
             register to itself.  This should be fixed.  In the mean
             time, hack around it.  */
 
-         if (! (TEST_HARD_REG_BIT (elim_reg_set, regno)
-                && (regno == FRAME_POINTER_REGNUM
-                    || regno == ARG_POINTER_REGNUM)))
-           {
-             int n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-             do
-               regs_ever_live[regno + --n] = 1;
-             while (n > 0);
-           }
+         if (! (TEST_HARD_REG_BIT (elim_reg_set, regno_first)
+                && (regno_first == FRAME_POINTER_REGNUM
+                    || regno_first == ARG_POINTER_REGNUM)))
+           for (i = regno_first; i <= regno_last; ++i)
+             regs_ever_live[i] = 1;
        }
       else
        {
          /* Keep track of which basic block each reg appears in.  */
 
          register int blocknum = pbi->bb->index;
-         if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
-           REG_BASIC_BLOCK (regno) = blocknum;
-         else if (REG_BASIC_BLOCK (regno) != blocknum)
-           REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
+         if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
+           REG_BASIC_BLOCK (regno_first) = blocknum;
+         else if (REG_BASIC_BLOCK (regno_first) != blocknum)
+           REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
 
          /* Count (weighted) number of uses of each reg.  */
-         REG_N_REFS (regno) += (optimize_size ? 1
-                                : pbi->bb->loop_depth + 1);
+         REG_FREQ (regno_first)
+           += (optimize_size || !pbi->bb->frequency ? 1 : pbi->bb->frequency);
+         REG_N_REFS (regno_first)++;
        }
     }
 
-  /* Find out if any of the register was set this insn.  */
-  some_not_set = ! REGNO_REG_SET_P (pbi->new_set, regno);
-  if (regno < FIRST_PSEUDO_REGISTER)
-    {
-      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-      while (--n > 0)
-       some_not_set |= ! REGNO_REG_SET_P (pbi->new_set, regno + n);
-    }
-
   /* Record and count the insns in which a reg dies.  If it is used in
      this insn and was dead below the insn then it dies in this insn.
      If it was set in this insn, we do not make a REG_DEAD note;
@@ -5684,120 +6093,102 @@ mark_used_reg (pbi, reg, cond, insn)
     {
       /* Check for the case where the register dying partially
         overlaps the register set by this insn.  */
-      if (regno < FIRST_PSEUDO_REGISTER
-         && HARD_REGNO_NREGS (regno, GET_MODE (reg)) > 1)
-       {
-         n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-         while (--n >= 0)
-           some_was_live |= REGNO_REG_SET_P (pbi->new_set, regno + n);
-       }
+      if (regno_first != regno_last)
+       for (i = regno_first; i <= regno_last; ++i)
+         some_was_live |= REGNO_REG_SET_P (pbi->new_set, i);
 
       /* If none of the words in X is needed, make a REG_DEAD note.
         Otherwise, we must make partial REG_DEAD notes.  */
       if (! some_was_live)
        {
          if ((pbi->flags & PROP_DEATH_NOTES)
-             && ! find_regno_note (insn, REG_DEAD, regno))
+             && ! find_regno_note (insn, REG_DEAD, regno_first))
            REG_NOTES (insn)
              = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
 
          if (pbi->flags & PROP_REG_INFO)
-           REG_N_DEATHS (regno)++;
+           REG_N_DEATHS (regno_first)++;
        }
       else
        {
          /* Don't make a REG_DEAD note for a part of a register
             that is set in the insn.  */
-
-         n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
-         for (; n >= regno; n--)
-           if (! REGNO_REG_SET_P (pbi->reg_live, n)
-               && ! dead_or_set_regno_p (insn, n))
+         for (i = regno_first; i <= regno_last; ++i)
+           if (! REGNO_REG_SET_P (pbi->reg_live, i)
+               && ! dead_or_set_regno_p (insn, i))
              REG_NOTES (insn)
                = alloc_EXPR_LIST (REG_DEAD,
-                                  gen_rtx_REG (reg_raw_mode[n], n),
+                                  gen_rtx_REG (reg_raw_mode[i], i),
                                   REG_NOTES (insn));
        }
     }
 
-  SET_REGNO_REG_SET (pbi->reg_live, regno);
-  if (regno < FIRST_PSEUDO_REGISTER)
+  /* Mark the register as being live.  */
+  for (i = regno_first; i <= regno_last; ++i)
     {
-      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-      while (--n > 0)
-       SET_REGNO_REG_SET (pbi->reg_live, regno + n);
-    }
+      SET_REGNO_REG_SET (pbi->reg_live, i);
 
 #ifdef HAVE_conditional_execution
-  /* If this is a conditional use, record that fact.  If it is later
-     conditionally set, we'll know to kill the register.  */
-  if (cond != NULL_RTX)
-    {
-      splay_tree_node node;
-      struct reg_cond_life_info *rcli;
-      rtx ncond;
-
-      if (some_was_live)
+      /* If this is a conditional use, record that fact.  If it is later
+        conditionally set, we'll know to kill the register.  */
+      if (cond != NULL_RTX)
        {
-         node = splay_tree_lookup (pbi->reg_cond_dead, regno);
-         if (node == NULL)
-           {
-             /* The register was unconditionally live previously.
-                No need to do anything.  */
-           }
-         else
+         splay_tree_node node;
+         struct reg_cond_life_info *rcli;
+         rtx ncond;
+
+         if (some_was_live)
            {
-             /* The register was conditionally live previously.
-                Subtract the new life cond from the old death cond.  */
-             rcli = (struct reg_cond_life_info *) node->value;
-             ncond = rcli->condition;
-             ncond = and_reg_cond (ncond, not_reg_cond (cond), 1);
-
-             /* If the register is now unconditionally live, remove the
-                entry in the splay_tree.  */
-             if (ncond == const0_rtx)
+             node = splay_tree_lookup (pbi->reg_cond_dead, i);
+             if (node == NULL)
                {
-                 rcli->condition = NULL_RTX;
-                 splay_tree_remove (pbi->reg_cond_dead, regno);
+                 /* The register was unconditionally live previously.
+                    No need to do anything.  */
                }
              else
                {
-                 rcli->condition = ncond;
-                 SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
+                 /* The register was conditionally live previously.
+                    Subtract the new life cond from the old death cond.  */
+                 rcli = (struct reg_cond_life_info *) node->value;
+                 ncond = rcli->condition;
+                 ncond = and_reg_cond (ncond, not_reg_cond (cond), 1);
+
+                 /* If the register is now unconditionally live,
+                    remove the entry in the splay_tree.  */
+                 if (ncond == const0_rtx)
+                   splay_tree_remove (pbi->reg_cond_dead, i);
+                 else
+                   {
+                     rcli->condition = ncond;
+                     SET_REGNO_REG_SET (pbi->reg_cond_reg,
+                                        REGNO (XEXP (cond, 0)));
+                   }
                }
            }
-       }
-      else
-       {
-         /* The register was not previously live at all.  Record
-            the condition under which it is still dead.  */
-         rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
-         rcli->condition = not_reg_cond (cond);
-         splay_tree_insert (pbi->reg_cond_dead, regno,
-                            (splay_tree_value) rcli);
+         else
+           {
+             /* The register was not previously live at all.  Record
+                the condition under which it is still dead.  */
+             rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
+             rcli->condition = not_reg_cond (cond);
+             rcli->stores = const0_rtx;
+             rcli->orig_condition = const0_rtx;
+             splay_tree_insert (pbi->reg_cond_dead, i,
+                                (splay_tree_value) rcli);
 
-         SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
+             SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
+           }
        }
-    }
-  else if (some_was_live)
-    {
-      splay_tree_node node;
-      struct reg_cond_life_info *rcli;
-
-      node = splay_tree_lookup (pbi->reg_cond_dead, regno);
-      if (node != NULL)
+      else if (some_was_live)
        {
-         /* The register was conditionally live previously, but is now
-            unconditionally so.  Remove it from the conditionally dead
-            list, so that a conditional set won't cause us to think
+         /* The register may have been conditionally live previously, but
+            is now unconditionally live.  Remove it from the conditionally
+            dead list, so that a conditional set won't cause us to think
             it dead.  */
-         rcli = (struct reg_cond_life_info *) node->value;
-         rcli->condition = NULL_RTX;
-         splay_tree_remove (pbi->reg_cond_dead, regno);
+         splay_tree_remove (pbi->reg_cond_dead, i);
        }
-    }
-
 #endif
+    }
 }
 
 /* Scan expression X and store a 1-bit in NEW_LIVE for each reg it uses.
@@ -6109,8 +6500,8 @@ try_pre_increment_1 (pbi, insn)
         so we want to make that less likely.  */
       if (regno >= FIRST_PSEUDO_REGISTER)
        {
-         REG_N_REFS (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)++;
        }
 
@@ -6292,6 +6683,10 @@ dump_regset (r, outf)
     });
 }
 
+/* Print a human-reaable representation of R on the standard error
+   stream.  This function is designed to be used from within the
+   debugger.  */
+
 void
 debug_regset (r)
      regset r;
@@ -6353,8 +6748,10 @@ dump_flow_info (file)
       register basic_block bb = BASIC_BLOCK (i);
       register edge e;
 
-      fprintf (file, "\nBasic block %d: first insn %d, last %d, loop_depth %d, count %d.\n",
-              i, INSN_UID (bb->head), INSN_UID (bb->end), bb->loop_depth, bb->count);
+      fprintf (file, "\nBasic block %d: first insn %d, last %d, loop_depth %d, count ",
+              i, INSN_UID (bb->head), INSN_UID (bb->end), bb->loop_depth);
+      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
+      fprintf (file, ", freq %i.\n", bb->frequency);
 
       fprintf (file, "Predecessors: ");
       for (e = bb->pred; e; e = e->pred_next)
@@ -6382,7 +6779,7 @@ debug_flow_info ()
   dump_flow_info (stderr);
 }
 
-static void
+void
 dump_edge_info (file, e, do_succ)
      FILE *file;
      edge e;
@@ -6397,8 +6794,14 @@ 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:%d", e->count);
+    {
+      fprintf (file, " count:");
+      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) e->count);
+    }
 
   if (e->flags)
     {
@@ -6438,10 +6841,9 @@ dump_bb (bb, outf)
   rtx last;
   edge e;
 
-  fprintf (outf, ";; Basic block %d, loop depth %d, count %d",
-          bb->index, bb->loop_depth, bb->count);
-  if (bb->eh_beg != -1 || bb->eh_end != -1)
-    fprintf (outf, ", eh regions %d/%d", bb->eh_beg, bb->eh_end);
+  fprintf (outf, ";; Basic block %d, loop depth %d, count ",
+          bb->index, bb->loop_depth);
+  fprintf (outf, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) bb->count);
   putc ('\n', outf);
 
   fputs (";; Predecessors: ", outf);
@@ -6574,15 +6976,20 @@ print_rtl_with_bb (outf, rtx_first)
 }
 
 /* Dump the rtl into the current debugging dump file, then abort.  */
+
 static void
-print_rtl_and_abort ()
+print_rtl_and_abort_fcn (file, line, function)
+     const char *file;
+     int line;
+     const char *function;
 {
   if (rtl_dump_file)
     {
       print_rtl_with_bb (rtl_dump_file, get_insns ());
       fclose (rtl_dump_file);
     }
-  abort ();
+
+  fancy_abort (file, line, function);
 }
 
 /* Recompute register set/reference counts immediately prior to register
@@ -6727,15 +7134,32 @@ set_block_for_insn (insn, bb)
   VARRAY_BB (basic_block_for_insn, uid) = bb;
 }
 
-/* Record INSN's block number as BB.  */
-/* ??? This has got to go.  */
+/* When a new insn has been inserted into an existing block, it will
+   sometimes emit more than a single insn. This routine will set the
+   block number for the specified insn, and look backwards in the insn
+   chain to see if there are any other uninitialized insns immediately 
+   previous to this one, and set the block number for them too.  */
 
 void
-set_block_num (insn, bb)
+set_block_for_new_insns (insn, bb)
      rtx insn;
-     int bb;
+     basic_block bb;
 {
-  set_block_for_insn (insn, BASIC_BLOCK (bb));
+  set_block_for_insn (insn, bb);
+
+  /* Scan the previous instructions setting the block number until we find 
+     an instruction that has the block number set, or we find a note 
+     of any kind.  */
+  for (insn = PREV_INSN (insn); insn != NULL_RTX; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == NOTE)
+       break;
+      if (INSN_UID (insn) >= basic_block_for_insn->num_elements 
+         || BLOCK_FOR_INSN (insn) == 0)
+       set_block_for_insn (insn, bb);
+      else
+       break;
+    }
 }
 \f
 /* Verify the CFG consistency.  This function check some CFG invariants and
@@ -6941,7 +7365,9 @@ verify_flow_info ()
          basic_block bb = NOTE_BASIC_BLOCK (x);
          num_bb_notes++;
          if (bb->index != last_bb_num_seen + 1)
-           fatal ("Basic blocks not numbered consecutively");
+           /* Basic blocks not numbered consecutively.  */
+           abort ();
+              
          last_bb_num_seen = bb->index;
        }
 
@@ -6981,8 +7407,9 @@ verify_flow_info ()
     }
 
   if (num_bb_notes != n_basic_blocks)
-    fatal ("number of bb notes in insn chain (%d) != n_basic_blocks (%d)",
-          num_bb_notes, n_basic_blocks);
+    internal_error
+      ("number of bb notes in insn chain (%d) != n_basic_blocks (%d)",
+       num_bb_notes, n_basic_blocks);
 
   if (err)
     abort ();
@@ -7814,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;