OSDN Git Service

* flow.c (calculate_global_regs_live): Skip for_each_successor_phi
[pf3gnuchains/gcc-fork.git] / gcc / flow.c
index c6efbd7..f0cee82 100644 (file)
@@ -1,5 +1,6 @@
 /* Data flow analysis for GNU compiler.
-   Copyright (C) 1987, 88, 92-99, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -134,8 +135,10 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "recog.h"
 #include "insn-flags.h"
+#include "expr.h"
 
 #include "obstack.h"
+#include "splay-tree.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
@@ -152,10 +155,12 @@ Boston, MA 02111-1307, USA.  */
 #ifndef HAVE_epilogue
 #define HAVE_epilogue 0
 #endif
-
 #ifndef HAVE_prologue
 #define HAVE_prologue 0
 #endif
+#ifndef HAVE_sibcall_epilogue
+#define HAVE_sibcall_epilogue 0
+#endif
 
 /* The contents of the current function definition are allocated
    in this obstack, and all are freed at the end of the function.
@@ -217,16 +222,6 @@ int max_regno;
 
 varray_type reg_n_info;
 
-/* Size of the reg_n_info table.  */
-
-unsigned int reg_n_max;
-
-/* Element N is the next insn that uses (hard or pseudo) register number N
-   within the current basic block; or zero, if there is no such insn.
-   This is valid only during the final backward scan in propagate_block.  */
-
-static rtx *reg_next_use;
-
 /* Size of a regset for the current function,
    in (1) bytes and (2) elements.  */
 
@@ -244,20 +239,6 @@ regset regs_live_at_setjmp;
    are another pair, etc.  */
 rtx regs_may_share;
 
-/* Depth within loops of basic block being scanned for lifetime analysis,
-   plus one.  This is the weight attached to references to registers.  */
-
-static int loop_depth;
-
-/* During propagate_block, this is non-zero if the value of CC0 is live.  */
-
-static int cc0_live;
-
-/* During propagate_block, this contains a list of all the MEMs we are
-   tracking for dead store elimination.  */
-
-static rtx mem_set_list;
-
 /* Set of registers that may be eliminable.  These are handled specially
    in updating regs_ever_live.  */
 
@@ -273,16 +254,60 @@ varray_type basic_block_for_insn;
 
 static rtx label_value_list;
 
-/* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile.  */
+/* Holds information for tracking conditional register life information.  */
+struct reg_cond_life_info
+{
+  /* An EXPR_LIST of conditions under which a register is dead.  */
+  rtx condition;
+
+  /* ??? Could store mask of bytes that are dead, so that we could finally
+     track lifetimes of multi-word registers accessed via subregs.  */
+};
+
+/* For use in communicating between propagate_block and its subroutines.
+   Holds all information needed to compute life and def-use information.  */
 
-#define INSN_VOLATILE(INSN) bitmap_bit_p (uid_volatile, INSN_UID (INSN))
-#define SET_INSN_VOLATILE(INSN) bitmap_set_bit (uid_volatile, INSN_UID (INSN))
-static bitmap uid_volatile;
+struct propagate_block_info
+{
+  /* The basic block we're considering.  */
+  basic_block bb;
+
+  /* Bit N is set if register N is conditionally or unconditionally live.  */
+  regset reg_live;
+
+  /* Bit N is set if register N is set this insn.  */
+  regset new_set;
+
+  /* Element N is the next insn that uses (hard or pseudo) register N
+     within the current basic block; or zero, if there is no such insn.  */
+  rtx *reg_next_use;
+
+  /* Contains a list of all the MEMs we are tracking for dead store
+     elimination.  */
+  rtx mem_set_list;
+
+  /* If non-null, record the set of registers set in the basic block.  */
+  regset local_set;
+
+#ifdef HAVE_conditional_execution
+  /* Indexed by register number, holds a reg_cond_life_info for each
+     register that is not unconditionally live or dead.  */
+  splay_tree reg_cond_dead;
+
+  /* Bit N is set if register N is in an expression in reg_cond_dead.  */
+  regset reg_cond_reg;
+#endif
+
+  /* Non-zero if the value of CC0 is live.  */
+  int cc0_live;
+
+  /* Flags controling the set of information propagate_block collects.  */
+  int flags;
+};
 
 /* Forward declarations */
 static int count_basic_blocks          PARAMS ((rtx));
 static rtx find_basic_blocks_1         PARAMS ((rtx));
-static void create_basic_block         PARAMS ((int, rtx, rtx, rtx));
 static void clear_edges                        PARAMS ((void));
 static void make_edges                 PARAMS ((rtx));
 static void make_label_edge            PARAMS ((sbitmap *, basic_block,
@@ -298,51 +323,66 @@ static void commit_one_edge_insertion     PARAMS ((edge));
 static void delete_unreachable_blocks  PARAMS ((void));
 static void delete_eh_regions          PARAMS ((void));
 static int can_delete_note_p           PARAMS ((rtx));
-static int delete_block                        PARAMS ((basic_block));
 static void expunge_block              PARAMS ((basic_block));
 static int can_delete_label_p          PARAMS ((rtx));
 static int merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
                                                          basic_block));
 static int merge_blocks_move_successor_nojumps PARAMS ((basic_block,
                                                        basic_block));
-static void merge_blocks_nomove                PARAMS ((basic_block, basic_block));
 static int merge_blocks                        PARAMS ((edge,basic_block,basic_block));
 static void try_merge_blocks           PARAMS ((void));
-static void tidy_fallthru_edge         PARAMS ((edge,basic_block,basic_block));
 static void tidy_fallthru_edges                PARAMS ((void));
 static int verify_wide_reg_1           PARAMS ((rtx *, void *));
 static void verify_wide_reg            PARAMS ((int, rtx, rtx));
 static void verify_local_live_at_start PARAMS ((regset, basic_block));
 static int set_noop_p                  PARAMS ((rtx));
 static int noop_move_p                 PARAMS ((rtx));
-static void notice_stack_pointer_modification PARAMS ((rtx, rtx, void *));
-static void record_volatile_insns      PARAMS ((rtx));
+static void delete_noop_moves          PARAMS ((rtx));
+static void notice_stack_pointer_modification_1 PARAMS ((rtx, rtx, void *));
+static void notice_stack_pointer_modification PARAMS ((rtx));
 static void mark_reg                   PARAMS ((rtx, void *));
 static void mark_regs_live_at_end      PARAMS ((regset));
-static void life_analysis_1            PARAMS ((rtx, int, int));
+static int set_phi_alternative_reg      PARAMS ((rtx, int, int, void *));
 static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
-static void propagate_block            PARAMS ((basic_block, regset,
-                                                regset, int));
-static int insn_dead_p                 PARAMS ((rtx, regset, int, rtx));
-static int libcall_dead_p              PARAMS ((rtx, regset, rtx, rtx));
-static void mark_set_regs              PARAMS ((regset, regset, rtx,
-                                                rtx, regset, int));
-static void mark_set_1                 PARAMS ((regset, regset, rtx,
-                                                rtx, regset, int));
+static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
+static rtx propagate_block_delete_libcall PARAMS ((basic_block, rtx, rtx));
+static int insn_dead_p                 PARAMS ((struct propagate_block_info *,
+                                                rtx, int, rtx));
+static int libcall_dead_p              PARAMS ((struct propagate_block_info *,
+                                                rtx, rtx, rtx));
+static void mark_set_regs              PARAMS ((struct propagate_block_info *,
+                                                rtx, rtx));
+static void mark_set_1                 PARAMS ((struct propagate_block_info *,
+                                                enum rtx_code, rtx, rtx,
+                                                rtx, int));
+#ifdef HAVE_conditional_execution
+static int mark_regno_cond_dead                PARAMS ((struct propagate_block_info *,
+                                                int, rtx));
+static void free_reg_cond_life_info    PARAMS ((splay_tree_value));
+static int flush_reg_cond_reg_1                PARAMS ((splay_tree_node, void *));
+static void flush_reg_cond_reg         PARAMS ((struct propagate_block_info *,
+                                                int));
+static rtx ior_reg_cond                        PARAMS ((rtx, rtx));
+static rtx not_reg_cond                        PARAMS ((rtx));
+static rtx nand_reg_cond               PARAMS ((rtx, rtx));
+#endif
 #ifdef AUTO_INC_DEC
-static void find_auto_inc              PARAMS ((regset, rtx, rtx));
-static int try_pre_increment_1         PARAMS ((rtx));
+static void find_auto_inc              PARAMS ((struct propagate_block_info *,
+                                                rtx, rtx));
+static int try_pre_increment_1         PARAMS ((struct propagate_block_info *,
+                                                rtx));
 static int try_pre_increment           PARAMS ((rtx, rtx, HOST_WIDE_INT));
 #endif
-static void mark_used_regs             PARAMS ((regset, regset, rtx, int, rtx));
+static void mark_used_reg              PARAMS ((struct propagate_block_info *,
+                                                rtx, rtx, rtx));
+static void mark_used_regs             PARAMS ((struct propagate_block_info *,
+                                                rtx, rtx, rtx));
 void dump_flow_info                    PARAMS ((FILE *));
 void debug_flow_info                   PARAMS ((void));
 static void dump_edge_info             PARAMS ((FILE *, edge, int));
 
-static void count_reg_sets_1           PARAMS ((rtx));
-static void count_reg_sets             PARAMS ((rtx));
-static void count_reg_references       PARAMS ((rtx));
-static void invalidate_mems_from_autoinc PARAMS ((rtx));
+static void invalidate_mems_from_autoinc PARAMS ((struct propagate_block_info *,
+                                                 rtx));
 static void remove_fake_successors     PARAMS ((basic_block));
 static void flow_nodes_print   PARAMS ((const char *, const sbitmap, FILE *));
 static void flow_exits_print PARAMS ((const char *, const edge *, int, FILE *));
@@ -356,12 +396,6 @@ static void flow_loop_tree_node_add        PARAMS ((struct loop *, struct loop *));
 static void flow_loops_tree_build      PARAMS ((struct loops *));
 static int flow_loop_level_compute     PARAMS ((struct loop *, int));
 static int flow_loops_level_compute    PARAMS ((struct loops *));
-
-/* 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
-   it being unused. */
-void verify_flow_info                  PARAMS ((void));
-int flow_loop_outside_edge_p           PARAMS ((const struct loop *, edge));
 \f
 /* Find basic blocks of the current function.
    F is the first insn of the function and NREGS the number of register
@@ -445,7 +479,6 @@ count_basic_blocks (f)
   register int count = 0;
   int eh_region = 0;
   int call_had_abnormal_edge = 0;
-  rtx prev_call = NULL_RTX;
 
   prev_code = JUMP_INSN;
   for (insn = f; insn; insn = NEXT_INSN (insn))
@@ -457,32 +490,26 @@ count_basic_blocks (f)
              && (prev_code == JUMP_INSN
                  || prev_code == BARRIER
                  || (prev_code == CALL_INSN && call_had_abnormal_edge))))
-       {
-         count++;
-       }
+       count++;
 
       /* Record whether this call created an edge.  */
       if (code == CALL_INSN)
        {
          rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-         int region = (note ? XWINT (XEXP (note, 0), 0) : 1);
-         prev_call = insn;
+         int region = (note ? INTVAL (XEXP (note, 0)) : 1);
+
          call_had_abnormal_edge = 0;
 
-         /* If there is a specified EH region, we have an edge.  */
-         if (eh_region && region > 0)
+         /* If there is an EH region or rethrow, we have an edge.  */
+         if ((eh_region && region > 0)
+             || find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
+           call_had_abnormal_edge = 1;
+         else if (nonlocal_goto_handler_labels && region >= 0)
+           /* If there is a nonlocal goto label and the specified
+              region number isn't -1, we have an edge. (0 means
+              no throw, but might have a nonlocal goto).  */
            call_had_abnormal_edge = 1;
-         else
-           {
-             /* If there is a nonlocal goto label and the specified
-                region number isn't -1, we have an edge. (0 means
-                no throw, but might have a nonlocal goto).  */
-             if (nonlocal_goto_handler_labels && region >= 0)
-               call_had_abnormal_edge = 1;
-           }
        }
-      else if (code != NOTE)
-       prev_call = NULL_RTX;
 
       if (code != NOTE)
        prev_code = code;
@@ -490,7 +517,6 @@ count_basic_blocks (f)
        ++eh_region;
       else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
        --eh_region;
-
     }
 
   /* The rest of the compiler works a bit smoother when we don't have to
@@ -514,7 +540,6 @@ find_basic_blocks_1 (f)
      rtx f;
 {
   register rtx insn, next;
-  int call_has_abnormal_edge = 0;
   int i = 0;
   rtx bb_note = NULL_RTX;
   rtx eh_list = NULL_RTX;
@@ -534,26 +559,6 @@ find_basic_blocks_1 (f)
 
       next = NEXT_INSN (insn);
 
-      if (code == CALL_INSN)
-       {
-         /* Record whether this call created an edge.  */
-         rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-         int region = (note ? XWINT (XEXP (note, 0), 0) : 1);
-         call_has_abnormal_edge = 0;
-
-         /* If there is an EH region, we have an edge.  */
-         if (eh_list && region > 0)
-           call_has_abnormal_edge = 1;
-         else
-           {
-             /* If there is a nonlocal goto label and the specified
-                region number isn't -1, we have an edge. (0 means
-                no throw, but might have a nonlocal goto).  */
-             if (nonlocal_goto_handler_labels && region >= 0)
-               call_has_abnormal_edge = 1;
-           }
-       }
-
       switch (code)
        {
        case NOTE:
@@ -566,6 +571,7 @@ find_basic_blocks_1 (f)
            else if (kind == NOTE_INSN_EH_REGION_END)
              {
                rtx t = eh_list;
+
                eh_list = XEXP (eh_list, 1);
                free_INSN_LIST_node (t);
              }
@@ -578,9 +584,9 @@ find_basic_blocks_1 (f)
              {
                if (bb_note == NULL_RTX)
                  bb_note = insn;
+
                next = flow_delete_insn (insn);
              }
-
            break;
          }
 
@@ -594,7 +600,7 @@ find_basic_blocks_1 (f)
                 does not imply an abnormal edge, it will be a bit before
                 everything can be updated.  So continue to emit a noop at
                 the end of such a block.  */
-             if (GET_CODE (end) == CALL_INSN)
+             if (GET_CODE (end) == CALL_INSN && ! SIBLING_CALL_P (end))
                {
                  rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
                  end = emit_insn_after (nop, end);
@@ -603,6 +609,7 @@ find_basic_blocks_1 (f)
              create_basic_block (i++, head, end, bb_note);
              bb_note = NULL_RTX;
            }
+
          head = end = insn;
          break;
 
@@ -646,7 +653,7 @@ find_basic_blocks_1 (f)
             imply an abnormal edge, it will be a bit before everything can
             be updated.  So continue to emit a noop at the end of such a
             block.  */
