OSDN Git Service

* global.c: Include machmode.h amd move hard-reg-set.h before
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index 9bdfd10..d382537 100644 (file)
@@ -1,5 +1,5 @@
 /* Allocate registers for pseudo-registers that span basic blocks.
-   Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 94, 96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,18 +15,22 @@ 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.  */
 
 
-#include <stdio.h>
 #include "config.h"
+#include "system.h"
+
+#include "machmode.h"
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "flags.h"
 #include "basic-block.h"
-#include "hard-reg-set.h"
 #include "regs.h"
 #include "insn-config.h"
 #include "output.h"
+#include "toplev.h"
 
 /* This pass of the compiler performs global register allocation.
    It assigns hard register numbers to all the pseudo registers
@@ -74,7 +78,7 @@ static int max_allocno;
 /* Indexed by (pseudo) reg number, gives the allocno, or -1
    for pseudo registers already allocated by local_allocate.  */
 
-static int *reg_allocno;
+int *reg_allocno;
 
 /* Indexed by allocno, gives the reg number.  */
 
@@ -91,11 +95,18 @@ static int *allocno_order;
 static int *allocno_size;
 
 /* Indexed by (pseudo) reg number, gives the number of another
-   lower-numbered pseudo reg which can share a hard reg with this peudo
+   lower-numbered pseudo reg which can share a hard reg with this pseudo
    *even if the two pseudos would otherwise appear to conflict*.  */
 
 static int *reg_may_share;
 
+/* Define the number of bits in each element of `conflicts' and what
+   type that element has.  We use the largest integer format on the
+   host machine.  */
+
+#define INT_BITS HOST_BITS_PER_WIDE_INT
+#define INT_TYPE HOST_WIDE_INT
+
 /* max_allocno by max_allocno array of bits,
    recording whether two allocno's conflict (can't go in the same
    hardware register).
@@ -103,7 +114,7 @@ static int *reg_may_share;
    `conflicts' is not symmetric; a conflict between allocno's i and j
    is recorded either in element i,j or in element j,i.  */
 
-static int *conflicts;
+static INT_TYPE *conflicts;
 
 /* Number of ints require to hold max_allocno bits.
    This is the length of a row in `conflicts'.  */
@@ -114,11 +125,11 @@ static int allocno_row_words;
 
 #define CONFLICTP(I, J) \
  (conflicts[(I) * allocno_row_words + (J) / INT_BITS]  \
-  & (1 << ((J) % INT_BITS)))
+  & ((INT_TYPE) 1 << ((J) % INT_BITS)))
 
 #define SET_CONFLICT(I, J) \
  (conflicts[(I) * allocno_row_words + (J) / INT_BITS]  \
-  |= (1 << ((J) % INT_BITS)))
+  |= ((INT_TYPE) 1 << ((J) % INT_BITS)))
 
 /* Set of hard regs currently live (during scan of all insns).  */
 
@@ -194,21 +205,19 @@ static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
 
 /* Bit mask for allocnos live at current point in the scan.  */
 
-static int *allocnos_live;
-
-#define INT_BITS HOST_BITS_PER_INT
+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[(I) / INT_BITS] & (1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] & ((INT_TYPE) 1 << ((I) % INT_BITS)))
 
 #define SET_ALLOCNO_LIVE(I) \
-  (allocnos_live[(I) / INT_BITS] |= (1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] |= ((INT_TYPE) 1 << ((I) % INT_BITS)))
 
 #define CLEAR_ALLOCNO_LIVE(I) \
