OSDN Git Service

Fix mips64vr4100-elf build failure.
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index a922afd..e7ea926 100644 (file)
@@ -1,5 +1,5 @@
 /* Compute register class preferences for pseudo-registers.
-   Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file contains two passes of the compiler: reg_scan and reg_class.
@@ -23,6 +24,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    and a function init_reg_sets to initialize the tables.  */
 
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
 #include "hard-reg-set.h"
 #include "flags.h"
@@ -32,19 +34,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "recog.h"
 #include "reload.h"
 #include "real.h"
-#include "bytecode.h"
+#include "toplev.h"
+#include "output.h"
 
 #ifndef REGISTER_MOVE_COST
 #define REGISTER_MOVE_COST(x, y) 2
 #endif
 
-#ifndef MEMORY_MOVE_COST
-#define MEMORY_MOVE_COST(x) 4
-#endif
-
 /* If we have auto-increment or auto-decrement and we can have secondary
    reloads, we are not allowed to use classes requiring secondary
-   reloads for psuedos auto-incremented since reload can't handle it.  */
+   reloads for pseudos auto-incremented since reload can't handle it.  */
 
 #ifdef AUTO_INC_DEC
 #if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
@@ -80,6 +79,9 @@ char call_used_regs[FIRST_PSEUDO_REGISTER];
 
 HARD_REG_SET call_used_reg_set;
 
+/* HARD_REG_SET of registers we want to avoid caller saving.  */
+HARD_REG_SET losing_caller_save_reg_set;
+
 /* Data for initializing the above.  */
 
 static char initial_call_used_regs[] = CALL_USED_REGISTERS;
@@ -152,14 +154,12 @@ enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
 
 char *reg_names[] = REGISTER_NAMES;
 
-/* Indexed by n, gives number of times (REG n) is set or clobbered.
-   This information remains valid for the rest of the compilation
-   of the current function; it is used to control register allocation.
-
-   This information applies to both hard registers and pseudo registers,
-   unlike much of the information above.  */
+/* For each hard register, the widest mode object that it can contain.
+   This will be a MODE_INT mode if the register can hold integers.  Otherwise
+   it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
+   register.  */
 
-short *reg_n_sets;
+enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
 
 /* Maximum cost of moving from a register in one class to a register in
    another class.  Based on REGISTER_MOVE_COST.  */
@@ -185,6 +185,14 @@ static char *in_inc_dec;
 
 #endif /* FORBIDDEN_INC_DEC_CLASSES */
 
+#ifdef HAVE_SECONDARY_RELOADS
+
+/* Sample MEM values for use by memory_move_secondary_cost.  */
+
+static rtx top_of_stack[MAX_MACHINE_MODE];
+
+#endif /* HAVE_SECONDARY_RELOADS */
+
 /* Function called only once to initialize the above data on reg usage.
    Once this is done, various switches may override.  */
 
@@ -212,7 +220,7 @@ init_reg_sets ()
 
   /* Compute number of hard regs in each class.  */
 
-  bzero (reg_class_size, sizeof reg_class_size);
+  bzero ((char *) reg_class_size, sizeof reg_class_size);
   for (i = 0; i < N_REG_CLASSES; i++)
     for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
       if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
@@ -313,6 +321,50 @@ init_reg_sets ()
        }
     }
 
+  /* Do any additional initialization regsets may need */
+  INIT_ONCE_REG_SET ();
+}
+
+/* After switches have been processed, which perhaps alter
+   `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
+
+static void
+init_reg_sets_1 ()
+{
+  register unsigned int i, j;
+
+  /* This macro allows the fixed or call-used registers
+     to depend on target flags.  */
+
+#ifdef CONDITIONAL_REGISTER_USAGE
+  CONDITIONAL_REGISTER_USAGE;
+#endif
+
+  /* Initialize "constant" tables.  */
+
+  CLEAR_HARD_REG_SET (fixed_reg_set);
+  CLEAR_HARD_REG_SET (call_used_reg_set);
+  CLEAR_HARD_REG_SET (call_fixed_reg_set);
+
+  bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
+
+  n_non_fixed_regs = 0;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (fixed_regs[i])
+       SET_HARD_REG_BIT (fixed_reg_set, i);
+      else
+       n_non_fixed_regs++;
+
+      if (call_used_regs[i])
+       SET_HARD_REG_BIT (call_used_reg_set, i);
+      if (call_fixed_regs[i])
+       SET_HARD_REG_BIT (call_fixed_reg_set, i);
+      if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
+       SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
+    }
+
   /* Initialize the move cost table.  Find every subset of each class
      and take the maximum cost of moving any subset to any other.  */
 
