OSDN Git Service

* except.c (expand_start_all_catch): If the machine needs to
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 58399dd..f562472 100644 (file)
@@ -1,5 +1,5 @@
 /* Compute register class preferences for pseudo-registers.
-   Copyright (C) 1987, 1988, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 92, 93, 94, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file contains two passes of the compiler: reg_scan and reg_class.
@@ -32,6 +33,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "recog.h"
 #include "reload.h"
 #include "real.h"
+#include "bytecode.h"
 
 #ifndef REGISTER_MOVE_COST
 #define REGISTER_MOVE_COST(x, y) 2
@@ -40,6 +42,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #ifndef MEMORY_MOVE_COST
 #define MEMORY_MOVE_COST(x) 4
 #endif
+
+/* If we have auto-increment or auto-decrement and we can have secondary
+   reloads, we are not allowed to use classes requiring secondary
+   reloads for pseudos auto-incremented since reload can't handle it.  */
+
+#ifdef AUTO_INC_DEC
+#if defined(SECONDARY_INPUT_RELOAD_CLASS) || defined(SECONDARY_OUTPUT_RELOAD_CLASS)
+#define FORBIDDEN_INC_DEC_CLASSES
+#endif
+#endif
 \f
 /* Register tables used by many passes.  */
 
@@ -69,6 +81,9 @@ char call_used_regs[FIRST_PSEUDO_REGISTER];
 
 HARD_REG_SET call_used_reg_set;
 
+/* HARD_REG_SET of registers we want to avoid caller saving.  */
+HARD_REG_SET losing_caller_save_reg_set;
+
 /* Data for initializing the above.  */
 
 static char initial_call_used_regs[] = CALL_USED_REGISTERS;
@@ -103,7 +118,17 @@ int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER;
 
 /* For each reg class, a HARD_REG_SET saying which registers are in it.  */
 
-HARD_REG_SET reg_class_contents[] = REG_CLASS_CONTENTS;
+HARD_REG_SET reg_class_contents[N_REG_CLASSES];
+
+/* The same information, but as an array of unsigned ints.  We copy from
+   these unsigned ints to the table above.  We do this so the tm.h files
+   do not have to be aware of the wordsize for machines with <= 64 regs.  */
+
+#define N_REG_INTS  \
+  ((FIRST_PSEUDO_REGISTER + (HOST_BITS_PER_INT - 1)) / HOST_BITS_PER_INT)
+
+static unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS] 
+  = REG_CLASS_CONTENTS;
 
 /* For each reg class, number of regs it contains.  */
 
@@ -131,6 +156,13 @@ enum reg_class reg_class_superunion[N_REG_CLASSES][N_REG_CLASSES];
 
 char *reg_names[] = REGISTER_NAMES;
 
+/* For each hard register, the widest mode object that it can contain.
+   This will be a MODE_INT mode if the register can hold integers.  Otherwise
+   it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the
+   register.  */
+
+enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
+
 /* Indexed by n, gives number of times (REG n) is set or clobbered.
    This information remains valid for the rest of the compilation
    of the current function; it is used to control register allocation.
@@ -150,6 +182,20 @@ static int move_cost[N_REG_CLASSES][N_REG_CLASSES];
 
 static int may_move_cost[N_REG_CLASSES][N_REG_CLASSES];
 
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+
+/* These are the classes that regs which are auto-incremented or decremented
+   cannot be put in.  */
+
+static int forbidden_inc_dec_class[N_REG_CLASSES];
+
+/* Indexed by n, is non-zero if (REG n) is used in an auto-inc or auto-dec
+   context.  */
+
+static char *in_inc_dec;
+
+#endif /* FORBIDDEN_INC_DEC_CLASSES */
+
 /* Function called only once to initialize the above data on reg usage.
    Once this is done, various switches may override.  */
 
@@ -158,13 +204,26 @@ init_reg_sets ()
 {
   register int i, j;
 
+  /* First copy the register information from the initial int form into
+     the regsets.  */
+
+  for (i = 0; i < N_REG_CLASSES; i++)
+    {
+      CLEAR_HARD_REG_SET (reg_class_contents[i]);
+
+      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)))
+         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);
 
   /* Compute number of hard regs in each class.  */
 
