Makefile.in (cfgrtl.o): Add.
authorJan Hubicka <jh@suse.cz>
Tue, 25 Sep 2001 15:26:55 +0000 (17:26 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Tue, 25 Sep 2001 15:26:55 +0000 (15:26 +0000)
* Makefile.in (cfgrtl.o): Add.
* basic-block.h (alloc_block, alloc_aux_for_block, alloc_aux_for_blocks,
free_aux_for_block, alloc_aux_for_edge, alloc_aux_for_edges,
free_aux_for_edge): Declare.
* cfg.c
(HAVE_return): Undefine.
* basic-block.h (alloc_block, alloc_aux_for_block, alloc_aux_for_blocks,
free_aux_for_block, alloc_aux_for_edge, alloc_aux_for_edges,
free_aux_for_edge): New global functions.
(first_delete_block): New static variable.
(init_flow): Clear first_delete_block.
(basic_block_for_insn, label_value_list, tail_recursion_label_list,
 can_delete_note_p, can_delete_label_p, commit_one_edge_insertion,
 try_redirect_by_replacing_jump, last_loop_beg_note,
 back_edge_of_syntactic_loop_p, force_nonfallthru_and_redirect,
 delete_insn, delete_insn_chain, create_basic_block_structure,
 create_basic_block, flow_delete_block, compute_bb_for_insn,
 free_bb_for_insn, update_bb_for_insn, set_block_for_insn,
 set_block_for_new_insns, split_block, merge_blocks_nomove,
 block_label, try_redirect_by_replacing_jump, last_loop_beg_note,
 redirect_edge_and_branch, force_nonfallthru_and_redirect,
 force_nonfallthru, redirect_edge_and_branch_force, tidy_fallthru_edge,
 tidy_fallthru_edges, split_edge, insert_insn_on_edge,
 commit_one_edge_insertion, commit_edge_insertions, dump_bb, debug_bb,
 debug_bb_n, print_rtl_with_bb, verify_flow_info, purge_dead_edges,
 purge_all_dead_edges): Move to ....
* cfgrtl.c: New file; .... Here.

* bb-reorder.c (fixup_reorder_chain): Use alloc_aux_for_block.
(reroder_basic_block): Use alloc_aux_for_blocks.
* predict.c (estimate_bb_frequencies): Likewise; use
alloc_aux_for_edges.
* profile.c (compute_branch_probabilities): Likewise.
(branch_prob): Likewise.
* reg-stack.c (reg_to_stack): Likewise.

* emit-rtl.c (emit_insns_after): Never return NULL.

* basic-block.h (set_block_for_new_insns): Delete.
* cfgrtl.c (set_block_for_new_insns): Delete.

* cfgcleanup.c (try_optimize_cfg): Add fake exit edges for noreturn
calls when crossjumping.

* cfgcleanup.c (try_simplify_condjump): Cleanup invert_jump call.
* unroll.c (copy_loop_body): Use delete_insn.

* final.c (final, final_scan_insn): Use delete_insn/delete_note.
* function.c (fixup_var_refs_insn, fixup_var_refs_1,
keep_stack_depressed): Likewise.
* gcse.c (cprop_cc0_jump): Likewise.
* local-alloc.c (update_equiv_regs): Likewise.
* loop.c (scan_loop, loop_delete_insns): Likewise.
* regmove.c (try_auto_increment, fixup_match_1): Likewise.
* reload1.c (reload, calculate_needs_all_insns, reload_as_needed,
delete_output_reload, delete_address_reloads_1,
reload_cse_delete_noop_set, reload_combine, reload_cse_move2add):
Likewise.
* sibcall.c (replace_call_placeholder): Likewise.
* cse.c (cse_insn): Likewise.

From-SVN: r45807

20 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/basic-block.h
gcc/bb-reorder.c
gcc/cfg.c
gcc/cfgcleanup.c
gcc/cfgrtl.c [new file with mode: 0644]
gcc/emit-rtl.c
gcc/final.c
gcc/function.c
gcc/gcse.c
gcc/local-alloc.c
gcc/loop.c
gcc/predict.c
gcc/profile.c
gcc/reg-stack.c
gcc/regmove.c
gcc/reload1.c
gcc/sibcall.c
gcc/unroll.c

index 2f8878ed992458f0e693931cc01d740709c50e69..6b434277309bea712bfd9e3c66a01bbc2ec0e517 100644 (file)
@@ -1,3 +1,66 @@
+Tue Sep 25 17:13:56 CEST 2001  Jan Hubicka  <jh@suse.cz>
+
+       * Makefile.in (cfgrtl.o): Add.
+       * basic-block.h (alloc_block, alloc_aux_for_block, alloc_aux_for_blocks,
+       free_aux_for_block, alloc_aux_for_edge, alloc_aux_for_edges,
+       free_aux_for_edge): Declare.
+       * cfg.c
+       (HAVE_return): Undefine.
+       * basic-block.h (alloc_block, alloc_aux_for_block, alloc_aux_for_blocks,
+       free_aux_for_block, alloc_aux_for_edge, alloc_aux_for_edges,
+       free_aux_for_edge): New global functions.
+       (first_delete_block): New static variable.
+       (init_flow): Clear first_delete_block.
+       (basic_block_for_insn, label_value_list, tail_recursion_label_list,
+        can_delete_note_p, can_delete_label_p, commit_one_edge_insertion,
+        try_redirect_by_replacing_jump, last_loop_beg_note,
+        back_edge_of_syntactic_loop_p, force_nonfallthru_and_redirect,
+        delete_insn, delete_insn_chain, create_basic_block_structure,
+        create_basic_block, flow_delete_block, compute_bb_for_insn,
+        free_bb_for_insn, update_bb_for_insn, set_block_for_insn,
+        set_block_for_new_insns, split_block, merge_blocks_nomove,
+        block_label, try_redirect_by_replacing_jump, last_loop_beg_note,
+        redirect_edge_and_branch, force_nonfallthru_and_redirect,
+        force_nonfallthru, redirect_edge_and_branch_force, tidy_fallthru_edge,
+        tidy_fallthru_edges, split_edge, insert_insn_on_edge,
+        commit_one_edge_insertion, commit_edge_insertions, dump_bb, debug_bb,
+        debug_bb_n, print_rtl_with_bb, verify_flow_info, purge_dead_edges,
+        purge_all_dead_edges): Move to ....
+       * cfgrtl.c: New file; .... Here.
+
+       * bb-reorder.c (fixup_reorder_chain): Use alloc_aux_for_block.
+       (reroder_basic_block): Use alloc_aux_for_blocks.
+       * predict.c (estimate_bb_frequencies): Likewise; use
+       alloc_aux_for_edges.
+       * profile.c (compute_branch_probabilities): Likewise.
+       (branch_prob): Likewise.
+       * reg-stack.c (reg_to_stack): Likewise.
+
+       * emit-rtl.c (emit_insns_after): Never return NULL.
+
+       * basic-block.h (set_block_for_new_insns): Delete.
+       * cfgrtl.c (set_block_for_new_insns): Delete.
+
+       * cfgcleanup.c (try_optimize_cfg): Add fake exit edges for noreturn
+       calls when crossjumping.
+
+       * cfgcleanup.c (try_simplify_condjump): Cleanup invert_jump call.
+       * unroll.c (copy_loop_body): Use delete_insn.
+
+       * final.c (final, final_scan_insn): Use delete_insn/delete_note.
+       * function.c (fixup_var_refs_insn, fixup_var_refs_1,
+       keep_stack_depressed): Likewise.
+       * gcse.c (cprop_cc0_jump): Likewise.
+       * local-alloc.c (update_equiv_regs): Likewise.
+       * loop.c (scan_loop, loop_delete_insns): Likewise.
+       * regmove.c (try_auto_increment, fixup_match_1): Likewise.
+       * reload1.c (reload, calculate_needs_all_insns, reload_as_needed,
+       delete_output_reload, delete_address_reloads_1,
+       reload_cse_delete_noop_set, reload_combine, reload_cse_move2add):
+       Likewise.
+       * sibcall.c (replace_call_placeholder): Likewise.
+       * cse.c (cse_insn): Likewise.
+
 2001-09-25  Bernd Schmidt  <bernds@redhat.com>
 
        From Graham Stott  <grahams@redhat.com>
index 6daa0ab012cbb532add9d6b86e4ee99b0d555a2b..5cc264cba2949e6ac9740adf9fe6b9addff4c31e 100644 (file)
@@ -747,7 +747,7 @@ OBJS =                                                                      \
  sdbout.o sibcall.o simplify-rtx.o splay-tree.o ssa.o ssa-ccp.o         \
  ssa-dce.o stmt.o stor-layout.o stringpool.o timevar.o toplev.o tree.o  \
  unroll.o varasm.o varray.o version.o xcoffout.o cfg.o cfganal.o       \
- cfgbuild.o cfgcleanup.o cfgloop.o        \
+ cfgbuild.o cfgcleanup.o cfgloop.o cfgrtl.o        \
  $(GGC) $(out_object_file) $(EXTRA_OBJS)
 
 BACKEND = main.o libbackend.a
@@ -1497,6 +1497,9 @@ flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h insn-config.h
 cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h insn-config.h \
    $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
    function.h except.h $(GGC_H) $(TM_P_H)
+cfgrtl.o : cfgrtl.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h insn-config.h \
+   $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h $(RECOG_H) \
+   function.h except.h $(GGC_H) $(TM_P_H)
 cfganal.o : cfganal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
    $(BASIC_BLOCK_H) hard-reg-set.h $(GGC_H)
 cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h insn-config.h \
index 880d6ee908784dc0844cce6d83a6ffe8920c7830..9b215c532230178ced1a5d52bc1a903a20cabd98 100644 (file)
@@ -291,7 +291,6 @@ extern void compute_bb_for_insn             PARAMS ((int));
 extern void free_bb_for_insn           PARAMS ((void));
 extern void update_bb_for_insn         PARAMS ((basic_block));
 extern void set_block_for_insn         PARAMS ((rtx, basic_block));
-extern void set_block_for_new_insns    PARAMS ((rtx, basic_block));
 
 extern void free_basic_block_vars      PARAMS ((int));
 
@@ -630,6 +629,7 @@ extern void debug_regset            PARAMS ((regset));
 extern void allocate_reg_life_data      PARAMS ((void));
 extern void allocate_bb_life_data      PARAMS ((void));
 extern void expunge_block              PARAMS ((basic_block));
+extern basic_block alloc_block         PARAMS ((void));
 extern void find_unreachable_blocks    PARAMS ((void));
 extern void delete_noop_moves          PARAMS ((rtx));
 extern basic_block redirect_edge_and_branch_force PARAMS ((edge, basic_block));
@@ -645,6 +645,12 @@ extern void flow_nodes_print               PARAMS ((const char *, const sbitmap,
                                                 FILE *));
 extern void flow_edge_list_print       PARAMS ((const char *, const edge *,
                                                 int, FILE *));
+extern void alloc_aux_for_block                PARAMS ((basic_block, int));
+extern void alloc_aux_for_blocks       PARAMS ((int));
+extern void free_aux_for_blocks                PARAMS ((void));
+extern void alloc_aux_for_edge         PARAMS ((edge, int));
+extern void alloc_aux_for_edges                PARAMS ((int));
+extern void free_aux_for_edges         PARAMS ((void));
 
 /* This function is always defined so it can be called from the
    debugger, and it is declared extern so we don't get warnings about
index c471a6fa6e837999a8eb3197db7123f91a67be6b..aa303158dc12bd8c9bf80b4b82f4e24a7d224b3c 100644 (file)
@@ -660,7 +660,7 @@ fixup_reorder_chain ()
 
       if (nb)
        {
-         nb->aux = xmalloc (sizeof (struct reorder_block_def));
+         alloc_aux_for_block (nb, sizeof (struct reorder_block_def));
          RBI (nb)->eff_head = nb->head;
          RBI (nb)->eff_end = NEXT_INSN (nb->end);
          RBI (nb)->scope = RBI (bb)->scope;
@@ -1327,15 +1327,11 @@ void
 reorder_basic_blocks ()
 {
   scope_forest_info forest;
-  int i;
 
   if (n_basic_blocks <= 1)
     return;
 
-  for (i = 0; i < n_basic_blocks; i++)
-    BASIC_BLOCK (i)->aux = xcalloc (1, sizeof (struct reorder_block_def));
-
-  EXIT_BLOCK_PTR->aux = xcalloc (1, sizeof (struct reorder_block_def));
+  alloc_aux_for_blocks (sizeof (struct reorder_block_def));
 
   build_scope_forest (&forest);
   remove_scope_notes ();
@@ -1356,10 +1352,7 @@ reorder_basic_blocks ()
   free_scope_forest (&forest);
   reorder_blocks ();
 
-  for (i = 0; i < n_basic_blocks; i++)
-    free (BASIC_BLOCK (i)->aux);
-
-  free (EXIT_BLOCK_PTR->aux);
+  free_aux_for_blocks ();
 
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
index 9988ecd20990d05fd05004a5b148fe763a4f0781..932b7e32c019a29459e7ef1bf2ab1965cfb60346 100644 (file)
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -21,35 +21,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 /* This file contains low level functions to manipulate with CFG and analyze it.
    All other modules should not transform the datastructure directly and use
-   abstraction instead.  The file is supposed to be ordered bottom-up.
+   abstraction instead.  The file is supposed to be ordered bottom-up and should
+   not contain any code depdendent on particular intermediate language (RTL or trees)
 
    Available functionality:
      - Initialization/deallocation
         init_flow, clear_edges
-     - CFG aware instruction chain manipulation
-        delete_insn, delete_insn_chain
-     - Basic block manipulation
-        create_basic_block, flow_delete_block, split_block, merge_blocks_nomove
-     - Infrastructure to determine quickly basic block for instruction.
-        compute_bb_for_insn, update_bb_for_insn, set_block_for_insn,
-        set_block_for_new_insns
+     - Low level basic block manipulation
+        alloc_block, expunge_block
      - Edge manipulation
         make_edge, make_single_succ_edge, cached_make_edge, remove_edge
         - Low level edge redirection (without updating instruction chain)
             redirect_edge_succ, redirect_edge_succ_nodup, redirect_edge_pred
-        - High level edge redirection (with updating and optimizing instruction
-          chain)
-            block_label, redirect_edge_and_branch,
-            redirect_edge_and_branch_force, tidy_fallthru_edge, force_nonfallthru
-      - Edge splitting and commiting to edges
-         split_edge, insert_insn_on_edge, commit_edge_insertions
-      - Dumpipng and debugging
-         dump_flow_info, debug_flow_info, dump_edge_info, dump_bb, debug_bb,
-         debug_bb_n, print_rtl_with_bb
-      - Consistency checking
-         verify_flow_info
-      - CFG updating after constant propagation
-         purge_dead_edges, purge_all_dead_edges
+     - Dumpipng and debugging
+        dump_flow_info, debug_flow_info, dump_edge_info
+     - Allocation of AUX fields for basic blocks
+        alloc_aux_for_blocks, free_aux_for_blocks, alloc_aux_for_block
  */
 \f
 #include "config.h"
@@ -67,13 +54,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm_p.h"
 #include "obstack.h"
 
-
-/* Stubs in case we haven't got a return insn.  */
-#ifndef HAVE_return
-#define HAVE_return 0
-#define gen_return() NULL_RTX
-#endif
-
 /* The obstack on which the flow graph components are allocated.  */
 
 struct obstack flow_obstack;
@@ -90,6 +70,7 @@ int n_edges;
 /* First edge in the deleted edges chain.  */
 
 edge first_deleted_edge;
+static basic_block first_deleted_block;
 
 /* The basic block array.  */
 
@@ -135,25 +116,7 @@ struct basic_block_def entry_exit_blocks[2]
   }
 };
 
-/* The basic block structure for every insn, indexed by uid.  */
-
-varray_type basic_block_for_insn;
-
-/* The labels mentioned in non-jump rtl.  Valid during find_basic_blocks.  */
-/* ??? Should probably be using LABEL_NUSES instead.  It would take a
-   bit of surgery to be able to use or co-opt the routines in jump.  */
-
-rtx label_value_list;
-rtx tail_recursion_label_list;
-
 void debug_flow_info                   PARAMS ((void));
-static int can_delete_note_p           PARAMS ((rtx));
-static int can_delete_label_p          PARAMS ((rtx));
-static void commit_one_edge_insertion  PARAMS ((edge));
-static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
-static rtx last_loop_beg_note          PARAMS ((rtx));
-static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
-static basic_block force_nonfallthru_and_redirect PARAMS ((edge, basic_block));
 \f
 /* Called once at intialization time.  */
 
@@ -163,6 +126,7 @@ init_flow ()
   static int initialized;
 
   first_deleted_edge = 0;
+  first_deleted_block = 0;
   n_edges = 0;
 
   if (!initialized)
@@ -200,247 +164,24 @@ clear_edges ()
     abort ();
 }
 \f
-/* Return true if NOTE is not one of the ones that must be kept paired,
-   so that we may simply delete them.  */
-
-static int
-can_delete_note_p (note)
-     rtx note;
-{
-  return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
-         || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
-}
-
-/* True if a given label can be deleted.  */
-
-static int
-can_delete_label_p (label)
-     rtx label;
-{
-  rtx x;
-
-  if (LABEL_PRESERVE_P (label))
-    return 0;
-
-  for (x = forced_labels; x; x = XEXP (x, 1))
-    if (label == XEXP (x, 0))
-      return 0;
-  for (x = label_value_list; x; x = XEXP (x, 1))
-    if (label == XEXP (x, 0))
-      return 0;
-  for (x = exception_handler_labels; x; x = XEXP (x, 1))
-    if (label == XEXP (x, 0))
-      return 0;
-
-  /* User declared labels must be preserved.  */
-  if (LABEL_NAME (label) != 0)
-    return 0;
-
-  return 1;
-}
-
-/* Delete INSN by patching it out.  Return the next insn.  */
-
-rtx
-delete_insn (insn)
-     rtx insn;
-{
-  rtx next = NEXT_INSN (insn);
-  rtx note;
-  bool really_delete = true;
-
-  if (GET_CODE (insn) == CODE_LABEL)
-    {
-      /* Some labels can't be directly removed from the INSN chain, as they
-         might be references via variables, constant pool etc. 
-         Convert them to the special NOTE_INSN_DELETED_LABEL note.  */
-      if (! can_delete_label_p (insn))
-       {
-         const char *name = LABEL_NAME (insn);
-
-         really_delete = false;
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
-         NOTE_SOURCE_FILE (insn) = name;
-       }
-      remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
-    }
-
-  if (really_delete)
-    {
-      remove_insn (insn);
-      INSN_DELETED_P (insn) = 1;
-    }
-
-  /* If deleting a jump, decrement the use count of the label.  Deleting
-     the label itself should happen in the normal course of block merging.  */
-  if (GET_CODE (insn) == JUMP_INSN
-      && JUMP_LABEL (insn)
-      && GET_CODE (JUMP_LABEL (insn)) == CODE_LABEL)
-    LABEL_NUSES (JUMP_LABEL (insn))--;
-
-  /* Also if deleting an insn that references a label.  */
-  else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
-          && 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;
-}
-
-/* Unlink a chain of insns between START and FINISH, leaving notes
-   that must be paired.  */
-
-void
-delete_insn_chain (start, finish)
-     rtx start, finish;
-{
-  /* Unchain the insns one by one.  It would be quicker to delete all
-     of these with a single unchaining, rather than one at a time, but
-     we need to keep the NOTE's.  */
-
-  rtx next;
-
-  while (1)
-    {
-      next = NEXT_INSN (start);
-      if (GET_CODE (start) == NOTE && !can_delete_note_p (start))
-       ;
-      else
-       next = delete_insn (start);
-
-      if (start == finish)
-       break;
-      start = next;
-    }
-}
-\f
-/* Create a new basic block consisting of the instructions between
-   HEAD and END inclusive.  This function is designed to allow fast
-   BB construction - reuses the note and basic block struct
-   in BB_NOTE, if any and do not grow BASIC_BLOCK chain and should
-   be used directly only by CFG construction code.
-   END can be NULL in to create new empty basic block before HEAD.
-   Both END and HEAD can be NULL to create basic block at the end of
-   INSN chain.  */
+/* Allocate memory for basic_block.  */
 
 basic_block
