OSDN Git Service

Don't include sys/file.h for winnt; use process.h instead.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index 92038ea..57c238e 100644 (file)
@@ -1,5 +1,5 @@
 /* Search an insn for pseudo regs that must be in hard regs and are not.
-   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -141,11 +141,15 @@ a register with any other reload.  */
                           for addressing a non-reloaded mem ref,
                           or for unspecified purposes (i.e., more than one
                           of the above).
-   reload_secondary_reload int, gives the reload number of a secondary
-                          reload, when needed; otherwise -1
    reload_secondary_p    int, 1 if this is a secondary register for one
-                         or more reloads.
-   reload_secondary_icode enum insn_code, if a secondary reload is required,
+                          or more reloads.
+   reload_secondary_in_reload
+   reload_secondary_out_reload
+                         int, gives the reload number of a secondary
+                          reload, when needed; otherwise -1
+   reload_secondary_in_icode
+   reload_secondary_out_icode
+                         enum insn_code, if a secondary reload is required,
                           gives the INSN_CODE that uses the secondary
                           reload as a scratch register, or CODE_FOR_nothing
                           if the secondary reload register is to be an
@@ -164,9 +168,11 @@ rtx reload_in_reg[MAX_RELOADS];
 char reload_nocombine[MAX_RELOADS];
 int reload_opnum[MAX_RELOADS];
 enum reload_type reload_when_needed[MAX_RELOADS];
-int reload_secondary_reload[MAX_RELOADS];
 int reload_secondary_p[MAX_RELOADS];
-enum insn_code reload_secondary_icode[MAX_RELOADS];
+int reload_secondary_in_reload[MAX_RELOADS];
+int reload_secondary_out_reload[MAX_RELOADS];
+enum insn_code reload_secondary_in_icode[MAX_RELOADS];
+enum insn_code reload_secondary_out_icode[MAX_RELOADS];
 
 /* All the "earlyclobber" operands of the current insn
    are recorded here.  */
@@ -254,20 +260,43 @@ static int subst_reg_equivs_changed;
    operand, which can be different for that from the input operand.  */
 static int output_reloadnum;
 
-static enum reg_class find_secondary_reload PROTO((rtx, enum reg_class,
-                                                  enum machine_mode, int,
-                                                  enum insn_code *,
-                                                  enum machine_mode *,
-                                                  enum reg_class *,
-                                                  enum insn_code *,
-                                                  enum machine_mode *));
+  /* Compare two RTX's.  */
+#define MATCHES(x, y) \
+ (x == y || (x != 0 && (GET_CODE (x) == REG                            \
+                       ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \
+                       : rtx_equal_p (x, y) && ! side_effects_p (x))))
+
+  /* Indicates if two reloads purposes are for similar enough things that we
+     can merge their reloads.  */
+#define MERGABLE_RELOADS(when1, when2, op1, op2) \
+  ((when1) == RELOAD_OTHER || (when2) == RELOAD_OTHER  \
+   || ((when1) == (when2) && (op1) == (op2))           \
+   || ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \
+   || ((when1) == RELOAD_FOR_OPERAND_ADDRESS           \
+       && (when2) == RELOAD_FOR_OPERAND_ADDRESS)       \
+   || ((when1) == RELOAD_FOR_OTHER_ADDRESS             \
+       && (when2) == RELOAD_FOR_OTHER_ADDRESS))
+
+  /* Nonzero if these two reload purposes produce RELOAD_OTHER when merged.  */
+#define MERGE_TO_OTHER(when1, when2, op1, op2) \
+  ((when1) != (when2)                                  \
+   || ! ((op1) == (op2)                                        \
+        || (when1) == RELOAD_FOR_INPUT                 \
+        || (when1) == RELOAD_FOR_OPERAND_ADDRESS       \
+        || (when1) == RELOAD_FOR_OTHER_ADDRESS))
+
+static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
+                                       enum machine_mode, enum reload_type,
+                                       enum insn_code *));
 static int push_reload         PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
                                       enum machine_mode, enum machine_mode,
                                       int, int, int, enum reload_type));
 static void push_replacement   PROTO((rtx *, int, enum machine_mode));
 static void combine_reloads    PROTO((void));
 static rtx find_dummy_reload   PROTO((rtx, rtx, rtx *, rtx *,
+                                      enum machine_mode, enum machine_mode,
                                       enum reg_class, int));
+static int earlyclobber_operand_p PROTO((rtx));
 static int hard_reg_set_here_p PROTO((int, int, rtx));
 static struct decomposition decompose PROTO((rtx));
 static int immune_p            PROTO((rtx, rtx, struct decomposition));
@@ -289,33 +318,24 @@ static int find_inc_amount        PROTO((rtx, rtx));
 
 /* Determine if any secondary reloads are needed for loading (if IN_P is
    non-zero) or storing (if IN_P is zero) X to or from a reload register of
-   register class RELOAD_CLASS in mode RELOAD_MODE.
-
-   Return the register class of a secondary reload register, or NO_REGS if
-   none.  *PMODE is set to the mode that the register is required in.
-   If the reload register is needed as a scratch register instead of an
-   intermediate register, *PICODE is set to the insn_code of the insn to be
-   used to load or store the primary reload register; otherwise *PICODE
-   is set to CODE_FOR_nothing.
-
-   In some cases (such as storing MQ into an external memory location on
-   the RT), both an intermediate register and a scratch register.  In that
-   case, *PICODE is set to CODE_FOR_nothing, the class for the intermediate
-   register is returned, and the *PTERTIARY_... variables are set to describe
-   the scratch register.  */
-
-static enum reg_class
-find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
-                     ptertiary_class, ptertiary_icode, ptertiary_mode)
+   register class RELOAD_CLASS in mode RELOAD_MODE.  If secondary reloads
+   are needed, push them.
+
+   Return the reload number of the secondary reload we made, or -1 if
+   we didn't need one.  *PICODE is set to the insn_code to use if we do
+   need a secondary reload.  */
+
+static int
+push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
+                      type, picode)
+     int in_p;
      rtx x;
+     int opnum;
+     int optional;
      enum reg_class reload_class;
      enum machine_mode reload_mode;
-     int in_p;
+     enum reload_type type;
      enum insn_code *picode;
-     enum machine_mode *pmode;
-     enum reg_class *ptertiary_class;
-     enum insn_code *ptertiary_icode;
-     enum machine_mode *ptertiary_mode;
 {
   enum reg_class class = NO_REGS;
   enum machine_mode mode = reload_mode;
@@ -323,6 +343,16 @@ find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
   enum reg_class t_class = NO_REGS;
   enum machine_mode t_mode = VOIDmode;
   enum insn_code t_icode = CODE_FOR_nothing;
+  enum reload_type secondary_type;
+  int i;
+  int s_reload, t_reload = -1;
+
+  if (type == RELOAD_FOR_INPUT_ADDRESS || type == RELOAD_FOR_OUTPUT_ADDRESS)
+    secondary_type = type;
+  else
+    secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS;
+
+  *picode = CODE_FOR_nothing;
 
   /* If X is a pseudo-register that has an equivalent MEM (actually, if it
      is still a pseudo-register by now, it *must* have an equivalent MEM
@@ -344,10 +374,9 @@ find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
     class = SECONDARY_OUTPUT_RELOAD_CLASS (reload_class, reload_mode, x);
 #endif
 
-  /* If we don't need any secondary registers, go away; the rest of the
-     values won't be used.  */
+  /* If we don't need any secondary registers, done.  */
   if (class == NO_REGS)
-    return NO_REGS;
+    return -1;
 
   /* Get a possible insn to use.  If the predicate doesn't accept X, don't
      use the insn.  */
@@ -399,13 +428,165 @@ find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
        }
     }
 
