OSDN Git Service

* regclass.c (record_reg_classes): Correctly handle 'p' constraint.
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 3beac27..9faf8ab 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-98, 1999 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,19 @@ 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
+static void init_reg_sets_1    PROTO((void));
+static void init_reg_modes     PROTO((void));
 
 /* 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)
@@ -57,7 +59,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* Indexed by hard register number, contains 1 for registers
    that are fixed use (stack pointer, pc, frame pointer, etc.).
    These are the registers that cannot be used to allocate
-   a pseudo reg whose life does not cross calls.  */
+   a pseudo reg for general use.  */
 
 char fixed_regs[FIRST_PSEUDO_REGISTER];
 
@@ -72,7 +74,8 @@ static char initial_fixed_regs[] = FIXED_REGISTERS;
 /* Indexed by hard register number, contains 1 for registers
    that are fixed use or are clobbered by function calls.
    These are the registers that cannot be used to allocate
-   a pseudo reg whose life crosses calls.  */
+   a pseudo reg whose life crosses calls unless we are able
+   to save/restore them across the calls.  */
 
 char call_used_regs[FIRST_PSEUDO_REGISTER];
 
@@ -80,15 +83,17 @@ 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;
   
 /* Indexed by hard register number, contains 1 for registers that are
-   fixed use -- i.e. in fixed_regs -- or a function value return register
-   or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM.  These are the
-   registers that cannot hold quantities across calls even if we are
-   willing to save and restore them.  */
+   fixed use or call used registers that cannot hold quantities across
+   calls even if we are willing to save and restore them.  call fixed
+   registers are a subset of call used registers.  */
 
 char call_fixed_regs[FIRST_PSEUDO_REGISTER];
 
@@ -152,14 +157,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 +188,29 @@ 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 */
+
+/* Linked list of reg_info structures allocated for reg_n_info array.
+   Grouping all of the allocated structures together in one lump
+   means only one call to bzero to clear them, rather than n smaller
+   calls.  */
+struct reg_info_data {
+  struct reg_info_data *next;  /* next set of reg_info structures */
+  size_t min_index;            /* minimum index # */
+  size_t max_index;            /* maximum index # */
+  char used_p;                 /* non-zero if this has been used previously */
+  reg_info data[1];            /* beginning of the reg_info data */
+};
+
+static struct reg_info_data *reg_info_head;
+
+
 /* Function called only once to initialize the above data on reg usage.
    Once this is done, various switches may override.  */
 
@@ -210,9 +236,28 @@ init_reg_sets ()
   bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);
   bzero (global_regs, sizeof global_regs);
 
