OSDN Git Service

update the sample output
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 489f824..c022b0a 100644 (file)
@@ -1,5 +1,6 @@
 /* Compute register class preferences for pseudo-registers.
-   Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
+   1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -26,23 +27,27 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "expr.h"
+#include "tm_p.h"
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "basic-block.h"
 #include "regs.h"
+#include "function.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
 #include "real.h"
 #include "toplev.h"
 #include "output.h"
+#include "ggc.h"
 
 #ifndef REGISTER_MOVE_COST
-#define REGISTER_MOVE_COST(x, y) 2
+#define REGISTER_MOVE_COST(m, x, y) 2
 #endif
 
-static void init_reg_sets_1    PROTO((void));
-static void init_reg_modes     PROTO((void));
+static void init_reg_sets_1    PARAMS ((void));
+static void init_reg_modes     PARAMS ((void));
 
 /* If we have auto-increment or auto-decrement and we can have secondary
    reloads, we are not allowed to use classes requiring secondary
@@ -111,10 +116,22 @@ int n_non_fixed_regs;
    and are also considered fixed.  */
 
 char global_regs[FIRST_PSEUDO_REGISTER];
-  
+
+/* Contains 1 for registers that are set or clobbered by calls.  */
+/* ??? Ideally, this would be just call_used_regs plus global_regs, but
+   for someone's bright idea to have call_used_regs strictly include
+   fixed_regs.  Which leaves us guessing as to the set of fixed_regs
+   that are actually preserved.  We know for sure that those associated
+   with the local stack frame are safe, but scant others.  */
+
+HARD_REG_SET regs_invalidated_by_call;
+
 /* Table of register numbers in the order in which to try to use them.  */
 #ifdef REG_ALLOC_ORDER
 int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;
+
+/* The inverse of reg_alloc_order.  */
+int inv_reg_alloc_order[FIRST_PSEUDO_REGISTER];
 #endif
 
 /* For each reg class, a HARD_REG_SET saying which registers are in it.  */
@@ -133,7 +150,7 @@ static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
 
 /* For each reg class, number of regs it contains.  */
 
-int reg_class_size[N_REG_CLASSES];
+unsigned int reg_class_size[N_REG_CLASSES];
 
 /* For each reg class, table listing all the containing classes.  */
 
@@ -153,9 +170,12 @@ enum reg_class reg_class_subunion[N_REG_CLASSES][N_REG_CLASSES];
 
 enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
 
-/* Array containing all of the register names */
+/* Array containing all of the register names.  Unless
+   DEBUG_REGISTER_NAMES is defined, use the copy in print-rtl.c.  */
 
-char *reg_names[] = REGISTER_NAMES;
+#ifdef DEBUG_REGISTER_NAMES
+const char * reg_names[] = REGISTER_NAMES;
+#endif
 
 /* 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
@@ -164,15 +184,24 @@ char *reg_names[] = REGISTER_NAMES;
 
 enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
 
+/* 1 if class does contain register of given mode.  */
+
+static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE];
+
 /* Maximum cost of moving from a register in one class to a register in
    another class.  Based on REGISTER_MOVE_COST.  */
 
-static int move_cost[N_REG_CLASSES][N_REG_CLASSES];
+static int move_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
 
 /* Similar, but here we don't have to move if the first index is a subset
    of the second so in that case the cost is zero.  */
 
-static int may_move_cost[N_REG_CLASSES][N_REG_CLASSES];
+static int may_move_in_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
+
+/* Similar, but here we don't have to move if the first index is a superset
+   of the second so in that case the cost is zero.  */
+
+static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 
@@ -188,6 +217,21 @@ static char *in_inc_dec;
 
 #endif /* FORBIDDEN_INC_DEC_CLASSES */
 
+#ifdef CLASS_CANNOT_CHANGE_MODE
+
+/* These are the classes containing only registers that can be used in
+   a SUBREG expression that changes the mode of the register in some
+   way that is illegal.  */
+
+static int class_can_change_mode[N_REG_CLASSES];
+
+/* Registers, including pseudos, which change modes in some way that
+   is illegal.  */
+
+static regset reg_changes_mode;
+
+#endif /* CLASS_CANNOT_CHANGE_MODE */
+
 #ifdef HAVE_SECONDARY_RELOADS
 
 /* Sample MEM values for use by memory_move_secondary_cost.  */
@@ -210,6 +254,11 @@ struct reg_info_data {
 
 static struct reg_info_data *reg_info_head;
 
+/* No more global register variables may be declared; true once
+   regclass has been initialized. */
+
+static int no_global_reg_vars = 0;
+
 
 /* Function called only once to initialize the above data on reg usage.
    Once this is done, various switches may override.  */
@@ -226,18 +275,24 @@ init_reg_sets ()
     {
       CLEAR_HARD_REG_SET (reg_class_contents[i]);
 
+      /* Note that we hard-code 32 here, not HOST_BITS_PER_INT.  */
       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
-       if (int_reg_class_contents[i][j / HOST_BITS_PER_INT]
-           & ((unsigned) 1 << (j % HOST_BITS_PER_INT)))
+       if (int_reg_class_contents[i][j / 32]
+           & ((unsigned) 1 << (j % 32)))
          SET_HARD_REG_BIT (reg_class_contents[i], j);
     }
 
-  bcopy (initial_fixed_regs, fixed_regs, sizeof fixed_regs);
-  bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);
-  bzero (global_regs, sizeof global_regs);
+  memcpy (fixed_regs, initial_fixed_regs, sizeof fixed_regs);
+  memcpy (call_used_regs, initial_call_used_regs, sizeof call_used_regs);
+  memset (global_regs, 0, sizeof global_regs);
 
   /* Do any additional initialization regsets may need */
   INIT_ONCE_REG_SET ();
+
+#ifdef REG_ALLOC_ORDER
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    inv_reg_alloc_order[reg_alloc_order[i]] = i;
+#endif
 }
 
 /* After switches have been processed, which perhaps alter
@@ -247,6 +302,8 @@ static void
 init_reg_sets_1 ()
 {
   register unsigned int i, j;
+  register unsigned int /* enum machine_mode */ m;
+  char allocatable_regs_of_mode [MAX_MACHINE_MODE];
 
   /* This macro allows the fixed or call-used registers
      and the register classes to depend on target flags.  */
@@ -257,7 +314,7 @@ init_reg_sets_1 ()
 
   /* Compute number of hard regs in each class.  */
 
-  bzero ((char *) reg_class_size, sizeof reg_class_size);
+  memset ((char *) reg_class_size, 0, 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))
@@ -363,8 +420,9 @@ init_reg_sets_1 ()
   CLEAR_HARD_REG_SET (fixed_reg_set);
   CLEAR_HARD_REG_SET (call_used_reg_set);
   CLEAR_HARD_REG_SET (call_fixed_reg_set);
