OSDN Git Service

(OBJC_ERR_BAD_STATE): New error code.
[pf3gnuchains/gcc-fork.git] / gcc / flow.c
index 74695a7..0689d60 100644 (file)
@@ -1,5 +1,5 @@
 /* Data flow analysis for GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file contains the data flow analysis pass of the compiler.
@@ -116,11 +117,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "output.h"
+#include "except.h"
 
 #include "obstack.h"
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
+/* The contents of the current function definition are allocated
+   in this obstack, and all are freed at the end of the function.
+   For top-level functions, this is temporary_obstack.
+   Separate obstacks are made for nested functions.  */
+
+extern struct obstack *function_obstack;
+
 /* List of labels that must never be deleted.  */
 extern rtx forced_labels;
 
@@ -153,7 +162,8 @@ int n_basic_blocks;
 
 int max_regno;
 
-/* Maximum number of SCRATCH rtx's used in any basic block of this function. */
+/* Maximum number of SCRATCH rtx's used in any basic block of this
+   function.  */
 
 int max_scratch;
 
@@ -161,50 +171,9 @@ int max_scratch;
 
 static int num_scratch;
 
-/* Indexed by n, gives number of basic block that  (REG n) is used in.
-   If the value is REG_BLOCK_GLOBAL (-2),
-   it means (REG n) is used in more than one basic block.
-   REG_BLOCK_UNKNOWN (-1) means it hasn't been seen yet so we don't know.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.  */
-
-int *reg_basic_block;
-
-/* Indexed by n, gives number of times (REG n) is used or set, each
-   weighted by its loop-depth.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.  */
-
-int *reg_n_refs;
-
-/* Indexed by N, gives number of places register N dies.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.  */
-
-short *reg_n_deaths;
-
-/* Indexed by N, gives 1 if that reg is live across any CALL_INSNs.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.  */
-
-int *reg_n_calls_crossed;
-
-/* Total number of instructions at which (REG n) is live.
-   The larger this is, the less priority (REG n) gets for
-   allocation in a real register.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.
-
-   local-alloc.c may alter this number to change the priority.
-
-   Negative values are special.
-   -1 is used to mark a pseudo reg which has a constant or memory equivalent
-   and is used infrequently enough that it should not get a hard register.
-   -2 is used to mark a pseudo reg for a parameter, when a frame pointer
-   is not required.  global.c makes an allocno for this but does
-   not try to assign a hard register to it.  */
+/* Indexed by n, giving various register information */
 
-int *reg_live_length;
+reg_info *reg_n_info;
 
 /* 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.
@@ -280,13 +249,14 @@ static HARD_REG_SET elim_reg_set;
 
 /* Forward declarations */
 static void find_basic_blocks          PROTO((rtx, rtx));
-static int uses_reg_or_mem             PROTO((rtx));
+static int jmp_uses_reg_or_mem         PROTO((rtx));
 static void mark_label_ref             PROTO((rtx, rtx, int));
 static void life_analysis              PROTO((rtx, int));
 void allocate_for_life_analysis                PROTO((void));
-static void init_regset_vector         PROTO((regset *, regset, int, int));
+static void init_regset_vector         PROTO((regset *, int, int, struct obstack *));
 static void propagate_block            PROTO((regset, rtx, rtx, int, 
                                               regset, int));
+static rtx flow_delete_insn            PROTO((rtx));
 static int insn_dead_p                 PROTO((rtx, regset, int));
 static int libcall_dead_p              PROTO((rtx, regset, rtx, rtx));
 static void mark_set_regs              PROTO((regset, regset, rtx,
@@ -319,7 +289,7 @@ flow_analysis (f, nregs, file)
 #endif
 
   /* Record which registers will be eliminated.  We use this in
-     mark_used_regs. */
+     mark_used_regs.  */
 
   CLEAR_HARD_REG_SET (elim_reg_set);
 
@@ -347,17 +317,14 @@ flow_analysis (f, nregs, file)
            || (GET_RTX_CLASS (code) == 'i'
                && (prev_code == JUMP_INSN
                    || (prev_code == CALL_INSN
-                       && nonlocal_label_list != 0
-                       /* Ignore a CLOBBER after a CALL_INSN here.  */
-                       && ! (code == INSN
-                             && GET_CODE (PATTERN (insn)) == CLOBBER))
+                       && nonlocal_label_list != 0)
                    || prev_code == BARRIER)))
          i++;
-       if (code != NOTE
-           /* Skip a CLOBBER after a CALL_INSN.  See similar code in
-              find_basic_blocks.  */
-           && ! (prev_code == CALL_INSN
-                 && code == INSN && GET_CODE (PATTERN (insn)) == CLOBBER))
+
+       if (code == CALL_INSN && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+         code = INSN;
+
+       if (code != NOTE)
          prev_code = code;
       }
   }
@@ -408,11 +375,17 @@ find_basic_blocks (f, nonlocal_label_list)
   register char *block_marked = (char *) alloca (n_basic_blocks);
   /* List of label_refs to all labels whose addresses are taken
      and used as data.  */
-  rtx label_value_list = 0;
+  rtx label_value_list;
+  int label_value_list_marked_live;
   rtx x, note;
   enum rtx_code prev_code, code;
-  int depth;
+  int depth, pass;
+
+  pass = 1;
+ restart:
 
+  label_value_list = 0;
+  label_value_list_marked_live = 0;
   block_live_static = block_live;
   bzero (block_live, n_basic_blocks);
   bzero (block_marked, n_basic_blocks);
@@ -444,10 +417,7 @@ find_basic_blocks (f, nonlocal_label_list)
                   && (prev_code == JUMP_INSN
                       || (prev_code == CALL_INSN
                           && nonlocal_label_list != 0
-                          /* Ignore if CLOBBER since we consider this
-                             part of the CALL.  See below.  */
-                          && ! (code == INSN
-                                && GET_CODE (PATTERN (insn)) == CLOBBER))
+                          && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
                       || prev_code == BARRIER)))
        {
          basic_block_head[++i] = insn;
@@ -481,30 +451,24 @@ find_basic_blocks (f, nonlocal_label_list)
 
       BLOCK_NUM (insn) = i;
 
-      /* Don't separate a CALL_INSN from following CLOBBER insns.  This is a
-        kludge that will go away when each CALL_INSN records its USE and
-        CLOBBERs.  */
-
-      if (code != NOTE
-         && ! (prev_code == CALL_INSN && code == INSN
-               && GET_CODE (PATTERN (insn)) == CLOBBER))
+      if (code != NOTE)
        prev_code = code;
     }
 
-  if (i + 1 != n_basic_blocks)
+  /* During the second pass, `n_basic_blocks' is only an upper bound.
+     Only perform the sanity check for the first pass, and on the second
+     pass ensure `n_basic_blocks' is set to the correct value.  */
+  if (pass == 1 && i + 1 != n_basic_blocks)
     abort ();
-
-  /* Don't delete the labels (in this function)
-     that are referenced by non-jump instructions.  */
-
-  for (x = label_value_list; x; x = XEXP (x, 1))
-    if (! LABEL_REF_NONLOCAL_P (x))
-      block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
+  n_basic_blocks = i + 1;
 
   for (x = forced_labels; x; x = XEXP (x, 1))
     if (! LABEL_REF_NONLOCAL_P (x))
       block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
 
+  for (x = exception_handler_labels; x; x = XEXP (x, 1))
+    block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
+
   /* Record which basic blocks control can drop in to.  */
 
   for (i = 0; i < n_basic_blocks; i++)