+  /* 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
+     and the register classes to depend on target flags.  */
+
+#ifdef CONDITIONAL_REGISTER_USAGE
+  CONDITIONAL_REGISTER_USAGE;
+#endif
+
   /* 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 +358,31 @@ init_reg_sets ()
        }
     }
 
+  /* 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 +416,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,20 +572,32 @@ 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.  */
 
   if ((i = decode_reg_name (name)) >= 0)
     {
-      fixed_regs[i] = fixed;
-      call_used_regs[i] = call_used;
+      if ((i == STACK_POINTER_REGNUM
+#ifdef HARD_FRAME_POINTER_REGNUM
+          || i == HARD_FRAME_POINTER_REGNUM
+#else
+          || i == FRAME_POINTER_REGNUM
+#endif
+          )
+         && (fixed == 0 || call_used == 0))
+       {
+         static char* what_option[2][2] = {
+           { "call-saved", "call-used" },
+           { "no-such-option", "fixed" }};
+         
+         error ("can't use '%s' as a %s register", name, 
+                what_option[fixed][call_used]);
+       }
+      else
+       {
+         fixed_regs[i] = fixed;
+         call_used_regs[i] = call_used;
+       }
     }
   else
     {
@@ -471,6 +651,10 @@ struct costs
 
 static struct costs *costs;
 
+/* Initialized once, and used to initialize cost values for each insn.  */
+
+static struct costs init_cost;
+
 /* Record the same data by operand number, accumulated for each alternative
    in an insn.  The contribution to a pseudo is that of the minimum-cost
    alternative.  */
@@ -494,6 +678,10 @@ static char *prefclass;
 
 static char *altclass;
 
+/* Allocated buffers for prefclass and altclass. */
+static char *prefclass_buffer;
+static char *altclass_buffer;
+
 /* Record the depth of loops that we are in.  */
 
 static int loop_depth;
@@ -503,13 +691,16 @@ static int loop_depth;
 
 static int loop_cost;
 
+static rtx scan_one_insn       PROTO((rtx, int));
 static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
-                                      char **, rtx));
+                                      const 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));
-static auto_inc_dec_reg_p      PROTO((rtx, enum machine_mode));
-static void reg_scan_mark_refs PROTO((rtx, rtx, 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, 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.
@@ -526,6 +717,7 @@ reg_preferred_class (regno)
 
 enum reg_class
 reg_alternate_class (regno)
+     int regno;
 {
   if (prefclass == 0)
     return ALL_REGS;
@@ -533,15 +725,216 @@ reg_alternate_class (regno)
   return (enum reg_class) altclass[regno];
 }
 
-/* This prevents dump_flow_info from losing if called
-   before regclass is run.  */
+/* Initialize some global data for this pass.  */
 
 void
 regclass_init ()
 {
+  int i;
+
+  init_cost.mem_cost = 10000;
+  for (i = 0; i < N_REG_CLASSES; i++)
+    init_cost.cost[i] = 10000;
+
+  /* This prevents dump_flow_info from losing if called
+     before regclass is run.  */
   prefclass = 0;
 }
 \f
+/* Subroutine of regclass, processes one insn INSN.  Scan it and record each
+   time it would save code to put a certain register in a certain class.
+   PASS, when nonzero, inhibits some optimizations which need only be done
+   once.
+   Return the last insn processed, so that the scan can be continued from
+   there.  */
+
+static rtx
+scan_one_insn (insn, pass)
+     rtx insn;
+     int pass;
+{
+  enum rtx_code code = GET_CODE (insn);
+  enum rtx_code pat_code;
+  const char *constraints[MAX_RECOG_OPERANDS];
+  enum machine_mode modes[MAX_RECOG_OPERANDS];
+  rtx set, note;
+  int i, j;
+
+  /* Show that an insn inside a loop is likely to be executed three
+     times more than insns outside a loop.  This is much more aggressive
+     than the assumptions made elsewhere and is being tried as an
+     experiment.  */
+
+  if (code == NOTE)
+    {
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+       loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));
+      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+       loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));
+
+      return insn;
+    }
+
+  if (GET_RTX_CLASS (code) != 'i')
+    return insn;
+
+  pat_code = GET_CODE (PATTERN (insn));
+  if (pat_code == USE
+      || pat_code == CLOBBER
+      || pat_code == ASM_INPUT
+      || pat_code == ADDR_VEC
+      || pat_code == ADDR_DIFF_VEC)
+    return insn;
+
+  set = single_set (insn);
+  extract_insn (insn);
+
+  for (i = 0; i < recog_n_operands; i++)
+    {
+      constraints[i] = recog_constraints[i];
+      modes[i] = recog_operand_mode[i];
+    }
+
+  /* If this insn loads a parameter from its stack slot, then
+     it represents a savings, rather than a cost, if the
+     parameter is stored in memory.  Record this fact.  */
+
+  if (set != 0 && GET_CODE (SET_DEST (set)) == REG
+      && GET_CODE (SET_SRC (set)) == MEM
+      && (note = find_reg_note (insn, REG_EQUIV,
+                               NULL_RTX)) != 0
+      && GET_CODE (XEXP (note, 0)) == MEM)
+    {
+      costs[REGNO (SET_DEST (set))].mem_cost
+       -= (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);
+      return insn;
+    }
+
+  /* Improve handling of two-address insns such as
+     (set X (ashift CONST Y)) where CONST must be made to
+     match X. Change it into two insns: (set X CONST)
+     (set X (ashift X Y)).  If we left this for reloading, it
+     would probably get three insns because X and Y might go
+     in the same place. This prevents X and Y from receiving
+     the same hard reg.
+
+     We can only do this if the modes of operands 0 and 1
+     (which might not be the same) are tieable and we only need
+     do this during our first pass.  */
+
+  if (pass == 0 && optimize
+      && recog_n_operands >= 3
+      && recog_constraints[1][0] == '0'
+      && recog_constraints[1][1] == 0
+      && CONSTANT_P (recog_operand[1])
+      && ! rtx_equal_p (recog_operand[0], recog_operand[1])
+      && ! rtx_equal_p (recog_operand[0], recog_operand[2])
+      && GET_CODE (recog_operand[0]) == REG
+      && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
+                         recog_operand_mode[1]))
+    {
+      rtx previnsn = prev_real_insn (insn);
+      rtx dest
+       = gen_lowpart (recog_operand_mode[1],
+                      recog_operand[0]);
+      rtx newinsn
+       = emit_insn_before (gen_move_insn (dest,
+                                          recog_operand[1]),
+                           insn);
+
+      /* If this insn was the start of a basic block,
+        include the new insn in that block.
+        We need not check for code_label here;
+        while a basic block can start with a code_label,
+        INSN could not be at the beginning of that block.  */
+      if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
+       {
+         int b;
+         for (b = 0; b < n_basic_blocks; b++)
+           if (insn == BLOCK_HEAD (b))
+             BLOCK_HEAD (b) = newinsn;
+       }
+
+      /* 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 = recog_n_dups - 1; i >= 0; i--)
+       if (recog_dup_num[i] == 1)
+         *recog_dup_loc[i] = recog_operand[0];
+
+      return PREV_INSN (newinsn);
+    }
+
+  /* If we get here, we are set up to record the costs of all the
+     operands for this insn.  Start by initializing the costs.
+     Then handle any address registers.  Finally record the desired
+     classes for any pseudos, doing it twice if some pair of
+     operands are commutative.  */
+            
+  for (i = 0; i < recog_n_operands; i++)
+    {
+      op_costs[i] = init_cost;
+
+      if (GET_CODE (recog_operand[i]) == SUBREG)
+       recog_operand[i] = SUBREG_REG (recog_operand[i]);
+
+      if (GET_CODE (recog_operand[i]) == MEM)
+       record_address_regs (XEXP (recog_operand[i], 0),
+                            BASE_REG_CLASS, loop_cost * 2);
+      else if (constraints[i][0] == 'p')
+       record_address_regs (recog_operand[i],
+                            BASE_REG_CLASS, loop_cost * 2);
+    }
+
+  /* Check for commutative in a separate loop so everything will
+     have been initialized.  We must do this even if one operand
+     is a constant--see addsi3 in m68k.md.  */
+
+  for (i = 0; i < recog_n_operands - 1; i++)
+    if (constraints[i][0] == '%')
+      {
+       const char *xconstraints[MAX_RECOG_OPERANDS];
+       int j;
+
+       /* Handle commutative operands by swapping the constraints.
+          We assume the modes are the same.  */
+
+       for (j = 0; j < recog_n_operands; j++)
+         xconstraints[j] = constraints[j];
+
+       xconstraints[i] = constraints[i+1];
+       xconstraints[i+1] = constraints[i];
+       record_reg_classes (recog_n_alternatives, recog_n_operands,
+                           recog_operand, modes, xconstraints,
+                           insn);
+      }
+
+  record_reg_classes (recog_n_alternatives, recog_n_operands, recog_operand,
+                     modes, constraints, insn);
+
+  /* Now add the cost for each operand to the total costs for
+     its register.  */
+
+  for (i = 0; i < recog_n_operands; i++)
+    if (GET_CODE (recog_operand[i]) == REG
+       && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
+      {
+       int regno = REGNO (recog_operand[i]);
+       struct costs *p = &costs[regno], *q = &op_costs[i];
+
+       p->mem_cost += q->mem_cost * loop_cost;
+       for (j = 0; j < N_REG_CLASSES; j++)
+         p->cost[j] += q->cost[j] * loop_cost;
+      }
+
+  return insn;
+}
+
 /* This is a pass of the compiler that scans all instructions
    and calculates the preferred class for each pseudo-register.
    This information can be accessed later by calling `reg_preferred_class'.
@@ -554,14 +947,12 @@ regclass (f, nregs)
 {
 #ifdef REGISTER_CONSTRAINTS
   register rtx insn;
-  register int i, j;
-  struct costs init_cost;
-  rtx set;
+  register int i;
   int pass;
 
   init_recog ();
 
-  costs = (struct costs *) alloca (nregs * sizeof (struct costs));
+  costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 
@@ -574,8 +965,9 @@ 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;
+      register int j;
 
       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
        if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
@@ -594,6 +986,10 @@ regclass (f, nregs)
                     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)
@@ -602,6 +998,7 @@ regclass (f, nregs)
                       || (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;
@@ -610,10 +1007,6 @@ regclass (f, nregs)
     }
 #endif /* FORBIDDEN_INC_DEC_CLASSES */
 
-  init_cost.mem_cost = 10000;
-  for (i = 0; i < N_REG_CLASSES; i++)
-    init_cost.cost[i] = 10000;
-
   /* Normally we scan the insns once and determine the best class to use for
      each register.  However, if -fexpensive_optimizations are on, we do so
      twice, the second time using the tentative best classes to guide the
@@ -623,7 +1016,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);
@@ -636,198 +1029,9 @@ regclass (f, nregs)
 
       for (insn = f; insn; insn = NEXT_INSN (insn))
        {
-         char *constraints[MAX_RECOG_OPERANDS];
-         enum machine_mode modes[MAX_RECOG_OPERANDS];
-         int nalternatives;
-         int noperands;
-
-         /* Show that an insn inside a loop is likely to be executed three
-            times more than insns outside a loop.  This is much more aggressive
-            than the assumptions made elsewhere and is being tried as an
-            experiment.  */
-
-         if (GET_CODE (insn) == NOTE
-             && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
-           loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5));
-         else if (GET_CODE (insn) == NOTE
-                  && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
-           loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5));
-
-         else if ((GET_CODE (insn) == INSN
-                   && GET_CODE (PATTERN (insn)) != USE
-                   && GET_CODE (PATTERN (insn)) != CLOBBER
-                   && GET_CODE (PATTERN (insn)) != ASM_INPUT)
-                  || (GET_CODE (insn) == JUMP_INSN
-                      && GET_CODE (PATTERN (insn)) != ADDR_VEC
-                      && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
-                  || GET_CODE (insn) == CALL_INSN)
-           {
-             if (GET_CODE (insn) == INSN
-                 && (noperands = asm_noperands (PATTERN (insn))) >= 0)
-               {
-                 decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
-                                      constraints, modes);
-                 nalternatives = (noperands == 0 ? 0
-                                  : n_occurrences (',', constraints[0]) + 1);
-               }
-             else
-               {
-                 int insn_code_number = recog_memoized (insn);
-                 rtx note;
-
-                 set = single_set (insn);
-                 insn_extract (insn);
-
-                 nalternatives = insn_n_alternatives[insn_code_number];
-                 noperands = insn_n_operands[insn_code_number];
-
-                 /* If this insn loads a parameter from its stack slot, then
-                    it represents a savings, rather than a cost, if the
-                    parameter is stored in memory.  Record this fact.  */
-
-                 if (set != 0 && GET_CODE (SET_DEST (set)) == REG
-                     && GET_CODE (SET_SRC (set)) == MEM
-                     && (note = find_reg_note (insn, REG_EQUIV,
-                                               NULL_RTX)) != 0
-                     && GET_CODE (XEXP (note, 0)) == MEM)
-                   {
-                     costs[REGNO (SET_DEST (set))].mem_cost
-                       -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)))
-                           * loop_cost);
-                     record_address_regs (XEXP (SET_SRC (set), 0),
-                                          BASE_REG_CLASS, loop_cost * 2);
-                     continue;
-                   }
-             
-                 /* Improve handling of two-address insns such as
-                    (set X (ashift CONST Y)) where CONST must be made to
-                    match X. Change it into two insns: (set X CONST)
-                    (set X (ashift X Y)).  If we left this for reloading, it
-                    would probably get three insns because X and Y might go
-                    in the same place. This prevents X and Y from receiving
-                    the same hard reg.
-
-                    We can only do this if the modes of operands 0 and 1
-                    (which might not be the same) are tieable and we only need
-                    do this during our first pass.  */
-
-                 if (pass == 0 && optimize
-                     && noperands >= 3
-                     && insn_operand_constraint[insn_code_number][1][0] == '0'
-                     && insn_operand_constraint[insn_code_number][1][1] == 0
-                     && CONSTANT_P (recog_operand[1])
-                     && ! rtx_equal_p (recog_operand[0], recog_operand[1])
-                     && ! rtx_equal_p (recog_operand[0], recog_operand[2])
-                     && GET_CODE (recog_operand[0]) == REG
-                     && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
-                                         insn_operand_mode[insn_code_number][1]))
-                   {
-                     rtx previnsn = prev_real_insn (insn);
-                     rtx dest
-                       = gen_lowpart (insn_operand_mode[insn_code_number][1],
-                                      recog_operand[0]);
-                     rtx newinsn
-                       = emit_insn_before (gen_move_insn (dest,
-                                                          recog_operand[1]),
-                                           insn);
-
-                     /* If this insn was the start of a basic block,
-                        include the new insn in that block.
-                        We need not check for code_label here;
-                        while a basic block can start with a code_label,
-                        INSN could not be at the beginning of that block.  */
-                     if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
-                       {
-                         int b;
-                         for (b = 0; b < n_basic_blocks; b++)
-                           if (insn == basic_block_head[b])
-                             basic_block_head[b] = newinsn;
-                       }
-
-                     /* 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--)
-                       if (recog_dup_num[i] == 1)
-                         *recog_dup_loc[i] = recog_operand[0];
-
-                     insn = PREV_INSN (newinsn);
-                     continue;
-                   }
-
-                 for (i = 0; i < noperands; i++)
-                   {
-                     constraints[i]
-                       = insn_operand_constraint[insn_code_number][i];
-                     modes[i] = insn_operand_mode[insn_code_number][i];
-                   }
-               }
-
-             /* If we get here, we are set up to record the costs of all the
-                operands for this insn.  Start by initializing the costs.
-                Then handle any address registers.  Finally record the desired
-                classes for any pseudos, doing it twice if some pair of
-                operands are commutative.  */
-            
-             for (i = 0; i < noperands; i++)
-               {
-                 op_costs[i] = init_cost;
-
-                 if (GET_CODE (recog_operand[i]) == SUBREG)
-                   recog_operand[i] = SUBREG_REG (recog_operand[i]);
-
-                 if (GET_CODE (recog_operand[i]) == MEM)
-                   record_address_regs (XEXP (recog_operand[i], 0),
-                                        BASE_REG_CLASS, loop_cost * 2);
-                 else if (constraints[i][0] == 'p')
-                   record_address_regs (recog_operand[i],
-                                        BASE_REG_CLASS, loop_cost * 2);
-               }
-
-             /* Check for commutative in a separate loop so everything will
-                have been initialized.  We must do this even if one operand
-                is a constant--see addsi3 in m68k.md.  */
-             
-             for (i = 0; i < noperands - 1; i++)
-               if (constraints[i][0] == '%')
-                 {
-                   char *xconstraints[MAX_RECOG_OPERANDS];
-                   int j;
-
-                   /* Handle commutative operands by swapping the constraints.
-                      We assume the modes are the same.  */
-
-                   for (j = 0; j < noperands; j++)
-                     xconstraints[j] = constraints[j];
-
-                   xconstraints[i] = constraints[i+1];
-                   xconstraints[i+1] = constraints[i];
-                   record_reg_classes (nalternatives, noperands,
-                                       recog_operand, modes, xconstraints,
-                                       insn);
-                 }
-
-             record_reg_classes (nalternatives, noperands, recog_operand,
-                                 modes, constraints, insn);
-
-             /* Now add the cost for each operand to the total costs for
-                its register.  */
-
-             for (i = 0; i < noperands; i++)
-               if (GET_CODE (recog_operand[i]) == REG
-                   && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
-                 {
-                   int regno = REGNO (recog_operand[i]);
-                   struct costs *p = &costs[regno], *q = &op_costs[i];
-
-                   p->mem_cost += q->mem_cost * loop_cost;
-                   for (j = 0; j < N_REG_CLASSES; j++)
-                     p->cost[j] += q->cost[j] * loop_cost;
-                 }
-           }
+         insn = scan_one_insn (insn, pass);
        }
