flow.c (dump_flow_info): Also print number of sets and whether or not the pseudo...
[gcc.git] / gcc / flow.c
index 59167855fef7849970e989ac882ad10897ff39e4..2598f8c3513318fbb8d17c8bd67177a4a32de8bb 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-97, 1998 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.
@@ -107,8 +108,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    register usage: reg_n_refs, reg_n_deaths, reg_n_sets, reg_live_length,
    reg_n_calls_crosses and reg_basic_block.  */
 \f
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
 #include "basic-block.h"
 #include "insn-config.h"
@@ -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;
 
@@ -138,7 +147,7 @@ static int max_uid_for_flow;
    This is set up by find_basic_blocks and used there and in life_analysis,
    and then freed.  */
 
-static int *uid_block_number;
+int *uid_block_number;
 
 /* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile.  */
 
@@ -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,13 @@ 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;
+reg_info *reg_n_info;
 
-/* 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.  */
+/* Size of the reg_n_info table.  */
 
-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;
+unsigned int reg_n_max;
 
 /* Element N is the next insn that uses (hard or pseudo) register number N
    within the current basic block; or zero, if there is no such insn.
@@ -234,6 +201,11 @@ rtx *basic_block_head;
 
 rtx *basic_block_end;
 
+/* Element N indicates whether basic block N can be reached through a
+   computed jump.  */
+
+char *basic_block_computed_jump_target;
+
 /* Element N is a regset describing the registers live
    at the start of basic block N.
    This info lasts until we finish compiling the function.  */
@@ -285,12 +257,12 @@ static rtx last_mem_set;
 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 void find_basic_blocks_1                PROTO((rtx, rtx, int));
 static void mark_label_ref             PROTO((rtx, rtx, int));
-static void life_analysis              PROTO((rtx, int));
+static void life_analysis_1            PROTO((rtx, int));
 void allocate_for_life_analysis                PROTO((void));
-static void init_regset_vector         PROTO((regset *, regset, int, int));
+void init_regset_vector                        PROTO((regset *, int, struct obstack *));
+void free_regset_vector                        PROTO((regset *, int));
 static void propagate_block            PROTO((regset, rtx, rtx, int, 
                                               regset, int));
 static rtx flow_delete_insn            PROTO((rtx));
@@ -300,53 +272,55 @@ static void mark_set_regs         PROTO((regset, regset, rtx,
                                               rtx, regset));
 static void mark_set_1                 PROTO((regset, regset, rtx,
                                               rtx, regset));
+#ifdef AUTO_INC_DEC
 static void find_auto_inc              PROTO((regset, rtx, rtx));
-static void mark_used_regs             PROTO((regset, regset, rtx, int, rtx));
 static int try_pre_increment_1         PROTO((rtx));
 static int try_pre_increment           PROTO((rtx, rtx, HOST_WIDE_INT));
-static rtx find_use_as_address         PROTO((rtx, rtx, HOST_WIDE_INT));
+#endif
+static void mark_used_regs             PROTO((regset, regset, rtx, int, rtx));
 void dump_flow_info                    PROTO((FILE *));
+static void add_pred_succ              PROTO ((int, int, int_list_ptr *,
+                                               int_list_ptr *, int *, int *));
+static int_list_ptr alloc_int_list_node PROTO ((int_list_block **));
+static int_list_ptr add_int_list_node   PROTO ((int_list_block **,
+                                               int_list **, int));
 \f
-/* Find basic blocks of the current function and perform data flow analysis.
+/* Find basic blocks of the current function.
    F is the first insn of the function and NREGS the number of register numbers
-   in use.  */
+   in use.
+   LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
+   be reachable.  This turns on a kludge that causes the control flow
+   information to be inaccurate and not suitable for passes like GCSE.  */
 
 void
-flow_analysis (f, nregs, file)
+find_basic_blocks (f, nregs, file, live_reachable_p)
      rtx f;
      int nregs;
      FILE *file;
+     int live_reachable_p;
 {
   register rtx insn;
   register int i;
   rtx nonlocal_label_list = nonlocal_label_rtx_list ();
-
-#ifdef ELIMINABLE_REGS
-  static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
-#endif
-
-  /* Record which registers will be eliminated.  We use this in
-     mark_used_regs. */
-
-  CLEAR_HARD_REG_SET (elim_reg_set);
-
-#ifdef ELIMINABLE_REGS
-  for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
-    SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
-#else
-  SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
-#endif
+  int in_libcall_block = 0;
 
   /* Count the basic blocks.  Also find maximum insn uid value used.  */
 
   {
     register RTX_CODE prev_code = JUMP_INSN;
     register RTX_CODE code;
+    int eh_region = 0;
 
     max_uid_for_flow = 0;
 
     for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
       {
+
+       /* Track when we are inside in LIBCALL block.  */
+       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+           && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+         in_libcall_block = 1;
+
        code = GET_CODE (insn);
        if (INSN_UID (insn) > max_uid_for_flow)
          max_uid_for_flow = INSN_UID (insn);
@@ -354,72 +328,94 @@ flow_analysis (f, nregs, file)
            || (GET_RTX_CLASS (code) == 'i'
                && (prev_code == JUMP_INSN
                    || (prev_code == CALL_INSN
-                       && nonlocal_label_list != 0)
+                       && (nonlocal_label_list != 0 || eh_region)
+                       && ! in_libcall_block)
                    || prev_code == BARRIER)))
          i++;
+
+       if (code == CALL_INSN && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+         code = INSN;
+
        if (code != NOTE)
          prev_code = code;
+       else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+         ++eh_region;
+       else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+         --eh_region;
+
+       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+           && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+         in_libcall_block = 0;
       }
   }
 
+  n_basic_blocks = i;
+
 #ifdef AUTO_INC_DEC
-  /* Leave space for insns we make in some cases for auto-inc.  These cases
-     are rare, so we don't need too much space.  */
+  /* Leave space for insns life_analysis makes in some cases for auto-inc.
+     These cases are rare, so we don't need too much space.  */
   max_uid_for_flow += max_uid_for_flow / 10;
 #endif
 
   /* Allocate some tables that last till end of compiling this function
      and some needed only in find_basic_blocks and life_analysis.  */
 
-  n_basic_blocks = i;
-  basic_block_head = (rtx *) oballoc (n_basic_blocks * sizeof (rtx));
-  basic_block_end = (rtx *) oballoc (n_basic_blocks * sizeof (rtx));
-  basic_block_drops_in = (char *) alloca (n_basic_blocks);
-  basic_block_loop_depth = (short *) alloca (n_basic_blocks * sizeof (short));
+  basic_block_head = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
+  basic_block_end = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
+  basic_block_drops_in = (char *) xmalloc (n_basic_blocks);
+  basic_block_computed_jump_target = (char *) oballoc (n_basic_blocks);
+  basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
   uid_block_number
-    = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
-  uid_volatile = (char *) alloca (max_uid_for_flow + 1);
+    = (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
+  uid_volatile = (char *) xmalloc (max_uid_for_flow + 1);
   bzero (uid_volatile, max_uid_for_flow + 1);
 
-  find_basic_blocks (f, nonlocal_label_list);
-  life_analysis (f, nregs);
-  if (file)
-    dump_flow_info (file);
-
-  basic_block_drops_in = 0;
-  uid_block_number = 0;
-  basic_block_loop_depth = 0;
+  find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p);
 }
-\f
+
 /* Find all basic blocks of the function whose first insn is F.
    Store the correct data in the tables that describe the basic blocks,
    set up the chains of references for each CODE_LABEL, and
    delete any entire basic blocks that cannot be reached.
 
-   NONLOCAL_LABEL_LIST is the same local variable from flow_analysis.  */
+   NONLOCAL_LABEL_LIST is a list of non-local labels in the function.
+   Blocks that are otherwise unreachable may be reachable with a non-local
+   goto.
+   LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
+   be reachable.  This turns on a kludge that causes the control flow
+   information to be inaccurate and not suitable for passes like GCSE.  */
 
 static void
-find_basic_blocks (f, nonlocal_label_list)
+find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
      rtx f, nonlocal_label_list;
