OSDN Git Service

PR libgcj/23508
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index f811f22..f82cd08 100644 (file)
@@ -1,6 +1,6 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
    Copyright (C) 1987, 1988, 1991, 1994, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -16,25 +16,28 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
 #include "system.h"
-
+#include "coretypes.h"
+#include "tm.h"
 #include "machmode.h"
 #include "hard-reg-set.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "flags.h"
-#include "basic-block.h"
 #include "regs.h"
 #include "function.h"
 #include "insn-config.h"
+#include "recog.h"
 #include "reload.h"
 #include "output.h"
 #include "toplev.h"
+#include "tree-pass.h"
+#include "timevar.h"
 
 /* This pass of the compiler performs global register allocation.
    It assigns hard register numbers to all the pseudo registers
@@ -52,7 +55,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    1. Assign allocation-numbers (allocnos) to the pseudo-registers
    still needing allocations and to the pseudo-registers currently
    allocated by local-alloc which may be spilled by reload.
-   Set up tables reg_allocno and allocno_reg to map 
+   Set up tables reg_allocno and allocno_reg to map
    reg numbers to allocnos and vice versa.
    max_allocno gets the number of allocnos in use.
 
@@ -130,6 +133,11 @@ struct allocno
   /* Set of hard registers that some later allocno has a preference for.  */
 
   HARD_REG_SET regs_someone_prefers;
+
+#ifdef STACK_REGS
+  /* Set to true if allocno can't be allocated in the stack register.  */
+  bool no_stack_reg;
+#endif
 };
 
 static struct allocno *allocno;
@@ -168,12 +176,8 @@ static int allocno_row_words;
 /* Two macros to test or store 1 in an element of `conflicts'.  */
 
 #define CONFLICTP(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned)(J) / INT_BITS]        \
-  & ((INT_TYPE) 1 << ((unsigned)(J) % INT_BITS)))
-
-#define SET_CONFLICT(I, J) \
- (conflicts[(I) * allocno_row_words + (unsigned)(J) / INT_BITS]        \
-  |= ((INT_TYPE) 1 << ((unsigned)(J) % INT_BITS)))
+ (conflicts[(I) * allocno_row_words + (unsigned) (J) / INT_BITS]       \
+  & ((INT_TYPE) 1 << ((unsigned) (J) % INT_BITS)))
 
 /* For any allocno set in ALLOCNO_SET, set ALLOCNO to that allocno,
    and execute CODE.  */
@@ -231,12 +235,8 @@ static int local_reg_freq[FIRST_PSEUDO_REGISTER];
 
 static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
 
-/* Test a bit in TABLE, a vector of HARD_REG_SETs,
-   for vector element I, and hard register number J.  */
-
-#define REGBITP(TABLE, I, J)     TEST_HARD_REG_BIT (allocno[I].TABLE, J)
-
-/* Set to 1 a bit in a vector of HARD_REG_SETs.  Works like REGBITP.  */
+/* Set to 1 a bit in a vector TABLE of HARD_REG_SETs, for vector
+   element I, and hard register number J.  */
 
 #define SET_REGBIT(TABLE, I, J)  SET_HARD_REG_BIT (allocno[I].TABLE, J)
 
@@ -247,17 +247,13 @@ static INT_TYPE *allocnos_live;
 /* Test, set or clear bit number I in allocnos_live,
    a bit vector indexed by allocno.  */
 