@@ -523,6 +487,7 @@ find_basic_blocks (f, nonlocal_label_list)
   if (n_basic_blocks > 0)
     {
       int something_marked = 1;
+      int deleted;
 
       /* Find all indirect jump insns and mark them as possibly jumping to all
         the labels whose addresses are explicitly used.  This is because,
@@ -553,16 +518,31 @@ find_basic_blocks (f, nonlocal_label_list)
                  for (i = len - 1; i >= 0; i--)
                    if (GET_CODE (XVECEXP (pat, 0, i)) == SET
                        && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
-                       && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
+                       && jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
                      computed_jump = 1;
              }
            else if (GET_CODE (pat) == SET
                     && SET_DEST (pat) == pc_rtx
-                    && uses_reg_or_mem (SET_SRC (pat)))
+                    && jmp_uses_reg_or_mem (SET_SRC (pat)))
              computed_jump = 1;
                    
            if (computed_jump)
              {
+               if (label_value_list_marked_live == 0)
+                 {
+                   label_value_list_marked_live = 1;
+
+                   /* This could be made smarter by only considering
+                      these live, if the computed goto is live.  */
+
+                   /* Don't delete the labels (in this function) that
+                      are referenced by non-jump instructions.  */
+
+                   for (x = label_value_list; x; x = XEXP (x, 1))
+                     if (! LABEL_REF_NONLOCAL_P (x))
+                       block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
+                 }
+
                for (x = label_value_list; x; x = XEXP (x, 1))
                  mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
                                  insn, 0);
@@ -577,14 +557,12 @@ find_basic_blocks (f, nonlocal_label_list)
         to all the nonlocal goto handler labels.  */
 
       for (insn = f; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == CALL_INSN)
+       if (GET_CODE (insn) == CALL_INSN
+           && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
          {
            for (x = nonlocal_label_list; x; x = XEXP (x, 1))
-             /* Don't try marking labels that
-                were deleted as unreferenced.  */
-             if (GET_CODE (XEXP (x, 0)) == CODE_LABEL)
-               mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                               insn, 0);
+             mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
+                             insn, 0);
 
            /* ??? This could be made smarter:
               in some cases it's possible to tell that certain
@@ -597,6 +575,13 @@ find_basic_blocks (f, nonlocal_label_list)
               gotos.  */
          }
 
+      /* All blocks associated with labels in label_value_list are
+        trivially considered as marked live, if the list is empty.
+        We do this to speed up the below code.  */
+
+      if (label_value_list == 0)
+       label_value_list_marked_live = 1;
+
       /* Pass over all blocks, marking each block that is reachable
         and has not yet been marked.
         Keep doing this until, in one pass, no blocks have been marked.
@@ -616,41 +601,110 @@ find_basic_blocks (f, nonlocal_label_list)
                insn = basic_block_end[i];
                if (GET_CODE (insn) == JUMP_INSN)
                  mark_label_ref (PATTERN (insn), insn, 0);
+
+               if (label_value_list_marked_live == 0)
+                 /* Now that we know that this block is live, mark as
+                    live, all the blocks that we might be able to get
+                    to as live.  */
+
+                 for (insn = basic_block_head[i];
+                      insn != NEXT_INSN (basic_block_end[i]);
+                      insn = NEXT_INSN (insn))
+                   {
+                     if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+                       {
+                         for (note = REG_NOTES (insn);
+                              note;
+                              note = XEXP (note, 1))
+                           if (REG_NOTE_KIND (note) == REG_LABEL)
+                             {
+                               x = XEXP (note, 0);
+                               block_live[BLOCK_NUM (x)] = 1;
+                             }
+                       }
+                   }
              }
        }
 
+      /* ??? See if we have a "live" basic block that is not reachable.
+        This can happen if it is headed by a label that is preserved or
+        in one of the label lists, but no call or computed jump is in
+        the loop.  It's not clear if we can delete the block or not,
+        but don't for now.  However, we will mess up register status if
+        it remains unreachable, so add a fake reachability from the
+        previous block.  */
+
+      for (i = 1; i < n_basic_blocks; i++)
+       if (block_live[i] && ! basic_block_drops_in[i]
+           && GET_CODE (basic_block_head[i]) == CODE_LABEL
+           && LABEL_REFS (basic_block_head[i]) == basic_block_head[i])
+         basic_block_drops_in[i] = 1;
+
       /* Now delete the code for any basic blocks that can't be reached.
         They can occur because jump_optimize does not recognize
         unreachable loops as unreachable.  */
 
+      deleted = 0;
       for (i = 0; i < n_basic_blocks; i++)
        if (!block_live[i])
          {
+           deleted++;
+
+           /* Delete the insns in a (non-live) block.  We physically delete
+              every non-note insn except the start and end (so
+              basic_block_head/end needn't be updated), we turn the latter
+              into NOTE_INSN_DELETED notes.
+              We use to "delete" the insns by turning them into notes, but
+              we may be deleting lots of insns that subsequent passes would
+              otherwise have to process.  Secondly, lots of deleted blocks in
+              a row can really slow down propagate_block since it will
+              otherwise process insn-turned-notes multiple times when it
+              looks for loop begin/end notes.  */
+           if (basic_block_head[i] != basic_block_end[i])
+             {
+               /* It would be quicker to delete all of these with a single
+                  unchaining, rather than one at a time, but we need to keep
+                  the NOTE's.  */
+               insn = NEXT_INSN (basic_block_head[i]);
+               while (insn != basic_block_end[i])
+                 {
+                   if (GET_CODE (insn) == BARRIER)
+                     abort ();
+                   else if (GET_CODE (insn) != NOTE)
+                     insn = flow_delete_insn (insn);
+                   else
+                     insn = NEXT_INSN (insn);
+                 }
+             }
            insn = basic_block_head[i];
-           while (1)
+           if (GET_CODE (insn) != NOTE)
              {
+               /* Turn the head into a deleted insn note.  */
                if (GET_CODE (insn) == BARRIER)
                  abort ();
-               if (GET_CODE (insn) != NOTE)
-                 {
-                   PUT_CODE (insn, NOTE);
-                   NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                   NOTE_SOURCE_FILE (insn) = 0;
-                 }
-               if (insn == basic_block_end[i])
-                 {
-                   /* BARRIERs are between basic blocks, not part of one.
-                      Delete a BARRIER if the preceding jump is deleted.
-                      We cannot alter a BARRIER into a NOTE
-                      because it is too short; but we can really delete
-                      it because it is not part of a basic block.  */
-                   if (NEXT_INSN (insn) != 0
-                       && GET_CODE (NEXT_INSN (insn)) == BARRIER)
-                     delete_insn (NEXT_INSN (insn));
-                   break;
-                 }
-               insn = NEXT_INSN (insn);
+               PUT_CODE (insn, NOTE);
+               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+               NOTE_SOURCE_FILE (insn) = 0;
+             }
+           insn = basic_block_end[i];
+           if (GET_CODE (insn) != NOTE)
+             {
+               /* Turn the tail into a deleted insn note.  */
+               if (GET_CODE (insn) == BARRIER)
+                 abort ();
+               PUT_CODE (insn, NOTE);
+               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+               NOTE_SOURCE_FILE (insn) = 0;
              }
+           /* BARRIERs are between basic blocks, not part of one.
+              Delete a BARRIER if the preceding jump is deleted.
+              We cannot alter a BARRIER into a NOTE
+              because it is too short; but we can really delete
+              it because it is not part of a basic block.  */
+           if (NEXT_INSN (insn) != 0
+               && GET_CODE (NEXT_INSN (insn)) == BARRIER)
+             delete_insn (NEXT_INSN (insn));
+
            /* Each time we delete some basic blocks,
               see if there is a jump around them that is
               being turned into a no-op.  If so, delete it.  */
@@ -658,7 +712,7 @@ find_basic_blocks (f, nonlocal_label_list)
            if (block_live[i - 1])
              {
                register int j;
-               for (j = i; j < n_basic_blocks; j++)
+               for (j = i + 1; j < n_basic_blocks; j++)
                  if (block_live[j])
                    {
                      rtx label;
@@ -683,41 +737,88 @@ find_basic_blocks (f, nonlocal_label_list)
                    }
              }
          }