-  *pmode = mode;
-  *picode = icode;
-  *ptertiary_class = t_class;
-  *ptertiary_mode = t_mode;
-  *ptertiary_icode = t_icode;
+  /* This case isn't valid, so fail.  Reload is allowed to use the same
+     register for RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT reloads, but
+     in the case of a secondary register, we actually need two different
+     registers for correct code.  We fail here to prevent the possibility of
+     silently generating incorrect code later.
+
+     The convention is that secondary input reloads are valid only if the
+     secondary_class is different from class.  If you have such a case, you
+     can not use secondary reloads, you must work around the problem some
+     other way.
 
-  return class;
+     Allow this when MODE is not reload_mode and assume that the generated
+     code handles this case (it does on the Alpha, which is the only place
+     this currently happens).  */
+
+  if (in_p && class == reload_class && mode == reload_mode)
+    abort ();
+
+  /* If we need a tertiary reload, see if we have one we can reuse or else
+     make a new one.  */
+
+  if (t_class != NO_REGS)
+    {
+      for (t_reload = 0; t_reload < n_reloads; t_reload++)
+       if (reload_secondary_p[t_reload]
+           && (reg_class_subset_p (t_class, reload_reg_class[t_reload])
+               || reg_class_subset_p (reload_reg_class[t_reload], t_class))
+           && ((in_p && reload_inmode[t_reload] == t_mode)
+               || (! in_p && reload_outmode[t_reload] == t_mode))
+           && ((in_p && (reload_secondary_in_icode[t_reload]
+                         == CODE_FOR_nothing))
+               || (! in_p &&(reload_secondary_out_icode[t_reload]
+                             == CODE_FOR_nothing)))
+           && (reg_class_size[(int) t_class] == 1
+#ifdef SMALL_REGISTER_CLASSES
+               || 1
+#endif
+               )
+           && MERGABLE_RELOADS (secondary_type,
+                                reload_when_needed[t_reload],
+                                opnum, reload_opnum[t_reload]))
+         {
+           if (in_p)
+             reload_inmode[t_reload] = t_mode;
+           if (! in_p)
+             reload_outmode[t_reload] = t_mode;
+
+           if (reg_class_subset_p (t_class, reload_reg_class[t_reload]))
+             reload_reg_class[t_reload] = t_class;
+
+           reload_opnum[t_reload] = MIN (reload_opnum[t_reload], opnum);
+           reload_optional[t_reload] &= optional;
+           reload_secondary_p[t_reload] = 1;
+           if (MERGE_TO_OTHER (secondary_type, reload_when_needed[t_reload],
+                               opnum, reload_opnum[t_reload]))
+             reload_when_needed[t_reload] = RELOAD_OTHER;
+         }
+
+      if (t_reload == n_reloads)
+       {
+         /* We need to make a new tertiary reload for this register class.  */
+         reload_in[t_reload] = reload_out[t_reload] = 0;
+         reload_reg_class[t_reload] = t_class;
+         reload_inmode[t_reload] = in_p ? t_mode : VOIDmode;
+         reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
+         reload_reg_rtx[t_reload] = 0;
+         reload_optional[t_reload] = optional;
+         reload_inc[t_reload] = 0;
+         /* Maybe we could combine these, but it seems too tricky.  */
+         reload_nocombine[t_reload] = 1;
+         reload_in_reg[t_reload] = 0;
+         reload_opnum[t_reload] = opnum;
+         reload_when_needed[t_reload] = secondary_type;
+         reload_secondary_in_reload[t_reload] = -1;
+         reload_secondary_out_reload[t_reload] = -1;
+         reload_secondary_in_icode[t_reload] = CODE_FOR_nothing;
+         reload_secondary_out_icode[t_reload] = CODE_FOR_nothing;
+         reload_secondary_p[t_reload] = 1;
+
+         n_reloads++;
+       }
+    }
+
+  /* See if we can reuse an existing secondary reload.  */
+  for (s_reload = 0; s_reload < n_reloads; s_reload++)
+    if (reload_secondary_p[s_reload]
+       && (reg_class_subset_p (class, reload_reg_class[s_reload])
+           || reg_class_subset_p (reload_reg_class[s_reload], class))
+       && ((in_p && reload_inmode[s_reload] == mode)
+           || (! in_p && reload_outmode[s_reload] == mode))
+       && ((in_p && reload_secondary_in_reload[s_reload] == t_reload)
+           || (! in_p && reload_secondary_out_reload[s_reload] == t_reload))
+       && ((in_p && reload_secondary_in_icode[s_reload] == t_icode)
+           || (! in_p && reload_secondary_out_icode[s_reload] == t_icode))
+       && (reg_class_size[(int) class] == 1
+#ifdef SMALL_REGISTER_CLASSES
+           || 1
+#endif
+           )
+       && MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],
+                            opnum, reload_opnum[s_reload]))
+      {
+       if (in_p)
+         reload_inmode[s_reload] = mode;
+       if (! in_p)
+         reload_outmode[s_reload] = mode;
+
+       if (reg_class_subset_p (class, reload_reg_class[s_reload]))
+         reload_reg_class[s_reload] = class;
+
+       reload_opnum[s_reload] = MIN (reload_opnum[s_reload], opnum);
+       reload_optional[s_reload] &= optional;
+       reload_secondary_p[s_reload] = 1;
+       if (MERGE_TO_OTHER (secondary_type, reload_when_needed[s_reload],
+                           opnum, reload_opnum[s_reload]))
+         reload_when_needed[s_reload] = RELOAD_OTHER;
+      }
+
+  if (s_reload == n_reloads)
+    {
+      /* We need to make a new secondary reload for this register class.  */
+      reload_in[s_reload] = reload_out[s_reload] = 0;
+      reload_reg_class[s_reload] = class;
+
+      reload_inmode[s_reload] = in_p ? mode : VOIDmode;
+      reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;
+      reload_reg_rtx[s_reload] = 0;
+      reload_optional[s_reload] = optional;
+      reload_inc[s_reload] = 0;
+      /* Maybe we could combine these, but it seems too tricky.  */
+      reload_nocombine[s_reload] = 1;
+      reload_in_reg[s_reload] = 0;
+      reload_opnum[s_reload] = opnum;
+      reload_when_needed[s_reload] = secondary_type;
+      reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
+      reload_secondary_out_reload[s_reload] = ! in_p ? t_reload : -1;
+      reload_secondary_in_icode[s_reload] = in_p ? t_icode : CODE_FOR_nothing; 
+      reload_secondary_out_icode[s_reload]
+       = ! in_p ? t_icode : CODE_FOR_nothing;
+      reload_secondary_p[s_reload] = 1;
+
+      n_reloads++;
+
+#ifdef SECONDARY_MEMORY_NEEDED
+      /* If we need a memory location to copy between the two reload regs,
+        set it up now.  */
+
+      if (in_p && icode == CODE_FOR_nothing
+         && SECONDARY_MEMORY_NEEDED (class, reload_class, reload_mode))
+       get_secondary_mem (x, reload_mode, opnum, type);
+
+      if (! in_p && icode == CODE_FOR_nothing
+         && SECONDARY_MEMORY_NEEDED (reload_class, class, reload_mode))
+       get_secondary_mem (x, reload_mode, opnum, type);
+#endif
+    }
+
+  *picode = icode;
+  return s_reload;
 }
 #endif /* HAVE_SECONDARY_RELOADS */
 \f
@@ -425,14 +606,17 @@ get_secondary_mem (x, mode, opnum, type)
   rtx loc;
   int mem_valid;
 
-  /* If MODE is narrower than a word, widen it.  This is required because
-     most machines that require these memory locations do not support
-     short load and stores from all registers (e.g., FP registers).  We could
-     possibly conditionalize this, but we lose nothing by doing the wider
-     mode.  */
+  /* By default, if MODE is narrower than a word, widen it to a word.
+     This is required because most machines that require these memory
+     locations do not support short load and stores from all registers
+     (e.g., FP registers).  */
 
+#ifdef SECONDARY_MEMORY_NEEDED_MODE
+  mode = SECONDARY_MEMORY_NEEDED_MODE (mode);
+#else
   if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
     mode = mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (mode), 0);
+#endif
 
   /* If we already have made a MEM for this operand in MODE, return it.  */
   if (secondary_memlocs_elim[(int) mode][opnum] != 0)
@@ -487,7 +671,7 @@ get_secondary_mem (x, mode, opnum, type)
 void
 clear_secondary_mem ()
 {
-  bzero (secondary_memlocs, sizeof secondary_memlocs);
+  bzero ((char *) secondary_memlocs, sizeof secondary_memlocs);
 }
 #endif /* SECONDARY_MEMORY_NEEDED */
 \f