-  bzero (reg_class_size, sizeof reg_class_size);
+  bzero ((char *) reg_class_size, sizeof reg_class_size);
   for (i = 0; i < N_REG_CLASSES; i++)
     for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
       if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
@@ -301,7 +360,7 @@ init_reg_sets ()
 /* After switches have been processed, which perhaps alter
    `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
 
-void
+static void
 init_reg_sets_1 ()
 {
   register int i;
@@ -313,16 +372,6 @@ init_reg_sets_1 ()
   CONDITIONAL_REGISTER_USAGE;
 #endif
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (global_regs[i])
-      {
-       if (call_used_regs[i] && ! fixed_regs[i])
-         warning ("call-clobbered register used for global register variable");
-       fixed_regs[i] = 1;
-       /* Prevent saving/restoring of this reg.  */
-       call_used_regs[i] = 1;
-      }
-
   /* Initialize "constant" tables.  */
 
   CLEAR_HARD_REG_SET (fixed_reg_set);
@@ -330,19 +379,11 @@ init_reg_sets_1 ()
   CLEAR_HARD_REG_SET (call_fixed_reg_set);
 
   bcopy (fixed_regs, call_fixed_regs, sizeof call_fixed_regs);
-#ifdef STRUCT_VALUE_REGNUM
-  call_fixed_regs[STRUCT_VALUE_REGNUM] = 1;
-#endif
-#ifdef STATIC_CHAIN_REGNUM
-  call_fixed_regs[STATIC_CHAIN_REGNUM] = 1;
-#endif
 
   n_non_fixed_regs = 0;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (FUNCTION_VALUE_REGNO_P (i))
-       call_fixed_regs[i] = 1;
       if (fixed_regs[i])
        SET_HARD_REG_BIT (fixed_reg_set, i);
       else
@@ -352,9 +393,91 @@ init_reg_sets_1 ()
        SET_HARD_REG_BIT (call_used_reg_set, i);
       if (call_fixed_regs[i])
        SET_HARD_REG_BIT (call_fixed_reg_set, i);
+      if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
+       SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
+    }
+}
+
+/* Compute the table of register modes.
+   These values are used to record death information for individual registers
+   (as opposed to a multi-register mode).  */
+
+static void
+init_reg_modes ()
+{
+  register int i;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
+
+      /* If we couldn't find a valid mode, fall back to `word_mode'.
+        ??? We assume `word_mode' has already been initialized.
+         ??? One situation in which we need to do this is on the mips where
+        HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2.  Ideally we'd like
+        to use DF mode for the even registers and VOIDmode for the odd
+        (for the cpu models where the odd ones are inaccessible).  */
+      if (reg_raw_mode[i] == VOIDmode)
+       reg_raw_mode[i] = word_mode;
     }
 }
 
+/* Finish initializing the register sets and
+   initialize the register modes.  */
+
+void
+init_regs ()
+{
+  /* This finishes what was started by init_reg_sets, but couldn't be done
+     until after register usage was specified.  */
+  if (!output_bytecode)
+    init_reg_sets_1 ();
+
+  init_reg_modes ();
+}
+
+/* Return a machine mode that is legitimate for hard reg REGNO and large
+   enough to save nregs.  If we can't find one, return VOIDmode.  */
+
+enum machine_mode
+choose_hard_reg_mode (regno, nregs)
+     int regno;
+     int nregs;
+{
+  enum machine_mode found_mode = VOIDmode, mode;
+
+  /* We first look for the largest integer mode that can be validly
+     held in REGNO.  If none, we look for the largest floating-point mode.
+     If we still didn't find a valid mode, try CCmode.  */
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (HARD_REGNO_NREGS (regno, mode) == nregs
+       && HARD_REGNO_MODE_OK (regno, mode))
+      found_mode = mode;
+
+  if (found_mode != VOIDmode)
+    return found_mode;
+
+  if (HARD_REGNO_NREGS (regno, CCmode) == nregs
+      && HARD_REGNO_MODE_OK (regno, CCmode))
+    return CCmode;
+
+  /* We can't find a mode valid for this register.  */
+  return VOIDmode;
+}
+
 /* Specify the usage characteristics of the register named NAME.
    It should be a fixed register if FIXED and a
    call-used register if CALL_USED.  */