+     int live_reachable_p;
 {
   register rtx insn;
   register int i;
   register char *block_live = (char *) alloca (n_basic_blocks);
   register char *block_marked = (char *) alloca (n_basic_blocks);
+  /* An array of CODE_LABELs, indexed by UID for the start of the active
+     EH handler for each insn in F.  */
+  rtx *active_eh_handler;
   /* List of label_refs to all labels whose addresses are taken
      and used as data.  */
   rtx label_value_list;
-  rtx x, note;
+  rtx x, note, eh_note;
   enum rtx_code prev_code, code;
   int depth, pass;
+  int in_libcall_block = 0;
 
   pass = 1;
+  active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx));
  restart:
 
   label_value_list = 0;
   block_live_static = block_live;
   bzero (block_live, n_basic_blocks);
   bzero (block_marked, n_basic_blocks);
+  bzero (basic_block_computed_jump_target, n_basic_blocks);
+  bzero (active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx));
+  current_function_has_computed_jump = 0;
 
   /* Initialize with just block 0 reachable and no blocks marked.  */
   if (n_basic_blocks > 0)
@@ -430,9 +426,15 @@ find_basic_blocks (f, nonlocal_label_list)
      the block it is in.   Also mark as reachable any blocks headed by labels
      that must not be deleted.  */
 
-  for (insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
+  for (eh_note = NULL_RTX, insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
        insn; insn = NEXT_INSN (insn))
     {
+
+      /* Track when we are inside in LIBCALL block.  */
+      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+         && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+       in_libcall_block = 1;
+
       code = GET_CODE (insn);
       if (code == NOTE)
        {
@@ -447,7 +449,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 || eh_note)
+                          && ! in_libcall_block)
                       || prev_code == BARRIER)))
        {
          basic_block_head[++i] = insn;
@@ -475,29 +478,55 @@ find_basic_blocks (f, nonlocal_label_list)
          /* Make a list of all labels referred to other than by jumps.  */
          for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
            if (REG_NOTE_KIND (note) == REG_LABEL)
-             label_value_list = gen_rtx (EXPR_LIST, VOIDmode, XEXP (note, 0),
-                                         label_value_list);
+             label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
+                                                   label_value_list);
        }
 
+      /* Keep a lifo list of the currently active exception handlers.  */
+      if (GET_CODE (insn) == NOTE)
+       {
+         if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+           {
+             for (x = exception_handler_labels; x; x = XEXP (x, 1))
+               if (CODE_LABEL_NUMBER (XEXP (x, 0)) == NOTE_BLOCK_NUMBER (insn))
+                 {
+                   eh_note = gen_rtx_EXPR_LIST (VOIDmode,
+                                                XEXP (x, 0), eh_note);
+                   break;
+                 }
+             if (x == NULL_RTX)
+               abort ();
+           }
+         else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+           eh_note = XEXP (eh_note, 1);
+       }
+      /* If we encounter a CALL_INSN, note which exception handler it
+        might pass control to.
+
+        If doing asynchronous exceptions, record the active EH handler
+        for every insn, since most insns can throw.  */
+      else if (eh_note
+              && (asynchronous_exceptions
+                  || (GET_CODE (insn) == CALL_INSN
+                      && ! in_libcall_block)))
+       active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0);
+
       BLOCK_NUM (insn) = i;
 
       if (code != NOTE)
        prev_code = code;
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+         && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+       in_libcall_block = 0;
     }
 
-  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;
-
-  for (x = forced_labels; x; x = XEXP (x, 1))
-    if (! LABEL_REF_NONLOCAL_P (x))
-      block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
+  n_basic_blocks = i + 1;
 
   /* Record which basic blocks control can drop in to.  */
 
@@ -519,76 +548,6 @@ find_basic_blocks (f, nonlocal_label_list)
       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,
-        when there are computed gotos, we can't tell which labels they jump
-        to, of all the possibilities.
-
-        Tablejumps and casesi insns are OK and we can recognize them by
-        a (use (label_ref)).  */
-
-      for (insn = f; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == JUMP_INSN)
-         {
-           rtx pat = PATTERN (insn);
-           int computed_jump = 0;
-
-           if (GET_CODE (pat) == PARALLEL)
-             {
-               int len = XVECLEN (pat, 0);
-               int has_use_labelref = 0;
-
-               for (i = len - 1; i >= 0; i--)
-                 if (GET_CODE (XVECEXP (pat, 0, i)) == USE
-                     && (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
-                         == LABEL_REF))
-                   has_use_labelref = 1;
-
-               if (! has_use_labelref)
-                 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))))
-                     computed_jump = 1;
-             }
-           else if (GET_CODE (pat) == SET
-                    && SET_DEST (pat) == pc_rtx
-                    && uses_reg_or_mem (SET_SRC (pat)))
-             computed_jump = 1;
-                   
-           if (computed_jump)
-             {
-               for (x = label_value_list; x; x = XEXP (x, 1))
-                 mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                                 insn, 0);
-
-               for (x = forced_labels; x; x = XEXP (x, 1))
-                 mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
-                             insn, 0);
-             }
-         }
-
-      /* Find all call insns and mark them as possibly jumping
-        to all the nonlocal goto handler labels.  */
-
-      for (insn = f; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == CALL_INSN)
-         {
-           for (x = nonlocal_label_list; x; x = XEXP (x, 1))
-             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
-              calls will not do a nonlocal goto.
-
-              For example, if the nested functions that do the
-              nonlocal gotos do not have their addresses taken, then
-              only calls to those functions or to other nested
-              functions that use them could possibly do nonlocal
-              gotos.  */
-         }
-
       /* 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.
@@ -608,22 +567,135 @@ 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 we have any forced labels, mark them as potentially
+                  reachable from this block.  */
+               for (x = forced_labels; x; x = XEXP (x, 1))
+                 if (! LABEL_REF_NONLOCAL_P (x))
+                   mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)),
+                                   insn, 0);
+
+               /* Now scan the insns for this block, we may need to make
+                  edges for some of them to various non-obvious locations
+                  (exception handlers, nonlocal labels, etc).  */
+               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')
+                     {
+                       
+                       /* References to labels in non-jumping insns have
+                          REG_LABEL notes attached to them.
+
+                          This can happen for computed gotos; we don't care
+                          about them here since the values are also on the
+                          label_value_list and will be marked live if we find
+                          a live computed goto.
+
+                          This can also happen when we take the address of
+                          a label to pass as an argument to __throw.  Note
+                          throw only uses the value to determine what handler
+                          should be called -- ie the label is not used as
+                          a jump target, it just marks regions in the code.
+
+                          In theory we should be able to ignore the REG_LABEL
+                          notes, but we have to make sure that the label and
+                          associated insns aren't marked dead, so we make
+                          the block in question live and create an edge from
+                          this insn to the label.  This is not strictly
+                          correct, but it is close enough for now.  */
+                       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;
+                               mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, x),
+                                               insn, 0);
+                             }
+                         }
+
+                       /* If this is a computed jump, then mark it as
+                          reaching everything on the label_value_list
+                          and forced_labels list.  */
+                       if (computed_jump_p (insn))
+                         {
+                           current_function_has_computed_jump = 1;
+                           for (x = label_value_list; x; x = XEXP (x, 1))
+                             {
+                               int b = BLOCK_NUM (XEXP (x, 0));
+                               basic_block_computed_jump_target[b] = 1;
+                               mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+                                                                  XEXP (x, 0)),
+                                               insn, 0);
+                             }
+
+                           for (x = forced_labels; x; x = XEXP (x, 1))
+                             {
+                               int b = BLOCK_NUM (XEXP (x, 0));
+                               basic_block_computed_jump_target[b] = 1;
+                               mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+                                                                  XEXP (x, 0)),
+                                               insn, 0);
+                             }
+                         }
+
+                       /* If this is a CALL_INSN, then mark it as reaching
+                          the active EH handler for this CALL_INSN.  If
+                          we're handling asynchronous exceptions mark every
+                          insn as reaching the active EH handler.
+
+                          Also mark the CALL_INSN as reaching any nonlocal
+                          goto sites.  */
+                       else if (asynchronous_exceptions
+                                || (GET_CODE (insn) == CALL_INSN
+                                    && ! find_reg_note (insn, REG_RETVAL,
+                                                        NULL_RTX)))
+                         {
+                           if (active_eh_handler[INSN_UID (insn)])
+                             mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+                                                                active_eh_handler[INSN_UID (insn)]),
+                                             insn, 0);
+
+                           if (!asynchronous_exceptions)
+                             {
+                               for (x = nonlocal_label_list;
+                                    x;
+                                    x = XEXP (x, 1))
+                                 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 calls will not do a nonlocal goto.
+
+                              For example, if the nested functions that
+                              do the nonlocal gotos do not have their
+                              addresses taken, then only calls to those
+                              functions or to other nested functions that
+                              use them could possibly do nonlocal gotos.  */
+                         }
+                     }
+                 }
              }
        }
 