-         if (GET_CODE (end) == CALL_INSN)
+         if (GET_CODE (end) == CALL_INSN && ! SIBLING_CALL_P (end))
            {
              rtx nop = gen_rtx_USE (VOIDmode, const0_rtx);
              end = emit_insn_after (nop, end);
@@ -654,20 +661,37 @@ find_basic_blocks_1 (f)
          goto new_bb_exclusive;
 
        case CALL_INSN:
-         /* A basic block ends at a call that can either throw or
-            do a non-local goto.  */
-         if (call_has_abnormal_edge)
-           {
-           new_bb_inclusive:
-             if (head == NULL_RTX)
-               head = insn;
-             end = insn;
+         {
+           /* Record whether this call created an edge.  */
+           rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+           int region = (note ? INTVAL (XEXP (note, 0)) : 1);
+           int call_has_abnormal_edge = 0;
+
+           /* If there is an EH region or rethrow, we have an edge.  */
+           if ((eh_list && region > 0)
+               || find_reg_note (insn, REG_EH_RETHROW, NULL_RTX))
+             call_has_abnormal_edge = 1;
+           else if (nonlocal_goto_handler_labels && region >= 0)
+             /* If there is a nonlocal goto label and the specified
+                region number isn't -1, we have an edge. (0 means
+                no throw, but might have a nonlocal goto).  */
+             call_has_abnormal_edge = 1;
 
-           new_bb_exclusive:
-             create_basic_block (i++, head, end, bb_note);
-             head = end = NULL_RTX;
-             bb_note = NULL_RTX;
-             break;
+           /* A basic block ends at a call that can either throw or
+              do a non-local goto.  */
+           if (call_has_abnormal_edge)
+             {
+             new_bb_inclusive:
+               if (head == NULL_RTX)
+                 head = insn;
+               end = insn;
+
+             new_bb_exclusive:
+               create_basic_block (i++, head, end, bb_note);
+               head = end = NULL_RTX;
+               bb_note = NULL_RTX;
+               break;
+             }
            }
          /* FALLTHRU */
 
@@ -697,10 +721,10 @@ find_basic_blocks_1 (f)
          for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
            if (REG_NOTE_KIND (note) == REG_LABEL)
              {
-               rtx lab = XEXP (note, 0), next;
+               rtx lab = XEXP (note, 0), next;
 
                if (lab == eh_return_stub_label)
-                 ;
+                   ;
                else if ((next = next_nonnote_insn (lab)) != NULL
                         && GET_CODE (next) == JUMP_INSN
                         && (GET_CODE (PATTERN (next)) == ADDR_VEC
@@ -742,7 +766,7 @@ cleanup_cfg (f)
    HEAD and END inclusive.  Reuses the note and basic block struct
    in BB_NOTE, if any.  */
 
-static void
+void
 create_basic_block (index, head, end, bb_note)
      int index;
      rtx head, end, bb_note;
@@ -975,6 +999,15 @@ make_edges (label_value_list)
            }
        }
 
+      /* If this is a sibling call insn, then this is in effect a 
+        combined call and return, and so we need an edge to the
+        exit block.  No need to worry about EH edges, since we
+        wouldn't have created the sibling call in the first place.  */
+
+      if (code == CALL_INSN && SIBLING_CALL_P (insn))
+       make_edge (edge_cache, bb, EXIT_BLOCK_PTR, 0);
+      else
+
       /* If this is a CALL_INSN, then mark it as reaching the active EH
         handler for this CALL_INSN.  If we're handling asynchronous
         exceptions then any insn can reach any of the active handlers.
@@ -983,10 +1016,10 @@ make_edges (label_value_list)
 
       if (code == CALL_INSN || asynchronous_exceptions)
        {
-         /* If there's an EH region active at the end of a block,
-            add the appropriate edges.  */
-         if (bb->eh_end >= 0)
-           make_eh_edge (edge_cache, eh_nest_info, bb, insn, bb->eh_end);
+         /* Add any appropriate EH edges.  We do this unconditionally
+            since there may be a REG_EH_REGION or REG_EH_RETHROW note
+            on the call, and this needn't be within an EH region.  */
+         make_eh_edge (edge_cache, eh_nest_info, bb, insn, bb->eh_end);
 
          /* If we have asynchronous exceptions, do the same for *all*
             exception regions active in the block.  */
@@ -1020,7 +1053,7 @@ make_edges (label_value_list)
              /* We do know that a REG_EH_REGION note with a value less
                 than 0 is guaranteed not to perform a non-local goto.  */
              rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-             if (!note || XINT (XEXP (note, 0), 0) >=  0)
+             if (!note || INTVAL (XEXP (note, 0)) >=  0)
                for (x = nonlocal_goto_handler_labels; x ; x = XEXP (x, 1))
                  make_label_edge (edge_cache, bb, XEXP (x, 0),
                                   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
@@ -1367,7 +1400,8 @@ split_edge (edge_in)
          basic_block jump_block;
          rtx pos;
 
-         if ((e->flags & EDGE_CRITICAL) == 0)
+         if ((e->flags & EDGE_CRITICAL) == 0
+             && e->src != ENTRY_BLOCK_PTR)
            {
              /* Non critical -- we can simply add a jump to the end
                 of the existing predecessor.  */
@@ -1736,7 +1770,7 @@ delete_unreachable_blocks ()
     }
 
   /* Delete all unreachable basic blocks.  Count down so that we don't
-     interfere with the block renumbering that happens in delete_block.  */
+     interfere with the block renumbering that happens in flow_delete_block. */
 
   deleted_handler = 0;
 
@@ -1748,7 +1782,7 @@ delete_unreachable_blocks ()
        /* This block was found.  Tidy up the mark.  */
        b->aux = NULL;
       else
-       deleted_handler |= delete_block (b);
+       deleted_handler |= flow_delete_block (b);
     }
 
   tidy_fallthru_edges ();
@@ -1778,7 +1812,7 @@ delete_eh_regions ()
          {
            int num = NOTE_EH_HANDLER (insn);
            /* A NULL handler indicates a region is no longer needed,
-              as long as it isn't the target of a rethrow.  */
+              as long as its rethrow label isn't used.  */
            if (get_first_handler (num) == NULL && ! rethrow_used (num))
              {
                NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
@@ -1836,12 +1870,12 @@ flow_delete_insn_chain (start, finish)
 /* ??? Preserving all such notes strikes me as wrong.  It would be nice
    to post-process the stream to remove empty blocks, loops, ranges, etc.  */
 
-static int
-delete_block (b)
+int
+flow_delete_block (b)
      basic_block b;
 {
   int deleted_handler = 0;
-  rtx insn, end;
+  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.
@@ -1890,11 +1924,22 @@ delete_block (b)
        }
     }
 
-  /* Selectively unlink the insn chain.  Include any BARRIER that may
-     follow the basic block.  */
-  end = next_nonnote_insn (b->end);
-  if (!end || GET_CODE (end) != BARRIER)
-    end = b->end;
+  /* 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.  */
   flow_delete_insn_chain (insn, end);
 
  no_delete_insns:
@@ -1960,6 +2005,7 @@ flow_delete_insn (insn)
 {
   rtx prev = PREV_INSN (insn);
   rtx next = NEXT_INSN (insn);
+  rtx note;
 
   PREV_INSN (insn) = NULL_RTX;
   NEXT_INSN (insn) = NULL_RTX;
@@ -1979,6 +2025,10 @@ flow_delete_insn (insn)
   if (GET_CODE (insn) == JUMP_INSN && JUMP_LABEL (insn))
     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)
+    LABEL_NUSES (XEXP (note, 0))--;
+
   return next;
 }
 
@@ -2010,6 +2060,109 @@ can_delete_label_p (label)
   return 1;
 }
 
+/* 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 (GET_CODE (b_head) == NOTE 
+      && NOTE_LINE_NUMBER (b_head) == NOTE_INSN_BASIC_BLOCK)
+    {
+      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;
+
+      prev = prev_nonnote_insn (a_end);
+      if (!prev) 
+       prev = a->head;
+
+      del_first = a_end;
+
+#ifdef HAVE_cc0
+      /* If this was a conditional jump, we need to also delete
+        the insn that set cc0.  */
+      if (prev && sets_cc0_p (prev))
+       {
+          rtx tmp = prev;
+         prev = prev_nonnote_insn (prev);
+         if (!prev)
+           prev = a->head;
+         del_first = tmp;
+       }
+#endif
+
+      a_end = prev;
+    }
+
+  /* Delete everything marked above as well as crap that might be
+     hanging out between the two blocks.  */
+  flow_delete_insn_chain (del_first, del_last);
+
+  /* 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;
+
+  /* Reassociate the insns of B with A.  */
+  if (!b_empty)
+    {
+      if (basic_block_for_insn)
+       {
+         BLOCK_FOR_INSN (b_head) = a;
+         while (b_head != b_end)
+           {
+             b_head = NEXT_INSN (b_head);
+             BLOCK_FOR_INSN (b_head) = a;
+           }
+       }
+      a_end = b_end;
+    }
+  a->end = a_end;
+
+  expunge_block (b);
+}
+
 /* Blocks A and B are to be merged into a single block.  A has no incoming
    fallthru edge, so it can be moved before B without adding or modifying
    any jumps (aside from the jump from A to B).  */
@@ -2123,95 +2276,6 @@ merge_blocks_move_successor_nojumps (a, b)
   return 1;
 }
 
-/* Blocks A and B are to be merged into a single block.  The insns
-   are already contiguous, hence `nomove'.  */
-
-static void
-merge_blocks_nomove (a, b)
-     basic_block a, b;
-{
-  edge e;
-  rtx b_head, b_end, a_end;
-  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;
-      b_head = flow_delete_insn (b_head);
-    }
-
-  /* Delete the basic block note.  */
-  if (GET_CODE (b_head) == NOTE 
-      && NOTE_LINE_NUMBER (b_head) == NOTE_INSN_BASIC_BLOCK)
-    {
-      if (b_head == b_end)
-       b_empty = 1;
-      b_head = flow_delete_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;
-
-      prev = prev_nonnote_insn (a_end);
-      if (!prev) 
-       prev = a->head;
-
-#ifdef HAVE_cc0
-      /* If this was a conditional jump, we need to also delete
-        the insn that set cc0.  */
-
-      if (prev && sets_cc0_p (prev))
-       {
-          rtx tmp = prev;
-         prev = prev_nonnote_insn (prev);
-         if (!prev)
-           prev = a->head;
-         flow_delete_insn (tmp);
-       }
-#endif
-
-      /* Note that a->head != a->end, since we should have at least a
-        bb note plus the jump, so prev != insn.  */
-      flow_delete_insn (a_end);
-      a_end = prev;
-    }
-
-  /* By definition, there should only be one successor of A, and that is
-     B.  Free that edge struct.  */
-  n_edges--;
-  free (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;
-
-  /* Reassociate the insns of B with A.  */
-  if (!b_empty)
-    {
-      BLOCK_FOR_INSN (b_head) = a;
-      while (b_head != b_end)
-       {
-         b_head = NEXT_INSN (b_head);
-         BLOCK_FOR_INSN (b_head) = a;
-       }
-      a_end = b_head;
-    }
-  a->end = a_end;
-  
-  /* Compact the basic block array.  */
-  expunge_block (b);
-}
-
 /* Attempt to merge basic blocks that are potentially non-adjacent.  
    Return true iff the attempt succeeded.  */
 
@@ -2344,7 +2408,7 @@ try_merge_blocks ()
 /* 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.  */
 
-static void
+void
 tidy_fallthru_edge (e, b, c)
      edge e;
      basic_block b, c;
@@ -2368,7 +2432,9 @@ tidy_fallthru_edge (e, b, c)
      If block B consisted only of this single jump, turn it into a deleted
      note.  */
   q = b->end;
-  if (GET_CODE (q) == JUMP_INSN)
+  if (GET_CODE (q) == JUMP_INSN
+      && (simplejump_p (q)
+         || (b->succ == e && e->succ_next == NULL)))
     {
 #ifdef HAVE_cc0
       /* If this was a conditional jump, we need to also delete
@@ -2430,40 +2496,21 @@ tidy_fallthru_edges ()
        tidy_fallthru_edge (s, b, c);
     }
 }
-
-/* Discover and record the loop depth at the head of each basic block.  */
-
-void
-calculate_loop_depth (dump)
-     FILE *dump;
-{
-  struct loops loops;
-
-  /* The loop infrastructure does the real job for us.  */
-  flow_loops_find (&loops);
-
-  if (dump)
-    flow_loops_dump (&loops, dump, 0);
-
-  flow_loops_free (&loops);
-}
 \f
 /* Perform data flow analysis.
-   F is the first insn of the function and NREGS the number of register numbers
-   in use.  */
+   F is the first insn of the function; FLAGS is a set of PROP_* flags
+   to be used in accumulating flow info.  */
 
 void
-life_analysis (f, nregs, file, remove_dead_code)
+life_analysis (f, file, flags)
      rtx f;
-     int nregs;
      FILE *file;
-     int remove_dead_code;
+     int flags;
 {
 #ifdef ELIMINABLE_REGS
-  register size_t i;
+  register int i;
   static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
 #endif
-  int flags;
 
   /* Record which registers will be eliminated.  We use this in
      mark_used_regs.  */
@@ -2471,37 +2518,61 @@ life_analysis (f, nregs, file, remove_dead_code)
   CLEAR_HARD_REG_SET (elim_reg_set);
 
 #ifdef ELIMINABLE_REGS
-  for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
+  for (i = 0; i < (int) (sizeof eliminables / sizeof eliminables[0]); i++)
     SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
 #else
   SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
 #endif
 
-  /* Allocate a bitmap to be filled in by record_volatile_insns.  */
-  uid_volatile = BITMAP_XMALLOC ();
-
-  /* We want alias analysis information for local dead store elimination.  */
-  init_alias_analysis ();
-
   if (! optimize)
-    flags = PROP_DEATH_NOTES | PROP_REG_INFO;
-  else
-    {
-      flags = PROP_FINAL;
-      if (! remove_dead_code)
-       flags &= ~(PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
-    }
-  life_analysis_1 (f, nregs, flags);
-
-  if (! reload_completed)
-    mark_constant_function ();
+    flags &= PROP_DEATH_NOTES | PROP_REG_INFO;
 
-  end_alias_analysis ();
+  /* The post-reload life analysis have (on a global basis) the same
+     registers live as was computed by reload itself.  elimination
+     Otherwise offsets and such may be incorrect.
+
+     Reload will make some registers as live even though they do not
+     appear in the rtl.  */
+  if (reload_completed)
+    flags &= ~PROP_REG_INFO;
+
+  /* We want alias analysis information for local dead store elimination.  */
+  if (flags & PROP_SCAN_DEAD_CODE)
+    init_alias_analysis ();
+
+  /* Always remove no-op moves.  Do this before other processing so
+     that we don't have to keep re-scanning them.  */
+  delete_noop_moves (f);
+
+  /* Some targets can emit simpler epilogues if they know that sp was
+     not ever modified during the function.  After reload, of course,
+     we've already emitted the epilogue so there's no sense searching.  */
+  if (! reload_completed)
+    notice_stack_pointer_modification (f);
+    
+  /* Allocate and zero out data structures that will record the
+     data from lifetime analysis.  */
+  allocate_reg_life_data ();
+  allocate_bb_life_data ();
+
+  /* Find the set of registers live on function exit.  */
+  mark_regs_live_at_end (EXIT_BLOCK_PTR->global_live_at_start);
+
+  /* "Update" life info from zero.  It'd be nice to begin the
+     relaxation with just the exit and noreturn blocks, but that set
+     is not immediately handy.  */
+
+  if (flags & PROP_REG_INFO)
+    memset (regs_ever_live, 0, sizeof(regs_ever_live));
+  update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
+
+  /* Clean up.  */
+  if (flags & PROP_SCAN_DEAD_CODE)
+    end_alias_analysis ();
 
   if (file)
     dump_flow_info (file);
 
-  BITMAP_XFREE (uid_volatile);
   free_basic_block_vars (1);
 }
 
@@ -2514,7 +2585,7 @@ verify_wide_reg_1 (px, pregno)
      void *pregno;
 {
   rtx x = *px;
-  int regno = *(int *) pregno;
+  unsigned int regno = *(int *) pregno;
 
   if (GET_CODE (x) == REG && REGNO (x) == regno)
     {
@@ -2580,11 +2651,12 @@ verify_local_live_at_start (new_live_at_start, bb)
     }
 }
 
-/* Updates death notes starting with the basic blocks set in BLOCKS.
+/* Updates life information starting with the basic blocks set in BLOCKS.
+   If BLOCKS is null, consider it to be the universal set.
    
-   If LOCAL_ONLY, such as after splitting or peepholeing, we are only
-   expecting local modifications to basic blocks.  If we find extra
-   registers live at the beginning of a block, then we either killed
+   If EXTENT is UPDATE_LIFE_LOCAL, such as after splitting or peepholeing,
+   we are only expecting local modifications to basic blocks.  If we find
+   extra registers live at the beginning of a block, then we either killed
    useful data, or we have a broken split that wants data not provided.
    If we find registers removed from live_at_start, that means we have
    a broken peephole that is killing a register it shouldn't.
@@ -2593,11 +2665,8 @@ verify_local_live_at_start (new_live_at_start, bb)
    generates subregs of a multi-word pseudo, current life analysis will
    lose the kill.  So we _can_ have a pseudo go live.  How irritating.
 
-   BLOCK_FOR_INSN is assumed to be correct.
-
-   ??? PROP_FLAGS should not contain PROP_LOG_LINKS.  Need to set up
-   reg_next_use for that.  Including PROP_REG_INFO does not refresh
-   regs_ever_live unless the caller resets it to zero.  */
+   Including PROP_REG_INFO does not properly refresh regs_ever_live
+   unless the caller resets it to zero.  */
 
 void
 update_life_info (blocks, extent, prop_flags)
@@ -2606,9 +2675,10 @@ update_life_info (blocks, extent, prop_flags)
      int prop_flags;
 {
   regset tmp;
+  regset_head tmp_head;
   int i;
 
-  tmp = ALLOCA_REG_SET ();
+  tmp = INITIALIZE_REG_SET (tmp_head);
 
   /* For a global update, we go through the relaxation process again.  */
   if (extent != UPDATE_LIFE_LOCAL)
@@ -2621,18 +2691,63 @@ update_life_info (blocks, extent, prop_flags)
        count_or_remove_death_notes (blocks, 1);
     }
 
-  EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
+  if (blocks)
     {
-      basic_block bb = BASIC_BLOCK (i);
+      EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
+       {
+         basic_block bb = BASIC_BLOCK (i);
 
-      COPY_REG_SET (tmp, bb->global_live_at_end);
-      propagate_block (bb, tmp, (regset) NULL, prop_flags);
+         COPY_REG_SET (tmp, bb->global_live_at_end);
+         propagate_block (bb, tmp, (regset) NULL, prop_flags);
 
-      if (extent == UPDATE_LIFE_LOCAL)
-       verify_local_live_at_start (tmp, bb);
-    });
+         if (extent == UPDATE_LIFE_LOCAL)
+           verify_local_live_at_start (tmp, bb);
+       });
+    }
+  else
+    {
+      for (i = n_basic_blocks - 1; i >= 0; --i)
+       {
+         basic_block bb = BASIC_BLOCK (i);
+
+         COPY_REG_SET (tmp, bb->global_live_at_end);
+         propagate_block (bb, tmp, (regset) NULL, prop_flags);
+
+         if (extent == UPDATE_LIFE_LOCAL)
+           verify_local_live_at_start (tmp, bb);
+       }
+    }
 
   FREE_REG_SET (tmp);
+
+  if (prop_flags & PROP_REG_INFO)
+    {
+      /* The only pseudos that are live at the beginning of the function
+        are those that were not set anywhere in the function.  local-alloc
+        doesn't know how to handle these correctly, so mark them as not
+        local to any one basic block.  */
+      EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->global_live_at_end,
+                                FIRST_PSEUDO_REGISTER, i,
+                                { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
+
+      /* We have a problem with any pseudoreg that lives across the setjmp. 
+        ANSI says that if a user variable does not change in value between
+        the setjmp and the longjmp, then the longjmp preserves it.  This
+        includes longjmp from a place where the pseudo appears dead.
+        (In principle, the value still exists if it is in scope.)
+        If the pseudo goes in a hard reg, some other value may occupy
+        that hard reg where this pseudo is dead, thus clobbering the pseudo.
+        Conclusion: such a pseudo must not go in a hard reg.  */
+      EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+                                FIRST_PSEUDO_REGISTER, i,
+                                {
+                                  if (regno_reg_rtx[i] != 0)
+                                    {
+                                      REG_LIVE_LENGTH (i) = -1;
+                                      REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
+                                    }
+                                });
+    }
 }
 
 /* Free the variables allocated by find_basic_blocks.
@@ -2669,18 +2784,17 @@ set_noop_p (set)
 {
   rtx src = SET_SRC (set);
   rtx dst = SET_DEST (set);
-  if (GET_CODE (src) == REG && GET_CODE (dst) == REG
-      && REGNO (src) == REGNO (dst))
-    return 1;
-  if (GET_CODE (src) != SUBREG || GET_CODE (dst) != SUBREG
-      || SUBREG_WORD (src) != SUBREG_WORD (dst))
-    return 0;
-  src = SUBREG_REG (src);
-  dst = SUBREG_REG (dst);
-  if (GET_CODE (src) == REG && GET_CODE (dst) == REG
-      && REGNO (src) == REGNO (dst))
-    return 1;
-  return 0;
+
+  if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
+    {
+      if (SUBREG_WORD (src) != SUBREG_WORD (dst))
+       return 0;
+      src = SUBREG_REG (src);
+      dst = SUBREG_REG (dst);
+    }
+
+  return (GET_CODE (src) == REG && GET_CODE (dst) == REG
+         && REGNO (src) == REGNO (dst));
 }
 
 /* Return nonzero if an insn consists only of SETs, each of which only sets a
@@ -2720,8 +2834,29 @@ noop_move_p (insn)
   return 0;
 }
 
+/* Delete any insns that copy a register to itself.  */
+
+static void
+delete_noop_moves (f)
+     rtx f;
+{
+  rtx insn;
+  for (insn = f; insn; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == INSN && noop_move_p (insn))
+       {
+         PUT_CODE (insn, NOTE);
+         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+         NOTE_SOURCE_FILE (insn) = 0;
+       }
+    }
+}
+
+/* Determine if the stack pointer is constant over the life of the function.
+   Only useful before prologues have been emitted.  */
+
 static void
-notice_stack_pointer_modification (x, pat, data)
+notice_stack_pointer_modification_1 (x, pat, data)
      rtx x;
      rtx pat ATTRIBUTE_UNUSED;
      void *data ATTRIBUTE_UNUSED;
@@ -2739,57 +2874,28 @@ notice_stack_pointer_modification (x, pat, data)
     current_function_sp_is_unchanging = 0;
 }
 
-/* Record which insns refer to any volatile memory
-   or for any reason can't be deleted just because they are dead stores.
-   Also, delete any insns that copy a register to itself.
-   And see if the stack pointer is modified.  */
 static void