+
+      /* There are pathological cases where one function calling hundreds of
+        nested inline functions can generate lots and lots of unreachable
+        blocks that jump can't delete.  Since we don't use sparse matrices
+        a lot of memory will be needed to compile such functions.
+        Implementing sparse matrices is a fair bit of work and it is not
+        clear that they win more than they lose (we don't want to
+        unnecessarily slow down compilation of normal code).  By making
+        another pass for the pathological case, we can greatly speed up
+        their compilation without hurting normal code.  This works because
+        all the insns in the unreachable blocks have either been deleted or
+        turned into notes.
+        Note that we're talking about reducing memory usage by 10's of
+        megabytes and reducing compilation time by several minutes.  */
+      /* ??? The choice of when to make another pass is a bit arbitrary,
+        and was derived from empirical data.  */
+      if (pass == 1
+         && deleted > 200)
+       {
+         pass++;
+         n_basic_blocks -= deleted;
+         /* `n_basic_blocks' may not be correct at this point: two previously
+            separate blocks may now be merged.  That's ok though as we
+            recalculate it during the second pass.  It certainly can't be
+            any larger than the current value.  */
+         goto restart;
+       }
     }
 }
 \f
-/* Return 1 if X contain a REG or MEM that is not in the constant pool.  */
+/* Subroutines of find_basic_blocks.  */
+
+/* Return 1 if X, the SRC_SRC of  SET of (pc) contain a REG or MEM that is
+   not in the constant pool and not in the condition of an IF_THEN_ELSE.  */
 
 static int
-uses_reg_or_mem (x)
+jmp_uses_reg_or_mem (x)
      rtx x;
 {
   enum rtx_code code = GET_CODE (x);
   int i, j;
   char *fmt;
 
-  if (code == REG
-      || (code == MEM
-         && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
-               && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))))
-    return 1;
+  switch (code)
+    {
+    case CONST:
+    case LABEL_REF:
+    case PC:
+      return 0;
+
+    case REG:
+      return 1;
+
+    case MEM:
+      return ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+               && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
+
+    case IF_THEN_ELSE:
+      return (jmp_uses_reg_or_mem (XEXP (x, 1))
+             || jmp_uses_reg_or_mem (XEXP (x, 2)));
+
+    case PLUS:  case MINUS:  case MULT:
+      return (jmp_uses_reg_or_mem (XEXP (x, 0))
+             || jmp_uses_reg_or_mem (XEXP (x, 1)));
+    }
 
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e'
-         && uses_reg_or_mem (XEXP (x, i)))
+         && jmp_uses_reg_or_mem (XEXP (x, i)))
        return 1;
 
       if (fmt[i] == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         if (uses_reg_or_mem (XVECEXP (x, i, j)))
+         if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
            return 1;
     }
 
   return 0;
 }
-\f
+
 /* Check expression X for label references;
    if one is found, add INSN to the label's chain of references.
 
@@ -778,6 +879,20 @@ mark_label_ref (x, insn, checkdup)
        }
     }
 }
+
+/* Delete INSN by patching it out.
+   Return the next insn.  */
+
+static rtx
+flow_delete_insn (insn)
+     rtx insn;
+{
+  /* ??? For the moment we assume we don't have to watch for NULLs here
+     since the start/end of basic blocks aren't deleted like this.  */
+  NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+  PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+  return NEXT_INSN (insn);
+}
 \f
 /* Determine which registers are live at the start of each
    basic block of the function whose first insn is F.
@@ -791,7 +906,6 @@ life_analysis (f, nregs)
      rtx f;
      int nregs;
 {
-  register regset tem;
   int first_pass;
   int changed;
   /* For each basic block, a bitmask of regs
@@ -825,33 +939,34 @@ life_analysis (f, nregs)
   allocate_for_life_analysis ();
 
   reg_next_use = (rtx *) alloca (nregs * sizeof (rtx));
-  bzero (reg_next_use, nregs * sizeof (rtx));
+  bzero ((char *) reg_next_use, nregs * sizeof (rtx));
 
   /* Set up several regset-vectors used internally within this function.
      Their meanings are documented above, with their declarations.  */
 
-  basic_block_live_at_end = (regset *) alloca (n_basic_blocks * sizeof (regset));
+  basic_block_live_at_end
+    = (regset *) alloca (n_basic_blocks * sizeof (regset));
+
   /* Don't use alloca since that leads to a crash rather than an error message
      if there isn't enough space.
      Don't use oballoc since we may need to allocate other things during
      this function on the temporary obstack.  */
-  tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
-  bzero (tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_live_at_end, tem, n_basic_blocks, regset_bytes);
+  init_regset_vector (basic_block_live_at_end, n_basic_blocks, regset_bytes,
+                     &flow_obstack);
 
-  basic_block_new_live_at_end = (regset *) alloca (n_basic_blocks * sizeof (regset));
-  tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
-  bzero (tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_new_live_at_end, tem, n_basic_blocks, regset_bytes);
+  basic_block_new_live_at_end
+    = (regset *) alloca (n_basic_blocks * sizeof (regset));
+  init_regset_vector (basic_block_new_live_at_end, n_basic_blocks, regset_bytes,
+                     &flow_obstack);
 
-  basic_block_significant = (regset *) alloca (n_basic_blocks * sizeof (regset));
-  tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
-  bzero (tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_significant, tem, n_basic_blocks, regset_bytes);
+  basic_block_significant
+    = (regset *) alloca (n_basic_blocks * sizeof (regset));
+  init_regset_vector (basic_block_significant, n_basic_blocks, regset_bytes,
+                     &flow_obstack);
 
   /* 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. */
+     Also, delete any insns that copy a register to itself.  */
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
     {
@@ -864,8 +979,25 @@ life_analysis (f, nregs)
          if (GET_CODE (PATTERN (insn)) == SET
              && GET_CODE (SET_DEST (PATTERN (insn))) == REG
              && GET_CODE (SET_SRC (PATTERN (insn))) == REG
-             && REGNO (SET_DEST (PATTERN (insn))) ==
-                       REGNO (SET_SRC (PATTERN (insn)))
+             && (REGNO (SET_DEST (PATTERN (insn)))
+                 == REGNO (SET_SRC (PATTERN (insn))))
+             /* Insns carrying these notes are useful later on.  */
+             && ! find_reg_note (insn, REG_EQUAL, NULL_RTX))
+           {
+             PUT_CODE (insn, NOTE);
+             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (insn) = 0;
+           }
+         /* Delete (in effect) any obvious no-op moves.  */
+         else if (GET_CODE (PATTERN (insn)) == SET
+             && GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG
+             && GET_CODE (SUBREG_REG (SET_DEST (PATTERN (insn)))) == REG
+             && GET_CODE (SET_SRC (PATTERN (insn))) == SUBREG
+             && GET_CODE (SUBREG_REG (SET_SRC (PATTERN (insn)))) == REG
+             && (REGNO (SUBREG_REG (SET_DEST (PATTERN (insn))))
+                 == REGNO (SUBREG_REG (SET_SRC (PATTERN (insn)))))
+             && SUBREG_WORD (SET_DEST (PATTERN (insn))) ==
+                             SUBREG_WORD (SET_SRC (PATTERN (insn)))
              /* Insns carrying these notes are useful later on.  */
              && ! find_reg_note (insn, REG_EQUAL, NULL_RTX))
            {
@@ -931,12 +1063,10 @@ life_analysis (f, nregs)
       {
        /* If exiting needs the right stack value,
           consider the stack pointer live at the end of the function.  */
-       basic_block_live_at_end[n_basic_blocks - 1]
-         [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
-           |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
-       basic_block_new_live_at_end[n_basic_blocks - 1]
-         [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
-           |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+       SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+                          STACK_POINTER_REGNUM);
+       SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+                          STACK_POINTER_REGNUM);
       }
 
   /* Mark the frame pointer is needed at the end of the function.  If
@@ -945,38 +1075,33 @@ life_analysis (f, nregs)
 
   if (n_basic_blocks > 0)
     {
-      basic_block_live_at_end[n_basic_blocks - 1]
-       [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
-         |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
-      basic_block_new_live_at_end[n_basic_blocks - 1]
-       [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
-         |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
+      SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+                        FRAME_POINTER_REGNUM);
+      SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+                        FRAME_POINTER_REGNUM);
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
       /* If they are different, also mark the hard frame pointer as live */
-      basic_block_live_at_end[n_basic_blocks - 1]
-       [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
-         |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
-                                    % REGSET_ELT_BITS);
-      basic_block_new_live_at_end[n_basic_blocks - 1]
-       [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
-         |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
-                                    % REGSET_ELT_BITS);
+      SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+                        HARD_FRAME_POINTER_REGNUM);
+      SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+                        HARD_FRAME_POINTER_REGNUM);
 #endif      
       }
 