-      /* ??? 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.  */
+      /* This should never happen.  If it does that means we've computed an
+        incorrect flow graph, which can lead to aborts/crashes later in the
+        compiler or incorrect code generation.
 
+        We used to try and continue here, but that's just asking for trouble
+        later during the compile or at runtime.  It's easier to debug the
+        problem here than later!  */
       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;
+         abort ();
 
       /* Now delete the code for any basic blocks that can't be reached.
         They can occur because jump_optimize does not recognize
@@ -667,6 +739,51 @@ find_basic_blocks (f, nonlocal_label_list)
                /* Turn the head into a deleted insn note.  */
                if (GET_CODE (insn) == BARRIER)
                  abort ();
+
+               /* If the head of this block is a CODE_LABEL, then it might
+                  be the label for an exception handler which can't be
+                  reached.
+
+                  We need to remove the label from the exception_handler_label
+                  list and remove the associated NOTE_EH_REGION_BEG and
+                  NOTE_EH_REGION_END notes.  */
+               if (GET_CODE (insn) == CODE_LABEL)
+                 {
+                   rtx x, *prev = &exception_handler_labels;
+
+                   for (x = exception_handler_labels; x; x = XEXP (x, 1))
+                     {
+                       if (XEXP (x, 0) == insn)
+                         {
+                           /* Found a match, splice this label out of the
+                              EH label list.  */
+                           *prev = XEXP (x, 1);
+                           XEXP (x, 1) = NULL_RTX;
+                           XEXP (x, 0) = NULL_RTX;
+
+                           /* Now we have to find the EH_BEG and EH_END notes
+                              associated with this label and remove them.  */
+
+                           for (x = get_insns (); x; x = NEXT_INSN (x))
+                             {
+                               if (GET_CODE (x) == NOTE
+                                   && ((NOTE_LINE_NUMBER (x)
+                                        == NOTE_INSN_EH_REGION_BEG)
+                                       || (NOTE_LINE_NUMBER (x)
+                                           == NOTE_INSN_EH_REGION_END))
+                                   && (NOTE_BLOCK_NUMBER (x)
+                                       == CODE_LABEL_NUMBER (insn)))
+                                 {
+                                   NOTE_LINE_NUMBER (x) = NOTE_INSN_DELETED;
+                                   NOTE_SOURCE_FILE (x) = 0;
+                                 }
+                             }
+                           break;
+                         }
+                       prev = &XEXP (x, 1);
+                     }
+                 }
+                
                PUT_CODE (insn, NOTE);
                NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
                NOTE_SOURCE_FILE (insn) = 0;
@@ -711,6 +828,14 @@ find_basic_blocks (f, nonlocal_label_list)
                          && INSN_UID (label) != 0
                          && BLOCK_NUM (label) == j)
                        {
+                         int k;
+
+                         /* The deleted blocks still show up in the cfg,
+                            so we must set basic_block_drops_in for blocks
+                            I to J inclusive to keep the cfg accurate.  */
+                         for (k = i; k <= j; k++)
+                           basic_block_drops_in[k] = 1;
+
                          PUT_CODE (insn, NOTE);
                          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
                          NOTE_SOURCE_FILE (insn) = 0;
@@ -723,14 +848,14 @@ 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.
@@ -743,45 +868,35 @@ find_basic_blocks (f, nonlocal_label_list)
        {
          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
-/* Subroutines of find_basic_blocks.  */
 
-/* Return 1 if X contain a REG or MEM that is not in the constant pool.  */
+/* Record INSN's block number as BB.  */
 
-static int
-uses_reg_or_mem (x)
-     rtx x;
+void
+set_block_num (insn, bb)
+     rtx insn;
+     int bb;
 {
-  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;
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+  if (INSN_UID (insn) >= max_uid_for_flow)
     {
-      if (fmt[i] == 'e'
-         && 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)))
-           return 1;
+      /* Add one-eighth the size so we don't keep calling xrealloc.  */
+      max_uid_for_flow = INSN_UID (insn) + (INSN_UID (insn) + 7) / 8;
+      uid_block_number = (int *)
+       xrealloc (uid_block_number, (max_uid_for_flow + 1) * sizeof (int));
     }
-
-  return 0;
+  BLOCK_NUM (insn) = bb;
 }
 
+\f
+/* Subroutines of find_basic_blocks.  */
+
 /* Check expression X for label references;
    if one is found, add INSN to the label's chain of references.
 
@@ -857,6 +972,80 @@ flow_delete_insn (insn)
   return NEXT_INSN (insn);
 }
 \f
+/* Perform data flow analysis.
+   F is the first insn of the function and NREGS the number of register numbers
+   in use.  */
+
+void
+life_analysis (f, nregs, file)
+     rtx f;
+     int nregs;
+     FILE *file;
+{
+#ifdef ELIMINABLE_REGS
+  register size_t i;
+  static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
+#endif
+
+  /* Record which registers will be eliminated.  We use this in
+     mark_used_regs.  */
+
+  CLEAR_HARD_REG_SET (elim_reg_set);
+
+#ifdef ELIMINABLE_REGS
+  for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
+    SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
+#else
+  SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
+#endif
+
+  life_analysis_1 (f, nregs);
+  if (file)
+    dump_flow_info (file);
+
+  free_basic_block_vars (1);
+}
+
+/* Free the variables allocated by find_basic_blocks.
+
+   KEEP_HEAD_END_P is non-zero if basic_block_head and basic_block_end
+   are not to be freed.  */
+
+void
+free_basic_block_vars (keep_head_end_p)
+     int keep_head_end_p;
+{
+  if (basic_block_drops_in)
+    {
+      free (basic_block_drops_in);
+      /* Tell dump_flow_info this isn't available anymore.  */
+      basic_block_drops_in = 0;
+    }
+  if (basic_block_loop_depth)
+    {
+      free (basic_block_loop_depth);
+      basic_block_loop_depth = 0;
+    }
+  if (uid_block_number)
+    {
+      free (uid_block_number);
+      uid_block_number = 0;
+    }
+  if (uid_volatile)
+    {
+      free (uid_volatile);
+      uid_volatile = 0;
+    }
+
+  if (! keep_head_end_p && basic_block_head)
+    {
+      free (basic_block_head);
+      basic_block_head = 0;
+      free (basic_block_end);
+      basic_block_end = 0;
+    }
+}
+
 /* Determine which registers are live at the start of each
    basic block of the function whose first insn is F.
    NREGS is the number of registers used in F.
@@ -865,11 +1054,10 @@ flow_delete_insn (insn)
    regset_size and regset_bytes are also set here.  */
 
 static void