@@ -346,51 +398,149 @@ init_reg_sets ()
       }
 }
 
-/* After switches have been processed, which perhaps alter
-   `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
+/* Compute the table of register modes.
+   These values are used to record death information for individual registers
+   (as opposed to a multi-register mode).  */
 
-void
-init_reg_sets_1 ()
+static void
+init_reg_modes ()
 {
   register int i;
 
-  /* This macro allows the fixed or call-used registers
-     to depend on target flags.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
+
+      /* If we couldn't find a valid mode, just use the previous mode.
+         ??? One situation in which we need to do this is on the mips where
+        HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2.  Ideally we'd like
+        to use DF mode for the even registers and VOIDmode for the odd
+        (for the cpu models where the odd ones are inaccessible).  */
+      if (reg_raw_mode[i] == VOIDmode)
+       reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
+    }
+}
 
-#ifdef CONDITIONAL_REGISTER_USAGE
-  CONDITIONAL_REGISTER_USAGE;
+/* Finish initializing the register sets and
+   initialize the register modes.  */
+
+void
+init_regs ()
+{
+  /* This finishes what was started by init_reg_sets, but couldn't be done
+     until after register usage was specified.  */
+  init_reg_sets_1 ();
+
+  init_reg_modes ();
+
+#ifdef HAVE_SECONDARY_RELOADS
+  {
+    /* Make some fake stack-frame MEM references for use in
+       memory_move_secondary_cost.  */
+    int i;
+    for (i = 0; i < MAX_MACHINE_MODE; i++)
+      top_of_stack[i] = gen_rtx (MEM, i, stack_pointer_rtx);
+  }
 #endif
+}
 
-  /* Initialize "constant" tables.  */
+#ifdef HAVE_SECONDARY_RELOADS
 
-  CLEAR_HARD_REG_SET (fixed_reg_set);
-  CLEAR_HARD_REG_SET (call_used_reg_set);
-  CLEAR_HARD_REG_SET (call_fixed_reg_set);
+/* Compute extra cost of moving registers to/from memory due to reloads.
+   Only needed if secondary reloads are required for memory moves.  */
 
-  bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
-#ifdef STRUCT_VALUE_REGNUM
-  call_fixed_regs[STRUCT_VALUE_REGNUM] = 1;
+int
+memory_move_secondary_cost (mode, class, in)
+     enum machine_mode mode;
+     enum reg_class class;
+     int in;
+{
+  enum reg_class altclass;
+  int partial_cost = 0;
+  /* We need a memory reference to feed to SECONDARY... macros.  */
+  rtx mem = top_of_stack[(int) mode];
+
+  if (in)
+    {
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+      altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem);
+#else
+      altclass = NO_REGS;
 #endif
-#ifdef STATIC_CHAIN_REGNUM
-  call_fixed_regs[STATIC_CHAIN_REGNUM] = 1;
+    }
+  else
+    {
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+      altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem);
+#else
+      altclass = NO_REGS;
 #endif
+    }
 
-  n_non_fixed_regs = 0;
+  if (altclass == NO_REGS)
+    return 0;
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      if (FUNCTION_VALUE_REGNO_P (i))
-       call_fixed_regs[i] = 1;
-      if (fixed_regs[i])
-       SET_HARD_REG_BIT (fixed_reg_set, i);
-      else
-       n_non_fixed_regs++;
+  if (in)
+    partial_cost = REGISTER_MOVE_COST (altclass, class);
+  else
+    partial_cost = REGISTER_MOVE_COST (class, altclass);
 