-create_basic_block_structure (index, head, end, bb_note)
-     int index;
-     rtx head, end, bb_note;
+alloc_block ()
 {
   basic_block bb;
 
-  if (bb_note
-      && ! RTX_INTEGRATED_P (bb_note)
-      && (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL
-      && bb->aux == NULL)
+  if (first_deleted_block)
     {
-      /* If we found an existing note, thread it back onto the chain.  */
-
-      rtx after;
-
-      if (GET_CODE (head) == CODE_LABEL)
-       after = head;
-      else
-       {
-         after = PREV_INSN (head);
-         head = bb_note;
-       }
-
-      if (after != bb_note && NEXT_INSN (after) != bb_note)
-       reorder_insns (bb_note, bb_note, after);
+      bb = first_deleted_block;
+      first_deleted_block = (basic_block) bb->succ;
+      bb->succ = NULL;
     }
   else
     {
-      /* Otherwise we must create a note and a basic block structure.
-        Since we allow basic block structs in rtl, give the struct
-        the same lifetime by allocating it off the function obstack
-        rather than using malloc.  */
-
       bb = (basic_block) obstack_alloc (&flow_obstack, sizeof (*bb));
       memset (bb, 0, sizeof (*bb));
-
-      if (!head && !end)
-       {
-         head = end = bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK,
-                                                 get_last_insn ());
-       }
-      else if (GET_CODE (head) == CODE_LABEL && end)
-       {
-         bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK, head);
-         if (head == end)
-           end = bb_note;
-       }
-      else
-       {
-         bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK, head);
-         head = bb_note;
-         if (!end)
-           end = head;
-       }
-      NOTE_BASIC_BLOCK (bb_note) = bb;
-    }
-
-  /* Always include the bb note in the block.  */
-  if (NEXT_INSN (end) == bb_note)
-    end = bb_note;
-
-  bb->head = head;
-  bb->end = end;
-  bb->index = index;
-  BASIC_BLOCK (index) = bb;
-  if (basic_block_for_insn)
-    update_bb_for_insn (bb);
-
-  /* Tag the block so that we know it has been used when considering
-     other basic block notes.  */
-  bb->aux = bb;
-
-  return bb;
-}
-
-/* Create new basic block consisting of instructions in between HEAD and
-   END and place it to the BB chain at possition INDEX.
-   END can be NULL in to create new empty basic block before HEAD.
-   Both END and HEAD can be NULL to create basic block at the end of
-   INSN chain.  */
-
-basic_block
-create_basic_block (index, head, end)
-     int index;
-     rtx head, end;
-{
-  basic_block bb;
-  int i;
-
-  /* Place the new block just after the block being split.  */
-  VARRAY_GROW (basic_block_info, ++n_basic_blocks);
-
-  /* Some parts of the compiler expect blocks to be number in
-     sequential order so insert the new block immediately after the
-     block being split..  */
-  for (i = n_basic_blocks - 1; i > index; --i)
-    {
-      basic_block tmp = BASIC_BLOCK (i - 1);
-      BASIC_BLOCK (i) = tmp;
-      tmp->index = i;
     }
-
-  bb = create_basic_block_structure (index, head, end, NULL);
-  bb->aux = NULL;
   return bb;
 }
 
@@ -464,180 +205,8 @@ expunge_block (b)
   b->index = -3;
   basic_block_info->num_elements--;
   n_basic_blocks--;
-}
-
-/* Delete the insns in a (non-live) block.  We physically delete every
-   non-deleted-note insn, and update the flow graph appropriately.
-
-   Return nonzero if we deleted an exception handler.  */
-
-/* ??? Preserving all such notes strikes me as wrong.  It would be nice
-   to post-process the stream to remove empty blocks, loops, ranges, etc.  */
-
-int
-flow_delete_block (b)
-     basic_block b;
-{
-  int deleted_handler = 0;
-  rtx insn, end, tmp;
-
-  /* If the head of this block is a CODE_LABEL, then it might be the
-     label for an exception handler which can't be reached.
-
-     We need to remove the label from the exception_handler_label list
-     and remove the associated NOTE_INSN_EH_REGION_BEG and
-     NOTE_INSN_EH_REGION_END notes.  */
-
-  insn = b->head;
-
-  never_reached_warning (insn);
-
-  if (GET_CODE (insn) == CODE_LABEL)
-    maybe_remove_eh_handler (insn);
-
-  /* Include any jump table following the basic block.  */
-  end = b->end;
-  if (GET_CODE (end) == JUMP_INSN
-      && (tmp = JUMP_LABEL (end)) != 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))
-    end = tmp;
-
-  /* Include any barrier that may follow the basic block.  */
-  tmp = next_nonnote_insn (end);
-  if (tmp && GET_CODE (tmp) == BARRIER)
-    end = tmp;
-
-  /* Selectively delete the entire chain.  */
-  b->head = NULL;
-  delete_insn_chain (insn, end);
-
-  /* Remove the edges into and out of this block.  Note that there may
-     indeed be edges in, if we are removing an unreachable loop.  */
-  while (b->pred != NULL)
-    remove_edge (b->pred);
-  while (b->succ != NULL)
-    remove_edge (b->succ);
-
-  b->pred = NULL;
-  b->succ = NULL;
-
-  /* Remove the basic block from the array, and compact behind it.  */
-  expunge_block (b);
-
-  return deleted_handler;
-}
-\f
-/* Records the basic block struct in BB_FOR_INSN, for every instruction
-   indexed by INSN_UID.  MAX is the size of the array.  */
-
-void
-compute_bb_for_insn (max)
-     int max;
-{
-  int i;
-
-  if (basic_block_for_insn)
-    VARRAY_FREE (basic_block_for_insn);
-  VARRAY_BB_INIT (basic_block_for_insn, max, "basic_block_for_insn");
-
-  for (i = 0; i < n_basic_blocks; ++i)
-    {
-      basic_block bb = BASIC_BLOCK (i);
-      rtx insn, end;
-
-      end = bb->end;
-      insn = bb->head;
-      while (1)
-       {
-         int uid = INSN_UID (insn);
-         if (uid < max)
-           VARRAY_BB (basic_block_for_insn, uid) = bb;
-         if (insn == end)
-           break;
-         insn = NEXT_INSN (insn);
-       }
-    }
-}
-
-/* Release the basic_block_for_insn array.  */
-
-void
-free_bb_for_insn ()
-{
-  if (basic_block_for_insn)
-    VARRAY_FREE (basic_block_for_insn);
-  basic_block_for_insn = 0;
-}
-
-/* Update insns block within BB.  */
-
-void
-update_bb_for_insn (bb)
-     basic_block bb;
-{
-  rtx insn;
-
-  if (! basic_block_for_insn)
-    return;
-
-  for (insn = bb->head; ; insn = NEXT_INSN (insn))
-    {
-      set_block_for_insn (insn, bb);
-
-      if (insn == bb->end)
-       break;
-    }
-}
-
-/* Record INSN's block as BB.  */
-
-void
-set_block_for_insn (insn, bb)
-     rtx insn;
-     basic_block bb;
-{
-  size_t uid = INSN_UID (insn);
-  if (uid >= basic_block_for_insn->num_elements)
-    {
-      int new_size;
-
-      /* Add one-eighth the size so we don't keep calling xrealloc.  */
-      new_size = uid + (uid + 7) / 8;
-
-      VARRAY_GROW (basic_block_for_insn, new_size);
-    }
-  VARRAY_BB (basic_block_for_insn, uid) = bb;
-}
-
-/* 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_for_new_insns (insn, bb)
-     rtx 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 ((unsigned) INSN_UID (insn) >= basic_block_for_insn->num_elements
-         || BLOCK_FOR_INSN (insn) == 0)
-       set_block_for_insn (insn, bb);
-      else
-       break;
-    }
+  b->succ = (edge) first_deleted_block;
+  first_deleted_block = (basic_block) b;
 }
 \f
 /* Create an edge connecting SRC and DST with FLAGS optionally using
@@ -837,998 +406,121 @@ redirect_edge_pred (e, new_pred)
   e->src = new_pred;
 }
 \f
-/* Split a block BB after insn INSN creating a new fallthru edge.
-   Return the new edge.  Note that to keep other parts of the compiler happy,
-   this function renumbers all the basic blocks so that the new
-   one has a number one greater than the block split.  */
-
-edge
-split_block (bb, insn)
-     basic_block bb;
-     rtx insn;
+void
+dump_flow_info (file)
+     FILE *file;
 {
-  basic_block new_bb;
-  edge new_edge;
-  edge e;
+  register int i;
+  static const char * const reg_class_names[] = REG_CLASS_NAMES;
+
+  fprintf (file, "%d registers.\n", max_regno);
+  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+    if (REG_N_REFS (i))
+      {
+       enum reg_class class, altclass;
+       fprintf (file, "\nRegister %d used %d times across %d insns",
+                i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
+       if (REG_BASIC_BLOCK (i) >= 0)
+         fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
+       if (REG_N_SETS (i))
+         fprintf (file, "; set %d time%s", REG_N_SETS (i),
+                  (REG_N_SETS (i) == 1) ? "" : "s");
+       if (REG_USERVAR_P (regno_reg_rtx[i]))
+         fprintf (file, "; user var");
+       if (REG_N_DEATHS (i) != 1)
+         fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+       if (REG_N_CALLS_CROSSED (i) == 1)
+         fprintf (file, "; crosses 1 call");
+       else if (REG_N_CALLS_CROSSED (i))
+         fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
+       if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
+         fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
+       class = reg_preferred_class (i);
+       altclass = reg_alternate_class (i);
+       if (class != GENERAL_REGS || altclass != ALL_REGS)
+         {
+           if (altclass == ALL_REGS || class == ALL_REGS)
+             fprintf (file, "; pref %s", reg_class_names[(int) class]);
+           else if (altclass == NO_REGS)
+             fprintf (file, "; %s or none", reg_class_names[(int) class]);
+           else
+             fprintf (file, "; pref %s, else %s",
+                      reg_class_names[(int) class],
+                      reg_class_names[(int) altclass]);
+         }
+       if (REG_POINTER (regno_reg_rtx[i]))
+         fprintf (file, "; pointer");
+       fprintf (file, ".\n");
+      }
+
+  fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
+  for (i = 0; i < n_basic_blocks; i++)
+    {
+      register basic_block bb = BASIC_BLOCK (i);
+      register edge e;
+
+      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);
 
-  /* There is no point splitting the block after its end.  */
-  if (bb->end == insn)
-    return 0;
+      fprintf (file, "Predecessors: ");
+      for (e = bb->pred; e; e = e->pred_next)
+       dump_edge_info (file, e, 0);
 
-  /* Create the new basic block.  */
-  new_bb = create_basic_block (bb->index + 1, NEXT_INSN (insn), bb->end);
-  new_bb->count = bb->count;
-  new_bb->frequency = bb->frequency;
-  new_bb->loop_depth = bb->loop_depth;
-  bb->end = insn;
+      fprintf (file, "\nSuccessors: ");
+      for (e = bb->succ; e; e = e->succ_next)
+       dump_edge_info (file, e, 1);
 
-  /* Redirect the outgoing edges.  */
-  new_bb->succ = bb->succ;
-  bb->succ = NULL;
-  for (e = new_bb->succ; e; e = e->succ_next)
-    e->src = new_bb;
+      fprintf (file, "\nRegisters live at start:");
+      dump_regset (bb->global_live_at_start, file);
 
-  new_edge = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
+      fprintf (file, "\nRegisters live at end:");
+      dump_regset (bb->global_live_at_end, file);
 
-  if (bb->global_live_at_start)
-    {
-      new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
-
-      /* We now have to calculate which registers are live at the end
-        of the split basic block and at the start of the new basic
-        block.  Start with those registers that are known to be live
-        at the end of the original basic block and get
-        propagate_block to determine which registers are live.  */
-      COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_end);
-      propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
-      COPY_REG_SET (bb->global_live_at_end,
-                   new_bb->global_live_at_start);
+      putc ('\n', file);
     }
 
-  return new_edge;
+  putc ('\n', file);
 }
 
-/* Blocks A and B are to be merged into a single block A.  The insns
-   are already contiguous, hence `nomove'.  */
+void
+debug_flow_info ()
+{
+  dump_flow_info (stderr);
+}
 
 void
-merge_blocks_nomove (a, b)
-     basic_block a, b;
+dump_edge_info (file, e, do_succ)
+     FILE *file;
+     edge e;
+     int do_succ;
 {
-  edge e;
-  rtx b_head, b_end, a_end;
-  rtx del_first = NULL_RTX, del_last = NULL_RTX;
-  int b_empty = 0;
-
-  /* If there was a CODE_LABEL beginning B, delete it.  */
-  b_head = b->head;
-  b_end = b->end;
-  if (GET_CODE (b_head) == CODE_LABEL)
-    {
-      /* Detect basic blocks with nothing but a label.  This can happen
-        in particular at the end of a function.  */
-      if (b_head == b_end)
-       b_empty = 1;
-      del_first = del_last = b_head;
-      b_head = NEXT_INSN (b_head);
-    }
+  basic_block side = (do_succ ? e->dest : e->src);
+
+  if (side == ENTRY_BLOCK_PTR)
+    fputs (" ENTRY", file);
+  else if (side == EXIT_BLOCK_PTR)
+    fputs (" EXIT", file);
+  else
+    fprintf (file, " %d", side->index);
+
+  if (e->probability)
+    fprintf (file, " [%.1f%%] ", e->probability * 100.0 / REG_BR_PROB_BASE);
 
-  /* Delete the basic block note.  */
-  if (NOTE_INSN_BASIC_BLOCK_P (b_head))
+  if (e->count)
     {
-      if (b_head == b_end)
-       b_empty = 1;
-      if (! del_last)
-       del_first = b_head;
-      del_last = b_head;
-      b_head = NEXT_INSN (b_head);
+      fprintf (file, " count:");
+      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) e->count);
     }
 