-
+      
       /* Now for each register look at how desirable each class is
         and find which class is preferred.  Store that in
         `prefclass[REGNO]'.  Record in `altclass[REGNO]' the largest register
@@ -835,8 +1039,8 @@ regclass (f, nregs)
     
       if (pass == 0)
        {
-         prefclass = (char *) oballoc (nregs);
-         altclass = (char *) oballoc (nregs);
+         prefclass = prefclass_buffer;
+         altclass = altclass_buffer;
        }
 
       for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
@@ -888,7 +1092,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;
@@ -896,6 +1100,8 @@ regclass (f, nregs)
        }
     }
 #endif /* REGISTER_CONSTRAINTS */
+
+  free (costs);
 }
 \f
 #ifdef REGISTER_CONSTRAINTS
@@ -930,17 +1136,12 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
      int n_ops;
      rtx *ops;
      enum machine_mode *modes;
-     char **constraints;
+     const char **constraints;
      rtx insn;
 {
   int alt;
-  enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
   int i, j;
-
-  /* By default, each operand is an input operand.  */
-
-  for (i = 0; i < n_ops; i++)
-    op_types[i] = OP_READ;
+  rtx set;
 
   /* Process each alternative, each time minimizing an operand's cost with
      the cost for each operand in that alternative.  */
@@ -955,12 +1156,16 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
       for (i = 0; i < n_ops; i++)
        {
-         char *p = constraints[i];
+         const char *p = constraints[i];
          rtx op = ops[i];
          enum machine_mode mode = modes[i];
+         int allows_addr = 0;
          int allows_mem = 0;
          int win = 0;
-         char c;
+         unsigned char c;
+
+         /* Initially show we know nothing about the register class.  */
+         classes[i] = NO_REGS;
 
          /* If this operand has no constraints at all, we can conclude 
             nothing about it since anything is valid.  */
@@ -973,12 +1178,13 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              continue;
            }
 
-         if (*p == '%')
-           p++;
-
          /* If this alternative is only relevant when this operand
             matches a previous operand, we do different things depending
-            on whether this operand is a pseudo-reg or not.  */
+            on whether this operand is a pseudo-reg or not.  We must process
+            any modifiers for the operand before we can make this test.  */
+
+         while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
+           p++;
 
          if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
            {
@@ -1044,28 +1250,24 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
             any of the constraints.  Collect the valid register classes
             and see if this operand accepts memory.  */
 
-         classes[i] = NO_REGS;
          while (*p && (c = *p++) != ',')
            switch (c)
              {
-             case '=':
-               op_types[i] = OP_WRITE;
-               break;
-
-             case '+':
-               op_types[i] = OP_READ_WRITE;
-               break;
-
              case '*':
                /* Ignore the next letter for this pass.  */
                p++;
                break;
 
-             case '%':
-             case '?':  case '!':  case '#':
-             case '&':
+             case '?':
+               alt_cost += 2;
+             case '!':  case '#':  case '&':
              case '0':  case '1':  case '2':  case '3':  case '4':
+             case '5':  case '6':  case '7':  case '8':  case '9':
+               break;
+
              case 'p':
+               allows_addr = 1;
+               win = address_operand (op, GET_MODE (op));
                break;
 
              case 'm':  case 'o':  case 'V':
@@ -1091,12 +1293,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;
@@ -1194,7 +1398,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
          if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
            {
              if (classes[i] == NO_REGS)
-               alt_fail = 1;
+               {
+                 if (! allows_addr)
+                   alt_fail = 1;
+               }
              else
                {
                  struct costs *pp = &this_op_costs[i];
@@ -1206,7 +1413,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
@@ -1215,7 +1423,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
                  if (prefclass)
                    alt_cost
-                     += may_move_cost[prefclass[REGNO (op)]][(int) classes[i]];
+                     += may_move_cost[(unsigned char)prefclass[REGNO (op)]][(int) classes[i]];
                }
            }
 
@@ -1233,18 +1441,18 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
          else if (classes[i] != NO_REGS)
            {
-             if (op_types[i] != OP_WRITE)
+             if (recog_op_type[i] != OP_OUT)
                alt_cost += copy_cost (op, mode, classes[i], 1);
 
-             if (op_types[i] != OP_READ)
+             if (recog_op_type[i] != OP_IN)
                alt_cost += copy_cost (op, mode, classes[i], 0);
            }
 
          /* The only other way this alternative can be used is if this is a
             constant that could be placed into memory.  */
 
-         else if (CONSTANT_P (op) && allows_mem)
-           alt_cost += MEMORY_MOVE_COST (mode);
+         else if (CONSTANT_P (op) && (allows_addr || allows_mem))
+           alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
          else
            alt_fail = 1;
        }
@@ -1260,7 +1468,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
            && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
          {
            struct costs *pp = &op_costs[i], *qq = &this_op_costs[i];
-           int scale = 1 + (op_types[i] == OP_READ_WRITE);
+           int scale = 1 + (recog_op_type[i] == OP_INOUT);
 
            pp->mem_cost = MIN (pp->mem_cost,
                                (qq->mem_cost + alt_cost) * scale);
@@ -1270,6 +1478,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[(unsigned char)prefclass[regno]]
+                 == CLASS_MAX_NREGS (prefclass[regno], mode)))
+           op_costs[i].cost[(unsigned char)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
@@ -1284,7 +1532,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.  */
@@ -1321,7 +1571,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];
@@ -1413,38 +1663,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 (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_POINTER_FLAG (REGNO (arg0)))
+                && 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;
 
@@ -1471,7 +1737,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;
@@ -1494,30 +1760,26 @@ record_address_regs (x, class, scale)
 /* Return 1 if REG is valid as an auto-increment memory reference
    to an object of MODE.  */
 
-static 
+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)))
+  if (HAVE_POST_INCREMENT
+      && 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)))
+  if (HAVE_POST_DECREMENT
+      && 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)))
+  if (HAVE_PRE_INCREMENT
+      && 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)))
+  if (HAVE_PRE_DECREMENT
+      && memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
     return 1;
-#endif
 
   return 0;
 }
