OSDN Git Service

update the sample output
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 41d3353..c022b0a 100644 (file)
@@ -1,6 +1,6 @@
 /* Compute register class preferences for pseudo-registers.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
-   1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,6 +27,7 @@ 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"
@@ -42,7 +43,7 @@ Boston, MA 02111-1307, USA.  */
 #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    PARAMS ((void));
@@ -115,7 +116,16 @@ 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;
@@ -140,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.  */
 
@@ -160,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.  */
 
-const 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
@@ -171,20 +184,24 @@ const 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_in_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[N_REG_CLASSES][N_REG_CLASSES];
+static int may_move_out_cost[MAX_MACHINE_MODE][N_REG_CLASSES][N_REG_CLASSES];
 
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 
@@ -200,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.  */
@@ -243,15 +275,16 @@ 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 ();
@@ -269,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.  */
@@ -279,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))
@@ -385,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;
 
@@ -403,44 +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))
-         may_move_in_cost[i][j] = 0;
-       else
-         may_move_in_cost[i][j] = cost;
+       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;
+             }
+      }
 
-       if (reg_class_subset_p (j, i))
-         may_move_out_cost[i][j] = 0;
-       else
-         may_move_out_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.
@@ -483,6 +595,7 @@ 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);
@@ -529,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
@@ -554,9 +667,10 @@ memory_move_secondary_cost (mode, class, in)
 
 enum machine_mode
 choose_hard_reg_mode (regno, nregs)
-     int regno ATTRIBUTE_UNUSED;
-     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
@@ -583,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;
@@ -713,16 +832,15 @@ static struct reg_pref *reg_pref;
 
 static struct reg_pref *reg_pref_buffer;
 
-/* Account for the fact that insns within a loop are executed very commonly,
-   but don't keep doing this as loops go too deep.  */
+/* Frequency of executions of current insn.  */
 
-static int loop_cost;
+static int frequency;
 
 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 *,
-                                      char *, const char **, rtx,
+                                      const char **, rtx,
                                       struct costs *, struct reg_pref *));
 static int copy_cost           PARAMS ((rtx, enum machine_mode, 
                                       enum reg_class, int));
@@ -730,7 +848,7 @@ static void record_address_regs     PARAMS ((rtx, enum reg_class, int));
 #ifdef FORBIDDEN_INC_DEC_CLASSES
 static int auto_inc_dec_reg_p  PARAMS ((rtx, enum machine_mode));
 #endif
-static void reg_scan_mark_refs PARAMS ((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.
@@ -783,13 +901,23 @@ dump_regclass (dump)
   int i;
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     {
-      enum reg_class class;
+      int /* enum reg_class */ class;
       if (REG_N_REFS (i))
        {
          fprintf (dump, "  Register %i costs:", i);
-         for (class = 0; class < N_REG_CLASSES; class++)
-           fprintf (dump, " %s:%i", reg_class_names[(int) class],
-                    costs[i].cost[class]);
+         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);
        }
     }
@@ -806,7 +934,6 @@ record_operand_costs (insn, op_costs, reg_pref)
 {
   const char *constraints[MAX_RECOG_OPERANDS];
   enum machine_mode modes[MAX_RECOG_OPERANDS];
-  char subreg_changes_size[MAX_RECOG_OPERANDS];
   int i;
 
   for (i = 0; i < recog_data.n_operands; i++)
@@ -814,7 +941,6 @@ record_operand_costs (insn, op_costs, reg_pref)
       constraints[i] = recog_data.constraints[i];
       modes[i] = recog_data.operand_mode[i];
     }
-  memset (subreg_changes_size, 0, sizeof (subreg_changes_size));
 
   /* If we get here, we are set up to record the costs of all the
      operands for this insn.  Start by initializing the costs.
@@ -829,17 +955,20 @@ record_operand_costs (insn, op_costs, reg_pref)
       if (GET_CODE (recog_data.operand[i]) == SUBREG)
        {
          rtx inner = SUBREG_REG (recog_data.operand[i]);
-         if (GET_MODE_SIZE (modes[i]) != GET_MODE_SIZE (GET_MODE (inner)))
-           subreg_changes_size[i] = 1;
+#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, loop_cost * 2);
+                            BASE_REG_CLASS, frequency * 2);
       else if (constraints[i][0] == 'p')
        record_address_regs (recog_data.operand[i],
-                            BASE_REG_CLASS, loop_cost * 2);
+                            BASE_REG_CLASS, frequency * 2);
     }
 
   /* Check for commutative in a separate loop so everything will
@@ -861,12 +990,12 @@ record_operand_costs (insn, op_costs, reg_pref)
        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, subreg_changes_size,
+                           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, subreg_changes_size,
+                     recog_data.operand, modes, 
                      constraints, insn, op_costs, reg_pref);
 }
 \f
@@ -915,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;
     }
 
@@ -966,11 +1095,19 @@ scan_one_insn (insn, pass)
 
       /* This makes one more setting of new insns's dest.  */
       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];