-  /* If there was a jump out of A, delete it.  */
-  a_end = a->end;
-  if (GET_CODE (a_end) == JUMP_INSN)
+  if (e->flags)
     {
-      rtx prev;
-
-      for (prev = PREV_INSN (a_end); ; prev = PREV_INSN (prev))
-       if (GET_CODE (prev) != NOTE
-           || NOTE_LINE_NUMBER (prev) == NOTE_INSN_BASIC_BLOCK
-           || prev == a->head)
-         break;
-
-      del_first = a_end;
-
-#ifdef HAVE_cc0
-      /* If this was a conditional jump, we need to also delete
-        the insn that set cc0.  */
-      if (only_sets_cc0_p (prev))
-       {
-         rtx tmp = prev;
-         prev = prev_nonnote_insn (prev);
-         if (!prev)
-           prev = a->head;
-         del_first = tmp;
-       }
-#endif
-
-      a_end = PREV_INSN (del_first);
-    }
-  else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
-    del_first = NEXT_INSN (a_end);
-
-  /* Normally there should only be one successor of A and that is B, but
-     partway though the merge of blocks for conditional_execution we'll
-     be merging a TEST block with THEN and ELSE successors.  Free the
-     whole lot of them and hope the caller knows what they're doing.  */
-  while (a->succ)
-    remove_edge (a->succ);
-
-  /* Adjust the edges out of B for the new owner.  */
-  for (e = b->succ; e; e = e->succ_next)
-    e->src = a;
-  a->succ = b->succ;
-
-  /* B hasn't quite yet ceased to exist.  Attempt to prevent mishap.  */
-  b->pred = b->succ = NULL;
-
-  expunge_block (b);
-
-  /* Delete everything marked above as well as crap that might be
-     hanging out between the two blocks.  */
-  delete_insn_chain (del_first, del_last);
-
-  /* Reassociate the insns of B with A.  */
-  if (!b_empty)
-    {
-      rtx x = a_end;
-      if (basic_block_for_insn)
-       {
-         BLOCK_FOR_INSN (x) = a;
-         while (x != b_end)
-           {
-             x = NEXT_INSN (x);
-             BLOCK_FOR_INSN (x) = a;
-           }
-       }
-      a_end = b_end;
-    }
-  a->end = a_end;
-}
-\f
-/* Return label in the head of basic block.  Create one if it doesn't exist.  */
-
-rtx
-block_label (block)
-     basic_block block;
-{
-  if (block == EXIT_BLOCK_PTR)
-    return NULL_RTX;
-  if (GET_CODE (block->head) != CODE_LABEL)
-    {
-      block->head = emit_label_before (gen_label_rtx (), block->head);
-      if (basic_block_for_insn)
-       set_block_for_insn (block->head, block);
-    }
-  return block->head;
-}
-
-/* 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, kill_from;
-  edge tmp;
-  rtx set;
-  int fallthru = 0;
-
-  /* Verify that all targets will be TARGET.  */
-  for (tmp = src->succ; tmp; tmp = tmp->succ_next)
-    if (tmp->dest != target && tmp != e)
-      break;
-  if (tmp || !onlyjump_p (insn))
-    return false;
-
-  /* Avoid removing branch with side effects.  */
-  set = single_set (insn);
-  if (!set || side_effects_p (set))
-    return false;
-
-  /* In case we zap a conditional jump, we'll need to kill
-     the cc0 setter too.  */
-  kill_from = insn;
-#ifdef HAVE_cc0
-  if (reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-    kill_from = PREV_INSN (insn);
-#endif
-
-  /* See if we can create the fallthru edge.  */
-  if (can_fallthru (src, target))
-    {
-      if (rtl_dump_file)
-       fprintf (rtl_dump_file, "Removing jump %i.\n", INSN_UID (insn));
-      fallthru = 1;
-
-      /* Selectivly unlink whole insn chain.  */
-      delete_insn_chain (kill_from, PREV_INSN (target->head));
-    }
-  /* 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);
-      rtx barrier;
-
-      emit_jump_insn_after (gen_jump (target_label), kill_from);
-      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));
-
-      delete_insn_chain (kill_from, insn);
-
-      barrier = next_nonnote_insn (src->end);
-      if (!barrier || GET_CODE (barrier) != BARRIER)
-       emit_barrier_after (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;
-
-  /* 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 (e->src->end) == NOTE
-        && NOTE_LINE_NUMBER (e->src->end) >= 0)
-    delete_insn (e->src->end);
-
-  if (e->dest != target)
-    redirect_edge_succ (e, target);
-  return true;
-}
-
-/* Return last loop_beg note appearing after INSN, before start of next
-   basic block.  Return INSN if there are no such notes.
-
-   When emmiting jump to redirect an fallthru edge, it should always
-   appear after the LOOP_BEG notes, as loop optimizer expect loop to
-   eighter start by fallthru edge or jump following the LOOP_BEG note
-   jumping to the loop exit test.  */
-
-static rtx
-last_loop_beg_note (insn)
-     rtx insn;
-{
-  rtx last = insn;
-  insn = NEXT_INSN (insn);
-  while (insn && GET_CODE (insn) == NOTE
-        && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
-    {
-      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-       last = insn;
-      insn = NEXT_INSN (insn);
-    }
-  return last;
-}
-
-/* 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.  */
-
-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 (e->flags & EDGE_COMPLEX)
-    return false;
-
-  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)
-    redirect_edge_succ_nodup (e, target);
-  return true;
-}
-
-/* Like force_nonfallthru bellow, but additionally performs redirection
-   Used by redirect_edge_and_branch_force.  */
-
-static basic_block
-force_nonfallthru_and_redirect (e, target)
-     edge e;
-     basic_block target;
-{
-  basic_block jump_block, new_bb = NULL;
-  rtx note;
-  edge new_edge;
-
-  if (e->flags & EDGE_ABNORMAL)
-    abort ();
-  if (!(e->flags & EDGE_FALLTHRU))
-    abort ();
-  if (e->src->succ->succ_next)
-    {
-      /* Create the new structures.  */
-      note = last_loop_beg_note (e->src->end);
-      jump_block = create_basic_block (e->src->index + 1, NEXT_INSN (note), NULL);
-      jump_block->count = e->count;
-      jump_block->frequency = EDGE_FREQUENCY (e);
-      jump_block->loop_depth = target->loop_depth;
-
-      if (target->global_live_at_start)
-       {
-         jump_block->global_live_at_start =
-           OBSTACK_ALLOC_REG_SET (&flow_obstack);
-         jump_block->global_live_at_end =
-           OBSTACK_ALLOC_REG_SET (&flow_obstack);
-         COPY_REG_SET (jump_block->global_live_at_start,
-                       target->global_live_at_start);
-         COPY_REG_SET (jump_block->global_live_at_end,
-                       target->global_live_at_start);
-       }
-
-      /* Wire edge in.  */
-      new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
-      new_edge->probability = e->probability;
-      new_edge->count = e->count;
-
-      /* Redirect old edge.  */
-      redirect_edge_pred (e, jump_block);
-      e->probability = REG_BR_PROB_BASE;
-
-      new_bb = jump_block;
-    }
-  else
-    jump_block = e->src;
-  e->flags &= ~EDGE_FALLTHRU;
-  if (target == EXIT_BLOCK_PTR)
-    {
-      if (HAVE_return)
-       emit_jump_insn_after (gen_return (), jump_block->end);
-      else
-       abort ();
-    }
-  else
-    {
-      rtx label = block_label (target);
-      emit_jump_insn_after (gen_jump (label), jump_block->end);
-      JUMP_LABEL (jump_block->end) = label;
-      LABEL_NUSES (label)++;
-    }
-  emit_barrier_after (jump_block->end);
-  redirect_edge_succ_nodup (e, target);
-
-  return new_bb;
-}
-
-/* Edge E is assumed to be fallthru edge.  Emit needed jump instruction
-   (and possibly create new basic block) to make edge non-fallthru.
-   Return newly created BB or NULL if none.  */
-basic_block
-force_nonfallthru (e)
-     edge e;
-{
-  return force_nonfallthru_and_redirect (e, e->dest);
-}
-
-/* Redirect edge even at the expense of creating new jump insn or
-   basic block.  Return new basic block if created, NULL otherwise.
-   Abort if converison is impossible.  */
-
-basic_block
-redirect_edge_and_branch_force (e, target)
-     edge e;
-     basic_block target;
-{
-  basic_block new_bb;
-
-  if (redirect_edge_and_branch (e, target))
-    return NULL;
-  if (e->dest == target)
-    return NULL;
-
-  /* In case the edge redirection failed, try to force it to be non-fallthru
-     and redirect newly created simplejump.  */
-  new_bb = force_nonfallthru_and_redirect (e, target);
-  return new_bb;
-}
-
-/* The given edge should potentially be a fallthru edge.  If that is in
-   fact true, delete the jump and barriers that are in the way.  */
-
-void
-tidy_fallthru_edge (e, b, c)
-     edge e;
-     basic_block b, c;
-{
-  rtx q;
-
-  /* ??? In a late-running flow pass, other folks may have deleted basic
-     blocks by nopping out blocks, leaving multiple BARRIERs between here
-     and the target label. They ought to be chastized and fixed.
-
-     We can also wind up with a sequence of undeletable labels between
-     one block and the next.
-
-     So search through a sequence of barriers, labels, and notes for
-     the head of block C and assert that we really do fall through.  */
-
-  if (next_real_insn (b->end) != next_real_insn (PREV_INSN (c->head)))
-    return;
-
-  /* Remove what will soon cease being the jump insn from the source block.
-     If block B consisted only of this single jump, turn it into a deleted
-     note.  */
-  q = b->end;
-  if (GET_CODE (q) == JUMP_INSN
-      && onlyjump_p (q)
-      && (any_uncondjump_p (q)
-         || (b->succ == e && e->succ_next == NULL)))
-    {
-#ifdef HAVE_cc0
-      /* If this was a conditional jump, we need to also delete
-        the insn that set cc0.  */
-      if (any_condjump_p (q) && only_sets_cc0_p (PREV_INSN (q)))
-       q = PREV_INSN (q);
-#endif
-
-      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);
-    }
-
-  /* Selectively unlink the sequence.  */
-  if (q != PREV_INSN (c->head))
-    delete_insn_chain (NEXT_INSN (q), PREV_INSN (c->head));
-
-  e->flags |= EDGE_FALLTHRU;
-}
-
-/* Fix up edges that now fall through, or rather should now fall through
-   but previously required a jump around now deleted blocks.  Simplify
-   the search by only examining blocks numerically adjacent, since this
-   is how find_basic_blocks created them.  */
-
-void
-tidy_fallthru_edges ()
-{
-  int i;
-
-  for (i = 1; i < n_basic_blocks; ++i)
-    {
-      basic_block b = BASIC_BLOCK (i - 1);
-      basic_block c = BASIC_BLOCK (i);
-      edge s;
-
-      /* We care about simple conditional or unconditional jumps with
-        a single successor.
-
-        If we had a conditional branch to the next instruction when
-        find_basic_blocks was called, then there will only be one
-        out edge for the block which ended with the conditional
-        branch (since we do not create duplicate edges).
-
-        Furthermore, the edge will be marked as a fallthru because we
-        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.  */
-         && (GET_CODE (b->end) != JUMP_INSN
-             || onlyjump_p (b->end)))
-       tidy_fallthru_edge (s, b, c);
-    }
-}
-\f
-/* Helper function for split_edge.  Return true in case edge BB2 to BB1
-   is back edge of syntactic loop.  */
-
-static bool
-back_edge_of_syntactic_loop_p (bb1, bb2)
-       basic_block bb1, bb2;
-{
-  rtx insn;
-  int count = 0;
-
-  if (bb1->index > bb2->index)
-    return false;
-
-  if (bb1->index == bb2->index)
-    return true;
-
-  for (insn = bb1->end; insn != bb2->head && count >= 0;
-       insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == NOTE)
-      {
-       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-         count++;
-       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-         count--;
-      }
-
-  return count >= 0;
-}
-
-/* Split a (typically critical) edge.  Return the new block.
-   Abort on abnormal edges.
-
-   ??? The code generally expects to be called on critical edges.
-   The case of a block ending in an unconditional jump to a
-   block with multiple predecessors is not handled optimally.  */
-
-basic_block
-split_edge (edge_in)
-     edge edge_in;
-{
-  basic_block bb;
-  edge edge_out;
-  rtx before;
-
-  /* Abnormal edges cannot be split.  */
-  if ((edge_in->flags & EDGE_ABNORMAL) != 0)
-    abort ();
-
-  /* We are going to place the new block in front of edge destination.
-     Avoid existence of fallthru predecesors.  */
-  if ((edge_in->flags & EDGE_FALLTHRU) == 0)
-    {
-      edge e;
-      for (e = edge_in->dest->pred; e; e = e->pred_next)
-       if (e->flags & EDGE_FALLTHRU)
-         break;
-
-      if (e)
-       force_nonfallthru (e);
-    }
-
-  /* Create the basic block note.
-
-     Where we place the note can have a noticable impact on the generated
-     code.  Consider this cfg:
-
-                       E
-                       |
-                       0
-                      / \
-                  +->1-->2--->E
-                   |  |
-                  +--+
-
-      If we need to insert an insn on the edge from block 0 to block 1,
-      we want to ensure the instructions we insert are outside of any
-      loop notes that physically sit between block 0 and block 1.  Otherwise
-      we confuse the loop optimizer into thinking the loop is a phony.  */
-
-  if (edge_in->dest != EXIT_BLOCK_PTR
-      && PREV_INSN (edge_in->dest->head)
-      && GET_CODE (PREV_INSN (edge_in->dest->head)) == NOTE
-      && NOTE_LINE_NUMBER (PREV_INSN (edge_in->dest->head)) == NOTE_INSN_LOOP_BEG
-      && !back_edge_of_syntactic_loop_p (edge_in->dest, edge_in->src))
-    before = PREV_INSN (edge_in->dest->head);
-  else if (edge_in->dest != EXIT_BLOCK_PTR)
-    before = edge_in->dest->head;
-  else
-    before = NULL_RTX;
-
-  bb = create_basic_block (edge_in->dest == EXIT_BLOCK_PTR ? n_basic_blocks
-                          : edge_in->dest->index, before, NULL);
-  bb->count = edge_in->count;
-  bb->frequency = EDGE_FREQUENCY (edge_in);
-
-  /* ??? This info is likely going to be out of date very soon.  */
-  if (edge_in->dest->global_live_at_start)
-    {
-      bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-      COPY_REG_SET (bb->global_live_at_start, edge_in->dest->global_live_at_start);
-      COPY_REG_SET (bb->global_live_at_end, edge_in->dest->global_live_at_start);
-    }
-
-  edge_out = make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
-
-  /* For non-fallthry edges, we must adjust the predecessor's
-     jump instruction to target our new block.  */
-  if ((edge_in->flags & EDGE_FALLTHRU) == 0)
-    {
-      if (!redirect_edge_and_branch (edge_in, bb))
-       abort ();
-    }
-  else
-    redirect_edge_succ (edge_in, bb);
-
-  return bb;
-}
-
-/* Queue instructions for insertion on an edge between two basic blocks.
-   The new instructions and basic blocks (if any) will not appear in the
-   CFG until commit_edge_insertions is called.  */
-
-void
-insert_insn_on_edge (pattern, e)
-     rtx pattern;
-     edge e;
-{
-  /* We cannot insert instructions on an abnormal critical edge.
-     It will be easier to find the culprit if we die now.  */
-  if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
-    abort ();
-
-  if (e->insns == NULL_RTX)
-    start_sequence ();
-  else
-    push_to_sequence (e->insns);
-
-  emit_insn (pattern);
-
-  e->insns = get_insns ();
-  end_sequence ();
-}
-
-/* Update the CFG for the instructions queued on edge E.  */
-
-static void
-commit_one_edge_insertion (e)
-     edge e;
-{
-  rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
-  basic_block bb;
-
-  /* Pull the insns off the edge now since the edge might go away.  */
-  insns = e->insns;
-  e->insns = NULL_RTX;
-
-  /* Figure out where to put these things.  If the destination has
-     one predecessor, insert there.  Except for the exit block.  */
-  if (e->dest->pred->pred_next == NULL
-      && e->dest != EXIT_BLOCK_PTR)
-    {
-      bb = e->dest;
-
-      /* Get the location correct wrt a code label, and "nice" wrt
-        a basic block note, and before everything else.  */
-      tmp = bb->head;
-      if (GET_CODE (tmp) == CODE_LABEL)
-       tmp = NEXT_INSN (tmp);
-      if (NOTE_INSN_BASIC_BLOCK_P (tmp))
-       tmp = NEXT_INSN (tmp);
-      if (tmp == bb->head)
-       before = tmp;
-      else
-       after = PREV_INSN (tmp);
-    }
-
-  /* If the source has one successor and the edge is not abnormal,
-     insert there.  Except for the entry block.  */
-  else if ((e->flags & EDGE_ABNORMAL) == 0
-          && e->src->succ->succ_next == NULL
-          && e->src != ENTRY_BLOCK_PTR)
-    {
-      bb = e->src;
-      /* It is possible to have a non-simple jump here.  Consider a target
-        where some forms of unconditional jumps clobber a register.  This
-        happens on the fr30 for example.
-
-        We know this block has a single successor, so we can just emit
-        the queued insns before the jump.  */
-      if (GET_CODE (bb->end) == JUMP_INSN)
-       {
-         before = bb->end;
-         while (GET_CODE (PREV_INSN (before)) == NOTE
-                && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG)
-           before = PREV_INSN (before);
-       }
-      else
-       {
-         /* We'd better be fallthru, or we've lost track of what's what.  */
-         if ((e->flags & EDGE_FALLTHRU) == 0)
-           abort ();
-
-         after = bb->end;
-       }
-    }
-
-  /* Otherwise we must split the edge.  */
-  else
-    {
-      bb = split_edge (e);
-      after = bb->end;
-    }
-
-  /* Now that we've found the spot, do the insertion.  */
-
-  if (before)
-    {
-      emit_insns_before (insns, before);
-      last = prev_nonnote_insn (before);
-    }
-  else
-    last = emit_insns_after (insns, after);
-
-  if (returnjump_p (last))
-    {
-      /* ??? Remove all outgoing edges from BB and add one for EXIT.
-         This is not currently a problem because this only happens
-        for the (single) epilogue, which already has a fallthru edge
-        to EXIT.  */
-
-      e = bb->succ;
-      if (e->dest != EXIT_BLOCK_PTR
-         || e->succ_next != NULL
-         || (e->flags & EDGE_FALLTHRU) == 0)
-       abort ();
-      e->flags &= ~EDGE_FALLTHRU;
-
-      emit_barrier_after (last);
-
-      if (before)
-       delete_insn (before);
-    }
-  else if (GET_CODE (last) == JUMP_INSN)
-    abort ();
-  find_sub_basic_blocks (bb);
-}
-
-/* Update the CFG for all queued instructions.  */
-
-void
-commit_edge_insertions ()
-{
-  int i;
-  basic_block bb;
-
-#ifdef ENABLE_CHECKING
-  verify_flow_info ();
-#endif
-
-  i = -1;
-  bb = ENTRY_BLOCK_PTR;
-  while (1)
-    {
-      edge e, next;
-
-      for (e = bb->succ; e; e = next)
-       {
-         next = e->succ_next;
-         if (e->insns)
-           commit_one_edge_insertion (e);
-       }
-
-      if (++i >= n_basic_blocks)
-       break;
-      bb = BASIC_BLOCK (i);
-    }
-}
-\f
-void
-dump_flow_info (file)
-     FILE *file;
-{
-  register int i;
-  static const char * const reg_class_names[] = REG_CLASS_NAMES;
-
-  fprintf (file, "%d registers.\n", max_regno);
-  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (REG_N_REFS (i))
-      {
-       enum reg_class class, altclass;
-       fprintf (file, "\nRegister %d used %d times across %d insns",
-                i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
-       if (REG_BASIC_BLOCK (i) >= 0)
-         fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
-       if (REG_N_SETS (i))
-         fprintf (file, "; set %d time%s", REG_N_SETS (i),
-                  (REG_N_SETS (i) == 1) ? "" : "s");
-       if (REG_USERVAR_P (regno_reg_rtx[i]))
-         fprintf (file, "; user var");
-       if (REG_N_DEATHS (i) != 1)
-         fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
-       if (REG_N_CALLS_CROSSED (i) == 1)
-         fprintf (file, "; crosses 1 call");
-       else if (REG_N_CALLS_CROSSED (i))
-         fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
-       if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
-         fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
-       class = reg_preferred_class (i);
-       altclass = reg_alternate_class (i);
-       if (class != GENERAL_REGS || altclass != ALL_REGS)
-         {
-           if (altclass == ALL_REGS || class == ALL_REGS)
-             fprintf (file, "; pref %s", reg_class_names[(int) class]);
-           else if (altclass == NO_REGS)
-             fprintf (file, "; %s or none", reg_class_names[(int) class]);
-           else
-             fprintf (file, "; pref %s, else %s",
-                      reg_class_names[(int) class],
-                      reg_class_names[(int) altclass]);
-         }
-       if (REG_POINTER (regno_reg_rtx[i]))
-         fprintf (file, "; pointer");
-       fprintf (file, ".\n");
-      }
-
-  fprintf (file, "\n%d basic blocks, %d edges.\n", n_basic_blocks, n_edges);
-  for (i = 0; i < n_basic_blocks; i++)
-    {
-      register basic_block bb = BASIC_BLOCK (i);
-      register edge e;
-
-      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)
-       dump_edge_info (file, e, 0);
-
-      fprintf (file, "\nSuccessors: ");
-      for (e = bb->succ; e; e = e->succ_next)
-       dump_edge_info (file, e, 1);
-
-      fprintf (file, "\nRegisters live at start:");
-      dump_regset (bb->global_live_at_start, file);
-
-      fprintf (file, "\nRegisters live at end:");
-      dump_regset (bb->global_live_at_end, file);
-
-      putc ('\n', file);
-    }
-
-  putc ('\n', file);
-}
-
-void
-debug_flow_info ()
-{
-  dump_flow_info (stderr);
-}
-
-void
-dump_edge_info (file, e, do_succ)
-     FILE *file;
-     edge e;
-     int do_succ;
-{
-  basic_block side = (do_succ ? e->dest : e->src);
-
-  if (side == ENTRY_BLOCK_PTR)
-    fputs (" ENTRY", file);
-  else if (side == EXIT_BLOCK_PTR)
-    fputs (" EXIT", file);
-  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:");
-      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, (HOST_WIDEST_INT) e->count);
-    }
-
-  if (e->flags)
-    {
-      static const char * const bitnames[] = {
-       "fallthru", "ab", "abcall", "eh", "fake", "dfs_back"
-      };
-      int comma = 0;
-      int i, flags = e->flags;
+      static const char * const bitnames[] = {
+       "fallthru", "ab", "abcall", "eh", "fake", "dfs_back"
+      };
+      int comma = 0;
+      int i, flags = e->flags;
 
       fputc (' ', file);
       fputc ('(', file);
@@ -1849,584 +541,146 @@ dump_edge_info (file, e, do_succ)
     }
 }
 \f
-/* Print out one basic block with live information at start and end.  */
-
-void
-dump_bb (bb, outf)
-     basic_block bb;
-     FILE *outf;
-{
-  rtx insn;
-  rtx last;
-  edge e;
+/* Simple routies to easilly allocate AUX fields of basic blocks.  */
+static struct obstack block_aux_obstack;
+static void *first_block_aux_obj = 0;
+static struct obstack edge_aux_obstack;
+static void *first_edge_aux_obj = 0;
 
-  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);
-  for (e = bb->pred; e; e = e->pred_next)
-    dump_edge_info (outf, e, 0);
-  putc ('\n', outf);
-
-  fputs (";; Registers live at start:", outf);
-  dump_regset (bb->global_live_at_start, outf);
-  putc ('\n', outf);
-
-  for (insn = bb->head, last = NEXT_INSN (bb->end);
-       insn != last;
-       insn = NEXT_INSN (insn))
-    print_rtl_single (outf, insn);
-
-  fputs (";; Registers live at end:", outf);
-  dump_regset (bb->global_live_at_end, outf);
-  putc ('\n', outf);
-
-  fputs (";; Successors: ", outf);
-  for (e = bb->succ; e; e = e->succ_next)
-    dump_edge_info (outf, e, 1);
-  putc ('\n', outf);
-}
+/* Allocate an memory block of SIZE as BB->aux.  The obstack must
+   be first initialized by alloc_aux_for_blocks.  */
 