@@ -1525,38 +1787,167 @@ auto_inc_dec_reg_p (reg, mode)
 
 #endif /* REGISTER_CONSTRAINTS */
 \f
-/* This is the `regscan' pass of the compiler, run just before cse
-   and again just before loop.
+static short *renumber = (short *)0;
+static size_t regno_allocated = 0;
 
-   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.
+/* 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.  */
 
-   REPEAT is nonzero the second time this is called.  */
+void
+allocate_reg_info (num_regs, new_p, renumber_p)
+     size_t num_regs;
+     int new_p;
+     int renumber_p;
+{
+  size_t size_info;
+  size_t size_renumber;
+  size_t min = (new_p) ? 0 : reg_n_max;
+  struct reg_info_data *reg_data;
+  struct reg_info_data *reg_next;
+
+  if (num_regs > regno_allocated)
+    {
+      size_t old_allocated = regno_allocated;
+
+      regno_allocated = num_regs + (num_regs / 20);    /* add some slop space */
+      size_renumber = regno_allocated * sizeof (short);
+
+      if (!reg_n_info)
+       {
+         VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info");
+         renumber = (short *) xmalloc (size_renumber);
+         prefclass_buffer = (char *) xmalloc (regno_allocated);
+         altclass_buffer = (char *) xmalloc (regno_allocated);
+       }
+
+      else
+       {
+         VARRAY_GROW (reg_n_info, regno_allocated);
+
+         if (new_p)            /* if we're zapping everything, no need to realloc */
+           {
+             free ((char *)renumber);
+             free ((char *)prefclass_buffer);
+             free ((char *)altclass_buffer);
+             renumber = (short *) xmalloc (size_renumber);
+             prefclass_buffer = (char *) xmalloc (regno_allocated);
+             altclass_buffer = (char *) xmalloc (regno_allocated);
+           }
+
+         else
+           {
+             renumber = (short *) xrealloc ((char *)renumber, size_renumber);
+             prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer,
+                                                   regno_allocated);
+
+             altclass_buffer = (char *) xrealloc ((char *)altclass_buffer,
+                                                  regno_allocated);
+           }
+       }
 
-/* Indexed by pseudo register number, gives uid of first insn using the reg
-   (as of the time reg_scan is called).  */
+      size_info = (regno_allocated - old_allocated) * sizeof (reg_info)
+       + sizeof (struct reg_info_data) - sizeof (reg_info);
+      reg_data = (struct reg_info_data *) xcalloc (size_info, 1);
+      reg_data->min_index = old_allocated;
+      reg_data->max_index = regno_allocated - 1;
+      reg_data->next = reg_info_head;
+      reg_info_head = reg_data;
+    }
 