-life_analysis (f, nregs)
+life_analysis_1 (f, nregs)
      rtx f;
      int nregs;
 {
-  register regset tem;
   int first_pass;
   int changed;
   /* For each basic block, a bitmask of regs
@@ -915,28 +1103,20 @@ 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, &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,
+                     &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, &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))
     {
@@ -949,8 +1129,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))
            {
@@ -1011,17 +1208,17 @@ life_analysis (f, nregs)
   if (n_basic_blocks > 0)
 #ifdef EXIT_IGNORE_STACK
     if (! EXIT_IGNORE_STACK
-       || (! FRAME_POINTER_REQUIRED && flag_omit_frame_pointer))
+       || (! FRAME_POINTER_REQUIRED
+           && ! current_function_calls_alloca
+           && flag_omit_frame_pointer))
 #endif
       {
        /* 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
@@ -1030,38 +1227,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
@@ -1096,21 +1288,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;
            }
@@ -1124,23 +1313,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]
@@ -1155,12 +1343,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.  */
@@ -1170,10 +1354,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
@@ -1189,10 +1371,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
@@ -1223,14 +1406,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
 
@@ -1243,14 +1428,23 @@ 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;
+                                }
+                            });
+
+
+  free_regset_vector (basic_block_live_at_end, n_basic_blocks);
+  free_regset_vector (basic_block_new_live_at_end, n_basic_blocks);
+  free_regset_vector (basic_block_significant, n_basic_blocks);
+  basic_block_live_at_end = (regset *)0;
+  basic_block_new_live_at_end = (regset *)0;
+  basic_block_significant = (regset *)0;
 
   obstack_free (&flow_obstack, NULL_PTR);
 }
@@ -1264,66 +1458,60 @@ 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 ((char *) reg_n_refs, max_regno * sizeof (int));
+  /* Recalculate the register space, in case it has grown.  Old style
+     vector oriented regsets would set regset_{size,bytes} here also.  */
+  allocate_reg_info (max_regno, FALSE, FALSE);
 
-  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));
+  /* 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.  */
   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,
+                     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,
-   taking the space for all those regsets from SPACE.
-   SPACE is of type regset, but it is really as long as NELTS regsets.
-   BYTES_PER_ELT is the number of bytes in one regset.  */
+/* Make each element of VECTOR point at a regset.  The vector has
+   NELTS elements, and space is allocated from the ALLOC_OBSTACK
+   obstack.  */
 
-static void
-init_regset_vector (vector, space, nelts, bytes_per_elt)
+void
+init_regset_vector (vector, nelts, 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]);
     }
 }
 
+/* Release any additional space allocated for each element of VECTOR point
+   other than the regset header itself.  The vector has NELTS elements.  */
+
+void
+free_regset_vector (vector, nelts)
+     regset *vector;
+     int nelts;
+{
+  register int i;
+
+  for (i = 0; i < nelts; i++)
+    FREE_REG_SET (vector[i]);
+}
+
 /* Compute the registers live at the beginning of a basic block
    from those live at the end.
 
@@ -1360,11 +1548,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.  */
@@ -1375,8 +1560,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;
@@ -1396,32 +1581,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.  */
@@ -1448,11 +1623,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.
@@ -1508,19 +1679,17 @@ 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.  */
 #ifdef AUTO_INC_DEC
          {
-           register rtx x = PATTERN (insn);
+           register rtx x = single_set (insn);
+
            /* Does this instruction increment or decrement a register?  */
-           if (final && GET_CODE (x) == SET
+           if (final && x != 0
                && GET_CODE (SET_DEST (x)) == REG
                && (GET_CODE (SET_SRC (x)) == PLUS
                    || GET_CODE (SET_SRC (x)) == MINUS)
@@ -1595,26 +1764,24 @@ 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.  */
                  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                    if (global_regs[i])
                      mark_used_regs (old, live,
-                                     gen_rtx (REG, reg_raw_mode[i], i),
+                                     gen_rtx_REG (reg_raw_mode[i], i),
                                      final, insn);
 
                  /* Calls also clobber memory.  */
@@ -1622,11 +1789,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)
                {
@@ -1634,11 +1798,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)++;
                }
            }
 
@@ -1648,33 +1812,23 @@ propagate_block (old, first, last, final, significant, bnum)
 
          if (final)
            {
-             for (i = 0; i < regset_size; i++)
+             register int regno;
+             register int *p;
+
+             EXECUTE_IF_AND_COMPL_IN_REG_SET
+               (live, maxlive, 0, regno,
+                {
+                  regs_sometimes_live[sometimes_max++] = regno;
+                  SET_REGNO_REG_SET (maxlive, regno);
+                });
+
+             p = regs_sometimes_live;
+             for (i = 0; i < sometimes_max; i++)
                {
-                 register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i];
-
-                 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++;
-                         }
-                   }
+                 regno = *p++;
+                 if (REGNO_REG_SET_P (old, regno))
+                   REG_LIVE_LENGTH (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]++;
-                 }
-             }
            }
        }
     flushed: ;
@@ -1682,6 +1836,11 @@ propagate_block (old, first, last, final, significant, bnum)
        break;
     }
 
+  FREE_REG_SET (dead);
+  FREE_REG_SET (live);
+  if (final)
+    FREE_REG_SET (maxlive);
+
   if (num_scratch > max_scratch)
     max_scratch = num_scratch;
 }
@@ -1698,13 +1857,15 @@ insn_dead_p (x, needed, call_ok)
      regset needed;
      int call_ok;
 {
-  register RTX_CODE code = GET_CODE (x);
+  enum rtx_code code = GET_CODE (x);
+
   /* If setting something that's a reg or part of one,
      see if that register's altered value will be live.  */
 
   if (code == SET)
     {
-      register rtx r = SET_DEST (x);
+      rtx r = SET_DEST (x);
+
       /* A SET that is a subroutine call cannot be dead.  */
       if (! call_ok && GET_CODE (SET_SRC (x)) == CALL)
        return 0;
@@ -1718,18 +1879,13 @@ insn_dead_p (x, needed, call_ok)
          && rtx_equal_p (r, last_mem_set))
        return 1;
 
-      while (GET_CODE (r) == SUBREG
-            || GET_CODE (r) == STRICT_LOW_PART
-            || GET_CODE (r) == ZERO_EXTRACT
-            || GET_CODE (r) == SIGN_EXTRACT)
+      while (GET_CODE (r) == SUBREG || GET_CODE (r) == STRICT_LOW_PART
+            || GET_CODE (r) == ZERO_EXTRACT)
        r = SUBREG_REG (r);
 
       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);
+         int regno = REGNO (r);
 
          /* Don't delete insns to set global regs.  */
          if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
@@ -1741,10 +1897,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
@@ -1754,35 +1910,40 @@ 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;
            }
 
          return 1;
        }
     }
+
   /* If performing several activities,
      insn is dead if each activity is individually dead.
      Also, CLOBBERs and USEs can be ignored; a CLOBBER or USE
      that's inside a PARALLEL doesn't make the insn worth keeping.  */
   else if (code == PARALLEL)
     {
-      register int i = XVECLEN (x, 0);
+      int i = XVECLEN (x, 0);
+
       for (i--; i >= 0; i--)
-       {
-         rtx elt = XVECEXP (x, 0, i);
-         if (!insn_dead_p (elt, needed, call_ok)
-             && GET_CODE (elt) != CLOBBER
-             && GET_CODE (elt) != USE)
-           return 0;
-       }
+       if (GET_CODE (XVECEXP (x, 0, i)) != CLOBBER
+           && GET_CODE (XVECEXP (x, 0, i)) != USE
+           && ! insn_dead_p (XVECEXP (x, 0, i), needed, call_ok))
+         return 0;
+
       return 1;
     }
-  /* We do not check CLOBBER or USE here.
-     An insn consisting of just a CLOBBER or just a USE
-     should not be deleted.  */
+
+  /* A CLOBBER of a pseudo-register that is dead serves no purpose.  That
+     is not necessarily true for hard registers.  */
+  else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG
+          && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER
+          && ! REGNO_REG_SET_P (needed, REGNO (XEXP (x, 0))))
+    return 1;
+
+  /* We do not check other CLOBBER or USE here.  An insn consisting of just
+     a CLOBBER or just a USE should not be deleted.  */
   return 0;
 }
 
@@ -1853,18 +2014,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
@@ -1878,11 +2040,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.
@@ -1975,18 +2135,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;
+      /* Mark it as dead before this insn.  */
+      SET_REGNO_REG_SET (dead, regno);
 
       /* A hard reg in a wide mode may really be multiple registers.
         If so, mark all of them just like the first.  */
@@ -2002,17 +2159,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.  */
@@ -2035,7 +2189,7 @@ mark_set_1 (needed, dead, x, insn, significant)
                  reg_next_use[i] = 0;
 
                  regs_ever_live[i] = 1;
-                 reg_n_sets[i]++;
+                 REG_N_SETS (i)++;
                }
            }
          else