-  (allocnos_live[(I) / INT_BITS] &= ~(1 << ((I) % INT_BITS)))
+  (allocnos_live[(I) / INT_BITS] &= ~((INT_TYPE) 1 << ((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.)
@@ -241,36 +250,48 @@ static struct { int allocno1, allocno2;}
 static rtx *regs_set;
 static int n_regs_set;
 
-/* All register that can be eliminated.  */
+/* All registers that can be eliminated.  */
 
 static HARD_REG_SET eliminable_regset;
 
-static int allocno_compare ();
-static void mark_reg_store ();
-static void mark_reg_clobber ();
-static void mark_reg_live_nc ();
-static void mark_reg_death ();
-static void dump_conflicts ();
-void dump_global_regs ();
-static void find_reg ();
-static void global_conflicts ();
-static void expand_preferences ();
-static void prune_preferences ();
-static void record_conflicts ();
-static void set_preference ();
+static int allocno_compare     PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void global_conflicts   PROTO((void));
+static void expand_preferences PROTO((void));
+static void prune_preferences  PROTO((void));
+static void find_reg           PROTO((int, HARD_REG_SET, int, int, int));
+static void record_one_conflict PROTO((int));
+static void record_conflicts   PROTO((short *, int));
+static void mark_reg_store     PROTO((rtx, rtx));
+static void mark_reg_clobber   PROTO((rtx, rtx));
+static void mark_reg_conflicts PROTO((rtx));
+static void mark_reg_death     PROTO((rtx));
+static void mark_reg_live_nc   PROTO((int, enum machine_mode));
+static void set_preference     PROTO((rtx, rtx));
+static void dump_conflicts     PROTO((FILE *));
 \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.  */
+   or zero if such output is not desired.
 
-void
+   Return value is nonzero if reload failed
+   and we must not do any more for this function.  */
+
+int
 global_alloc (file)
      FILE *file;
 {
+  int retval;
 #ifdef ELIMINABLE_REGS
   static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
 #endif
-  register int i;
+  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;
   rtx x;
 
   max_allocno = 0;
@@ -293,16 +314,18 @@ global_alloc (file)
       SET_HARD_REG_BIT (eliminable_regset, eliminables[i].from);
 
       if (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-         || (eliminables[i].from == FRAME_POINTER_REGNUM
-             && (! flag_omit_frame_pointer || FRAME_POINTER_REQUIRED)))
+         || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp))
        SET_HARD_REG_BIT (no_global_alloc_regs, eliminables[i].from);
     }
+#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);
+#endif
+
 #else
   SET_HARD_REG_BIT (eliminable_regset, FRAME_POINTER_REGNUM);
-
-  /* If we know we will definitely not be eliminating the frame pointer,
-     don't allocate it.  */
-  if (! flag_omit_frame_pointer || FRAME_POINTER_REQUIRED)
+  if (need_fp)
     SET_HARD_REG_BIT (no_global_alloc_regs, FRAME_POINTER_REGNUM);
 #endif
 
@@ -351,7 +374,7 @@ global_alloc (file)
   /* Initialize the shared-hard-reg mapping
      from the list of pairs that may share.  */
   reg_may_share = (int *) alloca (max_regno * sizeof (int));
-  bzero (reg_may_share, max_regno * sizeof (int));
+  bzero ((char *) reg_may_share, max_regno * sizeof (int));
   for (x = regs_may_share; x; x = XEXP (XEXP (x, 1), 1))
     {
       int r1 = REGNO (XEXP (x, 0));
@@ -366,17 +389,17 @@ global_alloc (file)
     /* Note that reg_live_length[i] < 0 indicates a "constant" reg
        that we are supposed to refrain from putting in a hard reg.
        -2 means do make an allocno but don't allocate it.  */
-    if (reg_n_refs[i] != 0 && reg_renumber[i] < 0 && reg_live_length[i] != -1
+    if (REG_N_REFS (i) != 0 && reg_renumber[i] < 0 && REG_LIVE_LENGTH (i) != -1
        /* 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))
       {
        if (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)
+       if (REG_LIVE_LENGTH (i) == 0)
          abort ();
       }
     else
@@ -387,10 +410,10 @@ global_alloc (file)
   allocno_calls_crossed = (int *) alloca (max_allocno * sizeof (int));
   allocno_n_refs = (int *) alloca (max_allocno * sizeof (int));
   allocno_live_length = (int *) alloca (max_allocno * sizeof (int));
-  bzero (allocno_size, max_allocno * sizeof (int));
-  bzero (allocno_calls_crossed, max_allocno * sizeof (int));
-  bzero (allocno_n_refs, max_allocno * sizeof (int));
-  bzero (allocno_live_length, max_allocno * sizeof (int));
+  bzero ((char *) allocno_size, max_allocno * sizeof (int));
+  bzero ((char *) allocno_calls_crossed, max_allocno * sizeof (int));
+  bzero ((char *) allocno_n_refs, max_allocno * sizeof (int));
+  bzero ((char *) allocno_live_length, max_allocno * sizeof (int));
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_allocno[i] >= 0)
@@ -398,17 +421,17 @@ global_alloc (file)
        int allocno = reg_allocno[i];
        allocno_reg[allocno] = i;
        allocno_size[allocno] = PSEUDO_REGNO_SIZE (i);
-       allocno_calls_crossed[allocno] += reg_n_calls_crossed[i];
-       allocno_n_refs[allocno] += reg_n_refs[i];
-       if (allocno_live_length[allocno] < reg_live_length[i])
-         allocno_live_length[allocno] = reg_live_length[i];
+       allocno_calls_crossed[allocno] += REG_N_CALLS_CROSSED (i);
+       allocno_n_refs[allocno] += REG_N_REFS (i);
+       if (allocno_live_length[allocno] < REG_LIVE_LENGTH (i))
+         allocno_live_length[allocno] = REG_LIVE_LENGTH (i);
       }
 
   /* Calculate amount of usage of each hard reg by pseudos
      allocated by local-alloc.  This is to see if we want to
      override it.  */
-  bzero (local_reg_live_length, sizeof local_reg_live_length);
-  bzero (local_reg_n_refs, sizeof local_reg_n_refs);
+  bzero ((char *) local_reg_live_length, sizeof local_reg_live_length);
+  bzero ((char *) local_reg_n_refs, sizeof local_reg_n_refs);
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_allocno[i] < 0 && reg_renumber[i] >= 0)
       {
@@ -418,8 +441,8 @@ global_alloc (file)
 
        for (j = regno; j < endregno; j++)
          {
-           local_reg_n_refs[j] += reg_n_refs[i];
-           local_reg_live_length[j] += reg_live_length[i];
+           local_reg_n_refs[j] += REG_N_REFS (i);
+           local_reg_live_length[j] += REG_LIVE_LENGTH (i);
          }
       }
 
@@ -428,35 +451,54 @@ global_alloc (file)
     if (regs_ever_live[i])
       local_reg_n_refs[i] = 0;
 
+  /* Likewise for regs used in a SCRATCH.  */
+  for (i = 0; i < scratch_list_length; i++)
+    if (scratch_list[i])
+      {
+       int regno = REGNO (scratch_list[i]);
+       int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (scratch_list[i]));
+       int j;
+
+       for (j = regno; j < lim; j++)
+         local_reg_n_refs[j] = 0;
+      }
+       
   /* Allocate the space for the conflict and preference tables and
      initialize them.  */
 
   hard_reg_conflicts
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_conflicts, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_conflicts, max_allocno * sizeof (HARD_REG_SET));
 
   hard_reg_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_preferences, max_allocno * sizeof (HARD_REG_SET));
   
   hard_reg_copy_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_copy_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_copy_preferences,