-  /* Mark all global registers as being live at the end of the function
-     since they may be referenced by our caller.  */
+  /* Mark all global registers and all registers used by the epilogue
+     as being live at the end of the function since they may be
+     referenced by our caller.  */
 
   if (n_basic_blocks > 0)
     for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-      if (global_regs[i])
+      if (global_regs[i]
+#ifdef EPILOGUE_USES
+         || EPILOGUE_USES (i)
+#endif
+         )
        {
-         basic_block_live_at_end[n_basic_blocks - 1]
-           [i / REGSET_ELT_BITS]
-             |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
-         basic_block_new_live_at_end[n_basic_blocks - 1]
-           [i / REGSET_ELT_BITS]
-             |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+         SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1], i);
+         SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1], i);
        }
 
   /* Propagate life info through the basic blocks
@@ -1011,21 +1136,18 @@ life_analysis (f, nregs)
                 reg that is live at the end now but was not live there before
                 is one of the significant regs of this basic block).  */
 
-             for (j = 0; j < regset_size; j++)
-               {
-                 register REGSET_ELT_TYPE x
-                   = (basic_block_new_live_at_end[i][j]
-                      & ~basic_block_live_at_end[i][j]);
-                 if (x)
-                   consider = 1;
-                 if (x & basic_block_significant[i][j])
-                   {
-                     must_rescan = 1;
-                     consider = 1;
-                     break;
-                   }
-               }
-
+             EXECUTE_IF_AND_COMPL_IN_REG_SET (basic_block_new_live_at_end[i],
+                                              basic_block_live_at_end[i],
+                                              0, j,
+                                              {
+                                                consider = 1;
+                                                if (REGNO_REG_SET_P (basic_block_significant[i], j))
+                                                  {
+                                                    must_rescan = 1;
+                                                    goto done;
+                                                  }
+                                              });
+           done:
              if (! consider)
                continue;
            }
@@ -1039,23 +1161,22 @@ life_analysis (f, nregs)
              /* No complete rescan needed;
                 just record those variables newly known live at end
                 as live at start as well.  */
-             for (j = 0; j < regset_size; j++)
-               {
-                 register REGSET_ELT_TYPE x
-                   = (basic_block_new_live_at_end[i][j]
-                      & ~basic_block_live_at_end[i][j]);
-                 basic_block_live_at_start[i][j] |= x;
-                 basic_block_live_at_end[i][j] |= x;
-               }
+             IOR_AND_COMPL_REG_SET (basic_block_live_at_start[i],
+                                    basic_block_new_live_at_end[i],
+                                    basic_block_live_at_end[i]);
+
+             IOR_AND_COMPL_REG_SET (basic_block_live_at_end[i],
+                                    basic_block_new_live_at_end[i],
+                                    basic_block_live_at_end[i]);
            }
          else
            {
              /* Update the basic_block_live_at_start
                 by propagation backwards through the block.  */
-             bcopy (basic_block_new_live_at_end[i],
-                    basic_block_live_at_end[i], regset_bytes);
-             bcopy (basic_block_live_at_end[i],
-                    basic_block_live_at_start[i], regset_bytes);
+             COPY_REG_SET (basic_block_live_at_end[i],
+                           basic_block_new_live_at_end[i]);
+             COPY_REG_SET (basic_block_live_at_start[i],
+                           basic_block_live_at_end[i]);
              propagate_block (basic_block_live_at_start[i],
                               basic_block_head[i], basic_block_end[i], 0,
                               first_pass ? basic_block_significant[i]
@@ -1065,18 +1186,14 @@ life_analysis (f, nregs)
 
          {
            register rtx jump, head;
+
            /* Update the basic_block_new_live_at_end's of the block
               that falls through into this one (if any).  */
            head = basic_block_head[i];
-           jump = PREV_INSN (head);
            if (basic_block_drops_in[i])
-             {
-               register int from_block = BLOCK_NUM (jump);
-               register int j;
-               for (j = 0; j < regset_size; j++)
-                 basic_block_new_live_at_end[from_block][j]
-                   |= basic_block_live_at_start[i][j];
-             }
+             IOR_REG_SET (basic_block_new_live_at_end[i-1],
+                          basic_block_live_at_start[i]);
+
            /* Update the basic_block_new_live_at_end's of
               all the blocks that jump to this one.  */
            if (GET_CODE (head) == CODE_LABEL)
@@ -1085,10 +1202,8 @@ life_analysis (f, nregs)
                   jump = LABEL_NEXTREF (jump))
                {
                  register int from_block = BLOCK_NUM (CONTAINING_INSN (jump));
-                 register int j;
-                 for (j = 0; j < regset_size; j++)
-                   basic_block_new_live_at_end[from_block][j]
-                     |= basic_block_live_at_start[i][j];
+                 IOR_REG_SET (basic_block_new_live_at_end[from_block],
+                              basic_block_live_at_start[i]);
                }
          }
 #ifdef USE_C_ALLOCA
@@ -1104,10 +1219,11 @@ life_analysis (f, nregs)
      one basic block.  */
 
   if (n_basic_blocks > 0)
-    for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-      if (basic_block_live_at_start[0][i / REGSET_ELT_BITS]
-         & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
-       reg_basic_block[i] = REG_BLOCK_GLOBAL;
+    EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[0],
+                              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
@@ -1138,14 +1254,16 @@ life_analysis (f, nregs)
      But we don't need to do this for the user's variables, since
      ANSI says only volatile variables need this.  */
 #ifdef LONGJMP_RESTORE_FROM_STACK
-  for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
-    if (regs_live_at_setjmp[i / REGSET_ELT_BITS]
-       & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS))
-       && regno_reg_rtx[i] != 0 && ! REG_USERVAR_P (regno_reg_rtx[i]))
-      {
-       reg_live_length[i] = -1;
-       reg_basic_block[i] = -1;
-      }
+  EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+                            FIRST_PSEUDO_REGISTER, i,
+                            {
+                              if (regno_reg_rtx[i] != 0
+                                  && ! REG_USERVAR_P (regno_reg_rtx[i]))
+                                {
+                                  REG_LIVE_LENGTH (i) = -1;
+                                  REG_BASIC_BLOCK (i) = -1;
+                                }
+                            });
 #endif
 #endif
 
@@ -1158,14 +1276,15 @@ life_analysis (f, nregs)
      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.  */
-  for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
-    if ((regs_live_at_setjmp[i / REGSET_ELT_BITS]
-        & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
-       && regno_reg_rtx[i] != 0)
-      {
-       reg_live_length[i] = -1;
-       reg_basic_block[i] = -1;
-      }
+  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) = -1;
+                                }
+                            });
 
   obstack_free (&flow_obstack, NULL_PTR);
 }