@@ -539,33 +723,8 @@ push_reload (in, out, inloc, outloc, class,
   register int i;
   int dont_share = 0;
   rtx *in_subreg_loc = 0, *out_subreg_loc = 0;
-  int secondary_reload = -1;
-  enum insn_code secondary_icode = CODE_FOR_nothing;
-
-  /* Compare two RTX's.  */
-#define MATCHES(x, y) \
- (x == y || (x != 0 && (GET_CODE (x) == REG                            \
-                       ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \
-                       : rtx_equal_p (x, y) && ! side_effects_p (x))))
-
-  /* Indicates if two reloads purposes are for similar enough things that we
-     can merge their reloads.  */
-#define MERGABLE_RELOADS(when1, when2, op1, op2) \
-  ((when1) == RELOAD_OTHER || (when2) == RELOAD_OTHER  \
-   || ((when1) == (when2) && (op1) == (op2))           \
-   || ((when1) == RELOAD_FOR_INPUT && (when2) == RELOAD_FOR_INPUT) \
-   || ((when1) == RELOAD_FOR_OPERAND_ADDRESS           \
-       && (when2) == RELOAD_FOR_OPERAND_ADDRESS)       \
-   || ((when1) == RELOAD_FOR_OTHER_ADDRESS             \
-       && (when2) == RELOAD_FOR_OTHER_ADDRESS))
-
-  /* Nonzero if these two reload purposes produce RELOAD_OTHER when merged.  */
-#define MERGE_TO_OTHER(when1, when2, op1, op2) \
-  ((when1) != (when2)                                  \
-   || ! ((op1) == (op2)                                        \
-        || (when1) == RELOAD_FOR_INPUT                 \
-        || (when1) == RELOAD_FOR_OPERAND_ADDRESS       \
-        || (when1) == RELOAD_FOR_OTHER_ADDRESS))
+  int secondary_in_reload = -1, secondary_out_reload = -1;
+  enum insn_code secondary_in_icode, secondary_out_icode;
 
   /* INMODE and/or OUTMODE could be VOIDmode if no mode
      has been specified for the operand.  In that case,
@@ -613,13 +772,13 @@ push_reload (in, out, inloc, outloc, class,
     }
 
   /* If we are reloading a (SUBREG constant ...), really reload just the
-     inside expression in its own mode.
+     inside expression in its own mode.  Similarly for (SUBREG (PLUS ...)).
      If we have (SUBREG:M1 (MEM:M2 ...) ...) (or an inner REG that is still
      a pseudo and hence will become a MEM) with M1 wider than M2 and the
      register is a pseudo, also reload the inside expression.
      For machines that extend byte loads, do this for any SUBREG of a pseudo
-     where both M1 and M2 are a word or smaller unless they are the same
-     size.
+     where both M1 and M2 are a word or smaller, M1 is wider than M2, and
+     M2 is an integral mode that gets extended when loaded.
      Similar issue for (SUBREG:M1 (REG:M2 ...) ...) for a hard register R where
      either M1 is not valid for R or M2 is wider than a word but we only
      need one word to store an M2-sized quantity in R.
@@ -633,24 +792,31 @@ push_reload (in, out, inloc, outloc, class,
      STRICT_LOW_PART (presumably, in == out in the cas).
 
      Also reload the inner expression if it does not require a secondary
-     reload but the SUBREG does.  */
+     reload but the SUBREG does.
+
+     Finally, reload the inner expression if it is a register that is in
+     the class whose registers cannot be referenced in a different size
+     and M1 is not the same size as M2.  */
 
   if (in != 0 && GET_CODE (in) == SUBREG
       && (CONSTANT_P (SUBREG_REG (in))
+         || GET_CODE (SUBREG_REG (in)) == PLUS
          || strict_low
          || (((GET_CODE (SUBREG_REG (in)) == REG
                && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER)
               || GET_CODE (SUBREG_REG (in)) == MEM)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
-             && GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
-             && GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) <= UNITS_PER_WORD
-             && (GET_MODE_SIZE (inmode)
-                 != GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
-#else
-             && (GET_MODE_SIZE (inmode)
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+             && ((GET_MODE_SIZE (inmode)
+                  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+#ifdef LOAD_EXTEND_OP
+                 || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+                     && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                         <= UNITS_PER_WORD)
+                     && (GET_MODE_SIZE (inmode)
+                         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+                     && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
+                     && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
 #endif
-             )
+                 ))
          || (GET_CODE (SUBREG_REG (in)) == REG
              && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
              /* The case where out is nonzero
@@ -673,12 +839,21 @@ push_reload (in, out, inloc, outloc, class,
                                                SUBREG_REG (in))
                  == NO_REGS))
 #endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+         || (GET_CODE (SUBREG_REG (in)) == REG
+             && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+             && (TEST_HARD_REG_BIT
+                 (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                  REGNO (SUBREG_REG (in))))
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                 != GET_MODE_SIZE (inmode)))
+#endif
          ))
     {
       in_subreg_loc = inloc;
       inloc = &SUBREG_REG (in);
       in = *inloc;
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+#ifndef LOAD_EXTEND_OP
       if (GET_CODE (in) == MEM)
        /* This is supposed to happen only for paradoxical subregs made by
           combine.c.  (SUBREG (MEM)) isn't supposed to occur other ways.  */
@@ -724,16 +899,8 @@ push_reload (in, out, inloc, outloc, class,
          || (((GET_CODE (SUBREG_REG (out)) == REG
                && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER)
               || GET_CODE (SUBREG_REG (out)) == MEM)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
-             && GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
-             && GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) <= UNITS_PER_WORD
-             && (GET_MODE_SIZE (outmode)
-                 != GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-#else
-             && (GET_MODE_SIZE (outmode)
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
-#endif
-             )
+             && ((GET_MODE_SIZE (outmode)
+                  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))))
          || (GET_CODE (SUBREG_REG (out)) == REG
              && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
              && ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
@@ -753,12 +920,21 @@ push_reload (in, out, inloc, outloc, class,
                                                 SUBREG_REG (out))
                  == NO_REGS))
 #endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+         || (GET_CODE (SUBREG_REG (out)) == REG
+             && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
+             && (TEST_HARD_REG_BIT
+                 (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                  REGNO (SUBREG_REG (out))))
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
+                 != GET_MODE_SIZE (outmode)))
+#endif
          ))
     {
       out_subreg_loc = outloc;
       outloc = &SUBREG_REG (out);
       out = *outloc; 
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+#ifndef LOAD_EXTEND_OP
      if (GET_CODE (out) == MEM
          && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
        abort ();
@@ -929,235 +1105,28 @@ push_reload (in, out, inloc, outloc, class,
 
   if (i == n_reloads)
     {
-#ifdef HAVE_SECONDARY_RELOADS
-      enum reg_class secondary_class = NO_REGS;
-      enum reg_class secondary_out_class = NO_REGS;
-      enum machine_mode secondary_mode = inmode;
-      enum machine_mode secondary_out_mode = outmode;
-      enum insn_code secondary_icode;
-      enum insn_code secondary_out_icode = CODE_FOR_nothing;
-      enum reg_class tertiary_class = NO_REGS;
-      enum reg_class tertiary_out_class = NO_REGS;
-      enum machine_mode tertiary_mode;
-      enum machine_mode tertiary_out_mode;
-      enum insn_code tertiary_icode;
-      enum insn_code tertiary_out_icode = CODE_FOR_nothing;
-      int tertiary_reload = -1;
-
-      /* See if we need a secondary reload register to move between
-        CLASS and IN or CLASS and OUT.  Get the modes and icodes to
-        use for each of them if so.  */
+      /* See if we need a secondary reload register to move between CLASS
+        and IN or CLASS and OUT.  Get the icode and push any required reloads
+        needed for each of them if so.  */
 
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
       if (in != 0)
-       secondary_class
-         = find_secondary_reload (in, class, inmode, 1, &secondary_icode,
-                                  &secondary_mode, &tertiary_class,
-                                  &tertiary_icode, &tertiary_mode);
+       secondary_in_reload
+         = push_secondary_reload (1, in, opnum, optional, class, inmode, type,
+                                  &secondary_in_icode);
 #endif
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
       if (out != 0 && GET_CODE (out) != SCRATCH)
-       secondary_out_class
-         = find_secondary_reload (out, class, outmode, 0,
-                                  &secondary_out_icode, &secondary_out_mode,
-                                  &tertiary_out_class, &tertiary_out_icode,
-                                  &tertiary_out_mode);
-#endif
-
-      /* We can only record one secondary and one tertiary reload.  If both
-        IN and OUT need secondary reloads, we can only make an in-out
-        reload if neither need an insn and if the classes are compatible.
-        If they aren't, all we can do is abort since making two separate
-        reloads is invalid.  */
-
-      if (secondary_class != NO_REGS && secondary_out_class != NO_REGS
-         && reg_class_subset_p (secondary_out_class, secondary_class))
-       secondary_class = secondary_out_class;
-
-      if (secondary_class != NO_REGS && secondary_out_class != NO_REGS
-         && (! reg_class_subset_p (secondary_class, secondary_out_class)
-             || secondary_icode != CODE_FOR_nothing
-             || secondary_out_icode != CODE_FOR_nothing))
-       abort ();
-
-      /* If we need a secondary reload for OUT but not IN, copy the
-        information.  */
-      if (secondary_class == NO_REGS && secondary_out_class != NO_REGS)
-       {
-         secondary_class = secondary_out_class;
-         secondary_icode = secondary_out_icode;
-         tertiary_class = tertiary_out_class;
-         tertiary_icode = tertiary_out_icode;
-         tertiary_mode = tertiary_out_mode;
-       }
-
-      if (secondary_class != NO_REGS)
-       {
-         /* Secondary reloads don't conflict as badly as the primary object
-            being reload.  Specifically, we can always treat them as
-            being for an input or output address and hence allowed to be
-            reused in the same manner such address components could be
-            reused.  This is used as the reload_type for our secondary
-            reloads.  */
-
-         enum reload_type secondary_type
-           = (type == RELOAD_FOR_INPUT ? RELOAD_FOR_INPUT_ADDRESS
-              : type == RELOAD_FOR_OUTPUT ? RELOAD_FOR_OUTPUT_ADDRESS
-              : type);
-
-         /* If we need a tertiary reload, see if we have one we can reuse
-            or else make one.  */
-
-         if (tertiary_class != NO_REGS)
-           {
-             for (tertiary_reload = 0; tertiary_reload < n_reloads;
-                  tertiary_reload++)
-               if (reload_secondary_p[tertiary_reload]
-                   && (reg_class_subset_p (tertiary_class,
-                                           reload_reg_class[tertiary_reload])
-                       || reg_class_subset_p (reload_reg_class[tertiary_reload],
-                                              tertiary_class))
-                   && ((reload_inmode[tertiary_reload] == tertiary_mode)
-                       || reload_inmode[tertiary_reload] == VOIDmode)
-                   && ((reload_outmode[tertiary_reload] == tertiary_mode)
-                       || reload_outmode[tertiary_reload] == VOIDmode)
-                   && (reload_secondary_icode[tertiary_reload]
-                       == CODE_FOR_nothing)
-                   && (reg_class_size[(int) tertiary_class] == 1
-#ifdef SMALL_REGISTER_CLASSES
-                       || 1
-#endif
-                       )
-                   && MERGABLE_RELOADS (secondary_type,
-                                        reload_when_needed[tertiary_reload],
-                                        opnum, reload_opnum[tertiary_reload]))
-                 {
-                   if (tertiary_mode != VOIDmode)
-                     reload_inmode[tertiary_reload] = tertiary_mode;
-                   if (tertiary_out_mode != VOIDmode)
-                     reload_outmode[tertiary_reload] = tertiary_mode;
-                   if (reg_class_subset_p (tertiary_class,
-                                           reload_reg_class[tertiary_reload]))
-                     reload_reg_class[tertiary_reload] = tertiary_class;
-                   if (MERGE_TO_OTHER (secondary_type,
-                                       reload_when_needed[tertiary_reload],
-                                       opnum,
-                                       reload_opnum[tertiary_reload]))
-                     reload_when_needed[tertiary_reload] = RELOAD_OTHER;
-                   reload_opnum[tertiary_reload]
-                     = MIN (reload_opnum[tertiary_reload], opnum);
-                   reload_optional[tertiary_reload] &= optional;
-                   reload_secondary_p[tertiary_reload] = 1;
-                 }
-
-             if (tertiary_reload == n_reloads)
-               {
-                 /* We need to make a new tertiary reload for this register
-                    class.  */
-                 reload_in[tertiary_reload] = reload_out[tertiary_reload] = 0;
-                 reload_reg_class[tertiary_reload] = tertiary_class;
-                 reload_inmode[tertiary_reload] = tertiary_mode;
-                 reload_outmode[tertiary_reload] = tertiary_mode;
-                 reload_reg_rtx[tertiary_reload] = 0;
-                 reload_optional[tertiary_reload] = optional;
-                 reload_inc[tertiary_reload] = 0;
-                 /* Maybe we could combine these, but it seems too tricky.  */
-                 reload_nocombine[tertiary_reload] = 1;
-                 reload_in_reg[tertiary_reload] = 0;
-                 reload_opnum[tertiary_reload] = opnum;
-                 reload_when_needed[tertiary_reload] = secondary_type;
-                 reload_secondary_reload[tertiary_reload] = -1;
-                 reload_secondary_icode[tertiary_reload] = CODE_FOR_nothing;
-                 reload_secondary_p[tertiary_reload] = 1;
-
-                 n_reloads++;
-                 i = n_reloads;
-               }
-           }
-
-         /* See if we can reuse an existing secondary reload.  */
-         for (secondary_reload = 0; secondary_reload < n_reloads;
-              secondary_reload++)
-           if (reload_secondary_p[secondary_reload]
-               && (reg_class_subset_p (secondary_class,
-                                       reload_reg_class[secondary_reload])
-                   || reg_class_subset_p (reload_reg_class[secondary_reload],
-                                          secondary_class))
-               && ((reload_inmode[secondary_reload] == secondary_mode)
-                   || reload_inmode[secondary_reload] == VOIDmode)
-               && ((reload_outmode[secondary_reload] == secondary_out_mode)
-                   || reload_outmode[secondary_reload] == VOIDmode)
-               && reload_secondary_reload[secondary_reload] == tertiary_reload
-               && reload_secondary_icode[secondary_reload] == tertiary_icode
-               && (reg_class_size[(int) secondary_class] == 1
-#ifdef SMALL_REGISTER_CLASSES
-                   || 1
-#endif
-                   )
-               && MERGABLE_RELOADS (secondary_type,
-                                    reload_when_needed[secondary_reload],
-                                    opnum, reload_opnum[secondary_reload]))
-             {
-               if (secondary_mode != VOIDmode)
-                 reload_inmode[secondary_reload] = secondary_mode;
-               if (secondary_out_mode != VOIDmode)
-                 reload_outmode[secondary_reload] = secondary_out_mode;
-               if (reg_class_subset_p (secondary_class,
-                                       reload_reg_class[secondary_reload]))
-                 reload_reg_class[secondary_reload] = secondary_class;
-               if (MERGE_TO_OTHER (secondary_type,
-                                   reload_when_needed[secondary_reload],
-                                   opnum, reload_opnum[secondary_reload]))
-                 reload_when_needed[secondary_reload] = RELOAD_OTHER;
-               reload_opnum[secondary_reload]
-                 = MIN (reload_opnum[secondary_reload], opnum);
-               reload_optional[secondary_reload] &= optional;
-               reload_secondary_p[secondary_reload] = 1;
-             }
-
-         if (secondary_reload == n_reloads)
-           {
-             /* We need to make a new secondary reload for this register
-                class.  */
-             reload_in[secondary_reload] = reload_out[secondary_reload] = 0;
-             reload_reg_class[secondary_reload] = secondary_class;
-             reload_inmode[secondary_reload] = secondary_mode;
-             reload_outmode[secondary_reload] = secondary_out_mode;
-             reload_reg_rtx[secondary_reload] = 0;
-             reload_optional[secondary_reload] = optional;
-             reload_inc[secondary_reload] = 0;
-             /* Maybe we could combine these, but it seems too tricky.  */
-             reload_nocombine[secondary_reload] = 1;
-             reload_in_reg[secondary_reload] = 0;
-             reload_opnum[secondary_reload] = opnum;
-             reload_when_needed[secondary_reload] = secondary_type;
-             reload_secondary_reload[secondary_reload] = tertiary_reload;
-             reload_secondary_icode[secondary_reload] = tertiary_icode;
-             reload_secondary_p[secondary_reload] = 1;
-
-             n_reloads++;
-             i = n_reloads;
-
-#ifdef SECONDARY_MEMORY_NEEDED
-             /* If we need a memory location to copy between the two
-                reload regs, set it up now.  */
-
-             if (in != 0 && secondary_icode == CODE_FOR_nothing
-                 && SECONDARY_MEMORY_NEEDED (secondary_class, class, inmode))
-               get_secondary_mem (in, inmode, opnum, type);
-
-             if (out != 0 && secondary_icode == CODE_FOR_nothing
-                 && SECONDARY_MEMORY_NEEDED (class, secondary_class, outmode))
-               get_secondary_mem (out, outmode, opnum, type);
-#endif
-           }
-       }
+       secondary_out_reload
+         = push_secondary_reload (0, out, opnum, optional, class, outmode,
+                                  type, &secondary_out_icode);
 #endif
 
       /* We found no existing reload suitable for re-use.
         So add an additional reload.  */
 
+      i = n_reloads;
       reload_in[i] = in;
       reload_out[i] = out;
       reload_reg_class[i] = class;
@@ -1170,8 +1139,10 @@ push_reload (in, out, inloc, outloc, class,
       reload_in_reg[i] = inloc ? *inloc : 0;
       reload_opnum[i] = opnum;
       reload_when_needed[i] = type;
-      reload_secondary_reload[i] = secondary_reload;
-      reload_secondary_icode[i] = secondary_icode;
+      reload_secondary_in_reload[i] = secondary_in_reload;
+      reload_secondary_out_reload[i] = secondary_out_reload;
+      reload_secondary_in_icode[i] = secondary_in_icode;
+      reload_secondary_out_icode[i] = secondary_out_icode;
       reload_secondary_p[i] = 0;
 
       n_reloads++;
@@ -1279,6 +1250,7 @@ push_reload (in, out, inloc, outloc, class,
   if (in != 0 && out != 0 && in != out && reload_reg_rtx[i] == 0)
     {
       reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc,
+                                            inmode, outmode,
                                             reload_reg_class[i], i);
 
       /* If the outgoing register already contains the same value
@@ -1431,10 +1403,8 @@ combine_reloads ()
     return;
 
   /* If this reload is for an earlyclobber operand, we can't do anything.  */
-
-  for (i = 0; i < n_earlyclobbers; i++)
-    if (reload_out[output_reload] == reload_earlyclobbers[i])
-      return;
+  if (earlyclobber_operand_p (reload_out[output_reload]))
+    return;
 
   /* Check each input reload; can we combine it?  */
 
@@ -1448,12 +1418,9 @@ combine_reloads ()
                                reload_outmode[output_reload]))
        && reload_inc[i] == 0
        && reload_reg_rtx[i] == 0
-       /* Don't combine two reloads with different secondary reloads. */
-       && (reload_secondary_reload[i] == reload_secondary_reload[output_reload]
-           || reload_secondary_reload[i] == -1
-           || reload_secondary_reload[output_reload] == -1)
 #ifdef SECONDARY_MEMORY_NEEDED
-       /* Likewise for different secondary memory locations.  */
+       /* Don't combine two reloads with different secondary
+          memory locations.  */
        && (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]] == 0
            || secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] == 0
            || rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]],