+        max_allocno * sizeof (HARD_REG_SET));
   
   hard_reg_full_preferences
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (hard_reg_full_preferences, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) hard_reg_full_preferences,
+        max_allocno * sizeof (HARD_REG_SET));
   
   regs_someone_prefers
     = (HARD_REG_SET *) alloca (max_allocno * sizeof (HARD_REG_SET));
-  bzero (regs_someone_prefers, max_allocno * sizeof (HARD_REG_SET));
+  bzero ((char *) regs_someone_prefers, max_allocno * sizeof (HARD_REG_SET));
 
   allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
 
-  conflicts = (int *) alloca (max_allocno * allocno_row_words * sizeof (int));
-  bzero (conflicts, max_allocno * allocno_row_words * sizeof (int));
+  /* 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 *) xmalloc (max_allocno * allocno_row_words
+                                   * sizeof (INT_TYPE));
+  bzero ((char *) conflicts,
+        max_allocno * allocno_row_words * sizeof (INT_TYPE));
 
-  allocnos_live = (int *) alloca (allocno_row_words * sizeof (int));
+  allocnos_live = (INT_TYPE *) alloca (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.  */
@@ -519,19 +561,19 @@ global_alloc (file)
         except for parameters marked with reg_live_length[regno] == -2.  */
 
       for (i = 0; i < max_allocno; i++)