-#define ALLOCNO_LIVE_P(I)                              \
-  (allocnos_live[(unsigned)(I) / INT_BITS]             \
-   & ((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
-
 #define SET_ALLOCNO_LIVE(I)                            \
-  (allocnos_live[(unsigned)(I) / INT_BITS]             \
-     |= ((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
+  (allocnos_live[(unsigned) (I) / INT_BITS]            \
+     |= ((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
 
 #define CLEAR_ALLOCNO_LIVE(I)                          \
-  (allocnos_live[(unsigned)(I) / INT_BITS]             \
-     &= ~((INT_TYPE) 1 << ((unsigned)(I) % INT_BITS)))
+  (allocnos_live[(unsigned) (I) / INT_BITS]            \
+     &= ~((INT_TYPE) 1 << ((unsigned) (I) % INT_BITS)))
 
 /* This is turned off because it doesn't work right for DImode.
    (And it is only used for DImode, so the other cases are worthless.)
@@ -294,25 +290,38 @@ static int n_regs_set;
 
 static HARD_REG_SET eliminable_regset;
 
-static int allocno_compare     PARAMS ((const PTR, const PTR));
-static void global_conflicts   PARAMS ((void));
-static void mirror_conflicts   PARAMS ((void));
-static void expand_preferences PARAMS ((void));
-static void prune_preferences  PARAMS ((void));
-static void find_reg           PARAMS ((int, HARD_REG_SET, int, int, int));
-static void record_one_conflict PARAMS ((int));
-static void record_conflicts   PARAMS ((int *, int));
-static void mark_reg_store     PARAMS ((rtx, rtx, void *));
-static void mark_reg_clobber   PARAMS ((rtx, rtx, void *));
-static void mark_reg_conflicts PARAMS ((rtx));
-static void mark_reg_death     PARAMS ((rtx));
-static void mark_reg_live_nc   PARAMS ((int, enum machine_mode));
-static void set_preference     PARAMS ((rtx, rtx));
-static void dump_conflicts     PARAMS ((FILE *));
-static void reg_becomes_live   PARAMS ((rtx, rtx, void *));
-static void reg_dies           PARAMS ((int, enum machine_mode,
-                                      struct insn_chain *));
+static int allocno_compare (const void *, const void *);
+static void global_conflicts (void);
+static void mirror_conflicts (void);
+static void expand_preferences (void);
+static void prune_preferences (void);
+static void find_reg (int, HARD_REG_SET, int, int, int);
+static void record_one_conflict (int);
+static void record_conflicts (int *, int);
+static void mark_reg_store (rtx, rtx, void *);
+static void mark_reg_clobber (rtx, rtx, void *);
+static void mark_reg_conflicts (rtx);
+static void mark_reg_death (rtx);
+static void mark_reg_live_nc (int, enum machine_mode);
+static void set_preference (rtx, rtx);
+static void dump_conflicts (FILE *);
+static void reg_becomes_live (rtx, rtx, void *);
+static void reg_dies (int, enum machine_mode, struct insn_chain *);
+
+static void allocate_bb_info (void);
+static void free_bb_info (void);
+static bool check_earlyclobber (rtx);
+static void mark_reg_use_for_earlyclobber_1 (rtx *, void *);
+static int mark_reg_use_for_earlyclobber (rtx *, void *);
+static void calculate_local_reg_bb_info (void);
+static void set_up_bb_rts_numbers (void);
+static int rpost_cmp (const void *, const void *);
+static void calculate_reg_pav (void);
+static void modify_reg_pav (void);
+static void make_accurate_live_analysis (void);
+
 \f
+
 /* Perform allocation of pseudo-registers not allocated by local_alloc.
    FILE is a file to output debugging information on,
    or zero if such output is not desired.
@@ -321,8 +330,7 @@ static void reg_dies                PARAMS ((int, enum machine_mode,
    and we must not do any more for this function.  */
 
 int
-global_alloc (file)
-     FILE *file;
+global_alloc (FILE *file)
 {
   int retval;
 #ifdef ELIMINABLE_REGS
@@ -330,14 +338,14 @@ global_alloc (file)
 #endif
   int need_fp
     = (! flag_omit_frame_pointer
-#ifdef EXIT_IGNORE_STACK
        || (current_function_calls_alloca && EXIT_IGNORE_STACK)
-#endif
        || FRAME_POINTER_REQUIRED);
 
-  register size_t i;
+  size_t i;
   rtx x;
 
+  make_accurate_live_analysis ();
+
   max_allocno = 0;
 
   /* A machine may have certain hard registers that
@@ -350,22 +358,48 @@ global_alloc (file)
 #ifdef ELIMINABLE_REGS
   for (i = 0; i < ARRAY_SIZE (eliminables); i++)
     {
-      SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
+      bool cannot_elim
+       = (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
+          || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
+
+      if (!regs_asm_clobbered[eliminables[i].from])
+       {
+         SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
 
-      if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-         || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
-       SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
+         if (cannot_elim)
+           SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
+       }
+      else if (cannot_elim)
+       error ("%s cannot be used in asm here",
+              reg_names[eliminables[i].from]);
+      else
+       regs_ever_live[eliminables[i].from] = 1;
     }
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-  SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
-  if (need_fp)
-    SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+  if (!regs_asm_clobbered[HARD_FRAME_POINTER_REGNUM])
+    {
+      SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
+      if (need_fp)
+       SET_HARD_REG_BIT (no_global_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+    }
+  else if (need_fp)
+    error ("%s cannot be used in asm here",
+          reg_names[HARD_FRAME_POINTER_REGNUM]);
+  else
+    regs_ever_live[HARD_FRAME_POINTER_REGNUM] = 1;
 #endif
 
 #else
-  SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
-  if (need_fp)
-    SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+  if (!regs_asm_clobbered[FRAME_POINTER_REGNUM])
+    {
+      SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
+      if (need_fp)
+       SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
+    }
+  else if (need_fp)
+    error ("%s cannot be used in asm here", reg_names[FRAME_POINTER_REGNUM]);
+  else
+    regs_ever_live[FRAME_POINTER_REGNUM] = 1;
 #endif
 
   /* Track which registers have already been used.  Start with registers
@@ -379,8 +413,8 @@ global_alloc (file)
      that need a register window.  So prefer the ones that can be used in
      a leaf function.  */
   {
-    char *cheap_regs;
-    char *leaf_regs = LEAF_REGISTERS;
+    const char *cheap_regs;
+    const char *const leaf_regs = LEAF_REGISTERS;
 
     if (only_leaf_regs_used () && leaf_function_p ())
       cheap_regs = leaf_regs;
@@ -405,14 +439,14 @@ global_alloc (file)
   /* Establish mappings from register number to allocation number
      and vice versa.  In the process, count the allocnos.  */
 
-  reg_allocno = (int *) xmalloc (max_regno * sizeof (int));
+  reg_allocno = xmalloc (max_regno * sizeof (int));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     reg_allocno[i] = -1;
 
   /* Initialize the shared-hard-reg mapping
      from the list of pairs that may share.  */
-  reg_may_share = (int *) xcalloc (max_regno, sizeof (int));
+  reg_may_share = xcalloc (max_regno, sizeof (int));
   for (x = regs_may_share; x; x = XEXP (XEXP (x, 1), 1))
     {
       int r1 = REGNO (XEXP (x, 0));
@@ -431,19 +465,21 @@ global_alloc (file)
        /* Don't allocate pseudos that cross calls,
           if this function receives a nonlocal goto.  */
        && (! current_function_has_nonlocal_label
-           || REG_N_CALLS_CROSSED (i) == 0))
+           || REG_N_CALLS_CROSSED (i) == 0)
+       /* Don't allocate pseudos that cross calls that may throw.  */
+       && REG_N_THROWING_CALLS_CROSSED (i) == 0)
       {
-       if (reg_renumber[i] < 0 && reg_may_share[i] && reg_allocno[reg_may_share[i]] >= 0)
+       if (reg_renumber[i] < 0
+           && reg_may_share[i] && reg_allocno[reg_may_share[i]] >= 0)
          reg_allocno[i] = reg_allocno[reg_may_share[i]];
        else
          reg_allocno[i] = max_allocno++;
-       if (REG_LIVE_LENGTH (i) == 0)
-         abort ();
+       gcc_assert (REG_LIVE_LENGTH (i));
       }
     else
       reg_allocno[i] = -1;
 
-  allocno = (struct allocno *) xcalloc (max_allocno, sizeof (struct allocno));
+  allocno = xcalloc (max_allocno, sizeof (struct allocno));
 
   for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
     if (reg_allocno[i] >= 0)
@@ -461,14 +497,14 @@ global_alloc (file)
   /* Calculate amount of usage of each hard reg by pseudos
      allocated by local-alloc.  This is to see if we want to
      override it.  */
-  memset ((char *) local_reg_live_length, 0, sizeof local_reg_live_length);
-  memset ((char *) local_reg_n_refs, 0, sizeof local_reg_n_refs);
-  memset ((char *) local_reg_freq, 0, sizeof local_reg_freq);
+  memset (local_reg_live_length, 0, sizeof local_reg_live_length);
+  memset (local_reg_n_refs, 0, sizeof local_reg_n_refs);
+  memset (local_reg_freq, 0, sizeof local_reg_freq);
   for (i = FIRST_PSEUDO_REGISTER; i < (size_t) max_regno; i++)
     if (reg_renumber[i] >= 0)
       {
        int regno = reg_renumber[i];
-       int endregno = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
+       int endregno = regno + hard_regno_nregs[regno][PSEUDO_REGNO_MODE (i)];
        int j;
 
        for (j = regno; j < endregno; j++)
@@ -483,16 +519,15 @@ global_alloc (file)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (regs_ever_live[i])
       local_reg_n_refs[i] = 0, local_reg_freq[i] = 0;
-       
+
   allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
 
   /* We used to use alloca here, but the size of what it would try to
      allocate would occasionally cause it to exceed the stack limit and
      cause unpredictable core dumps.  Some examples were > 2Mb in size.  */
-  conflicts = (INT_TYPE *) xcalloc (max_allocno * allocno_row_words,
-                                   sizeof (INT_TYPE));
+  conflicts = xcalloc (max_allocno * allocno_row_words, sizeof (INT_TYPE));
 
-  allocnos_live = (INT_TYPE *) xmalloc (allocno_row_words * sizeof (INT_TYPE));
+  allocnos_live = xmalloc (allocno_row_words * sizeof (INT_TYPE));
 
   /* If there is work to be done (at least one reg to allocate),
      perform global conflict analysis and allocate the regs.  */
@@ -529,7 +564,7 @@ global_alloc (file)
 
       /* Determine the order to allocate the remaining pseudo registers.  */
 
-      allocno_order = (int *) xmalloc (max_allocno * sizeof (int));
+      allocno_order = xmalloc (max_allocno * sizeof (int));
       for (i = 0; i < (size_t) max_allocno; i++)
        allocno_order[i] = i;
 
@@ -549,7 +584,7 @@ global_alloc (file)
        }
 
       qsort (allocno_order, max_allocno, sizeof (int), allocno_compare);
-      
+
       prune_preferences ();
 
       if (file)
@@ -604,9 +639,7 @@ global_alloc (file)
    Returns -1 (1) if *v1 should be allocated before (after) *v2.  */
 
 static int
-allocno_compare (v1p, v2p)
-     const PTR v1p;
-     const PTR v2p;
+allocno_compare (const void *v1p, const void *v2p)
 {
   int v1 = *(const int *)v1p, v2 = *(const int *)v2p;
   /* Note that the quotient will never be bigger than
@@ -614,11 +647,11 @@ allocno_compare (v1p, v2p)
      times a register can occur in one insn (surely less than 100)
      weighted by the frequency (maximally REG_FREQ_MAX).
      Multiplying this by 10000/REG_FREQ_MAX can't overflow.  */
-  register int pri1
+  int pri1
     = (((double) (floor_log2 (allocno[v1].n_refs) * allocno[v1].freq)
        / allocno[v1].live_length)
        * (10000 / REG_FREQ_MAX) * allocno[v1].size);
-  register int pri2
+  int pri2
     = (((double) (floor_log2 (allocno[v2].n_refs) * allocno[v2].freq)
        / allocno[v2].live_length)
        * (10000 / REG_FREQ_MAX) * allocno[v2].size);
@@ -634,20 +667,21 @@ allocno_compare (v1p, v2p)
    conflict matrices and preference tables.  */
 
 static void
-global_conflicts ()
+global_conflicts (void)
 {
-  register int b, i;
-  register rtx insn;
+  unsigned i;
+  basic_block b;
+  rtx insn;
   int *block_start_allocnos;
 
   /* Make a vector that mark_reg_{store,clobber} will store in.  */
-  regs_set = (rtx *) xmalloc (max_parallel * sizeof (rtx) * 2);
+  regs_set = xmalloc (max_parallel * sizeof (rtx) * 2);
 
-  block_start_allocnos = (int *) xmalloc (max_allocno * sizeof (int));
+  block_start_allocnos = xmalloc (max_allocno * sizeof (int));
 
-  for (b = 0; b < n_basic_blocks; b++)
+  FOR_EACH_BB (b)
     {
-      memset ((char *) allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
+      memset (allocnos_live, 0, allocno_row_words * sizeof (INT_TYPE));
 
       /* Initialize table of registers currently live
         to the state at the beginning of this basic block.
@@ -661,25 +695,25 @@ global_conflicts ()
         since one hard reg can be used with various sizes.
         Therefore, we must require that all the hard regs
         implicitly live as part of a multi-word hard reg
-        are explicitly marked in basic_block_live_at_start.  */
+        be explicitly marked in basic_block_live_at_start.  */
 
       {
-       register regset old = BASIC_BLOCK (b)->global_live_at_start;
+       regset old = b->il.rtl->global_live_at_start;
        int ax = 0;
+       reg_set_iterator rsi;
 
        REG_SET_TO_HARD_REG_SET (hard_regs_live, old);
-       EXECUTE_IF_SET_IN_REG_SET (old, FIRST_PSEUDO_REGISTER, i,
-                                  {
-                                    register int a = reg_allocno[i];
-                                    if (a >= 0)
-                                      {
-                                        SET_ALLOCNO_LIVE (a);
-                                        block_start_allocnos[ax++] = a;
-                                      }
-                                    else if ((a = reg_renumber[i]) >= 0)
-                                      mark_reg_live_nc
-                                        (a, PSEUDO_REGNO_MODE (i));
-                                  });
+       EXECUTE_IF_SET_IN_REG_SET (old, FIRST_PSEUDO_REGISTER, i, rsi)
+         {
+           int a = reg_allocno[i];
+           if (a >= 0)
+             {
+               SET_ALLOCNO_LIVE (a);
+               block_start_allocnos[ax++] = a;
+             }
+           else if ((a = reg_renumber[i]) >= 0)
+             mark_reg_live_nc (a, PSEUDO_REGNO_MODE (i));
+         }
 
        /* Record that each allocno now live conflicts with each hard reg
           now live.
@@ -699,31 +733,50 @@ global_conflicts ()
                2. Y is live at some instruction on the path that
                   evaluates X.
 
-               3. Either X or Y is not evaluted on the path to P
-                  (ie it is used uninitialized) and thus the
+               3. Either X or Y is not evaluated on the path to P
+                  (i.e. it is used uninitialized) and thus the
                   conflict can be ignored.
 
            In cases #1 and #2 the conflict will be recorded when we
            scan the instruction that makes either X or Y become live.  */
        record_conflicts (block_start_allocnos, ax);
 
-#ifdef STACK_REGS
+       /* Pseudos can't go in stack regs at the start of a basic block that
+          is reached by an abnormal edge. Likewise for call clobbered regs,
+          because because caller-save, fixup_abnormal_edges, and possibly
+          the table driven EH machinery are not quite ready to handle such
+          regs live across such edges.  */
        {
-         /* Pseudos can't go in stack regs at the start of a basic block
-            that is reached by an abnormal edge.  */
-
          edge e;
-         for (e = BASIC_BLOCK (b)->pred; e ; e = e->pred_next)
+         edge_iterator ei;
+
+         FOR_EACH_EDGE (e, ei, b->preds)
            if (e->flags & EDGE_ABNORMAL)
              break;
+
          if (e != NULL)
-           for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
-             record_one_conflict (ax);
-       }
+           {
+#ifdef STACK_REGS
+             EXECUTE_IF_SET_IN_ALLOCNO_SET (allocnos_live, ax,
+                                            {
+                                              allocno[ax].no_stack_reg = 1;
+                                            });
+             for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
+               record_one_conflict (ax);
 #endif
+
+             /* No need to record conflicts for call clobbered regs if we have
+                nonlocal labels around, as we don't ever try to allocate such
+                regs in this case.  */
+             if (! current_function_has_nonlocal_label)
+               for (ax = 0; ax < FIRST_PSEUDO_REGISTER; ax++)
+                 if (call_used_regs [ax])
+                   record_one_conflict (ax);
+           }
+       }
       }
 
-      insn = BLOCK_HEAD (b);
+      insn = BB_HEAD (b);
 
       /* Scan the code of this basic block, noting which allocnos
         and hard regs are born or die.  When one is born,
@@ -731,8 +784,8 @@ global_conflicts ()
 
       while (1)
        {
-         register RTX_CODE code = GET_CODE (insn);
-         register rtx link;
+         RTX_CODE code = GET_CODE (insn);
+         rtx link;
 
          /* Make regs_set an empty set.  */
 
@@ -803,7 +856,7 @@ global_conflicts ()
                        {
                          rtx set = XVECEXP (PATTERN (insn), 0, i);
                          if (GET_CODE (set) == SET
-                             && GET_CODE (SET_DEST (set)) != REG
+                             && !REG_P (SET_DEST (set))
                              && !rtx_equal_p (reg, SET_DEST (set))
                              && reg_overlap_mentioned_p (reg, SET_DEST (set)))
                            used_in_output = 1;
@@ -823,7 +876,7 @@ global_conflicts ()
                }
            }
 
-         if (insn == BLOCK_END (b))
+         if (insn == BB_END (b))
            break;
          insn = NEXT_INSN (insn);
        }
@@ -838,7 +891,7 @@ global_conflicts ()
    merge any preferences between those allocnos.  */
 
 static void
-expand_preferences ()
+expand_preferences (void)
 {
   rtx insn;
   rtx link;
@@ -850,11 +903,11 @@ expand_preferences ()
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn)
        && (set = single_set (insn)) != 0
-       && GET_CODE (SET_DEST (set)) == REG
+       && REG_P (SET_DEST (set))
        && reg_allocno[REGNO (SET_DEST (set))] >= 0)
       for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
        if (REG_NOTE_KIND (link) == REG_DEAD
-           && GET_CODE (XEXP (link, 0)) == REG
+           && REG_P (XEXP (link, 0))
            && reg_allocno[REGNO (XEXP (link, 0))] >= 0
            && ! CONFLICTP (reg_allocno[REGNO (SET_DEST (set))],
                            reg_allocno[REGNO (XEXP (link, 0))]))
@@ -883,18 +936,18 @@ expand_preferences ()
 \f
 /* Prune the preferences for global registers to exclude registers that cannot
    be used.
-   
+
    Compute `regs_someone_prefers', which is a bitmask of the hard registers
    that are preferred by conflicting registers of lower priority.  If possible,
    we will avoid using these registers.  */
-   
+
 static void
-prune_preferences ()
+prune_preferences (void)
 {
   int i;
   int num;
-  int *allocno_to_order = (int *) xmalloc (max_allocno * sizeof (int));
-  
+  int *allocno_to_order = xmalloc (max_allocno * sizeof (int));
+
   /* Scan least most important to most important.
      For each allocno, remove from preferences registers that cannot be used,
      either because of conflicts or register type.  Then compute all registers
@@ -962,7 +1015,7 @@ prune_preferences ()
    of a long enough stretch of hard regs none of which conflicts with ALLOCNO.
    The registers marked in PREFREGS are tried first.
 
-   LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot
+   LOSERS, if nonzero, is a HARD_REG_SET indicating registers that cannot
    be used for this allocation.
 
    If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
@@ -977,18 +1030,10 @@ prune_preferences ()
    If not, do nothing.  */
 
 static void
-find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
-     int num;
-     HARD_REG_SET losers;
-     int alt_regs_p;
-     int accept_call_clobbered;
-     int retrying;
+find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbered, int retrying)
 {
-  register int i, best_reg, pass;
-#ifdef HARD_REG_SET
-  register             /* Declare it register if it's a scalar.  */
-#endif
-    HARD_REG_SET used, used1, used2;
+  int i, best_reg, pass;
+  HARD_REG_SET used, used1, used2;
 
   enum reg_class class = (alt_regs_p
                          ? reg_alternate_class (allocno[num].reg)
@@ -1012,10 +1057,8 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
 
   IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
 
-#ifdef CLASS_CANNOT_CHANGE_MODE
-  if (REG_CHANGES_MODE (allocno[num].reg))
-    IOR_HARD_REG_SET (used1,
-                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+  cannot_change_mode_set_regs (&used1, mode, allocno[num].reg);
 #endif
 
   /* Try each hard reg to see if it fits.  Do this in two passes.
@@ -1027,7 +1070,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
   COPY_HARD_REG_SET (used, used1);
   IOR_COMPL_HARD_REG_SET (used, regs_used_so_far);
   IOR_HARD_REG_SET (used, allocno[num].regs_someone_prefers);
-  
+
   best_reg = -1;
   for (i = FIRST_PSEUDO_REGISTER, pass = 0;
        pass <= 1 && i >= FIRST_PSEUDO_REGISTER;
@@ -1048,8 +1091,8 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
                  || accept_call_clobbered
                  || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
            {
-             register int j;
-             register int lim = regno + HARD_REGNO_NREGS (regno, mode);
+             int j;
+             int lim = regno + hard_regno_nregs[regno][mode];
              for (j = regno + 1;
                   (j < lim
                    && ! TEST_HARD_REG_BIT (used, j));
@@ -1072,7 +1115,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
 
      Remove from the preferred registers and conflicting registers.  Note that
      additional conflicts may have been added after `prune_preferences' was
-     called. 
+     called.
 
      First do this for those register with copy preferences, then all
      preferred registers.  */
@@ -1086,19 +1129,22 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (allocno[num].hard_reg_copy_preferences, i)
            && HARD_REGNO_MODE_OK (i, mode)
+           && (allocno[num].calls_crossed == 0
+               || accept_call_clobbered
+               || ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
            && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
                || reg_class_subset_p (REGNO_REG_CLASS (i),
                                       REGNO_REG_CLASS (best_reg))
                || reg_class_subset_p (REGNO_REG_CLASS (best_reg),
                                       REGNO_REG_CLASS (i))))
            {
-             register int j;
-             register int lim = i + HARD_REGNO_NREGS (i, mode);
+             int j;
+             int lim = i + hard_regno_nregs[i][mode];
              for (j = i + 1;
                   (j < lim
                    && ! TEST_HARD_REG_BIT (used, j)
                    && (REGNO_REG_CLASS (j)
-                       == REGNO_REG_CLASS (best_reg + (j - i))
+                       == REGNO_REG_CLASS (best_reg + (j - i))
                        || reg_class_subset_p (REGNO_REG_CLASS (j),
                                               REGNO_REG_CLASS (best_reg + (j - i)))
                        || reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)),
@@ -1122,19 +1168,22 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (allocno[num].hard_reg_preferences, i)
            && HARD_REGNO_MODE_OK (i, mode)
+           && (allocno[num].calls_crossed == 0
+               || accept_call_clobbered
+               || ! HARD_REGNO_CALL_PART_CLOBBERED (i, mode))
            && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg)
                || reg_class_subset_p (REGNO_REG_CLASS (i),
                                       REGNO_REG_CLASS (best_reg))
                || reg_class_subset_p (REGNO_REG_CLASS (best_reg),
                                       REGNO_REG_CLASS (i))))
            {
-             register int j;
-             register int lim = i + HARD_REGNO_NREGS (i, mode);
+             int j;
+             int lim = i + hard_regno_nregs[i][mode];
              for (j = i + 1;
                   (j < lim
                    && ! TEST_HARD_REG_BIT (used, j)
                    && (REGNO_REG_CLASS (j)
-                       == REGNO_REG_CLASS (best_reg + (j - i))
+                       == REGNO_REG_CLASS (best_reg + (j - i))
                        || reg_class_subset_p (REGNO_REG_CLASS (j),
                                               REGNO_REG_CLASS (best_reg + (j - i)))
                        || reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)),
@@ -1149,7 +1198,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
     }
  no_prefs:
 
-  /* If we haven't succeeded yet, try with caller-saves. 
+  /* If we haven't succeeded yet, try with caller-saves.
      We need not check to see if the current function has nonlocal
      labels because we don't put any pseudos that are live over calls in
      registers in that case.  */
@@ -1169,7 +1218,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
            CLEAR_HARD_REG_SET (new_losers);
          else
            COPY_HARD_REG_SET (new_losers, losers);
-           
+
          IOR_HARD_REG_SET(new_losers, losing_caller_save_reg_set);
          find_reg (num, new_losers, alt_regs_p, 1, retrying);
          if (reg_renumber[allocno[num].reg] >= 0)
@@ -1202,18 +1251,28 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
              /* Don't use a reg no good for this pseudo.  */
              && ! TEST_HARD_REG_BIT (used2, regno)
              && HARD_REGNO_MODE_OK (regno, mode)
-#ifdef CLASS_CANNOT_CHANGE_MODE
-             && ! (REG_CHANGES_MODE (allocno[num].reg)
-                   && (TEST_HARD_REG_BIT
-                       (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-                        regno)))
+             /* The code below assumes that we need only a single
+                register, but the check of allocno[num].size above
+                was not enough.  Sometimes we need more than one
+                register for a single-word value.  */
+             && hard_regno_nregs[regno][mode] == 1
+             && (allocno[num].calls_crossed == 0
+                 || accept_call_clobbered
+                 || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+             && ! invalid_mode_change_p (regno, REGNO_REG_CLASS (regno),
+                                         mode)
+#endif
+#ifdef STACK_REGS
+            && (!allocno[num].no_stack_reg
+                || regno < FIRST_STACK_REG || regno > LAST_STACK_REG)
 #endif
              )
            {
              /* We explicitly evaluate the divide results into temporary
                 variables so as to avoid excess precision problems that occur
-                on a i386-unknown-sysv4.2 (unixware) host.  */
-                
+                on an i386-unknown-sysv4.2 (unixware) host.  */
+
              double tmp1 = ((double) local_reg_freq[regno]
                            / local_reg_live_length[regno]);
              double tmp2 = ((double) allocno[num].freq
@@ -1229,7 +1288,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
                      {
                        int r = reg_renumber[k];
                        int endregno
-                         = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k));
+                         = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (k)];
 
                        if (regno >= r && regno < endregno)
                          reg_renumber[k] = -1;
@@ -1246,7 +1305,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
 
   if (best_reg >= 0)
     {
-      register int lim, j;
+      int lim, j;
       HARD_REG_SET this_reg;
 
       /* Yes.  Record it as the hard register of this pseudo-reg.  */
@@ -1259,7 +1318,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
 
       /* Make a set of the hard regs being allocated.  */
       CLEAR_HARD_REG_SET (this_reg);
-      lim = best_reg + HARD_REGNO_NREGS (best_reg, mode);
+      lim = best_reg + hard_regno_nregs[best_reg][mode];
       for (j = best_reg; j < lim; j++)
        {
          SET_HARD_REG_BIT (this_reg, j);
@@ -1286,9 +1345,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying)
    If FORBIDDEN_REGS is zero, no regs are forbidden.  */
 
 void
-retry_global_alloc (regno, forbidden_regs)
-     int regno;
-     HARD_REG_SET forbidden_regs;
+retry_global_alloc (int regno, HARD_REG_SET forbidden_regs)
 {
   int alloc_no = reg_allocno[regno];
   if (alloc_no >= 0)
@@ -1319,10 +1376,9 @@ retry_global_alloc (regno, forbidden_regs)
    reg_renumber before calling here.  */
 
 static void
-record_one_conflict (regno)
-     int regno;
+record_one_conflict (int regno)
 {
-  register int j;
+  int j;
 
   if (regno < FIRST_PSEUDO_REGISTER)
     /* When a hard register becomes live,
@@ -1336,22 +1392,12 @@ record_one_conflict (regno)
        record conflicts first with hard regs,
        then with other pseudo regs.  */
     {
-      register int ialloc = reg_allocno[regno];
-      register int ialloc_prod = ialloc * allocno_row_words;
+      int ialloc = reg_allocno[regno];
+      int ialloc_prod = ialloc * allocno_row_words;
+
       IOR_HARD_REG_SET (allocno[ialloc].hard_reg_conflicts, hard_regs_live);
       for (j = allocno_row_words - 1; j >= 0; j--)
-       {
-#if 0
-         int k;
-         for (k = 0; k < n_no_conflict_pairs; k++)
-           if (! ((j == no_conflict_pairs[k].allocno1
-                   && ialloc == no_conflict_pairs[k].allocno2)
-                  ||
-                  (j == no_conflict_pairs[k].allocno2
-                   && ialloc == no_conflict_pairs[k].allocno1)))
-#endif /* 0 */
-             conflicts[ialloc_prod + j] |= allocnos_live[j];
-       }
+       conflicts[ialloc_prod + j] |= allocnos_live[j];
     }
 }
 
@@ -1362,26 +1408,18 @@ record_one_conflict (regno)
    are currently live.  Their bits are also flagged in allocnos_live.  */
 
 static void
-record_conflicts (allocno_vec, len)
-     register int *allocno_vec;
-     register int len;
+record_conflicts (int *allocno_vec, int len)
 {
-  register int num;
-  register int ialloc_prod;
-
   while (--len >= 0)
-    {
-      num = allocno_vec[len];
-      ialloc_prod = num * allocno_row_words;
-      IOR_HARD_REG_SET (allocno[num].hard_reg_conflicts, hard_regs_live);
-    }
+    IOR_HARD_REG_SET (allocno[allocno_vec[len]].hard_reg_conflicts,
+                      hard_regs_live);
 }
 
 /* If CONFLICTP (i, j) is true, make sure CONFLICTP (j, i) is also true.  */
 static void
-mirror_conflicts ()
+mirror_conflicts (void)
 {
-  register int i, j;
+  int i, j;
   int rw = allocno_row_words;
   int rwb = rw * INT_BITS;
   INT_TYPE *p = conflicts;
@@ -1427,16 +1465,14 @@ mirror_conflicts ()
    a REG_INC note was found for it).  */
 
 static void
-mark_reg_store (reg, setter, data)
-     rtx reg, setter;
-     void *data ATTRIBUTE_UNUSED;
+mark_reg_store (rtx reg, rtx setter, void *data ATTRIBUTE_UNUSED)
 {
-  register int regno;
+  int regno;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
 
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     return;
 
   regs_set[n_regs_set++] = reg;
@@ -1463,7 +1499,7 @@ mark_reg_store (reg, setter, data)
   /* Handle hardware regs (and pseudos allocated to hard regs).  */
   if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
     {
-      register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
       while (regno < last)
        {
          record_one_conflict (regno);
@@ -1476,9 +1512,7 @@ mark_reg_store (reg, setter, data)
 /* Like mark_reg_set except notice just CLOBBERs; ignore SETs.  */
 
 static void
-mark_reg_clobber (reg, setter, data)
-     rtx reg, setter;
-     void *data ATTRIBUTE_UNUSED;
+mark_reg_clobber (rtx reg, rtx setter, void *data)
 {
   if (GET_CODE (setter) == CLOBBER)
     mark_reg_store (reg, setter, data);
@@ -1488,15 +1522,14 @@ mark_reg_clobber (reg, setter, data)
    Do not mark REG itself as live.  */
 
 static void
-mark_reg_conflicts (reg)
-     rtx reg;
+mark_reg_conflicts (rtx reg)
 {
-  register int regno;
+  int regno;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
 
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     return;
 
   regno = REGNO (reg);
@@ -1515,7 +1548,7 @@ mark_reg_conflicts (reg)
   /* Handle hardware regs (and pseudos allocated to hard regs).  */
   if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
     {
-      register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
       while (regno < last)
        {
          record_one_conflict (regno);
@@ -1528,10 +1561,9 @@ mark_reg_conflicts (reg)
    Store a 0 in regs_live or allocnos_live for this register.  */
 
 static void
-mark_reg_death (reg)
-     rtx reg;
+mark_reg_death (rtx reg)
 {
-  register int regno = REGNO (reg);
+  int regno = REGNO (reg);
 
   /* Either this is one of the max_allocno pseudo regs not allocated,
      or it is a hardware reg.  First handle the pseudo-regs.  */
@@ -1550,7 +1582,7 @@ mark_reg_death (reg)
     {
       /* Pseudo regs already assigned hardware regs are treated
         almost the same as explicit hardware regs.  */
-      register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      int last = regno + hard_regno_nregs[regno][GET_MODE (reg)];
       while (regno < last)
        {
          CLEAR_HARD_REG_BIT (hard_regs_live, regno);
@@ -1565,11 +1597,9 @@ mark_reg_death (reg)
    it is assumed that the caller will do that.  */
 
 static void
-mark_reg_live_nc (regno, mode)
-     register int regno;
-     enum machine_mode mode;
+mark_reg_live_nc (int regno, enum machine_mode mode)
 {
-  register int last = regno + HARD_REGNO_NREGS (regno, mode);
+  int last = regno + hard_regno_nregs[regno][mode];
   while (regno < last)
     {
       SET_HARD_REG_BIT (hard_regs_live, regno);
@@ -1582,13 +1612,12 @@ mark_reg_live_nc (regno, mode)
    that SRC is a register.  If SRC or the first operand of SRC is a register,
    try to set a preference.  If one of the two is a hard register and the other
    is a pseudo-register, mark the preference.
-   
+
    Note that we are not as aggressive as local-alloc in trying to tie a
    pseudo-register to a hard register.  */
 
 static void
-set_preference (dest, src)
-     rtx dest, src;
+set_preference (rtx dest, rtx src)
 {
   unsigned int src_regno, dest_regno;
   /* Amount to add to the hard regno for SRC, or subtract from that for DEST,
@@ -1603,9 +1632,9 @@ set_preference (dest, src)
   /* Get the reg number for both SRC and DEST.
      If neither is a reg, give up.  */
 
-  if (GET_CODE (src) == REG)
+  if (REG_P (src))
     src_regno = REGNO (src);
-  else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG)
+  else if (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src)))
     {
       src_regno = REGNO (SUBREG_REG (src));
 
@@ -1621,9 +1650,9 @@ set_preference (dest, src)
   else
     return;
 
-  if (GET_CODE (dest) == REG)
+  if (REG_P (dest))
     dest_regno = REGNO (dest);
-  else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
+  else if (GET_CODE (dest) == SUBREG && REG_P (SUBREG_REG (dest)))
     {
       dest_regno = REGNO (SUBREG_REG (dest));
 
@@ -1663,7 +1692,7 @@ set_preference (dest, src)
          SET_REGBIT (hard_reg_preferences,
                      reg_allocno[src_regno], dest_regno);
          for (i = dest_regno;
-              i < dest_regno + HARD_REGNO_NREGS (dest_regno, GET_MODE (dest));
+              i < dest_regno + hard_regno_nregs[dest_regno][GET_MODE (dest)];
               i++)
            SET_REGBIT (hard_reg_full_preferences, reg_allocno[src_regno], i);
        }
@@ -1682,7 +1711,7 @@ set_preference (dest, src)
          SET_REGBIT (hard_reg_preferences,
                      reg_allocno[dest_regno], src_regno);
          for (i = src_regno;
-              i < src_regno + HARD_REGNO_NREGS (src_regno, GET_MODE (src));
+              i < src_regno + hard_regno_nregs[src_regno][GET_MODE (src)];
               i++)
            SET_REGBIT (hard_reg_full_preferences, reg_allocno[dest_regno], i);
        }
@@ -1695,14 +1724,13 @@ set_preference (dest, src)
    a use of TO.  */
 
 void
-mark_elimination (from, to)
-     int from, to;
+mark_elimination (int from, int to)
 {
-  int i;
+  basic_block bb;
 
-  for (i = 0; i < n_basic_blocks; i++)
+  FOR_EACH_BB (bb)
     {
-      register regset r = BASIC_BLOCK (i)->global_live_at_start; 
+      regset r = bb->il.rtl->global_live_at_start;
       if (REGNO_REG_SET_P (r, from))
        {
          CLEAR_REGNO_REG_SET (r, from);
@@ -1718,23 +1746,20 @@ static regset live_relevant_regs;
 /* Record in live_relevant_regs and REGS_SET that register REG became live.
    This is called via note_stores.  */
 static void
-reg_becomes_live (reg, setter, regs_set)
-     rtx reg;
-     rtx setter ATTRIBUTE_UNUSED;
-     void *regs_set;
+reg_becomes_live (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *regs_set)
 {
   int regno;
 
   if (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
 
-  if (GET_CODE (reg) != REG)
+  if (!REG_P (reg))
     return;
-  
+
   regno = REGNO (reg);
   if (regno < FIRST_PSEUDO_REGISTER)
     {
-      int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      int nregs = hard_regno_nregs[regno][GET_MODE (reg)];
       while (nregs-- > 0)
        {
          SET_REGNO_REG_SET (live_relevant_regs, regno);
@@ -1752,14 +1777,11 @@ reg_becomes_live (reg, setter, regs_set)
 
 /* Record in live_relevant_regs that register REGNO died.  */
 static void
-reg_dies (regno, mode, chain)
-     int regno;
-     enum machine_mode mode;
-     struct insn_chain *chain;
+reg_dies (int regno, enum machine_mode mode, struct insn_chain *chain)
 {
   if (regno < FIRST_PSEUDO_REGISTER)
     {
-      int nregs = HARD_REGNO_NREGS (regno, mode);
+      int nregs = hard_regno_nregs[regno][mode];
       while (nregs-- > 0)
        {
          CLEAR_REGNO_REG_SET (live_relevant_regs, regno);
@@ -1779,37 +1801,35 @@ reg_dies (regno, mode, chain)
 /* Walk the insns of the current function and build reload_insn_chain,
    and record register life information.  */
 void
-build_insn_chain (first)
-     rtx first;
+build_insn_chain (rtx first)
 {
   struct insn_chain **p = &reload_insn_chain;
   struct insn_chain *prev = 0;
-  int b = 0;
-  regset_head live_relevant_regs_head;
+  basic_block b = ENTRY_BLOCK_PTR->next_bb;
 
-  live_relevant_regs = INITIALIZE_REG_SET (live_relevant_regs_head);
+  live_relevant_regs = ALLOC_REG_SET (&reg_obstack);
 
   for (; first; first = NEXT_INSN (first))
     {
       struct insn_chain *c;
 
-      if (first == BLOCK_HEAD (b))
+      if (first == BB_HEAD (b))
        {
-         int i;
+         unsigned i;
+         bitmap_iterator bi;
 
          CLEAR_REG_SET (live_relevant_regs);
 
-         EXECUTE_IF_SET_IN_BITMAP
-           (BASIC_BLOCK (b)->global_live_at_start, 0, i,
-            {
-              if (i < FIRST_PSEUDO_REGISTER
-                  ? ! TEST_HARD_REG_BIT (eliminable_regset, i)
-                  : reg_renumber[i] >= 0)
-                SET_REGNO_REG_SET (live_relevant_regs, i);
-            });
-       }
-
-      if (GET_CODE (first) != NOTE && GET_CODE (first) != BARRIER)
+         EXECUTE_IF_SET_IN_BITMAP (b->il.rtl->global_live_at_start, 0, i, bi)
+           {
+             if (i < FIRST_PSEUDO_REGISTER
+                 ? ! TEST_HARD_REG_BIT (eliminable_regset, i)
+                 : reg_renumber[i] >= 0)
+               SET_REGNO_REG_SET (live_relevant_regs, i);
+           }
+       }
+
+      if (!NOTE_P (first) && !BARRIER_P (first))
        {
          c = new_insn_chain ();
          c->prev = prev;
@@ -1817,7 +1837,7 @@ build_insn_chain (first)
          *p = c;
          p = &c->next;
          c->insn = first;
-         c->block = b;
+         c->block = b->index;
 
          if (INSN_P (first))
            {
@@ -1827,7 +1847,7 @@ build_insn_chain (first)
 
              for (link = REG_NOTES (first); link; link = XEXP (link, 1))
                if (REG_NOTE_KIND (link) == REG_DEAD
-                   && GET_CODE (XEXP (link, 0)) == REG)
+                   && REG_P (XEXP (link, 0)))
                  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
                            c);
 
@@ -1849,14 +1869,14 @@ build_insn_chain (first)
 
              for (link = REG_NOTES (first); link; link = XEXP (link, 1))
                if (REG_NOTE_KIND (link) == REG_UNUSED
-                   && GET_CODE (XEXP (link, 0)) == REG)
+                   && REG_P (XEXP (link, 0)))
                  reg_dies (REGNO (XEXP (link, 0)), GET_MODE (XEXP (link, 0)),
                            c);
            }
        }
 
-      if (first == BLOCK_END (b))
-       b++;
+      if (first == BB_END (b))
+       b = b->next_bb;
 
       /* Stop after we pass the end of the last basic block.  Verify that
         no real insns are after the end of the last basic block.
@@ -1864,16 +1884,17 @@ build_insn_chain (first)
         We may want to reorganize the loop somewhat since this test should
         always be the right exit test.  Allow an ADDR_VEC or ADDR_DIF_VEC if
         the previous real insn is a JUMP_INSN.  */
-      if (b == n_basic_blocks)
+      if (b == EXIT_BLOCK_PTR)
        {
-         for (first = NEXT_INSN (first) ; first; first = NEXT_INSN (first))
-           if (INSN_P (first)
-               && GET_CODE (PATTERN (first)) != USE
-               && ! ((GET_CODE (PATTERN (first)) == ADDR_VEC
-                      || GET_CODE (PATTERN (first)) == ADDR_DIFF_VEC)
-                     && prev_real_insn (first) != 0
-                     && GET_CODE (prev_real_insn (first)) == JUMP_INSN))
-             abort ();
+#ifdef ENABLE_CHECKING
+         for (first = NEXT_INSN (first); first; first = NEXT_INSN (first))
+           gcc_assert (!INSN_P (first)
+                       || GET_CODE (PATTERN (first)) == USE
+                       || ((GET_CODE (PATTERN (first)) == ADDR_VEC
+                            || GET_CODE (PATTERN (first)) == ADDR_DIFF_VEC)
+                           && prev_real_insn (first) != 0
+                           && JUMP_P (prev_real_insn (first))));
+#endif
          break;
        }
     }
@@ -1885,17 +1906,16 @@ build_insn_chain (first)
    showing the information on which the allocation decisions are based.  */
 
 static void
-dump_conflicts (file)
-     FILE *file;
+dump_conflicts (FILE *file)
 {
-  register int i;
-  register int has_preferences;
-  register int nregs;
+  int i;
+  int has_preferences;
+  int nregs;
   nregs = 0;
   for (i = 0; i < max_allocno; i++)
     {
       if (reg_renumber[allocno[allocno_order[i]].reg] >= 0)
-        continue;
+       continue;
       nregs++;
     }
   fprintf (file, ";; %d regs to allocate:", nregs);
@@ -1916,7 +1936,7 @@ dump_conflicts (file)
 
   for (i = 0; i < max_allocno; i++)
     {
-      register int j;
+      int j;
       fprintf (file, ";; %d conflicts:", allocno[i].reg);
       for (j = 0; j < max_allocno; j++)
        if (CONFLICTP (j, i))
@@ -1943,17 +1963,16 @@ dump_conflicts (file)
 }
 
 void
-dump_global_regs (file)
-     FILE *file;
+dump_global_regs (FILE *file)
 {
-  register int i, j;
-  
+  int i, j;
+
   fprintf (file, ";; Register dispositions:\n");
   for (i = FIRST_PSEUDO_REGISTER, j = 0; i < max_regno; i++)
     if (reg_renumber[i] >= 0)
       {
        fprintf (file, "%d in %d  ", i, reg_renumber[i]);
-        if (++j % 6 == 0)
+       if (++j % 6 == 0)
          fprintf (file, "\n");
       }
 
@@ -1963,3 +1982,546 @@ dump_global_regs (file)
       fprintf (file, " %d", i);
   fprintf (file, "\n\n");
 }
+
+\f
+
+/* This page contains code to make live information more accurate.
+   The accurate register liveness at program point P means:
+     o there is a path from P to usage of the register and the
+       register is not redefined or killed on the path.
+     o register at P is partially available, i.e. there is a path from
+       a register definition to the point P and the register is not
+       killed (clobbered) on the path
+
+   The standard GCC live information means only the first condition.
+   Without the partial availability, there will be more register
+   conflicts and as a consequence worse register allocation.  The
+   typical example where the information can be different is a
+   register initialized in the loop at the basic block preceding the
+   loop in CFG.  */
+
+/* The following structure contains basic block data flow information
+   used to calculate partial availability of registers.  */
+
+struct bb_info
+{
+  /* The basic block reverse post-order number.  */
+  int rts_number;
+  /* Registers used uninitialized in an insn in which there is an
+     early clobbered register might get the same hard register.  */
+  bitmap earlyclobber;
+  /* Registers correspondingly killed (clobbered) and defined but not
+     killed afterward in the basic block.  */
+  bitmap killed, avloc;
+  /* Registers partially available and living (in other words whose
+     values were calculated and used) correspondingly at the start
+     and end of the basic block.  */
+  bitmap live_pavin, live_pavout;
+};
+
+/* Macros for accessing data flow information of basic blocks.  */
+
+#define BB_INFO(BB) ((struct bb_info *) (BB)->aux)
+#define BB_INFO_BY_INDEX(N) BB_INFO (BASIC_BLOCK(N))
+
+/* The function allocates the info structures of each basic block.  It
+   also initialized LIVE_PAVIN and LIVE_PAVOUT as if all hard
+   registers were partially available.  */
+
+static void
+allocate_bb_info (void)
+{
+  int i;
+  basic_block bb;
+  struct bb_info *bb_info;
+  bitmap init;
+
+  alloc_aux_for_blocks (sizeof (struct bb_info));
+  init = BITMAP_ALLOC (NULL);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    bitmap_set_bit (init, i);
+  FOR_EACH_BB (bb)
+    {
+      bb_info = bb->aux;
+      bb_info->earlyclobber = BITMAP_ALLOC (NULL);
+      bb_info->avloc = BITMAP_ALLOC (NULL);
+      bb_info->killed = BITMAP_ALLOC (NULL);
+      bb_info->live_pavin = BITMAP_ALLOC (NULL);
+      bb_info->live_pavout = BITMAP_ALLOC (NULL);
+      bitmap_copy (bb_info->live_pavin, init);
+      bitmap_copy (bb_info->live_pavout, init);
+    }
+  BITMAP_FREE (init);
+}
+
+/* The function frees the allocated info of all basic blocks.  */
+
+static void
+free_bb_info (void)
+{
+  basic_block bb;
+  struct bb_info *bb_info;
+
+  FOR_EACH_BB (bb)
+    {
+      bb_info = BB_INFO (bb);
+      BITMAP_FREE (bb_info->live_pavout);
+      BITMAP_FREE (bb_info->live_pavin);
+      BITMAP_FREE (bb_info->killed);
+      BITMAP_FREE (bb_info->avloc);
+      BITMAP_FREE (bb_info->earlyclobber);
+    }
+  free_aux_for_blocks ();
+}
+
+/* The function modifies local info for register REG being changed in
+   SETTER.  DATA is used to pass the current basic block info.  */
+
+static void
+mark_reg_change (rtx reg, rtx setter, void *data)
+{
+  int regno;
+  basic_block bb = data;
+  struct bb_info *bb_info = BB_INFO (bb);
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (!REG_P (reg))
+    return;
+
+  regno = REGNO (reg);
+  bitmap_set_bit (bb_info->killed, regno);
+  
+  if (GET_CODE (setter) != CLOBBER)
+    bitmap_set_bit (bb_info->avloc, regno);
+  else
+    bitmap_clear_bit (bb_info->avloc, regno);
+}
+
+/* Classes of registers which could be early clobbered in the current
+   insn.  */
+
+DEF_VEC_I(int);
+DEF_VEC_ALLOC_I(int,heap);
+
+static VEC(int,heap) *earlyclobber_regclass;
+
+/* This function finds and stores register classes that could be early
+   clobbered in INSN.  If any earlyclobber classes are found, the function
+   returns TRUE, in all other cases it returns FALSE.  */
+
+static bool
+check_earlyclobber (rtx insn)
+{
+  int opno;
+  bool found = false;
+
+  extract_insn (insn);
+
+  VEC_truncate (int, earlyclobber_regclass, 0);
+  for (opno = 0; opno < recog_data.n_operands; opno++)
+    {
+      char c;
+      bool amp_p;
+      int i;
+      enum reg_class class;
+      const char *p = recog_data.constraints[opno];
+
+      class = NO_REGS;
+      amp_p = false;
+      for (;;)
+       {
+         c = *p;
+         switch (c)
+           {
+           case '=':  case '+':  case '?':
+           case '#':  case '!':
+           case '*':  case '%':
+           case 'm':  case '<':  case '>':  case 'V':  case 'o':
+           case 'E':  case 'F':  case 'G':  case 'H':
+           case 's':  case 'i':  case 'n':
+           case 'I':  case 'J':  case 'K':  case 'L':
+           case 'M':  case 'N':  case 'O':  case 'P':
+           case 'X':
+           case '0': case '1':  case '2':  case '3':  case '4':
+           case '5': case '6':  case '7':  case '8':  case '9':
+             /* These don't say anything we care about.  */
+             break;
+
+           case '&':
+             amp_p = true;
+             break;
+           case '\0':
+           case ',':
+             if (amp_p && class != NO_REGS)
+               {
+                 int rc;
+
+                 found = true;
+                 for (i = 0;
+                      VEC_iterate (int, earlyclobber_regclass, i, rc);
+                      i++)
+                   {
+                     if (rc == (int) class)
+                       goto found_rc;
+                   }
+
+                 /* We use VEC_quick_push here because
+                    earlyclobber_regclass holds no more than
+                    N_REG_CLASSES elements. */
+                 VEC_quick_push (int, earlyclobber_regclass, (int) class);
+               found_rc:
+                 ;
+               }
+             
+             amp_p = false;
+             class = NO_REGS;
+             break;
+
+           case 'r':
+             class = GENERAL_REGS;
+             break;
+
+           default:
+             class = REG_CLASS_FROM_CONSTRAINT (c, p);
+             break;
+           }
+         if (c == '\0')
+           break;
+         p += CONSTRAINT_LEN (c, p);
+       }
+    }
+
+  return found;
+}
+
+/* The function checks that pseudo-register *X has a class
+   intersecting with the class of pseudo-register could be early
+   clobbered in the same insn.
+   This function is a no-op if earlyclobber_regclass is empty.  */
+
+static int
+mark_reg_use_for_earlyclobber (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  enum reg_class pref_class, alt_class;
+  int i, regno;
+  basic_block bb = data;
+  struct bb_info *bb_info = BB_INFO (bb);
+
+  if (REG_P (*x) && REGNO (*x) >= FIRST_PSEUDO_REGISTER)
+    {
+      int rc;
+
+      regno = REGNO (*x);
+      if (bitmap_bit_p (bb_info->killed, regno)
+         || bitmap_bit_p (bb_info->avloc, regno))
+       return 0;
+      pref_class = reg_preferred_class (regno);
+      alt_class = reg_alternate_class (regno);
+      for (i = 0; VEC_iterate (int, earlyclobber_regclass, i, rc); i++)
+       {
+         if (reg_classes_intersect_p (rc, pref_class)
+             || (rc != NO_REGS
+                 && reg_classes_intersect_p (rc, alt_class)))
+           {
+             bitmap_set_bit (bb_info->earlyclobber, regno);
+             break;
+           }
+       }
+    }
+  return 0;
+}
+
+/* The function processes all pseudo-registers in *X with the aid of
+   previous function.  */
+
+static void
+mark_reg_use_for_earlyclobber_1 (rtx *x, void *data)
+{
+  for_each_rtx (x, mark_reg_use_for_earlyclobber, data);
+}
+
+/* The function calculates local info for each basic block.  */
+
+static void
+calculate_local_reg_bb_info (void)
+{
+  basic_block bb;
+  rtx insn, bound;
+
+  /* We know that earlyclobber_regclass holds no more than
+    N_REG_CLASSES elements.  See check_earlyclobber.  */
+  earlyclobber_regclass = VEC_alloc (int, heap, N_REG_CLASSES);
+  FOR_EACH_BB (bb)
+    {
+      bound = NEXT_INSN (BB_END (bb));
+      for (insn = BB_HEAD (bb); insn != bound; insn = NEXT_INSN (insn))
+       if (INSN_P (insn))
+         {
+           note_stores (PATTERN (insn), mark_reg_change, bb);
+           if (check_earlyclobber (insn))
+             note_uses (&PATTERN (insn), mark_reg_use_for_earlyclobber_1, bb);
+         }
+    }
+  VEC_free (int, heap, earlyclobber_regclass);
+}
+
+/* The function sets up reverse post-order number of each basic
+   block.  */
+
+static void
+set_up_bb_rts_numbers (void)
+{
+  int i;
+  int *rts_order;
+  
+  rts_order = xmalloc (sizeof (int) * n_basic_blocks);
+  flow_reverse_top_sort_order_compute (rts_order);
+  for (i = 0; i < n_basic_blocks; i++)
+    BB_INFO_BY_INDEX (rts_order [i])->rts_number = i;
+  free (rts_order);
+}
+
+/* Compare function for sorting blocks in reverse postorder.  */
+
+static int
+rpost_cmp (const void *bb1, const void *bb2)
+{
+  basic_block b1 = *(basic_block *) bb1, b2 = *(basic_block *) bb2;
+
+  return BB_INFO (b2)->rts_number - BB_INFO (b1)->rts_number;
+}
+
+/* Temporary bitmap used for live_pavin, live_pavout calculation.  */
+static bitmap temp_bitmap;
+
+DEF_VEC_P(basic_block);
+DEF_VEC_ALLOC_P(basic_block,heap);
+
+/* The function calculates partial register availability according to
+   the following equations:
+
+     bb.live_pavin
+       = empty for entry block
+         | union (live_pavout of predecessors) & global_live_at_start
+     bb.live_pavout = union (bb.live_pavin - bb.killed, bb.avloc)
+                      & global_live_at_end  */
+
+static void
+calculate_reg_pav (void)
+{
+  basic_block bb, succ;
+  edge e;
+  int i, nel;
+  VEC(basic_block,heap) *bbs, *new_bbs, *temp;
+  basic_block *bb_array;
+  sbitmap wset;
+
+  bbs = VEC_alloc (basic_block, heap, n_basic_blocks);
+  new_bbs = VEC_alloc (basic_block, heap, n_basic_blocks);
+  temp_bitmap = BITMAP_ALLOC (NULL);
+  FOR_EACH_BB (bb)
+    {
+      VEC_quick_push (basic_block, bbs, bb);
+    }
+  wset = sbitmap_alloc (n_basic_blocks + 1);
+  while (VEC_length (basic_block, bbs))
+    {
+      bb_array = VEC_address (basic_block, bbs);
+      nel = VEC_length (basic_block, bbs);
+      qsort (bb_array, nel, sizeof (basic_block), rpost_cmp);
+      sbitmap_zero (wset);
+      for (i = 0; i < nel; i++)
+       {
+         edge_iterator ei;
+         struct bb_info *bb_info;
+         bitmap bb_live_pavin, bb_live_pavout;
+             
+         bb = bb_array [i];
+         bb_info = BB_INFO (bb);
+         bb_live_pavin = bb_info->live_pavin;
+         bb_live_pavout = bb_info->live_pavout;
+         FOR_EACH_EDGE (e, ei, bb->preds)
+           {
+             basic_block pred = e->src;
+
+             if (pred->index != ENTRY_BLOCK)
+               bitmap_ior_into (bb_live_pavin, BB_INFO (pred)->live_pavout);
+           }
+         bitmap_and_into (bb_live_pavin, bb->il.rtl->global_live_at_start);
+         bitmap_ior_and_compl (temp_bitmap, bb_info->avloc,
+                               bb_live_pavin, bb_info->killed);
+         bitmap_and_into (temp_bitmap, bb->il.rtl->global_live_at_end);
+         if (! bitmap_equal_p (temp_bitmap, bb_live_pavout))
+           {
+             bitmap_copy (bb_live_pavout, temp_bitmap);
+             FOR_EACH_EDGE (e, ei, bb->succs)
+               {
+                 succ = e->dest;
+                 if (succ->index != EXIT_BLOCK
+                     && !TEST_BIT (wset, succ->index))
+                   {
+                     SET_BIT (wset, succ->index);
+                     VEC_quick_push (basic_block, new_bbs, succ);
+                   }
+               }
+           }
+       }
+      temp = bbs;
+      bbs = new_bbs;
+      new_bbs = temp;
+      VEC_truncate (basic_block, new_bbs, 0);
+    }
+  sbitmap_free (wset);
+  BITMAP_FREE (temp_bitmap);
+  VEC_free (basic_block, heap, new_bbs);
+  VEC_free (basic_block, heap, bbs);
+}
+
+/* The function modifies partial availability information for two
+   special cases to prevent incorrect work of the subsequent passes
+   with the accurate live information based on the partial
+   availability.  */
+
+static void
+modify_reg_pav (void)
+{
+  basic_block bb;
+  struct bb_info *bb_info;
+#ifdef STACK_REGS
+  int i;
+  HARD_REG_SET zero, stack_hard_regs, used;
+  bitmap stack_regs;
+
+  CLEAR_HARD_REG_SET (zero);
+  CLEAR_HARD_REG_SET (stack_hard_regs);
+  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+    SET_HARD_REG_BIT(stack_hard_regs, i);
+  stack_regs = BITMAP_ALLOC (NULL);
+  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+    {
+      COPY_HARD_REG_SET (used, reg_class_contents[reg_preferred_class (i)]);
+      IOR_HARD_REG_SET (used, reg_class_contents[reg_alternate_class (i)]);
+      AND_HARD_REG_SET (used, stack_hard_regs);
+      GO_IF_HARD_REG_EQUAL(used, zero, skip);
+      bitmap_set_bit (stack_regs, i);
+    skip:
+      ;
+    }
+#endif
+  FOR_EACH_BB (bb)
+    {
+      bb_info = BB_INFO (bb);
+      
+      /* Reload can assign the same hard register to uninitialized
+        pseudo-register and early clobbered pseudo-register in an
+        insn if the pseudo-register is used first time in given BB
+        and not lived at the BB start.  To prevent this we don't
+        change life information for such pseudo-registers.  */
+      bitmap_ior_into (bb_info->live_pavin, bb_info->earlyclobber);
+#ifdef STACK_REGS
+      /* We can not use the same stack register for uninitialized
+        pseudo-register and another living pseudo-register because if the
+        uninitialized pseudo-register dies, subsequent pass reg-stack
+        will be confused (it will believe that the other register
+        dies).  */
+      bitmap_ior_into (bb_info->live_pavin, stack_regs);
+#endif
+    }
+#ifdef STACK_REGS
+  BITMAP_FREE (stack_regs);
+#endif
+}
+
+/* The following function makes live information more accurate by
+   modifying global_live_at_start and global_live_at_end of basic
+   blocks.
+
+   The standard GCC life analysis permits registers to live
+   uninitialized, for example:
+
+       R is never used
+       .....
+       Loop:
+         R is defined
+       ...
+       R is used.
+
+   With normal life_analysis, R would be live before "Loop:".
+   The result is that R causes many interferences that do not
+   serve any purpose.
+
+   After the function call a register lives at a program point
+   only if it is initialized on a path from CFG entry to the
+   program point.  */
+
+static void
+make_accurate_live_analysis (void)
+{
+  basic_block bb;
+  struct bb_info *bb_info;
+
+  max_regno = max_reg_num ();
+  compact_blocks ();
+  allocate_bb_info ();
+  calculate_local_reg_bb_info ();
+  set_up_bb_rts_numbers ();
+  calculate_reg_pav ();
+  modify_reg_pav ();
+  FOR_EACH_BB (bb)
+    {
+      bb_info = BB_INFO (bb);
+      
+      bitmap_and_into (bb->il.rtl->global_live_at_start, bb_info->live_pavin);
+      bitmap_and_into (bb->il.rtl->global_live_at_end, bb_info->live_pavout);
+    }
+  free_bb_info ();
+}
+/* Run old register allocator.  Return TRUE if we must exit
+   rest_of_compilation upon return.  */
+static void
+rest_of_handle_global_alloc (void)
+{
+  bool failure;
+
+  /* If optimizing, allocate remaining pseudo-regs.  Do the reload
+     pass fixing up any insns that are invalid.  */
+
+  if (optimize)
+    failure = global_alloc (dump_file);
+  else
+    {
+      build_insn_chain (get_insns ());
+      failure = reload (get_insns (), 0);
+    }
+
+  if (dump_enabled_p (pass_global_alloc.static_pass_number))
+    {
+      timevar_push (TV_DUMP);
+      dump_global_regs (dump_file);
+      timevar_pop (TV_DUMP);
+    }
+
+  gcc_assert (reload_completed || failure);
+  reload_completed = !failure;
+}
+
+struct tree_opt_pass pass_global_alloc =
+{
+  "greg",                               /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_global_alloc,          /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_GLOBAL_ALLOC,                      /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'g'                                   /* letter */
+};
+