+  CLEAR_HARD_REG_SET (regs_invalidated_by_call);
 
-  bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
+  memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs);
 
   n_non_fixed_regs = 0;
 
@@ -381,39 +439,120 @@ init_reg_sets_1 ()
        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);
+
+      /* There are a couple of fixed registers that we know are safe to
+        exclude from being clobbered by calls:
+
+        The frame pointer is always preserved across calls.  The arg pointer
+        is if it is fixed.  The stack pointer usually is, unless
+        RETURN_POPS_ARGS, in which case an explicit CLOBBER will be present.
+        If we are generating PIC code, the PIC offset table register is
+        preserved across calls, though the target can override that.  */
+        
+      if (i == STACK_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
+       ;
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+      else if (i == HARD_FRAME_POINTER_REGNUM)
+       ;
+#endif
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+      else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
+       ;
+#endif
+#ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+      else if (i == PIC_OFFSET_TABLE_REGNUM && flag_pic)
+       ;
+#endif
+      else if (call_used_regs[i] || global_regs[i])
+       SET_HARD_REG_BIT (regs_invalidated_by_call, i);
     }
 
+  memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
+  memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
+  for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
+    for (i = 0; i < N_REG_CLASSES; i++)
+      if (CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
+       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+         if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j)
+             && HARD_REGNO_MODE_OK (j, m))
+            {
+              contains_reg_of_mode [i][m] = 1;
+              allocatable_regs_of_mode [m] = 1;
+              break;
+            }
+
   /* Initialize the move cost table.  Find every subset of each class
      and take the maximum cost of moving any subset to any other.  */
 
-  for (i = 0; i < N_REG_CLASSES; i++)
-    for (j = 0; j < N_REG_CLASSES; j++)
+  for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
+    if (allocatable_regs_of_mode [m])
       {
-       int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j);
-       enum reg_class *p1, *p2;
-
-       for (p2 = &reg_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++)
-         if (*p2 != i)
-           cost = MAX (cost, REGISTER_MOVE_COST (i, *p2));
-
-       for (p1 = &reg_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++)
-         {
-           if (*p1 != j)
-             cost = MAX (cost, REGISTER_MOVE_COST (*p1, j));
-
-           for (p2 = &reg_class_subclasses[j][0];
-                *p2 != LIM_REG_CLASSES; p2++)
-             if (*p1 != *p2)
-               cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2));
-         }
-
-       move_cost[i][j] = cost;
-
-       if (reg_class_subset_p (i, j))
-         cost = 0;
+       for (i = 0; i < N_REG_CLASSES; i++)
+         if (contains_reg_of_mode [i][m])
+           for (j = 0; j < N_REG_CLASSES; j++)
+             {
+               int cost;
+               enum reg_class *p1, *p2;
+
+               if (!contains_reg_of_mode [j][m])
+                 {
+                   move_cost[m][i][j] = 65536;
+                   may_move_in_cost[m][i][j] = 65536;
+                   may_move_out_cost[m][i][j] = 65536;
+                 }
+               else
+                 {
+                   cost = i == j ? 2 : REGISTER_MOVE_COST (m, i, j);
+
+                   for (p2 = &reg_class_subclasses[j][0];
+                        *p2 != LIM_REG_CLASSES;
+                        p2++)
+                     if (*p2 != i && contains_reg_of_mode [*p2][m])
+                       cost = MAX (cost, move_cost [m][i][*p2]);
+
+                   for (p1 = &reg_class_subclasses[i][0];
+                        *p1 != LIM_REG_CLASSES;
+                        p1++)
+                     if (*p1 != j && contains_reg_of_mode [*p1][m])
+                       cost = MAX (cost, move_cost [m][*p1][j]);
+
+                   move_cost[m][i][j] = cost;
+
+                   if (reg_class_subset_p (i, j))
+                     may_move_in_cost[m][i][j] = 0;
+                   else
+                     may_move_in_cost[m][i][j] = cost;
+
+                   if (reg_class_subset_p (j, i))
+                     may_move_out_cost[m][i][j] = 0;
+                   else
+                     may_move_out_cost[m][i][j] = cost;
+                 }
+             }
+         else
+           for (j = 0; j < N_REG_CLASSES; j++)
+             {
+               move_cost[m][i][j] = 65536;
+               may_move_in_cost[m][i][j] = 65536;
+               may_move_out_cost[m][i][j] = 65536;
+             }
+      }
 
-       may_move_cost[i][j] = cost;
+#ifdef CLASS_CANNOT_CHANGE_MODE
+  {
+    HARD_REG_SET c;
+    COMPL_HARD_REG_SET (c, reg_class_contents[CLASS_CANNOT_CHANGE_MODE]);
+      
+    for (i = 0; i < N_REG_CLASSES; i++)
+      {
+       GO_IF_HARD_REG_SUBSET (reg_class_contents[i], c, ok_class);
+       class_can_change_mode [i] = 0;
+       continue;
+      ok_class:
+       class_can_change_mode [i] = 1;
       }
+    }
+#endif /* CLASS_CANNOT_CHANGE_MODE */
 }
 
 /* Compute the table of register modes.
@@ -456,8 +595,10 @@ init_regs ()
     /* 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);
+    ggc_add_rtx_root (top_of_stack, MAX_MACHINE_MODE);
   }
 #endif
 }
@@ -476,7 +617,9 @@ memory_move_secondary_cost (mode, class, 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];
+  /* mem may be unused even if the SECONDARY_ macros are defined. */
+  rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode];
+
 
   if (in)
     {
@@ -499,9 +642,9 @@ memory_move_secondary_cost (mode, class, in)
     return 0;
 
   if (in)
-    partial_cost = REGISTER_MOVE_COST (altclass, class);
+    partial_cost = REGISTER_MOVE_COST (mode, altclass, class);
   else
-    partial_cost = REGISTER_MOVE_COST (class, altclass);
+    partial_cost = REGISTER_MOVE_COST (mode, class, altclass);
 
   if (class == altclass)
     /* This isn't simply a copy-to-temporary situation.  Can't guess
@@ -524,9 +667,10 @@ memory_move_secondary_cost (mode, class, in)
 
 enum machine_mode
 choose_hard_reg_mode (regno, nregs)
-     int regno;
-     int nregs;
+     unsigned int regno ATTRIBUTE_UNUSED;
+     unsigned int nregs;
 {
+  unsigned int /* enum machine_mode */ m;
   enum machine_mode found_mode = VOIDmode, mode;
 
   /* We first look for the largest integer mode that can be validly
@@ -553,9 +697,14 @@ choose_hard_reg_mode (regno, nregs)
   if (found_mode != VOIDmode)
     return found_mode;
 
-  if (HARD_REGNO_NREGS (regno, CCmode) == nregs
-      && HARD_REGNO_MODE_OK (regno, CCmode))
-    return CCmode;
+  /* Iterate over all of the CCmodes.  */
+  for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m)
+    {
+      mode = (enum machine_mode) m;
+      if (HARD_REGNO_NREGS (regno, mode) == nregs
+         && HARD_REGNO_MODE_OK (regno, mode))
+       return mode;
+    }
 
   /* We can't find a mode valid for this register.  */
   return VOIDmode;