-int *regno_first_uid;
+  reg_n_max = num_regs;
+  if (min < num_regs)
+    {
+      /* Loop through each of the segments allocated for the actual
+        reg_info pages, and set up the pointers, zero the pages, etc.  */
+      for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+       {
+         size_t min_index = reg_data->min_index;
+         size_t max_index = reg_data->max_index;
 
-/* Indexed by pseudo register number, gives uid of last insn using the reg
-   (as of the time reg_scan is called).  */
+         reg_next = reg_data->next;
+         if (min <= max_index)
+           {
+             size_t max = max_index;
+             size_t local_min = min - min_index;
+             size_t i;
+
+             if (min < min_index)
+               local_min = 0;
+             if (!reg_data->used_p)    /* page just allocated with calloc */
+               reg_data->used_p = 1;   /* no need to zero */
+             else
+               bzero ((char *) &reg_data->data[local_min],
+                      sizeof (reg_info) * (max - min_index - local_min + 1));
 
-int *regno_last_uid;
+             for (i = min_index+local_min; i <= max; i++)
+               {
+                 VARRAY_REG (reg_n_info, i) = &reg_data->data[i-min_index];
+                 REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
+                 renumber[i] = -1;
+                 prefclass_buffer[i] = (char) NO_REGS;
+                 altclass_buffer[i] = (char) NO_REGS;
+               }
+           }
+       }
+    }
+
+  /* If {pref,alt}class have already been allocated, update the pointers to
+     the newly realloced ones.  */
+  if (prefclass)
+    {
+      prefclass = prefclass_buffer;
+      altclass = altclass_buffer;
+    }
+
+  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);
+}
+
+/* Free up the space allocated by allocate_reg_info.  */
+void
+free_reg_info ()
+{
+  if (reg_n_info)
+    {
+      struct reg_info_data *reg_data;
+      struct reg_info_data *reg_next;
 
-/* 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).  */
+      VARRAY_FREE (reg_n_info);
+      for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+       {
+         reg_next = reg_data->next;
+         free ((char *)reg_data);
+       }
 
-int *regno_last_note_uid;
+      free (prefclass_buffer);
+      free (altclass_buffer);
+      prefclass_buffer = (char *)0;
+      altclass_buffer = (char *)0;
+      reg_info_head = (struct reg_info_data *)0;
+      renumber = (short *)0;
+    }
+  regno_allocated = 0;
+  reg_n_max = 0;
+}
+\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;
@@ -1569,25 +1960,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))
@@ -1598,30 +1971,64 @@ reg_scan (f, nregs, repeat)
        if (GET_CODE (PATTERN (insn)) == PARALLEL
            && XVECLEN (PATTERN (insn), 0) > max_parallel)
          max_parallel = XVECLEN (PATTERN (insn), 0);