-record_volatile_insns (f)
+notice_stack_pointer_modification (f)
      rtx f;
 {
   rtx insn;
+
+  /* Assume that the stack pointer is unchanging if alloca hasn't
+     been used.  */
+  current_function_sp_is_unchanging = !current_function_calls_alloca;
+  if (! current_function_sp_is_unchanging)
+    return;
+
   for (insn = f; insn; insn = NEXT_INSN (insn))
     {
-      enum rtx_code code1 = GET_CODE (insn);
-      if (code1 == CALL_INSN)
-       SET_INSN_VOLATILE (insn);
-      else if (code1 == INSN || code1 == JUMP_INSN)
+      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        {
-         if (GET_CODE (PATTERN (insn)) != USE
-             && volatile_refs_p (PATTERN (insn)))
-           SET_INSN_VOLATILE (insn);
-
-         /* A SET that makes space on the stack cannot be dead.
-            (Such SETs occur only for allocating variable-size data,
-            so they will always have a PLUS or MINUS according to the
-            direction of stack growth.)
-            Even if this function never uses this stack pointer value,
-            signal handlers do!  */
-         else if (code1 == INSN && GET_CODE (PATTERN (insn)) == SET
-                  && SET_DEST (PATTERN (insn)) == stack_pointer_rtx
-#ifdef STACK_GROWS_DOWNWARD
-                  && GET_CODE (SET_SRC (PATTERN (insn))) == MINUS
-#else
-                  && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
-#endif
-                  && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx)
-           SET_INSN_VOLATILE (insn);
-
-         /* Delete (in effect) any obvious no-op moves.  */
-         else if (noop_move_p (insn))
-           {
-             PUT_CODE (insn, NOTE);
-             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (insn) = 0;
-           }
+         /* Check if insn modifies the stack pointer.  */
+         note_stores (PATTERN (insn), notice_stack_pointer_modification_1,
+                      NULL);
+         if (! current_function_sp_is_unchanging)
+           return;
        }
-
-      /* Check if insn modifies the stack pointer.  */
-      if ( current_function_sp_is_unchanging
-          && GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-       note_stores (PATTERN (insn),
-                    notice_stack_pointer_modification,
-                    NULL);
     }
 }
 
@@ -2821,7 +2927,6 @@ static void
 mark_regs_live_at_end (set)
      regset set;
 {
-  tree result, type;
   int i;
 
   /* If exiting needs the right stack value, consider the stack pointer
@@ -2882,119 +2987,26 @@ mark_regs_live_at_end (set)
   diddle_return_value (mark_reg, set);
 }
 
-/* Determine which registers are live at the start of each
-   basic block of the function whose first insn is F.
-   NREGS is the number of registers used in F.
-   We allocate the vector basic_block_live_at_start
-   and the regsets that it points to, and fill them with the data.
-   regset_size and regset_bytes are also set here.  */
+/* Callback function for for_each_successor_phi.  DATA is a regset.
+   Sets the SRC_REGNO, the regno of the phi alternative for phi node
+   INSN, in the regset.  */
 
-static void
-life_analysis_1 (f, nregs, flags)
-     rtx f;
-     int nregs;
-     int flags;
+static int
+set_phi_alternative_reg (insn, dest_regno, src_regno, data)
+     rtx insn ATTRIBUTE_UNUSED;
+     int dest_regno ATTRIBUTE_UNUSED;
+     int src_regno;
+     void *data;
 {
-  char save_regs_ever_live[FIRST_PSEUDO_REGISTER];
-  register int i;
-
-  max_regno = nregs;
-
-  /* Allocate and zero out many data structures
-     that will record the data from lifetime analysis.  */
-
-  allocate_reg_life_data ();
-  allocate_bb_life_data ();
-
-  reg_next_use = (rtx *) xcalloc (nregs, sizeof (rtx));
-
-  /* Assume that the stack pointer is unchanging if alloca hasn't been used.
-     This will be cleared by record_volatile_insns if it encounters an insn
-     which modifies the stack pointer.  */
-  current_function_sp_is_unchanging = !current_function_calls_alloca;
-  record_volatile_insns (f);
-
-  /* Find the set of registers live on function exit.  Do this before
-     zeroing regs_ever_live, as we use that data post-reload.  */
-  mark_regs_live_at_end (EXIT_BLOCK_PTR->global_live_at_start);
-
-  /* The post-reload life analysis have (on a global basis) the same
-     registers live as was computed by reload itself.  elimination
-     Otherwise offsets and such may be incorrect.
-
-     Reload will make some registers as live even though they do not
-     appear in the rtl.  */
-  if (reload_completed)
-    memcpy (save_regs_ever_live, regs_ever_live, sizeof (regs_ever_live));
-  memset (regs_ever_live, 0, sizeof regs_ever_live);
-
-  /* Compute register life at block boundaries.  It'd be nice to 
-     begin with just the exit and noreturn blocks, but that set 
-     is not immediately handy.  */
-  {
-    sbitmap blocks;
-    blocks = sbitmap_alloc (n_basic_blocks);
-    sbitmap_ones (blocks);
-    calculate_global_regs_live (blocks, blocks, flags & PROP_SCAN_DEAD_CODE);
-    sbitmap_free (blocks);
-  }
-
-  /* The only pseudos that are live at the beginning of the function are
-     those that were not set anywhere in the function.  local-alloc doesn't
-     know how to handle these correctly, so mark them as not local to any
-     one basic block.  */
-
-  EXECUTE_IF_SET_IN_REG_SET (ENTRY_BLOCK_PTR->global_live_at_end,
-                            FIRST_PSEUDO_REGISTER, i,
-                            { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
-
-  /* Now the life information is accurate.  Make one more pass over each
-     basic block to delete dead stores, create autoincrement addressing
-     and record how many times each register is used, is set, or dies.  */
-  {
-    regset tmp;
-    tmp = ALLOCA_REG_SET ();
-
-    for (i = n_basic_blocks - 1; i >= 0; --i)
-      {
-        basic_block bb = BASIC_BLOCK (i);
-
-       COPY_REG_SET (tmp, bb->global_live_at_end);
-       propagate_block (bb, tmp, (regset) NULL, flags);
-      }
-
-    FREE_REG_SET (tmp);
-  }
-
-  /* We have a problem with any pseudoreg that lives across the setjmp. 
-     ANSI says that if a user variable does not change in value between
-     the setjmp and the longjmp, then the longjmp preserves it.  This
-     includes longjmp from a place where the pseudo appears dead.
-     (In principle, the value still exists if it is in scope.)
-     If the pseudo goes in a hard reg, some other value may occupy
-     that hard reg where this pseudo is dead, thus clobbering the pseudo.
-     Conclusion: such a pseudo must not go in a hard reg.  */
-  EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
-                            FIRST_PSEUDO_REGISTER, i,
-                            {
-                              if (regno_reg_rtx[i] != 0)
-                                {
-                                  REG_LIVE_LENGTH (i) = -1;
-                                  REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
-                                }
-                            });
-
-  /* Restore regs_ever_live that was provided by reload.  */
-  if (reload_completed)
-    memcpy (regs_ever_live, save_regs_ever_live, sizeof (regs_ever_live));
-
-  /* Clean up.  */
-  free (reg_next_use);
-  reg_next_use = NULL;
+  regset live = (regset) data;
+  SET_REGNO_REG_SET (live, src_regno);
+  return 0;
 }
 
 /* Propagate global life info around the graph of basic blocks.  Begin
    considering blocks with their corresponding bit set in BLOCKS_IN. 
+   If BLOCKS_IN is null, consider it the universal set.
+
    BLOCKS_OUT is set for every block that was changed.  */
 
 static void
@@ -3004,10 +3016,12 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
 {
   basic_block *queue, *qhead, *qtail, *qend;
   regset tmp, new_live_at_end;
+  regset_head tmp_head;
+  regset_head new_live_at_end_head;
   int i;
 
-  tmp = ALLOCA_REG_SET ();
-  new_live_at_end = ALLOCA_REG_SET ();
+  tmp = INITIALIZE_REG_SET (tmp_head);
+  new_live_at_end = INITIALIZE_REG_SET (new_live_at_end_head);
 
   /* Create a worklist.  Allocate an extra slot for ENTRY_BLOCK, and one
      because the `head == tail' style test for an empty queue doesn't 
@@ -3023,14 +3037,27 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
   /* Queue the blocks set in the initial mask.  Do this in reverse block
      number order so that we are more likely for the first round to do 
      useful work.  We use AUX non-null to flag that the block is queued.  */
-  EXECUTE_IF_SET_IN_SBITMAP (blocks_in, 0, i,
+  if (blocks_in)
     {
-      basic_block bb = BASIC_BLOCK (i);
-      *--qhead = bb;
-      bb->aux = bb;
-    });
+      EXECUTE_IF_SET_IN_SBITMAP (blocks_in, 0, i,
+       {
+         basic_block bb = BASIC_BLOCK (i);
+         *--qhead = bb;
+         bb->aux = bb;
+       });
+    }
+  else
+    {
+      for (i = 0; i < n_basic_blocks; ++i)
+       {
+         basic_block bb = BASIC_BLOCK (i);
+         *--qhead = bb;
+         bb->aux = bb;
+       }
+    }
 
-  sbitmap_zero (blocks_out);
+  if (blocks_out)
+    sbitmap_zero (blocks_out);
 
   while (qhead != qtail)
     {
@@ -3051,6 +3078,18 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
          IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
        }
 
+      /* Force the stack pointer to be live -- which might not already be 
+        the case for blocks within infinite loops.  */
+      SET_REGNO_REG_SET (new_live_at_end, STACK_POINTER_REGNUM);
+
+      /* Regs used in phi nodes are not included in
+        global_live_at_start, since they are live only along a
+        particular edge.  Set those regs that are live because of a
+        phi node alternative corresponding to this particular block.  */
+      if (in_ssa_form)
+       for_each_successor_phi (bb, &set_phi_alternative_reg, 
+                               new_live_at_end);
+
       if (bb == ENTRY_BLOCK_PTR)
        {
          COPY_REG_SET (bb->global_live_at_end, new_live_at_end);
@@ -3096,7 +3135,8 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
 
       /* Let our caller know that BB changed enough to require its
         death notes updated.  */
-      SET_BIT (blocks_out, bb->index);
+      if (blocks_out)
+       SET_BIT (blocks_out, bb->index);
 
       if (! rescan)
        {
@@ -3146,11 +3186,22 @@ calculate_global_regs_live (blocks_in, blocks_out, flags)
   FREE_REG_SET (tmp);
   FREE_REG_SET (new_live_at_end);
 
-  EXECUTE_IF_SET_IN_SBITMAP (blocks_out, 0, i,
+  if (blocks_out)
     {
-      basic_block bb = BASIC_BLOCK (i);
-      FREE_REG_SET (bb->local_set);
-    });
+      EXECUTE_IF_SET_IN_SBITMAP (blocks_out, 0, i,
+       {
+         basic_block bb = BASIC_BLOCK (i);
+         FREE_REG_SET (bb->local_set);
+       });
+    }
+  else
+    {
+      for (i = n_basic_blocks - 1; i >= 0; --i)
+       {
+         basic_block bb = BASIC_BLOCK (i);
+         FREE_REG_SET (bb->local_set);
+       }
+    }
 
   free (queue);
 }
@@ -3186,6 +3237,8 @@ allocate_reg_life_data ()
 {
   int i;
 
+  max_regno = max_reg_num ();
+
   /* Recalculate the register space, in case it has grown.  Old style
      vector oriented regsets would set regset_{size,bytes} here also.  */
   allocate_reg_info (max_regno, FALSE, FALSE);
@@ -3203,347 +3256,470 @@ allocate_reg_life_data ()
     }
 }
 
-/* Compute the registers live at the beginning of a basic block
-   from those live at the end.
+/* Delete dead instructions for propagate_block.  */
 
-   When called, OLD contains those live at the end.
-   On return, it contains those live at the beginning.
-   FIRST and LAST are the first and last insns of the basic block.
+static void
+propagate_block_delete_insn (bb, insn)
+     basic_block bb;
+     rtx insn;
+{
+  rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
 
-   FINAL is nonzero if we are doing the final pass which is not
-   for computing the life info (since that has already been done)
-   but for acting on it.  On this pass, we delete dead stores,
-   set up the logical links and dead-variables lists of instructions,
-   and merge instructions for autoincrement and autodecrement addresses.
+  /* If the insn referred to a label, and that label was attached to
+     an ADDR_VEC, it's safe to delete the ADDR_VEC.  In fact, it's
+     pretty much mandatory to delete it, because the ADDR_VEC may be
+     referencing labels that no longer exist.  */
 
-   SIGNIFICANT is nonzero only the first time for each basic block.
-   If it is nonzero, it points to a regset in which we store
-   a 1 for each register that is set within the block.
+  if (inote)
+    {
+      rtx label = XEXP (inote, 0);
+      rtx next;
+
+      if (LABEL_NUSES (label) == 1
+         && (next = next_nonnote_insn (label)) != NULL
+         && GET_CODE (next) == JUMP_INSN
+         && (GET_CODE (PATTERN (next)) == ADDR_VEC
+             || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
+       {
+         rtx pat = PATTERN (next);
+         int diff_vec_p = GET_CODE (pat) == ADDR_DIFF_VEC;
+         int len = XVECLEN (pat, diff_vec_p);
+         int i;
 
-   BNUM is the number of the basic block.  */
+         for (i = 0; i < len; i++)
+           LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
 
-static void
-propagate_block (bb, old, significant, flags)
+         flow_delete_insn (next);
+       }
+    }
+
+  if (bb->end == insn)
+    bb->end = PREV_INSN (insn);
+  flow_delete_insn (insn);
+}
+
+/* Delete dead libcalls for propagate_block.  Return the insn
+   before the libcall.  */
+
+static rtx
+propagate_block_delete_libcall (bb, insn, note)
      basic_block bb;
-     regset old;
-     regset significant;
-     int flags;
+     rtx insn, note;
 {
-  register rtx insn;
-  rtx prev;
-  regset live;
-  regset dead;
+  rtx first = XEXP (note, 0);
+  rtx before = PREV_INSN (first);
 
-  /* Find the loop depth for this block.  Ignore loop level changes in the
-     middle of the basic block -- for register allocation purposes, the 
-     important uses will be in the blocks wholely contained within the loop
-     not in the loop pre-header or post-trailer.  */
-  loop_depth = bb->loop_depth;
+  if (insn == bb->end)
+    bb->end = before;
+  
+  flow_delete_insn_chain (first, insn);
+  return before;
+}
 
-  dead = ALLOCA_REG_SET ();
-  live = ALLOCA_REG_SET ();
+/* Update the life-status of regs for one insn.  Return the previous insn.  */
 
-  cc0_live = 0;
+rtx
+propagate_one_insn (pbi, insn)
+     struct propagate_block_info *pbi;
+     rtx insn;
+{
+  rtx prev = PREV_INSN (insn);
+  int flags = pbi->flags;
+  int insn_is_dead = 0;
+  int libcall_is_dead = 0;
+  rtx note;
+  int i;
 
-  if (flags & PROP_REG_INFO)
-    {
-      register int i;
+  if (! INSN_P (insn))
+    return prev;
 
-      /* Process the regs live at the end of the block.
-        Mark them as not local to any one basic block. */
-      EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
-                                {
-                                  REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
-                                });
+  note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+  if (flags & PROP_SCAN_DEAD_CODE)
+    {
+      insn_is_dead = insn_dead_p (pbi, PATTERN (insn), 0,
+                                 REG_NOTES (insn));
+      libcall_is_dead = (insn_is_dead && note != 0
+                        && libcall_dead_p (pbi, PATTERN (insn),
+                                           note, insn));
     }
 
-  /* Scan the block an insn at a time from end to beginning.  */
+  /* We almost certainly don't want to delete prologue or epilogue
+     instructions.  Warn about probable compiler losage.  */
+  if (insn_is_dead
+      && reload_completed
+      && (((HAVE_epilogue || HAVE_prologue)
+          && prologue_epilogue_contains (insn))
+         || (HAVE_sibcall_epilogue
+             && sibcall_epilogue_contains (insn))))
+    {
+      if (flags & PROP_KILL_DEAD_CODE)
+       { 
+         warning ("ICE: would have deleted prologue/epilogue insn");
+         if (!inhibit_warnings)
+           debug_rtx (insn);
+       }
+      libcall_is_dead = insn_is_dead = 0;
+    }
 
-  for (insn = bb->end; ; insn = prev)
+  /* If an instruction consists of just dead store(s) on final pass,
+     delete it.  */
+  if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
     {
-      prev = PREV_INSN (insn);
+      /* Record sets.  Do this even for dead instructions, since they
+        would have killed the values if they hadn't been deleted.  */
+      mark_set_regs (pbi, PATTERN (insn), insn);
 
-      if (GET_CODE (insn) == NOTE)
-       {
-         /* If this is a call to `setjmp' et al,
-            warn if any non-volatile datum is live.  */
+      /* CC0 is now known to be dead.  Either this insn used it,
+        in which case it doesn't anymore, or clobbered it,
+        so the next insn can't use it.  */
+      pbi->cc0_live = 0;
 
-         if ((flags & PROP_REG_INFO)
-             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
-           IOR_REG_SET (regs_live_at_setjmp, old);
+      if (libcall_is_dead)
+       {
+         prev = propagate_block_delete_libcall (pbi->bb, insn, note);
+         insn = NEXT_INSN (prev);
        }
+      else
+       propagate_block_delete_insn (pbi->bb, insn);
 
-      /* Update the life-status of regs for this insn.
-        First DEAD gets which regs are set in this insn
-        then LIVE gets which regs are used in this insn.
-        Then the regs live before the insn
-        are those live after, with DEAD regs turned off,
-        and then LIVE regs turned on.  */
-
-      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-       {
-         register int i;
-         rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
-         int insn_is_dead = 0;
-         int libcall_is_dead = 0;
+      return prev;
+    }
 
-         if (flags & PROP_SCAN_DEAD_CODE)
-           {
-             insn_is_dead = (insn_dead_p (PATTERN (insn), old, 0,
-                                          REG_NOTES (insn))
-                             /* Don't delete something that refers to
-                                volatile storage!  */
-                             && ! INSN_VOLATILE (insn));
-             libcall_is_dead = (insn_is_dead && note != 0
-                                && libcall_dead_p (PATTERN (insn), old,
-                                                   note, insn));
-           }
+  /* See if this is an increment or decrement that can be merged into
+     a following memory address.  */
+#ifdef AUTO_INC_DEC
+  {
+    register rtx x = single_set (insn);
+
+    /* Does this instruction increment or decrement a register?  */
+    if (!reload_completed
+       && (flags & PROP_AUTOINC)
+       && x != 0
+       && GET_CODE (SET_DEST (x)) == REG
+       && (GET_CODE (SET_SRC (x)) == PLUS
+           || GET_CODE (SET_SRC (x)) == MINUS)
+       && XEXP (SET_SRC (x), 0) == SET_DEST (x)
+       && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+       /* Ok, look for a following memory ref we can combine with.
+          If one is found, change the memory ref to a PRE_INC
+          or PRE_DEC, cancel this insn, and return 1.
+          Return 0 if nothing has been done.  */
+       && try_pre_increment_1 (pbi, insn))
+      return prev;
+  }
+#endif /* AUTO_INC_DEC */
 
-         /* We almost certainly don't want to delete prologue or epilogue
-            instructions.  Warn about probable compiler losage.  */
-         if (insn_is_dead
-             && reload_completed
-             && (HAVE_epilogue || HAVE_prologue)
-             && prologue_epilogue_contains (insn))
-           {
-             if (flags & PROP_KILL_DEAD_CODE)
-               { 
-                 warning ("ICE: would have deleted prologue/epilogue insn");
-                 if (!inhibit_warnings)
-                   debug_rtx (insn);
-               }
-             libcall_is_dead = insn_is_dead = 0;
-           }
+  CLEAR_REG_SET (pbi->new_set);
 
-         /* If an instruction consists of just dead store(s) on final pass,
-            "delete" it by turning it into a NOTE of type NOTE_INSN_DELETED.
-            We could really delete it with delete_insn, but that
-            can cause trouble for first or last insn in a basic block.  */
-         if ((flags & PROP_KILL_DEAD_CODE) && insn_is_dead)
-           {
-             rtx inote;
-             /* If the insn referred to a label, note that the label is
-                now less used.  */
-             for (inote = REG_NOTES (insn); inote; inote = XEXP (inote, 1))
-               {
-                 if (REG_NOTE_KIND (inote) == REG_LABEL)
-                   {
-                     rtx label = XEXP (inote, 0);
-                     rtx next;
-                     LABEL_NUSES (label)--;
-
-                     /* If this label was attached to an ADDR_VEC, it's
-                        safe to delete the ADDR_VEC.  In fact, it's pretty
-                        much mandatory to delete it, because the ADDR_VEC may
-                        be referencing labels that no longer exist.  */
-                     if (LABEL_NUSES (label) == 0
-                         && (next = next_nonnote_insn (label)) != NULL
-                         && GET_CODE (next) == JUMP_INSN
-                         && (GET_CODE (PATTERN (next)) == ADDR_VEC
-                             || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
-                       {
-                         rtx pat = PATTERN (next);
-                         int diff_vec_p = GET_CODE (pat) == 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))--;
-                         PUT_CODE (next, NOTE);
-                         NOTE_LINE_NUMBER (next) = NOTE_INSN_DELETED;
-                         NOTE_SOURCE_FILE (next) = 0;
-                       }
-                   }
-               }
+  /* If this is not the final pass, and this insn is copying the value of
+     a library call and it's dead, don't scan the insns that perform the
+     library call, so that the call's arguments are not marked live.  */
+  if (libcall_is_dead)
+    {
+      /* Record the death of the dest reg.  */
+      mark_set_regs (pbi, PATTERN (insn), insn);
 
-             PUT_CODE (insn, NOTE);
-             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (insn) = 0;
+      insn = XEXP (note, 0);
+      return PREV_INSN (insn);
+    }
+  else if (GET_CODE (PATTERN (insn)) == SET
+          && SET_DEST (PATTERN (insn)) == stack_pointer_rtx
+          && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
+          && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx
+          && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT)
+    /* We have an insn to pop a constant amount off the stack.
+       (Such insns use PLUS regardless of the direction of the stack,
+       and any insn to adjust the stack by a constant is always a pop.)
+       These insns, if not dead stores, have no effect on life.  */
+    ;
+  else
+    {
+      /* Any regs live at the time of a call instruction must not go
+        in a register clobbered by calls.  Find all regs now live and
+        record this for them.  */
 
-             /* CC0 is now known to be dead.  Either this insn used it,
-                in which case it doesn't anymore, or clobbered it,
-                so the next insn can't use it.  */
-             cc0_live = 0;
+      if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
+       EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+                                  { REG_N_CALLS_CROSSED (i)++; });
 
-             /* If this insn is copying the return value from a library call,
-                delete the entire library call.  */
-             if (libcall_is_dead)
-               {
-                 rtx first = XEXP (note, 0);
-                 rtx p = insn;
-                 while (INSN_DELETED_P (first))
-                   first = NEXT_INSN (first);
-                 while (p != first)
-                   {
-                     p = PREV_INSN (p);
-                     PUT_CODE (p, NOTE);
-                     NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
-                     NOTE_SOURCE_FILE (p) = 0;
-                   }
-               }
-             goto flushed;
-           }
+      /* Record sets.  Do this even for dead instructions, since they
+        would have killed the values if they hadn't been deleted.  */
+      mark_set_regs (pbi, PATTERN (insn), insn);
 
-         CLEAR_REG_SET (dead);
-         CLEAR_REG_SET (live);
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         register int i;
+         rtx note, cond;
+
+         cond = NULL_RTX;
+         if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+           cond = COND_EXEC_TEST (PATTERN (insn));
+
+         /* Non-constant calls clobber memory.  */
+         if (! CONST_CALL_P (insn))
+           free_EXPR_LIST_list (&pbi->mem_set_list);
+
+         /* There may be extra registers to be clobbered.  */
+         for (note = CALL_INSN_FUNCTION_USAGE (insn);
+              note;
+              note = XEXP (note, 1))
+           if (GET_CODE (XEXP (note, 0)) == CLOBBER)
+             mark_set_1 (pbi, CLOBBER, XEXP (XEXP (note, 0), 0),
+                         cond, insn, pbi->flags);
+
+         /* Calls change all call-used and global registers.  */
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (call_used_regs[i] && ! global_regs[i]
+               && ! fixed_regs[i])
+             {
+               /* We do not want REG_UNUSED notes for these registers.  */
+               mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
+                           cond, insn, pbi->flags & ~PROP_DEATH_NOTES);
+             }
+       }
 
-         /* See if this is an increment or decrement that can be
-            merged into a following memory address.  */
-#ifdef AUTO_INC_DEC
-         {
-           register rtx x = single_set (insn);
-
-           /* Does this instruction increment or decrement a register?  */
-           if (!reload_completed
-               && (flags & PROP_AUTOINC)
-               && x != 0
-               && GET_CODE (SET_DEST (x)) == REG
-               && (GET_CODE (SET_SRC (x)) == PLUS
-                   || GET_CODE (SET_SRC (x)) == MINUS)
-               && XEXP (SET_SRC (x), 0) == SET_DEST (x)
-               && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
-               /* Ok, look for a following memory ref we can combine with.
-                  If one is found, change the memory ref to a PRE_INC
-                  or PRE_DEC, cancel this insn, and return 1.
-                  Return 0 if nothing has been done.  */
-               && try_pre_increment_1 (insn))
-             goto flushed;
-         }
-#endif /* AUTO_INC_DEC */
+      /* If an insn doesn't use CC0, it becomes dead since we assume
+        that every insn clobbers it.  So show it dead here;
+        mark_used_regs will set it live if it is referenced.  */
+      pbi->cc0_live = 0;
 
-         /* If this is not the final pass, and this insn is copying the
-            value of a library call and it's dead, don't scan the
-            insns that perform the library call, so that the call's
-            arguments are not marked live.  */
-         if (libcall_is_dead)
-           {
-             /* Mark the dest reg as `significant'.  */
-             mark_set_regs (old, dead, PATTERN (insn), NULL_RTX,
-                            significant, flags);
+      /* Record uses.  */
+      if (! insn_is_dead)
+       mark_used_regs (pbi, PATTERN (insn), NULL_RTX, insn);
 
-             insn = XEXP (note, 0);
-             prev = PREV_INSN (insn);
-           }
-         else if (GET_CODE (PATTERN (insn)) == SET
-                  && SET_DEST (PATTERN (insn)) == stack_pointer_rtx
-                  && GET_CODE (SET_SRC (PATTERN (insn))) == PLUS
-                  && XEXP (SET_SRC (PATTERN (insn)), 0) == stack_pointer_rtx
-                  && GET_CODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == CONST_INT)
-           /* We have an insn to pop a constant amount off the stack.
-              (Such insns use PLUS regardless of the direction of the stack,
-              and any insn to adjust the stack by a constant is always a pop.)
-              These insns, if not dead stores, have no effect on life.  */
-           ;
-         else
-           {
-             /* Any regs live at the time of a call instruction
-                must not go in a register clobbered by calls.
-                Find all regs now live and record this for them.  */
-
-             if (GET_CODE (insn) == CALL_INSN
-                 && (flags & PROP_REG_INFO))
-               EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
-                                          {
-                                            REG_N_CALLS_CROSSED (i)++;
-                                          });
-
-             /* LIVE gets the regs used in INSN;
-                DEAD gets those set by it.  Dead insns don't make anything
-                live.  */
-
-             mark_set_regs (old, dead, PATTERN (insn),
-                            insn, significant, flags);
-
-             /* If an insn doesn't use CC0, it becomes dead since we 
-                assume that every insn clobbers it.  So show it dead here;
-                mark_used_regs will set it live if it is referenced.  */
-             cc0_live = 0;
-
-             if (! insn_is_dead)
-               mark_used_regs (old, live, PATTERN (insn), flags, insn);
-
-             /* Sometimes we may have inserted something before INSN (such as
-                a move) when we make an auto-inc.  So ensure we will scan
-                those insns.  */
+      /* Sometimes we may have inserted something before INSN (such as a move)
+        when we make an auto-inc.  So ensure we will scan those insns.  */
 #ifdef AUTO_INC_DEC
-             prev = PREV_INSN (insn);
+      prev = PREV_INSN (insn);
 #endif
 
-             if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
-               {
-                 register int i;
-
-                 rtx note;
-
-                 for (note = CALL_INSN_FUNCTION_USAGE (insn);
-                      note;
-                      note = XEXP (note, 1))
-                   if (GET_CODE (XEXP (note, 0)) == USE)
-                     mark_used_regs (old, live, XEXP (XEXP (note, 0), 0),
-                                     flags, insn);
-
-                 /* Each call clobbers all call-clobbered regs that are not
-                    global or fixed.  Note that the function-value reg is a
-                    call-clobbered reg, and mark_set_regs has already had
-                    a chance to handle it.  */
-
-                 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-                   if (call_used_regs[i] && ! global_regs[i]
-                       && ! fixed_regs[i])
-                     {
-                       SET_REGNO_REG_SET (dead, i);
-                       if (significant)
-                         SET_REGNO_REG_SET (significant, i);
-                     }
-
-                 /* The stack ptr is used (honorarily) by a CALL insn.  */
-                 SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
-
-                 /* Calls may also reference any of the global registers,
-                    so they are made live.  */
-                 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-                   if (global_regs[i])
-                     mark_used_regs (old, live,
-                                     gen_rtx_REG (reg_raw_mode[i], i),
-                                     flags, insn);
-
-                 /* Calls also clobber memory.  */
-                 free_EXPR_LIST_list (&mem_set_list);
-               }
-
-             /* Update OLD for the registers used or set.  */
-             AND_COMPL_REG_SET (old, dead);
-             IOR_REG_SET (old, live);
-
-           }
-
-         /* On final pass, update counts of how many insns in which
-            each reg is live.  */
-         if (flags & PROP_REG_INFO)
-           EXECUTE_IF_SET_IN_REG_SET (old, 0, i, { REG_LIVE_LENGTH (i)++; });
+      if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
+       {
+         register int i;
+         rtx note, cond;
+
+         cond = NULL_RTX;
+         if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+           cond = COND_EXEC_TEST (PATTERN (insn));
+
+         /* Calls use their arguments.  */
+         for (note = CALL_INSN_FUNCTION_USAGE (insn);
+              note;
+              note = XEXP (note, 1))
+           if (GET_CODE (XEXP (note, 0)) == USE)
+             mark_used_regs (pbi, XEXP (XEXP (note, 0), 0),
+                             cond, insn);
+
+         /* The stack ptr is used (honorarily) by a CALL insn.  */
+         SET_REGNO_REG_SET (pbi->reg_live, STACK_POINTER_REGNUM);
+
+         /* Calls may also reference any of the global registers,
+            so they are made live.  */
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (global_regs[i])
+             mark_used_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i),
+                            cond, insn);
        }
-    flushed:
-      if (insn == bb->head)
-       break;
     }
 
-  FREE_REG_SET (dead);
-  FREE_REG_SET (live);
-  free_EXPR_LIST_list (&mem_set_list);
+  /* On final pass, update counts of how many insns in which each reg
+     is live.  */
+  if (flags & PROP_REG_INFO)
+    EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+                              { REG_LIVE_LENGTH (i)++; });
+
+  return prev;
 }