@@ -567,7 +716,7 @@ choose_hard_reg_mode (regno, nregs)
 
 void
 fix_register (name, fixed, call_used)
-     char *name;
+     const char *name;
      int fixed, call_used;
 {
   int i;
@@ -586,7 +735,7 @@ fix_register (name, fixed, call_used)
           )
          && (fixed == 0 || call_used == 0))
        {
-         static char* what_option[2][2] = {
+         static const char * const what_option[2][2] = {
            { "call-saved", "call-used" },
            { "no-such-option", "fixed" }};
          
@@ -611,6 +760,9 @@ void
 globalize_reg (i)
      int i;
 {
+  if (fixed_regs[i] == 0 && no_global_reg_vars)
+    error ("global register variable follows a function definition");
+
   if (global_regs[i])
     {
       warning ("register used for two global register variables");
@@ -647,6 +799,22 @@ struct costs
   int mem_cost;
 };
 
+/* Structure used to record preferrences of given pseudo.  */
+struct reg_pref
+{
+  /* (enum reg_class) prefclass is the preferred class.  */
+  char prefclass;
+
+  /* altclass is a register class that we should use for allocating
+     pseudo if no register in the preferred class is available.
+     If no register in this class is available, memory is preferred.
+
+     It might appear to be more general to have a bitmask of classes here,
+     but since it is recommended that there be a class corresponding to the
+     union of most major pair of classes, that generality is not required.  */
+  char altclass;
+};
+
 /* Record the cost of each class for each pseudo.  */
 
 static struct costs *costs;
@@ -655,53 +823,32 @@ static struct costs *costs;
 
 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.  */
-
-static struct costs op_costs[MAX_RECOG_OPERANDS];
-
-/* (enum reg_class) prefclass[R] is the preferred class for pseudo number R.
+/* Record preferrences of each pseudo.
    This is available after `regclass' is run.  */
 
-static char *prefclass;
-
-/* altclass[R] is a register class that we should use for allocating
-   pseudo number R if no register in the preferred class is available.
-   If no register in this class is available, memory is preferred.
+static struct reg_pref *reg_pref;
 
-   It might appear to be more general to have a bitmask of classes here,
-   but since it is recommended that there be a class corresponding to the
-   union of most major pair of classes, that generality is not required. 
-
-   This is available after `regclass' is run.  */
+/* Allocated buffers for reg_pref. */
 
-static char *altclass;
+static struct reg_pref *reg_pref_buffer;
 
-/* Allocated buffers for prefclass and altclass. */
-static char *prefclass_buffer;
-static char *altclass_buffer;
+/* Frequency of executions of current insn.  */
 
-/* Record the depth of loops that we are in.  */
+static int frequency;
 
-static int loop_depth;
-
-/* Account for the fact that insns within a loop are executed very commonly,
-   but don't keep doing this as loops go too deep.  */
-
-static int loop_cost;
-
-static int n_occurrences       PROTO((int, char *));
-static rtx scan_one_insn       PROTO((rtx, int));
-static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
-                                      char **, rtx));
-static int copy_cost           PROTO((rtx, enum machine_mode, 
+static rtx scan_one_insn       PARAMS ((rtx, int));
+static void record_operand_costs PARAMS ((rtx, struct costs *, struct reg_pref *));
+static void dump_regclass      PARAMS ((FILE *));
+static void record_reg_classes PARAMS ((int, int, rtx *, enum machine_mode *,
+                                      const char **, rtx,
+                                      struct costs *, struct reg_pref *));
+static int copy_cost           PARAMS ((rtx, enum machine_mode, 
                                       enum reg_class, int));
-static void record_address_regs        PROTO((rtx, enum reg_class, int));
+static void record_address_regs        PARAMS ((rtx, enum reg_class, int));
 #ifdef FORBIDDEN_INC_DEC_CLASSES
-static int auto_inc_dec_reg_p  PROTO((rtx, enum machine_mode));
+static int auto_inc_dec_reg_p  PARAMS ((rtx, enum machine_mode));
 #endif
-static void reg_scan_mark_refs PROTO((rtx, rtx, int, int));
+static void reg_scan_mark_refs PARAMS ((rtx, rtx, int, unsigned 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.
@@ -711,19 +858,19 @@ enum reg_class
 reg_preferred_class (regno)
      int regno;
 {
-  if (prefclass == 0)
+  if (reg_pref == 0)
     return GENERAL_REGS;
-  return (enum reg_class) prefclass[regno];
+  return (enum reg_class) reg_pref[regno].prefclass;
 }
 
 enum reg_class
 reg_alternate_class (regno)
      int regno;
 {
-  if (prefclass == 0)
+  if (reg_pref == 0)
     return ALL_REGS;
 
-  return (enum reg_class) altclass[regno];
+  return (enum reg_class) reg_pref[regno].altclass;
 }
 
 /* Initialize some global data for this pass.  */
@@ -739,21 +886,119 @@ regclass_init ()
 
   /* This prevents dump_flow_info from losing if called
      before regclass is run.  */
-  prefclass = 0;
+  reg_pref = NULL;
+
+  /* No more global register variables may be declared. */
+  no_global_reg_vars = 1;
 }
 \f
-/* Return the number of times character C occurs in string S.  */
-static int
-n_occurrences (c, s)
-     int c;
-     char *s;
+/* Dump register costs.  */
+static void
+dump_regclass (dump)
+     FILE *dump;
 {
-  int n = 0;
-  while (*s)
-    n += (*s++ == c);
-  return n;
+  static const char *const reg_class_names[] = REG_CLASS_NAMES;
+  int i;
+  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
+    {
+      int /* enum reg_class */ class;
+      if (REG_N_REFS (i))
+       {
+         fprintf (dump, "  Register %i costs:", i);
+         for (class = 0; class < (int) N_REG_CLASSES; class++)
+           if (contains_reg_of_mode [(enum reg_class) class][PSEUDO_REGNO_MODE (i)]
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+               && (!in_inc_dec[i]
+                   || !forbidden_inc_dec_class[(enum reg_class) class])
+#endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+               && (!REGNO_REG_SET_P (reg_changes_mode, i)
+                    || class_can_change_mode [(enum reg_class) class])
+#endif
+               )
+           fprintf (dump, " %s:%i", reg_class_names[class],
+                    costs[i].cost[(enum reg_class) class]);
+         fprintf (dump, " MEM:%i\n", costs[i].mem_cost);
+       }
+    }
 }
+\f
+
+/* Calculate the costs of insn operands.  */
+
+static void
+record_operand_costs (insn, op_costs, reg_pref)
+     rtx insn;
+     struct costs *op_costs;
+     struct reg_pref *reg_pref;
+{
+  const char *constraints[MAX_RECOG_OPERANDS];
+  enum machine_mode modes[MAX_RECOG_OPERANDS];
+  int i;
+
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      constraints[i] = recog_data.constraints[i];
+      modes[i] = recog_data.operand_mode[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 < recog_data.n_operands; i++)
+    {
+      op_costs[i] = init_cost;
+
+      if (GET_CODE (recog_data.operand[i]) == SUBREG)
+       {
+         rtx inner = SUBREG_REG (recog_data.operand[i]);
+#ifdef CLASS_CANNOT_CHANGE_MODE
+         if (GET_CODE (inner) == REG
+             && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner)))
+           SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner));
+#endif
+         recog_data.operand[i] = inner;
+       }
+
+      if (GET_CODE (recog_data.operand[i]) == MEM)
+       record_address_regs (XEXP (recog_data.operand[i], 0),
+                            BASE_REG_CLASS, frequency * 2);
+      else if (constraints[i][0] == 'p')
+       record_address_regs (recog_data.operand[i],
+                            BASE_REG_CLASS, frequency * 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 < (int) recog_data.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_data.n_operands; j++)
+         xconstraints[j] = constraints[j];
+
+       xconstraints[i] = constraints[i+1];
+       xconstraints[i+1] = constraints[i];
+       record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
+                           recog_data.operand, modes, 
+                           xconstraints, insn, op_costs, reg_pref);
+      }
+
+  record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
+                     recog_data.operand, modes, 
+                     constraints, insn, op_costs, reg_pref);
+}
+\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
@@ -768,25 +1013,9 @@ scan_one_insn (insn, pass)
 {
   enum rtx_code code = GET_CODE (insn);
   enum rtx_code pat_code;
-  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;
-    }
+  struct costs op_costs[MAX_RECOG_OPERANDS];
 
   if (GET_RTX_CLASS (code) != 'i')
     return insn;