@@ -1502,8 +1469,14 @@ combine_reloads ()
        /* The combined reload is needed for the entire insn.  */
        reload_when_needed[i] = RELOAD_OTHER;
        /* If the output reload had a secondary reload, copy it. */
-       if (reload_secondary_reload[output_reload] != -1)
-         reload_secondary_reload[i] = reload_secondary_reload[output_reload];
+       if (reload_secondary_out_reload[output_reload] != -1)
+         {
+           reload_secondary_out_reload[i]
+             = reload_secondary_out_reload[output_reload];
+           reload_secondary_out_icode[i]
+             = reload_secondary_out_icode[output_reload];
+         }
+
 #ifdef SECONDARY_MEMORY_NEEDED
        /* Copy any secondary MEM.  */
        if (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]] != 0)
@@ -1576,9 +1549,11 @@ combine_reloads ()
    is just to see if a register can be found, not to find and install it.  */
 
 static rtx
-find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
+find_dummy_reload (real_in, real_out, inloc, outloc,
+                  inmode, outmode, class, for_real)
      rtx real_in, real_out;
      rtx *inloc, *outloc;
+     enum machine_mode inmode, outmode;
      enum reg_class class;
      int for_real;
 {
@@ -1590,9 +1565,9 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
 
   /* If operands exceed a word, we can't use either of them
      unless they have the same size.  */
-  if (GET_MODE_SIZE (GET_MODE (real_out)) != GET_MODE_SIZE (GET_MODE (real_in))
-      && (GET_MODE_SIZE (GET_MODE (real_out)) > UNITS_PER_WORD
-         || GET_MODE_SIZE (GET_MODE (real_in)) > UNITS_PER_WORD))
+  if (GET_MODE_SIZE (outmode) != GET_MODE_SIZE (inmode)
+      && (GET_MODE_SIZE (outmode) > UNITS_PER_WORD
+         || GET_MODE_SIZE (inmode) > UNITS_PER_WORD))
     return 0;
 
   /* Find the inside of any subregs.  */
@@ -1616,7 +1591,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
       && REGNO (out) < FIRST_PSEUDO_REGISTER)
     {
       register int regno = REGNO (out) + out_offset;
-      int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_out));
+      int nwords = HARD_REGNO_NREGS (regno, outmode);
       rtx saved_rtx;
 
       /* When we consider whether the insn uses OUT,
@@ -1651,7 +1626,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
              if (GET_CODE (real_out) == REG)
                value = real_out;
              else
-               value = gen_rtx (REG, GET_MODE (real_out), regno);
+               value = gen_rtx (REG, outmode, regno);
            }
        }
 
@@ -1670,10 +1645,16 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
          || find_reg_note (this_insn, REG_UNUSED, real_out))
       && find_reg_note (this_insn, REG_DEAD, real_in)
       && !fixed_regs[REGNO (in)]
-      && HARD_REGNO_MODE_OK (REGNO (in), GET_MODE (out)))
+      && HARD_REGNO_MODE_OK (REGNO (in),
+                            /* The only case where out and real_out might
+                               have different modes is where real_out
+                               is a subreg, and in that case, out
+                               has a real mode.  */
+                            (GET_MODE (out) != VOIDmode
+                             ? GET_MODE (out) : outmode)))
     {
       register int regno = REGNO (in) + in_offset;
-      int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_in));
+      int nwords = HARD_REGNO_NREGS (regno, inmode);
 
       if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR)
          && ! hard_reg_set_here_p (regno, regno + nwords,
@@ -1695,7 +1676,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
              if (GET_CODE (real_in) == REG)
                value = real_in;
              else
-               value = gen_rtx (REG, GET_MODE (real_in), regno);
+               value = gen_rtx (REG, inmode, regno);
            }
        }
     }