-\f
-/* Return 1 if X (the body of an insn, or part of it) is just dead stores
-   (SET expressions whose destinations are registers dead after the insn).
-   NEEDED is the regset that says which regs are alive after the insn.
 
-   Unless CALL_OK is non-zero, an insn is needed if it contains a CALL.
+/* Initialize a propagate_block_info struct for public consumption.
+   Note that the structure itself is opaque to this file, but that
+   the user can use the regsets provided here.  */
+
+struct propagate_block_info *
+init_propagate_block_info (bb, live, local_set, flags)
+     basic_block bb;
+     regset live;
+     regset local_set;
+     int flags;
+{
+  struct propagate_block_info *pbi = xmalloc (sizeof(*pbi));
+
+  pbi->bb = bb;
+  pbi->reg_live = live;
+  pbi->mem_set_list = NULL_RTX;
+  pbi->local_set = local_set;
+  pbi->cc0_live = 0;
+  pbi->flags = flags;
+
+  if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+    pbi->reg_next_use = (rtx *) xcalloc (max_reg_num (), sizeof (rtx));
+  else
+    pbi->reg_next_use = NULL;
+
+  pbi->new_set = BITMAP_XMALLOC ();
+
+#ifdef HAVE_conditional_execution
+  pbi->reg_cond_dead = splay_tree_new (splay_tree_compare_ints, NULL,
+                                      free_reg_cond_life_info);
+  pbi->reg_cond_reg = BITMAP_XMALLOC ();
+
+  /* If this block ends in a conditional branch, for each register live
+     from one side of the branch and not the other, record the register
+     as conditionally dead.  */
+  if (GET_CODE (bb->end) == JUMP_INSN
+      && condjump_p (bb->end)
+      && ! simplejump_p (bb->end))
+    {
+      regset_head diff_head;
+      regset diff = INITIALIZE_REG_SET (diff_head);
+      basic_block bb_true, bb_false;
+      rtx cond_true, cond_false;
+      int i;
+
+      /* Identify the successor blocks.  */
+      bb_false = bb->succ->succ_next->dest;
+      bb_true = bb->succ->dest;
+      if (bb->succ->flags & EDGE_FALLTHRU)
+       {
+         basic_block t = bb_false;
+         bb_false = bb_true;
+         bb_true = t;
+       }
+      else if (! (bb->succ->succ_next->flags & EDGE_FALLTHRU))
+       abort ();
+     
+      /* Extract the condition from the branch.  */
+      cond_true = XEXP (SET_SRC (PATTERN (bb->end)), 0);
+      cond_false = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)),
+                                  GET_MODE (cond_true), XEXP (cond_true, 0),
+                                  XEXP (cond_true, 1));
+      if (GET_CODE (XEXP (SET_SRC (PATTERN (bb->end)), 1)) == PC)
+       {
+         rtx t = cond_false;
+         cond_false = cond_true;
+         cond_true = t;
+       }
+
+      /* Compute which register lead different lives in the successors.  */
+      if (bitmap_operation (diff, bb_true->global_live_at_start,
+                           bb_false->global_live_at_start, BITMAP_XOR))
+       {
+         if (GET_CODE (XEXP (cond_true, 0)) != REG)
+           abort ();
+         SET_REGNO_REG_SET (pbi.reg_cond_reg, REGNO (XEXP (cond_true, 0)));
+
+         /* For each such register, mark it conditionally dead.  */
+         EXECUTE_IF_SET_IN_REG_SET
+           (diff, 0, i,
+            {
+              struct reg_cond_life_info *rcli;
+              rtx cond;
+
+              rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
+
+              if (REGNO_REG_SET_P (bb_true->global_live_at_start, i))
+                cond = cond_false;
+              else
+                cond = cond_true;
+              rcli->condition = alloc_EXPR_LIST (0, cond, NULL_RTX);
+
+              splay_tree_insert (pbi.reg_cond_dead, i,
+                                 (splay_tree_value) rcli);
+            });
+       }
+
+      FREE_REG_SET (diff);
+    }
+#endif
+
+  return pbi;
+}
+
+/* Release a propagate_block_info struct.  */
+
+void
+free_propagate_block_info (pbi)
+     struct propagate_block_info *pbi;
+{
+  free_EXPR_LIST_list (&pbi->mem_set_list);
+
+  BITMAP_XFREE (pbi->new_set);
+
+#ifdef HAVE_conditional_execution
+  splay_tree_delete (pbi->reg_cond_dead);
+  BITMAP_XFREE (pbi->reg_cond_reg);
+#endif
+
+  if (pbi->reg_next_use)
+    free (pbi->reg_next_use);
+
+  free (pbi);
+}
+
+/* Compute the registers live at the beginning of a basic block BB from
+   those live at the end.
+
+   When called, REG_LIVE contains those live at the end.  On return, it
+   contains those live at the beginning.
+
+   LOCAL_SET, if non-null, will be set with all registers killed by 
+   this basic block.  */
+
+void
+propagate_block (bb, live, local_set, flags)
+     basic_block bb;
+     regset live;
+     regset local_set;
+     int flags;
+{
+  struct propagate_block_info *pbi;
+  rtx insn, prev;
+  
+  pbi = init_propagate_block_info (bb, live, local_set, flags);
+
+  if (flags & PROP_REG_INFO)
+    {
+      register int i;
+
+      /* Process the regs live at the end of the block.
+        Mark them as not local to any one basic block. */
+      EXECUTE_IF_SET_IN_REG_SET (live, 0, i,
+                                { REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL; });
+    }
+
+  /* Scan the block an insn at a time from end to beginning.  */
+
+  for (insn = bb->end; ; insn = prev)
+    {
+      /* If this is a call to `setjmp' et al, warn if any
+        non-volatile datum is live.  */
+      if ((flags & PROP_REG_INFO)
+         && GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+       IOR_REG_SET (regs_live_at_setjmp, pbi->reg_live);
+
+      prev = propagate_one_insn (pbi, insn);
+
+      if (insn == bb->head)
+       break;
+    }
+
+  free_propagate_block_info (pbi);
+}
+\f
+/* Return 1 if X (the body of an insn, or part of it) is just dead stores
+   (SET expressions whose destinations are registers dead after the insn).
+   NEEDED is the regset that says which regs are alive after the insn.
+
+   Unless CALL_OK is non-zero, an insn is needed if it contains a CALL.
 
    If X is the entire body of an insn, NOTES contains the reg notes
    pertaining to the insn.  */
 
 static int
-insn_dead_p (x, needed, call_ok, notes)
+insn_dead_p (pbi, x, call_ok, notes)
+     struct propagate_block_info *pbi;
      rtx x;
-     regset needed;
      int call_ok;
      rtx notes ATTRIBUTE_UNUSED;
 {
@@ -3562,7 +3738,7 @@ insn_dead_p (x, needed, call_ok, notes)
 
              /* Don't delete insns to set global regs.  */
              if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
-                 || REGNO_REG_SET_P (needed, regno))
+                 || REGNO_REG_SET_P (pbi->reg_live, regno))
                return 0;
            }
        }