@@ -802,12 +1031,6 @@ scan_one_insn (insn, pass)
   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.  */
@@ -821,9 +1044,9 @@ scan_one_insn (insn, pass)
       costs[REGNO (SET_DEST (set))].mem_cost
        -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
                              GENERAL_REGS, 1)
-           * loop_cost);
+           * frequency);
       record_address_regs (XEXP (SET_SRC (set), 0),
-                          BASE_REG_CLASS, loop_cost * 2);
+                          BASE_REG_CLASS, frequency * 2);
       return insn;
     }
 
@@ -840,24 +1063,22 @@ scan_one_insn (insn, pass)
      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]))
+      && recog_data.n_operands >= 3
+      && recog_data.constraints[1][0] == '0'
+      && recog_data.constraints[1][1] == 0
+      && CONSTANT_P (recog_data.operand[1])
+      && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[1])
+      && ! rtx_equal_p (recog_data.operand[0], recog_data.operand[2])
+      && GET_CODE (recog_data.operand[0]) == REG
+      && MODES_TIEABLE_P (GET_MODE (recog_data.operand[0]),
+                         recog_data.operand_mode[1]))
     {
       rtx previnsn = prev_real_insn (insn);
       rtx dest
-       = gen_lowpart (recog_operand_mode[1],
-                      recog_operand[0]);
+       = gen_lowpart (recog_data.operand_mode[1],
+                      recog_data.operand[0]);
       rtx newinsn
-       = emit_insn_before (gen_move_insn (dest,
-                                          recog_operand[1]),
-                           insn);
+       = emit_insn_before (gen_move_insn (dest, recog_data.operand[1]), insn);
 
       /* If this insn was the start of a basic block,
         include the new insn in that block.
@@ -868,81 +1089,44 @@ scan_one_insn (insn, pass)
        {
          int b;
          for (b = 0; b < n_basic_blocks; b++)
-           if (insn == basic_block_head[b])
-             basic_block_head[b] = newinsn;
+           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];
+      REG_N_SETS (REGNO (recog_data.operand[0]))++;
+      REG_N_REFS (REGNO (recog_data.operand[0]))++;
+      REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
+
+      *recog_data.operand_loc[1] = recog_data.operand[0];
+      REG_N_REFS (REGNO (recog_data.operand[0]))++;
+      REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
+      for (i = recog_data.n_dups - 1; i >= 0; i--)
+       if (recog_data.dup_num[i] == 1)
+         {
+           *recog_data.dup_loc[i] = recog_data.operand[0];
+           REG_N_REFS (REGNO (recog_data.operand[0]))++;
+           REG_FREQ (REGNO (recog_data.operand[0])) += frequency;
+         }
 
       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] == '%')
-      {
-       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);
+  record_operand_costs (insn, op_costs, reg_pref);
 
   /* 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)
+  for (i = 0; i < recog_data.n_operands; i++)
+    if (GET_CODE (recog_data.operand[i]) == REG
+       && REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
       {
-       int regno = REGNO (recog_operand[i]);
+       int regno = REGNO (recog_data.operand[i]);
        struct costs *p = &costs[regno], *q = &op_costs[i];
 
-       p->mem_cost += q->mem_cost * loop_cost;
+       p->mem_cost += q->mem_cost * frequency;
        for (j = 0; j < N_REG_CLASSES; j++)
-         p->cost[j] += q->cost[j] * loop_cost;
+         p->cost[j] += q->cost[j] * frequency;
       }
 
   return insn;
@@ -954,11 +1138,11 @@ scan_one_insn (insn, pass)
    This pass comes just before local register allocation.  */
 
 void
-regclass (f, nregs)
+regclass (f, nregs, dump)
      rtx f;
      int nregs;
+     FILE *dump;
 {
-#ifdef REGISTER_CONSTRAINTS
   register rtx insn;
   register int i;
   int pass;
@@ -967,9 +1151,13 @@ regclass (f, nregs)
 
   costs = (struct costs *) xmalloc (nregs * sizeof (struct costs));
 
+#ifdef CLASS_CANNOT_CHANGE_MODE
+  reg_changes_mode = BITMAP_XMALLOC();
+#endif  
+
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 
-  in_inc_dec = (char *) alloca (nregs);
+  in_inc_dec = (char *) xmalloc (nregs);
 
   /* Initialize information about which register classes can be used for
      pseudos that are auto-incremented or auto-decremented.  It would
@@ -1027,35 +1215,61 @@ regclass (f, nregs)
 
   for (pass = 0; pass <= flag_expensive_optimizations; pass++)
     {
+      int index;
+
+      if (dump)
+        fprintf (dump, "\n\nPass %i\n\n",pass);
       /* Zero out our accumulation of the cost of each class for each reg.  */
 
-      bzero ((char *) costs, nregs * sizeof (struct costs));
+      memset ((char *) costs, 0, nregs * sizeof (struct costs));
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
-      bzero (in_inc_dec, nregs);
+      memset (in_inc_dec, 0, nregs);
 #endif
 
-      loop_depth = 0, loop_cost = 1;
-
       /* Scan the instructions and record each time it would
         save code to put a certain register in a certain class.  */
 
-      for (insn = f; insn; insn = NEXT_INSN (insn))
+      if (!optimize)
        {
-         insn = scan_one_insn (insn, pass);
+         frequency = 1;
+         for (insn = f; insn; insn = NEXT_INSN (insn))
+           insn = scan_one_insn (insn, pass);
        }
+      else
+       for (index = 0; index < n_basic_blocks; index++)        
+         {
+           basic_block bb = BASIC_BLOCK (index);
+
+           /* 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 (optimize_size)
+             frequency = 1;
+           else
+             frequency = bb->frequency ? bb->frequency : 1;
+           for (insn = bb->head; ; insn = NEXT_INSN (insn))
+             {
+               insn = scan_one_insn (insn, pass);
+               if (insn == bb->end)
+                 break;
+             }
+         }
       
       /* 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
+        `prefclass'.  Record in `altclass' the largest register
         class any of whose registers is better than memory.  */
     
       if (pass == 0)
-       {
-         prefclass = prefclass_buffer;
-         altclass = altclass_buffer;
-       }
+       reg_pref = reg_pref_buffer;
 
+      if (dump)
+        {
+         dump_regclass (dump);
+         fprintf (dump,"\n");
+       }
       for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
        {
          register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
@@ -1065,15 +1279,23 @@ regclass (f, nregs)
          register int class;
          register struct costs *p = &costs[i];
 
+         /* In non-optimizing compilation REG_N_REFS is not initialized
+            yet.  */
+         if (optimize && !REG_N_REFS (i))
+           continue;
+
          for (class = (int) ALL_REGS - 1; class > 0; class--)
            {
              /* Ignore classes that are too small for this operand or
                 invalid for a operand that was auto-incremented.  */
-             if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i))
-                 > reg_class_size[class]
+             if (!contains_reg_of_mode [class][PSEUDO_REGNO_MODE (i)]
 #ifdef FORBIDDEN_INC_DEC_CLASSES
                  || (in_inc_dec[i] && forbidden_inc_dec_class[class])
 #endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+                 || (REGNO_REG_SET_P (reg_changes_mode, i)
+                     && ! class_can_change_mode [class])
+#endif
                  )
                ;
              else if (p->cost[class] < best_cost)
@@ -1092,7 +1314,7 @@ regclass (f, nregs)
             should be provided as a register class.  Don't do this if we
             will be doing it again later.  */
 
-         if (pass == 1 || ! flag_expensive_optimizations)
+         if ((pass == 1  || dump) || ! flag_expensive_optimizations)
            for (class = 0; class < N_REG_CLASSES; class++)
              if (p->cost[class] < p->mem_cost
                  && (reg_class_size[(int) reg_class_subunion[(int) alt][class]]
@@ -1100,6 +1322,10 @@ regclass (f, nregs)
 #ifdef FORBIDDEN_INC_DEC_CLASSES
                  && ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
 #endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+                 && ! (REGNO_REG_SET_P (reg_changes_mode, i)
+                       && ! class_can_change_mode [class])
+#endif
                  )
                alt = reg_class_subunion[(int) alt][class];
          
@@ -1107,18 +1333,37 @@ regclass (f, nregs)
          if (alt == best)
            alt = NO_REGS;
 
+         if (dump 
+             && (reg_pref[i].prefclass != (int) best
+                 || reg_pref[i].altclass != (int) alt))
+           {
+             static const char *const reg_class_names[] = REG_CLASS_NAMES;
+             fprintf (dump, "  Register %i", i);
+             if (alt == ALL_REGS || best == ALL_REGS)
+               fprintf (dump, " pref %s\n", reg_class_names[(int) best]);
+             else if (alt == NO_REGS)
+               fprintf (dump, " pref %s or none\n", reg_class_names[(int) best]);
+             else
+               fprintf (dump, " pref %s, else %s\n",
+                        reg_class_names[(int) best],
+                        reg_class_names[(int) alt]);
+           }
+
          /* We cast to (int) because (char) hits bugs in some compilers.  */
-         prefclass[i] = (int) best;
-         altclass[i] = (int) alt;
+         reg_pref[i].prefclass = (int) best;
+         reg_pref[i].altclass = (int) alt;
        }
     }