@@ -2046,25 +2200,25 @@ mark_set_1 (needed, dead, x, insn, significant)
 
              /* 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.
@@ -2079,7 +2233,7 @@ mark_set_1 (needed, dead, x, insn, significant)
                  && (regno >= FIRST_PSEUDO_REGISTER
                      || asm_noperands (PATTERN (y)) < 0))
                LOG_LINKS (y)
-                 = gen_rtx (INSN_LIST, VOIDmode, insn, LOG_LINKS (y));
+                 = gen_rtx_INSN_LIST (VOIDmode, insn, LOG_LINKS (y));
            }
          else if (! some_needed)
            {
@@ -2088,8 +2242,8 @@ mark_set_1 (needed, dead, x, insn, significant)
                 be eliminated (because the same insn does something useful).
                 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)]++;
+               = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
+             REG_N_DEATHS (REGNO (reg))++;
            }
          else
            {
@@ -2103,14 +2257,12 @@ 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],
-                                       regno + i),
-                              REG_NOTES (insn));
+                   = gen_rtx_EXPR_LIST (REG_UNUSED,
+                                        gen_rtx_REG (reg_raw_mode[regno + i],
+                                                     regno + i),
+                                        REG_NOTES (insn));
            }
        }
     }
@@ -2122,7 +2274,7 @@ mark_set_1 (needed, dead, x, insn, significant)
   else if (GET_CODE (reg) == SCRATCH && insn != 0)
     {
       REG_NOTES (insn)
-       = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn));
+       = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
       num_scratch++;
     }
 }
@@ -2196,14 +2348,18 @@ find_auto_inc (needed, x, insn)
                 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),
+                                    gen_rtx_fmt_e (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,
@@ -2233,7 +2389,7 @@ find_auto_inc (needed, x, insn)
                 so is not correct in the pre-inc case.  */
 
              validate_change (insn, &XEXP (x, 0),
-                              gen_rtx (inc_code, Pmode, q),
+                              gen_rtx_fmt_e (inc_code, Pmode, q),
                               1);
              validate_change (incr, &XEXP (y, 0), q, 1);
              if (! apply_change_group ())
@@ -2264,14 +2420,13 @@ 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;
@@ -2281,7 +2436,7 @@ find_auto_inc (needed, x, insn)
             has an implicit side effect.  */
 
          REG_NOTES (insn)
-           = gen_rtx (EXPR_LIST, REG_INC, addr, 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.  */
@@ -2303,11 +2458,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)++;
            }
        }
     }
@@ -2365,9 +2520,13 @@ 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;
+      /* 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;
 
 #ifdef AUTO_INC_DEC
       if (final)
@@ -2379,15 +2538,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
@@ -2395,13 +2559,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;
+       int some_needed = REGNO_REG_SET_P (needed, regno);
+       int 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)
@@ -2442,14 +2604,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)
@@ -2477,14 +2637,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.
@@ -2493,7 +2653,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])
@@ -2515,8 +2675,8 @@ mark_used_regs (needed, live, x, final, insn)
                if (! some_needed)
                  {
                    REG_NOTES (insn)
-                     = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn));
-                   reg_n_deaths[regno]++;
+                     = gen_rtx_EXPR_LIST (REG_DEAD, x, REG_NOTES (insn));
+                   REG_N_DEATHS (regno)++;
                  }
                else
                  {
@@ -2527,15 +2687,13 @@ 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, reg_raw_mode[regno + i],
-                                             regno + i),
-                                    REG_NOTES (insn));
+                         = gen_rtx_EXPR_LIST (REG_DEAD,
+                                              gen_rtx_REG (reg_raw_mode[regno + i],
+                                                           regno + i),
+                                              REG_NOTES (insn));
                  }
              }
          }
@@ -2572,6 +2730,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.  */
@@ -2610,19 +2775,26 @@ 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))
+         || (! FRAME_POINTER_REQUIRED
+             && ! current_function_calls_alloca
+             && 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;
+
+    default:
       break;
     }
 
@@ -2662,7 +2834,7 @@ try_pre_increment_1 (insn)
 {
   /* Find the next use of this reg.  If in same basic block,
      make it do pre-increment or pre-decrement if appropriate.  */
-  rtx x = PATTERN (insn);
+  rtx x = single_set (insn);
   HOST_WIDE_INT amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1)
                * INTVAL (XEXP (SET_SRC (x), 1)));
   int regno = REGNO (SET_DEST (x));
@@ -2670,10 +2842,9 @@ 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))
+      && try_pre_increment (y, SET_DEST (x), amount))
     {
       /* We have found a suitable auto-increment
         and already changed insn Y to do it.
@@ -2687,8 +2858,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;
     }
@@ -2767,14 +2938,14 @@ try_pre_increment (insn, reg, amount)
 
   /* 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))
+                        gen_rtx_fmt_e (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));
+  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg, REG_NOTES (insn));
   return 1;
 }
 
@@ -2789,7 +2960,7 @@ try_pre_increment (insn, reg, amount)
    If REG appears more than once, or is used other than in such an address,
    return (rtx)1.  */
 
-static rtx
+rtx
 find_use_as_address (x, reg, plusconst)
      register rtx x;
      rtx reg;
@@ -2861,19 +3032,24 @@ 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_SETS (i))
+         fprintf (file, "; set %d time%s", REG_N_SETS (i),
+                  (REG_N_SETS (i) == 1) ? "" : "s");
+       if (REG_USERVAR_P (regno_reg_rtx[i]))
+         fprintf (file, "; user var");
+       if (REG_N_DEATHS (i) != 1)
+         fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+       if (REG_N_CALLS_CROSSED (i) == 1)
          fprintf (file, "; crosses 1 call");
-       else if (reg_n_calls_crossed[i])
-         fprintf (file, "; crosses %d calls", reg_n_calls_crossed[i]);
+       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);
@@ -2922,14 +3098,887 @@ dump_flow_info (file)
        }
       fprintf (file, "\nRegisters live at start:");
       for (regno = 0; regno < max_regno; regno++)