-void
-debug_bb (bb)
+inline void
+alloc_aux_for_block (bb, size)
      basic_block bb;
+     int size;
 {
-  dump_bb (bb, stderr);
-}
-
-void
-debug_bb_n (n)
-     int n;
-{
-  dump_bb (BASIC_BLOCK (n), stderr);
+  /* Verify that aux field is clear.  */
+  if (bb->aux || !first_block_aux_obj)
+    abort ();
+  bb->aux = obstack_alloc (&block_aux_obstack, size);
+  memset (bb->aux, 0, size);
 }
 
-/* Like print_rtl, but also print out live information for the start of each
-   basic block.  */
+/* Initialize the block_aux_obstack and if SIZE is nonzero, call
+   alloc_aux_for_block for each basic block.  */
 
 void
-print_rtl_with_bb (outf, rtx_first)
-     FILE *outf;
-     rtx rtx_first;
+alloc_aux_for_blocks (size)
+     int size;
 {
-  register rtx tmp_rtx;
+  static int initialized;
 
-  if (rtx_first == 0)
-    fprintf (outf, "(nil)\n");
-  else
+  if (!initialized)
     {
-      int i;
-      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
-      int max_uid = get_max_uid ();
-      basic_block *start = (basic_block *)
-       xcalloc (max_uid, sizeof (basic_block));
-      basic_block *end = (basic_block *)
-       xcalloc (max_uid, sizeof (basic_block));
-      enum bb_state *in_bb_p = (enum bb_state *)
-       xcalloc (max_uid, sizeof (enum bb_state));
-
-      for (i = n_basic_blocks - 1; i >= 0; i--)
-       {
-         basic_block bb = BASIC_BLOCK (i);
-         rtx x;
-
-         start[INSN_UID (bb->head)] = bb;
-         end[INSN_UID (bb->end)] = bb;
-         for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
-           {
-             enum bb_state state = IN_MULTIPLE_BB;
-             if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
-               state = IN_ONE_BB;
-             in_bb_p[INSN_UID (x)] = state;
-
-             if (x == bb->end)
-               break;
-           }
-       }
-
-      for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
-       {
-         int did_output;
-         basic_block bb;
-
-         if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
-           {
-             fprintf (outf, ";; Start of basic block %d, registers live:",
-                      bb->index);
-             dump_regset (bb->global_live_at_start, outf);
-             putc ('\n', outf);
-           }
-
-         if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
-             && GET_CODE (tmp_rtx) != NOTE
-             && GET_CODE (tmp_rtx) != BARRIER)
-           fprintf (outf, ";; Insn is not within a basic block\n");
-         else if (in_bb_p[INSN_UID (tmp_rtx)] == IN_MULTIPLE_BB)
-           fprintf (outf, ";; Insn is in multiple basic blocks\n");
-
-         did_output = print_rtl_single (outf, tmp_rtx);
-
-         if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
-           {
-             fprintf (outf, ";; End of basic block %d, registers live:\n",
-                      bb->index);
-             dump_regset (bb->global_live_at_end, outf);
-             putc ('\n', outf);
-           }
-
-         if (did_output)
-           putc ('\n', outf);
-       }
-
-      free (start);
-      free (end);
-      free (in_bb_p);
+      gcc_obstack_init (&block_aux_obstack);
+      initialized = 1;
     }
-
-  if (current_function_epilogue_delay_list != 0)
+  /* Check whether AUX data are still allocated.  */
+  else if (first_block_aux_obj)
+    abort ();
+  first_block_aux_obj = (char *) obstack_alloc (&block_aux_obstack, 0);
+  if (size)
     {
-      fprintf (outf, "\n;; Insns in epilogue delay list:\n\n");
-      for (tmp_rtx = current_function_epilogue_delay_list; tmp_rtx != 0;
-          tmp_rtx = XEXP (tmp_rtx, 1))
-       print_rtl_single (outf, XEXP (tmp_rtx, 0));
+      int i;
+      for (i = 0; i < n_basic_blocks; i++)
+       alloc_aux_for_block (BASIC_BLOCK (i), size);
+      alloc_aux_for_block (ENTRY_BLOCK_PTR, size);
+      alloc_aux_for_block (EXIT_BLOCK_PTR, size);
     }
 }
-\f
-/* Verify the CFG consistency.  This function check some CFG invariants and
-   aborts when something is wrong.  Hope that this function will help to
-   convert many optimization passes to preserve CFG consistent.
-
-   Currently it does following checks:
-
-   - test head/end pointers
-   - overlapping of basic blocks
-   - edge list correctness
-   - headers of basic blocks (the NOTE_INSN_BASIC_BLOCK note)
-   - tails of basic blocks (ensure that boundary is necesary)
-   - scans body of the basic block for JUMP_INSN, CODE_LABEL
-     and NOTE_INSN_BASIC_BLOCK
-   - check that all insns are in the basic blocks
-   (except the switch handling code, barriers and notes)
-   - check that all returns are followed by barriers
-
-   In future it can be extended check a lot of other stuff as well
-   (reachability of basic blocks, life information, etc. etc.).  */
+
+/* Free data allocated in block_aux_obstack and clear AUX pointers
+   of all blocks.  */
 
 void
-verify_flow_info ()
+free_aux_for_blocks ()
 {
-  const int max_uid = get_max_uid ();
-  const rtx rtx_first = get_insns ();
-  rtx last_head = get_last_insn ();
-  basic_block *bb_info, *last_visited;
-  size_t *edge_checksum;
-  rtx x;
-  int i, last_bb_num_seen, num_bb_notes, err = 0;
-
-  bb_info = (basic_block *) xcalloc (max_uid, sizeof (basic_block));
-  last_visited = (basic_block *) xcalloc (n_basic_blocks + 2,
-                                         sizeof (basic_block));
-  edge_checksum = (size_t *) xcalloc (n_basic_blocks + 2, sizeof (size_t));
-
-  for (i = n_basic_blocks - 1; i >= 0; i--)
-    {
-      basic_block bb = BASIC_BLOCK (i);
-      rtx head = bb->head;
-      rtx end = bb->end;
-
-      /* Verify the end of the basic block is in the INSN chain.  */
-      for (x = last_head; x != NULL_RTX; x = PREV_INSN (x))
-       if (x == end)
-         break;
-      if (!x)
-       {
-         error ("End insn %d for block %d not found in the insn stream.",
-                INSN_UID (end), bb->index);
-         err = 1;
-       }
+  int i;
 
-      /* Work backwards from the end to the head of the basic block
-        to verify the head is in the RTL chain.  */
-      for (; x != NULL_RTX; x = PREV_INSN (x))
-       {
-         /* While walking over the insn chain, verify insns appear
-            in only one basic block and initialize the BB_INFO array
-            used by other passes.  */
-         if (bb_info[INSN_UID (x)] != NULL)
-           {
-             error ("Insn %d is in multiple basic blocks (%d and %d)",
-                    INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index);
-             err = 1;
-           }
-         bb_info[INSN_UID (x)] = bb;
-
-         if (x == head)
-           break;
-       }
-      if (!x)
-       {
-         error ("Head insn %d for block %d not found in the insn stream.",
-                INSN_UID (head), bb->index);
-         err = 1;
-       }
+  if (!first_block_aux_obj)
+    abort ();
+  obstack_free (&block_aux_obstack, first_block_aux_obj);
+  for (i = 0; i < n_basic_blocks; i++)
+    BASIC_BLOCK (i)->aux = NULL;
+  ENTRY_BLOCK_PTR->aux = NULL;
+  EXIT_BLOCK_PTR->aux = NULL;
+  first_block_aux_obj = NULL;
+}
 
-      last_head = x;
-    }
+/* Allocate an memory edge of SIZE as BB->aux.  The obstack must
+   be first initialized by alloc_aux_for_edges.  */
 