-#endif /* REGISTER_CONSTRAINTS */
 
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+  free (in_inc_dec);
+#endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+  BITMAP_XFREE (reg_changes_mode);
+#endif
   free (costs);
 }
 \f
-#ifdef REGISTER_CONSTRAINTS
-
 /* Record the cost of using memory or registers of various classes for
    the operands in INSN.
 
@@ -1144,13 +1389,16 @@ regclass (f, nregs)
    alternatives.  */
 
 static void
-record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
+record_reg_classes (n_alts, n_ops, ops, modes,
+                   constraints, insn, op_costs, reg_pref)
      int n_alts;
      int n_ops;
      rtx *ops;
      enum machine_mode *modes;
-     char **constraints;
+     const char **constraints;
      rtx insn;
+     struct costs *op_costs;
+     struct reg_pref *reg_pref;
 {
   int alt;
   int i, j;
@@ -1165,19 +1413,21 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
       int alt_fail = 0;
       int alt_cost = 0;
       enum reg_class classes[MAX_RECOG_OPERANDS];
+      int allows_mem[MAX_RECOG_OPERANDS];
       int class;
 
       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_mem = 0;
+         int allows_addr = 0;
          int win = 0;
          unsigned char c;
 
          /* Initially show we know nothing about the register class.  */
          classes[i] = NO_REGS;
+         allows_mem[i] = 0;
 
          /* If this operand has no constraints at all, we can conclude 
             nothing about it since anything is valid.  */
@@ -1185,7 +1435,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
          if (*p == 0)
            {
              if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
-               bzero ((char *) &this_op_costs[i], sizeof this_op_costs[i]);
+               memset ((char *) &this_op_costs[i], 0, sizeof this_op_costs[i]);
 
              continue;
            }
@@ -1200,8 +1450,12 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
          if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
            {
+             /* Copy class and whether memory is allowed from the matching
+                alternative.  Then perform any needed cost computations
+                and/or adjustments.  */
              j = p[0] - '0';
              classes[i] = classes[j];
+             allows_mem[i] = allows_mem[j];
 
              if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER)
                {
@@ -1237,12 +1491,45 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                }
              else
                {
-                 /* The costs of this operand are the same as that of the
-                    other operand.  However, if we cannot tie them, this
-                    alternative needs to do a copy, which is one
-                    instruction.  */
+                 /* The costs of this operand are not the same as the other
+                    operand since move costs are not symmetric.  Moreover,
+                    if we cannot tie them, this alternative needs to do a
+                    copy, which is one instruction.  */
+
+                 struct costs *pp = &this_op_costs[i];
+
+                 for (class = 0; class < N_REG_CLASSES; class++)
+                   pp->cost[class]
+                     = ((recog_data.operand_type[i] != OP_OUT
+                         ? may_move_in_cost[mode][class][(int) classes[i]]
+                         : 0)
+                        + (recog_data.operand_type[i] != OP_IN
+                           ? may_move_out_cost[mode][(int) classes[i]][class]
+                           : 0));
+                 
+                 /* If the alternative actually allows memory, make things
+                    a bit cheaper since we won't need an extra insn to
+                    load it.  */
+
+                 pp->mem_cost
+                   = ((recog_data.operand_type[i] != OP_IN
+                       ? MEMORY_MOVE_COST (mode, classes[i], 0)
+                       : 0)
+                      + (recog_data.operand_type[i] != OP_OUT
+                         ? MEMORY_MOVE_COST (mode, classes[i], 1)
+                         : 0) - allows_mem[i]);
+
+                 /* If we have assigned a class to this register in our
+                    first pass, add a cost to this alternative corresponding
+                    to what we would add if this register were not in the
+                    appropriate class.  */
+
+                 if (reg_pref)
+                   alt_cost
+                     += (may_move_in_cost[mode]
+                         [(unsigned char) reg_pref[REGNO (op)].prefclass]
+                         [(int) classes[i]]);
 
-                 this_op_costs[i] = this_op_costs[j];
                  if (REGNO (ops[i]) != REGNO (ops[j])
                      && ! find_reg_note (insn, REG_DEAD, op))
                    alt_cost += 2;
@@ -1275,13 +1562,23 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              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));
+               /* We know this operand is an address, so we want it to be
+                  allocated to a register that can be the base of an
+                  address, ie BASE_REG_CLASS.  */
+               classes[i]
+                 = reg_class_subunion[(int) classes[i]]
+                   [(int) BASE_REG_CLASS];
                break;
 
              case 'm':  case 'o':  case 'V':
                /* It doesn't seem worth distinguishing between offsettable
                   and non-offsettable addresses here.  */