@@ -366,6 +489,13 @@ fix_register (name, fixed, call_used)
 {
   int i;
 
+  if (output_bytecode)
+    {
+      warning ("request to mark `%s' as %s ignored by bytecode compiler",
+              name, call_used ? "call-used" : "fixed");
+      return;
+    }
+
   /* Decode the name and update the primary form of
      the register info.  */
 
@@ -379,6 +509,35 @@ fix_register (name, fixed, call_used)
       warning ("unknown register name: %s", name);
     }
 }
+
+/* Mark register number I as global.  */
+
+void
+globalize_reg (i)
+     int i;
+{
+  if (global_regs[i])
+    {
+      warning ("register used for two global register variables");
+      return;
+    }
+
+  if (call_used_regs[i] && ! fixed_regs[i])
+    warning ("call-clobbered register used for global register variable");
+
+  global_regs[i] = 1;
+
+  /* If already fixed, nothing else to do.  */
+  if (fixed_regs[i])
+    return;
+
+  fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1;
+  n_non_fixed_regs--;
+
+  SET_HARD_REG_BIT (fixed_reg_set, i);
+  SET_HARD_REG_BIT (call_used_reg_set, i);
+  SET_HARD_REG_BIT (call_fixed_reg_set, i);
+}
 \f
 /* Now the data and code for the `regclass' pass, which happens
    just before local-alloc.  */
@@ -429,10 +588,13 @@ static int loop_depth;
 
 static int loop_cost;
 
-static int copy_cost ();
-static void record_reg_classes ();
-static void record_address_regs ();
-
+static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
+                                      char **, rtx));
+static int copy_cost           PROTO((rtx, enum machine_mode, 
+                                      enum reg_class, int));
+static void record_address_regs        PROTO((rtx, enum reg_class, int));
+static auto_inc_dec_reg_p      PROTO((rtx, enum machine_mode));
+static void reg_scan_mark_refs PROTO((rtx, rtx, int));
 
 /* Return the reg_class in which pseudo reg number REGNO is best allocated.
    This function is sometimes called before the info has been computed.
@@ -484,6 +646,60 @@ regclass (f, nregs)
 
   init_recog ();
 
+  costs = (struct costs *) alloca (nregs * sizeof (struct costs));
+
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+
+  in_inc_dec = (char *) alloca (nregs);
+
+  /* Initialize information about which register classes can be used for
+     pseudos that are auto-incremented or auto-decremented.  It would
+     seem better to put this in init_reg_sets, but we need to be able
+     to allocate rtx, which we can't do that early.  */
+
+  for (i = 0; i < N_REG_CLASSES; i++)
+    {
+      rtx r = gen_rtx (REG, VOIDmode, 0);
+      enum machine_mode m;
+
+      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+       if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
+         {
+           REGNO (r) = j;
+
+           for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE;
+                m = (enum machine_mode) ((int) m + 1))
+             if (HARD_REGNO_MODE_OK (j, m))
+               {
+                 PUT_MODE (r, m);
+
+                 /* If a register is not directly suitable for an
+                    auto-increment or decrement addressing mode and
+                    requires secondary reloads, disallow its class from
+                    being used in such addresses.  */
+
+                 if ((0
+#ifdef SECONDARY_RELOAD_CLASS
+                      || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#else
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+                      || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#endif
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+                      || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+                          != NO_REGS)
+#endif
+#endif
+                      )
+                     && ! auto_inc_dec_reg_p (r, m))
+                   forbidden_inc_dec_class[i] = 1;
+               }
+         }
+    }
+#endif /* FORBIDDEN_INC_DEC_CLASSES */
+
   init_cost.mem_cost = 10000;
   for (i = 0; i < N_REG_CLASSES; i++)
     init_cost.cost[i] = 10000;
