OSDN Git Service

(OBJC_ERR_BAD_STATE): New error code.
[pf3gnuchains/gcc-fork.git] / gcc / flow.c
index b15817c..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,56 +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; says whether a psuedo register N was ever used
-   within a SUBREG that changes the size of the reg.  Some machines prohibit
-   such objects to be in certain (usually floating-point) registers.  */
-
-char *reg_changes_size;
-
-/* 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.  */
+/* Indexed by n, giving various register information */
 
-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.  */
-
-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.
@@ -286,11 +249,11 @@ 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));
@@ -326,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);
 
@@ -357,6 +320,10 @@ flow_analysis (f, nregs, file)
                        && nonlocal_label_list != 0)
                    || prev_code == BARRIER)))
          i++;
+
+       if (code == CALL_INSN && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+         code = INSN;
+
        if (code != NOTE)
          prev_code = code;
       }
@@ -409,6 +376,7 @@ find_basic_blocks (f, nonlocal_label_list)
   /* List of label_refs to all labels whose addresses are taken
      and used as data.  */
   rtx label_value_list;
+  int label_value_list_marked_live;
   rtx x, note;
   enum rtx_code prev_code, code;
   int depth, pass;
@@ -417,6 +385,7 @@ find_basic_blocks (f, nonlocal_label_list)
  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);
@@ -447,7 +416,8 @@ find_basic_blocks (f, nonlocal_label_list)
               || (GET_RTX_CLASS (code) == 'i'
                   && (prev_code == JUMP_INSN
                       || (prev_code == CALL_INSN
-                          && nonlocal_label_list != 0)
+                          && nonlocal_label_list != 0
+                          && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
                       || prev_code == BARRIER)))
        {
          basic_block_head[++i] = insn;
@@ -485,20 +455,20 @@ find_basic_blocks (f, nonlocal_label_list)
        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++)
@@ -548,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);
@@ -572,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
@@ -592,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.
@@ -611,6 +601,28 @@ 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;
+                             }
+                       }
+                   }
              }
        }
 
@@ -650,6 +662,9 @@ find_basic_blocks (f, nonlocal_label_list)
               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])
                  {
@@ -723,24 +738,30 @@ find_basic_blocks (f, nonlocal_label_list)
              }
          }
 
-      /* There are pathalogical cases where one function calling hundreds of
+      /* 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 pathalogical case, we can greatly speed up
+        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.  */
+        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 > n_basic_blocks / 2 || deleted > 1000))
+         && 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;
        }
     }
@@ -748,32 +769,50 @@ find_basic_blocks (f, nonlocal_label_list)
 \f
 /* Subroutines of find_basic_blocks.  */
 
-/* Return 1 if X contain a REG or MEM that is not in the constant pool.  */
+/* 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;
     }
 
@@ -867,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
@@ -913,28 +951,22 @@ life_analysis (f, nregs)
      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 ((char *) 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 ((char *) tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_new_live_at_end, tem,
-                     n_basic_blocks, regset_bytes);
+  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 ((char *) tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_significant, tem,
-                     n_basic_blocks, regset_bytes);
+  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))
     {
@@ -947,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))
            {
@@ -1014,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
@@ -1028,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
@@ -1094,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;
            }
@@ -1122,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 ((char *) basic_block_new_live_at_end[i],
-                    (char *) basic_block_live_at_end[i], regset_bytes);
-             bcopy ((char *) basic_block_live_at_end[i],
-                    (char *) 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]
@@ -1153,12 +1191,8 @@ life_analysis (f, nregs)
               that falls through into this one (if any).  */
            head = basic_block_head[i];
            if (basic_block_drops_in[i])
-             {
-               register int j;
-               for (j = 0; j < regset_size; j++)
-                 basic_block_new_live_at_end[i-1][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.  */
@@ -1168,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
@@ -1187,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
@@ -1221,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
 
@@ -1241,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);
 }
@@ -1262,42 +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);
+  regset_bytes = regset_size * sizeof (*(regset) 0);
 