-               allows_mem = 1;
+               allows_mem[i] = 1;
                if (GET_CODE (op) == MEM)
                  win = 1;
                break;
@@ -1363,17 +1660,6 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                win = 1;
                break;
 
-#ifdef EXTRA_CONSTRAINT
-              case 'Q':
-              case 'R':
-              case 'S':
-              case 'T':
-              case 'U':
-               if (EXTRA_CONSTRAINT (op, c))
-                 win = 1;
-               break;
-#endif
-
              case 'g':
                if (GET_CODE (op) == MEM
                    || (CONSTANT_P (op)
@@ -1382,16 +1668,22 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 #endif
                        ))
                  win = 1;
-               allows_mem = 1;
+               allows_mem[i] = 1;
              case 'r':
                classes[i]
                  = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS];
                break;
 
              default:
-               classes[i]
-                 = reg_class_subunion[(int) classes[i]]
-                   [(int) REG_CLASS_FROM_LETTER (c)];
+               if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+                 classes[i]
+                   = reg_class_subunion[(int) classes[i]]
+                     [(int) REG_CLASS_FROM_LETTER (c)];
+#ifdef EXTRA_CONSTRAINT
+               else if (EXTRA_CONSTRAINT (op, c))
+                 win = 1;
+#endif
+               break;
              }
 
          constraints[i] = p;
@@ -1406,29 +1698,50 @@ 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;
+               {
+                 /* We must always fail if the operand is a REG, but
+                    we did not find a suitable class.
+                    
+                    Otherwise we may perform an uninitialized read
+                    from this_op_costs after the `continue' statement
+                    below.  */
+                 alt_fail = 1;
+               }
              else
                {
                  struct costs *pp = &this_op_costs[i];
 
                  for (class = 0; class < N_REG_CLASSES; class++)
-                   pp->cost[class] = may_move_cost[class][(int) classes[i]];
+                   pp->cost[class]
+                     = ((recog_data.operand_type[i] != OP_OUT
+                         ? may_move_in_cost[mode][class][(int) classes[i]]
+                         : 0)
+                        + (recog_data.operand_type[i] != OP_IN
+                           ? may_move_out_cost[mode][(int) classes[i]][class]
+                           : 0));
 
                  /* If the alternative actually allows memory, make things
                     a bit cheaper since we won't need an extra insn to
                     load it.  */
 
-                 pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1)
-                                 - allows_mem);
+                 pp->mem_cost
+                   = ((recog_data.operand_type[i] != OP_IN
+                       ? MEMORY_MOVE_COST (mode, classes[i], 0)
+                       : 0)
+                      + (recog_data.operand_type[i] != OP_OUT
+                         ? MEMORY_MOVE_COST (mode, classes[i], 1)
+                         : 0) - allows_mem[i]);
 
                  /* If we have assigned a class to this register in our
                     first pass, add a cost to this alternative corresponding
                     to what we would add if this register were not in the
                     appropriate class.  */
 
-                 if (prefclass)
+                 if (reg_pref)
                    alt_cost
-                     += may_move_cost[(unsigned char)prefclass[REGNO (op)]][(int) classes[i]];
+                     += (may_move_in_cost[mode]
+                         [(unsigned char) reg_pref[REGNO (op)].prefclass]
+                         [(int) classes[i]]);
                }
            }
 