-       if (reg_live_length[allocno_reg[allocno_order[i]]] >= 0)
+       if (REG_LIVE_LENGTH (allocno_reg[allocno_order[i]]) >= 0)
          {
            /* If we have more than one register class,
               first try allocating in the class that is cheapest
               for this pseudo-reg.  If that fails, try any reg.  */
            if (N_REG_CLASSES > 1)
              {
-               find_reg (allocno_order[i], HARD_CONST (0), 0, 0, 0);
+               find_reg (allocno_order[i], 0, 0, 0, 0);
                if (reg_renumber[allocno_reg[allocno_order[i]]] >= 0)
                  continue;
              }
-           if (!reg_preferred_or_nothing (allocno_reg[allocno_order[i]]))
-             find_reg (allocno_order[i], HARD_CONST (0), 1, 0, 0);
+           if (reg_alternate_class (allocno_reg[allocno_order[i]]) != NO_REGS)
+             find_reg (allocno_order[i], 0, 1, 0, 0);
          }
     }
 
@@ -542,34 +584,39 @@ global_alloc (file)
         for the sake of debugging information.  */
   if (n_basic_blocks > 0)
 #endif
-    reload (basic_block_head[0], 1, file);
+    retval = reload (get_insns (), 1, file);
+
+  free (conflicts);
+  return retval;
 }
 
 /* Sort predicate for ordering the allocnos.
    Returns -1 (1) if *v1 should be allocated before (after) *v2.  */
 
 static int