-      if (call_used_regs[i])
-       SET_HARD_REG_BIT (call_used_reg_set, i);
-      if (call_fixed_regs[i])
-       SET_HARD_REG_BIT (call_fixed_reg_set, i);
-    }
+  if (class == altclass)
+    /* This isn't simply a copy-to-temporary situation.  Can't guess
+       what it is, so MEMORY_MOVE_COST really ought not to be calling
+       here in that case.
+
+       I'm tempted to put in an abort here, but returning this will
+       probably only give poor estimates, which is what we would've
+       had before this code anyways.  */
+    return partial_cost;
+
+  /* Check if the secondary reload register will also need a
+     secondary reload.  */
+  return memory_move_secondary_cost (mode, altclass, in) + partial_cost;
+}
+#endif
+
+/* Return a machine mode that is legitimate for hard reg REGNO and large
+   enough to save nregs.  If we can't find one, return VOIDmode.  */
+
+enum machine_mode
+choose_hard_reg_mode (regno, nregs)
+     int regno;
+     int nregs;
+{
+  enum machine_mode found_mode = VOIDmode, mode;
+
+  /* We first look for the largest integer mode that can be validly
+     held in REGNO.  If none, we look for the largest floating-point mode.
+     If we still didn't find a valid mode, try CCmode.  */
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  if (HARD_REGNO_NREGS (regno, CCmode) == nregs
+      && HARD_REGNO_MODE_OK (regno, CCmode))
+    return CCmode;
+
+  /* We can't find a mode valid for this register.  */
+  return VOIDmode;
 }
 
 /* Specify the usage characteristics of the register named NAME.
@@ -404,13 +554,6 @@ fix_register (name, fixed, call_used)
 {
   int i;
 
-  if (output_bytecode)
-    {
-      warning ("request to mark `%s' as %s ignored by bytecode compiler",
-              name, call_used ? "call-used" : "fixed");
-      return;
-    }
-
   /* Decode the name and update the primary form of
      the register info.  */
 
@@ -503,10 +646,15 @@ static int loop_depth;
 
 static int loop_cost;
 
-static int copy_cost ();
-static void record_reg_classes ();
-static void record_address_regs ();
-
+static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
+                                      char **, rtx));
+static int copy_cost           PROTO((rtx, enum machine_mode, 
+                                      enum reg_class, int));
+static void record_address_regs        PROTO((rtx, enum reg_class, int));
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+static int auto_inc_dec_reg_p  PROTO((rtx, enum machine_mode));
+#endif
+static void reg_scan_mark_refs PROTO((rtx, rtx, int));
 
 /* Return the reg_class in which pseudo reg number REGNO is best allocated.
    This function is sometimes called before the info has been computed.
@@ -523,6 +671,7 @@ reg_preferred_class (regno)
 
 enum reg_class
 reg_alternate_class (regno)
+     int regno;
 {
   if (prefclass == 0)
     return ALL_REGS;
@@ -571,7 +720,7 @@ regclass (f, nregs)
 
   for (i = 0; i < N_REG_CLASSES; i++)
     {
-      rtx r = gen_rtx (REG, VOIDmode, 0);
+      rtx r = gen_rtx_REG (VOIDmode, 0);
       enum machine_mode m;
 
       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
@@ -584,16 +733,28 @@ regclass (f, nregs)
              if (HARD_REGNO_MODE_OK (j, m))
                {
                  PUT_MODE (r, m);
-                 if (0
+
+                 /* If a register is not directly suitable for an
+                    auto-increment or decrement addressing mode and
+                    requires secondary reloads, disallow its class from
+                    being used in such addresses.  */
+
+                 if ((0
+#ifdef SECONDARY_RELOAD_CLASS
+                      || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#else
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
-                     || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
-                         != NO_REGS)
+                      || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
 #endif
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-                     || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
-                         != NO_REGS)
+                      || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#endif
 #endif
-                     )
+                      )
+                     && ! auto_inc_dec_reg_p (r, m))
                    forbidden_inc_dec_class[i] = 1;
                }
          }
@@ -613,7 +774,7 @@ regclass (f, nregs)
     {
       /* Zero out our accumulation of the cost of each class for each reg.  */
 
-      bzero (costs, nregs * sizeof (struct costs));
+      bzero ((char *) costs, nregs * sizeof (struct costs));
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
       bzero (in_inc_dec, nregs);
@@ -682,7 +843,8 @@ regclass (f, nregs)
                      && GET_CODE (XEXP (note, 0)) == MEM)
                    {
                      costs[REGNO (SET_DEST (set))].mem_cost
-                       -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)))
+                       -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
+                                             GENERAL_REGS, 1)
                            * loop_cost);
                      record_address_regs (XEXP (SET_SRC (set), 0),
                                           BASE_REG_CLASS, loop_cost * 2);