@@ -1446,17 +1759,17 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
          else if (classes[i] != NO_REGS)
            {
-             if (recog_op_type[i] != OP_OUT)
+             if (recog_data.operand_type[i] != OP_OUT)
                alt_cost += copy_cost (op, mode, classes[i], 1);
 
-             if (recog_op_type[i] != OP_IN)
+             if (recog_data.operand_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)
+         else if (CONSTANT_P (op) && (allows_addr || allows_mem[i]))
            alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
          else
            alt_fail = 1;
@@ -1473,7 +1786,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 + (recog_op_type[i] == OP_INOUT);
+           int scale = 1 + (recog_data.operand_type[i] == OP_INOUT);
 
            pp->mem_cost = MIN (pp->mem_cost,
                                (qq->mem_cost + alt_cost) * scale);
@@ -1485,24 +1798,40 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
     }
 
   /* 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.  */
+     and one operand is a pseudo with the other a hard reg or a pseudo
+     that prefers a register that is in its own register class then
+     we may want to adjust the cost of that register class to -1.
+     Avoid the adjustment if the source does not die to avoid stressing of
+     register allocator by preferrencing two coliding registers into single
+     class.
+
+     Also avoid the adjustment if a copy between registers of the class
+     is expensive (ten times the cost of a default copy is considered
+     arbitrarily expensive).  This avoids losing when the preferred class
+     is very expensive as the source of a copy instruction.  */
 
   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)
+      && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG
+      && find_regno_note (insn, REG_DEAD, REGNO (ops[1])))
     for (i = 0; i <= 1; i++)
       if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
        {
-         int regno = REGNO (ops[!i]);
+         unsigned int regno = REGNO (ops[!i]);
          enum machine_mode mode = GET_MODE (ops[!i]);
          int class;
-         int nr;
+         unsigned int nr;
+
+         if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0)
+           {
+             enum reg_class pref = reg_pref[regno].prefclass;
 
-         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;
+             if ((reg_class_size[(unsigned char) pref]
+                  == CLASS_MAX_NREGS (pref, mode))
+                 && REGISTER_MOVE_COST (mode, pref, pref) < 10 * 2)
+               op_costs[i].cost[(unsigned char) pref] = -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)
@@ -1512,13 +1841,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                    op_costs[i].cost[class] = -1;
                  else
                    {
-                     for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
+                     for (nr = 0; nr < HARD_REGNO_NREGS (regno, mode); nr++)
                        {
-                         if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
+                         if (! TEST_HARD_REG_BIT (reg_class_contents[class],
+                                                  regno + nr))
                            break;
                        }
 
-                     if (nr == HARD_REGNO_NREGS(regno,mode))
+                     if (nr == HARD_REGNO_NREGS (regno,mode))
                        op_costs[i].cost[class] = -1;
                    }
                }
@@ -1533,9 +1863,9 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 static int
 copy_cost (x, mode, class, to_p)
      rtx x;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
      enum reg_class class;
-     int to_p;
+     int to_p ATTRIBUTE_UNUSED;
 {
 #ifdef HAVE_SECONDARY_RELOADS
   enum reg_class secondary_class = NO_REGS;
@@ -1567,7 +1897,7 @@ copy_cost (x, mode, class, to_p)
 #endif
 
   if (secondary_class != NO_REGS)
-    return (move_cost[(int) secondary_class][(int) class]
+    return (move_cost[mode][(int) secondary_class][(int) class]
            + copy_cost (x, mode, secondary_class, 2));
 #endif  /* HAVE_SECONDARY_RELOADS */
 
@@ -1579,11 +1909,11 @@ copy_cost (x, mode, class, to_p)
     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];
+    return move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
 
   else
     /* If this is a constant, we may eventually want to call rtx_cost here.  */
-    return 2;
+    return COSTS_N_INSNS (1);
 }
 \f
 /* Record the pseudo registers we must reload into hard registers
@@ -1617,10 +1947,10 @@ record_address_regs (x, class, scale)
       /* When we have an address that is a sum,
         we must determine whether registers are "base" or "index" regs.
         If there is a sum of two registers, we must choose one to be
-        the "base".  Luckily, we can use the REGNO_POINTER_FLAG
-        to make a good choice most of the time.  We only need to do this
-        on machines that can have two registers in an address and where
-        the base and index register classes are different.
+        the "base".  Luckily, we can use the REG_POINTER to make a good
+        choice most of the time.  We only need to do this on machines
+        that can have two registers in an address and where the base
+        and index register classes are different.
 
         ??? This code used to set REGNO_POINTER_FLAG in some cases, but
         that seems bogus since it should only be set when we are sure
@@ -1693,13 +2023,13 @@ record_address_regs (x, class, scale)
           with the other operand the index.  Likewise if the other operand
           is a MULT.  */
 
-       else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0)))
+       else if ((code0 == REG && REG_POINTER (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)))
+       else if ((code1 == REG && REG_POINTER (arg1))
                 || code0 == MULT)
          {
            record_address_regs (arg0, INDEX_REG_CLASS, scale);
@@ -1719,6 +2049,17 @@ record_address_regs (x, class, scale)
       }
       break;
 
+      /* Double the importance of a pseudo register that is incremented
+        or decremented, since it would take two extra insns
+        if it ends up in the wrong place.  */
+    case POST_MODIFY:
+    case PRE_MODIFY:
+      record_address_regs (XEXP (x, 0), BASE_REG_CLASS, 2 * scale);
+      if (REG_P (XEXP (XEXP (x, 1), 1)))
+       record_address_regs (XEXP (XEXP (x, 1), 1),
+                            INDEX_REG_CLASS, 2 * scale);
+      break;
+
     case POST_INC:
     case PRE_INC:
     case POST_DEC:
@@ -1745,13 +2086,13 @@ record_address_regs (x, class, scale)
        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;
+         pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2;
       }
       break;
 
     default:
       {
-       register char *fmt = GET_RTX_FORMAT (code);
+       register const char *fmt = GET_RTX_FORMAT (code);
        register int i;
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
          if (fmt[i] == 'e')
@@ -1789,11 +2130,10 @@ auto_inc_dec_reg_p (reg, mode)
   return 0;
 }
 #endif
-
-#endif /* REGISTER_CONSTRAINTS */
 \f
-static short *renumber = (short *)0;
-static size_t regno_allocated = 0;
+static short *renumber;
+static size_t regno_allocated;
+static unsigned int reg_n_max;
 
 /* 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
@@ -1812,7 +2152,6 @@ allocate_reg_info (num_regs, new_p, renumber_p)
   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)
     {
@@ -1825,8 +2164,8 @@ allocate_reg_info (num_regs, new_p, renumber_p)
        {
          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);
+         reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
+                                             * sizeof (struct reg_pref));
        }
 
       else
@@ -1836,21 +2175,18 @@ allocate_reg_info (num_regs, new_p, renumber_p)
          if (new_p)            /* if we're zapping everything, no need to realloc */
            {
              free ((char *)renumber);
-             free ((char *)prefclass_buffer);
-             free ((char *)altclass_buffer);
+             free ((char *)reg_pref);
              renumber = (short *) xmalloc (size_renumber);
-             prefclass_buffer = (char *) xmalloc (regno_allocated);
-             altclass_buffer = (char *) xmalloc (regno_allocated);
+             reg_pref_buffer = (struct reg_pref *) xmalloc (regno_allocated 
+                                                 * sizeof (struct reg_pref));
            }
 
          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);