@@ -1179,37 +1298,26 @@ void
 allocate_for_life_analysis ()
 {
   register int i;
-  register regset tem;
 
   regset_size = ((max_regno + REGSET_ELT_BITS - 1) / REGSET_ELT_BITS);
-  regset_bytes = regset_size * sizeof (*(regset)0);
-
-  reg_n_refs = (int *) oballoc (max_regno * sizeof (int));
-  bzero (reg_n_refs, max_regno * sizeof (int));
-
-  reg_n_sets = (short *) oballoc (max_regno * sizeof (short));
-  bzero (reg_n_sets, max_regno * sizeof (short));
+  regset_bytes = regset_size * sizeof (*(regset) 0);
 
-  reg_n_deaths = (short *) oballoc (max_regno * sizeof (short));
-  bzero (reg_n_deaths, max_regno * sizeof (short));
+  /* Because both reg_scan and flow_analysis want to set up the REG_N_SETS
+     information, explicitly reset it here.  The allocation should have
+     already happened on the previous reg_scan pass.  Make sure in case
+     some more registers were allocated.  */
+  allocate_reg_info (max_regno, FALSE, FALSE);
 
-  reg_live_length = (int *) oballoc (max_regno * sizeof (int));
-  bzero (reg_live_length, max_regno * sizeof (int));
-
-  reg_n_calls_crossed = (int *) oballoc (max_regno * sizeof (int));
-  bzero (reg_n_calls_crossed, max_regno * sizeof (int));
-
-  reg_basic_block = (int *) oballoc (max_regno * sizeof (int));
   for (i = 0; i < max_regno; i++)
-    reg_basic_block[i] = REG_BLOCK_UNKNOWN;
+    REG_N_SETS (i) = 0;
 
-  basic_block_live_at_start = (regset *) oballoc (n_basic_blocks * sizeof (regset));
-  tem = (regset) oballoc (n_basic_blocks * regset_bytes);
-  bzero (tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_live_at_start, tem, n_basic_blocks, regset_bytes);
+  basic_block_live_at_start
+    = (regset *) oballoc (n_basic_blocks * sizeof (regset));
+  init_regset_vector (basic_block_live_at_start, n_basic_blocks, regset_bytes,
+                     function_obstack);
 
-  regs_live_at_setjmp = (regset) oballoc (regset_bytes);
-  bzero (regs_live_at_setjmp, regset_bytes);
+  regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (function_obstack);
+  CLEAR_REG_SET (regs_live_at_setjmp);
 }
 
 /* Make each element of VECTOR point at a regset,
@@ -1218,19 +1326,18 @@ allocate_for_life_analysis ()
    BYTES_PER_ELT is the number of bytes in one regset.  */
 
 static void
-init_regset_vector (vector, space, nelts, bytes_per_elt)
+init_regset_vector (vector, nelts, bytes_per_elt, alloc_obstack)
      regset *vector;
-     regset space;
      int nelts;
      int bytes_per_elt;
+     struct obstack *alloc_obstack;
 {
   register int i;
-  register regset p = space;
 
   for (i = 0; i < nelts; i++)
     {
-      vector[i] = p;
-      p += bytes_per_elt / sizeof (*p);
+      vector[i] = OBSTACK_ALLOC_REG_SET (alloc_obstack);
+      CLEAR_REG_SET (vector[i]);
     }
 }
 
@@ -1270,11 +1377,8 @@ propagate_block (old, first, last, final, significant, bnum)
   /* The following variables are used only if FINAL is nonzero.  */
   /* This vector gets one element for each reg that has been live
      at any point in the basic block that has been scanned so far.
-     SOMETIMES_MAX says how many elements are in use so far.
-     In each element, OFFSET is the byte-number within a regset
-     for the register described by the element, and BIT is a mask
-     for that register's bit within the byte.  */
-  register struct sometimes { short offset; short bit; } *regs_sometimes_live;
+     SOMETIMES_MAX says how many elements are in use so far.  */
+  register int *regs_sometimes_live;
   int sometimes_max = 0;
   /* This regset has 1 for each reg that we have seen live so far.
      It and REGS_SOMETIMES_LIVE are updated together.  */
@@ -1285,8 +1389,8 @@ propagate_block (old, first, last, final, significant, bnum)
      current basic block, and adjust as we pass ends and starts of loops.  */
   loop_depth = basic_block_loop_depth[bnum];
 
-  dead = (regset) alloca (regset_bytes);
-  live = (regset) alloca (regset_bytes);
+  dead = ALLOCA_REG_SET ();
+  live = ALLOCA_REG_SET ();
 
   cc0_live = 0;
   last_mem_set = 0;
@@ -1306,32 +1410,22 @@ propagate_block (old, first, last, final, significant, bnum)
 
   if (final)
     {
-      register int i, offset;
-      REGSET_ELT_TYPE bit;
+      register int i;
 
       num_scratch = 0;
-      maxlive = (regset) alloca (regset_bytes);
-      bcopy (old, maxlive, regset_bytes);
-      regs_sometimes_live
-       = (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
+      maxlive = ALLOCA_REG_SET ();
+      COPY_REG_SET (maxlive, old);
+      regs_sometimes_live = (int *) alloca (max_regno * sizeof (int));
 
       /* Process the regs live at the end of the block.
         Enter them in MAXLIVE and REGS_SOMETIMES_LIVE.
-        Also mark them as not local to any one basic block.  */
-
-      for (offset = 0, i = 0; offset < regset_size; offset++)
-       for (bit = 1; bit; bit <<= 1, i++)
-         {
-           if (i == max_regno)
-             break;
-           if (old[offset] & bit)
-             {
-               reg_basic_block[i] = REG_BLOCK_GLOBAL;
-               regs_sometimes_live[sometimes_max].offset = offset;
-               regs_sometimes_live[sometimes_max].bit = i % REGSET_ELT_BITS;
-               sometimes_max++;
-             }
-         }
+        Also 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;
+                                  regs_sometimes_live[sometimes_max] = i;
+                                  sometimes_max++;
+                                });
     }
 
   /* Scan the block an insn at a time from end to beginning.  */
@@ -1340,28 +1434,25 @@ propagate_block (old, first, last, final, significant, bnum)
     {
       prev = PREV_INSN (insn);
 
-      /* Look for loop boundaries, remembering that we are going backwards.  */
-      if (GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-       loop_depth++;
-      else if (GET_CODE (insn) == NOTE
-              && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-       loop_depth--;
-
-      /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error. 
-        Abort now rather than setting register status incorrectly.  */
-      if (loop_depth == 0)
-       abort ();
-
-      /* If this is a call to `setjmp' et al,
-        warn if any non-volatile datum is live.  */
-
-      if (final && GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+      if (GET_CODE (insn) == NOTE)
        {
-         int i;
-         for (i = 0; i < regset_size; i++)
-           regs_live_at_setjmp[i] |= old[i];
+         /* Look for loop boundaries, remembering that we are going
+            backwards.  */
+         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+           loop_depth++;
+         else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+           loop_depth--;
+
+         /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error. 
+            Abort now rather than setting register status incorrectly.  */
+         if (loop_depth == 0)
+           abort ();
+
+         /* If this is a call to `setjmp' et al,
+            warn if any non-volatile datum is live.  */
+
+         if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+           IOR_REG_SET (regs_live_at_setjmp, old);
        }
 
       /* Update the life-status of regs for this insn.
@@ -1371,7 +1462,7 @@ propagate_block (old, first, last, final, significant, bnum)
         are those live after, with DEAD regs turned off,
         and then LIVE regs turned on.  */
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        {
          register int i;
          rtx note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
@@ -1417,11 +1508,8 @@ propagate_block (old, first, last, final, significant, bnum)
              goto flushed;
            }
 
-         for (i = 0; i < regset_size; i++)
-           {
-             dead[i] = 0;      /* Faster than bzero here */
-             live[i] = 0;      /* since regset_size is usually small */
-           }
+         CLEAR_REG_SET (dead);
+         CLEAR_REG_SET (live);
 
          /* See if this is an increment or decrement that can be
             merged into a following memory address.  */
@@ -1494,39 +1582,43 @@ propagate_block (old, first, last, final, significant, bnum)
                {
                  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, SET_DEST (XEXP (note, 0)),
+                                     final, insn);
+
                  /* Each call clobbers all call-clobbered regs that are not
-                    global.  Note that the function-value reg is a
+                    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])
-                     dead[i / REGSET_ELT_BITS]
-                       |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));
+                   if (call_used_regs[i] && ! global_regs[i]
+                       && ! fixed_regs[i])
+                     SET_REGNO_REG_SET (dead, i);
 
                  /* The stack ptr is used (honorarily) by a CALL insn.  */
-                 live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
-                   |= ((REGSET_ELT_TYPE) 1
-                       << (STACK_POINTER_REGNUM % REGSET_ELT_BITS));
+                 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])
-                     live[i / REGSET_ELT_BITS]
-                       |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));
+                     mark_used_regs (old, live,
+                                     gen_rtx (REG, reg_raw_mode[i], i),
+                                     final, insn);
 
                  /* Calls also clobber memory.  */
                  last_mem_set = 0;
                }
 
              /* Update OLD for the registers used or set.  */