@@ -3576,23 +3752,34 @@ insn_dead_p (x, needed, call_ok, notes)
     {
       rtx r = SET_DEST (x);
 
-      /* A SET that is a subroutine call cannot be dead.  */
-      if (! call_ok && GET_CODE (SET_SRC (x)) == CALL)
-       return 0;
-
 #ifdef HAVE_cc0
       if (GET_CODE (r) == CC0)
-       return ! cc0_live;
+       return ! pbi->cc0_live;
 #endif
       
-      if (GET_CODE (r) == MEM && ! MEM_VOLATILE_P (r))
+      /* A SET that is a subroutine call cannot be dead.  */
+      if (GET_CODE (SET_SRC (x)) == CALL)
+       {
+         if (! call_ok)
+           return 0;
+       }
+
+      /* Don't eliminate loads from volatile memory or volatile asms.  */
+      else if (volatile_refs_p (SET_SRC (x)))
+       return 0;
+
+      if (GET_CODE (r) == MEM)
        {
          rtx temp;
+
+         if (MEM_VOLATILE_P (r))
+           return 0;
+
          /* Walk the set of memory locations we are currently tracking
             and see if one is an identical match to this memory location.
             If so, this memory write is dead (remember, we're walking
             backwards from the end of the block to the start.  */
-         temp = mem_set_list;
+         temp = pbi->mem_set_list;
          while (temp)
            {
              if (rtx_equal_p (XEXP (temp, 0), r))
@@ -3600,52 +3787,68 @@ insn_dead_p (x, needed, call_ok, notes)
              temp = XEXP (temp, 1);
            }
        }
+      else
+       {
+         while (GET_CODE (r) == SUBREG
+                || GET_CODE (r) == STRICT_LOW_PART
+                || GET_CODE (r) == ZERO_EXTRACT)
+           r = XEXP (r, 0);
 
-      while (GET_CODE (r) == SUBREG || GET_CODE (r) == STRICT_LOW_PART
-            || GET_CODE (r) == ZERO_EXTRACT)
-       r = XEXP (r, 0);
+         if (GET_CODE (r) == REG)
+           {
+             int regno = REGNO (r);
 
-      if (GET_CODE (r) == REG)
-       {
-         int regno = REGNO (r);
+             /* Obvious.  */
+             if (REGNO_REG_SET_P (pbi->reg_live, regno))
+               return 0;
 
-         /* Don't delete insns to set global regs.  */
-         if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
-             /* Make sure insns to set frame pointer aren't deleted.  */
-             || (regno == FRAME_POINTER_REGNUM
+             /* If this is a hard register, verify that subsequent
+                words are not needed.  */
+             if (regno < FIRST_PSEUDO_REGISTER)
+               {
+                 int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
+
+                 while (--n > 0)
+                   if (REGNO_REG_SET_P (pbi->reg_live, regno+n))
+                     return 0;
+               }
+
+             /* Don't delete insns to set global regs.  */
+             if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
+               return 0;
+
+             /* Make sure insns to set the stack pointer aren't deleted.  */
+             if (regno == STACK_POINTER_REGNUM)
+               return 0;
+
+             /* Make sure insns to set the frame pointer aren't deleted.  */
+             if (regno == FRAME_POINTER_REGNUM
                  && (! reload_completed || frame_pointer_needed))
+               return 0;
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-             || (regno == HARD_FRAME_POINTER_REGNUM
+             if (regno == HARD_FRAME_POINTER_REGNUM
                  && (! reload_completed || frame_pointer_needed))
+               return 0;
 #endif
+
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
              /* Make sure insns to set arg pointer are never deleted
-                (if the arg pointer isn't fixed, there will be a USE for
-                it, so we can treat it normally).  */
-             || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+                (if the arg pointer isn't fixed, there will be a USE
+                for it, so we can treat it normally).  */
+             if (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+               return 0;
 #endif
-             || REGNO_REG_SET_P (needed, regno))
-           return 0;
-
-         /* If this is a hard register, verify that subsequent words are
-            not needed.  */
-         if (regno < FIRST_PSEUDO_REGISTER)
-           {
-             int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
 
-             while (--n > 0)
-               if (REGNO_REG_SET_P (needed, regno+n))
-                 return 0;
+             /* Otherwise, the set is dead.  */
+             return 1;
            }
-
-         return 1;
        }
     }
 
-  /* If performing several activities,
-     insn is dead if each activity is individually dead.
-     Also, CLOBBERs and USEs can be ignored; a CLOBBER or USE
-     that's inside a PARALLEL doesn't make the insn worth keeping.  */
+  /* If performing several activities, insn is dead if each activity
+     is individually dead.  Also, CLOBBERs and USEs can be ignored; a
+     CLOBBER or USE that's inside a PARALLEL doesn't make the insn
+     worth keeping.  */
   else if (code == PARALLEL)
     {
       int i = XVECLEN (x, 0);
@@ -3653,7 +3856,7 @@ insn_dead_p (x, needed, call_ok, notes)
       for (i--; i >= 0; i--)
        if (GET_CODE (XVECEXP (x, 0, i)) != CLOBBER
            && GET_CODE (XVECEXP (x, 0, i)) != USE
-           && ! insn_dead_p (XVECEXP (x, 0, i), needed, call_ok, NULL_RTX))
+           && ! insn_dead_p (pbi, XVECEXP (x, 0, i), call_ok, NULL_RTX))
          return 0;
 
       return 1;
@@ -3663,7 +3866,7 @@ insn_dead_p (x, needed, call_ok, notes)
      is not necessarily true for hard registers.  */
   else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG
           && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER
-          && ! REGNO_REG_SET_P (needed, REGNO (XEXP (x, 0))))
+          && ! REGNO_REG_SET_P (pbi->reg_live, REGNO (XEXP (x, 0))))
     return 1;
 
   /* We do not check other CLOBBER or USE here.  An insn consisting of just
@@ -3686,9 +3889,9 @@ insn_dead_p (x, needed, call_ok, notes)
    NOTE is the REG_RETVAL note of the insn.  INSN is the insn itself.  */
 
 static int
-libcall_dead_p (x, needed, note, insn)
+libcall_dead_p (pbi, x, note, insn)
+     struct propagate_block_info *pbi;
      rtx x;
-     regset needed;
      rtx note;
      rtx insn;
 {
@@ -3731,7 +3934,7 @@ libcall_dead_p (x, needed, note, insn)
              call_pat = XVECEXP (call_pat, 0, i);
            }
 
-         return insn_dead_p (call_pat, needed, 1, REG_NOTES (call));
+         return insn_dead_p (pbi, call_pat, 1, REG_NOTES (call));
        }
     }
   return 1;
@@ -3776,7 +3979,8 @@ regno_clobbered_at_setjmp (regno)
    Find any entries on the mem_set_list that need to be invalidated due
    to an address change.  */
 static void