-  /* Now check the basic blocks (boundaries etc.) */
-  for (i = n_basic_blocks - 1; i >= 0; i--)
-    {
-      basic_block bb = BASIC_BLOCK (i);
-      int has_fallthru = 0;
-      edge e;
+inline void
+alloc_aux_for_edge (e, size)
+     edge e;
+     int size;
+{
+  /* Verify that aux field is clear.  */
+  if (e->aux || !first_edge_aux_obj)
+    abort ();
+  e->aux = obstack_alloc (&edge_aux_obstack, size);
+  memset (e->aux, 0, size);
+}
 
-      e = bb->succ;
-      while (e)
-       {
-         if (last_visited [e->dest->index + 2] == bb)
-           {
-             error ("verify_flow_info: Duplicate edge %i->%i",
-                    e->src->index, e->dest->index);
-             err = 1;
-           }
-         last_visited [e->dest->index + 2] = bb;
-
-         if (e->flags & EDGE_FALLTHRU)
-           has_fallthru = 1;
-
-         if ((e->flags & EDGE_FALLTHRU)
-             && e->src != ENTRY_BLOCK_PTR
-             && e->dest != EXIT_BLOCK_PTR)
-           {
-             rtx insn;
-             if (e->src->index + 1 != e->dest->index)
-               {
-                   error ("verify_flow_info: Incorrect blocks for fallthru %i->%i",
-                          e->src->index, e->dest->index);
-                   err = 1;
-               }
-             else
-               for (insn = NEXT_INSN (e->src->end); insn != e->dest->head;
-                    insn = NEXT_INSN (insn))
-                 if (GET_CODE (insn) == BARRIER || INSN_P (insn))
-                   {
-                     error ("verify_flow_info: Incorrect fallthru %i->%i",
-                            e->src->index, e->dest->index);
-                     fatal_insn ("Wrong insn in the fallthru edge", insn);
-                     err = 1;
-                   }
-           }
-         if (e->src != bb)
-           {
-             error ("verify_flow_info: Basic block %d succ edge is corrupted",
-                    bb->index);
-             fprintf (stderr, "Predecessor: ");
-             dump_edge_info (stderr, e, 0);
-             fprintf (stderr, "\nSuccessor: ");
-             dump_edge_info (stderr, e, 1);
-             fprintf (stderr, "\n");
-             err = 1;
-           }
-         edge_checksum[e->dest->index + 2] += (size_t) e;
-         e = e->succ_next;
-       }
-      if (!has_fallthru)
-       {
-         rtx insn = bb->end;
-
-         /* Ensure existence of barrier in BB with no fallthru edges.  */
-         for (insn = bb->end; GET_CODE (insn) != BARRIER;
-              insn = NEXT_INSN (insn))
-           if (!insn
-               || (GET_CODE (insn) == NOTE
-                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK))
-               {
-                 error ("Missing barrier after block %i", bb->index);
-                 err = 1;
-               }
-       }
+/* Initialize the edge_aux_obstack and if SIZE is nonzero, call
+   alloc_aux_for_edge for each basic edge.  */
 
-      e = bb->pred;
-      while (e)
-       {
-         if (e->dest != bb)
-           {
-             error ("Basic block %d pred edge is corrupted", bb->index);
-             fputs ("Predecessor: ", stderr);
-             dump_edge_info (stderr, e, 0);
-             fputs ("\nSuccessor: ", stderr);
-             dump_edge_info (stderr, e, 1);
-             fputc ('\n', stderr);
-             err = 1;
-           }
-         edge_checksum[e->dest->index + 2] -= (size_t) e;
-         e = e->pred_next;
-       }
-       for (x = bb->head; x != NEXT_INSN (bb->end); x = NEXT_INSN (x))
-        if (basic_block_for_insn && BLOCK_FOR_INSN (x) != bb)
-          {
-            debug_rtx (x);
-            if (! BLOCK_FOR_INSN (x))
-              error ("Insn %d is inside basic block %d but block_for_insn is NULL",
-                     INSN_UID (x), bb->index);
-            else
-              error ("Insn %d is inside basic block %d but block_for_insn is %i",
-                     INSN_UID (x), bb->index, BLOCK_FOR_INSN (x)->index);
-            err = 1;
-          }
-
-      /* OK pointers are correct.  Now check the header of basic
-         block.  It ought to contain optional CODE_LABEL followed
-        by NOTE_BASIC_BLOCK.  */
-      x = bb->head;
-      if (GET_CODE (x) == CODE_LABEL)
-       {
-         if (bb->end == x)
-           {
-             error ("NOTE_INSN_BASIC_BLOCK is missing for block %d",
-                    bb->index);
-             err = 1;
-           }
-         x = NEXT_INSN (x);
-       }
-      if (!NOTE_INSN_BASIC_BLOCK_P (x) || NOTE_BASIC_BLOCK (x) != bb)
-       {
-         error ("NOTE_INSN_BASIC_BLOCK is missing for block %d",
-                bb->index);
-         err = 1;
-       }
+void
+alloc_aux_for_edges (size)
+     int size;
+{
+  static int initialized;
 
-      if (bb->end == x)
-       {
-         /* Do checks for empty blocks here */
-       }
-      else
-       {
-         x = NEXT_INSN (x);
-         while (x)
-           {
-             if (NOTE_INSN_BASIC_BLOCK_P (x))
-               {
-                 error ("NOTE_INSN_BASIC_BLOCK %d in the middle of basic block %d",
-                        INSN_UID (x), bb->index);
-                 err = 1;
-               }
-
-             if (x == bb->end)
-               break;
-
-             if (GET_CODE (x) == JUMP_INSN
-                 || GET_CODE (x) == CODE_LABEL
-                 || GET_CODE (x) == BARRIER)
-               {
-                 error ("In basic block %d:", bb->index);
-                 fatal_insn ("Flow control insn inside a basic block", x);
-               }
-
-             x = NEXT_INSN (x);
-           }
-       }
+  if (!initialized)
+    {
+      gcc_obstack_init (&edge_aux_obstack);
+      initialized = 1;
     }
-
-  /* Complete edge checksumming for ENTRY and EXIT.  */
-  {
-    edge e;
-    for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
-      edge_checksum[e->dest->index + 2] += (size_t) e;
-    for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
-      edge_checksum[e->dest->index + 2] -= (size_t) e;
-  }
-
-  for (i = -2; i < n_basic_blocks; ++i)
-    if (edge_checksum[i + 2])
-      {
-       error ("Basic block %i edge lists are corrupted", i);
-       err = 1;
-      }
-
-  last_bb_num_seen = -1;
-  num_bb_notes = 0;
-  x = rtx_first;
-  while (x)
+  /* Check whether AUX data are still allocated.  */
+  else if (first_edge_aux_obj)
+    abort ();
+  first_edge_aux_obj = (char *) obstack_alloc (&edge_aux_obstack, 0);
+  if (size)
     {
-      if (NOTE_INSN_BASIC_BLOCK_P (x))
-       {
-         basic_block bb = NOTE_BASIC_BLOCK (x);
-         num_bb_notes++;
-         if (bb->index != last_bb_num_seen + 1)
-           internal_error ("Basic blocks not numbered consecutively.");
-
-         last_bb_num_seen = bb->index;
-       }
-
-      if (!bb_info[INSN_UID (x)])
+      int i;
+      for (i = -1; i < n_basic_blocks; i++)
        {
-         switch (GET_CODE (x))
-           {
-           case BARRIER:
-           case NOTE:
-             break;
-
-           case CODE_LABEL:
-             /* An addr_vec is placed outside any block block.  */
-             if (NEXT_INSN (x)
-                 && GET_CODE (NEXT_INSN (x)) == JUMP_INSN
-                 && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
-                     || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
-               {
-                 x = NEXT_INSN (x);
-               }
-
-             /* But in any case, non-deletable labels can appear anywhere.  */
-             break;
-
-           default:
-             fatal_insn ("Insn outside basic block", x);
-           }
+         basic_block bb;
+         edge e;
+
+         if (i >= 0)
+           bb = BASIC_BLOCK (i);
+         else
+           bb = ENTRY_BLOCK_PTR;
+         for (e = bb->succ; e; e = e->succ_next)
+           alloc_aux_for_edge (e, size);
        }
-
-      if (INSN_P (x)
-         && GET_CODE (x) == JUMP_INSN
-         && returnjump_p (x) && ! condjump_p (x)
-         && ! (NEXT_INSN (x) && GET_CODE (NEXT_INSN (x)) == BARRIER))
-           fatal_insn ("Return not followed by barrier", x);
-
-      x = NEXT_INSN (x);
     }
-
-  if (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)
-    internal_error ("verify_flow_info failed.");
-
-  /* Clean up.  */
-  free (bb_info);
-  free (last_visited);
-  free (edge_checksum);
 }
-\f
-/* Assume that the preceeding pass has possibly eliminated jump instructions
-   or converted the unconditional jumps.  Eliminate the edges from CFG.
-   Return true if any edges are eliminated.  */
 
-bool
-purge_dead_edges (bb)
-     basic_block bb;
+/* Free data allocated in edge_aux_obstack and clear AUX pointers
+   of all edges.  */
+
+void
+free_aux_for_edges ()
 {
-  edge e, next;
-  rtx insn = bb->end;
-  bool purged = false;
+  int i;
 
-  if (GET_CODE (insn) == JUMP_INSN && !simplejump_p (insn))
-    return false;
-  if (GET_CODE (insn) == JUMP_INSN)
+  if (!first_edge_aux_obj)
+    abort ();
+  obstack_free (&edge_aux_obstack, first_edge_aux_obj);
+  for (i = -1; i < n_basic_blocks; i++)
     {
-      rtx note;
-      edge b,f;
-      /* We do care only about conditional jumps and simplejumps.  */
-      if (!any_condjump_p (insn)
-         && !returnjump_p (insn)
-         && !simplejump_p (insn))
-       return false;
-      for (e = bb->succ; e; e = next)
-       {
-         next = e->succ_next;
-
-         /* Check purposes we can have edge.  */
-         if ((e->flags & EDGE_FALLTHRU)
-             && any_condjump_p (insn))
-           continue;
-         if (e->dest != EXIT_BLOCK_PTR
-             && e->dest->head == JUMP_LABEL (insn))
-           continue;
-         if (e->dest == EXIT_BLOCK_PTR
-             && returnjump_p (insn))
-           continue;
-         purged = true;
-         remove_edge (e);
-       }
-      if (!bb->succ || !purged)
-       return false;
-      if (rtl_dump_file)
-       fprintf (rtl_dump_file, "Purged edges from bb %i\n", bb->index);
-      if (!optimize)
-       return purged;
-
-      /* Redistribute probabilities.  */
-      if (!bb->succ->succ_next)
-       {
-         bb->succ->probability = REG_BR_PROB_BASE;
-         bb->succ->count = bb->count;
-        }
-      else
-       {
-         note = find_reg_note (insn, REG_BR_PROB, NULL);
-         if (!note)
-           return purged;
-         b = BRANCH_EDGE (bb);
-         f = FALLTHRU_EDGE (bb);
-         b->probability = INTVAL (XEXP (note, 0));
-         f->probability = REG_BR_PROB_BASE - b->probability;
-         b->count = bb->count * b->probability / REG_BR_PROB_BASE;
-         f->count = bb->count * f->probability / REG_BR_PROB_BASE;
-       }
-      return purged;
-    }
-
-  /* Cleanup abnormal edges caused by throwing insns that have been
-     eliminated.  */
-  if (! can_throw_internal (bb->end))
-    for (e = bb->succ; e; e = next)
-      {
-       next = e->succ_next;
-       if (e->flags & EDGE_EH)
-         {
-           remove_edge (e);
-           purged = true;
-         }
-      }
+      basic_block bb;
+      edge e;
 
-  /* If we don't see a jump insn, we don't know exactly why the block would
-     have been broken at this point.  Look for a simple, non-fallthru edge,
-     as these are only created by conditional branches.  If we find such an
-     edge we know that there used to be a jump here and can then safely
-     remove all non-fallthru edges.  */
-  for (e = bb->succ; e && (e->flags & (EDGE_COMPLEX | EDGE_FALLTHRU));
-       e = e->succ_next);
-  if (!e)
-    return purged;
-  for (e = bb->succ; e; e = next)
-    {
-      next = e->succ_next;
-      if (!(e->flags & EDGE_FALLTHRU))
-       remove_edge (e), purged = true;
+      if (i >= 0)
+       bb = BASIC_BLOCK (i);
+      else
+       bb = ENTRY_BLOCK_PTR;
+      for (e = bb->succ; e; e = e->succ_next)
+       e->aux = NULL;
     }
-  if (!bb->succ || bb->succ->succ_next)
-    abort ();
-  bb->succ->probability = REG_BR_PROB_BASE;
-  bb->succ->count = bb->count;
-
-  if (rtl_dump_file)
-    fprintf (rtl_dump_file, "Purged non-fallthru edges from bb %i\n",
-            bb->index);
-  return purged;
-}
-
-/* Search all basic blocks for potentionally dead edges and purge them.
-
-   Return true ifif some edge has been elliminated.
- */
-
-bool
-purge_all_dead_edges ()
-{
-  int i, purged = false;
-  for (i = 0; i < n_basic_blocks; i++)
-    purged |= purge_dead_edges (BASIC_BLOCK (i));
-  return purged;
+  first_edge_aux_obj = NULL;
 }
index c52d255d53b788f15acff1086253b7b7e1f2936a..a9a8ec16c2cee7bfbd328fa445dfe4b3e148daf2 100644 (file)
@@ -106,14 +106,9 @@ try_simplify_condjump (cbranch_block)
   if (!can_fallthru (jump_block, cbranch_dest_block))
     return false;
 
-  /* Invert the conditional branch.  Prevent jump.c from deleting
-     "unreachable" instructions.  */
-  LABEL_NUSES (JUMP_LABEL (cbranch_insn))++;
-  if (!invert_jump (cbranch_insn, block_label (jump_dest_block), 1))
-    {
-      LABEL_NUSES (JUMP_LABEL (cbranch_insn))--;
-      return false;
-    }
+  /* Invert the conditional branch.  */
+  if (!invert_jump (cbranch_insn, block_label (jump_dest_block), 0))
+    return false;
 
   if (rtl_dump_file)
     fprintf (rtl_dump_file, "Simplifying condjump %i around jump %i\n",
@@ -1054,6 +1049,9 @@ try_optimize_cfg (mode)
   bool changed;
   int iterations = 0;
 
+  if (mode & CLEANUP_CROSSJUMP)
+    add_noreturn_fake_exit_edges ();
+
   /* 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.  */
@@ -1184,6 +1182,10 @@ try_optimize_cfg (mode)
       changed_overall |= changed;
     }
   while (changed);
+
+  if (mode & CLEANUP_CROSSJUMP)
+    remove_fake_edges ();
+
   return changed_overall;
 }
 \f
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
new file mode 100644 (file)
index 0000000..953ff80
--- /dev/null
@@ -0,0 +1,1928 @@
+/* Control flow graph manipulation code for GNU compiler.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* This file contains low level functions to manipulate with CFG and analyze it
+   that are aware of RTL intermediate language.
+
+   Available functionality:
+     - CFG aware instruction chain manipulation
+        delete_insn, delete_insn_chain
+     - Basic block manipulation
+        create_basic_block, flow_delete_block, split_block, merge_blocks_nomove
+     - Infrastructure to determine quickly basic block for instruction.
+        compute_bb_for_insn, update_bb_for_insn, set_block_for_insn,
+     - Edge redirection with updating and optimizing instruction chain
+            block_label, redirect_edge_and_branch,
+            redirect_edge_and_branch_force, tidy_fallthru_edge, force_nonfallthru
+     - Edge splitting and commiting to edges
+         split_edge, insert_insn_on_edge, commit_edge_insertions
+     - Dumpipng and debugging
+         print_rtl_with_bb, dump_bb, debug_bb, debug_bb_n
+     - Consistency checking
+         verify_flow_info
+     - CFG updating after constant propagation
+         purge_dead_edges, purge_all_dead_edges
+ */
+\f
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "rtl.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "regs.h"
+#include "flags.h"
+#include "output.h"
+#include "function.h"
+#include "except.h"
+#include "toplev.h"
+#include "tm_p.h"
+#include "obstack.h"
+
+/* Stubs in case we haven't got a return insn.  */
+#ifndef HAVE_return
+#define HAVE_return 0
+#define gen_return() NULL_RTX
+#endif
+
+/* The basic block structure for every insn, indexed by uid.  */
+
+varray_type basic_block_for_insn;
+
+/* The labels mentioned in non-jump rtl.  Valid during find_basic_blocks.  */
+/* ??? Should probably be using LABEL_NUSES instead.  It would take a
+   bit of surgery to be able to use or co-opt the routines in jump.  */
+
+rtx label_value_list;
+rtx tail_recursion_label_list;
+
+static int can_delete_note_p           PARAMS ((rtx));
+static int can_delete_label_p          PARAMS ((rtx));
+static void commit_one_edge_insertion  PARAMS ((edge));
+static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
+static rtx last_loop_beg_note          PARAMS ((rtx));
+static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
+static basic_block force_nonfallthru_and_redirect PARAMS ((edge, basic_block));
+\f
+/* Return true if NOTE is not one of the ones that must be kept paired,
+   so that we may simply delete them.  */
+
+static int
+can_delete_note_p (note)
+     rtx note;
+{
+  return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
+         || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
+}
+
+/* True if a given label can be deleted.  */
+
+static int
+can_delete_label_p (label)
+     rtx label;
+{
+  rtx x;
+
+  if (LABEL_PRESERVE_P (label))
+    return 0;
+
+  for (x = forced_labels; x; x = XEXP (x, 1))
+    if (label == XEXP (x, 0))
+      return 0;
+  for (x = label_value_list; x; x = XEXP (x, 1))
+    if (label == XEXP (x, 0))
+      return 0;
+  for (x = exception_handler_labels; x; x = XEXP (x, 1))
+    if (label == XEXP (x, 0))
+      return 0;
+
+  /* User declared labels must be preserved.  */
+  if (LABEL_NAME (label) != 0)
+    return 0;
+
+  return 1;
+}
+
+/* Delete INSN by patching it out.  Return the next insn.  */
+
+rtx
+delete_insn (insn)
+     rtx insn;
+{
+  rtx next = NEXT_INSN (insn);
+  rtx note;
+  bool really_delete = true;
+
+  if (GET_CODE (insn) == CODE_LABEL)
+    {
+      /* Some labels can't be directly removed from the INSN chain, as they
+         might be references via variables, constant pool etc. 
+         Convert them to the special NOTE_INSN_DELETED_LABEL note.  */
+      if (! can_delete_label_p (insn))
+       {
+         const char *name = LABEL_NAME (insn);
+
+         really_delete = false;
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED_LABEL;
+         NOTE_SOURCE_FILE (insn) = name;
+       }
+      remove_node_from_expr_list (insn, &nonlocal_goto_handler_labels);
+    }
+
+  if (really_delete)
+    {
+      remove_insn (insn);
+      INSN_DELETED_P (insn) = 1;
+    }
+
+  /* If deleting a jump, decrement the use count of the label.  Deleting
+     the label itself should happen in the normal course of block merging.  */
+  if (GET_CODE (insn) == JUMP_INSN
+      && JUMP_LABEL (insn)
+      && GET_CODE (JUMP_LABEL (insn)) == CODE_LABEL)
+    LABEL_NUSES (JUMP_LABEL (insn))--;
+
+  /* Also if deleting an insn that references a label.  */
+  else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
+          && 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;
+}
+
+/* Unlink a chain of insns between START and FINISH, leaving notes
+   that must be paired.  */
+
+void
+delete_insn_chain (start, finish)
+     rtx start, finish;
+{
+  /* Unchain the insns one by one.  It would be quicker to delete all
+     of these with a single unchaining, rather than one at a time, but
+     we need to keep the NOTE's.  */
+
+  rtx next;
+
+  while (1)
+    {
+      next = NEXT_INSN (start);
+      if (GET_CODE (start) == NOTE && !can_delete_note_p (start))
+       ;
+      else
+       next = delete_insn (start);
+
+      if (start == finish)
+       break;
+      start = next;
+    }
+}
+\f
+/* Create a new basic block consisting of the instructions between
+   HEAD and END inclusive.  This function is designed to allow fast
+   BB construction - reuses the note and basic block struct
+   in BB_NOTE, if any and do not grow BASIC_BLOCK chain and should
+   be used directly only by CFG construction code.
+   END can be NULL in to create new empty basic block before HEAD.
+   Both END and HEAD can be NULL to create basic block at the end of
+   INSN chain.  */
+
+basic_block
+create_basic_block_structure (index, head, end, bb_note)
+     int index;
+     rtx head, end, bb_note;
+{
+  basic_block bb;
+
+  if (bb_note
+      && ! RTX_INTEGRATED_P (bb_note)
+      && (bb = NOTE_BASIC_BLOCK (bb_note)) != NULL
+      && bb->aux == NULL)
+    {
+      /* If we found an existing note, thread it back onto the chain.  */
+
+      rtx after;
+
+      if (GET_CODE (head) == CODE_LABEL)
+       after = head;
+      else
+       {
+         after = PREV_INSN (head);
+         head = bb_note;
+       }
+
+      if (after != bb_note && NEXT_INSN (after) != bb_note)
+       reorder_insns (bb_note, bb_note, after);
+    }
+  else
+    {
+      /* Otherwise we must create a note and a basic block structure.  */
+
+      bb = alloc_block ();
+
+      if (!head && !end)
+       {
+         head = end = bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK,
+                                                 get_last_insn ());
+       }
+      else if (GET_CODE (head) == CODE_LABEL && end)
+       {
+         bb_note = emit_note_after (NOTE_INSN_BASIC_BLOCK, head);
+         if (head == end)
+           end = bb_note;
+       }
+      else
+       {
+         bb_note = emit_note_before (NOTE_INSN_BASIC_BLOCK, head);
+         head = bb_note;
+         if (!end)
+           end = head;
+       }
+      NOTE_BASIC_BLOCK (bb_note) = bb;
+    }
+
+  /* Always include the bb note in the block.  */
+  if (NEXT_INSN (end) == bb_note)
+    end = bb_note;
+
+  bb->head = head;
+  bb->end = end;
+  bb->index = index;
+  BASIC_BLOCK (index) = bb;
+  if (basic_block_for_insn)
+    update_bb_for_insn (bb);
+
+  /* Tag the block so that we know it has been used when considering
+     other basic block notes.  */
+  bb->aux = bb;
+
+  return bb;
+}
+
+/* Create new basic block consisting of instructions in between HEAD and
+   END and place it to the BB chain at possition INDEX.
+   END can be NULL in to create new empty basic block before HEAD.
+   Both END and HEAD can be NULL to create basic block at the end of
+   INSN chain.  */
+
+basic_block
+create_basic_block (index, head, end)
+     int index;
+     rtx head, end;
+{
+  basic_block bb;
+  int i;
+
+  /* Place the new block just after the block being split.  */
+  VARRAY_GROW (basic_block_info, ++n_basic_blocks);
+
+  /* Some parts of the compiler expect blocks to be number in
+     sequential order so insert the new block immediately after the
+     block being split..  */
+  for (i = n_basic_blocks - 1; i > index; --i)
+    {
+      basic_block tmp = BASIC_BLOCK (i - 1);
+      BASIC_BLOCK (i) = tmp;
+      tmp->index = i;
+    }
+
+  bb = create_basic_block_structure (index, head, end, NULL);
+  bb->aux = NULL;
+  return bb;
+}
+\f
+/* Delete the insns in a (non-live) block.  We physically delete every
+   non-deleted-note insn, and update the flow graph appropriately.
+
+   Return nonzero if we deleted an exception handler.  */
+
+/* ??? Preserving all such notes strikes me as wrong.  It would be nice
+   to post-process the stream to remove empty blocks, loops, ranges, etc.  */
+
+int
+flow_delete_block (b)
+     basic_block b;
+{
+  int deleted_handler = 0;
+  rtx insn, end, tmp;
+
+  /* If the head of this block is a CODE_LABEL, then it might be the
+     label for an exception handler which can't be reached.
+
+     We need to remove the label from the exception_handler_label list
+     and remove the associated NOTE_INSN_EH_REGION_BEG and
+     NOTE_INSN_EH_REGION_END notes.  */
+
+  insn = b->head;
+
+  never_reached_warning (insn);
+
+  if (GET_CODE (insn) == CODE_LABEL)
+    maybe_remove_eh_handler (insn);
+
+  /* Include any jump table following the basic block.  */
+  end = b->end;
+  if (GET_CODE (end) == JUMP_INSN
+      && (tmp = JUMP_LABEL (end)) != 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))
+    end = tmp;
+
+  /* Include any barrier that may follow the basic block.  */
+  tmp = next_nonnote_insn (end);
+  if (tmp && GET_CODE (tmp) == BARRIER)
+    end = tmp;
+
+  /* Selectively delete the entire chain.  */
+  b->head = NULL;
+  delete_insn_chain (insn, end);
+
+  /* Remove the edges into and out of this block.  Note that there may
+     indeed be edges in, if we are removing an unreachable loop.  */
+  while (b->pred != NULL)
+    remove_edge (b->pred);
+  while (b->succ != NULL)
+    remove_edge (b->succ);
+
+  b->pred = NULL;
+  b->succ = NULL;
+
+  /* Remove the basic block from the array, and compact behind it.  */
+  expunge_block (b);
+
+  return deleted_handler;
+}
+\f
+/* Records the basic block struct in BB_FOR_INSN, for every instruction
+   indexed by INSN_UID.  MAX is the size of the array.  */
+
+void
+compute_bb_for_insn (max)
+     int max;
+{
+  int i;
+
+  if (basic_block_for_insn)
+    VARRAY_FREE (basic_block_for_insn);
+  VARRAY_BB_INIT (basic_block_for_insn, max, "basic_block_for_insn");
+
+  for (i = 0; i < n_basic_blocks; ++i)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      rtx insn, end;
+
+      end = bb->end;
+      insn = bb->head;
+      while (1)
+       {
+         int uid = INSN_UID (insn);
+         if (uid < max)
+           VARRAY_BB (basic_block_for_insn, uid) = bb;
+         if (insn == end)
+           break;
+         insn = NEXT_INSN (insn);
+       }
+    }
+}
+
+/* Release the basic_block_for_insn array.  */
+
+void
+free_bb_for_insn ()
+{
+  if (basic_block_for_insn)
+    VARRAY_FREE (basic_block_for_insn);
+  basic_block_for_insn = 0;
+}
+
+/* Update insns block within BB.  */
+
+void
+update_bb_for_insn (bb)
+     basic_block bb;
+{
+  rtx insn;
+
+  if (! basic_block_for_insn)
+    return;
+
+  for (insn = bb->head; ; insn = NEXT_INSN (insn))
+    {
+      set_block_for_insn (insn, bb);
+
+      if (insn == bb->end)
+       break;
+    }
+}
+
+/* Record INSN's block as BB.  */
+
+void
+set_block_for_insn (insn, bb)
+     rtx insn;
+     basic_block bb;
+{
+  size_t uid = INSN_UID (insn);
+  if (uid >= basic_block_for_insn->num_elements)
+    {
+      int new_size;
+
+      /* Add one-eighth the size so we don't keep calling xrealloc.  */
+      new_size = uid + (uid + 7) / 8;
+
+      VARRAY_GROW (basic_block_for_insn, new_size);
+    }
+  VARRAY_BB (basic_block_for_insn, uid) = bb;
+}
+\f
+/* Split a block BB after insn INSN creating a new fallthru edge.
+   Return the new edge.  Note that to keep other parts of the compiler happy,
+   this function renumbers all the basic blocks so that the new
+   one has a number one greater than the block split.  */
+
+edge
+split_block (bb, insn)
+     basic_block bb;
+     rtx insn;
+{
+  basic_block new_bb;
+  edge new_edge;
+  edge e;
+
+  /* There is no point splitting the block after its end.  */
+  if (bb->end == insn)
+    return 0;
+
+  /* Create the new basic block.  */
+  new_bb = create_basic_block (bb->index + 1, NEXT_INSN (insn), bb->end);
+  new_bb->count = bb->count;
+  new_bb->frequency = bb->frequency;
+  new_bb->loop_depth = bb->loop_depth;
+  bb->end = insn;
+
+  /* Redirect the outgoing edges.  */
+  new_bb->succ = bb->succ;
+  bb->succ = NULL;
+  for (e = new_bb->succ; e; e = e->succ_next)
+    e->src = new_bb;
+
+  new_edge = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
+
+  if (bb->global_live_at_start)
+    {
+      new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
+
+      /* We now have to calculate which registers are live at the end
+        of the split basic block and at the start of the new basic
+        block.  Start with those registers that are known to be live
+        at the end of the original basic block and get
+        propagate_block to determine which registers are live.  */
+      COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_end);
+      propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
+      COPY_REG_SET (bb->global_live_at_end,
+                   new_bb->global_live_at_start);
+    }
+
+  return new_edge;
+}
+
+/* Blocks A and B are to be merged into a single block A.  The insns
+   are already contiguous, hence `nomove'.  */
+
+void
+merge_blocks_nomove (a, b)
+     basic_block a, b;
+{
+  edge e;
+  rtx b_head, b_end, a_end;
+  rtx del_first = NULL_RTX, del_last = NULL_RTX;
+  int b_empty = 0;
+
+  /* If there was a CODE_LABEL beginning B, delete it.  */
+  b_head = b->head;
+  b_end = b->end;
+  if (GET_CODE (b_head) == CODE_LABEL)
+    {
+      /* Detect basic blocks with nothing but a label.  This can happen
+        in particular at the end of a function.  */
+      if (b_head == b_end)
+       b_empty = 1;
+      del_first = del_last = b_head;
+      b_head = NEXT_INSN (b_head);
+    }
+
+  /* Delete the basic block note.  */
+  if (NOTE_INSN_BASIC_BLOCK_P (b_head))
+    {
+      if (b_head == b_end)
+       b_empty = 1;
+      if (! del_last)
+       del_first = b_head;
+      del_last = b_head;
+      b_head = NEXT_INSN (b_head);
+    }
+
+  /* If there was a jump out of A, delete it.  */
+  a_end = a->end;
+  if (GET_CODE (a_end) == JUMP_INSN)
+    {
+      rtx prev;
+
+      for (prev = PREV_INSN (a_end); ; prev = PREV_INSN (prev))
+       if (GET_CODE (prev) != NOTE
+           || NOTE_LINE_NUMBER (prev) == NOTE_INSN_BASIC_BLOCK
+           || prev == a->head)
+         break;
+
+      del_first = a_end;
+
+#ifdef HAVE_cc0
+      /* If this was a conditional jump, we need to also delete
+        the insn that set cc0.  */
+      if (only_sets_cc0_p (prev))
+       {
+         rtx tmp = prev;
+         prev = prev_nonnote_insn (prev);
+         if (!prev)
+           prev = a->head;
+         del_first = tmp;
+       }
+#endif
+
+      a_end = PREV_INSN (del_first);
+    }
+  else if (GET_CODE (NEXT_INSN (a_end)) == BARRIER)
+    del_first = NEXT_INSN (a_end);
+
+  /* Normally there should only be one successor of A and that is B, but
+     partway though the merge of blocks for conditional_execution we'll
+     be merging a TEST block with THEN and ELSE successors.  Free the
+     whole lot of them and hope the caller knows what they're doing.  */
+  while (a->succ)
+    remove_edge (a->succ);
+
+  /* Adjust the edges out of B for the new owner.  */
+  for (e = b->succ; e; e = e->succ_next)
+    e->src = a;
+  a->succ = b->succ;
+
+  /* B hasn't quite yet ceased to exist.  Attempt to prevent mishap.  */
+  b->pred = b->succ = NULL;
+
+  expunge_block (b);
+
+  /* Delete everything marked above as well as crap that might be
+     hanging out between the two blocks.  */
+  delete_insn_chain (del_first, del_last);
+
+  /* Reassociate the insns of B with A.  */
+  if (!b_empty)
+    {
+      rtx x = a_end;
+      if (basic_block_for_insn)
+       {
+         BLOCK_FOR_INSN (x) = a;
+         while (x != b_end)
+           {
+             x = NEXT_INSN (x);
+             BLOCK_FOR_INSN (x) = a;
+           }
+       }
+      a_end = b_end;
+    }
+  a->end = a_end;
+}
+\f
+/* Return label in the head of basic block.  Create one if it doesn't exist.  */
+
+rtx
+block_label (block)
+     basic_block block;
+{
+  if (block == EXIT_BLOCK_PTR)
+    return NULL_RTX;
+  if (GET_CODE (block->head) != CODE_LABEL)
+    {
+      block->head = emit_label_before (gen_label_rtx (), block->head);
+      if (basic_block_for_insn)
+       set_block_for_insn (block->head, block);
+    }
+  return block->head;
+}
+
+/* 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, kill_from;
+  edge tmp;
+  rtx set;
+  int fallthru = 0;
+
+  /* Verify that all targets will be TARGET.  */
+  for (tmp = src->succ; tmp; tmp = tmp->succ_next)
+    if (tmp->dest != target && tmp != e)
+      break;
+  if (tmp || !onlyjump_p (insn))
+    return false;
+
+  /* Avoid removing branch with side effects.  */
+  set = single_set (insn);
+  if (!set || side_effects_p (set))
+    return false;
+
+  /* In case we zap a conditional jump, we'll need to kill
+     the cc0 setter too.  */
+  kill_from = insn;
+#ifdef HAVE_cc0
+  if (reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+    kill_from = PREV_INSN (insn);
+#endif
+
+  /* See if we can create the fallthru edge.  */
+  if (can_fallthru (src, target))
+    {
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Removing jump %i.\n", INSN_UID (insn));
+      fallthru = 1;
+
+      /* Selectivly unlink whole insn chain.  */
+      delete_insn_chain (kill_from, PREV_INSN (target->head));
+    }
+  /* 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);
+      rtx barrier;
+
+      emit_jump_insn_after (gen_jump (target_label), kill_from);
+      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));
+
+      delete_insn_chain (kill_from, insn);
+
+      barrier = next_nonnote_insn (src->end);
+      if (!barrier || GET_CODE (barrier) != BARRIER)
+       emit_barrier_after (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;
+
+  /* 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 (e->src->end) == NOTE
+        && NOTE_LINE_NUMBER (e->src->end) >= 0)
+    delete_insn (e->src->end);
+
+  if (e->dest != target)
+    redirect_edge_succ (e, target);
+  return true;
+}
+
+/* Return last loop_beg note appearing after INSN, before start of next
+   basic block.  Return INSN if there are no such notes.
+
+   When emmiting jump to redirect an fallthru edge, it should always
+   appear after the LOOP_BEG notes, as loop optimizer expect loop to
+   eighter start by fallthru edge or jump following the LOOP_BEG note
+   jumping to the loop exit test.  */
+
+static rtx
+last_loop_beg_note (insn)
+     rtx insn;
+{
+  rtx last = insn;
+  insn = NEXT_INSN (insn);
+  while (insn && GET_CODE (insn) == NOTE
+        && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
+    {
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+       last = insn;
+      insn = NEXT_INSN (insn);
+    }
+  return last;
+}
+
+/* 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.  */
+
+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 (e->flags & EDGE_COMPLEX)
+    return false;
+
+  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)
+    redirect_edge_succ_nodup (e, target);
+  return true;
+}
+
+/* Like force_nonfallthru bellow, but additionally performs redirection
+   Used by redirect_edge_and_branch_force.  */
+
+static basic_block
+force_nonfallthru_and_redirect (e, target)
+     edge e;
+     basic_block target;
+{
+  basic_block jump_block, new_bb = NULL;
+  rtx note;
+  edge new_edge;
+
+  if (e->flags & EDGE_ABNORMAL)
+    abort ();
+  if (!(e->flags & EDGE_FALLTHRU))
+    abort ();
+  if (e->src->succ->succ_next)
+    {
+      /* Create the new structures.  */
+      note = last_loop_beg_note (e->src->end);
+      jump_block = create_basic_block (e->src->index + 1, NEXT_INSN (note), NULL);
+      jump_block->count = e->count;
+      jump_block->frequency = EDGE_FREQUENCY (e);
+      jump_block->loop_depth = target->loop_depth;
+
+      if (target->global_live_at_start)
+       {
+         jump_block->global_live_at_start =
+           OBSTACK_ALLOC_REG_SET (&flow_obstack);
+         jump_block->global_live_at_end =
+           OBSTACK_ALLOC_REG_SET (&flow_obstack);
+         COPY_REG_SET (jump_block->global_live_at_start,
+                       target->global_live_at_start);
+         COPY_REG_SET (jump_block->global_live_at_end,
+                       target->global_live_at_start);
+       }
+
+      /* Wire edge in.  */
+      new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
+      new_edge->probability = e->probability;
+      new_edge->count = e->count;
+
+      /* Redirect old edge.  */
+      redirect_edge_pred (e, jump_block);
+      e->probability = REG_BR_PROB_BASE;
+
+      new_bb = jump_block;
+    }
+  else
+    jump_block = e->src;
+  e->flags &= ~EDGE_FALLTHRU;
+  if (target == EXIT_BLOCK_PTR)
+    {
+      if (HAVE_return)
+       emit_jump_insn_after (gen_return (), jump_block->end);
+      else
+       abort ();
+    }
+  else
+    {
+      rtx label = block_label (target);
+      emit_jump_insn_after (gen_jump (label), jump_block->end);
+      JUMP_LABEL (jump_block->end) = label;
+      LABEL_NUSES (label)++;
+    }
+  emit_barrier_after (jump_block->end);
+  redirect_edge_succ_nodup (e, target);
+
+  return new_bb;
+}
+
+/* Edge E is assumed to be fallthru edge.  Emit needed jump instruction
+   (and possibly create new basic block) to make edge non-fallthru.
+   Return newly created BB or NULL if none.  */
+basic_block
+force_nonfallthru (e)
+     edge e;
+{
+  return force_nonfallthru_and_redirect (e, e->dest);
+}
+
+/* Redirect edge even at the expense of creating new jump insn or
+   basic block.  Return new basic block if created, NULL otherwise.
+   Abort if converison is impossible.  */
+
+basic_block
+redirect_edge_and_branch_force (e, target)
+     edge e;
+     basic_block target;
+{
+  basic_block new_bb;
+
+  if (redirect_edge_and_branch (e, target))
+    return NULL;
+  if (e->dest == target)
+    return NULL;
+
+  /* In case the edge redirection failed, try to force it to be non-fallthru
+     and redirect newly created simplejump.  */
+  new_bb = force_nonfallthru_and_redirect (e, target);
+  return new_bb;
+}
+
+/* The given edge should potentially be a fallthru edge.  If that is in
+   fact true, delete the jump and barriers that are in the way.  */
+
+void
+tidy_fallthru_edge (e, b, c)
+     edge e;
+     basic_block b, c;
+{
+  rtx q;
+
+  /* ??? In a late-running flow pass, other folks may have deleted basic
+     blocks by nopping out blocks, leaving multiple BARRIERs between here
+     and the target label. They ought to be chastized and fixed.
+
+     We can also wind up with a sequence of undeletable labels between
+     one block and the next.
+
+     So search through a sequence of barriers, labels, and notes for
+     the head of block C and assert that we really do fall through.  */
+
+  if (next_real_insn (b->end) != next_real_insn (PREV_INSN (c->head)))
+    return;
+
+  /* Remove what will soon cease being the jump insn from the source block.
+     If block B consisted only of this single jump, turn it into a deleted
+     note.  */
+  q = b->end;
+  if (GET_CODE (q) == JUMP_INSN
+      && onlyjump_p (q)
+      && (any_uncondjump_p (q)
+         || (b->succ == e && e->succ_next == NULL)))
+    {
+#ifdef HAVE_cc0
+      /* If this was a conditional jump, we need to also delete
+        the insn that set cc0.  */
+      if (any_condjump_p (q) && only_sets_cc0_p (PREV_INSN (q)))
+       q = PREV_INSN (q);
+#endif
+
+      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);
+    }
+
+  /* Selectively unlink the sequence.  */
+  if (q != PREV_INSN (c->head))
+    delete_insn_chain (NEXT_INSN (q), PREV_INSN (c->head));
+
+  e->flags |= EDGE_FALLTHRU;
+}
+
+/* Fix up edges that now fall through, or rather should now fall through
+   but previously required a jump around now deleted blocks.  Simplify
+   the search by only examining blocks numerically adjacent, since this
+   is how find_basic_blocks created them.  */
+
+void
+tidy_fallthru_edges ()
+{
+  int i;
+
+  for (i = 1; i < n_basic_blocks; ++i)
+    {
+      basic_block b = BASIC_BLOCK (i - 1);
+      basic_block c = BASIC_BLOCK (i);
+      edge s;
+
+      /* We care about simple conditional or unconditional jumps with
+        a single successor.
+
+        If we had a conditional branch to the next instruction when
+        find_basic_blocks was called, then there will only be one
+        out edge for the block which ended with the conditional
+        branch (since we do not create duplicate edges).
+
+        Furthermore, the edge will be marked as a fallthru because we
+        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.  */
+         && (GET_CODE (b->end) != JUMP_INSN
+             || onlyjump_p (b->end)))
+       tidy_fallthru_edge (s, b, c);
+    }
+}
+\f
+/* Helper function for split_edge.  Return true in case edge BB2 to BB1
+   is back edge of syntactic loop.  */
+
+static bool
+back_edge_of_syntactic_loop_p (bb1, bb2)
+       basic_block bb1, bb2;
+{
+  rtx insn;
+  int count = 0;
+
+  if (bb1->index > bb2->index)
+    return false;
+
+  if (bb1->index == bb2->index)
+    return true;
+
+  for (insn = bb1->end; insn != bb2->head && count >= 0;
+       insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == NOTE)
+      {
+       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+         count++;
+       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+         count--;
+      }
+
+  return count >= 0;
+}
+
+/* Split a (typically critical) edge.  Return the new block.
+   Abort on abnormal edges.
+
+   ??? The code generally expects to be called on critical edges.
+   The case of a block ending in an unconditional jump to a
+   block with multiple predecessors is not handled optimally.  */
+
+basic_block
+split_edge (edge_in)
+     edge edge_in;
+{
+  basic_block bb;
+  edge edge_out;
+  rtx before;
+
+  /* Abnormal edges cannot be split.  */
+  if ((edge_in->flags & EDGE_ABNORMAL) != 0)
+    abort ();
+
+  /* We are going to place the new block in front of edge destination.
+     Avoid existence of fallthru predecesors.  */
+  if ((edge_in->flags & EDGE_FALLTHRU) == 0)
+    {
+      edge e;
+      for (e = edge_in->dest->pred; e; e = e->pred_next)
+       if (e->flags & EDGE_FALLTHRU)
+         break;
+
+      if (e)
+       force_nonfallthru (e);
+    }
+
+  /* Create the basic block note.
+
+     Where we place the note can have a noticable impact on the generated
+     code.  Consider this cfg:
+
+                       E
+                       |
+                       0
+                      / \
+                  +->1-->2--->E
+                   |  |
+                  +--+
+
+      If we need to insert an insn on the edge from block 0 to block 1,
+      we want to ensure the instructions we insert are outside of any
+      loop notes that physically sit between block 0 and block 1.  Otherwise
+      we confuse the loop optimizer into thinking the loop is a phony.  */
+
+  if (edge_in->dest != EXIT_BLOCK_PTR
+      && PREV_INSN (edge_in->dest->head)
+      && GET_CODE (PREV_INSN (edge_in->dest->head)) == NOTE
+      && NOTE_LINE_NUMBER (PREV_INSN (edge_in->dest->head)) == NOTE_INSN_LOOP_BEG
+      && !back_edge_of_syntactic_loop_p (edge_in->dest, edge_in->src))
+    before = PREV_INSN (edge_in->dest->head);
+  else if (edge_in->dest != EXIT_BLOCK_PTR)
+    before = edge_in->dest->head;
+  else
+    before = NULL_RTX;
+
+  bb = create_basic_block (edge_in->dest == EXIT_BLOCK_PTR ? n_basic_blocks
+                          : edge_in->dest->index, before, NULL);
+  bb->count = edge_in->count;
+  bb->frequency = EDGE_FREQUENCY (edge_in);
+
+  /* ??? This info is likely going to be out of date very soon.  */
+  if (edge_in->dest->global_live_at_start)
+    {
+      bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
+      COPY_REG_SET (bb->global_live_at_start, edge_in->dest->global_live_at_start);
+      COPY_REG_SET (bb->global_live_at_end, edge_in->dest->global_live_at_start);
+    }
+
+  edge_out = make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
+
+  /* For non-fallthry edges, we must adjust the predecessor's
+     jump instruction to target our new block.  */
+  if ((edge_in->flags & EDGE_FALLTHRU) == 0)
+    {
+      if (!redirect_edge_and_branch (edge_in, bb))
+       abort ();
+    }
+  else
+    redirect_edge_succ (edge_in, bb);
+
+  return bb;
+}
+
+/* Queue instructions for insertion on an edge between two basic blocks.
+   The new instructions and basic blocks (if any) will not appear in the
+   CFG until commit_edge_insertions is called.  */
+
+void
+insert_insn_on_edge (pattern, e)
+     rtx pattern;
+     edge e;
+{
+  /* We cannot insert instructions on an abnormal critical edge.
+     It will be easier to find the culprit if we die now.  */
+  if ((e->flags & EDGE_ABNORMAL) && EDGE_CRITICAL_P (e))
+    abort ();
+
+  if (e->insns == NULL_RTX)
+    start_sequence ();
+  else
+    push_to_sequence (e->insns);
+
+  emit_insn (pattern);
+
+  e->insns = get_insns ();
+  end_sequence ();
+}
+
+/* Update the CFG for the instructions queued on edge E.  */
+
+static void
+commit_one_edge_insertion (e)
+     edge e;
+{
+  rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
+  basic_block bb;
+
+  /* Pull the insns off the edge now since the edge might go away.  */
+  insns = e->insns;
+  e->insns = NULL_RTX;
+
+  /* Figure out where to put these things.  If the destination has
+     one predecessor, insert there.  Except for the exit block.  */
+  if (e->dest->pred->pred_next == NULL
+      && e->dest != EXIT_BLOCK_PTR)
+    {
+      bb = e->dest;
+
+      /* Get the location correct wrt a code label, and "nice" wrt
+        a basic block note, and before everything else.  */
+      tmp = bb->head;
+      if (GET_CODE (tmp) == CODE_LABEL)
+       tmp = NEXT_INSN (tmp);
+      if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+       tmp = NEXT_INSN (tmp);
+      if (tmp == bb->head)
+       before = tmp;
+      else
+       after = PREV_INSN (tmp);
+    }
+
+  /* If the source has one successor and the edge is not abnormal,
+     insert there.  Except for the entry block.  */
+  else if ((e->flags & EDGE_ABNORMAL) == 0
+          && e->src->succ->succ_next == NULL
+          && e->src != ENTRY_BLOCK_PTR)
+    {
+      bb = e->src;
+      /* It is possible to have a non-simple jump here.  Consider a target
+        where some forms of unconditional jumps clobber a register.  This
+        happens on the fr30 for example.
+
+        We know this block has a single successor, so we can just emit
+        the queued insns before the jump.  */
+      if (GET_CODE (bb->end) == JUMP_INSN)
+       {
+         before = bb->end;
+         while (GET_CODE (PREV_INSN (before)) == NOTE
+                && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG)
+           before = PREV_INSN (before);
+       }
+      else
+       {
+         /* We'd better be fallthru, or we've lost track of what's what.  */
+         if ((e->flags & EDGE_FALLTHRU) == 0)
+           abort ();
+
+         after = bb->end;
+       }
+    }
+
+  /* Otherwise we must split the edge.  */
+  else
+    {
+      bb = split_edge (e);
+      after = bb->end;
+    }
+
+  /* Now that we've found the spot, do the insertion.  */
+
+  if (before)
+    {
+      emit_insns_before (insns, before);
+      last = prev_nonnote_insn (before);
+    }
+  else
+    last = emit_insns_after (insns, after);
+
+  if (returnjump_p (last))
+    {
+      /* ??? Remove all outgoing edges from BB and add one for EXIT.
+         This is not currently a problem because this only happens
+        for the (single) epilogue, which already has a fallthru edge
+        to EXIT.  */
+
+      e = bb->succ;
+      if (e->dest != EXIT_BLOCK_PTR
+         || e->succ_next != NULL
+         || (e->flags & EDGE_FALLTHRU) == 0)
+       abort ();
+      e->flags &= ~EDGE_FALLTHRU;
+
+      emit_barrier_after (last);
+
+      if (before)
+       delete_insn (before);
+    }
+  else if (GET_CODE (last) == JUMP_INSN)
+    abort ();
+  find_sub_basic_blocks (bb);
+}
+
+/* Update the CFG for all queued instructions.  */
+
+void
+commit_edge_insertions ()
+{
+  int i;
+  basic_block bb;
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+
+  i = -1;
+  bb = ENTRY_BLOCK_PTR;
+  while (1)
+    {
+      edge e, next;
+
+      for (e = bb->succ; e; e = next)
+       {
+         next = e->succ_next;
+         if (e->insns)
+           commit_one_edge_insertion (e);
+       }
+
+      if (++i >= n_basic_blocks)
+       break;
+      bb = BASIC_BLOCK (i);
+    }
+}
+\f
+/* Print out one basic block with live information at start and end.  */
+
+void
+dump_bb (bb, outf)
+     basic_block bb;
+     FILE *outf;
+{
+  rtx insn;
+  rtx last;
+  edge e;
+
+  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);
+  for (e = bb->pred; e; e = e->pred_next)
+    dump_edge_info (outf, e, 0);
+  putc ('\n', outf);
+
+  fputs (";; Registers live at start:", outf);
+  dump_regset (bb->global_live_at_start, outf);
+  putc ('\n', outf);
+
+  for (insn = bb->head, last = NEXT_INSN (bb->end);
+       insn != last;
+       insn = NEXT_INSN (insn))
+    print_rtl_single (outf, insn);
+
+  fputs (";; Registers live at end:", outf);
+  dump_regset (bb->global_live_at_end, outf);
+  putc ('\n', outf);
+
+  fputs (";; Successors: ", outf);
+  for (e = bb->succ; e; e = e->succ_next)
+    dump_edge_info (outf, e, 1);
+  putc ('\n', outf);
+}
+
+void
+debug_bb (bb)
+     basic_block bb;
+{
+  dump_bb (bb, stderr);
+}
+
+void
+debug_bb_n (n)
+     int n;
+{
+  dump_bb (BASIC_BLOCK (n), stderr);
+}
+\f
+/* Like print_rtl, but also print out live information for the start of each
+   basic block.  */
+
+void
+print_rtl_with_bb (outf, rtx_first)
+     FILE *outf;
+     rtx rtx_first;
+{
+  register rtx tmp_rtx;
+
+  if (rtx_first == 0)
+    fprintf (outf, "(nil)\n");
+  else
+    {
+      int i;
+      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
+      int max_uid = get_max_uid ();
+      basic_block *start = (basic_block *)
+       xcalloc (max_uid, sizeof (basic_block));
+      basic_block *end = (basic_block *)
+       xcalloc (max_uid, sizeof (basic_block));
+      enum bb_state *in_bb_p = (enum bb_state *)
+       xcalloc (max_uid, sizeof (enum bb_state));
+
+      for (i = n_basic_blocks - 1; i >= 0; i--)
+       {
+         basic_block bb = BASIC_BLOCK (i);
+         rtx x;
+
+         start[INSN_UID (bb->head)] = bb;
+         end[INSN_UID (bb->end)] = bb;
+         for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
+           {
+             enum bb_state state = IN_MULTIPLE_BB;
+             if (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
+               state = IN_ONE_BB;
+             in_bb_p[INSN_UID (x)] = state;
+
+             if (x == bb->end)
+               break;
+           }
+       }
+
+      for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
+       {
+         int did_output;
+         basic_block bb;
+
+         if ((bb = start[INSN_UID (tmp_rtx)]) != NULL)
+           {
+             fprintf (outf, ";; Start of basic block %d, registers live:",
+                      bb->index);
+             dump_regset (bb->global_live_at_start, outf);
+             putc ('\n', outf);
+           }
+
+         if (in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB
+             && GET_CODE (tmp_rtx) != NOTE
+             && GET_CODE (tmp_rtx) != BARRIER)
+           fprintf (outf, ";; Insn is not within a basic block\n");
+         else if (in_bb_p[INSN_UID (tmp_rtx)] == IN_MULTIPLE_BB)
+           fprintf (outf, ";; Insn is in multiple basic blocks\n");
+
+         did_output = print_rtl_single (outf, tmp_rtx);
+
+         if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
+           {
+             fprintf (outf, ";; End of basic block %d, registers live:\n",
+                      bb->index);
+             dump_regset (bb->global_live_at_end, outf);
+             putc ('\n', outf);
+           }
+
+         if (did_output)
+           putc ('\n', outf);
+       }
+
+      free (start);
+      free (end);
+      free (in_bb_p);
+    }
+
+  if (current_function_epilogue_delay_list != 0)
+    {
+      fprintf (outf, "\n;; Insns in epilogue delay list:\n\n");
+      for (tmp_rtx = current_function_epilogue_delay_list; tmp_rtx != 0;
+          tmp_rtx = XEXP (tmp_rtx, 1))
+       print_rtl_single (outf, XEXP (tmp_rtx, 0));
+    }
+}
+\f
+/* Verify the CFG consistency.  This function check some CFG invariants and
+   aborts when something is wrong.  Hope that this function will help to
+   convert many optimization passes to preserve CFG consistent.
+
+   Currently it does following checks:
+
+   - test head/end pointers
+   - overlapping of basic blocks
+   - edge list correctness
+   - headers of basic blocks (the NOTE_INSN_BASIC_BLOCK note)
+   - tails of basic blocks (ensure that boundary is necesary)
+   - scans body of the basic block for JUMP_INSN, CODE_LABEL
+     and NOTE_INSN_BASIC_BLOCK
+   - check that all insns are in the basic blocks
+   (except the switch handling code, barriers and notes)
+   - check that all returns are followed by barriers
+
+   In future it can be extended check a lot of other stuff as well
+   (reachability of basic blocks, life information, etc. etc.).  */
+
+void
+verify_flow_info ()
+{
+  const int max_uid = get_max_uid ();
+  const rtx rtx_first = get_insns ();
+  rtx last_head = get_last_insn ();
+  basic_block *bb_info, *last_visited;
+  size_t *edge_checksum;
+  rtx x;
+  int i, last_bb_num_seen, num_bb_notes, err = 0;
+
+  bb_info = (basic_block *) xcalloc (max_uid, sizeof (basic_block));
+  last_visited = (basic_block *) xcalloc (n_basic_blocks + 2,
+                                         sizeof (basic_block));
+  edge_checksum = (size_t *) xcalloc (n_basic_blocks + 2, sizeof (size_t));
+
+  for (i = n_basic_blocks - 1; i >= 0; i--)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      rtx head = bb->head;
+      rtx end = bb->end;
+
+      /* Verify the end of the basic block is in the INSN chain.  */
+      for (x = last_head; x != NULL_RTX; x = PREV_INSN (x))
+       if (x == end)
+         break;
+      if (!x)
+       {
+         error ("End insn %d for block %d not found in the insn stream.",
+                INSN_UID (end), bb->index);
+         err = 1;
+       }
+
+      /* Work backwards from the end to the head of the basic block
+        to verify the head is in the RTL chain.  */
+      for (; x != NULL_RTX; x = PREV_INSN (x))
+       {
+         /* While walking over the insn chain, verify insns appear
+            in only one basic block and initialize the BB_INFO array
+            used by other passes.  */
+         if (bb_info[INSN_UID (x)] != NULL)
+           {
+             error ("Insn %d is in multiple basic blocks (%d and %d)",
+                    INSN_UID (x), bb->index, bb_info[INSN_UID (x)]->index);
+             err = 1;
+           }
+         bb_info[INSN_UID (x)] = bb;
+
+         if (x == head)
+           break;
+       }
+      if (!x)
+       {
+         error ("Head insn %d for block %d not found in the insn stream.",
+                INSN_UID (head), bb->index);
+         err = 1;
+       }
+
+      last_head = x;
+    }
+
+  /* Now check the basic blocks (boundaries etc.) */
+  for (i = n_basic_blocks - 1; i >= 0; i--)
+    {
+      basic_block bb = BASIC_BLOCK (i);
+      int has_fallthru = 0;
+      edge e;
+
+      e = bb->succ;
+      while (e)
+       {
+         if (last_visited [e->dest->index + 2] == bb)
+           {
+             error ("verify_flow_info: Duplicate edge %i->%i",
+                    e->src->index, e->dest->index);
+             err = 1;
+           }
+         last_visited [e->dest->index + 2] = bb;
+
+         if (e->flags & EDGE_FALLTHRU)
+           has_fallthru = 1;
+
+         if ((e->flags & EDGE_FALLTHRU)
+             && e->src != ENTRY_BLOCK_PTR
+             && e->dest != EXIT_BLOCK_PTR)
+           {
+             rtx insn;
+             if (e->src->index + 1 != e->dest->index)
+               {
+                   error ("verify_flow_info: Incorrect blocks for fallthru %i->%i",
+                          e->src->index, e->dest->index);
+                   err = 1;
+               }
+             else
+               for (insn = NEXT_INSN (e->src->end); insn != e->dest->head;
+                    insn = NEXT_INSN (insn))
+                 if (GET_CODE (insn) == BARRIER || INSN_P (insn))
+                   {
+                     error ("verify_flow_info: Incorrect fallthru %i->%i",
+                            e->src->index, e->dest->index);
+                     fatal_insn ("Wrong insn in the fallthru edge", insn);
+                     err = 1;
+                   }
+           }
+         if (e->src != bb)
+           {
+             error ("verify_flow_info: Basic block %d succ edge is corrupted",
+                    bb->index);
+             fprintf (stderr, "Predecessor: ");
+             dump_edge_info (stderr, e, 0);
+             fprintf (stderr, "\nSuccessor: ");
+             dump_edge_info (stderr, e, 1);
+             fprintf (stderr, "\n");
+             err = 1;
+           }
+         edge_checksum[e->dest->index + 2] += (size_t) e;
+         e = e->succ_next;
+       }
+      if (!has_fallthru)
+       {
+         rtx insn = bb->end;
+
+         /* Ensure existence of barrier in BB with no fallthru edges.  */
+         for (insn = bb->end; GET_CODE (insn) != BARRIER;
+              insn = NEXT_INSN (insn))
+           if (!insn
+               || (GET_CODE (insn) == NOTE
+                   && NOTE_LINE_NUMBER (insn) == NOTE_INSN_BASIC_BLOCK))
+               {
+                 error ("Missing barrier after block %i", bb->index);
+                 err = 1;
+               }
+       }
+
+      e = bb->pred;
+      while (e)
+       {
+         if (e->dest != bb)
+           {
+             error ("Basic block %d pred edge is corrupted", bb->index);
+             fputs ("Predecessor: ", stderr);
+             dump_edge_info (stderr, e, 0);
+             fputs ("\nSuccessor: ", stderr);
+             dump_edge_info (stderr, e, 1);
+             fputc ('\n', stderr);
+             err = 1;
+           }
+         edge_checksum[e->dest->index + 2] -= (size_t) e;
+         e = e->pred_next;
+       }
+       for (x = bb->head; x != NEXT_INSN (bb->end); x = NEXT_INSN (x))
+        if (basic_block_for_insn && BLOCK_FOR_INSN (x) != bb)
+          {
+            debug_rtx (x);
+            if (! BLOCK_FOR_INSN (x))
+              error ("Insn %d is inside basic block %d but block_for_insn is NULL",
+                     INSN_UID (x), bb->index);
+            else
+              error ("Insn %d is inside basic block %d but block_for_insn is %i",
+                     INSN_UID (x), bb->index, BLOCK_FOR_INSN (x)->index);
+            err = 1;
+          }
+
+      /* OK pointers are correct.  Now check the header of basic
+         block.  It ought to contain optional CODE_LABEL followed
+        by NOTE_BASIC_BLOCK.  */
+      x = bb->head;
+      if (GET_CODE (x) == CODE_LABEL)
+       {
+         if (bb->end == x)
+           {
+             error ("NOTE_INSN_BASIC_BLOCK is missing for block %d",
+                    bb->index);
+             err = 1;
+           }
+         x = NEXT_INSN (x);
+       }
+      if (!NOTE_INSN_BASIC_BLOCK_P (x) || NOTE_BASIC_BLOCK (x) != bb)
+       {
+         error ("NOTE_INSN_BASIC_BLOCK is missing for block %d",
+                bb->index);
+         err = 1;
+       }
+
+      if (bb->end == x)
+       {
+         /* Do checks for empty blocks here */
+       }
+      else
+       {
+         x = NEXT_INSN (x);
+         while (x)
+           {
+             if (NOTE_INSN_BASIC_BLOCK_P (x))
+               {
+                 error ("NOTE_INSN_BASIC_BLOCK %d in the middle of basic block %d",
+                        INSN_UID (x), bb->index);
+                 err = 1;
+               }
+
+             if (x == bb->end)
+               break;
+
+             if (GET_CODE (x) == JUMP_INSN
+                 || GET_CODE (x) == CODE_LABEL
+                 || GET_CODE (x) == BARRIER)
+               {
+                 error ("In basic block %d:", bb->index);
+                 fatal_insn ("Flow control insn inside a basic block", x);
+               }
+
+             x = NEXT_INSN (x);
+           }
+       }
+    }
+
+  /* Complete edge checksumming for ENTRY and EXIT.  */
+  {
+    edge e;
+    for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
+      edge_checksum[e->dest->index + 2] += (size_t) e;
+    for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
+      edge_checksum[e->dest->index + 2] -= (size_t) e;
+  }
+
+  for (i = -2; i < n_basic_blocks; ++i)
+    if (edge_checksum[i + 2])
+      {
+       error ("Basic block %i edge lists are corrupted", i);
+       err = 1;
+      }
+
+  last_bb_num_seen = -1;
+  num_bb_notes = 0;
+  x = rtx_first;
+  while (x)
+    {
+      if (NOTE_INSN_BASIC_BLOCK_P (x))
+       {
+         basic_block bb = NOTE_BASIC_BLOCK (x);
+         num_bb_notes++;
+         if (bb->index != last_bb_num_seen + 1)
+           internal_error ("Basic blocks not numbered consecutively.");
+
+         last_bb_num_seen = bb->index;
+       }
+
+      if (!bb_info[INSN_UID (x)])
+       {
+         switch (GET_CODE (x))
+           {
+           case BARRIER:
+           case NOTE:
+             break;
+
+           case CODE_LABEL:
+             /* An addr_vec is placed outside any block block.  */
+             if (NEXT_INSN (x)
+                 && GET_CODE (NEXT_INSN (x)) == JUMP_INSN
+                 && (GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_DIFF_VEC
+                     || GET_CODE (PATTERN (NEXT_INSN (x))) == ADDR_VEC))
+               {
+                 x = NEXT_INSN (x);
+               }
+
+             /* But in any case, non-deletable labels can appear anywhere.  */
+             break;
+
+           default:
+             fatal_insn ("Insn outside basic block", x);
+           }
+       }
+
+      if (INSN_P (x)
+         && GET_CODE (x) == JUMP_INSN
+         && returnjump_p (x) && ! condjump_p (x)
+         && ! (NEXT_INSN (x) && GET_CODE (NEXT_INSN (x)) == BARRIER))
+           fatal_insn ("Return not followed by barrier", x);
+
+      x = NEXT_INSN (x);
+    }
+
+  if (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)
+    internal_error ("verify_flow_info failed.");
+
+  /* Clean up.  */
+  free (bb_info);
+  free (last_visited);
+  free (edge_checksum);
+}
+\f
+/* Assume that the preceeding pass has possibly eliminated jump instructions
+   or converted the unconditional jumps.  Eliminate the edges from CFG.
+   Return true if any edges are eliminated.  */
+
+bool
+purge_dead_edges (bb)
+     basic_block bb;
+{
+  edge e, next;
+  rtx insn = bb->end;
+  bool purged = false;
+
+  if (GET_CODE (insn) == JUMP_INSN && !simplejump_p (insn))
+    return false;
+  if (GET_CODE (insn) == JUMP_INSN)
+    {
+      rtx note;
+      edge b,f;
+      /* We do care only about conditional jumps and simplejumps.  */
+      if (!any_condjump_p (insn)
+         && !returnjump_p (insn)
+         && !simplejump_p (insn))
+       return false;
+      for (e = bb->succ; e; e = next)
+       {
+         next = e->succ_next;
+
+         /* Check purposes we can have edge.  */
+         if ((e->flags & EDGE_FALLTHRU)
+             && any_condjump_p (insn))
+           continue;
+         if (e->dest != EXIT_BLOCK_PTR
+             && e->dest->head == JUMP_LABEL (insn))
+           continue;
+         if (e->dest == EXIT_BLOCK_PTR
+             && returnjump_p (insn))
+           continue;
+         purged = true;
+         remove_edge (e);
+       }
+      if (!bb->succ || !purged)
+       return false;
+      if (rtl_dump_file)
+       fprintf (rtl_dump_file, "Purged edges from bb %i\n", bb->index);
+      if (!optimize)
+       return purged;
+
+      /* Redistribute probabilities.  */
+      if (!bb->succ->succ_next)
+       {
+         bb->succ->probability = REG_BR_PROB_BASE;
+         bb->succ->count = bb->count;
+        }
+      else
+       {
+         note = find_reg_note (insn, REG_BR_PROB, NULL);
+         if (!note)
+           return purged;
+         b = BRANCH_EDGE (bb);
+         f = FALLTHRU_EDGE (bb);
+         b->probability = INTVAL (XEXP (note, 0));
+         f->probability = REG_BR_PROB_BASE - b->probability;
+         b->count = bb->count * b->probability / REG_BR_PROB_BASE;
+         f->count = bb->count * f->probability / REG_BR_PROB_BASE;
+       }
+      return purged;
+    }
+
+  /* Cleanup abnormal edges caused by throwing insns that have been
+     eliminated.  */
+  if (! can_throw_internal (bb->end))
+    for (e = bb->succ; e; e = next)
+      {
+       next = e->succ_next;
+       if (e->flags & EDGE_EH)
+         {
+           remove_edge (e);
+           purged = true;
+         }
+      }
+
+  /* If we don't see a jump insn, we don't know exactly why the block would
+     have been broken at this point.  Look for a simple, non-fallthru edge,
+     as these are only created by conditional branches.  If we find such an
+     edge we know that there used to be a jump here and can then safely
+     remove all non-fallthru edges.  */
+  for (e = bb->succ; e && (e->flags & (EDGE_COMPLEX | EDGE_FALLTHRU));
+       e = e->succ_next);
+  if (!e)
+    return purged;
+  for (e = bb->succ; e; e = next)
+    {
+      next = e->succ_next;
+      if (!(e->flags & EDGE_FALLTHRU))
+       remove_edge (e), purged = true;
+    }
+  if (!bb->succ || bb->succ->succ_next)
+    abort ();
+  bb->succ->probability = REG_BR_PROB_BASE;
+  bb->succ->count = bb->count;
+
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Purged non-fallthru edges from bb %i\n",
+            bb->index);
+  return purged;
+}
+
+/* Search all basic blocks for potentionally dead edges and purge them.
+
+   Return true ifif some edge has been elliminated.
+ */
+
+bool
+purge_all_dead_edges ()
+{
+  int i, purged = false;
+  for (i = 0; i < n_basic_blocks; i++)
+    purged |= purge_dead_edges (BASIC_BLOCK (i));
+  return purged;
+}
index 1c449d69f1b4ef355dcef8073d71575f3bcefa4f..f33df26338297272c42dfed5b200cbbaba12de86 100644 (file)
@@ -3528,7 +3528,7 @@ emit_insns_after (first, after)
     abort ();
 
   if (!first)