@@ -1707,6 +1688,21 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
    whether the IN or an OUT of a reload can serve as the
    reload register.  */
 
+/* Return 1 if X is an operand of an insn that is being earlyclobbered.  */
+
+static int
+earlyclobber_operand_p (x)
+     rtx x;
+{
+  int i;
+
+  for (i = 0; i < n_earlyclobbers; i++)
+    if (reload_earlyclobbers[i] == x)
+      return 1;
+
+  return 0;
+}
+
 /* Return 1 if expression X alters a hard reg in the range
    from BEG_REGNO (inclusive) to END_REGNO (exclusive),
    either explicitly or in the guise of a pseudo-reg allocated to REGNO.
@@ -1901,7 +1897,7 @@ operands_match_p (x, y)
 
 int
 n_occurrences (c, s)
-     char c;
+     int c;
      char *s;
 {
   int n = 0;
@@ -2070,10 +2066,12 @@ immune_p (x, y, ydata)
       /* Constants and stack slots never overlap.  */
       if (CONSTANT_P (xdata.base)
          && (ydata.base == frame_pointer_rtx
+             || ydata.base == hard_frame_pointer_rtx
              || ydata.base == stack_pointer_rtx))
        return 1;
       if (CONSTANT_P (ydata.base)
          && (xdata.base == frame_pointer_rtx
+             || xdata.base == hard_frame_pointer_rtx
              || xdata.base == stack_pointer_rtx))
        return 1;
       /* If either base is variable, we don't know anything.  */
@@ -2198,7 +2196,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   /* The eliminated forms of any secondary memory locations are per-insn, so
      clear them out here.  */
 