@@ -734,8 +896,8 @@ regclass (f, nregs)
                              basic_block_head[b] = newinsn;
                        }
 
-                     /* This makes one more setting of new insns's dest. */
-                     reg_n_sets[REGNO (recog_operand[0])]++;
+                     /* This makes one more setting of new insns's dest.  */
+                     REG_N_SETS (REGNO (recog_operand[0]))++;
 
                      *recog_operand_loc[1] = recog_operand[0];
                      for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
@@ -878,7 +1040,7 @@ regclass (f, nregs)
          
          /* If we don't add any classes, nothing to try.  */
          if (alt == best)
-           alt = (int) NO_REGS;
+           alt = NO_REGS;
 
          /* We cast to (int) because (char) hits bugs in some compilers.  */
          prefclass[i] = (int) best;
@@ -926,6 +1088,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
   int alt;
   enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
   int i, j;
+  rtx set;
 
   /* By default, each operand is an input operand.  */
 
@@ -978,15 +1141,15 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER)
                {
                  /* If this matches the other operand, we have no added
-                    cost.  */
+                    cost and we win.  */
                  if (rtx_equal_p (ops[j], op))
-                   ;
+                   win = 1;
 
                  /* If we can put the other operand into a register, add to
                     the cost of this alternative the cost to copy this
                     operand to the register used for the other operand.  */
 
-                 if (classes[j] != NO_REGS)
+                 else if (classes[j] != NO_REGS)
                    alt_cost += copy_cost (op, mode, classes[j], 1), win = 1;
                }
              else if (GET_CODE (ops[j]) != REG
@@ -1051,8 +1214,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                p++;
                break;
 
+             case '?':
+               alt_cost += 2;
              case '%':
-             case '?':  case '!':  case '#':
+             case '!':  case '#':
              case '&':
              case '0':  case '1':  case '2':  case '3':  case '4':
              case 'p':
@@ -1081,12 +1246,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                break;
 
              case 'E':
+#ifndef REAL_ARITHMETIC
                /* Match any floating double constant, but only if
                   we can examine the bits of it reliably.  */
                if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
                     || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
                    && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
                  break;
+#endif
                if (GET_CODE (op) == CONST_DOUBLE)
                  win = 1;
                break;
@@ -1196,7 +1363,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                     a bit cheaper since we won't need an extra insn to
                     load it.  */
 
-                 pp->mem_cost = MEMORY_MOVE_COST (mode) - allows_mem;
+                 pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1)
+                                 - allows_mem);
 
                  /* If we have assigned a class to this register in our
                     first pass, add a cost to this alternative corresponding
@@ -1234,7 +1402,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
             constant that could be placed into memory.  */
 
          else if (CONSTANT_P (op) && allows_mem)
-           alt_cost += MEMORY_MOVE_COST (mode);
+           alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
          else
            alt_fail = 1;
        }
@@ -1260,6 +1428,46 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                                     (qq->cost[class] + alt_cost) * scale);
          }
     }
+
+  /* If this insn is a single set copying operand 1 to operand 0
+     and one is a pseudo with the other a hard reg that is in its
+     own register class, set the cost of that register class to -1.  */
+
+  if ((set = single_set (insn)) != 0
+      && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
+      && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG)
+    for (i = 0; i <= 1; i++)
+      if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
+       {
+         int regno = REGNO (ops[!i]);
+         enum machine_mode mode = GET_MODE (ops[!i]);
+         int class;
+         int nr;
+
+         if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0
+             && (reg_class_size[prefclass[regno]]
+                 == CLASS_MAX_NREGS (prefclass[regno], mode)))
+           op_costs[i].cost[prefclass[regno]] = -1;
+         else if (regno < FIRST_PSEUDO_REGISTER)
+           for (class = 0; class < N_REG_CLASSES; class++)
+             if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+                 && reg_class_size[class] == CLASS_MAX_NREGS (class, mode))
+               {
+                 if (reg_class_size[class] == 1)
+                   op_costs[i].cost[class] = -1;
+                 else
+                   {
+                     for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
+                       {
+                         if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
+                           break;
+                       }
+
+                     if (nr == HARD_REGNO_NREGS(regno,mode))
+                       op_costs[i].cost[class] = -1;
+                   }
+               }
+       }
 }
 \f
 /* Compute the cost of loading X into (if TO_P is non-zero) or from (if
@@ -1274,7 +1482,9 @@ copy_cost (x, mode, class, to_p)
      enum reg_class class;
      int to_p;
 {
+#ifdef HAVE_SECONDARY_RELOADS
   enum reg_class secondary_class = NO_REGS;
+#endif
 
   /* If X is a SCRATCH, there is actually nothing to move since we are
      assuming optimal allocation.  */