+       if (REGNO_REG_SET_P (basic_block_live_at_start[i], regno))
+         fprintf (file, " %d", regno);
+      fprintf (file, "\n");
+    }
+  fprintf (file, "\n");
+}
+
+\f
+/* Like print_rtl, but also print out live information for the start of each
+   basic block.  */
+
+void
+print_rtl_with_bb (outf, rtx_first)
+     FILE *outf;
+     rtx rtx_first;
+{
+  register rtx tmp_rtx;
+
+  if (rtx_first == 0)
+    fprintf (outf, "(nil)\n");
+
+  else
+    {
+      int i, bb;
+      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
+      int max_uid = get_max_uid ();
+      int *start = (int *) alloca (max_uid * sizeof (int));
+      int *end = (int *) alloca (max_uid * sizeof (int));
+      char *in_bb_p = (char *) alloca (max_uid * sizeof (enum bb_state));
+
+      for (i = 0; i < max_uid; i++)
        {
-         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);
+         start[i] = end[i] = -1;
+         in_bb_p[i] = NOT_IN_BB;
+       }
+
+      for (i = n_basic_blocks-1; i >= 0; i--)
+       {
+         rtx x;
+         start[INSN_UID (basic_block_head[i])] = i;
+         end[INSN_UID (basic_block_end[i])] = i;
+         for (x = basic_block_head[i]; x != NULL_RTX; x = NEXT_INSN (x))
+           {
+             in_bb_p[ INSN_UID(x)]
+               = (in_bb_p[ INSN_UID(x)] == NOT_IN_BB)
+                ? IN_ONE_BB : IN_MULTIPLE_BB;
+             if (x == basic_block_end[i])
+               break;
+           }
+       }
+
+      for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
+       {
+         if ((bb = start[INSN_UID (tmp_rtx)]) >= 0)
+           {
+             fprintf (outf, ";; Start of basic block %d, registers live:",
+                      bb);
+
+             EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i,
+                                        {
+                                          fprintf (outf, " %d", i);
+                                          if (i < FIRST_PSEUDO_REGISTER)
+                                            fprintf (outf, " [%s]",
+                                                     reg_names[i]);
+                                        });
+             putc ('\n', outf);
+           }
+
+         if (in_bb_p[ INSN_UID(tmp_rtx)] == NOT_IN_BB
+             && GET_CODE (tmp_rtx) != NOTE
+             && GET_CODE (tmp_rtx) != BARRIER)
+           fprintf (outf, ";; Insn is not within a basic block\n");
+         else if (in_bb_p[ INSN_UID(tmp_rtx)] == IN_MULTIPLE_BB)
+           fprintf (outf, ";; Insn is in multiple basic blocks\n");
+
+         print_rtl_single (outf, tmp_rtx);
+
+         if ((bb = end[INSN_UID (tmp_rtx)]) >= 0)
+           fprintf (outf, ";; End of basic block %d\n", bb);
+
+         putc ('\n', outf);
+       }
+    }
+}
+
+\f
+/* Integer list support.  */
+
+/* Allocate a node from list *HEAD_PTR.  */
+
+static int_list_ptr
+alloc_int_list_node (head_ptr)
+     int_list_block **head_ptr;
+{
+  struct int_list_block *first_blk = *head_ptr;
+
+  if (first_blk == NULL || first_blk->nodes_left <= 0)
+    {
+      first_blk = (struct int_list_block *) xmalloc (sizeof (struct int_list_block));
+      first_blk->nodes_left = INT_LIST_NODES_IN_BLK;
+      first_blk->next = *head_ptr;
+      *head_ptr = first_blk;
+    }
+
+  first_blk->nodes_left--;
+  return &first_blk->nodes[first_blk->nodes_left];
+}
+
+/* Pointer to head of predecessor/successor block list.  */
+static int_list_block *pred_int_list_blocks;
+
+/* Add a new node to integer list LIST with value VAL.
+   LIST is a pointer to a list object to allow for different implementations.
+   If *LIST is initially NULL, the list is empty.
+   The caller must not care whether the element is added to the front or
+   to the end of the list (to allow for different implementations).  */
+
+static int_list_ptr
+add_int_list_node (blk_list, list, val)
+     int_list_block **blk_list;
+     int_list **list;
+     int val;
+{
+  int_list_ptr p = alloc_int_list_node (blk_list);
+
+  p->val = val;
+  p->next = *list;
+  *list = p;
+  return p;
+}
+
+/* Free the blocks of lists at BLK_LIST.  */
+
+void
+free_int_list (blk_list)
+     int_list_block **blk_list;
+{
+  int_list_block *p, *next;
+
+  for (p = *blk_list; p != NULL; p = next)
+    {
+      next = p->next;
+      free (p);
+    }
+
+  /* Mark list as empty for the next function we compile.  */
+  *blk_list = NULL;
+}
+\f
+/* Predecessor/successor computation.  */
+
+/* Mark PRED_BB a precessor of SUCC_BB,
+   and conversely SUCC_BB a successor of PRED_BB.  */
+
+static void
+add_pred_succ (pred_bb, succ_bb, s_preds, s_succs, num_preds, num_succs)
+     int pred_bb;
+     int succ_bb;
+     int_list_ptr *s_preds;
+     int_list_ptr *s_succs;
+     int *num_preds;
+     int *num_succs;
+{
+  if (succ_bb != EXIT_BLOCK)
+    {
+      add_int_list_node (&pred_int_list_blocks, &s_preds[succ_bb], pred_bb);
+      num_preds[succ_bb]++;
+    }
+  if (pred_bb != ENTRY_BLOCK)
+    {
+      add_int_list_node (&pred_int_list_blocks, &s_succs[pred_bb], succ_bb);
+      num_succs[pred_bb]++;
+    }
+}
+
+/* Compute the predecessors and successors for each block.  */
+void
+compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
+     int_list_ptr *s_preds;
+     int_list_ptr *s_succs;
+     int *num_preds;
+     int *num_succs;
+{
+  int bb, clear_local_bb_vars = 0;
+
+  bzero ((char *) s_preds, n_basic_blocks * sizeof (int_list_ptr));
+  bzero ((char *) s_succs, n_basic_blocks * sizeof (int_list_ptr));
+  bzero ((char *) num_preds, n_basic_blocks * sizeof (int));
+  bzero ((char *) num_succs, n_basic_blocks * sizeof (int));
+
+  /* This routine can be called after life analysis; in that case
+     basic_block_drops_in and uid_block_number will not be available
+     and we must recompute their values.  */
+  if (basic_block_drops_in == NULL || uid_block_number == NULL)
+    {
+      clear_local_bb_vars = 1;
+      basic_block_drops_in = (char *) alloca (n_basic_blocks);
+      uid_block_number = (int *) alloca ((get_max_uid () + 1) * sizeof (int));
+
+      bzero ((char *) basic_block_drops_in, n_basic_blocks * sizeof (char));
+      bzero ((char *) uid_block_number, n_basic_blocks * sizeof (int));
+
+      /* Scan each basic block setting basic_block_drops_in and
+        uid_block_number as needed.  */
+      for (bb = 0; bb < n_basic_blocks; bb++)
+       {
+         rtx insn, stop_insn;
+
+         if (bb == 0)
+           stop_insn = NULL_RTX;
+         else
+           stop_insn = basic_block_end[bb-1];
+
+         /* Look backwards from the start of this block.  Stop if we
+            hit the start of the function or the end of a previous
+            block.  Don't walk backwards through blocks that are just
+            deleted insns!  */
+         for (insn = PREV_INSN (basic_block_head[bb]);
+              insn && insn != stop_insn && GET_CODE (insn) == NOTE;
+              insn = PREV_INSN (insn))
+           ;
+
+         /* Never set basic_block_drops_in for the first block.  It is
+            implicit.
+
+            If we stopped on anything other than a BARRIER, then this
+            block drops in.  */
+         if (bb != 0)
+           basic_block_drops_in[bb] = (insn ? GET_CODE (insn) != BARRIER : 1);
+
+         insn = basic_block_head[bb];
+         while (insn)
+           {
+             BLOCK_NUM (insn) = bb;
+             if (insn == basic_block_end[bb])
+               break;
+             insn = NEXT_INSN (insn);
+           }
+       }
+    }
+      
+  for (bb = 0; bb < n_basic_blocks; bb++)
+    {
+      rtx head;
+      rtx jump;
+
+      head = BLOCK_HEAD (bb);
+
+      if (GET_CODE (head) == CODE_LABEL)
+       for (jump = LABEL_REFS (head);
+            jump != head;
+            jump = LABEL_NEXTREF (jump))
+         {
+           if (! INSN_DELETED_P (CONTAINING_INSN (jump))
+               && (GET_CODE (CONTAINING_INSN (jump)) != NOTE
+                   || (NOTE_LINE_NUMBER (CONTAINING_INSN (jump))
+                       != NOTE_INSN_DELETED)))
+             add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb,
+                            s_preds, s_succs, num_preds, num_succs);
+         }
+
+      jump = BLOCK_END (bb);
+      /* If this is a RETURN insn or a conditional jump in the last
+        basic block, or a non-jump insn in the last basic block, then
+        this block reaches the exit block.  */
+      if ((GET_CODE (jump) == JUMP_INSN && GET_CODE (PATTERN (jump)) == RETURN)
+         || (((GET_CODE (jump) == JUMP_INSN
+               && condjump_p (jump) && !simplejump_p (jump))
+              || GET_CODE (jump) != JUMP_INSN)
+             && (bb == n_basic_blocks - 1)))
+       add_pred_succ (bb, EXIT_BLOCK, s_preds, s_succs, num_preds, num_succs);
+
+      if (basic_block_drops_in[bb])
+       add_pred_succ (bb - 1, bb, s_preds, s_succs, num_preds, num_succs);
+    }
+
+  add_pred_succ (ENTRY_BLOCK, 0, s_preds, s_succs, num_preds, num_succs);
+
+
+  /* If we allocated any variables in temporary storage, clear out the
+     pointer to the local storage to avoid dangling pointers.  */
+  if (clear_local_bb_vars)
+    {
+      basic_block_drops_in = NULL;
+      uid_block_number = NULL;
+    
+    }
+}
+
+void
+dump_bb_data (file, preds, succs)
+     FILE *file;
+     int_list_ptr *preds;
+     int_list_ptr *succs;
+{
+  int bb;
+  int_list_ptr p;
+
+  fprintf (file, "BB data\n\n");
+  for (bb = 0; bb < n_basic_blocks; bb++)
+    {
+      fprintf (file, "BB %d, start %d, end %d\n", bb,
+              INSN_UID (BLOCK_HEAD (bb)), INSN_UID (BLOCK_END (bb)));
+      fprintf (file, "  preds:");
+      for (p = preds[bb]; p != NULL; p = p->next)
+       {
+         int pred_bb = INT_LIST_VAL (p);
+         if (pred_bb == ENTRY_BLOCK)
+           fprintf (file, " entry");
+         else
+           fprintf (file, " %d", pred_bb);
        }
       fprintf (file, "\n");
+      fprintf (file, "  succs:");
+      for (p = succs[bb]; p != NULL; p = p->next)
+       {
+         int succ_bb = INT_LIST_VAL (p);
+         if (succ_bb == EXIT_BLOCK)
+           fprintf (file, " exit");
+         else
+           fprintf (file, " %d", succ_bb);
+       }
+      fprintf (file, "\n");
+    }
+  fprintf (file, "\n");
+}
+
+void
+dump_sbitmap (file, bmap)
+     FILE *file;
+     sbitmap bmap;
+{
+  int i,j,n;
+  int set_size = bmap->size;
+  int total_bits = bmap->n_bits;
+
+  fprintf (file, "  ");
+  for (i = n = 0; i < set_size && n < total_bits; i++)
+    {
+      for (j = 0; j < SBITMAP_ELT_BITS && n < total_bits; j++, n++)
+       {
+         if (n != 0 && n % 10 == 0)
+           fprintf (file, " ");
+         fprintf (file, "%d", (bmap->elms[i] & (1L << j)) != 0);
+       }
+    }
+  fprintf (file, "\n");
+}
+
+void
+dump_sbitmap_vector (file, title, subtitle, bmaps, n_maps)
+     FILE *file;
+     char *title, *subtitle;
+     sbitmap *bmaps;
+     int n_maps;
+{
+  int bb;
+
+  fprintf (file, "%s\n", title);
+  for (bb = 0; bb < n_maps; bb++)
+    {
+      fprintf (file, "%s %d\n", subtitle, bb);
+      dump_sbitmap (file, bmaps[bb]);
     }
   fprintf (file, "\n");
 }