-             for (i = 0; i < regset_size; i++)
-               {
-                 old[i] &= ~dead[i];
-                 old[i] |= live[i];
-               }
+             AND_COMPL_REG_SET (old, dead);
+             IOR_REG_SET (old, live);
 
              if (GET_CODE (insn) == CALL_INSN && final)
                {
@@ -1534,11 +1626,11 @@ propagate_block (old, first, last, final, significant, bnum)
                     must not go in a register clobbered by calls.
                     Find all regs now live and record this for them.  */
 
-                 register struct sometimes *p = regs_sometimes_live;
+                 register int *p = regs_sometimes_live;
 
                  for (i = 0; i < sometimes_max; i++, p++)
-                   if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
-                     reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1;
+                   if (REGNO_REG_SET_P (old, *p))
+                     REG_N_CALLS_CROSSED (*p)++;
                }
            }
 
@@ -1548,33 +1640,22 @@ propagate_block (old, first, last, final, significant, bnum)
 
          if (final)
            {
-             for (i = 0; i < regset_size; i++)
-               {
-                 register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i];
+             register int regno;
+             register int *p;
 
-                 if (diff)
-                   {
-                     register int regno;
-                     maxlive[i] |= diff;
-                     for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++)
-                       if (diff & ((REGSET_ELT_TYPE) 1 << regno))
-                         {
-                           regs_sometimes_live[sometimes_max].offset = i;
-                           regs_sometimes_live[sometimes_max].bit = regno;
-                           diff &= ~ ((REGSET_ELT_TYPE) 1 << regno);
-                           sometimes_max++;
-                         }
-                   }
-               }
+             EXECUTE_IF_AND_COMPL_IN_REG_SET (live, maxlive, 0, regno,
+                                              {
+                                                regs_sometimes_live[sometimes_max++] = regno;
+                                                SET_REGNO_REG_SET (maxlive, regno);
+                                              });
 
-             {
-               register struct sometimes *p = regs_sometimes_live;
-               for (i = 0; i < sometimes_max; i++, p++)
-                 {
-                   if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
-                     reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++;
-                 }
-             }
+             p = regs_sometimes_live;
+             for (i = 0; i < sometimes_max; i++)
+               {
+                 regno = *p++;
+                 if (REGNO_REG_SET_P (old, regno))
+                   REG_LIVE_LENGTH (regno)++;
+               }
            }
        }
     flushed: ;
@@ -1627,9 +1708,6 @@ insn_dead_p (x, needed, call_ok)
       if (GET_CODE (r) == REG)
        {
          register int regno = REGNO (r);
-         register int offset = regno / REGSET_ELT_BITS;
-         register REGSET_ELT_TYPE bit
-           = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
 
          /* Don't delete insns to set global regs.  */
          if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
@@ -1641,10 +1719,10 @@ insn_dead_p (x, needed, call_ok)
 #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). */
+                it, so we can treat it normally).  */
              || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
 #endif
-             || (needed[offset] & bit) != 0)
+             || REGNO_REG_SET_P (needed, regno))
            return 0;
 
          /* If this is a hard register, verify that subsequent words are
@@ -1654,9 +1732,7 @@ insn_dead_p (x, needed, call_ok)
              int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
 
              while (--n > 0)
-               if ((needed[(regno + n) / REGSET_ELT_BITS]
-                    & ((REGSET_ELT_TYPE) 1
-                       << ((regno + n) % REGSET_ELT_BITS))) != 0)
+               if (REGNO_REG_SET_P (needed, regno+n))
                  return 0;
            }
 
@@ -1753,18 +1829,19 @@ libcall_dead_p (x, needed, note, insn)
 
 /* Return 1 if register REGNO was used before it was set.
    In other words, if it is live at function entry.
-   Don't count global regster variables, though.  */
+   Don't count global register variables or variables in registers
+   that can be used for function arg passing, though.  */
 
 int
 regno_uninitialized (regno)
      int regno;
 {
   if (n_basic_blocks == 0
-      || (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
+      || (regno < FIRST_PSEUDO_REGISTER
+         && (global_regs[regno] || FUNCTION_ARG_REGNO_P (regno))))
     return 0;
 
-  return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
-         & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)));
+  return REGNO_REG_SET_P (basic_block_live_at_start[0], regno);
 }
 
 /* 1 if register REGNO was alive at a place where `setjmp' was called
@@ -1778,11 +1855,9 @@ regno_clobbered_at_setjmp (regno)
   if (n_basic_blocks == 0)
     return 0;
 
-  return ((reg_n_sets[regno] > 1
-          || (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
-              & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
-         && (regs_live_at_setjmp[regno / REGSET_ELT_BITS]
-             & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))));
+  return ((REG_N_SETS (regno) > 1
+          || REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+         && REGNO_REG_SET_P (regs_live_at_setjmp, regno));
 }
 \f
 /* Process the registers that are set within X.
@@ -1875,18 +1950,15 @@ mark_set_1 (needed, dead, x, insn, significant)
       && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
     /* && regno != STACK_POINTER_REGNUM) -- let's try without this.  */
     {
-      register int offset = regno / REGSET_ELT_BITS;
-      register REGSET_ELT_TYPE bit
-       = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-      REGSET_ELT_TYPE all_needed = (needed[offset] & bit);
-      REGSET_ELT_TYPE some_needed = (needed[offset] & bit);
+      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)
-       significant[offset] |= bit;
+       SET_REGNO_REG_SET (significant, regno);
 
       /* Mark it as as dead before this insn.  */
-      dead[offset] |= bit;
+      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.  */
@@ -1902,17 +1974,14 @@ mark_set_1 (needed, dead, x, insn, significant)
          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)
-               significant[(regno + n) / REGSET_ELT_BITS]
-                 |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
-             dead[(regno + n) / REGSET_ELT_BITS]
-               |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
-             some_needed
-               |= (needed[(regno + n) / REGSET_ELT_BITS]
-                   & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
-             all_needed
-               &= (needed[(regno + n) / REGSET_ELT_BITS]
-                   & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
+               SET_REGNO_REG_SET (significant, regno_n);
+
+             SET_REGNO_REG_SET (dead, regno_n);
+             some_needed |= needed_regno;
+             some_not_needed |= ! needed_regno;
            }
        }
       /* Additional data to record if this is the final pass.  */
@@ -1921,9 +1990,6 @@ mark_set_1 (needed, dead, x, insn, significant)
          register rtx y = reg_next_use[regno];
          register int blocknum = BLOCK_NUM (insn);
 
-         /* The next use is no longer "next", since a store intervenes.  */
-         reg_next_use[regno] = 0;
-
          /* If this is a hard reg, record this function uses the reg.  */
 
          if (regno < FIRST_PSEUDO_REGISTER)