+             reg_pref_buffer = (struct reg_pref *) xrealloc ((char *)reg_pref_buffer,
+                                                  regno_allocated 
+                                                  * sizeof (struct reg_pref));
            }
        }
 
@@ -1868,45 +2204,42 @@ allocate_reg_info (num_regs, new_p, renumber_p)
     {
       /* 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)
+      for (reg_data = reg_info_head; 
+          reg_data && reg_data->max_index >= min;
+          reg_data = reg_data->next)
        {
          size_t min_index = reg_data->min_index;
          size_t max_index = reg_data->max_index;
+         size_t max = MIN (max_index, num_regs);
+         size_t local_min = min - min_index;
+         size_t i;
 
-         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));
+         if (reg_data->min_index > num_regs)
+           continue;
 
-             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 (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
+           memset ((char *) &reg_data->data[local_min], 0,
+                  sizeof (reg_info) * (max - min_index - local_min + 1));
+
+         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;
+             reg_pref_buffer[i].prefclass = (char) NO_REGS;
+             reg_pref_buffer[i].altclass = (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 (reg_pref)
+    reg_pref = reg_pref_buffer;
 
   if (renumber_p)
     reg_renumber = renumber;
@@ -1931,10 +2264,8 @@ free_reg_info ()
          free ((char *)reg_data);
        }
 
-      free (prefclass_buffer);
-      free (altclass_buffer);
-      prefclass_buffer = (char *)0;
-      altclass_buffer = (char *)0;
+      free (reg_pref_buffer);
+      reg_pref_buffer = (struct reg_pref *)0;
       reg_info_head = (struct reg_info_data *)0;
       renumber = (short *)0;
     }
@@ -1953,20 +2284,28 @@ free_reg_info ()
 
 /* Maximum number of parallel sets and clobbers in any insn in this fn.
    Always at least 3, since the combiner could put that many together
-   and we want this to remain correct for all the remaining passes.  */
+   and we want this to remain correct for all the remaining passes.
+   This corresponds to the maximum number of times note_stores will call
+   a function for any insn.  */
 
 int max_parallel;
 
+/* Used as a temporary to record the largest number of registers in 
+   PARALLEL in a SET_DEST.  This is added to max_parallel.  */
+
+static int max_set_parallel;
+
 void
 reg_scan (f, nregs, repeat)
      rtx f;
-     int nregs;
-     int repeat;
+     unsigned int nregs;
+     int repeat ATTRIBUTE_UNUSED;
 {
   register rtx insn;
 
   allocate_reg_info (nregs, TRUE, FALSE);
   max_parallel = 3;
+  max_set_parallel = 0;
 
   for (insn = f; insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == INSN
@@ -1981,6 +2320,8 @@ reg_scan (f, nregs, repeat)
        if (REG_NOTES (insn))
          reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
       }
+
+  max_parallel += max_set_parallel;
 }
 
 /* Update 'regscan' information by looking at the insns
@@ -1989,10 +2330,10 @@ reg_scan (f, nregs, repeat)
    such a REG.  We only update information for those.  */
 
 void
-reg_scan_update(first, last, old_max_regno)
+reg_scan_update (first, last, old_max_regno)
      rtx first;
      rtx last;
-     int old_max_regno;
+     unsigned int old_max_regno;
 {
   register rtx insn;
 
@@ -2023,7 +2364,7 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
      rtx x;
      rtx insn;
      int note_flag;
-     int min_regno;
+     unsigned int min_regno;
 {
   register enum rtx_code code;
   register rtx dest;
@@ -2033,10 +2374,6 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
   switch (code)
     {
     case CONST:
-      if (GET_CODE (XEXP (x, 0)) == CONSTANT_P_RTX)
-       reg_scan_mark_refs (XEXP (XEXP (x, 0), 0), insn, note_flag, min_regno);
-      return;
-
     case CONST_INT:
     case CONST_DOUBLE:
     case CC0:
@@ -2049,7 +2386,7 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
 
     case REG:
       {
-       register int regno = REGNO (x);
+       unsigned int regno = REGNO (x);
 
        if (regno >= min_regno)
          {
@@ -2082,6 +2419,11 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
           dest = XEXP (dest, 0))
        ;
 
+      /* For a PARALLEL, record the number of things (less the usual one for a
+        SET) that are set.  */
+      if (GET_CODE (dest) == PARALLEL)
+       max_set_parallel = MAX (max_set_parallel, XVECLEN (dest, 0) - 1);
+
       if (GET_CODE (dest) == REG
          && REGNO (dest) >= min_regno)
        REG_N_SETS (REGNO (dest))++;
@@ -2104,18 +2446,18 @@ reg_scan_mark_refs (x, insn, note_flag, 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
+            optimizations).  So only set REG_POINTER 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)))
+         && ! REG_POINTER (SET_DEST (x))
          && ((GET_CODE (SET_SRC (x)) == REG
-              && REGNO_POINTER_FLAG (REGNO (SET_SRC (x))))
+              && REG_POINTER (SET_SRC (x)))
              || ((GET_CODE (SET_SRC (x)) == PLUS
                   || GET_CODE (SET_SRC (x)) == LO_SUM)
                  && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
                  && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
-                 && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (x), 0))))
+                 && REG_POINTER (XEXP (SET_SRC (x), 0)))
              || GET_CODE (SET_SRC (x)) == CONST
              || GET_CODE (SET_SRC (x)) == SYMBOL_REF
              || GET_CODE (SET_SRC (x)) == LABEL_REF
@@ -2132,13 +2474,13 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
                  && (GET_CODE (XEXP (note, 0)) == CONST
                      || GET_CODE (XEXP (note, 0)) == SYMBOL_REF
                      || GET_CODE (XEXP (note, 0)) == LABEL_REF))))
-       REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
+       REG_POINTER (SET_DEST (x)) = 1;
 
       /* ... fall through ...  */
 
     default:
       {
-       register char *fmt = GET_RTX_FORMAT (code);
+       register const char *fmt = GET_RTX_FORMAT (code);
        register int i;
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
          {
@@ -2206,12 +2548,5 @@ reg_classes_intersect_p (c1, c2)
 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 ();
 }