+
+/* Free basic block data storage.  */
+
+void
+free_bb_mem ()
+{
+  free_int_list (&pred_int_list_blocks);
+}
+\f
+/* Bitmap manipulation routines.  */
+
+/* Allocate a simple bitmap of N_ELMS bits.  */
+
+sbitmap
+sbitmap_alloc (n_elms)
+     int n_elms;
+{
+  int bytes, size, amt;
+  sbitmap bmap;
+
+  size = SBITMAP_SET_SIZE (n_elms);
+  bytes = size * sizeof (SBITMAP_ELT_TYPE);
+  amt = (sizeof (struct simple_bitmap_def)
+        + bytes - sizeof (SBITMAP_ELT_TYPE));
+  bmap = (sbitmap) xmalloc (amt);
+  bmap->n_bits = n_elms;
+  bmap->size = size;
+  bmap->bytes = bytes;
+  return bmap;
+}
+
+/* Allocate a vector of N_VECS bitmaps of N_ELMS bits.  */
+
+sbitmap *
+sbitmap_vector_alloc (n_vecs, n_elms)
+     int n_vecs, n_elms;
+{
+  int i, bytes, offset, elm_bytes, size, amt, vector_bytes;
+  sbitmap *bitmap_vector;
+
+  size = SBITMAP_SET_SIZE (n_elms);
+  bytes = size * sizeof (SBITMAP_ELT_TYPE);
+  elm_bytes = (sizeof (struct simple_bitmap_def)
+              + bytes - sizeof (SBITMAP_ELT_TYPE));
+  vector_bytes = n_vecs * sizeof (sbitmap *);
+
+  /* Round up `vector_bytes' to account for the alignment requirements
+     of an sbitmap.  One could allocate the vector-table and set of sbitmaps
+     separately, but that requires maintaining two pointers or creating
+     a cover struct to hold both pointers (so our result is still just
+     one pointer).  Neither is a bad idea, but this is simpler for now.  */
+  {
+    /* Based on DEFAULT_ALIGNMENT computation in obstack.c.  */
+    struct { char x; SBITMAP_ELT_TYPE y; } align;
+    int alignment = (char *) & align.y - & align.x;
+    vector_bytes = (vector_bytes + alignment - 1) & ~ (alignment - 1);
+  }
+
+  amt = vector_bytes + (n_vecs * elm_bytes);
+  bitmap_vector = (sbitmap *) xmalloc (amt);
+
+  for (i = 0, offset = vector_bytes;
+       i < n_vecs;
+       i++, offset += elm_bytes)
+    {
+      sbitmap b = (sbitmap) ((char *) bitmap_vector + offset);
+      bitmap_vector[i] = b;
+      b->n_bits = n_elms;
+      b->size = size;
+      b->bytes = bytes;
+    }
+
+  return bitmap_vector;
+}
+
+/* Copy sbitmap SRC to DST.  */
+
+void
+sbitmap_copy (dst, src)
+     sbitmap dst, src;
+{
+  int i;
+  sbitmap_ptr d,s;
+
+  s = src->elms;
+  d = dst->elms;
+  for (i = 0; i < dst->size; i++)
+    *d++ = *s++;
+}
+
+/* Zero all elements in a bitmap.  */
+
+void
+sbitmap_zero (bmap)
+     sbitmap bmap;
+{
+  bzero ((char *) bmap->elms, bmap->bytes);
+}
+
+/* Set to ones all elements in a bitmap.  */
+
+void
+sbitmap_ones (bmap)
+     sbitmap bmap;
+{
+  memset (bmap->elms, -1, bmap->bytes);
+}
+
+/* Zero a vector of N_VECS bitmaps.  */
+
+void
+sbitmap_vector_zero (bmap, n_vecs)
+     sbitmap *bmap;
+     int n_vecs;
+{
+  int i;
+
+  for (i = 0; i < n_vecs; i++)
+    sbitmap_zero (bmap[i]);
+}
+
+/* Set to ones a vector of N_VECS bitmaps.  */
+
+void
+sbitmap_vector_ones (bmap, n_vecs)
+     sbitmap *bmap;
+     int n_vecs;
+{
+  int i;
+
+  for (i = 0; i < n_vecs; i++)
+    sbitmap_ones (bmap[i]);
+}
+
+/* Set DST to be A union (B - C).
+   DST = A | (B & ~C).
+   Return non-zero if any change is made.  */
+
+int
+sbitmap_union_of_diff (dst, a, b, c)
+     sbitmap dst, a, b, c;
+{
+  int i,changed;
+  sbitmap_ptr dstp, ap, bp, cp;
+
+  changed = 0;
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  cp = c->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = *ap | (*bp & ~*cp);
+      if (*dstp != tmp)
+       changed = 1;
+      *dstp = tmp;
+      dstp++; ap++; bp++; cp++;
+    }
+  return changed;
+}
+
+/* Set bitmap DST to the bitwise negation of the bitmap SRC.  */
+
+void
+sbitmap_not (dst, src)
+     sbitmap dst, src;
+{
+  int i;
+  sbitmap_ptr dstp, ap;
+
+  dstp = dst->elms;
+  ap = src->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = ~(*ap);
+      *dstp = tmp;
+      dstp++; ap++;
+    }
+}
+
+/* Set the bits in DST to be the difference between the bits
+   in A and the bits in B. i.e. dst = a - b.
+   The - operator is implemented as a & (~b).  */
+
+void
+sbitmap_difference (dst, a, b)
+     sbitmap dst, a, b;
+{
+  int i;
+  sbitmap_ptr dstp, ap, bp;
+
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  for (i = 0; i < dst->size; i++)
+    *dstp++ = *ap++ & (~*bp++);
+}
+
+/* Set DST to be (A and B)).
+   Return non-zero if any change is made.  */
+
+int
+sbitmap_a_and_b (dst, a, b)
+     sbitmap dst, a, b;
+{
+  int i,changed;
+  sbitmap_ptr dstp, ap, bp;
+
+  changed = 0;
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = *ap & *bp;
+      if (*dstp != tmp)
+       changed = 1;
+      *dstp = tmp;
+      dstp++; ap++; bp++;
+    }
+  return changed;
+}
+/* Set DST to be (A or B)).
+   Return non-zero if any change is made.  */
+
+int
+sbitmap_a_or_b (dst, a, b)
+     sbitmap dst, a, b;
+{
+  int i,changed;
+  sbitmap_ptr dstp, ap, bp;
+
+  changed = 0;
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = *ap | *bp;
+      if (*dstp != tmp)
+       changed = 1;
+      *dstp = tmp;
+      dstp++; ap++; bp++;
+    }
+  return changed;
+}
+
+/* Set DST to be (A or (B and C)).
+   Return non-zero if any change is made.  */
+
+int
+sbitmap_a_or_b_and_c (dst, a, b, c)
+     sbitmap dst, a, b, c;
+{
+  int i,changed;
+  sbitmap_ptr dstp, ap, bp, cp;
+
+  changed = 0;
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  cp = c->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = *ap | (*bp & *cp);
+      if (*dstp != tmp)
+       changed = 1;
+      *dstp = tmp;
+      dstp++; ap++; bp++; cp++;
+    }
+  return changed;
+}
+
+/* Set DST to be (A ann (B or C)).
+   Return non-zero if any change is made.  */
+
+int
+sbitmap_a_and_b_or_c (dst, a, b, c)
+     sbitmap dst, a, b, c;
+{
+  int i,changed;
+  sbitmap_ptr dstp, ap, bp, cp;
+
+  changed = 0;
+  dstp = dst->elms;
+  ap = a->elms;
+  bp = b->elms;
+  cp = c->elms;
+  for (i = 0; i < dst->size; i++)
+    {
+      SBITMAP_ELT_TYPE tmp = *ap & (*bp | *cp);
+      if (*dstp != tmp)
+       changed = 1;
+      *dstp = tmp;
+      dstp++; ap++; bp++; cp++;
+    }
+  return changed;
+}
+
+/* Set the bitmap DST to the intersection of SRC of all predecessors or
+   successors of block number BB (PRED_SUCC says which).  */
+
+void
+sbitmap_intersect_of_predsucc (dst, src, bb, pred_succ)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *pred_succ;
+{
+  int_list_ptr ps;
+  int ps_bb;
+  int set_size = dst->size;
+
+  ps = pred_succ[bb];
+
+  /* It is possible that there are no predecessors(/successors).
+     This can happen for example in unreachable code.  */
+
+  if (ps == NULL)
+    {
+      /* In APL-speak this is the `and' reduction of the empty set and thus
+        the result is the identity for `and'.  */
+      sbitmap_ones (dst);
+      return;
+    }
+
+  /* Set result to first predecessor/successor.  */
+
+  for ( ; ps != NULL; ps = ps->next)
+    {
+      ps_bb = INT_LIST_VAL (ps);
+      if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+       continue;
+      sbitmap_copy (dst, src[ps_bb]);
+      /* Break out since we're only doing first predecessor.  */
+      break;
+    }
+  if (ps == NULL)
+    return;
+
+  /* Now do the remaining predecessors/successors.  */
+
+  for (ps = ps->next; ps != NULL; ps = ps->next)
+    {
+      int i;
+      sbitmap_ptr p,r;
+
+      ps_bb = INT_LIST_VAL (ps);
+      if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+       continue;
+
+      p = src[ps_bb]->elms;
+      r = dst->elms;
+
+      for (i = 0; i < set_size; i++)
+       *r++ &= *p++;
+    }
+}
+
+/* Set the bitmap DST to the intersection of SRC of all predecessors
+   of block number BB.  */
+
+void
+sbitmap_intersect_of_predecessors (dst, src, bb, s_preds)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *s_preds;
+{
+  sbitmap_intersect_of_predsucc (dst, src, bb, s_preds);
+}
+
+/* Set the bitmap DST to the intersection of SRC of all successors
+   of block number BB.  */
+
+void
+sbitmap_intersect_of_successors (dst, src, bb, s_succs)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *s_succs;
+{
+  sbitmap_intersect_of_predsucc (dst, src, bb, s_succs);
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors/successors of
+   block number BB.  */
+
+void
+sbitmap_union_of_predsucc (dst, src, bb, pred_succ)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *pred_succ;
+{
+  int_list_ptr ps;
+  int ps_bb;
+  int set_size = dst->size;
+
+  ps = pred_succ[bb];
+
+  /* It is possible that there are no predecessors(/successors).
+     This can happen for example in unreachable code.  */
+
+  if (ps == NULL)
+    {
+      /* In APL-speak this is the `or' reduction of the empty set and thus
+        the result is the identity for `or'.  */
+      sbitmap_zero (dst);
+      return;
+    }
+
+  /* Set result to first predecessor/successor.  */
+
+  for ( ; ps != NULL; ps = ps->next)
+    {
+      ps_bb = INT_LIST_VAL (ps);
+      if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+       continue;
+      sbitmap_copy (dst, src[ps_bb]);
+      /* Break out since we're only doing first predecessor.  */
+      break;
+    }
+  if (ps == NULL)
+    return;
+
+  /* Now do the remaining predecessors/successors.  */
+
+  for (ps = ps->next; ps != NULL; ps = ps->next)
+    {
+      int i;
+      sbitmap_ptr p,r;
+
+      ps_bb = INT_LIST_VAL (ps);
+      if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+       continue;
+
+      p = src[ps_bb]->elms;
+      r = dst->elms;
+
+      for (i = 0; i < set_size; i++)
+       *r++ |= *p++;
+    }
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors of
+   block number BB.  */
+
+void
+sbitmap_union_of_predecessors (dst, src, bb, s_preds)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *s_preds;
+{
+  sbitmap_union_of_predsucc (dst, src, bb, s_preds);
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors of
+   block number BB.  */
+
+void
+sbitmap_union_of_successors (dst, src, bb, s_succ)
+     sbitmap dst;
+     sbitmap *src;
+     int bb;
+     int_list_ptr *s_succ;
+{
+  sbitmap_union_of_predsucc (dst, src, bb, s_succ);
+}
+
+/* Compute dominator relationships.  */
+void
+compute_dominators (dominators, post_dominators, s_preds, s_succs)
+     sbitmap *dominators;
+     sbitmap *post_dominators;
+     int_list_ptr *s_preds;
+     int_list_ptr *s_succs;
+{
+  int bb, changed, passes;
+  sbitmap *temp_bitmap;
+
+  temp_bitmap = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+  sbitmap_vector_ones (dominators, n_basic_blocks);
+  sbitmap_vector_ones (post_dominators, n_basic_blocks);
+  sbitmap_vector_zero (temp_bitmap, n_basic_blocks);
+
+  sbitmap_zero (dominators[0]);
+  SET_BIT (dominators[0], 0);
+
+  sbitmap_zero (post_dominators[n_basic_blocks-1]);
+  SET_BIT (post_dominators[n_basic_blocks-1], 0);
+
+  passes = 0;
+  changed = 1;
+  while (changed)
+    {
+      changed = 0;
+      for (bb = 1; bb < n_basic_blocks; bb++)
+       {
+         sbitmap_intersect_of_predecessors (temp_bitmap[bb], dominators,
+                                            bb, s_preds);
+         SET_BIT (temp_bitmap[bb], bb);
+         changed |= sbitmap_a_and_b (dominators[bb],
+                                     dominators[bb],
+                                     temp_bitmap[bb]);
+         sbitmap_intersect_of_successors (temp_bitmap[bb], post_dominators,
+                                          bb, s_succs);
+         SET_BIT (temp_bitmap[bb], bb);
+         changed |= sbitmap_a_and_b (post_dominators[bb],
+                                     post_dominators[bb],
+                                     temp_bitmap[bb]);
+       }
+      passes++;
+    }
+
+  free (temp_bitmap);
+}