@@ -1933,33 +1999,41 @@ mark_set_1 (needed, dead, x, insn, significant)
 
              for (i = regno; i < endregno; i++)
                {
+                 /* The next use is no longer "next", since a store
+                    intervenes.  */
+                 reg_next_use[i] = 0;
+
                  regs_ever_live[i] = 1;
-                 reg_n_sets[i]++;
+                 REG_N_SETS (i)++;
                }
            }
          else
            {
+             /* The next use is no longer "next", since a store
+                intervenes.  */
+             reg_next_use[regno] = 0;
+
              /* Keep track of which basic blocks each reg appears in.  */
 
-             if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
-               reg_basic_block[regno] = blocknum;
-             else if (reg_basic_block[regno] != blocknum)
-               reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+             if (REG_BASIC_BLOCK (regno) == 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
                 register twice if it is modified, but that is correct.  */
-             reg_n_sets[regno]++;
+             REG_N_SETS (regno)++;
 
-             reg_n_refs[regno] += loop_depth;
+             REG_N_REFS (regno) += loop_depth;
                  
              /* 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 (regno)++;
            }
 
-         if (all_needed)
+         if (! some_not_needed)
            {
              /* Make a logical link from the next following insn
                 that uses this register, back to this insn.
@@ -1984,7 +2058,7 @@ mark_set_1 (needed, dead, x, insn, significant)
                 Indicate this by marking the reg being set as dying here.  */
              REG_NOTES (insn)
                = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn));
-             reg_n_deaths[REGNO (reg)]++;
+             REG_N_DEATHS (REGNO (reg))++;
            }
          else
            {
@@ -1998,12 +2072,11 @@ mark_set_1 (needed, dead, x, insn, significant)
 
              for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
                   i >= 0; i--)
-               if ((needed[(regno + i) / REGSET_ELT_BITS]
-                    & ((REGSET_ELT_TYPE) 1
-                       << ((regno + i) % REGSET_ELT_BITS))) == 0)
+               if (!REGNO_REG_SET_P (needed, regno + i))
                  REG_NOTES (insn)
                    = gen_rtx (EXPR_LIST, REG_UNUSED,
-                              gen_rtx (REG, word_mode, regno + i),
+                              gen_rtx (REG, reg_raw_mode[regno + i],
+                                       regno + i),
                               REG_NOTES (insn));
            }
        }
@@ -2079,15 +2152,29 @@ find_auto_inc (needed, x, insn)
          && (use = find_use_as_address (PATTERN (insn), addr, offset),
              use != 0 && use != (rtx) 1))
        {
-         int win = 0;
          rtx q = SET_DEST (set);
+         enum rtx_code inc_code = (INTVAL (XEXP (y, 1)) == size
+                                   ? (offset ? PRE_INC : POST_INC)
+                                   : (offset ? PRE_DEC : POST_DEC));
 
          if (dead_or_set_p (incr, addr))
-           win = 1;
+           {
+             /* This is the simple case.  Try to make the auto-inc.  If
+                we can't, we are done.  Otherwise, we will do any
+                needed updates below.  */
+             if (! validate_change (insn, &XEXP (x, 0),
+                                    gen_rtx (inc_code, Pmode, addr),
+                                    0))
+               return;
+           }
          else if (GET_CODE (q) == REG
                   /* PREV_INSN used here to check the semi-open interval
                      [insn,incr).  */
-                  && ! reg_used_between_p (q,  PREV_INSN (insn), incr))
+                  && ! reg_used_between_p (q,  PREV_INSN (insn), incr)
+                  /* We must also check for sets of q as q may be
+                     a call clobbered hard register and there may
+                     be a call between PREV_INSN (insn) and incr.  */
+                  && ! reg_set_between_p (q,  PREV_INSN (insn), incr))
            {
              /* We have *p followed sometime later by q = p+size.
                 Both p and q must be live afterward,
@@ -2111,14 +2198,25 @@ find_auto_inc (needed, x, insn)
                  BLOCK_NUM (temp) = BLOCK_NUM (insn);
                }
 
+             /* If we can't make the auto-inc, or can't make the
+                replacement into Y, exit.  There's no point in making
+                the change below if we can't do the auto-inc and doing
+                so is not correct in the pre-inc case.  */
+
+             validate_change (insn, &XEXP (x, 0),
+                              gen_rtx (inc_code, Pmode, q),
+                              1);
+             validate_change (incr, &XEXP (y, 0), q, 1);
+             if (! apply_change_group ())
+               return;
+
+             /* We now know we'll be doing this change, so emit the
+                new insn(s) and do the updates.  */
              emit_insns_before (insns, insn);
 
              if (basic_block_head[BLOCK_NUM (insn)] == insn)
                basic_block_head[BLOCK_NUM (insn)] = insns;
 
-             XEXP (x, 0) = q;
-             XEXP (y, 0) = q;
-
              /* INCR will become a NOTE and INSN won't contain a
                 use of ADDR.  If a use of ADDR was just placed in
                 the insn before INSN, make that the next use. 
@@ -2132,62 +2230,54 @@ find_auto_inc (needed, x, insn)
 
              addr = q;
              regno = REGNO (q);
-             win = 1;
 
              /* 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.  */
-             needed[regno / REGSET_ELT_BITS]
-               |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+             SET_REGNO_REG_SET (needed, regno);
 
              /* If there are any calls between INSN and INCR, show
                 that REGNO now crosses them.  */
              for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
                if (GET_CODE (temp) == CALL_INSN)
-                 reg_n_calls_crossed[regno]++;
+                 REG_N_CALLS_CROSSED (regno)++;
            }
+         else
+           return;
+
+         /* If we haven't returned, it means we were able to make the
+            auto-inc, so update the status.  First, record that this insn
+            has an implicit side effect.  */
 
-         if (win)
+         REG_NOTES (insn)
+           = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn));
+
+         /* Modify the old increment-insn to simply copy
+            the already-incremented value of our register.  */
+         if (! validate_change (incr, &SET_SRC (set), addr, 0))
+           abort ();
+
+         /* If that makes it a no-op (copying the register into itself) delete
+            it so it won't appear to be a "use" and a "set" of this
+            register.  */
+         if (SET_DEST (set) == addr)
            {
-             /* We have found a suitable auto-increment: do POST_INC around
-                the register here, and patch out the increment instruction 
-                that follows. */
-             XEXP (x, 0) = gen_rtx ((INTVAL (XEXP (y, 1)) == size
-                                     ? (offset ? PRE_INC : POST_INC)
-                                     : (offset ? PRE_DEC : POST_DEC)),
-                                    Pmode, addr);
-
-             /* Record that this insn has an implicit side effect.  */
-             REG_NOTES (insn)
-               = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn));
-
-             /* Modify the old increment-insn to simply copy
-                the already-incremented value of our register.  */
-             SET_SRC (set) = addr;
-             /* Indicate insn must be re-recognized.  */
-             INSN_CODE (incr) = -1;
-
-             /* If that makes it a no-op (copying the register into itself)
-                then delete it so it won't appear to be a "use" and a "set"
-                of this register.  */
-             if (SET_DEST (set) == addr)
-               {
-                 PUT_CODE (incr, NOTE);
-                 NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (incr) = 0;
-               }
+             PUT_CODE (incr, NOTE);
+             NOTE_LINE_NUMBER (incr) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (incr) = 0;
+           }
 
-             if (regno >= FIRST_PSEUDO_REGISTER)
-               {
-                 /* 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;
-                 /* Count the increment as a setting of the register,
-                    even though it isn't a SET in rtl.  */
-                 reg_n_sets[regno]++;
-               }
+         if (regno >= FIRST_PSEUDO_REGISTER)
+           {
+             /* 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;
+
+             /* Count the increment as a setting of the register,
+                even though it isn't a SET in rtl.  */
+             REG_N_SETS (regno)++;
            }
        }
     }
@@ -2245,9 +2335,15 @@ mark_used_regs (needed, live, x, final, insn)
       return;
 
     case MEM:
-      /* Invalidate the data for the last MEM stored.  We could do this only
-        if the addresses conflict, but this doesn't seem worthwhile.  */
-      last_mem_set = 0;
+      /* CYGNUS LOCAL dje/8176 */
+      /* Invalidate the data for the last MEM stored, but only if MEM is
+        something that can be stored into.  */
+      if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
+       ; /* needn't clear last_mem_set */
+      else
+       last_mem_set = 0;
+      /* END CYGNUS LOCAL */
 
 #ifdef AUTO_INC_DEC
       if (final)