@@ -1311,7 +1521,7 @@ copy_cost (x, mode, class, to_p)
      else (constants).  */
 
   if (GET_CODE (x) == MEM || class == NO_REGS)
-    return MEMORY_MOVE_COST (mode);
+    return MEMORY_MOVE_COST (mode, class, to_p);
 
   else if (GET_CODE (x) == REG)
     return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
@@ -1403,38 +1613,54 @@ record_address_regs (x, class, scale)
        else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
          record_address_regs (arg0, INDEX_REG_CLASS, scale);
 
-       /* If this the sum of two registers where the first is known to be a 
-          pointer, it must be a base register with the second an index.  */
+       /* If both operands are registers but one is already a hard register
+          of index or base class, give the other the class that the hard
+          register is not.  */
 
+#ifdef REG_OK_FOR_BASE_P
        else if (code0 == REG && code1 == REG
-                && REGNO_POINTER_FLAG (REGNO (arg0)))
+                && REGNO (arg0) < FIRST_PSEUDO_REGISTER
+                && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0)))
+         record_address_regs (arg1,
+                              REG_OK_FOR_BASE_P (arg0)
+                              ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                              scale);
+       else if (code0 == REG && code1 == REG
+                && REGNO (arg1) < FIRST_PSEUDO_REGISTER
+                && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1)))
+         record_address_regs (arg0,
+                              REG_OK_FOR_BASE_P (arg1)
+                              ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                              scale);
+#endif
+
+       /* If one operand is known to be a pointer, it must be the base
+          with the other operand the index.  Likewise if the other operand
+          is a MULT.  */
+
+       else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0)))
+                || code1 == MULT)
          {
            record_address_regs (arg0, BASE_REG_CLASS, scale);
            record_address_regs (arg1, INDEX_REG_CLASS, scale);
          }
+       else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1)))
+                || code0 == MULT)
+         {
+           record_address_regs (arg0, INDEX_REG_CLASS, scale);
+           record_address_regs (arg1, BASE_REG_CLASS, scale);
+         }
 
-       /* If this is the sum of two registers and neither is known to
-          be a pointer, count equal chances that each might be a base
+       /* Otherwise, count equal chances that each might be a base
           or index register.  This case should be rare.  */
 
-       else if (code0 == REG && code1 == REG
-                && ! REGNO_POINTER_FLAG (REGNO (arg0))
-                && ! REGNO_POINTER_FLAG (REGNO (arg1)))
+       else
          {
            record_address_regs (arg0, BASE_REG_CLASS, scale / 2);
            record_address_regs (arg0, INDEX_REG_CLASS, scale / 2);
            record_address_regs (arg1, BASE_REG_CLASS, scale / 2);
            record_address_regs (arg1, INDEX_REG_CLASS, scale / 2);
          }
-
-       /* In all other cases, the first operand is an index and the
-          second is the base.  */
-
-       else
-         {
-           record_address_regs (arg0, INDEX_REG_CLASS, scale);
-           record_address_regs (arg1, BASE_REG_CLASS, scale);
-         }
       }
       break;
 
@@ -1461,7 +1687,7 @@ record_address_regs (x, class, scale)
        register struct costs *pp = &costs[REGNO (x)];
        register int i;
 
-       pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2;
+       pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
 
        for (i = 0; i < N_REG_CLASSES; i++)
          pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2;
@@ -1478,46 +1704,144 @@ record_address_regs (x, class, scale)
       }
     }
 }