-    return first;
+    return after;
 
   if (basic_block_for_insn
       && (unsigned int)INSN_UID (after) < basic_block_for_insn->num_elements
index ec29a45952d77b3dd462d7deb7e68b9a3847f94d..dd8266af25696b55ae00f025fb2132a6901213a7 100644 (file)
@@ -1972,8 +1972,7 @@ final (first, file, optimize, prescan)
                     && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
                     && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
              {
-               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (insn) = 0;
+               delete_note (insn);
                continue;
              }
            last = insn;
@@ -2719,9 +2718,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
               (It would not be recognized.)  */
            if (SET_SRC (body) == pc_rtx)
              {
-               PUT_CODE (insn, NOTE);
-               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (insn) = 0;
+               delete_insn (insn);
                break;
              }
            else if (GET_CODE (SET_SRC (body)) == RETURN)
@@ -2780,11 +2777,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                  else if (result == 2)
                    INSN_CODE (insn) = -1;
                  if (SET_DEST (set) == SET_SRC (set))
-                   {
-                     PUT_CODE (insn, NOTE);
-                     NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (insn) = 0;
-                   }
+                   delete_insn (insn);
                }
                break;
 
@@ -2902,10 +2895,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                 prev = PREV_INSN (prev))
              {
                if (GET_CODE (prev) == NOTE)
-                 {
-                   NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
-                   NOTE_SOURCE_FILE (prev) = 0;
-                 }
+                 delete_insn (prev);   /* Use delete_note.  */
              }
 
            return prev;