-invalidate_mems_from_autoinc (insn)
+invalidate_mems_from_autoinc (pbi, insn)
+     struct propagate_block_info *pbi;
      rtx insn;
 {
   rtx note = REG_NOTES (insn);
@@ -3784,7 +3988,7 @@ invalidate_mems_from_autoinc (insn)
     {
       if (REG_NOTE_KIND (note) == REG_INC)
         {
-          rtx temp = mem_set_list;
+          rtx temp = pbi->mem_set_list;
           rtx prev = NULL_RTX;
          rtx next;
 
@@ -3797,7 +4001,7 @@ invalidate_mems_from_autoinc (insn)
                  if (prev)
                    XEXP (prev, 1) = next;
                  else
-                   mem_set_list = next;
+                   pbi->mem_set_list = next;
                  free_EXPR_LIST_node (temp);
                }
              else
@@ -3816,44 +4020,73 @@ invalidate_mems_from_autoinc (insn)
    FLAGS is the set of operations to perform.  */
 
 static void
-mark_set_regs (needed, dead, x, insn, significant, flags)
-     regset needed;
-     regset dead;
-     rtx x;
-     rtx insn;
-     regset significant;
-     int flags;
+mark_set_regs (pbi, x, insn)
+     struct propagate_block_info *pbi;
+     rtx x, insn;
 {
-  register RTX_CODE code = GET_CODE (x);
+  rtx cond = NULL_RTX;
+  enum rtx_code code;
 
-  if (code == SET || code == CLOBBER)
-    mark_set_1 (needed, dead, x, insn, significant, flags);
-  else if (code == PARALLEL)
+ retry:
+  switch (code = GET_CODE (x))
     {
-      register int i;
-      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-       {
-         code = GET_CODE (XVECEXP (x, 0, i));
-         if (code == SET || code == CLOBBER)
-           mark_set_1 (needed, dead, XVECEXP (x, 0, i), insn,
-                       significant, flags);
-       }
+    case SET:
+    case CLOBBER:
+      mark_set_1 (pbi, code, SET_DEST (x), cond, insn, pbi->flags);
+      return;
+
+    case COND_EXEC:
+      cond = COND_EXEC_TEST (x);
+      x = COND_EXEC_CODE (x);
+      goto retry;
+
+    case PARALLEL:
+      {
+       register int i;
+       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+         {
+           rtx sub = XVECEXP (x, 0, i);
+           switch (code = GET_CODE (sub))
+             {
+             case COND_EXEC:
+               if (cond != NULL_RTX)
+                 abort ();
+
+               cond = COND_EXEC_TEST (sub);
+               sub = COND_EXEC_CODE (sub);
+               if (GET_CODE (sub) != SET && GET_CODE (sub) != CLOBBER)
+                 break;
+               /* FALLTHRU */
+
+             case SET:
+             case CLOBBER:
+               mark_set_1 (pbi, code, SET_DEST (sub), cond, insn, pbi->flags);
+               break;
+
+             default:
+               break;
+             }
+         }
+       break;
+      }
+
+    default:
+      break;
     }
 }
 
 /* Process a single SET rtx, X.  */
 
 static void
-mark_set_1 (needed, dead, x, insn, significant, flags)
-     regset needed;
-     regset dead;
-     rtx x;
-     rtx insn;
-     regset significant;
+mark_set_1 (pbi, code, reg, cond, insn, flags)
+     struct propagate_block_info *pbi;
+     enum rtx_code code;
+     rtx reg, cond, insn;
      int flags;
 {
-  register int regno = -1;
-  register rtx reg = SET_DEST (x);
+  int regno_first = -1, regno_last = -1;
+  int not_dead = 0;
+  int i;
 
   /* Some targets place small structures in registers for
      return values of functions.  We have to detect this
@@ -3861,39 +4094,97 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
   if (GET_CODE (reg) == PARALLEL
       && GET_MODE (reg) == BLKmode)
     {
-      register int i;
-
       for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
-       mark_set_1 (needed, dead, XVECEXP (reg, 0, i), insn,
-                   significant, flags);
+       mark_set_1 (pbi, code, XVECEXP (reg, 0, i), cond, insn, flags);
       return;
     }
 
-  /* Modifying just one hardware register of a multi-reg value
-     or just a byte field of a register
-     does not mean the value from before this insn is now dead.
-     But it does mean liveness of that register at the end of the block
-     is significant.
+  /* Modifying just one hardware register of a multi-reg value or just a
+     byte field of a register does not mean the value from before this insn
+     is now dead.  Of course, if it was dead after it's unused now.  */
 
-     Within mark_set_1, however, we treat it as if the register is
-     indeed modified.  mark_used_regs will, however, also treat this
-     register as being used.  Thus, we treat these insns as setting a
-     new value for the register as a function of its old value.  This
-     cases LOG_LINKS to be made appropriately and this will help combine.  */
+  switch (GET_CODE (reg))
+    {
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+    case STRICT_LOW_PART:
+      /* ??? Assumes STRICT_LOW_PART not used on multi-word registers.  */
+      do
+       reg = XEXP (reg, 0);
+      while (GET_CODE (reg) == SUBREG
+            || GET_CODE (reg) == ZERO_EXTRACT
+            || GET_CODE (reg) == SIGN_EXTRACT
+            || GET_CODE (reg) == STRICT_LOW_PART);
+      if (GET_CODE (reg) == MEM)
+       break;
+      not_dead = REGNO_REG_SET_P (pbi->reg_live, REGNO (reg));
+      /* FALLTHRU */
+
+    case REG:
+      regno_last = regno_first = REGNO (reg);
+      if (regno_first < FIRST_PSEUDO_REGISTER)
+       regno_last += HARD_REGNO_NREGS (regno_first, GET_MODE (reg)) - 1;
+      break;
+
+    case SUBREG:
+      if (GET_CODE (SUBREG_REG (reg)) == REG)
+       {
+         enum machine_mode outer_mode = GET_MODE (reg);
+         enum machine_mode inner_mode = GET_MODE (SUBREG_REG (reg));
+
+         /* Identify the range of registers affected.  This is moderately
+            tricky for hard registers.  See alter_subreg.  */
+
+         regno_last = regno_first = REGNO (SUBREG_REG (reg));
+         if (regno_first < FIRST_PSEUDO_REGISTER)
+           {
+#ifdef ALTER_HARD_SUBREG
+             regno_first = ALTER_HARD_SUBREG (outer_mode, SUBREG_WORD (reg),
+                                              inner_mode, regno_first);
+#else
+             regno_first += SUBREG_WORD (reg);
+#endif
+             regno_last = (regno_first
+                           + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
+
+             /* Since we've just adjusted the register number ranges, make
+                sure REG matches.  Otherwise some_was_live will be clear
+                when it shouldn't have been, and we'll create incorrect
+                REG_UNUSED notes.  */
+             reg = gen_rtx_REG (outer_mode, regno_first);
+           }
+         else
+           {
+             /* If the number of words in the subreg is less than the number
+                of words in the full register, we have a well-defined partial
+                set.  Otherwise the high bits are undefined.
+
+                This is only really applicable to pseudos, since we just took
+                care of multi-word hard registers.  */
+             if (((GET_MODE_SIZE (outer_mode)
+                   + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+                 < ((GET_MODE_SIZE (inner_mode)
+                     + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+               not_dead = REGNO_REG_SET_P (pbi->reg_live, regno_first);
+
+             reg = SUBREG_REG (reg);
+           }
+       }
+      else
+       reg = SUBREG_REG (reg);
+      break;
 
-  while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
-        || GET_CODE (reg) == SIGN_EXTRACT
-        || GET_CODE (reg) == STRICT_LOW_PART)
-    reg = XEXP (reg, 0);
+    default:
+      break;
+    }
 
   /* If this set is a MEM, then it kills any aliased writes. 
      If this set is a REG, then it kills any MEMs which use the reg.  */
   if (flags & PROP_SCAN_DEAD_CODE)
     {
-      if (GET_CODE (reg) == MEM
-         || GET_CODE (reg) == REG)
+      if (GET_CODE (reg) == MEM || GET_CODE (reg) == REG)
        {
-         rtx temp = mem_set_list;
+         rtx temp = pbi->mem_set_list;
          rtx prev = NULL_RTX;
          rtx next;
 
@@ -3909,7 +4200,7 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
                  if (prev)
                    XEXP (prev, 1) = next;
                  else
-                   mem_set_list = next;
+                   pbi->mem_set_list = next;
                  free_EXPR_LIST_node (temp);
                }
              else
@@ -3922,7 +4213,7 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
         address modes.  Then we may need to kill some entries on the
         memory set list.  */
       if (insn && GET_CODE (reg) == MEM)
-       invalidate_mems_from_autoinc (insn);
+       invalidate_mems_from_autoinc (pbi, insn);
 
       if (GET_CODE (reg) == MEM && ! side_effects_p (reg)
          /* We do not know the size of a BLKmode store, so we do not track
@@ -3932,121 +4223,102 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
             everything that invalidates it.  To be safe, don't eliminate any
             stores though SP; none of them should be redundant anyway.  */
          && ! reg_mentioned_p (stack_pointer_rtx, reg))
-       mem_set_list = alloc_EXPR_LIST (0, reg, mem_set_list);
+       pbi->mem_set_list = alloc_EXPR_LIST (0, reg, pbi->mem_set_list);
     }
 
   if (GET_CODE (reg) == REG
-      && (regno = REGNO (reg),
-         ! (regno == FRAME_POINTER_REGNUM
-            && (! reload_completed || frame_pointer_needed)))
+      && ! (regno_first == FRAME_POINTER_REGNUM
+           && (! reload_completed || frame_pointer_needed))
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-      && ! (regno == HARD_FRAME_POINTER_REGNUM
+      && ! (regno_first == HARD_FRAME_POINTER_REGNUM
            && (! reload_completed || frame_pointer_needed))
 #endif
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-      && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+      && ! (regno_first == ARG_POINTER_REGNUM && fixed_regs[regno_first])
 #endif
-      && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
-      /* && regno != STACK_POINTER_REGNUM) -- let's try without this.  */
+      )
     {
-      int some_needed = REGNO_REG_SET_P (needed, regno);
-      int some_not_needed = ! some_needed;
-
-      /* Mark it as a significant register for this basic block.  */
-      if (significant)
-       SET_REGNO_REG_SET (significant, regno);
+      int some_was_live = 0, some_was_dead = 0;
 
-      /* Mark it as dead before this insn.  */
-      SET_REGNO_REG_SET (dead, regno);
-
-      /* A hard reg in a wide mode may really be multiple registers.
-        If so, mark all of them just like the first.  */
-      if (regno < FIRST_PSEUDO_REGISTER)
+      for (i = regno_first; i <= regno_last; ++i)
        {
-         int n;
-
-         /* Nothing below is needed for the stack pointer; get out asap.
-            Eg, log links aren't needed, since combine won't use them.  */
-         if (regno == STACK_POINTER_REGNUM)
-           return;
+         int needed_regno = REGNO_REG_SET_P (pbi->reg_live, i);
+         if (pbi->local_set)
+           SET_REGNO_REG_SET (pbi->local_set, i);
+         if (code != CLOBBER)
+           SET_REGNO_REG_SET (pbi->new_set, i);
+
+         some_was_live |= needed_regno;
+         some_was_dead |= ! needed_regno;
+       }
 
-         n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-         while (--n > 0)
-           {
-             int regno_n = regno + n;
-             int needed_regno = REGNO_REG_SET_P (needed, regno_n);
-             if (significant)
-               SET_REGNO_REG_SET (significant, regno_n);
-
-             SET_REGNO_REG_SET (dead, regno_n);
-             some_needed |= needed_regno;
-             some_not_needed |= ! needed_regno;
-           }
+#ifdef HAVE_conditional_execution
+      /* Consider conditional death in deciding that the register needs
+        a death note.  */
+      if (some_was_live
+         /* The stack pointer is never dead.  Well, not strictly true,
+            but it's very difficult to tell from here.  Hopefully
+            combine_stack_adjustments will fix up the most egregious
+            errors.  */
+         && regno_first != STACK_POINTER_REGNUM)
+       {
+         for (i = regno_first; i <= regno_last; ++i)
+           if (! mark_regno_cond_dead (pbi, i, cond))
+             not_dead = 1;
        }
+#endif
 
       /* Additional data to record if this is the final pass.  */
       if (flags & (PROP_LOG_LINKS | PROP_REG_INFO
                   | PROP_DEATH_NOTES | PROP_AUTOINC))
        {
          register rtx y;
-         register int blocknum = BLOCK_NUM (insn);
+         register int blocknum = pbi->bb->index;
 
          y = NULL_RTX;
          if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-           y = reg_next_use[regno];
-
-         /* If this is a hard reg, record this function uses the reg.  */
-
-         if (regno < FIRST_PSEUDO_REGISTER)
            {
-             register int i;
-             int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+             y = pbi->reg_next_use[regno_first];
 
-             if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-               for (i = regno; i < endregno; i++)
-                 {
-                   /* The next use is no longer "next", since a store
-                      intervenes.  */
-                   reg_next_use[i] = 0;
-                 }
-
-             if (flags & PROP_REG_INFO)
-               for (i = regno; i < endregno; i++)
-                 {
-                   regs_ever_live[i] = 1;
-                   REG_N_SETS (i)++;
-                 }
+             /* The next use is no longer next, since a store intervenes.  */
+             for (i = regno_first; i <= regno_last; ++i)
+               pbi->reg_next_use[i] = 0;
            }
-         else
-           {
-             /* The next use is no longer "next", since a store
-                intervenes.  */
-             if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-               reg_next_use[regno] = 0;
-
-             /* Keep track of which basic blocks each reg appears in.  */
 
-             if (flags & PROP_REG_INFO)
+         if (flags & PROP_REG_INFO)
+           {
+             for (i = regno_first; i <= regno_last; ++i)
                {
-                 if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
-                   REG_BASIC_BLOCK (regno) = blocknum;
-                 else if (REG_BASIC_BLOCK (regno) != blocknum)
-                   REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
-
-                 /* Count (weighted) references, stores, etc.  This counts a
+                 /* Count (weighted) references, stores, etc.  This counts a
                     register twice if it is modified, but that is correct.  */
-                 REG_N_SETS (regno)++;
-                 REG_N_REFS (regno) += loop_depth + 1;
-                 
+                 REG_N_SETS (i) += 1;
+                 REG_N_REFS (i) += (optimize_size ? 1
+                                    : pbi->bb->loop_depth + 1);
+
                  /* The insns where a reg is live are normally counted
                     elsewhere, but we want the count to include the insn
                     where the reg is set, and the normal counting mechanism
                     would not count it.  */
-                 REG_LIVE_LENGTH (regno)++;
+                 REG_LIVE_LENGTH (i) += 1;
+               }
+
+             /* If this is a hard reg, record this function uses the reg.  */
+             if (regno_first < FIRST_PSEUDO_REGISTER)
+               {
+                 for (i = regno_first; i <= regno_last; i++)
+                   regs_ever_live[i] = 1;
+               }
+             else
+               {
+                 /* Keep track of which basic blocks each reg appears in.  */
+                 if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
+                   REG_BASIC_BLOCK (regno_first) = blocknum;
+                 else if (REG_BASIC_BLOCK (regno_first) != blocknum)
+                   REG_BASIC_BLOCK (regno_first) = REG_BLOCK_GLOBAL;
                }
            }
 
-         if (! some_not_needed)
+         if (! some_was_dead)
            {
              if (flags & PROP_LOG_LINKS)
                {
@@ -4060,15 +4332,17 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
                     even if reload can make what appear to be valid
                     assignments later.  */
                  if (y && (BLOCK_NUM (y) == blocknum)
-                     && (regno >= FIRST_PSEUDO_REGISTER
+                     && (regno_first >= FIRST_PSEUDO_REGISTER
                          || asm_noperands (PATTERN (y)) < 0))
                    LOG_LINKS (y) = alloc_INSN_LIST (insn, LOG_LINKS (y));
                }
            }
-         else if (! some_needed)
+         else if (not_dead)
+           ;
+         else if (! some_was_live)
            {
              if (flags & PROP_REG_INFO)
-               REG_N_DEATHS (REGNO (reg))++;
+               REG_N_DEATHS (regno_first) += 1;
 
              if (flags & PROP_DEATH_NOTES)
                {
@@ -4091,24 +4365,32 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
                     for those parts that were not needed.  This case should
                     be rare.  */
 
-                 int i;
-
-                 for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
-                      i >= 0; i--)
-                   if (!REGNO_REG_SET_P (needed, regno + i))
+                 for (i = regno_first; i <= regno_last; ++i)
+                   if (! REGNO_REG_SET_P (pbi->reg_live, i))
                      REG_NOTES (insn)
-                       = (alloc_EXPR_LIST
-                          (REG_UNUSED,
-                           gen_rtx_REG (reg_raw_mode[regno + i], regno + i),
-                           REG_NOTES (insn)));
+                       = alloc_EXPR_LIST (REG_UNUSED,
+                                          gen_rtx_REG (reg_raw_mode[i], i),
+                                          REG_NOTES (insn));
                }
            }
        }
+
+      /* Mark the register as being dead.  */
+      if (some_was_live
+         /* The stack pointer is never dead.  Well, not strictly true,
+            but it's very difficult to tell from here.  Hopefully
+            combine_stack_adjustments will fix up the most egregious
+            errors.  */
+         && regno_first != STACK_POINTER_REGNUM)
+       {
+         for (i = regno_first; i <= regno_last; ++i)
+           CLEAR_REGNO_REG_SET (pbi->reg_live, i);
+       }
     }
   else if (GET_CODE (reg) == REG)
     {
       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-       reg_next_use[regno] = 0;
+       pbi->reg_next_use[regno_first] = 0;
     }
 
   /* If this is the last pass and this is a SCRATCH, show it will be dying
@@ -4121,14 +4403,271 @@ mark_set_1 (needed, dead, x, insn, significant, flags)
     }
 }
 \f
+#ifdef HAVE_conditional_execution
+/* Mark REGNO conditionally dead.  Return true if the register is
+   now unconditionally dead.  */
+
+static int
+mark_regno_cond_dead (pbi, regno, cond)
+     struct propagate_block_info *pbi;
+     int regno;
+     rtx cond;
+{
+  /* If this is a store to a predicate register, the value of the
+     predicate is changing, we don't know that the predicate as seen
+     before is the same as that seen after.  Flush all dependant
+     conditions from reg_cond_dead.  This will make all such
+     conditionally live registers unconditionally live.  */
+  if (REGNO_REG_SET_P (pbi->reg_cond_reg, regno))
+    flush_reg_cond_reg (pbi, regno);
+
+  /* If this is an unconditional store, remove any conditional
+     life that may have existed.  */
+  if (cond == NULL_RTX)
+    splay_tree_remove (pbi->reg_cond_dead, regno);
+  else
+    {
+      splay_tree_node node;
+      struct reg_cond_life_info *rcli;
+      rtx ncond;
+
+      /* Otherwise this is a conditional set.  Record that fact.
+        It may have been conditionally used, or there may be a
+        subsequent set with a complimentary condition.  */
+
+      node = splay_tree_lookup (pbi->reg_cond_dead, regno);
+      if (node == NULL)
+       {
+         /* The register was unconditionally live previously.
+            Record the current condition as the condition under
+            which it is dead.  */
+         rcli = (struct reg_cond_life_info *)
+           xmalloc (sizeof (*rcli));
+         rcli->condition = alloc_EXPR_LIST (0, cond, NULL_RTX);
+         splay_tree_insert (pbi->reg_cond_dead, regno,
+                            (splay_tree_value) rcli);
+
+         SET_REGNO_REG_SET (pbi->reg_cond_reg,
+                            REGNO (XEXP (cond, 0)));
+
+         /* Not unconditionaly dead.  */
+         return 0;
+       }
+      else
+       {
+         /* The register was conditionally live previously. 
+            Add the new condition to the old.  */
+         rcli = (struct reg_cond_life_info *) node->value;
+         ncond = rcli->condition;
+         ncond = ior_reg_cond (ncond, cond);
+
+         /* If the register is now unconditionally dead,
+            remove the entry in the splay_tree.  */
+         if (ncond == const1_rtx)
+           splay_tree_remove (pbi->reg_cond_dead, regno);
+         else
+           {
+             rcli->condition = ncond;
+
+             SET_REGNO_REG_SET (pbi->reg_cond_reg,
+                                REGNO (XEXP (cond, 0)));
+
+             /* Not unconditionaly dead.  */
+             return 0;
+           }
+       }
+    }
+
+  return 1;
+}
+
+/* Called from splay_tree_delete for pbi->reg_cond_life.  */
+
+static void
+free_reg_cond_life_info (value)
+     splay_tree_value value;
+{
+  struct reg_cond_life_info *rcli = (struct reg_cond_life_info *) value;
+  free_EXPR_LIST_list (&rcli->condition);
+  free (rcli);
+}
+
+/* Helper function for flush_reg_cond_reg.  */
+
+static int
+flush_reg_cond_reg_1 (node, data)
+     splay_tree_node node;
+     void *data;
+{
+  struct reg_cond_life_info *rcli;
+  int *xdata = (int *) data;
+  unsigned int regno = xdata[0];
+  rtx c, *prev;
+
+  /* Don't need to search if last flushed value was farther on in
+     the in-order traversal.  */
+  if (xdata[1] >= (int) node->key)
+    return 0;
+
+  /* Splice out portions of the expression that refer to regno.  */
+  rcli = (struct reg_cond_life_info *) node->value;
+  c = *(prev = &rcli->condition);
+  while (c)
+    {
+      if (regno == REGNO (XEXP (XEXP (c, 0), 0)))
+       {
+         rtx next = XEXP (c, 1);
+         free_EXPR_LIST_node (c);
+         c = *prev = next;
+       }
+      else
+       c = *(prev = &XEXP (c, 1));
+    }
+
+  /* If the entire condition is now NULL, signal the node to be removed.  */
+  if (! rcli->condition)
+    {
+      xdata[1] = node->key;
+      return -1;
+    }
+  else
+    return 0;
+}
+
+/* Flush all (sub) expressions referring to REGNO from REG_COND_LIVE.  */
+
+static void
+flush_reg_cond_reg (pbi, regno)
+     struct propagate_block_info *pbi;
+     int regno;
+{
+  int pair[2];
+
+  pair[0] = regno;
+  pair[1] = -1;
+  while (splay_tree_foreach (pbi->reg_cond_dead,
+                            flush_reg_cond_reg_1, pair) == -1)
+    splay_tree_remove (pbi->reg_cond_dead, pair[1]);
+
+  CLEAR_REGNO_REG_SET (pbi->reg_cond_reg, regno);
+}
+
+/* Logical arithmetic on predicate conditions.  IOR, NOT and NAND.
+   We actually use EXPR_LIST to chain the sub-expressions together
+   instead of IOR because it's easier to manipulate and we have 
+   the lists.c functions to reuse nodes.
+   
+   Return a new rtl expression as appropriate.  */
+
+static rtx
+ior_reg_cond (old, x)
+     rtx old, x;
+{
+  enum rtx_code x_code;
+  rtx x_reg;
+  rtx c;
+
+  /* We expect these conditions to be of the form (eq reg 0).  */
+  x_code = GET_CODE (x);
+  if (GET_RTX_CLASS (x_code) != '<'
+      || GET_CODE (x_reg = XEXP (x, 0)) != REG
+      || XEXP (x, 1) != const0_rtx)
+    abort ();
+
+  /* Search the expression for an existing sub-expression of X_REG.  */
+  for (c = old; c ; c = XEXP (c, 1))
+    {
+      rtx y = XEXP (c, 0);
+      if (REGNO (XEXP (y, 0)) == REGNO (x_reg))
+       {
+         /* If we find X already present in OLD, we need do nothing.  */
+         if (GET_CODE (y) == x_code)
+           return old;
+
+         /* If we find X being a compliment of a condition in OLD, 
+            then the entire condition is true.  */
+         if (GET_CODE (y) == reverse_condition (x_code))
+           return const1_rtx;
+       }
+    }
+
+  /* Otherwise just add to the chain.  */
+  return alloc_EXPR_LIST (0, x, old);
+}
+
+static rtx
+not_reg_cond (x)
+     rtx x;
+{
+  enum rtx_code x_code;
+  rtx x_reg;
+
+  /* We expect these conditions to be of the form (eq reg 0).  */
+  x_code = GET_CODE (x);
+  if (GET_RTX_CLASS (x_code) != '<'
+      || GET_CODE (x_reg = XEXP (x, 0)) != REG
+      || XEXP (x, 1) != const0_rtx)
+    abort ();
+
+  return alloc_EXPR_LIST (0, gen_rtx_fmt_ee (reverse_condition (x_code),
+                                            VOIDmode, x_reg, const0_rtx),
+                         NULL_RTX);
+}
+
+static rtx
+nand_reg_cond (old, x)
+     rtx old, x;
+{
+  enum rtx_code x_code;
+  rtx x_reg;
+  rtx c, *prev;
+
+  /* We expect these conditions to be of the form (eq reg 0).  */
+  x_code = GET_CODE (x);
+  if (GET_RTX_CLASS (x_code) != '<'
+      || GET_CODE (x_reg = XEXP (x, 0)) != REG
+      || XEXP (x, 1) != const0_rtx)
+    abort ();
+
+  /* Search the expression for an existing sub-expression of X_REG.  */
+
+  for (c = *(prev = &old); c ; c = *(prev = &XEXP (c, 1)))
+    {
+      rtx y = XEXP (c, 0);
+      if (REGNO (XEXP (y, 0)) == REGNO (x_reg))
+       {
+         /* If we find X already present in OLD, then we need to 
+            splice it out.  */
+         if (GET_CODE (y) == x_code)
+           {
+             *prev = XEXP (c, 1);
+             free_EXPR_LIST_node (c);
+             return old ? old : const0_rtx;
+           }
+
+         /* If we find X being a compliment of a condition in OLD, 
+            then we need do nothing.  */
+         if (GET_CODE (y) == reverse_condition (x_code))
+           return old;
+       }
+    }
+
+  /* Otherwise, by implication, the register in question is now live for
+     the inverse of the condition X.  */
+  return alloc_EXPR_LIST (0, gen_rtx_fmt_ee (reverse_condition (x_code),
+                                            VOIDmode, x_reg, const0_rtx),
+                         old);
+}
+#endif /* HAVE_conditional_execution */
+\f
 #ifdef AUTO_INC_DEC
 
 /* X is a MEM found in INSN.  See if we can convert it into an auto-increment
    reference.  */
 
 static void
-find_auto_inc (needed, x, insn)
-     regset needed;
+find_auto_inc (pbi, x, insn)
+     struct propagate_block_info *pbi;
      rtx x;
      rtx insn;
 {
@@ -4151,7 +4690,7 @@ find_auto_inc (needed, x, insn)
       int regno = REGNO (addr);
 
       /* Is the next use an increment that might make auto-increment? */
-      if ((incr = reg_next_use[regno]) != 0
+      if ((incr = pbi->reg_next_use[regno]) != 0
          && (set = single_set (incr)) != 0
          && GET_CODE (set) == SET
          && BLOCK_NUM (incr) == BLOCK_NUM (insn)
@@ -4178,7 +4717,10 @@ find_auto_inc (needed, x, insn)
                                    ? (offset ? PRE_INC : POST_INC)
                                    : (offset ? PRE_DEC : POST_DEC));
 
-         if (dead_or_set_p (incr, addr))
+         if (dead_or_set_p (incr, addr)
+             /* Mustn't autoinc an eliminable register.  */
+             && (regno >= FIRST_PSEUDO_REGISTER
+                 || ! TEST_HARD_REG_BIT (elim_reg_set, regno)))
            {
              /* This is the simple case.  Try to make the auto-inc.  If
                 we can't, we are done.  Otherwise, we will do any
@@ -4203,16 +4745,15 @@ find_auto_inc (needed, x, insn)
                 Change it to q = p, ...*q..., q = q+size.
                 Then fall into the usual case.  */
              rtx insns, temp;
-             basic_block bb;
 
              start_sequence ();
              emit_move_insn (q, addr);
              insns = get_insns ();
              end_sequence ();
 
-             bb = BLOCK_FOR_INSN (insn);
-             for (temp = insns; temp; temp = NEXT_INSN (temp))
-               set_block_for_insn (temp, bb);
+             if (basic_block_for_insn)
+               for (temp = insns; temp; temp = NEXT_INSN (temp))
+                 set_block_for_insn (temp, pbi->bb);
 
              /* If we can't make the auto-inc, or can't make the
                 replacement into Y, exit.  There's no point in making
@@ -4230,8 +4771,8 @@ find_auto_inc (needed, x, insn)
                 new insn(s) and do the updates.  */
              emit_insns_before (insns, insn);
 
-             if (BLOCK_FOR_INSN (insn)->head == insn)
-               BLOCK_FOR_INSN (insn)->head = insns;
+             if (pbi->bb->head == insn)
+               pbi->bb->head = insns;
 
              /* INCR will become a NOTE and INSN won't contain a
                 use of ADDR.  If a use of ADDR was just placed in
@@ -4240,18 +4781,18 @@ find_auto_inc (needed, x, insn)
              if (GET_CODE (PREV_INSN (insn)) == INSN
                  && GET_CODE (PATTERN (PREV_INSN (insn))) == SET
                  && SET_SRC (PATTERN (PREV_INSN (insn))) == addr)
-               reg_next_use[regno] = PREV_INSN (insn);
+               pbi->reg_next_use[regno] = PREV_INSN (insn);
              else
-               reg_next_use[regno] = 0;
+               pbi->reg_next_use[regno] = 0;
 
              addr = q;
              regno = REGNO (q);
 
-             /* REGNO is now used in INCR which is below INSN, but
-                it previously wasn't live here.  If we don't mark
-                it as needed, we'll put a REG_DEAD note for it
-                on this insn, which is incorrect.  */
-             SET_REGNO_REG_SET (needed, regno);
+             /* REGNO is now used in INCR which is below INSN, but it
+                previously wasn't live here.  If we don't mark it as
+                live, we'll put a REG_DEAD note for it on this insn,
+                which is incorrect.  */
+             SET_REGNO_REG_SET (pbi->reg_live, regno);
 
              /* If there are any calls between INSN and INCR, show
                 that REGNO now crosses them.  */
@@ -4279,6 +4820,11 @@ find_auto_inc (needed, x, insn)
             register.  */
          if (SET_DEST (set) == addr)
            {
+             /* If the original source was dead, it's dead now.  */
+             rtx note = find_reg_note (incr, REG_DEAD, NULL_RTX);
+             if (note && XEXP (note, 0) != addr)
+               CLEAR_REGNO_REG_SET (pbi->reg_live, REGNO (XEXP (note, 0)));
+             
              PUT_CODE (incr, NOTE);
              NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (incr) = 0;
@@ -4289,7 +4835,7 @@ find_auto_inc (needed, x, insn)
              /* Count an extra reference to the reg.  When a reg is
                 incremented, spilling it is worse, so we want to make
                 that less likely.  */
-             REG_N_REFS (regno) += loop_depth + 1;
+             REG_N_REFS (regno) += pbi->bb->loop_depth + 1;
 
              /* Count the increment as a setting of the register,
                 even though it isn't a SET in rtl.  */
@@ -4300,26 +4846,207 @@ find_auto_inc (needed, x, insn)
 }
 #endif /* AUTO_INC_DEC */
 \f
-/* Scan expression X and store a 1-bit in LIVE for each reg it uses.
-   This is done assuming the registers needed from X
-   are those that have 1-bits in NEEDED.
+static void
+mark_used_reg (pbi, reg, cond, insn)
+     struct propagate_block_info *pbi;
+     rtx reg;
+     rtx cond ATTRIBUTE_UNUSED;
+     rtx insn;
+{
+  int regno = REGNO (reg);
+  int some_was_live = REGNO_REG_SET_P (pbi->reg_live, regno);
+  int some_was_dead = ! some_was_live;
+  int some_not_set;
+  int n;
 
-   FLAGS is the set of enabled operations.
+  /* A hard reg in a wide mode may really be multiple registers.
+     If so, mark all of them just like the first.  */
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (--n > 0)
+       {
+         int needed_regno = REGNO_REG_SET_P (pbi->reg_live, regno + n);
+         some_was_live |= needed_regno;
+         some_was_dead |= ! needed_regno;
+       }
+    }
 
-   INSN is the containing instruction.  If INSN is dead, this function is not
-   called.  */
+  if (pbi->flags & (PROP_LOG_LINKS | PROP_AUTOINC))
+    {
+      /* Record where each reg is used, so when the reg is set we know
+        the next insn that uses it.  */
+      pbi->reg_next_use[regno] = insn;
+    }
+
+  if (pbi->flags & PROP_REG_INFO)
+    {
+      if (regno < FIRST_PSEUDO_REGISTER)
+       {
+         /* If this is a register we are going to try to eliminate,
+            don't mark it live here.  If we are successful in
+            eliminating it, it need not be live unless it is used for
+            pseudos, in which case it will have been set live when it
+            was allocated to the pseudos.  If the register will not
+            be eliminated, reload will set it live at that point.
+
+            Otherwise, record that this function uses this register.  */
+         /* ??? The PPC backend tries to "eliminate" on the pic
+            register to itself.  This should be fixed.  In the mean
+            time, hack around it.  */
+
+         if (! (TEST_HARD_REG_BIT (elim_reg_set, regno)
+                && (regno == FRAME_POINTER_REGNUM
+                    || regno == ARG_POINTER_REGNUM)))
+           {
+             int n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+             do
+               regs_ever_live[regno + --n] = 1;
+             while (n > 0);
+           }
+       }
+      else
+       {
+         /* Keep track of which basic block each reg appears in.  */
+
+         register int blocknum = pbi->bb->index;
+         if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
+           REG_BASIC_BLOCK (regno) = blocknum;
+         else if (REG_BASIC_BLOCK (regno) != blocknum)
+           REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
+
+         /* Count (weighted) number of uses of each reg.  */
+         REG_N_REFS (regno) += pbi->bb->loop_depth + 1;
+       }
+    }
+
+  /* Find out if any of the register was set this insn.  */
+  some_not_set = ! REGNO_REG_SET_P (pbi->new_set, regno);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (--n > 0)
+       some_not_set |= ! REGNO_REG_SET_P (pbi->new_set, regno + n);
+    }
+
+  /* Record and count the insns in which a reg dies.  If it is used in
+     this insn and was dead below the insn then it dies in this insn.
+     If it was set in this insn, we do not make a REG_DEAD note;
+     likewise if we already made such a note.  */
+  if ((pbi->flags & (PROP_DEATH_NOTES | PROP_REG_INFO))
+      && some_was_dead
+      && some_not_set)
+    {
+      /* Check for the case where the register dying partially
+        overlaps the register set by this insn.  */
+      if (regno < FIRST_PSEUDO_REGISTER
+         && HARD_REGNO_NREGS (regno, GET_MODE (reg)) > 1)
+       {
+         n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+         while (--n >= 0)
+           some_was_live |= REGNO_REG_SET_P (pbi->new_set, regno + n);
+       }
+
+      /* If none of the words in X is needed, make a REG_DEAD note.
+        Otherwise, we must make partial REG_DEAD notes.  */
+      if (! some_was_live)
+       {
+         if ((pbi->flags & PROP_DEATH_NOTES)
+             && ! find_regno_note (insn, REG_DEAD, regno))
+           REG_NOTES (insn)
+             = alloc_EXPR_LIST (REG_DEAD, reg, REG_NOTES (insn));
+
+         if (pbi->flags & PROP_REG_INFO)
+           REG_N_DEATHS (regno)++;
+       }
+      else
+       {
+         /* Don't make a REG_DEAD note for a part of a register
+            that is set in the insn.  */
+
+         n = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
+         for (; n >= regno; n--)
+           if (! REGNO_REG_SET_P (pbi->reg_live, n)
+               && ! dead_or_set_regno_p (insn, n))
+             REG_NOTES (insn)
+               = alloc_EXPR_LIST (REG_DEAD,
+                                  gen_rtx_REG (reg_raw_mode[n], n),
+                                  REG_NOTES (insn));
+       }
+    }
+
+  SET_REGNO_REG_SET (pbi->reg_live, regno);
+  if (regno < FIRST_PSEUDO_REGISTER)
+    {
+      n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (--n > 0)
+       SET_REGNO_REG_SET (pbi->reg_live, regno + n);
+    }
+
+#ifdef HAVE_conditional_execution
+  /* If this is a conditional use, record that fact.  If it is later
+     conditionally set, we'll know to kill the register.  */
+  if (cond != NULL_RTX)
+    {
+      splay_tree_node node;
+      struct reg_cond_life_info *rcli;
+      rtx ncond;
+
+      if (some_was_live)
+       {
+         node = splay_tree_lookup (pbi->reg_cond_dead, regno);
+         if (node == NULL)
+           {
+             /* The register was unconditionally live previously.
+                No need to do anything.  */
+           }
+         else
+           {
+             /* The register was conditionally live previously. 
+                Subtract the new life cond from the old death cond.  */
+             rcli = (struct reg_cond_life_info *) node->value;
+             ncond = rcli->condition;
+             ncond = nand_reg_cond (ncond, cond);
+
+             /* If the register is now unconditionally live, remove the
+                entry in the splay_tree.  */
+             if (ncond == const0_rtx)
+               {
+                 rcli->condition = NULL_RTX;
+                 splay_tree_remove (pbi->reg_cond_dead, regno);
+               }
+             else
+               rcli->condition = ncond;
+           }
+       }
+      else
+       {
+         /* The register was not previously live at all.  Record
+            the condition under which it is still dead.  */
+         rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
+         rcli->condition = not_reg_cond (cond);
+         splay_tree_insert (pbi->reg_cond_dead, regno,
+                            (splay_tree_value) rcli);
+       }
+    }
+#endif
+}
+
+/* Scan expression X and store a 1-bit in NEW_LIVE for each reg it uses.
+   This is done assuming the registers needed from X are those that
+   have 1-bits in PBI->REG_LIVE.
+
+   INSN is the containing instruction.  If INSN is dead, this function
+   is not called.  */
 
 static void
-mark_used_regs (needed, live, x, flags, insn)
-     regset needed;
-     regset live;
-     rtx x;
-     int flags;
-     rtx insn;
+mark_used_regs (pbi, x, cond, insn)
+     struct propagate_block_info *pbi;
+     rtx x, cond, insn;
 {
   register RTX_CODE code;
   register int regno;
-  int i;
+  int flags = pbi->flags;
 
  retry:
   code = GET_CODE (x);
@@ -4337,7 +5064,7 @@ mark_used_regs (needed, live, x, flags, insn)
 
 #ifdef HAVE_cc0
     case CC0:
-      cc0_live = 1;
+      pbi->cc0_live = 1;
       return;
 #endif
 
@@ -4345,7 +5072,7 @@ mark_used_regs (needed, live, x, flags, insn)
       /* If we are clobbering a MEM, mark any registers inside the address
         as being used.  */
       if (GET_CODE (XEXP (x, 0)) == MEM)
-       mark_used_regs (needed, live, XEXP (XEXP (x, 0), 0), flags, insn);
+       mark_used_regs (pbi, XEXP (XEXP (x, 0), 0), cond, insn);
       return;
 
     case MEM:
@@ -4360,7 +5087,7 @@ mark_used_regs (needed, live, x, flags, insn)
            ; /* needn't clear the memory set list */
           else
            {
-             rtx temp = mem_set_list;
+             rtx temp = pbi->mem_set_list;
              rtx prev = NULL_RTX;
              rtx next;
 
@@ -4373,7 +5100,7 @@ mark_used_regs (needed, live, x, flags, insn)
                      if (prev)
                        XEXP (prev, 1) = next;
                      else
-                       mem_set_list = next;
+                       pbi->mem_set_list = next;
                      free_EXPR_LIST_node (temp);
                    }
                  else
@@ -4386,12 +5113,12 @@ mark_used_regs (needed, live, x, flags, insn)
             address modes.  Then we may need to kill some entries on the
             memory set list.  */
          if (insn)
-           invalidate_mems_from_autoinc (insn);
+           invalidate_mems_from_autoinc (pbi, insn);
        }
 
 #ifdef AUTO_INC_DEC
       if (flags & PROP_AUTOINC)
-        find_auto_inc (needed, x, insn);
+        find_auto_inc (pbi, x, insn);
 #endif
       break;
 
@@ -4404,169 +5131,13 @@ mark_used_regs (needed, live, x, flags, insn)
 
       /* While we're here, optimize this case.  */
       x = SUBREG_REG (x);
-
-      /* In case the SUBREG is not of a register, don't optimize */
       if (GET_CODE (x) != REG)
-       {
-         mark_used_regs (needed, live, x, flags, insn);
-         return;
-       }
-
-      /* ... fall through ...  */
+       goto retry;
+      /* FALLTHRU */
 
     case REG:
-      /* See a register other than being set
-        => mark it as needed.  */
-
-      regno = REGNO (x);
-      {
-       int some_needed = REGNO_REG_SET_P (needed, regno);
-       int some_not_needed = ! some_needed;
-
-       SET_REGNO_REG_SET (live, regno);
-
-       /* A hard reg in a wide mode may really be multiple registers.
-          If so, mark all of them just like the first.  */
-       if (regno < FIRST_PSEUDO_REGISTER)
-         {
-           int n;
-
-           /* For stack ptr or fixed arg pointer,
-              nothing below can be necessary, so waste no more time.  */
-           if (regno == STACK_POINTER_REGNUM
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-               || (regno == HARD_FRAME_POINTER_REGNUM
-                   && (! reload_completed || frame_pointer_needed))
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-               || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
-#endif
-               || (regno == FRAME_POINTER_REGNUM
-                   && (! reload_completed || frame_pointer_needed)))
-             {
-               /* If this is a register we are going to try to eliminate,
-                  don't mark it live here.  If we are successful in
-                  eliminating it, it need not be live unless it is used for
-                  pseudos, in which case it will have been set live when
-                  it was allocated to the pseudos.  If the register will not
-                  be eliminated, reload will set it live at that point.  */
-
-               if (! TEST_HARD_REG_BIT (elim_reg_set, regno))
-                 regs_ever_live[regno] = 1;
-               return;
-             }
-           /* No death notes for global register variables;
-              their values are live after this function exits.  */
-           if (global_regs[regno])
-             {
-               if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-                 reg_next_use[regno] = insn;
-               return;
-             }
-
-           n = HARD_REGNO_NREGS (regno, GET_MODE (x));
-           while (--n > 0)
-             {
-               int regno_n = regno + n;
-               int needed_regno = REGNO_REG_SET_P (needed, regno_n);
-
-               SET_REGNO_REG_SET (live, regno_n);
-               some_needed |= needed_regno;
-               some_not_needed |= ! needed_regno;
-             }
-         }
-
-       if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
-         {
-           /* Record where each reg is used, so when the reg
-              is set we know the next insn that uses it.  */
-
-           reg_next_use[regno] = insn;
-         }
-       if (flags & PROP_REG_INFO)
-         {
-           if (regno < FIRST_PSEUDO_REGISTER)
-             {
-               /* If a hard reg is being used,
-                  record that this function does use it.  */
-
-               i = HARD_REGNO_NREGS (regno, GET_MODE (x));
-               if (i == 0)
-                 i = 1;
-               do
-                 regs_ever_live[regno + --i] = 1;
-               while (i > 0);
-             }
-           else
-             {
-               /* Keep track of which basic block each reg appears in.  */
-
-               register int blocknum = BLOCK_NUM (insn);
-
-               if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
-                 REG_BASIC_BLOCK (regno) = blocknum;
-               else if (REG_BASIC_BLOCK (regno) != blocknum)
-                 REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
-
-               /* Count (weighted) number of uses of each reg.  */
-
-               REG_N_REFS (regno) += loop_depth + 1;
-             }
-         }
-
-       /* Record and count the insns in which a reg dies.
-          If it is used in this insn and was dead below the insn
-          then it dies in this insn.  If it was set in this insn,
-          we do not make a REG_DEAD note; likewise if we already
-          made such a note.  */
-
-       if (flags & PROP_DEATH_NOTES)
-         {
-           if (some_not_needed
-               && ! dead_or_set_p (insn, x)
-#if 0
-               && (regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno])
-#endif
-               )
-             {
-               /* Check for the case where the register dying partially
-                  overlaps the register set by this insn.  */
-               if (regno < FIRST_PSEUDO_REGISTER
-                   && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
-                 {
-                   int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
-                   while (--n >= 0)
-                     some_needed |= dead_or_set_regno_p (insn, regno + n);
-                 }
-
-               /* If none of the words in X is needed, make a REG_DEAD
-                  note.  Otherwise, we must make partial REG_DEAD notes.  */
-               if (! some_needed)
-                 {
-                   REG_NOTES (insn)
-                     = alloc_EXPR_LIST (REG_DEAD, x, REG_NOTES (insn));
-                   REG_N_DEATHS (regno)++;
-                 }
-               else
-                 {
-                   int i;
-
-                   /* Don't make a REG_DEAD note for a part of a register
-                      that is set in the insn.  */
-
-                   for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
-                        i >= 0; i--)
-                     if (!REGNO_REG_SET_P (needed, regno + i)
-                         && ! dead_or_set_regno_p (insn, regno + i))
-                       REG_NOTES (insn)
-                         = (alloc_EXPR_LIST
-                            (REG_DEAD, gen_rtx_REG (reg_raw_mode[regno + i],
-                                                    regno + i),
-                             REG_NOTES (insn)));
-                 }
-             }
-         }
-      }
+      /* See a register other than being set => mark it as needed.  */
+      mark_used_reg (pbi, x, cond, insn);
       return;
 
     case SET:
@@ -4580,10 +5151,10 @@ mark_used_regs (needed, live, x, flags, insn)
          {
 #ifdef AUTO_INC_DEC
            if (flags & PROP_AUTOINC)
-             find_auto_inc (needed, testreg, insn);
+             find_auto_inc (pbi, testreg, insn);
 #endif
-           mark_used_regs (needed, live, XEXP (testreg, 0), flags, insn);
-           mark_used_regs (needed, live, SET_SRC (x), flags, insn);
+           mark_used_regs (pbi, XEXP (testreg, 0), cond, insn);
+           mark_used_regs (pbi, SET_SRC (x), cond, insn);
            return;
          }
            
@@ -4618,14 +5189,15 @@ mark_used_regs (needed, live, x, flags, insn)
            testreg = XEXP (testreg, 0);
          }
 
-       /* If this is a store into a register,
-          recursively scan the value being stored.  */
+       /* If this is a store into a register, recursively scan the
+          value being stored.  */
 
        if ((GET_CODE (testreg) == PARALLEL
             && GET_MODE (testreg) == BLKmode)
            || (GET_CODE (testreg) == REG
-               && (regno = REGNO (testreg), ! (regno == FRAME_POINTER_REGNUM
-                                               && (! reload_completed || frame_pointer_needed)))
+               && (regno = REGNO (testreg),
+                   ! (regno == FRAME_POINTER_REGNUM
+                      && (! reload_completed || frame_pointer_needed)))
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
                && ! (regno == HARD_FRAME_POINTER_REGNUM
                      && (! reload_completed || frame_pointer_needed))
@@ -4634,12 +5206,10 @@ mark_used_regs (needed, live, x, flags, insn)
                && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
 #endif
                ))
-         /* We used to exclude global_regs here, but that seems wrong.
-            Storing in them is like storing in mem.  */
          {
-           mark_used_regs (needed, live, SET_SRC (x), flags, insn);
            if (mark_dest)
-             mark_used_regs (needed, live, SET_DEST (x), flags, insn);
+             mark_used_regs (pbi, SET_DEST (x), cond, insn);
+           mark_used_regs (pbi, SET_SRC (x), cond, insn);
            return;
          }
       }
@@ -4665,7 +5235,7 @@ mark_used_regs (needed, live, x, flags, insn)
           So for now, just clear the memory set list and mark any regs
           we can find in ASM_OPERANDS as used.  */
        if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
-         free_EXPR_LIST_list (&mem_set_list);
+         free_EXPR_LIST_list (&pbi->mem_set_list);
 
         /* For all ASM_OPERANDS, we must traverse the vector of input operands.
           We can not just fall through here since then we would be confused
@@ -4676,12 +5246,28 @@ mark_used_regs (needed, live, x, flags, insn)
            int j;
 
            for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
-             mark_used_regs (needed, live, ASM_OPERANDS_INPUT (x, j),
-                             flags, insn);
+             mark_used_regs (pbi, ASM_OPERANDS_INPUT (x, j), cond, insn);
          }
        break;
       }
 
+    case COND_EXEC:
+      if (cond != NULL_RTX)
+       abort ();
+
+      mark_used_regs (pbi, COND_EXEC_TEST (x), NULL_RTX, insn);
+
+      cond = COND_EXEC_TEST (x);
+      x = COND_EXEC_CODE (x);
+      goto retry;
+
+    case PHI:
+      /* We _do_not_ want to scan operands of phi nodes.  Operands of
+        a phi function are evaluated only when control reaches this
+        block along a particular edge.  Therefore, regs that appear
+        as arguments to phi should not be added to the global live at
+        start.  */
+      return;
 
     default:
       break;
@@ -4703,13 +5289,13 @@ mark_used_regs (needed, live, x, flags, insn)
                x = XEXP (x, 0);
                goto retry;
              }
-           mark_used_regs (needed, live, XEXP (x, i), flags, insn);
+           mark_used_regs (pbi, XEXP (x, i), cond, insn);
          }
        else if (fmt[i] == 'E')
          {
            register int j;
            for (j = 0; j < XVECLEN (x, i); j++)
-             mark_used_regs (needed, live, XVECEXP (x, i, j), flags, insn);
+             mark_used_regs (pbi, XVECEXP (x, i, j), cond, insn);
          }
       }
   }
@@ -4718,7 +5304,8 @@ mark_used_regs (needed, live, x, flags, insn)
 #ifdef AUTO_INC_DEC
 
 static int
-try_pre_increment_1 (insn)
+try_pre_increment_1 (pbi, insn)
+     struct propagate_block_info *pbi;
      rtx insn;
 {
   /* Find the next use of this reg.  If in same basic block,
@@ -4727,7 +5314,7 @@ try_pre_increment_1 (insn)
   HOST_WIDE_INT amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1)
                * INTVAL (XEXP (SET_SRC (x), 1)));
   int regno = REGNO (SET_DEST (x));
-  rtx y = reg_next_use[regno];
+  rtx y = pbi->reg_next_use[regno];
   if (y != 0
       && BLOCK_NUM (y) == BLOCK_NUM (insn)
       /* Don't do this if the reg dies, or gets set in y; a standard addressing
@@ -4747,7 +5334,7 @@ try_pre_increment_1 (insn)
         less likely.  */
       if (regno >= FIRST_PSEUDO_REGISTER)
        {
-         REG_N_REFS (regno) += loop_depth + 1;
+         REG_N_REFS (regno) += pbi->bb->loop_depth + 1;
          REG_N_SETS (regno)++;
        }
       return 1;
@@ -4904,6 +5491,35 @@ find_use_as_address (x, reg, plusconst)
    This is part of making a debugging dump.  */
 
 void
+dump_regset (r, outf)
+     regset r;
+     FILE *outf;
+{
+  int i;
+  if (r == NULL)
+    {
+      fputs (" (nil)", outf);
+      return;
+    }
+
+  EXECUTE_IF_SET_IN_REG_SET (r, 0, i,
+    {
+      fprintf (outf, " %d", i);
+      if (i < FIRST_PSEUDO_REGISTER)
+       fprintf (outf, " [%s]",
+                reg_names[i]);
+    });
+}
+
+void
+debug_regset (r)
+     regset r;
+{
+  dump_regset (r, stderr);
+  putc ('\n', stderr);
+}
+
+void
 dump_flow_info (file)
      FILE *file;
 {
@@ -4954,7 +5570,6 @@ dump_flow_info (file)
   for (i = 0; i < n_basic_blocks; i++)
     {
       register basic_block bb = BASIC_BLOCK (i);
-      register int regno;
       register edge e;
 
       fprintf (file, "\nBasic block %d: first insn %d, last %d, loop_depth %d.\n",
@@ -4969,24 +5584,10 @@ dump_flow_info (file)
        dump_edge_info (file, e, 1);
 
       fprintf (file, "\nRegisters live at start:");
-      if (bb->global_live_at_start)
-       {
-          for (regno = 0; regno < max_regno; regno++)
-           if (REGNO_REG_SET_P (bb->global_live_at_start, regno))
-             fprintf (file, " %d", regno);
-       }
-      else
-       fprintf (file, " n/a");
+      dump_regset (bb->global_live_at_start, file);
 
       fprintf (file, "\nRegisters live at end:");
-      if (bb->global_live_at_end)
-       {
-          for (regno = 0; regno < max_regno; regno++)
-           if (REGNO_REG_SET_P (bb->global_live_at_end, regno))
-             fprintf (file, " %d", regno);
-       }
-      else
-       fprintf (file, " n/a");
+      dump_regset (bb->global_live_at_end, file);
 
       putc('\n', file);
     }
@@ -5043,6 +5644,60 @@ 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;
+
+  fprintf (outf, ";; Basic block %d, loop depth %d",
+          bb->index, bb->loop_depth);
+  if (bb->eh_beg != -1 || bb->eh_end != -1)
+    fprintf (outf, ", eh regions %d/%d", bb->eh_beg, bb->eh_end);
+  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);
+}
+
 /* Like print_rtl, but also print out live information for the start of each
    basic block.  */
 
@@ -5095,14 +5750,7 @@ print_rtl_with_bb (outf, rtx_first)
            {
              fprintf (outf, ";; Start of basic block %d, registers live:",
                       bb->index);
-
-             EXECUTE_IF_SET_IN_REG_SET (bb->global_live_at_start, 0, i,
-                                        {
-                                          fprintf (outf, " %d", i);
-                                          if (i < FIRST_PSEUDO_REGISTER)
-                                            fprintf (outf, " [%s]",
-                                                     reg_names[i]);
-                                        });
+             dump_regset (bb->global_live_at_start, outf);
              putc ('\n', outf);
            }
 
@@ -5116,7 +5764,12 @@ print_rtl_with_bb (outf, rtx_first)
          did_output = print_rtl_single (outf, tmp_rtx);
 
          if ((bb = end[INSN_UID (tmp_rtx)]) != NULL)
-           fprintf (outf, ";; End of basic block %d\n", bb->index);
+           {
+             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);
@@ -5145,13 +5798,14 @@ compute_flow_dominators (dominators, post_dominators)
   int bb;
   sbitmap *temp_bitmap;
   edge e;
-  basic_block *worklist, *tos;
+  basic_block *worklist, *workend, *qin, *qout;
+  int qlen;
 
   /* Allocate a worklist array/queue.  Entries are only added to the
      list if they were not already on the list.  So the size is
      bounded by the number of basic blocks.  */
-  tos = worklist = (basic_block *) xmalloc (sizeof (basic_block)
-                   * n_basic_blocks);
+  worklist = (basic_block *) xmalloc (sizeof (basic_block) * n_basic_blocks);
+  workend = &worklist[n_basic_blocks];
 
   temp_bitmap = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
   sbitmap_vector_zero (temp_bitmap, n_basic_blocks);
@@ -5160,11 +5814,14 @@ compute_flow_dominators (dominators, post_dominators)
     {
       /* The optimistic setting of dominators requires us to put every
         block on the work list initially.  */
+      qin = qout = worklist;
       for (bb = 0; bb < n_basic_blocks; bb++)
        {
-         *tos++ = BASIC_BLOCK (bb);
+         *qin++ = BASIC_BLOCK (bb);
          BASIC_BLOCK (bb)->aux = BASIC_BLOCK (bb);
        }
+      qlen = n_basic_blocks;
+      qin = worklist;
 
       /* We want a maximal solution, so initially assume everything dominates
         everything else.  */
@@ -5175,10 +5832,14 @@ compute_flow_dominators (dominators, post_dominators)
        e->dest->aux = ENTRY_BLOCK_PTR;
 
       /* Iterate until the worklist is empty.  */
-      while (tos != worklist)
+      while (qlen)
        {
          /* Take the first entry off the worklist.  */
-         basic_block b = *--tos;
+         basic_block b = *qout++;
+         if (qout >= workend)
+           qout = worklist;
+         qlen--;
+
          bb = b->index;
 
          /* Compute the intersection of the dominators of all the
@@ -5218,7 +5879,11 @@ compute_flow_dominators (dominators, post_dominators)
                {
                  if (!e->dest->aux && e->dest != EXIT_BLOCK_PTR)
                    {
-                     *tos++ = e->dest;
+                     *qin++ = e->dest;
+                     if (qin >= workend)
+                       qin = worklist;
+                     qlen++;
+
                      e->dest->aux = e;
                    }
                }
@@ -5230,11 +5895,14 @@ compute_flow_dominators (dominators, post_dominators)
     {
       /* The optimistic setting of dominators requires us to put every
         block on the work list initially.  */
+      qin = qout = worklist;
       for (bb = 0; bb < n_basic_blocks; bb++)
        {
-         *tos++ = BASIC_BLOCK (bb);
+         *qin++ = BASIC_BLOCK (bb);
          BASIC_BLOCK (bb)->aux = BASIC_BLOCK (bb);
        }
+      qlen = n_basic_blocks;
+      qin = worklist;
 
       /* We want a maximal solution, so initially assume everything post
         dominates everything else.  */
@@ -5245,10 +5913,14 @@ compute_flow_dominators (dominators, post_dominators)
        e->src->aux = EXIT_BLOCK_PTR;
 
       /* Iterate until the worklist is empty.  */
-      while (tos != worklist)
+      while (qlen)
        {
          /* Take the first entry off the worklist.  */
-         basic_block b = *--tos;
+         basic_block b = *qout++;
+         if (qout >= workend)
+           qout = worklist;
+         qlen--;
+
          bb = b->index;
 
          /* Compute the intersection of the post dominators of all the
@@ -5291,13 +5963,19 @@ compute_flow_dominators (dominators, post_dominators)
                {
                  if (!e->src->aux && e->src != ENTRY_BLOCK_PTR)
                    {
-                     *tos++ = e->src;
+                     *qin++ = e->src;
+                     if (qin >= workend)
+                       qin = worklist;
+                     qlen++;
+
                      e->src->aux = e;
                    }
                }
            }
        }
     }
+
+  free (worklist);
   free (temp_bitmap);
 }
 
@@ -5341,205 +6019,6 @@ compute_immediate_dominators (idom, dominators)
   sbitmap_vector_free (tmp);
 }
 
-/* Count for a single SET rtx, X.  */
-
-static void
-count_reg_sets_1 (x)
-     rtx x;
-{
-  register int regno;
-  register rtx reg = SET_DEST (x);
-
-  /* Find the register that's set/clobbered.  */
-  while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
-        || GET_CODE (reg) == SIGN_EXTRACT
-        || GET_CODE (reg) == STRICT_LOW_PART)
-    reg = XEXP (reg, 0);
-
-  if (GET_CODE (reg) == PARALLEL
-      && GET_MODE (reg) == BLKmode)
-    {
-      register int i;
-      for (i = XVECLEN (reg, 0) - 1; i >= 0; i--)
-       count_reg_sets_1 (XVECEXP (reg, 0, i));
-      return;
-    }
-
-  if (GET_CODE (reg) == REG)
-    {
-      regno = REGNO (reg);
-      if (regno >= FIRST_PSEUDO_REGISTER)
-       {
-         /* Count (weighted) references, stores, etc.  This counts a
-            register twice if it is modified, but that is correct.  */
-         REG_N_SETS (regno)++;
-         REG_N_REFS (regno) += loop_depth + 1;
-       }
-    }
-}
-
-/* Increment REG_N_SETS for each SET or CLOBBER found in X; also increment
-   REG_N_REFS by the current loop depth for each SET or CLOBBER found.  */
-
-static void
-count_reg_sets  (x)
-     rtx x;
-{
-  register RTX_CODE code = GET_CODE (x);
-
-  if (code == SET || code == CLOBBER)
-    count_reg_sets_1 (x);
-  else if (code == PARALLEL)
-    {
-      register int i;
-      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-       {
-         code = GET_CODE (XVECEXP (x, 0, i));
-         if (code == SET || code == CLOBBER)
-           count_reg_sets_1 (XVECEXP (x, 0, i));
-       }
-    }
-}
-
-/* Increment REG_N_REFS by the current loop depth each register reference
-   found in X.  */
-
-static void
-count_reg_references (x)
-     rtx x;
-{
-  register RTX_CODE code;
-
- retry:
-  code = GET_CODE (x);
-  switch (code)
-    {
-    case LABEL_REF:
-    case SYMBOL_REF:
-    case CONST_INT:
-    case CONST:
-    case CONST_DOUBLE:
-    case PC:
-    case ADDR_VEC:
-    case ADDR_DIFF_VEC:
-    case ASM_INPUT:
-      return;
-
-#ifdef HAVE_cc0
-    case CC0:
-      return;
-#endif
-
-    case CLOBBER:
-      /* If we are clobbering a MEM, mark any registers inside the address
-        as being used.  */
-      if (GET_CODE (XEXP (x, 0)) == MEM)
-       count_reg_references (XEXP (XEXP (x, 0), 0));
-      return;
-
-    case SUBREG:
-      /* While we're here, optimize this case.  */
-      x = SUBREG_REG (x);
-
-      /* In case the SUBREG is not of a register, don't optimize */
-      if (GET_CODE (x) != REG)
-       {
-         count_reg_references (x);
-         return;
-       }
-
-      /* ... fall through ...  */
-
-    case REG:
-      if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
-       REG_N_REFS (REGNO (x)) += loop_depth + 1;
-      return;
-
-    case SET:
-      {
-       register rtx testreg = SET_DEST (x);
-       int mark_dest = 0;
-
-       /* If storing into MEM, don't show it as being used.  But do
-          show the address as being used.  */
-       if (GET_CODE (testreg) == MEM)
-         {
-           count_reg_references (XEXP (testreg, 0));
-           count_reg_references (SET_SRC (x));
-           return;
-         }
-           
-       /* Storing in STRICT_LOW_PART is like storing in a reg
-          in that this SET might be dead, so ignore it in TESTREG.
-          but in some other ways it is like using the reg.
-
-          Storing in a SUBREG or a bit field is like storing the entire
-          register in that if the register's value is not used
-          then this SET is not needed.  */
-       while (GET_CODE (testreg) == STRICT_LOW_PART
-              || GET_CODE (testreg) == ZERO_EXTRACT
-              || GET_CODE (testreg) == SIGN_EXTRACT
-              || GET_CODE (testreg) == SUBREG)
-         {
-           /* Modifying a single register in an alternate mode
-              does not use any of the old value.  But these other
-              ways of storing in a register do use the old value.  */
-           if (GET_CODE (testreg) == SUBREG
-               && !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg)))
-             ;
-           else
-             mark_dest = 1;
-
-           testreg = XEXP (testreg, 0);
-         }
-
-       /* If this is a store into a register,
-          recursively scan the value being stored.  */
-
-       if ((GET_CODE (testreg) == PARALLEL
-            && GET_MODE (testreg) == BLKmode)
-           || GET_CODE (testreg) == REG)
-         {
-           count_reg_references (SET_SRC (x));
-           if (mark_dest)
-             count_reg_references (SET_DEST (x));
-           return;
-         }
-      }
-      break;
-
-    default:
-      break;
-    }
-
-  /* Recursively scan the operands of this expression.  */
-
-  {
-    register const char *fmt = GET_RTX_FORMAT (code);
-    register int i;
-    
-    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-      {
-       if (fmt[i] == 'e')
-         {
-           /* Tail recursive case: save a function call level.  */
-           if (i == 0)
-             {
-               x = XEXP (x, 0);
-               goto retry;
-             }
-           count_reg_references (XEXP (x, i));
-         }
-       else if (fmt[i] == 'E')
-         {
-           register int j;
-           for (j = 0; j < XVECLEN (x, i); j++)
-             count_reg_references (XVECEXP (x, i, j));
-         }
-      }
-  }
-}
-
 /* Recompute register set/reference counts immediately prior to register
    allocation.
 
@@ -5564,67 +6043,8 @@ recompute_reg_usage (f, loop_step)
      rtx f ATTRIBUTE_UNUSED;
      int loop_step ATTRIBUTE_UNUSED;
 {
-  rtx insn;
-  int i, max_reg;
-  int index;
-
-  /* Clear out the old data.  */
-  max_reg = max_reg_num ();
-  for (i = FIRST_PSEUDO_REGISTER; i < max_reg; i++)
-    {
-      REG_N_SETS (i) = 0;
-      REG_N_REFS (i) = 0;
-    }
-
-  /* Scan each insn in the chain and count how many times each register is
-     set/used.  */
-  for (index = 0; index < n_basic_blocks; index++)
-    {
-      basic_block bb = BASIC_BLOCK (index);
-      loop_depth = bb->loop_depth;
-      for (insn = bb->head; insn; insn = NEXT_INSN (insn))
-       {
-         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-           {
-             rtx links;
-
-             /* This call will increment REG_N_SETS for each SET or CLOBBER
-                of a register in INSN.  It will also increment REG_N_REFS
-                by the loop depth for each set of a register in INSN.  */
-             count_reg_sets (PATTERN (insn));
-
-             /* count_reg_sets does not detect autoincrement address modes, so
-                detect them here by looking at the notes attached to INSN.  */
-             for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
-               {
-                 if (REG_NOTE_KIND (links) == REG_INC)
-                   /* Count (weighted) references, stores, etc.  This counts a
-                      register twice if it is modified, but that is correct.  */
-                   REG_N_SETS (REGNO (XEXP (links, 0)))++;
-               }
-
-             /* This call will increment REG_N_REFS by the current loop depth for
-                each reference to a register in INSN.  */
-             count_reg_references (PATTERN (insn));
-
-             /* count_reg_references will not include counts for arguments to
-                function calls, so detect them here by examining the
-                CALL_INSN_FUNCTION_USAGE data.  */
-             if (GET_CODE (insn) == CALL_INSN)
-               {
-                 rtx note;
-
-                 for (note = CALL_INSN_FUNCTION_USAGE (insn);
-                      note;
-                      note = XEXP (note, 1))
-                   if (GET_CODE (XEXP (note, 0)) == USE)
-                     count_reg_references (XEXP (XEXP (note, 0), 0));
-               }
-           }
-         if (insn == bb->end)
-           break;
-       }
-    }
+  allocate_reg_life_data ();
+  update_life_info (NULL, UPDATE_LIFE_LOCAL, PROP_REG_INFO);
 }
 
 /* Optionally removes all the REG_DEAD and REG_UNUSED notes from a set of
@@ -5745,6 +6165,7 @@ set_block_num (insn, bb)
      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.).  */
@@ -5948,6 +6369,12 @@ verify_flow_info ()
            }
        }
 
+      if (GET_RTX_CLASS (GET_CODE (x)) == 'i'
+         && 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);
     }
 