@@ -497,8 +713,11 @@ regclass (f, nregs)
     {
       /* Zero out our accumulation of the cost of each class for each reg.  */
 
-      costs = (struct costs *) alloca (nregs * sizeof (struct costs));
-      bzero (costs, nregs * sizeof (struct costs));
+      bzero ((char *) costs, nregs * sizeof (struct costs));
+
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+      bzero (in_inc_dec, nregs);
+#endif
 
       loop_depth = 0, loop_cost = 1;
 
@@ -513,7 +732,7 @@ regclass (f, nregs)
          int noperands;
 
          /* Show that an insn inside a loop is likely to be executed three
-            times more than insns outside a loop.  This is much more agressive
+            times more than insns outside a loop.  This is much more aggressive
             than the assumptions made elsewhere and is being tried as an
             experiment.  */
 
@@ -538,7 +757,8 @@ regclass (f, nregs)
                {
                  decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
                                       constraints, modes);
-                 nalternatives = n_occurrences (',', constraints[0]) + 1;
+                 nalternatives = (noperands == 0 ? 0
+                                  : n_occurrences (',', constraints[0]) + 1);
                }
              else
                {
@@ -614,7 +834,7 @@ regclass (f, nregs)
                              basic_block_head[b] = newinsn;
                        }
 
-                     /* This makes one more setting of new insns's dest. */
+                     /* This makes one more setting of new insns's dest.  */
                      reg_n_sets[REGNO (recog_operand[0])]++;
 
                      *recog_operand_loc[1] = recog_operand[0];
@@ -626,56 +846,6 @@ regclass (f, nregs)
                      continue;
                    }
 
-                 /* If this is setting a pseudo from another pseudo or the
-                    sum of a pseudo and a constant integer and the other
-                    pseudo is known to be a pointer, set the destination to
-                    be a pointer as well.
-
-                    Likewise if it is setting the destination from an address
-                    or from a value equivalent to an address or to the sum of
-                    an address and something else.
-                    
-                    But don't do any of this if the pseudo corresponds to
-                    a user variable since it should have already been set
-                    as a pointer based on the type.
-
-                    There is no point in doing this during our second
-                    pass since not enough should have changed.  */
-
-                 if (pass == 0 && set != 0 && GET_CODE (SET_DEST (set)) == REG
-                     && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
-                     && ! REG_USERVAR_P (SET_DEST (set))
-                     && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (set)))
-                     && ((GET_CODE (SET_SRC (set)) == REG
-                          && REGNO_POINTER_FLAG (REGNO (SET_SRC (set))))
-                         || ((GET_CODE (SET_SRC (set)) == PLUS
-                              || GET_CODE (SET_SRC (set)) == LO_SUM)
-                             && (GET_CODE (XEXP (SET_SRC (set), 1))
-                                 == CONST_INT)
-                             && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
-                             && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (set), 0))))
-                         || GET_CODE (SET_SRC (set)) == CONST
-                         || GET_CODE (SET_SRC (set)) == SYMBOL_REF
-                         || GET_CODE (SET_SRC (set)) == LABEL_REF
-                         || (GET_CODE (SET_SRC (set)) == HIGH
-                             && (GET_CODE (XEXP (SET_SRC (set), 0)) == CONST
-                                 || (GET_CODE (XEXP (SET_SRC (set), 0))
-                                     == SYMBOL_REF)
-                                 || (GET_CODE (XEXP (SET_SRC (set), 0))
-                                     == LABEL_REF)))
-                         || ((GET_CODE (SET_SRC (set)) == PLUS
-                              || GET_CODE (SET_SRC (set)) == LO_SUM)
-                             && (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST
-                                 || (GET_CODE (XEXP (SET_SRC (set), 1))
-                                     == SYMBOL_REF)
-                                 || (GET_CODE (XEXP (SET_SRC (set), 1))
-                                     == LABEL_REF)))
-                         || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
-                             && (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 (set))) = 1;
-
                  for (i = 0; i < noperands; i++)
                    {
                      constraints[i]
@@ -706,13 +876,11 @@ regclass (f, nregs)
                }
 
              /* Check for commutative in a separate loop so everything will
-                have been initialized.  Don't bother doing anything if the
-                second operand is a constant since that is the case
-                for which the constraints should have been written.  */
+                have been initialized.  We must do this even if one operand
+                is a constant--see addsi3 in m68k.md.  */
              