@@ -2255,19 +2351,36 @@ mark_used_regs (needed, live, x, final, insn)
 #endif
       break;
 
+    case SUBREG:
+      if (GET_CODE (SUBREG_REG (x)) == REG
+         && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
+         && (GET_MODE_SIZE (GET_MODE (x))
+             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+       REG_CHANGES_SIZE (REGNO (SUBREG_REG (x))) = 1;
+
+      /* 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, final, insn);
+         return;
+       }
+
+      /* ... fall through ...  */
+
     case REG:
       /* See a register other than being set
         => mark it as needed.  */
 
       regno = REGNO (x);
       {
-       register int offset = regno / REGSET_ELT_BITS;
-       register REGSET_ELT_TYPE bit
-         = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-       REGSET_ELT_TYPE all_needed = needed[offset] & bit;
-       REGSET_ELT_TYPE some_needed = needed[offset] & bit;
+       REGSET_ELT_TYPE some_needed = REGNO_REG_SET_P (needed, regno);
+       REGSET_ELT_TYPE some_not_needed = ! some_needed;
+
+       SET_REGNO_REG_SET (live, regno);
 
-       live[offset] |= bit;
        /* 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)
@@ -2308,14 +2421,12 @@ mark_used_regs (needed, live, x, final, insn)
            n = HARD_REGNO_NREGS (regno, GET_MODE (x));
            while (--n > 0)
              {
-               live[(regno + n) / REGSET_ELT_BITS]
-                 |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
-               some_needed
-                 |= (needed[(regno + n) / REGSET_ELT_BITS]
-                     & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
-               all_needed
-                 &= (needed[(regno + n) / REGSET_ELT_BITS]
-                     & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
+               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 (final)
@@ -2343,14 +2454,14 @@ mark_used_regs (needed, live, x, final, insn)
 
                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;
+               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;
+               REG_N_REFS (regno) += loop_depth;
              }
 
            /* Record and count the insns in which a reg dies.
@@ -2359,20 +2470,30 @@ mark_used_regs (needed, live, x, final, insn)
               we do not make a REG_DEAD note; likewise if we already
               made such a note.  */
 
-           if (! all_needed
+           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)
                      = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn));
-                   reg_n_deaths[regno]++;
+                   REG_N_DEATHS (regno)++;
                  }
                else
                  {
@@ -2383,13 +2504,12 @@ mark_used_regs (needed, live, x, final, insn)
 
                    for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
                         i >= 0; i--)
-                     if ((needed[(regno + i) / REGSET_ELT_BITS]
-                          & ((REGSET_ELT_TYPE) 1
-                             << ((regno + i) % REGSET_ELT_BITS))) == 0
+                     if (!REGNO_REG_SET_P (needed, regno + i)
                          && ! dead_or_set_regno_p (insn, regno + i))
                        REG_NOTES (insn)
                          = gen_rtx (EXPR_LIST, REG_DEAD,
-                                    gen_rtx (REG, word_mode, regno + i),
+                                    gen_rtx (REG, reg_raw_mode[regno + i],
+                                             regno + i),
                                     REG_NOTES (insn));
                  }
              }
@@ -2427,6 +2547,13 @@ mark_used_regs (needed, live, x, final, insn)
               || GET_CODE (testreg) == SIGN_EXTRACT
               || GET_CODE (testreg) == SUBREG)
          {
+           if (GET_CODE (testreg) == SUBREG
+               && GET_CODE (SUBREG_REG (testreg)) == REG
+               && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
+               && (GET_MODE_SIZE (GET_MODE (testreg))
+                   != GET_MODE_SIZE (GET_MODE (SUBREG_REG (testreg)))))
+             REG_CHANGES_SIZE (REGNO (SUBREG_REG (testreg))) = 1;
+
            /* 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.  */
@@ -2465,19 +2592,21 @@ mark_used_regs (needed, live, x, final, insn)
     case RETURN:
       /* If exiting needs the right stack value, consider this insn as
         using the stack pointer.  In any event, consider it as using
-        all global registers.  */
+        all global registers and all registers used by return.  */
 
 #ifdef EXIT_IGNORE_STACK
       if (! EXIT_IGNORE_STACK
          || (! FRAME_POINTER_REQUIRED && flag_omit_frame_pointer))
 #endif
-       live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
-         |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+       SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
 
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       if (global_regs[i])
-         live[i / REGSET_ELT_BITS]
-           |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+       if (global_regs[i]
+#ifdef EPILOGUE_USES
+           || EPILOGUE_USES (i)
+#endif
+           )
+         SET_REGNO_REG_SET (live, i);
       break;
     }
 
@@ -2524,6 +2653,9 @@ try_pre_increment_1 (insn)
   rtx y = 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
+        mode would be better.  */
+      && ! dead_or_set_p (y, SET_DEST (x))
       && try_pre_increment (y, SET_DEST (PATTERN (insn)),
                            amount))
     {
@@ -2539,8 +2671,8 @@ try_pre_increment_1 (insn)
         less likely.  */
       if (regno >= FIRST_PSEUDO_REGISTER)
        {
-         reg_n_refs[regno] += loop_depth;
-         reg_n_sets[regno]++;
+         REG_N_REFS (regno) += loop_depth;
+         REG_N_SETS (regno)++;
        }
       return 1;
     }
@@ -2617,10 +2749,13 @@ try_pre_increment (insn, reg, amount)
   if (GET_MODE_SIZE (GET_MODE (use)) != (amount > 0 ? amount : - amount))
     return 0;
 
-  XEXP (use, 0) = gen_rtx (amount > 0
-                          ? (do_post ? POST_INC : PRE_INC)
-                          : (do_post ? POST_DEC : PRE_DEC),
-                          Pmode, reg);
+  /* See if this combination of instruction and addressing mode exists.  */
+  if (! validate_change (insn, &XEXP (use, 0),
+                        gen_rtx (amount > 0
+                                 ? (do_post ? POST_INC : PRE_INC)
+                                 : (do_post ? POST_DEC : PRE_DEC),
+                                 Pmode, reg), 0))
+    return 0;
 
   /* Record that this insn now has an implicit side effect on X.  */
   REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_INC, reg, REG_NOTES (insn));
@@ -2710,19 +2845,19 @@ dump_flow_info (file)
   fprintf (file, "%d registers.\n", max_regno);
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (reg_n_refs[i])
+    if (REG_N_REFS (i))
       {
        enum reg_class class, altclass;
        fprintf (file, "\nRegister %d used %d times across %d insns",
-                i, reg_n_refs[i], reg_live_length[i]);
-       if (reg_basic_block[i] >= 0)
-         fprintf (file, " in block %d", reg_basic_block[i]);
-       if (reg_n_deaths[i] != 1)
-         fprintf (file, "; dies in %d places", reg_n_deaths[i]);
-       if (reg_n_calls_crossed[i] == 1)
+                i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
+       if (REG_BASIC_BLOCK (i) >= 0)
+         fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
+       if (REG_N_DEATHS (i) != 1)
+         fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+       if (REG_N_CALLS_CROSSED (i) == 1)
          fprintf (file, "; crosses 1 call");
-       else if (reg_n_calls_crossed[i])
-         fprintf (file, "; crosses %d calls", reg_n_calls_crossed[i]);
+       else if (REG_N_CALLS_CROSSED (i))
+         fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
        if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
          fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
        class = reg_preferred_class (i);
@@ -2771,13 +2906,8 @@ dump_flow_info (file)
        }
       fprintf (file, "\nRegisters live at start:");
       for (regno = 0; regno < max_regno; regno++)
-       {
-         register int offset = regno / REGSET_ELT_BITS;
-         register REGSET_ELT_TYPE bit
-           = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-         if (basic_block_live_at_start[i][offset] & bit)
-             fprintf (file, " %d", regno);
-       }
+       if (REGNO_REG_SET_P (basic_block_live_at_start[i], regno))
+         fprintf (file, " %d", regno);
       fprintf (file, "\n");
     }
   fprintf (file, "\n");