+         {
+           *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);
     }
@@ -987,9 +1124,9 @@ scan_one_insn (insn, pass)
        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;
@@ -1014,6 +1151,10 @@ regclass (f, nregs, dump)
 
   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 *) xmalloc (nregs);
@@ -1080,10 +1221,10 @@ regclass (f, nregs, 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
 
       /* Scan the instructions and record each time it would
@@ -1091,7 +1232,7 @@ regclass (f, nregs, dump)
 
       if (!optimize)
        {
-         loop_cost = 1;
+         frequency = 1;
          for (insn = f; insn; insn = NEXT_INSN (insn))
            insn = scan_one_insn (insn, pass);
        }
@@ -1105,9 +1246,9 @@ regclass (f, nregs, dump)
               aggressive than the assumptions made elsewhere and is being
               tried as an experiment.  */
            if (optimize_size)
-             loop_cost = 1;
+             frequency = 1;
            else
-             loop_cost = 1 << (2 * MIN (bb->loop_depth, 5));
+             frequency = bb->frequency ? bb->frequency : 1;
            for (insn = bb->head; ; insn = NEXT_INSN (insn))
              {
                insn = scan_one_insn (insn, pass);
@@ -1147,11 +1288,14 @@ regclass (f, nregs, dump)
            {
              /* 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)
@@ -1178,6 +1322,10 @@ regclass (f, nregs, dump)
 #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];
          
@@ -1210,6 +1358,9 @@ regclass (f, nregs, dump)
 #ifdef FORBIDDEN_INC_DEC_CLASSES
   free (in_inc_dec);
 #endif
+#ifdef CLASS_CANNOT_CHANGE_MODE
+  BITMAP_XFREE (reg_changes_mode);
+#endif
   free (costs);
 }
 \f
@@ -1238,13 +1389,12 @@ regclass (f, nregs, dump)
    alternatives.  */
 
 static void
-record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
+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 *subreg_changes_size ATTRIBUTE_UNUSED;
      const char **constraints;
      rtx insn;
      struct costs *op_costs;
@@ -1285,7 +1435,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
          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;
            }
@@ -1351,10 +1501,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
                  for (class = 0; class < N_REG_CLASSES; class++)
                    pp->cost[class]
                      = ((recog_data.operand_type[i] != OP_OUT
-                         ? may_move_in_cost[class][(int) classes[i]]
+                         ? may_move_in_cost[mode][class][(int) classes[i]]
                          : 0)
                         + (recog_data.operand_type[i] != OP_IN
-                           ? may_move_out_cost[(int) classes[i]][class]
+                           ? may_move_out_cost[mode][(int) classes[i]][class]
                            : 0));
                  
                  /* If the alternative actually allows memory, make things
@@ -1376,7 +1526,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
 
                  if (reg_pref)
                    alt_cost
-                     += (may_move_in_cost[(unsigned char) reg_pref[REGNO (op)].prefclass]
+                     += (may_move_in_cost[mode]
+                         [(unsigned char) reg_pref[REGNO (op)].prefclass]
                          [(int) classes[i]]);
 
                  if (REGNO (ops[i]) != REGNO (ops[j])
@@ -1509,17 +1660,6 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
                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)
@@ -1535,23 +1675,19 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
                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;
 
-#ifdef CLASS_CANNOT_CHANGE_SIZE
-         /* If we noted a subreg earlier, and the selected class is a 
-            subclass of CLASS_CANNOT_CHANGE_SIZE, zap it.  */
-         if (subreg_changes_size[i]
-             && (reg_class_subunion[(int) CLASS_CANNOT_CHANGE_SIZE]
-                                   [(int) classes[i]]
-                 == CLASS_CANNOT_CHANGE_SIZE))
-           classes[i] = NO_REGS;
-#endif
-
          /* How we account for this operand now depends on whether it is  a
             pseudo register or not.  If it is, we first check if any
             register classes are valid.  If not, we ignore this alternative,
@@ -1563,13 +1699,13 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
            {
              if (classes[i] == NO_REGS)
                {
-                   /* 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;
+                 /* 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
                {
@@ -1578,10 +1714,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
                  for (class = 0; class < N_REG_CLASSES; class++)
                    pp->cost[class]
                      = ((recog_data.operand_type[i] != OP_OUT
-                         ? may_move_in_cost[class][(int) classes[i]]
+                         ? may_move_in_cost[mode][class][(int) classes[i]]
                          : 0)
                         + (recog_data.operand_type[i] != OP_IN
-                           ? may_move_out_cost[(int) classes[i]][class]
+                           ? may_move_out_cost[mode][(int) classes[i]][class]
                            : 0));
 
                  /* If the alternative actually allows memory, make things
@@ -1603,7 +1739,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
 
                  if (reg_pref)
                    alt_cost
-                     += (may_move_in_cost[(unsigned char) reg_pref[REGNO (op)].prefclass]
+                     += (may_move_in_cost[mode]
+                         [(unsigned char) reg_pref[REGNO (op)].prefclass]
                          [(int) classes[i]]);
                }
            }
@@ -1681,10 +1818,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
     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)
            {
@@ -1692,7 +1829,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
 
              if ((reg_class_size[(unsigned char) pref]
                   == CLASS_MAX_NREGS (pref, mode))
-                 && REGISTER_MOVE_COST (pref, pref) < 10 * 2)
+                 && REGISTER_MOVE_COST (mode, pref, pref) < 10 * 2)
                op_costs[i].cost[(unsigned char) pref] = -1;
            }
          else if (regno < FIRST_PSEUDO_REGISTER)
@@ -1704,13 +1841,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, subreg_changes_size,
                    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;
                    }
                }
@@ -1759,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 */
 
@@ -1771,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
@@ -1809,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
@@ -1885,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);
@@ -1911,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:
@@ -1937,7 +2086,7 @@ 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_in_cost[i][(int) class] * scale) / 2;
+         pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2;
       }
       break;
 
@@ -1982,8 +2131,9 @@ auto_inc_dec_reg_p (reg, mode)
 }
 #endif
 \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
@@ -2002,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)
     {
@@ -2055,34 +2204,34 @@ 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;
-                 reg_pref_buffer[i].prefclass = (char) NO_REGS;
-                 reg_pref_buffer[i].altclass = (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;
            }
        }
     }
@@ -2135,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;
+     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
@@ -2163,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
@@ -2171,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;
 
@@ -2205,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;
@@ -2227,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)
          {
@@ -2260,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))++;
@@ -2282,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
@@ -2310,7 +2474,7 @@ 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 ...  */