-             for (i = 0; i < noperands; i++)
-               if (constraints[i][0] == '%'
-                   && ! CONSTANT_P (recog_operand[i+1]))
+             for (i = 0; i < noperands - 1; i++)
+               if (constraints[i][0] == '%')
                  {
                    char *xconstraints[MAX_RECOG_OPERANDS];
                    int j;
@@ -772,9 +940,14 @@ regclass (f, nregs)
 
          for (class = (int) ALL_REGS - 1; class > 0; class--)
            {
-             /* Ignore classes that are too small for this operand.  */
+             /* 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])
+                 > reg_class_size[class]
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+                 || (in_inc_dec[i] && forbidden_inc_dec_class[class])
+#endif
+                 )
                ;
              else if (p->cost[class] < best_cost)
                {
@@ -795,13 +968,17 @@ regclass (f, nregs)
          if (pass == 1 || ! flag_expensive_optimizations)
            for (class = 0; class < N_REG_CLASSES; class++)
              if (p->cost[class] < p->mem_cost
-                 && (reg_class_size[reg_class_subunion[(int) alt][class]]
-                     > reg_class_size[(int) alt]))
+                 && (reg_class_size[(int) reg_class_subunion[(int) alt][class]]
+                     > reg_class_size[(int) alt])
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+                 && ! (in_inc_dec[i] && forbidden_inc_dec_class[class])
+#endif
+                 )
                alt = reg_class_subunion[(int) alt][class];
          
          /* If we don't add any classes, nothing to try.  */
          if (alt == best)
-           alt = (int) NO_REGS;
+           alt = NO_REGS;
 
          /* We cast to (int) because (char) hits bugs in some compilers.  */
          prefclass[i] = (int) best;
@@ -849,6 +1026,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
   int alt;
   enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
   int i, j;
+  rtx set;
 
   /* By default, each operand is an input operand.  */
 
@@ -886,6 +1064,9 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              continue;
            }
 
+         if (*p == '%')
+           p++;
+
          /* If this alternative is only relevant when this operand
             matches a previous operand, we do different things depending
             on whether this operand is a pseudo-reg or not.  */
@@ -898,24 +1079,35 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER)
                {
                  /* If this matches the other operand, we have no added
-                    cost.  */
+                    cost and we win.  */
                  if (rtx_equal_p (ops[j], op))
-                   ;
+                   win = 1;
 
+                 /* If we can put the other operand into a register, add to
+                    the cost of this alternative the cost to copy this
+                    operand to the register used for the other operand.  */
+
+                 else if (classes[j] != NO_REGS)
+                   alt_cost += copy_cost (op, mode, classes[j], 1), win = 1;
+               }
+             else if (GET_CODE (ops[j]) != REG
+                      || REGNO (ops[j]) < FIRST_PSEUDO_REGISTER)
+               {
+                 /* This op is a pseudo but the one it matches is not.  */
+                 
                  /* If we can't put the other operand into a register, this
                     alternative can't be used.  */
 
-                 else if (classes[j] == NO_REGS)
+                 if (classes[j] == NO_REGS)
                    alt_fail = 1;
 
                  /* Otherwise, add to the cost of this alternative the cost
-                    to copy this operand to the register used for the other
+                    to copy the other operand to the register used for this
                     operand.  */
 
                  else
-                   alt_cost += copy_cost (op, mode, classes[j], 1);
+                   alt_cost += copy_cost (ops[j], mode, classes[j], 1);
                }