-       reg_scan_mark_refs (PATTERN (insn), insn, 0);
+       reg_scan_mark_refs (PATTERN (insn), insn, 0, 0);
+
+       if (REG_NOTES (insn))
+         reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
+      }
+}
+
+/* Update 'regscan' information by looking at the insns
+   from FIRST to LAST.  Some new REGs have been created,
+   and any REG with number greater than OLD_MAX_REGNO is
+   such a REG.  We only update information for those.  */
+
+void
+reg_scan_update(first, last, old_max_regno)
+     rtx first;
+     rtx last;
+     int old_max_regno;
+{
+  register rtx insn;
+
+  allocate_reg_info (max_reg_num (), FALSE, FALSE);
+
+  for (insn = first; insn != last; insn = NEXT_INSN (insn))
+    if (GET_CODE (insn) == INSN
+       || GET_CODE (insn) == CALL_INSN
+       || GET_CODE (insn) == JUMP_INSN)
+      {
+       if (GET_CODE (PATTERN (insn)) == PARALLEL
+           && XVECLEN (PATTERN (insn), 0) > max_parallel)
+         max_parallel = XVECLEN (PATTERN (insn), 0);
+       reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno);
 
        if (REG_NOTES (insn))
-         reg_scan_mark_refs (REG_NOTES (insn), insn, 1);
+         reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno);
       }
 }
 
 /* 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.  */