-  bzero (secondary_memlocs_elim, sizeof secondary_memlocs_elim);
+  bzero ((char *) secondary_memlocs_elim, sizeof secondary_memlocs_elim);
 #endif
 
   /* Find what kind of insn this is.  NOPERANDS gets number of operands.
@@ -2249,7 +2247,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                               constraints, operand_mode);
          if (noperands > 0)
            {
-             bcopy (constraints, constraints1, noperands * sizeof (char *));
+             bcopy ((char *) constraints, (char *) constraints1,
+                    noperands * sizeof (char *));
              n_alternatives = n_occurrences (',', constraints[0]) + 1;
              for (i = 1; i < noperands; i++)
                if (n_alternatives != n_occurrences (',', constraints[i]) + 1)
@@ -2390,7 +2389,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
           : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT_ADDRESS
           : RELOAD_OTHER);
 
-      if (constraints[i][0] == 'p')
+      if (*constraints[i] == 0)
+       /* Ignore things like match_operator operands.  */
+       ;
+      else if (constraints[i][0] == 'p')
        {
          find_reloads_address (VOIDmode, NULL_PTR,
                                recog_operand[i], recog_operand_loc[i],
@@ -2413,6 +2415,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                                 ind_levels,
                                 set != 0
                                 && &SET_DEST (set) == recog_operand_loc[i]);
+      else if (code == PLUS)
+       /* We can get a PLUS as an "operand" as a result of
+          register elimination.  See eliminate_regs and gen_input_reload.  */
+       substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
+         = find_reloads_toplev (recog_operand[i], i, address_type[i],
+                                ind_levels, 0);
       else if (code == REG)
        {
          /* This is equivalent to calling find_reloads_toplev.
@@ -2539,6 +2547,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
             regardless of what the constraint says.  */
          int force_reload = 0;
          int offmemok = 0;
+         /* Nonzero if a constant forced into memory would be OK for this
+            operand.  */
+         int constmemok = 0;
          int earlyclobber = 0;
 
          /* If the operand is a SUBREG, extract
@@ -2549,25 +2560,43 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            {
              offset += SUBREG_WORD (operand);
              operand = SUBREG_REG (operand);
-             /* Force reload if this is a constant or if there may may
+             /* Force reload if this is a constant or PLUS or if there may may
                 be a problem accessing OPERAND in the outer mode.  */
              if (CONSTANT_P (operand)
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
-                 /* If we have a SUBREG where both the inner and outer
-                    modes are different size but no wider than a word,
-                    combine.c has made assumptions about the behavior of
-                    the machine in such register access.  If the data is,
-                    in fact, in memory we must always load using the size
-                    assumed to be in the register and let the insn do the
-                    different-sized accesses.  */
+                 || GET_CODE (operand) == PLUS
+                 /* We must force a reload of paradoxical SUBREGs
+                    of a MEM because the alignment of the inner value
+                    may not be enough to do the outer reference.  On
+                    big-endian machines, it may also reference outside
+                    the object.
+
+                    On machines that extend byte operations and we have a
+                    SUBREG where both the inner and outer modes are no wider
+                    than a word and the inner mode is narrower, is integral,
+                    and gets extended when loaded from memory, combine.c has
+                    made assumptions about the behavior of the machine in such
+                    register access.  If the data is, in fact, in memory we
+                    must always load using the size assumed to be in the
+                    register and let the insn do the different-sized 
+                    accesses.  */
                  || ((GET_CODE (operand) == MEM
                       || (GET_CODE (operand)== REG
                           && REGNO (operand) >= FIRST_PSEUDO_REGISTER))
-                     && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-                     && GET_MODE_SIZE (GET_MODE (operand)) <= UNITS_PER_WORD
-                     && (GET_MODE_SIZE (operand_mode[i])
-                         != GET_MODE_SIZE (GET_MODE (operand))))
+                     && (((GET_MODE_BITSIZE (GET_MODE (operand))
+                           < BIGGEST_ALIGNMENT)
+                          && (GET_MODE_SIZE (operand_mode[i])
+                              > GET_MODE_SIZE (GET_MODE (operand))))
+                         || (GET_CODE (operand) == MEM && BYTES_BIG_ENDIAN)
+#ifdef LOAD_EXTEND_OP
+                         || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
+                             && (GET_MODE_SIZE (GET_MODE (operand))
+                                 <= UNITS_PER_WORD)
+                             && (GET_MODE_SIZE (operand_mode[i])
+                                 > GET_MODE_SIZE (GET_MODE (operand)))
+                             && INTEGRAL_MODE_P (GET_MODE (operand))
+                             && LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
 #endif
+                         ))
                  /* Subreg of a hard reg which can't handle the subreg's mode
                     or which would handle that mode in the wrong number of
                     registers for subregging to work.  */
@@ -2675,6 +2704,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                    value
                      = find_dummy_reload (recog_operand[i], recog_operand[c],
                                           recog_operand_loc[i], recog_operand_loc[c],
+                                          operand_mode[i], operand_mode[c],
                                           this_alternative[c], -1);
 
                    if (value != 0)
@@ -2684,12 +2714,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                   we are supposed to match can be fixed with reloads.  */
                badop = 0;
                this_alternative[i] = this_alternative[c];
+
+               /* If we have to reload this operand and some previous
+                  operand also had to match the same thing as this
+                  operand, we don't know how to do that.  So reject this
+                  alternative.  */
+               if (! win || force_reload)
+                 for (j = 0; j < i; j++)
+                   if (this_alternative_matches[j]
+                       == this_alternative_matches[i])
+                     badop = 1;
+
                break;
 
              case 'p':
                /* All necessary reloads for an address_operand
                   were handled in find_reloads_address.  */
-               this_alternative[i] = (int) ALL_REGS;
+               this_alternative[i] = (int) BASE_REG_CLASS;
                win = 1;
                break;
 
@@ -2703,6 +2744,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  win = 1;
                if (CONSTANT_P (operand))
                  badop = 0;
+               constmemok = 1;
                break;
 
              case '<':
@@ -2758,10 +2800,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                            || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0))
                    || (GET_CODE (operand) == REG
                        && REGNO (operand) >= FIRST_PSEUDO_REGISTER
-                       && reg_renumber[REGNO (operand)] < 0))
+                       && reg_renumber[REGNO (operand)] < 0
+                       /* If reg_equiv_address is nonzero, we will be
+                          loading it into a register; hence it will be
+                          offsettable, but we cannot say that reg_equiv_mem
+                          is offsettable without checking.  */
+                       && ((reg_equiv_mem[REGNO (operand)] != 0
+                            && offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
+                           || (reg_equiv_address[REGNO (operand)] != 0))))
                  win = 1;
                if (CONSTANT_P (operand) || GET_CODE (operand) == MEM)
                  badop = 0;
+               constmemok = 1;
                offmemok = 1;
                break;
 
@@ -2895,6 +2945,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            this_alternative_win[i] = 1;
          else
            {
+             int const_to_mem = 0;
+
              this_alternative_offmemok[i] = offmemok;
              losers++;
              if (badop)
@@ -2915,12 +2967,51 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              else if (modified[i] != RELOAD_WRITE && no_input_reloads)
                bad = 1;
 
+             /* If this is a constant that is reloaded into the desired
+                class by copying it to memory first, count that as another
+                reload.  This is consistent with other code and is
+                required to avoid chosing another alternative when
+                the constant is moved into memory by this function on
+                an early reload pass.  Note that the test here is 
+                precisely the same as in the code below that calls
+                force_const_mem.  */
+             if (CONSTANT_P (operand)
+                 /* force_const_mem does not accept HIGH.  */
+                 && GET_CODE (operand) != HIGH
+                 && (PREFERRED_RELOAD_CLASS (operand,
+                                             (enum reg_class) this_alternative[i])
+                     == NO_REGS)
+                 && operand_mode[i] != VOIDmode)
+               {
+                 const_to_mem = 1;
+                 if (this_alternative[i] != (int) NO_REGS)
+                   losers++;
+               }
+
+             /* If we can't reload this value at all, reject this
+                alternative.  Note that we could also lose due to
+                LIMIT_RELOAD_RELOAD_CLASS, but we don't check that
+                here.  */
+
+             if (! CONSTANT_P (operand)
+                 && (enum reg_class) this_alternative[i] != NO_REGS
+                 && (PREFERRED_RELOAD_CLASS (operand,
+                                             (enum reg_class) this_alternative[i])
+                     == NO_REGS))
+               bad = 1;
+
              /* We prefer to reload pseudos over reloading other things,
                 since such reloads may be able to be eliminated later.
                 If we are reloading a SCRATCH, we won't be generating any
                 insns, just using a register, so it is also preferred. 
-                So bump REJECT in other cases.  */
-             if (GET_CODE (operand) != REG && GET_CODE (operand) != SCRATCH)
+                So bump REJECT in other cases.  Don't do this in the
+                case where we are forcing a constant into memory and
+                it will then win since we don't want to have a different
+                alternative match then.  */
+             if (! (GET_CODE (operand) == REG
+                    && REGNO (operand) >= FIRST_PSEUDO_REGISTER)
+                 && GET_CODE (operand) != SCRATCH
+                 && ! (const_to_mem && constmemok))
                reject++;
            }
 
@@ -2938,18 +3029,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
             Don't bother with this if this alternative will accept this
             operand.
 