@@ -6717,41 +7144,35 @@ flow_loop_pre_header_find (header, dom)
 }
 
 
-/* Add LOOP to the loop hierarchy tree so that it is a sibling or a
-   descendant of ROOT.  */
+/* Add LOOP to the loop hierarchy tree where PREVLOOP was the loop
+   previously added.  The insertion algorithm assumes that the loops
+   are added in the order found by a depth first search of the CFG.  */
 static void
-flow_loop_tree_node_add (root, loop)
-     struct loop *root;
+flow_loop_tree_node_add (prevloop, loop)
+     struct loop *prevloop;
      struct loop *loop;
 {
-  struct loop *outer;
 
-  if (! loop)
-    return;
+  if (flow_loop_nested_p (prevloop, loop))
+    {
+      prevloop->inner = loop;
+      loop->outer = prevloop;
+      return;
+    }
 
-  for (outer = root; outer; outer = outer->next)
+  while (prevloop->outer)
     {
-      if (flow_loop_nested_p (outer, loop))
+      if (flow_loop_nested_p (prevloop->outer, loop))
        {
-         if (outer->inner)
-           {
-             /* Add LOOP as a sibling or descendent of OUTER->INNER.  */
-             flow_loop_tree_node_add (outer->inner, loop);
-           }
-         else
-           {
-             /* Add LOOP as child of OUTER.  */
-             outer->inner = loop;
-             loop->outer = outer;
-             loop->next = NULL;
-           }
+         prevloop->next = loop;
+         loop->outer = prevloop->outer;
          return;
        }
+      prevloop = prevloop->outer;
     }
-  /* Add LOOP as a sibling of ROOT.  */
-  loop->next = root->next;
-  root->next = loop;
-  loop->outer = root->outer;
+  
+  prevloop->next = loop;
+  loop->outer = NULL;
 }
 
 
@@ -6775,7 +7196,7 @@ flow_loops_tree_build (loops)
 
   /* Add the remaining loops to the tree.  */
   for (i = 1; i < num_loops; i++)
-    flow_loop_tree_node_add (loops->tree, &loops->array[i]);
+    flow_loop_tree_node_add (&loops->array[i - 1], &loops->array[i]);
 }
 
 
@@ -7013,3 +7434,15 @@ flow_loop_outside_edge_p (loop, e)
   return (e->src == ENTRY_BLOCK_PTR)
     || ! TEST_BIT (loop->nodes, e->src->index);
 }
+
+
+/* Clear LOG_LINKS fields of insns in a chain.  */
+void
+clear_log_links (insns)
+     rtx insns;
+{
+  rtx i;
+  for (i = insns; i; i = NEXT_INSN (i))
+    if (GET_RTX_CLASS (GET_CODE (i)) == 'i')
+      LOG_LINKS (i) = 0;
+}