-allocno_compare (v1, v2)
-     int *v1, *v2;
+allocno_compare (v1p, v2p)
+     const GENERIC_PTR v1p;
+     const GENERIC_PTR v2p;
 {
+  int v1 = *(int *)v1p, v2 = *(int *)v2p;
   /* Note that the quotient will never be bigger than
      the value of floor_log2 times the maximum number of
      times a register can occur in one insn (surely less than 100).
      Multiplying this by 10000 can't overflow.  */
   register int pri1
-    = (((double) (floor_log2 (allocno_n_refs[*v1]) * allocno_n_refs[*v1])
-       / (allocno_live_length[*v1] * allocno_size[*v1]))
-       * 10000);
+    = (((double) (floor_log2 (allocno_n_refs[v1]) * allocno_n_refs[v1])
+       / allocno_live_length[v1])
+       * 10000 * allocno_size[v1]);
   register int pri2
-    = (((double) (floor_log2 (allocno_n_refs[*v2]) * allocno_n_refs[*v2])
-       / (allocno_live_length[*v2] * allocno_size[*v2]))
-       * 10000);
+    = (((double) (floor_log2 (allocno_n_refs[v2]) * allocno_n_refs[v2])
+       / allocno_live_length[v2])
+       * 10000 * allocno_size[v2]);
   if (pri2 - pri1)
     return pri2 - pri1;
 
   /* If regs are equally good, sort by allocno,
      so that the results of qsort leave nothing to chance.  */
-  return *v1 - *v2;
+  return v1 - v2;
 }
 \f
 /* Scan the rtl code and record all conflicts and register preferences in the
@@ -589,7 +636,7 @@ global_conflicts ()
 
   for (b = 0; b < n_basic_blocks; b++)
     {
-      bzero (allocnos_live, allocno_row_words * sizeof (int));
+      bzero ((char *) allocnos_live, allocno_row_words * sizeof (INT_TYPE));
 
       /* Initialize table of registers currently live
         to the state at the beginning of this basic block.
@@ -605,40 +652,36 @@ global_conflicts ()
         are explicitly marked in basic_block_live_at_start.  */
 
       {
-       register int offset, bit;
        register regset old = basic_block_live_at_start[b];
        int ax = 0;
 
-#ifdef HARD_REG_SET
-       hard_regs_live = old[0];
-#else
-       COPY_HARD_REG_SET (hard_regs_live, old);
-#endif
-       for (offset = 0, i = 0; offset < regset_size; offset++)
-         if (old[offset] == 0)
-           i += HOST_BITS_PER_INT;
-         else
-           for (bit = 1; bit; bit <<= 1, i++)
-             {
-               if (i >= max_regno)
-                 break;
-               if (old[offset] & bit)
-                 {
-                   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));
-                 }
-             }
+       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));
+                                  });
 
        /* Record that each allocno now live conflicts with each other
           allocno now live, and with each hard reg now 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 can be reached through a computed goto, since reg-stack
+          can't handle computed gotos.  */
+       if (basic_block_computed_jump_target[b])
+         for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
+           record_one_conflict (ax);
+#endif
       }
 
       insn = basic_block_head[b];