-            Don't do this for a multiword operand, if
-            we have to worry about small classes, because making reg groups
-            harder to allocate is asking for trouble.
+            Don't do this for a multiword operand, since it is only a
+            small win and has the risk of requiring more spill registers,
+            which could cause a large loss.
 
             Don't do this if the preferred class has only one register
             because we might otherwise exhaust the class.  */
 
 
          if (! win && this_alternative[i] != (int) NO_REGS
-#ifdef SMALL_REGISTER_CLASSES
              && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-#endif
              && reg_class_size[(int) preferred_class[i]] > 1)
            {
              if (! reg_class_subset_p (this_alternative[i],
@@ -3123,7 +3212,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
          pref_or_nothing[commutative + 1] = t;
 
-         bcopy (constraints1, constraints, noperands * sizeof (char *));
+         bcopy ((char *) constraints1, (char *) constraints,
+                noperands * sizeof (char *));
          goto try_swapped;
        }
       else
@@ -3228,6 +3318,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   for (i = 0; i < noperands; i++)
     if (! goal_alternative_win[i]
        && CONSTANT_P (recog_operand[i])
+       /* force_const_mem does not accept HIGH.  */
+       && GET_CODE (recog_operand[i]) != HIGH
        && (PREFERRED_RELOAD_CLASS (recog_operand[i],
                                    (enum reg_class) goal_alternative[i])
            == NO_REGS)
@@ -3242,6 +3334,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          goal_alternative_win[i] = 1;
       }
 
+  /* Record the values of the earlyclobber operands for the caller.  */
+  if (goal_earlyclobber)
+    for (i = 0; i < noperands; i++)
+      if (goal_alternative_earlyclobber[i])
+       reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
+
   /* Now record reloads for all the operands that need them.  */
   for (i = 0; i < noperands; i++)
     if (! goal_alternative_win[i])
@@ -3251,7 +3349,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          ;
        /* Handle an operand with a nonoffsettable address
           appearing where an offsettable address will do
-          by reloading the address into a base register.  */
+          by reloading the address into a base register.
+
+          ??? We can also do this when the operand is a register and
+          reg_equiv_mem is not offsettable, but this is a bit tricky,
+          so we don't bother with it.  It may not be worth doing.  */
        else if (goal_alternative_matched[i] == -1
                 && goal_alternative_offmemok[i]
                 && GET_CODE (recog_operand[i]) == MEM)
@@ -3269,7 +3371,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
               now we are treating part of the operand as an input, so
               we must change these to RELOAD_FOR_INPUT_ADDRESS.  */
 
-           if (operand_type[i] == RELOAD_FOR_OUTPUT)
+           if (modified[i] == RELOAD_WRITE)
              for (j = 0; j < n_reloads; j++)
                if (reload_opnum[j] == i
                    && reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
@@ -3400,12 +3502,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                           0, 1, goal_alternative_matches[i], RELOAD_OTHER);
       }
   
-  /* Record the values of the earlyclobber operands for the caller.  */
-  if (goal_earlyclobber)
-    for (i = 0; i < noperands; i++)
-      if (goal_alternative_earlyclobber[i])
-       reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
-
   /* If this insn pattern contains any MATCH_DUP's, make sure that
      they will be substituted if the operands they match are substituted.
      Also do now any substitutions we already did on the operands.
@@ -3514,7 +3610,41 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
           || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
          && (operand_reloadnum[reload_opnum[i]] < 0
              || reload_optional[operand_reloadnum[reload_opnum[i]]]))
-       reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+       {
+         /* If we have a secondary reload to go along with this reload,
+            change its type to RELOAD_FOR_OPADDR_ADDR. */
+
+         if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+             && reload_secondary_in_reload[i] != -1)
+           {
+             int secondary_in_reload = reload_secondary_in_reload[i];
+
+             reload_when_needed[secondary_in_reload] = 
+               RELOAD_FOR_OPADDR_ADDR;
+
+             /* If there's a tertiary reload we have to change it also. */
+             if (secondary_in_reload > 0
+                 && reload_secondary_in_reload[secondary_in_reload] != -1)
+               reload_when_needed[reload_secondary_in_reload[secondary_in_reload]] 
+                 = RELOAD_FOR_OPADDR_ADDR;
+           }
+
+         if (reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+             && reload_secondary_out_reload[i] != -1)
+           {
+             int secondary_out_reload = reload_secondary_out_reload[i];
+
+             reload_when_needed[secondary_out_reload] = 
+               RELOAD_FOR_OPADDR_ADDR;
+
+             /* If there's a tertiary reload we have to change it also. */
+             if (secondary_out_reload
+                 && reload_secondary_out_reload[secondary_out_reload] != -1)
+               reload_when_needed[reload_secondary_out_reload[secondary_out_reload]] 
+                 = RELOAD_FOR_OPADDR_ADDR;
+           }
+         reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+       }
 
       if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
          && operand_reloadnum[reload_opnum[i]] >= 0
@@ -3540,7 +3670,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            && reload_when_needed[j] == reload_when_needed[i]
            && MATCHES (reload_in[i], reload_in[j])
            && reload_reg_class[i] == reload_reg_class[j]
-           && !reload_nocombine[i] && !reload_nocombine[j])
+           && !reload_nocombine[i] && !reload_nocombine[j]
+           && reload_reg_rtx[i] == reload_reg_rtx[j])
          {
            reload_opnum[i] = MIN (reload_opnum[i], reload_opnum[j]);
            transfer_replacements (i, j);
@@ -3789,7 +3920,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
         force a reload in that case.  So we should not do anything here.  */
 
       else if (regno >= FIRST_PSEUDO_REGISTER
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+#ifdef LOAD_EXTEND_OP
               && (GET_MODE_SIZE (GET_MODE (x))
                   <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
 #endif
@@ -4023,6 +4154,9 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
      (displacement is too large), compute the sum in a register.  */
   else if (GET_CODE (ad) == PLUS
           && (XEXP (ad, 0) == frame_pointer_rtx
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+              || XEXP (ad, 0) == hard_frame_pointer_rtx
+#endif
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
               || XEXP (ad, 0) == arg_pointer_rtx
 #endif
@@ -4032,7 +4166,6 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
       /* Unshare the MEM rtx so we can safely alter it.  */
       if (memrefloc)
        {
-         rtx oldref = *memrefloc;
          *memrefloc = copy_rtx (*memrefloc);
          loc = &XEXP (*memrefloc, 0);
        }
@@ -4089,6 +4222,9 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
           && (XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+              || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx
+#endif
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
               || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
 #endif
@@ -4109,6 +4245,9 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
           && (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+              || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx
+#endif
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
               || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
 #endif
@@ -4116,12 +4255,12 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
           && ! memory_address_p (mode, ad))
     {
       *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
+                          XEXP (XEXP (ad, 0), 0),
                           plus_constant (XEXP (XEXP (ad, 0), 1),
-                                         INTVAL (XEXP (ad, 1))),
-                          XEXP (XEXP (ad, 0), 0));
-      find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+                                         INTVAL (XEXP (ad, 1))));
+      find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), BASE_REG_CLASS,
                                 GET_MODE (ad), opnum, type, ind_levels);
-      find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), opnum, type, 0);
+      find_reloads_address_1 (XEXP (ad, 0), 1, &XEXP (ad, 0), opnum, type, 0);
 
       return 1;
     }
@@ -4158,7 +4297,6 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
       if (memrefloc && GET_CODE (ad) == SYMBOL_REF
          && CONSTANT_POOL_ADDRESS_P (ad))
        {
-         rtx oldref = *memrefloc;
          *memrefloc = copy_rtx (*memrefloc);
          loc = &XEXP (*memrefloc, 0);
        }
@@ -4361,78 +4499,107 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
 {
   register RTX_CODE code = GET_CODE (x);
 
-  if (code == PLUS)
+  switch (code)
     {
-      register rtx op0 = XEXP (x, 0);
-      register rtx op1 = XEXP (x, 1);
-      register RTX_CODE code0 = GET_CODE (op0);
-      register RTX_CODE code1 = GET_CODE (op1);
-      if (code0 == MULT || code0 == SIGN_EXTEND || code1 == MEM)
-       {
-         find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
-                                 ind_levels);
-         find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
-                                 ind_levels);
-       }
-      else if (code1 == MULT || code1 == SIGN_EXTEND || code0 == MEM)
-       {
-         find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
-                                 ind_levels);
-         find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
-                                 ind_levels);
-       }
-      else if (code0 == CONST_INT || code0 == CONST
-              || code0 == SYMBOL_REF || code0 == LABEL_REF)
-       find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type, ind_levels);
-      else if (code1 == CONST_INT || code1 == CONST
-              || code1 == SYMBOL_REF || code1 == LABEL_REF)
-       find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type, ind_levels);
-      else if (code0 == REG && code1 == REG)
-       {
-         if (REG_OK_FOR_INDEX_P (op0)
-             && REG_OK_FOR_BASE_P (op1))
-           return 0;
-         else if (REG_OK_FOR_INDEX_P (op1)
-             && REG_OK_FOR_BASE_P (op0))
-           return 0;
-         else if (REG_OK_FOR_BASE_P (op1))
-           find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type, 
+    case PLUS:
+      {
+       register rtx orig_op0 = XEXP (x, 0);
+       register rtx orig_op1 = XEXP (x, 1);
+       register RTX_CODE code0 = GET_CODE (orig_op0);
+       register RTX_CODE code1 = GET_CODE (orig_op1);
+       register rtx op0 = orig_op0;
+       register rtx op1 = orig_op1;
+
+       if (GET_CODE (op0) == SUBREG)
+         {
+           op0 = SUBREG_REG (op0);
+           code0 = GET_CODE (op0);
+         }
+
+       if (GET_CODE (op1) == SUBREG)
+         {
+           op1 = SUBREG_REG (op1);
+           code1 = GET_CODE (op1);
+         }
+
+       if (code0 == MULT || code0 == SIGN_EXTEND || code1 == MEM)
+         {
+           find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
                                    ind_levels);
-         else if (REG_OK_FOR_BASE_P (op0))
-           find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
+           find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
                                    ind_levels);
-         else if (REG_OK_FOR_INDEX_P (op1))
-           find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
+         }
+
+       else if (code1 == MULT || code1 == SIGN_EXTEND || code0 == MEM)
+         {
+           find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
                                    ind_levels);
-         else if (REG_OK_FOR_INDEX_P (op0))
-           find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
+           find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
                                    ind_levels);