index 46c0b8f832ec5f905e9bc851cebe4bc1d85d1671..c6fa510ef4059c501035bd22aae9a138c0f5c283 100644 (file)
@@ -1719,11 +1719,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
                     find_reg_note (XEXP (note, 0), REG_RETVAL,
                                    NULL_RTX));
 
-      /* In unoptimized compilation, we shouldn't call delete_insn
-        except in jump.c doing warnings.  */
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
+      delete_insn (insn);
     }
 
   /* The insn to load VAR from a home in the arglist
@@ -1744,11 +1740,7 @@ fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, toplevel)
                   && SET_DEST (prev_set) == SET_SRC (set)
                   && rtx_equal_p (SET_SRC (prev_set), var))))
     {
-      /* In unoptimized compilation, we shouldn't call delete_insn
-        except in jump.c doing warnings.  */
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
+      delete_insn (insn);
     }
   else
     {
@@ -2360,9 +2352,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  REG_NOTES (insn) = REG_NOTES (last);
                PATTERN (insn) = PATTERN (last);
 
-               PUT_CODE (last, NOTE);
-               NOTE_LINE_NUMBER (last) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (last) = 0;
+               delete_insn (last);
              }
            else
              PATTERN (insn) = pat;
@@ -2405,9 +2395,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                  REG_NOTES (insn) = REG_NOTES (last);
                PATTERN (insn) = PATTERN (last);
 