+   NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.
+   We should only record information for REGs with numbers
+   greater than or equal to MIN_REGNO.  */
 
 static void
-reg_scan_mark_refs (x, insn, note_flag)
+reg_scan_mark_refs (x, insn, note_flag, min_regno)
      rtx x;
      rtx insn;
      int note_flag;
+     int min_regno;
 {
-  register enum rtx_code code = GET_CODE (x);
+  register enum rtx_code code;
   register rtx dest;
   register rtx note;
 
+  code = GET_CODE (x);
   switch (code)
     {
-    case CONST_INT:
     case CONST:
+    case CONST_INT:
     case CONST_DOUBLE:
     case CC0:
     case PC:
@@ -1635,24 +2042,27 @@ reg_scan_mark_refs (x, insn, note_flag)
       {
        register int regno = REGNO (x);
 
-       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);
+       if (regno >= min_regno)
+         {
+           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);
+         }
       }
       break;
 
     case EXPR_LIST:
       if (XEXP (x, 0))
-       reg_scan_mark_refs (XEXP (x, 0), insn, note_flag);
+       reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
       if (XEXP (x, 1))
-       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
       break;
 
     case INSN_LIST:
       if (XEXP (x, 1))
-       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
       break;
 
     case SET:
@@ -1663,8 +2073,9 @@ reg_scan_mark_refs (x, insn, note_flag)
           dest = XEXP (dest, 0))
        ;
 
-      if (GET_CODE (dest) == REG)
-       reg_n_sets[REGNO (dest)]++;
+      if (GET_CODE (dest) == REG
+         && REGNO (dest) >= min_regno)
+       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
@@ -1680,6 +2091,13 @@ reg_scan_mark_refs (x, insn, note_flag)
 
       if (GET_CODE (SET_DEST (x)) == REG
          && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+         && REGNO (SET_DEST (x)) >= min_regno
+         /* 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
@@ -1707,7 +2125,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:
       {
@@ -1716,12 +2134,12 @@ reg_scan_mark_refs (x, insn, note_flag)
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
          {
            if (fmt[i] == 'e')
-             reg_scan_mark_refs (XEXP (x, i), insn, note_flag);
+             reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
            else if (fmt[i] == 'E' && XVEC (x, i) != 0)
              {
                register int j;
                for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-                 reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag);
+                 reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
              }
          }
       }
@@ -1774,3 +2192,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 ();
+}