-  reg_n_refs = (int *) oballoc (max_regno * sizeof (int));
-  bzero ((char *) reg_n_refs, max_regno * sizeof (int));
+  /* 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_n_sets = (short *) oballoc (max_regno * sizeof (short));
-  bzero ((char *) reg_n_sets, max_regno * sizeof (short));
-
-  reg_n_deaths = (short *) oballoc (max_regno * sizeof (short));
-  bzero ((char *) reg_n_deaths, max_regno * sizeof (short));
-
-  reg_changes_size = (char *) oballoc (max_regno * sizeof (char));
-  bzero (reg_changes_size, max_regno * sizeof (char));;
-
-  reg_live_length = (int *) oballoc (max_regno * sizeof (int));
-  bzero ((char *) reg_live_length, max_regno * sizeof (int));
-
-  reg_n_calls_crossed = (int *) oballoc (max_regno * sizeof (int));
-  bzero ((char *) 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 ((char *) tem, n_basic_blocks * regset_bytes);
-  init_regset_vector (basic_block_live_at_start, tem,
-                     n_basic_blocks, regset_bytes);
+  init_regset_vector (basic_block_live_at_start, n_basic_blocks, regset_bytes,
+                     function_obstack);
 
-  regs_live_at_setjmp = (regset) oballoc (regset_bytes);
-  bzero ((char *) 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,
@@ -1306,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]);
     }
 }
 
@@ -1358,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.  */
@@ -1373,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;
@@ -1394,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 ((char *) old, (char *) 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.  */
@@ -1446,11 +1452,7 @@ propagate_block (old, first, last, final, significant, bnum)
             warn if any non-volatile datum is live.  */
 
          if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
-           {
-             int i;
-             for (i = 0; i < regset_size; i++)
-               regs_live_at_setjmp[i] |= old[i];
-           }
+           IOR_REG_SET (regs_live_at_setjmp, old);
        }
 
       /* Update the life-status of regs for this insn.
@@ -1506,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.  */
@@ -1593,19 +1592,17 @@ propagate_block (old, first, last, final, significant, bnum)
                                      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.  */
@@ -1620,11 +1617,8 @@ propagate_block (old, first, last, final, significant, bnum)
                }
 
              /* 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)
                {
@@ -1632,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)++;
                }
            }
 
@@ -1646,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: ;
@@ -1725,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])
@@ -1739,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
@@ -1752,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;
            }
 
@@ -1851,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
@@ -1876,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.
@@ -1973,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.  */
@@ -2000,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.  */
@@ -2019,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)
@@ -2031,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.
@@ -2082,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
            {
@@ -2096,9 +2072,7 @@ 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, reg_raw_mode[regno + i],
@@ -2196,7 +2170,11 @@ find_auto_inc (needed, x, insn)
          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,
@@ -2257,15 +2235,16 @@ find_auto_inc (needed, x, insn)
                 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
@@ -2294,11 +2273,11 @@ 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;
+             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]++;
+             REG_N_SETS (regno)++;
            }
        }
     }
@@ -2356,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)
@@ -2370,15 +2355,20 @@ mark_used_regs (needed, live, x, final, insn)
       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))))
-         && (INTEGRAL_MODE_P (GET_MODE (x))
-             || INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (x)))))
-       reg_changes_size[REGNO (SUBREG_REG (x))] = 1;
+             != 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);
 
-      /* ... fall through ... */
+      /* 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
@@ -2386,13 +2376,11 @@ mark_used_regs (needed, live, x, final, insn)
 
       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)
@@ -2433,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)
@@ -2468,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.
@@ -2484,7 +2470,7 @@ 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])
@@ -2507,7 +2493,7 @@ mark_used_regs (needed, live, x, final, insn)
                  {
                    REG_NOTES (insn)
                      = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn));
-                   reg_n_deaths[regno]++;
+                   REG_N_DEATHS (regno)++;
                  }
                else
                  {
@@ -2518,9 +2504,7 @@ 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,
@@ -2563,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.  */
@@ -2601,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;
     }
 
@@ -2661,7 +2654,7 @@ try_pre_increment_1 (insn)
   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. */
+        mode would be better.  */
       && ! dead_or_set_p (y, SET_DEST (x))
       && try_pre_increment (y, SET_DEST (PATTERN (insn)),
                            amount))
@@ -2678,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;
     }
@@ -2852,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);
@@ -2913,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");