-
              else
                {
                  /* The costs of this operand are the same as that of the
@@ -924,11 +1116,19 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                     instruction.  */
 
                  this_op_costs[i] = this_op_costs[j];
-                 if (! find_reg_note (insn, REG_DEAD, op))
+                 if (REGNO (ops[i]) != REGNO (ops[j])
+                     && ! find_reg_note (insn, REG_DEAD, op))
                    alt_cost += 2;
-               }
 
-             continue;
+                 /* This is in place of ordinary cost computation
+                    for this operand, so skip to the end of the
+                    alternative (should be just one character).  */
+                 while (*p && *p++ != ',')
+                   ;
+
+                 constraints[i] = p;
+                 continue;
+               }
            }
 
          /* Scan all the constraint letters.  See if the operand matches
@@ -960,7 +1160,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                break;
 
              case 'm':  case 'o':  case 'V':
-               /* It doesn't seem worth distingishing between offsettable
+               /* It doesn't seem worth distinguishing between offsettable
                   and non-offsettable addresses here.  */
                allows_mem = 1;
                if (GET_CODE (op) == MEM)
@@ -982,12 +1182,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                break;
 
              case 'E':
+#ifndef REAL_ARITHMETIC
                /* Match any floating double constant, but only if
                   we can examine the bits of it reliably.  */
                if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
                     || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
                    && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
                  break;
+#endif
                if (GET_CODE (op) == CONST_DOUBLE)
                  win = 1;
                break;
@@ -1116,7 +1318,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
          else if (win
                   || (GET_CODE (op) == REG
-                      && reg_fits_class_p (op, classes[i], 0, mode)))
+                      && reg_fits_class_p (op, classes[i], 0, GET_MODE (op))))
            ;
 
          /* If registers are valid, the cost of this alternative includes
@@ -1161,6 +1363,46 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
                                     (qq->cost[class] + alt_cost) * scale);
          }
     }
+
+  /* If this insn is a single set copying operand 1 to operand 0
+     and one is a pseudo with the other a hard reg that is in its
+     own register class, set the cost of that register class to -1.  */
+
+  if ((set = single_set (insn)) != 0
+      && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
+      && GET_CODE (ops[0]) == REG && GET_CODE (ops[1]) == REG)
+    for (i = 0; i <= 1; i++)
+      if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
+       {
+         int regno = REGNO (ops[!i]);
+         enum machine_mode mode = GET_MODE (ops[!i]);
+         int class;
+         int nr;
+
+         if (regno >= FIRST_PSEUDO_REGISTER && prefclass != 0
+             && (reg_class_size[prefclass[regno]]
+                 == CLASS_MAX_NREGS (prefclass[regno], mode)))
+           op_costs[i].cost[prefclass[regno]] = -1;
+         else if (regno < FIRST_PSEUDO_REGISTER)
+           for (class = 0; class < N_REG_CLASSES; class++)
+             if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+                 && reg_class_size[class] == CLASS_MAX_NREGS (class, mode))
+               {
+                 if (reg_class_size[class] == 1)
+                   op_costs[i].cost[class] = -1;
+                 else
+                   {
+                     for (nr = 0; nr < HARD_REGNO_NREGS(regno, mode); nr++)
+                       {
+                         if (!TEST_HARD_REG_BIT (reg_class_contents[class], regno + nr))
+                           break;
+                       }
+
+                     if (nr == HARD_REGNO_NREGS(regno,mode))
+                       op_costs[i].cost[class] = -1;
+                   }
+               }
+       }
 }
 \f
 /* Compute the cost of loading X into (if TO_P is non-zero) or from (if
@@ -1197,7 +1439,7 @@ copy_cost (x, mode, class, to_p)
     secondary_class = SECONDARY_INPUT_RELOAD_CLASS (class, mode, x);
 #endif
 
-#ifdef SECONARY_OUTPUT_RELOAD_CLASS
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
   if (! to_p)
     secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x);
 #endif
@@ -1205,7 +1447,7 @@ copy_cost (x, mode, class, to_p)
   if (secondary_class != NO_REGS)
     return (move_cost[(int) secondary_class][(int) class]
            + copy_cost (x, mode, secondary_class, 2));
-#endif  /* HAVE_SECONARY_RELOADS */
+#endif  /* HAVE_SECONDARY_RELOADS */
 
   /* For memory, use the memory move cost, for (hard) registers, use the
      cost to move between the register classes, and use 2 for everything
@@ -1345,7 +1587,14 @@ record_address_regs (x, class, scale)
     case PRE_DEC:
       /* 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.  */