+\f
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+
+/* Return 1 if REG is valid as an auto-increment memory reference
+   to an object of MODE.  */
+
+static int
+auto_inc_dec_reg_p (reg, mode)
+     rtx reg;
+     enum machine_mode mode;
+{
+#ifdef HAVE_POST_INCREMENT
+  if (memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_POST_DECREMENT
+  if (memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_PRE_INCREMENT
+  if (memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_PRE_DECREMENT
+  if (memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
+    return 1;
+#endif
+
+  return 0;
+}
+#endif
+
 #endif /* REGISTER_CONSTRAINTS */
 \f
-/* This is the `regscan' pass of the compiler, run just before cse
-   and again just before loop.
+/* Allocate enough space to hold NUM_REGS registers for the tables used for
+   reg_scan and flow_analysis that are indexed by the register number.  If
+   NEW_P is non zero, initialize all of the registers, otherwise only
+   initialize the new registers allocated.  The same table is kept from
+   function to function, only reallocating it when we need more room.  If
+   RENUMBER_P is non zero, allocate the reg_renumber array also.  */
 
-   It finds the first and last use of each pseudo-register
-   and records them in the vectors regno_first_uid, regno_last_uid
-   and counts the number of sets in the vector reg_n_sets.
+void
+allocate_reg_info (num_regs, new_p, renumber_p)
+     int num_regs;
+     int new_p;
+     int renumber_p;
+{
+  static int regno_allocated = 0;
+  static short *renumber = (short *)0;
+  int i;
+  int size_info;
+  int size_renumber;
+  int min = (new_p) ? 0 : reg_n_max;
 
-   REPEAT is nonzero the second time this is called.  */
+  /* If this message come up, and you want to fix it, then all of the tables
+     like reg_renumber, etc. that use short will have to be found and lengthed
+     to int or HOST_WIDE_INT.  */
 
-/* Indexed by pseudo register number, gives uid of first insn using the reg
-   (as of the time reg_scan is called).  */
+  /* Free up all storage allocated */
+  if (num_regs < 0)
+    {
+      if (reg_n_info)
+       {
+         free ((char *)reg_n_info);
+         free ((char *)renumber);
+         reg_n_info = (reg_info *)0;
+         renumber = (short *)0;
+       }
+      regno_allocated = 0;
+      reg_n_max = 0;
+      return;
+    }
 
-int *regno_first_uid;
+  if (num_regs > regno_allocated)
+    {
+      regno_allocated = num_regs + (num_regs / 20);    /* add some slop space */
+      size_info = regno_allocated * sizeof (reg_info);
+      size_renumber = regno_allocated * sizeof (short);
 
-/* Indexed by pseudo register number, gives uid of last insn using the reg
-   (as of the time reg_scan is called).  */
+      if (!reg_n_info)
+       {
+         reg_n_info = (reg_info *) xmalloc (size_info);
+         renumber = (short *) xmalloc (size_renumber);
+       }
 
-int *regno_last_uid;
+      else if (new_p)          /* if we're zapping everything, no need to realloc */
+       {
+         free ((char *)reg_n_info);
+         free ((char *)renumber);
+         reg_n_info = (reg_info *) xmalloc (size_info);
+         renumber = (short *) xmalloc (size_renumber);
+       }
 
-/* Indexed by pseudo register number, gives uid of last insn using the reg
-   or mentioning it in a note (as of the time reg_scan is called).  */
+      else
+       {
+         reg_n_info = (reg_info *) xrealloc ((char *)reg_n_info, size_info);
+         renumber = (short *) xrealloc ((char *)renumber, size_renumber);
+       }
+    }
 
-int *regno_last_note_uid;
+  if (min < num_regs)
+    {
+      bzero ((char *) &reg_n_info[min], (num_regs - min) * sizeof (reg_info));
+      for (i = min; i < num_regs; i++)
+       {
+         REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
+         renumber[i] = -1;
+       }
+    }
+
+  if (renumber_p)
+    reg_renumber = renumber;
+
+  /* Tell the regset code about the new number of registers */
+  MAX_REGNO_REG_SET (num_regs, new_p, renumber_p);
+
+  reg_n_max = num_regs;
+}
+
+\f
+/* This is the `regscan' pass of the compiler, run just before cse
+   and again just before loop.
 
-/* Record the number of registers we used when we allocated the above two
-   tables.  If we are called again with more than this, we must re-allocate
-   the tables.  */
+   It finds the first and last use of each pseudo-register
+   and records them in the vectors regno_first_uid, regno_last_uid
+   and counts the number of sets in the vector reg_n_sets.
 
-static int highest_regno_in_uid_map;
+   REPEAT is nonzero the second time this is called.  */
 
 /* Maximum number of parallel sets and clobbers in any insn in this fn.
-   Always at least 3, since the combiner could put that many togetherm
+   Always at least 3, since the combiner could put that many together
    and we want this to remain correct for all the remaining passes.  */
 
 int max_parallel;
 
-void reg_scan_mark_refs ();
-
 void
 reg_scan (f, nregs, repeat)
      rtx f;
@@ -1526,25 +1850,7 @@ reg_scan (f, nregs, repeat)
 {
   register rtx insn;
 
-  if (!repeat || nregs > highest_regno_in_uid_map)
-    {
-      /* Leave some spare space in case more regs are allocated.  */
-      highest_regno_in_uid_map = nregs + nregs / 20;
-      regno_first_uid
-       = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
-      regno_last_uid
-       = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
-      regno_last_note_uid
-       = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
-      reg_n_sets
-       = (short *) oballoc (highest_regno_in_uid_map * sizeof (short));
-    }
-
-  bzero (regno_first_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (regno_last_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (regno_last_note_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (reg_n_sets, highest_regno_in_uid_map * sizeof (short));
-
+  allocate_reg_info (nregs, TRUE, FALSE);
   max_parallel = 3;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
@@ -1565,7 +1871,7 @@ reg_scan (f, nregs, repeat)
 /* X is the expression to scan.  INSN is the insn it appears in.
    NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.  */
 
-void
+static void
 reg_scan_mark_refs (x, insn, note_flag)
      rtx x;
      rtx insn;
@@ -1592,11 +1898,11 @@ reg_scan_mark_refs (x, insn, note_flag)
       {
        register int regno = REGNO (x);
 
-       regno_last_note_uid[regno] = INSN_UID (insn);
+       REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
        if (!note_flag)
-         regno_last_uid[regno] = INSN_UID (insn);
-       if (regno_first_uid[regno] == 0)
-         regno_first_uid[regno] = INSN_UID (insn);
+         REGNO_LAST_UID (regno) = INSN_UID (insn);
+       if (REGNO_FIRST_UID (regno) == 0)
+         REGNO_FIRST_UID (regno) = INSN_UID (insn);
       }
       break;
 
@@ -1621,7 +1927,7 @@ reg_scan_mark_refs (x, insn, note_flag)
        ;
 
       if (GET_CODE (dest) == REG)
-       reg_n_sets[REGNO (dest)]++;
+       REG_N_SETS (REGNO (dest))++;
 
       /* If this is setting a pseudo from another pseudo or the sum of a
         pseudo and a constant integer and the other pseudo is known to be
@@ -1637,6 +1943,12 @@ reg_scan_mark_refs (x, insn, note_flag)
 
       if (GET_CODE (SET_DEST (x)) == REG
          && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+         /* If the destination pseudo is set more than once, then other
+            sets might not be to a pointer value (consider access to a
+            union in two threads of control in the presense of global
+            optimizations).  So only set REGNO_POINTER_FLAG on the destination
+            pseudo if this is the only set of that pseudo.  */
+         && REG_N_SETS (REGNO (SET_DEST (x))) == 1
          && ! REG_USERVAR_P (SET_DEST (x))
          && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
          && ((GET_CODE (SET_SRC (x)) == REG
@@ -1664,7 +1976,7 @@ reg_scan_mark_refs (x, insn, note_flag)
                      || GET_CODE (XEXP (note, 0)) == LABEL_REF))))
        REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     default:
       {
@@ -1731,3 +2043,17 @@ reg_classes_intersect_p (c1, c2)
   return 0;
 }
 
+/* Release any memory allocated by register sets.  */
+
+void
+regset_release_memory ()
+{
+  if (basic_block_live_at_start)
+    {
+      free_regset_vector (basic_block_live_at_start, n_basic_blocks);
+      basic_block_live_at_start = 0;
+    }
+
+  FREE_REG_SET (regs_live_at_setjmp);
+  bitmap_release_memory ();
+}