@@ -658,9 +701,9 @@ global_conflicts ()
 
          if (code == INSN || code == CALL_INSN || code == JUMP_INSN)
            {
-             int i = 0;
 
 #if 0
+             int i = 0;
              for (link = REG_NOTES (insn);
                   link && i < NUM_NO_CONFLICT_PAIRS;
                   link = XEXP (link, 1))
@@ -695,9 +738,34 @@ global_conflicts ()
 #ifdef AUTO_INC_DEC
              for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
                if (REG_NOTE_KIND (link) == REG_INC)
-                 mark_reg_store (XEXP (link, 0), 0);
+                 mark_reg_store (XEXP (link, 0), NULL_RTX);
 #endif
 
+             /* If INSN has multiple outputs, then any reg that dies here
+                and is used inside of an output
+                must conflict with the other outputs.  */
+
+             if (GET_CODE (PATTERN (insn)) == PARALLEL && !single_set (insn))
+               for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+                 if (REG_NOTE_KIND (link) == REG_DEAD)
+                   {
+                     int used_in_output = 0;
+                     int i;
+                     rtx reg = XEXP (link, 0);
+
+                     for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+                       {
+                         rtx set = XVECEXP (PATTERN (insn), 0, i);
+                         if (GET_CODE (set) == SET
+                             && GET_CODE (SET_DEST (set)) != REG
+                             && !rtx_equal_p (reg, SET_DEST (set))
+                             && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+                           used_in_output = 1;
+                       }
+                     if (used_in_output)
+                       mark_reg_conflicts (reg);
+                   }
+
              /* Mark any registers set in INSN and then never used.  */
 
              while (n_regs_set > 0)
@@ -778,7 +846,7 @@ prune_preferences ()
   /* 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
-     prefered by each lower-priority register that conflicts.  */
+     preferred by each lower-priority register that conflicts.  */
 
   for (i = max_allocno - 1; i >= 0; i--)
     {
@@ -808,7 +876,8 @@ prune_preferences ()
         we want to give the lower-priority allocno the first chance for
         these registers).  */
       for (j = i + 1; j < max_allocno; j++)
-       if (CONFLICTP (allocno, allocno_order[j]))
+       if (CONFLICTP (allocno, allocno_order[j])
+           || CONFLICTP (allocno_order[j], allocno))
          {
            COPY_HARD_REG_SET (temp,
                               hard_reg_full_preferences[allocno_order[j]]);
@@ -828,8 +897,8 @@ prune_preferences ()
    LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot
    be used for this allocation.
 
-   If ALL_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
-   Otherwise ignore that preferred class.
+   If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg.
+   Otherwise ignore that preferred class and use the alternate class.
 
    If ACCEPT_CALL_CLOBBERED is nonzero, accept a call-clobbered hard reg that
    will have to be saved and restored at calls.
@@ -840,10 +909,10 @@ prune_preferences ()
    If not, do nothing.  */
 
 static void
-find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
+find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
      int allocno;
      HARD_REG_SET losers;
-     int all_regs_p;
+     int alt_regs_p;
      int accept_call_clobbered;
      int retrying;
 {
@@ -853,8 +922,9 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
 #endif
     HARD_REG_SET used, used1, used2;
 
-  enum reg_class class 
-    = all_regs_p ? ALL_REGS : reg_preferred_class (allocno_reg[allocno]);
+  enum reg_class class = (alt_regs_p
+                         ? reg_alternate_class (allocno_reg[allocno])
+                         : reg_preferred_class (allocno_reg[allocno]));
   enum machine_mode mode = PSEUDO_REGNO_MODE (allocno_reg[allocno]);
 
   if (accept_call_clobbered)
@@ -874,8 +944,14 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
 
   IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
 
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+  if (REG_CHANGES_SIZE (allocno_reg[allocno]))
+    IOR_HARD_REG_SET (used1,
+                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
+#endif
+
   /* Try each hard reg to see if it fits.  Do this in two passes.
-     In the first pass, skip registers that are prefered by some other pseudo
+     In the first pass, skip registers that are preferred by some other pseudo
      to give it a better chance of getting one of those registers.  Only if
      we can't get a register when excluding those do we take one of them.
      However, we never allocate a register for the first time in pass 0.  */
@@ -1002,7 +1078,11 @@ find_reg (allocno, losers, all_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.  */
+
   if (flag_caller_saves && best_reg < 0)
     {
       /* Did not find a register.  If it would be profitable to
@@ -1013,7 +1093,14 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
          && CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno],
                                     allocno_calls_crossed[allocno]))
        {
-         find_reg (allocno, losers, all_regs_p, 1, retrying);
+         HARD_REG_SET new_losers;
+         if (! losers)
+           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 (allocno, new_losers, alt_regs_p, 1, retrying);
          if (reg_renumber[allocno_reg[allocno]] >= 0)
            {
              caller_save_needed = 1;
@@ -1033,31 +1120,55 @@ find_reg (allocno, losers, all_regs_p, accept_call_clobbered, retrying)
     {
       /* Count from the end, to find the least-used ones first.  */
       for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
-       if (local_reg_n_refs[i] != 0
-           /* Don't use a reg no good for this pseudo.  */
-           && ! TEST_HARD_REG_BIT (used2, i)
-           && HARD_REGNO_MODE_OK (i, mode)
-           && ((double) local_reg_n_refs[i] / local_reg_live_length[i]
-               < ((double) allocno_n_refs[allocno]
-                  / allocno_live_length[allocno])))
-         {
-           /* Hard reg I was used less in total by local regs
-              than it would be used by this one allocno!  */
-           int k;
-           for (k = 0; k < max_regno; k++)
-             if (reg_renumber[k] >= 0)
+       {
+#ifdef REG_ALLOC_ORDER
+         int regno = reg_alloc_order[i];
+#else
+         int regno = i;
+#endif
+
+         if (local_reg_n_refs[regno] != 0
+             /* 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_SIZE
+             && ! (REG_CHANGES_SIZE (allocno_reg[allocno])
+                   && (TEST_HARD_REG_BIT
+                       (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                        regno)))
+#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.  */
+                
+             double tmp1 = ((double) local_reg_n_refs[regno]
+                           / local_reg_live_length[regno]);
+             double tmp2 = ((double) allocno_n_refs[allocno]
+                            / allocno_live_length[allocno]);
+
+             if (tmp1 < tmp2)
                {
-                 int regno = reg_renumber[k];
-                 int endregno
-                   = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (k));
+                 /* Hard reg REGNO was used less in total by local regs
+                    than it would be used by this one allocno!  */
+                 int k;
+                 for (k = 0; k < max_regno; k++)
+                   if (reg_renumber[k] >= 0)
+                     {
+                       int r = reg_renumber[k];
+                       int endregno
+                         = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k));
 
-                 if (i >= regno && i < endregno)
-                   reg_renumber[k] = -1;
-               }
+                       if (regno >= r && regno < endregno)
+                         reg_renumber[k] = -1;
+                     }
 
-           best_reg = i;
-           break;
-         }
+                 best_reg = regno;
+                 break;
+               }
+           }
+       }
     }
 
   /* Did we find a register?  */
@@ -1117,7 +1228,7 @@ retry_global_alloc (regno, forbidden_regs)
       if (N_REG_CLASSES > 1)
        find_reg (allocno, forbidden_regs, 0, 0, 1);
       if (reg_renumber[regno] < 0
-         && !reg_preferred_or_nothing (regno))
+         && reg_alternate_class (regno) != NO_REGS)
        find_reg (allocno, forbidden_regs, 1, 0, 1);
 
       /* If we found a register, modify the RTL for the register to
@@ -1334,6 +1445,45 @@ mark_reg_clobber (reg, setter)
        }
     }
 }
+
+/* Record that REG has conflicts with all the regs currently live.
+   Do not mark REG itself as live.  */
+
+static void
+mark_reg_conflicts (reg)
+     rtx reg;
+{
+  register int regno;
+
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+
+  if (GET_CODE (reg) != REG)
+    return;
+
+  regno = REGNO (reg);
+
+  if (reg_renumber[regno] >= 0)
+    regno = reg_renumber[regno];
+
+  /* Either this is one of the max_allocno pseudo regs not allocated,
+     or it is or has a hardware reg.  First handle the pseudo-regs.  */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      if (reg_allocno[regno] >= 0)
+       record_one_conflict (regno);
+    }
+  /* Handle hardware regs (and pseudos allocated to hard regs).  */
+  else if (! fixed_regs[regno])
+    {
+      register int last = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+      while (regno < last)
+       {
+         record_one_conflict (regno);
+         regno++;
+       }
+    }
+}
 \f
 /* Mark REG as being dead (following the insn being scanned now).
    Store a 0 in regs_live or allocnos_live for this register.  */
@@ -1393,7 +1543,7 @@ mark_reg_live_nc (regno, mode)
    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 agressive as local-alloc in trying to tie a
+   Note that we are not as aggressive as local-alloc in trying to tie a
    pseudo-register to a hard register.  */
 
 static void
@@ -1495,13 +1645,10 @@ mark_elimination (from, to)
   int i;
 
   for (i = 0; i < n_basic_blocks; i++)
-    if ((basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
-        & (1 << (from % HOST_BITS_PER_INT))) != 0)
+    if (REGNO_REG_SET_P (basic_block_live_at_start[i], from))
       {
-       basic_block_live_at_start[i][from / HOST_BITS_PER_INT]
-         &= ~ (1 << (from % HOST_BITS_PER_INT));
-       basic_block_live_at_start[i][to / HOST_BITS_PER_INT]
-         |= (1 << (to % HOST_BITS_PER_INT));
+       CLEAR_REGNO_REG_SET (basic_block_live_at_start[i], from);
+       SET_REGNO_REG_SET (basic_block_live_at_start[i], to);
       }
 }
 \f