+        if it ends up in the wrong place.  If the operand is a pseudo,
+        show it is being used in an INC_DEC context.  */
+
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+      if (GET_CODE (XEXP (x, 0)) == REG
+         && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
+       in_inc_dec[REGNO (XEXP (x, 0))] = 1;
+#endif
 
       record_address_regs (XEXP (x, 0), class, 2 * scale);
       break;
@@ -1372,6 +1621,41 @@ record_address_regs (x, class, scale)
       }
     }
 }
+\f
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+
+/* Return 1 if REG is valid as an auto-increment memory reference
+   to an object of MODE.  */
+
+static 
+auto_inc_dec_reg_p (reg, mode)
+     rtx reg;
+     enum machine_mode mode;
+{
+#ifdef HAVE_POST_INCREMENT
+  if (memory_address_p (mode, gen_rtx (POST_INC, Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_POST_DECREMENT
+  if (memory_address_p (mode, gen_rtx (POST_DEC, Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_PRE_INCREMENT
+  if (memory_address_p (mode, gen_rtx (PRE_INC, Pmode, reg)))
+    return 1;
+#endif
+
+#ifdef HAVE_PRE_DECREMENT
+  if (memory_address_p (mode, gen_rtx (PRE_DEC, Pmode, reg)))
+    return 1;
+#endif
+
+  return 0;
+}
+#endif
+
 #endif /* REGISTER_CONSTRAINTS */
 \f
 /* This is the `regscan' pass of the compiler, run just before cse
@@ -1393,6 +1677,11 @@ int *regno_first_uid;
 
 int *regno_last_uid;
 
+/* Indexed by pseudo register number, gives uid of last insn using the reg
+   or mentioning it in a note (as of the time reg_scan is called).  */
+
+int *regno_last_note_uid;
+
 /* Record the number of registers we used when we allocated the above two
    tables.  If we are called again with more than this, we must re-allocate
    the tables.  */
@@ -1400,13 +1689,11 @@ int *regno_last_uid;
 static int highest_regno_in_uid_map;
 
 /* Maximum number of parallel sets and clobbers in any insn in this fn.
-   Always at least 3, since the combiner could put that many togetherm
+   Always at least 3, since the combiner could put that many together
    and we want this to remain correct for all the remaining passes.  */
 
 int max_parallel;
 
-void reg_scan_mark_refs ();
-
 void
 reg_scan (f, nregs, repeat)
      rtx f;
@@ -1423,13 +1710,17 @@ reg_scan (f, nregs, repeat)
        = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
       regno_last_uid
        = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
+      regno_last_note_uid
+       = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
       reg_n_sets
        = (short *) oballoc (highest_regno_in_uid_map * sizeof (short));
     }
 
-  bzero (regno_first_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (regno_last_uid, highest_regno_in_uid_map * sizeof (int));
-  bzero (reg_n_sets, highest_regno_in_uid_map * sizeof (short));
+  bzero ((char *) regno_first_uid, highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) regno_last_uid, highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) regno_last_note_uid,
+        highest_regno_in_uid_map * sizeof (int));
+  bzero ((char *) reg_n_sets, highest_regno_in_uid_map * sizeof (short));
 
   max_parallel = 3;
 
@@ -1441,17 +1732,25 @@ reg_scan (f, nregs, repeat)
        if (GET_CODE (PATTERN (insn)) == PARALLEL
            && XVECLEN (PATTERN (insn), 0) > max_parallel)
          max_parallel = XVECLEN (PATTERN (insn), 0);
-       reg_scan_mark_refs (PATTERN (insn), INSN_UID (insn));
+       reg_scan_mark_refs (PATTERN (insn), insn, 0);
+
+       if (REG_NOTES (insn))
+         reg_scan_mark_refs (REG_NOTES (insn), insn, 1);
       }
 }
 
-void
-reg_scan_mark_refs (x, uid)
+/* X is the expression to scan.  INSN is the insn it appears in.
+   NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.  */
+
+static void
+reg_scan_mark_refs (x, insn, note_flag)
      rtx x;
-     int uid;
+     rtx insn;
+     int note_flag;
 {
   register enum rtx_code code = GET_CODE (x);
   register rtx dest;
+  register rtx note;
 
   switch (code)
     {
@@ -1470,12 +1769,26 @@ reg_scan_mark_refs (x, uid)
       {
        register int regno = REGNO (x);
 
-       regno_last_uid[regno] = uid;
+       regno_last_note_uid[regno] = INSN_UID (insn);
+       if (!note_flag)
+         regno_last_uid[regno] = INSN_UID (insn);
        if (regno_first_uid[regno] == 0)
-         regno_first_uid[regno] = uid;
+         regno_first_uid[regno] = INSN_UID (insn);
       }
       break;
 
+    case EXPR_LIST:
+      if (XEXP (x, 0))
+       reg_scan_mark_refs (XEXP (x, 0), insn, note_flag);
+      if (XEXP (x, 1))
+       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+      break;
+
+    case INSN_LIST:
+      if (XEXP (x, 1))
+       reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+      break;
+
     case SET:
       /* Count a set of the destination if it is a register.  */
       for (dest = SET_DEST (x);
@@ -1487,7 +1800,48 @@ reg_scan_mark_refs (x, uid)
       if (GET_CODE (dest) == REG)
        reg_n_sets[REGNO (dest)]++;
 
-      /* ... fall through ... */
+      /* If this is setting a pseudo from another pseudo or the sum of a
+        pseudo and a constant integer and the other pseudo is known to be
+        a pointer, set the destination to be a pointer as well.
+
+        Likewise if it is setting the destination from an address or from a
+        value equivalent to an address or to the sum of an address and
+        something else.
+                    
+        But don't do any of this if the pseudo corresponds to a user
+        variable since it should have already been set as a pointer based
+        on the type.  */
+
+      if (GET_CODE (SET_DEST (x)) == REG
+         && REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+         && ! REG_USERVAR_P (SET_DEST (x))
+         && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
+         && ((GET_CODE (SET_SRC (x)) == REG
+              && REGNO_POINTER_FLAG (REGNO (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))))
+             || GET_CODE (SET_SRC (x)) == CONST
+             || GET_CODE (SET_SRC (x)) == SYMBOL_REF
+             || GET_CODE (SET_SRC (x)) == LABEL_REF
+             || (GET_CODE (SET_SRC (x)) == HIGH
+                 && (GET_CODE (XEXP (SET_SRC (x), 0)) == CONST
+                     || GET_CODE (XEXP (SET_SRC (x), 0)) == SYMBOL_REF
+                     || GET_CODE (XEXP (SET_SRC (x), 0)) == LABEL_REF))
+             || ((GET_CODE (SET_SRC (x)) == PLUS
+                  || GET_CODE (SET_SRC (x)) == LO_SUM)
+                 && (GET_CODE (XEXP (SET_SRC (x), 1)) == CONST
+                     || GET_CODE (XEXP (SET_SRC (x), 1)) == SYMBOL_REF
+                     || GET_CODE (XEXP (SET_SRC (x), 1)) == LABEL_REF))
+             || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
+                 && (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;
+
+      /* ... fall through ...  */
 
     default:
       {
@@ -1496,12 +1850,12 @@ reg_scan_mark_refs (x, uid)
        for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
          {
            if (fmt[i] == 'e')
-             reg_scan_mark_refs (XEXP (x, i), uid);
+             reg_scan_mark_refs (XEXP (x, i), insn, note_flag);
            else if (fmt[i] == 'E' && XVEC (x, i) != 0)
              {
                register int j;
                for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-                 reg_scan_mark_refs (XVECEXP (x, i, j), uid);            
+                 reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag);
              }
          }
       }