-         else
-           {
-             find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
-                                     ind_levels);
-             find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
-                                     ind_levels);
-           }
-       }
-      else if (code0 == REG)
-       {
-         find_reloads_address_1 (op0, 1, &XEXP (x, 0), opnum, type,
-                                 ind_levels);
-         find_reloads_address_1 (op1, 0, &XEXP (x, 1), opnum, type,
-                                 ind_levels);
-       }
-      else if (code1 == REG)
-       {
-         find_reloads_address_1 (op1, 1, &XEXP (x, 1), opnum, type,
+         }
+
+       else if (code0 == CONST_INT || code0 == CONST
+                || code0 == SYMBOL_REF || code0 == LABEL_REF)
+         find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
                                  ind_levels);
-         find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
+
+       else if (code1 == CONST_INT || code1 == CONST
+                || code1 == SYMBOL_REF || code1 == LABEL_REF)
+         find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
                                  ind_levels);
-       }
-    }
-  else if (code == POST_INC || code == POST_DEC
-          || code == PRE_INC || code == PRE_DEC)
-    {
+
+       else if (code0 == REG && code1 == REG)
+         {
+           if (REG_OK_FOR_INDEX_P (op0)
+               && REG_OK_FOR_BASE_P (op1))
+             return 0;
+           else if (REG_OK_FOR_INDEX_P (op1)
+                    && REG_OK_FOR_BASE_P (op0))
+             return 0;
+           else if (REG_OK_FOR_BASE_P (op1))
+             find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type, 
+                                     ind_levels);
+           else if (REG_OK_FOR_BASE_P (op0))
+             find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
+                                     ind_levels);
+           else if (REG_OK_FOR_INDEX_P (op1))
+             find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
+                                     ind_levels);
+           else if (REG_OK_FOR_INDEX_P (op0))
+           find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+                                   ind_levels);
+           else
+             {
+               find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+                                       ind_levels);
+               find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+                                       ind_levels);
+             }
+         }
+
+       else if (code0 == REG)
+         {
+           find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
+                                   ind_levels);
+           find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
+                                   ind_levels);
+         }
+
+       else if (code1 == REG)
+         {
+           find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
+                                   ind_levels);
+           find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
+                                   ind_levels);
+         }
+      }
+
+      return 0;
+
+    case POST_INC:
+    case POST_DEC:
+    case PRE_INC:
+    case PRE_DEC:
       if (GET_CODE (XEXP (x, 0)) == REG)
        {
          register int regno = REGNO (XEXP (x, 0));
@@ -4498,6 +4665,7 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
            }
          return value;
        }
+
       else if (GET_CODE (XEXP (x, 0)) == MEM)
        {
          /* This is probably the result of a substitution, by eliminate_regs,
@@ -4530,16 +4698,16 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
 
          return 1;
        }
-    }
-  else if (code == MEM)
-    {
-      /* This is probably the result of a substitution, by eliminate_regs,
-        of an equivalent address for a pseudo that was not allocated to a
-        hard register.  Verify that the specified address is valid and reload
-        it into a register.
+      return 0;
 
-        Since we know we are going to reload this item, don't decrement
-        for the indirection level.
+    case MEM:
+      /* This is probably the result of a substitution, by eliminate_regs, of
+        an equivalent address for a pseudo that was not allocated to a hard
+        register.  Verify that the specified address is valid and reload it
+        into a register.
+
+        Since we know we are going to reload this item, don't decrement for
+        the indirection level.
 
         Note that this is actually conservative:  it would be slightly more
         efficient to use the value of SPILL_INDIRECT_LEVELS from
@@ -4547,78 +4715,102 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
 
       find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
                            opnum, type, ind_levels);
-
       push_reload (*loc, NULL_RTX, loc, NULL_PTR,
                   context ? INDEX_REG_CLASS : BASE_REG_CLASS,
                   GET_MODE (x), VOIDmode, 0, 0, opnum, type);
       return 1;
-    }
-  else if (code == REG)
-    {
-      register int regno = REGNO (x);
 
-      if (reg_equiv_constant[regno] != 0)
-       {
-         find_reloads_address_part (reg_equiv_constant[regno], loc, 
-                                    (context ? INDEX_REG_CLASS
-                                     : BASE_REG_CLASS),
-                                    GET_MODE (x), opnum, type, ind_levels);
-         return 1;
-       }
+    case REG:
+      {
+       register int regno = REGNO (x);
+
+       if (reg_equiv_constant[regno] != 0)
+         {
+           find_reloads_address_part (reg_equiv_constant[regno], loc, 
+                                      (context ? INDEX_REG_CLASS
+                                       : BASE_REG_CLASS),
+                                      GET_MODE (x), opnum, type, ind_levels);
+           return 1;
+         }
 
 #if 0 /* This might screw code in reload1.c to delete prior output-reload
         that feeds this insn.  */
-      if (reg_equiv_mem[regno] != 0)
-       {
-         push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
-                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
-                      GET_MODE (x), VOIDmode, 0, 0, opnum, type);
-         return 1;
-       }
+       if (reg_equiv_mem[regno] != 0)
+         {
+           push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
+                        context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
 #endif
-      if (reg_equiv_address[regno] != 0)
-       {
-         x = make_memloc (x, regno);
-         find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
-                               opnum, type, ind_levels);
-       }
 
-      if (reg_renumber[regno] >= 0)
-       regno = reg_renumber[regno];
-      if ((regno >= FIRST_PSEUDO_REGISTER
-          || !(context ? REGNO_OK_FOR_INDEX_P (regno)
-               : REGNO_OK_FOR_BASE_P (regno))))
-       {
-         push_reload (x, NULL_RTX, loc, NULL_PTR,
-                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
-                      GET_MODE (x), VOIDmode, 0, 0, opnum, type);
-         return 1;
-       }
+       if (reg_equiv_address[regno] != 0)
+         {
+           x = make_memloc (x, regno);
+           find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
+                                 opnum, type, ind_levels);
+         }
 
-      /* If a register appearing in an address is the subject of a CLOBBER
-        in this insn, reload it into some other register to be safe.
-        The CLOBBER is supposed to make the register unavailable
-        from before this insn to after it.  */
-      if (regno_clobbered_p (regno, this_insn))
-       {
-         push_reload (x, NULL_RTX, loc, NULL_PTR,
-                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
-                      GET_MODE (x), VOIDmode, 0, 0, opnum, type);
-         return 1;
-       }
-    }
-  else
-    {
-      register char *fmt = GET_RTX_FORMAT (code);
-      register int i;
-      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       if (reg_renumber[regno] >= 0)
+         regno = reg_renumber[regno];
+
+       if ((regno >= FIRST_PSEUDO_REGISTER
+            || !(context ? REGNO_OK_FOR_INDEX_P (regno)
+                 : REGNO_OK_FOR_BASE_P (regno))))
+         {
+           push_reload (x, NULL_RTX, loc, NULL_PTR,
+                        context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
+
+       /* If a register appearing in an address is the subject of a CLOBBER
+          in this insn, reload it into some other register to be safe.
+          The CLOBBER is supposed to make the register unavailable
+          from before this insn to after it.  */
+       if (regno_clobbered_p (regno, this_insn))
+         {
+           push_reload (x, NULL_RTX, loc, NULL_PTR,
+                        context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
+      }
+      return 0;
+
+    case SUBREG:
+      /* If this is a SUBREG of a hard register and the resulting register is
+        of the wrong class, reload the whole SUBREG.  This avoids needless
+        copies if SUBREG_REG is multi-word.  */
+      if (GET_CODE (SUBREG_REG (x)) == REG
+         && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
        {
-         if (fmt[i] == 'e')
-           find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
-                                   opnum, type, ind_levels);
+         int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+
+         if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
+                : REGNO_OK_FOR_BASE_P (regno)))
+           {
+             push_reload (x, NULL_RTX, loc, NULL_PTR,
+                          context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                          GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+             return 1;
+           }
        }
+      break;
     }
 
+  {
+    register char *fmt = GET_RTX_FORMAT (code);
+    register int i;
+
+    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+      {
+       if (fmt[i] == 'e')
+         find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
+                                 opnum, type, ind_levels);
+      }
+  }
+
   return 0;
 }
 \f
@@ -4805,7 +4997,7 @@ find_replacement (loc)
 \f
 /* Return nonzero if register in range [REGNO, ENDREGNO)
    appears either explicitly or implicitly in X
-   other than being stored into.
+   other than being stored into (except for earlyclobber operands).
 
    References contained within the substructure at LOC do not count.
    LOC may be zero, meaning don't ignore anything.
@@ -4882,7 +5074,10 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
               && refers_to_regno_for_reload_p (regno, endregno,
                                                SUBREG_REG (SET_DEST (x)),
                                                loc))
-             || (GET_CODE (SET_DEST (x)) != REG
+             /* If the ouput is an earlyclobber operand, this is
+                a conflict.  */
+             || ((GET_CODE (SET_DEST (x)) != REG
+                  || earlyclobber_operand_p (SET_DEST (x)))
                  && refers_to_regno_for_reload_p (regno, endregno,
                                                   SET_DEST (x), loc))))
        return 1;