-               PUT_CODE (last, NOTE);
-               NOTE_LINE_NUMBER (last) = NOTE_INSN_DELETED;
-               NOTE_SOURCE_FILE (last) = 0;
+               delete_insn (last);
              }
            else
              PATTERN (insn) = pat;
@@ -7154,9 +7142,7 @@ keep_stack_depressed (seq)
            sp_modified_unknown = 1;
 
          /* Don't allow the SP modification to happen.  */
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-         NOTE_SOURCE_FILE (insn) = 0;
+         delete_insn (insn);
        }
       else if (reg_referenced_p (stack_pointer_rtx, PATTERN (insn)))
        {
index 6cc915f650bddee4fa70732643357c98a2e4a810..e5b6e4aef7ef1e0ca9c1bf7081b4011559cc4738 100644 (file)
@@ -4102,9 +4102,7 @@ cprop_cc0_jump (bb, insn, reg_used, src)
     return 0;
 
   /* If we succeeded, delete the cc0 setter.  */
-  PUT_CODE (insn, NOTE);
-  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (insn) = 0;
+  delete_insn (insn);
 
   return 1;
  }
index 1df88db3340461146bbfe2391e305b3265ff2255..e0e8d812e653132f404a18d41d9842a894047ea9 100644 (file)
@@ -1107,9 +1107,7 @@ update_equiv_regs ()
                      remove_death (regno, insn);
                      REG_N_REFS (regno) = 0;
                      REG_FREQ (regno) = 0;
-                     PUT_CODE (equiv_insn, NOTE);
-                     NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (equiv_insn) = 0;
+                     delete_insn (equiv_insn);
                      
                      reg_equiv[regno].init_insns
                        = XEXP (reg_equiv[regno].init_insns, 1);
@@ -1128,9 +1126,7 @@ update_equiv_regs ()
                         otherwise eliminate_regs_in_insn will abort.  */
                      INSN_CODE (new_insn) = INSN_CODE (equiv_insn);
 
-                     PUT_CODE (equiv_insn, NOTE);
-                     NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (equiv_insn) = 0;
+                     delete_insn (equiv_insn);
 
                      XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
 
index d27e05880393f23c2e43f845288825f5796ab306..601828a666d19e5cdb9378e23c585ed6ee91de92 100644 (file)
@@ -807,9 +807,7 @@ scan_loop (loop, flags)
                    = replace_rtx (REG_NOTES (regs->array[regno].single_usage),
                                   SET_DEST (set), copy_rtx (SET_SRC (set)));
 
-                 PUT_CODE (p, NOTE);
-                 NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (p) = 0;
+                 delete_insn (p);
                  regs->array[regno].set_in_loop = 0;
                  continue;
                }
@@ -9340,11 +9338,10 @@ loop_delete_insns (first, last)
 {
   while (1)
     {
-      PUT_CODE (first, NOTE);
-      NOTE_LINE_NUMBER (first) = NOTE_INSN_DELETED;
       if (loop_dump_stream)
        fprintf (loop_dump_stream, ", deleting init_insn (%d)",
                 INSN_UID (first));
+      delete_insn (first);
 
       /* If this was the LAST instructions we're supposed to delete,
         we're done.  */
index 42d7795a01eb7cff653d8316db3888891fceea3e..e15df721cd78074d412db0f9b91ab0af6fdd5822 100644 (file)
@@ -832,9 +832,6 @@ static void
 estimate_bb_frequencies (loops)
      struct loops *loops;
 {
-  block_info bi;
-  edge_info ei;
-  int edgenum = 0;
   int i;
   double freq_max = 0;
 
@@ -891,8 +888,8 @@ estimate_bb_frequencies (loops)
   ENTRY_BLOCK_PTR->succ->probability = REG_BR_PROB_BASE;
 
   /* Set up block info for each basic block.  */
-  bi = (block_info) xcalloc ((n_basic_blocks + 2), sizeof (*bi));
-  ei = (edge_info) xcalloc ((n_edges), sizeof (*ei));
+  alloc_aux_for_blocks (sizeof (struct block_info_def));
+  alloc_aux_for_edges (sizeof (struct edge_info_def));
   for (i = -2; i < n_basic_blocks; i++)
     {
       edge e;
@@ -904,14 +901,10 @@ estimate_bb_frequencies (loops)
        bb = EXIT_BLOCK_PTR;
       else
        bb = BASIC_BLOCK (i);
-      bb->aux = bi + i + 2;
       BLOCK_INFO (bb)->tovisit = 0;
       for (e = bb->succ; e; e = e->succ_next)
-       {
-         e->aux = ei + edgenum, edgenum++;
-         EDGE_INFO (e)->back_edge_prob = ((double) e->probability
-                                          / REG_BR_PROB_BASE);
-       }
+       EDGE_INFO (e)->back_edge_prob = ((double) e->probability
+                                        / REG_BR_PROB_BASE);
     }
   /* First compute probabilities locally for each loop from innermost
      to outermost to examine probabilities for back edges.  */
@@ -940,6 +933,6 @@ estimate_bb_frequencies (loops)
                       + 0.5);
     }
 
-  free (ei);
-  free (bi);
+  free_aux_for_blocks ();
+  free_aux_for_edges ();
 }
index 644a9b45599dfc1c7ca401977762724c7fb2c0c2..44cd15d063eb9670f8219bfce9cbedde4a71e5cd 100644 (file)
@@ -217,18 +217,15 @@ compute_branch_probabilities ()
   int hist_br_prob[20];
   int num_never_executed;
   int num_branches;
-  struct bb_info *bb_infos;
 
   /* Attach extra info block to each bb.  */
 
-  bb_infos = (struct bb_info *)
-    xcalloc (n_basic_blocks + 2, sizeof (struct bb_info));
+  alloc_aux_for_blocks (sizeof (struct bb_info));
   for (i = 0; i < n_basic_blocks + 2; i++)
     {
       basic_block bb = GCOV_INDEX_TO_BB (i);
       edge e;
 
-      bb->aux = &bb_infos[i];
       for (e = bb->succ; e; e = e->succ_next)
        if (!EDGE_INFO (e)->ignore)
          BB_INFO (bb)->succ_count++;
@@ -496,7 +493,7 @@ compute_branch_probabilities ()
       fputc ('\n', rtl_dump_file);
     }
 
-  free (bb_infos);
+  free_aux_for_blocks ();
 }
 
 /* Instrument and/or analyze program behavior based on program flow graph.
@@ -520,7 +517,6 @@ branch_prob ()
 {
   int i;
   int num_edges, ignored_edges;
-  struct edge_info *edge_infos;
   struct edge_list *el;
 
   /* Start of a function.  */
@@ -612,15 +608,13 @@ branch_prob ()
 
   el = create_edge_list ();
   num_edges = NUM_EDGES (el);
-  edge_infos = (struct edge_info *)
-    xcalloc (num_edges, sizeof (struct edge_info));
+  alloc_aux_for_edges (sizeof (struct edge_info));
 
   ignored_edges = 0;
   for (i = 0 ; i < num_edges ; i++)
     {
       edge e = INDEX_EDGE (el, i);
       e->count = 0;
-      e->aux = &edge_infos[i];
 
       /* Mark edges we've replaced by fake edges above as ignored.  */
       if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
@@ -803,7 +797,7 @@ branch_prob ()
   if (rtl_dump_file)
     dump_flow_info (rtl_dump_file);
 
-  free (edge_infos);
+  free_aux_for_edges ();
   free_edge_list (el);
 }
 \f
@@ -904,6 +898,11 @@ find_spanning_tree (el)
          union_groups (e->src, e->dest);
        }
     }
+
+  EXIT_BLOCK_PTR->aux = NULL;
+  ENTRY_BLOCK_PTR->aux = NULL;
+  for (i = 0; i < n_basic_blocks; i++)
+    BASIC_BLOCK (i)->aux = NULL;
 }
 \f
 /* Perform file-level initialization for branch-prob processing.  */
index c247048b4d63658dfec74ab87d8695197b3e7129..2b39b71d7bcf0de30336fce3f187719f1035a38a 100644 (file)
@@ -420,7 +420,6 @@ reg_to_stack (first, file)
 {
   int i;
   int max_uid;
-  block_info bi;
 
   /* Clean up previous run.  */
   if (stack_regs_mentioned_data)
@@ -449,18 +448,16 @@ reg_to_stack (first, file)
   mark_dfs_back_edges ();
 
   /* Set up block info for each basic block.  */
-  bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
+  alloc_aux_for_blocks (sizeof (struct block_info_def));
   for (i = n_basic_blocks - 1; i >= 0; --i)
     {
       edge e;
       basic_block bb = BASIC_BLOCK (i);
-      bb->aux = bi + i;
       for (e = bb->pred; e; e=e->pred_next)
        if (!(e->flags & EDGE_DFS_BACK)
            && e->src != ENTRY_BLOCK_PTR)
          BLOCK_INFO (bb)->predecesors++;
     }
-  EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
 
   /* Create the replacement registers up front.  */
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
@@ -500,7 +497,7 @@ reg_to_stack (first, file)
 
   convert_regs (file);
 
-  free (bi);
+  free_aux_for_blocks ();
 }
 \f
 /* Check PAT, which is in INSN, for LABEL_REFs.  Add INSN to the
index 48f97640832aefd5d30286f02dbdab2ebd3f9563..8e2f315611f52c143dbab079083987cc5046df49 100644 (file)
@@ -148,11 +148,7 @@ try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
                    = gen_rtx_EXPR_LIST (REG_INC,
                                         reg, REG_NOTES (insn));
                  if (! inc_insn_set)
-                   {
-                     PUT_CODE (inc_insn, NOTE);
-                     NOTE_LINE_NUMBER (inc_insn) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (inc_insn) = 0;
-                   }
+                   delete_insn (inc_insn);
                  return 1;
                }
            }
@@ -1895,9 +1891,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
          rtx notes = REG_NOTES (insn);
 
          emit_insn_after_with_line_notes (pat, PREV_INSN (p), insn);
-         PUT_CODE (insn, NOTE);
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-         NOTE_SOURCE_FILE (insn) = 0;
+         delete_insn (insn);
          /* emit_insn_after_with_line_notes has no
             return value, so search for the new insn.  */
          insn = p;
@@ -1949,9 +1943,7 @@ fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
          if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2))
              && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
            {
-             PUT_CODE (q, NOTE);
-             NOTE_LINE_NUMBER (q) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (q) = 0;
+             delete_insn (q);
              REG_N_SETS (REGNO (src))--;
              REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
              REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
index 9ba07355a8b917ea2a6cae1b6a8a61139d604a1a..820843257a28dc07caa02b6f4a838a45bfec24ee 100644 (file)
@@ -1263,7 +1263,6 @@ reload (first, global)
   /* Free all the insn_chain structures at once.  */
   obstack_free (&reload_obstack, reload_startobj);
   unused_insn_chains = 0;
-  compute_bb_for_insn (get_max_uid ());
   fixup_abnormal_edges ();
 
   return failure;
@@ -1465,9 +1464,7 @@ calculate_needs_all_insns (global)
                  && GET_CODE (SET_SRC (set)) == REG
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
                {
-                 PUT_CODE (insn, NOTE);
-                 NOTE_SOURCE_FILE (insn) = 0;
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+                 delete_insn (insn);
                  /* Delete it from the reload chain */
                  if (chain->prev)
                    chain->prev->next = next;
@@ -1851,17 +1848,9 @@ delete_caller_save_insns ()
          struct insn_chain *next = c->next;
          rtx insn = c->insn;
 
-         if (insn == BLOCK_HEAD (c->block))
-           BLOCK_HEAD (c->block) = NEXT_INSN (insn);
-         if (insn == BLOCK_END (c->block))
-           BLOCK_END (c->block) = PREV_INSN (insn);
          if (c == reload_insn_chain)
            reload_insn_chain = next;
-
-         if (NEXT_INSN (insn) != 0)
-           PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
-         if (PREV_INSN (insn) != 0)
-           NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+         delete_insn (insn);
 
          if (next)
            next->prev = c->prev;
@@ -3908,9 +3897,7 @@ reload_as_needed (live_known)
                    {
                      error_for_asm (insn,
                                     "`asm' operand requires impossible reload");
-                     PUT_CODE (p, NOTE);
-                     NOTE_SOURCE_FILE (p) = 0;
-                     NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
+                     delete_insn (p);
                    }
            }
 
@@ -6941,8 +6928,6 @@ emit_reload_insns (chain)
   rtx insn = chain->insn;
 
   register int j;
-  rtx following_insn = NEXT_INSN (insn);
-  rtx before_insn = PREV_INSN (insn);
 
   CLEAR_HARD_REG_SET (reg_reloaded_died);
 
@@ -7018,19 +7003,10 @@ emit_reload_insns (chain)
 
   for (j = 0; j < reload_n_operands; j++)
     {
-      emit_insns_before (outaddr_address_reload_insns[j], following_insn);
-      emit_insns_before (output_address_reload_insns[j], following_insn);
-      emit_insns_before (output_reload_insns[j], following_insn);
-      emit_insns_before (other_output_reload_insns[j], following_insn);
-    }
-
-  /* Keep basic block info up to date.  */
-  if (n_basic_blocks)
-    {
-      if (BLOCK_HEAD (chain->block) == insn)
-       BLOCK_HEAD (chain->block) = NEXT_INSN (before_insn);
-      if (BLOCK_END (chain->block) == insn)
-       BLOCK_END (chain->block) = PREV_INSN (following_insn);
+      rtx x = emit_insns_after (outaddr_address_reload_insns[j], insn);
+      x = emit_insns_after (output_address_reload_insns[j], x);
+      x = emit_insns_after (output_reload_insns[j], x);
+      emit_insns_after (other_output_reload_insns[j], x);
     }
 
   /* For all the spill regs newly reloaded in this instruction,
@@ -7669,9 +7645,7 @@ delete_output_reload (insn, j, last_reload_reg)
              /* Some other ref remains; just delete the output reload we
                 know to be dead.  */
              delete_address_reloads (output_reload_insn, insn);
-             PUT_CODE (output_reload_insn, NOTE);
-             NOTE_SOURCE_FILE (output_reload_insn) = 0;
-             NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
+             delete_insn (output_reload_insn);
              return;
            }
        }
@@ -7686,9 +7660,7 @@ delete_output_reload (insn, j, last_reload_reg)
              delete_address_reloads (i2, insn);
              /* This might be a basic block head,
                 thus don't use delete_insn.  */
-             PUT_CODE (i2, NOTE);
-             NOTE_SOURCE_FILE (i2) = 0;
-             NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+             delete_insn (i2);
            }
          if (GET_CODE (i2) == CODE_LABEL
              || GET_CODE (i2) == JUMP_INSN)
@@ -7701,9 +7673,7 @@ delete_output_reload (insn, j, last_reload_reg)
       alter_reg (REGNO (reg), -1);
     }
   delete_address_reloads (output_reload_insn, insn);
-  PUT_CODE (output_reload_insn, NOTE);
-  NOTE_SOURCE_FILE (output_reload_insn) = 0;
-  NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
+  delete_insn (output_reload_insn);
 
 }
 
@@ -7852,10 +7822,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
     }
   delete_address_reloads_1 (prev, SET_SRC (set), current_insn);
   reg_reloaded_contents[REGNO (dst)] = -1;
-  /* Can't use delete_insn here because PREV might be a basic block head.  */
-  PUT_CODE (prev, NOTE);
-  NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (prev) = 0;
+  delete_insn (prev);
 }
 \f
 /* Output reload-insns to reload VALUE into RELOADREG.
@@ -8026,11 +7993,7 @@ reload_cse_delete_noop_set (insn, value)
       REG_NOTES (insn) = NULL_RTX;
     }
   else
-    {
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
-    }
+    delete_insn (insn);
 }
 
 /* See whether a single set SET is a noop.  */
@@ -8782,9 +8745,7 @@ reload_combine ()
                  rtx *np;
 
                  /* Delete the reg-reg addition.  */
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
+                 delete_insn (insn);
 
                  if (reg_state[regno].offset != const0_rtx)
                    /* Previous REG_EQUIV / REG_EQUAL notes for PREV
@@ -9226,14 +9187,7 @@ reload_cse_move2add (first)
                          = validate_change (next, &PATTERN (next),
                                             gen_add2_insn (reg, new_src), 0);
                      if (success)
-                       {
-                         /* INSN might be the first insn in a basic block
-                            if the preceding insn is a conditional jump
-                            or a possible-throwing call.  */
-                         PUT_CODE (insn, NOTE);
-                         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                         NOTE_SOURCE_FILE (insn) = 0;
-                       }
+                       delete_insn (insn);
                      insn = next;
                      reg_mode[regno] = GET_MODE (reg);
                      reg_offset[regno] = sext_for_mode (GET_MODE (reg),
index 3b9526c13df8028fec8b3fba150fd91ec6cfb8a6..4e979cd6b38427e1df41ac66d49b545652247ec5 100644 (file)
@@ -555,9 +555,7 @@ replace_call_placeholder (insn, use)
     LABEL_PRESERVE_P (XEXP (PATTERN (insn), 3)) = 0;
   
   /* "Delete" the placeholder insn.  */
-  PUT_CODE (insn, NOTE);
-  NOTE_SOURCE_FILE (insn) = 0;
-  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+  remove_insn (insn);
 }
 
 /* Given a (possibly empty) set of potential sibling or tail recursion call
index f3f565681d8a6fd2409d987cafdd4d65d6b7a4c2..c0fe373fdfbccc5f2ca98d61938b008e99bea6aa 100644 (file)
@@ -2154,14 +2154,7 @@ copy_loop_body (loop, copy_start, copy_end, map, exit_label, last_iteration,
              /* If this is now a no-op, delete it.  */
              if (map->last_pc_value == pc_rtx)
                {
-                 /* Don't let delete_insn delete the label referenced here,
-                    because we might possibly need it later for some other
-                    instruction in the loop.  */
-                 if (JUMP_LABEL (copy))
-                   LABEL_NUSES (JUMP_LABEL (copy))++;
-                 delete_related_insns (copy);
-                 if (JUMP_LABEL (copy))
-                   LABEL_NUSES (JUMP_LABEL (copy))--;
+                 delete_insn (copy);
                  copy = 0;
                }
              else