OSDN Git Service

(push_reload): Fix last argument of the call to find_dummy_reload.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index f3e8802..4a69835 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-6, 1997 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 subroutines used only from the file reload1.c.
@@ -86,6 +87,7 @@ a register with any other reload.  */
 
 #define REG_OK_STRICT
 
+#include <stdio.h>
 #include "config.h"
 #include "rtl.h"
 #include "insn-config.h"
@@ -96,10 +98,20 @@ a register with any other reload.  */
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "real.h"
+#include "output.h"
+#include "expr.h"
 
 #ifndef REGISTER_MOVE_COST
 #define REGISTER_MOVE_COST(x, y) 2
 #endif
+
+#ifndef REGNO_MODE_OK_FOR_BASE_P
+#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
+#endif
+
+#ifndef REG_MODE_OK_FOR_BASE_P
+#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
+#endif
 \f
 /* The variables set up by `find_reloads' are:
 
@@ -141,11 +153,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 +180,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.  */
@@ -203,11 +221,11 @@ static int n_replacements;
 /* Used to track what is modified by an operand.  */
 struct decomposition
 {
-  int reg_flag;                /* Nonzero if referencing a register. */
-  int safe;            /* Nonzero if this can't conflict with anything. */
-  rtx base;            /* Base adddress for MEM. */
-  HOST_WIDE_INT start; /* Starting offset or register number. */
-  HOST_WIDE_INT end;   /* Endinf offset or register number.  */
+  int reg_flag;                /* Nonzero if referencing a register.  */
+  int safe;            /* Nonzero if this can't conflict with anything.  */
+  rtx base;            /* Base address for MEM.  */
+  HOST_WIDE_INT start; /* Starting offset or register number.  */
+  HOST_WIDE_INT end;   /* Ending offset or register number.  */
 };
 
 /* MEM-rtx's created for pseudo-regs in stack slots not directly addressable;
@@ -254,20 +272,53 @@ 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))
+
+  /* If we are going to reload an address, compute the reload type to
+     use.  */
+#define ADDR_TYPE(type)                                        \
+  ((type) == RELOAD_FOR_INPUT_ADDRESS                  \
+   ? RELOAD_FOR_INPADDR_ADDRESS                                \
+   : ((type) == RELOAD_FOR_OUTPUT_ADDRESS              \
+      ? RELOAD_FOR_OUTADDR_ADDRESS                     \
+      : (type)))
+
+static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
+                                       enum machine_mode, enum reload_type,
+                                       enum insn_code *));
+static enum reg_class find_valid_class PROTO((enum machine_mode, int));
 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 reg_class, int));
+                                      enum machine_mode, enum machine_mode,
+                                      enum reg_class, int, 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));
@@ -275,11 +326,11 @@ static int alternative_allows_memconst PROTO((char *, int));
 static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
 static rtx make_memloc         PROTO((rtx, int));
 static int find_reloads_address        PROTO((enum machine_mode, rtx *, rtx, rtx *,
-                                      int, enum reload_type, int));
+                                      int, enum reload_type, int, rtx));
 static rtx subst_reg_equivs    PROTO((rtx));
 static rtx subst_indexed_address PROTO((rtx));
-static int find_reloads_address_1 PROTO((rtx, int, rtx *, int,
-                                        enum reload_type,int));
+static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
+                                        int, enum reload_type,int, rtx));
 static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
                                             enum machine_mode, int,
                                             enum reload_type, int));
@@ -289,33 +340,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.
+   register class RELOAD_CLASS in mode RELOAD_MODE.  If secondary reloads
+   are needed, push them.
 
-   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.
+   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.  */
 
-   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)
+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 +365,29 @@ 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
+      || type == RELOAD_FOR_INPADDR_ADDRESS
+      || type == RELOAD_FOR_OUTADDR_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 paradoxical SUBREG, use the inner value to determine both the
+     mode and object being reloaded.  */
+  if (GET_CODE (x) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (x))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+    {
+      x = SUBREG_REG (x);
+      reload_mode = GET_MODE (x);
+    }
 
   /* 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 +409,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 +463,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.
 
-  return class;
+     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.
+
+     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
+               || SMALL_REGISTER_CLASSES
+#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
+           || SMALL_REGISTER_CLASSES
+#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, mode))
+       get_secondary_mem (x, mode, opnum, type);
+
+      if (! in_p && icode == CODE_FOR_nothing
+         && SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
+       get_secondary_mem (x, mode, opnum, type);
+#endif
+    }
+
+  *picode = icode;
+  return s_reload;
 }
 #endif /* HAVE_SECONDARY_RELOADS */
 \f
@@ -425,14 +641,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)
@@ -455,7 +674,7 @@ get_secondary_mem (x, mode, opnum, type)
   /* Get a version of the address doing any eliminations needed.  If that
      didn't give us a new MEM, make a new one if it isn't valid.  */
 
-  loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX);
+  loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX, 0);
   mem_valid = strict_memory_address_p (mode, XEXP (loc, 0));
 
   if (! mem_valid && loc == secondary_memlocs[(int) mode])
@@ -475,7 +694,7 @@ get_secondary_mem (x, mode, opnum, type)
               : RELOAD_OTHER);
 
       find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),
-                           opnum, type, 0);
+                           opnum, type, 0, 0);
     }
 
   secondary_memlocs_elim[(int) mode][opnum] = loc;
@@ -487,10 +706,42 @@ 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
+/* Find the largest class for which every register number plus N is valid in
+   M1 (if in range).  Abort if no such class exists.  */
+
+static enum reg_class
+find_valid_class (m1, n)
+     enum machine_mode  m1;
+     int n;
+{
+  int class;
+  int regno;
+  enum reg_class best_class;
+  int best_size = 0;
+
+  for (class = 1; class < N_REG_CLASSES; class++)
+    {
+      int bad = 0;
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++)
+       if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+           && TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
+           && ! HARD_REGNO_MODE_OK (regno + n, m1))
+         bad = 1;
+
+      if (! bad && reg_class_size[class] > best_size)
+       best_class = class, best_size = reg_class_size[class];
+    }
+
+  if (best_size == 0)
+    abort ();
+
+  return best_class;
+}
+\f
 /* Record one reload that needs to be performed.
    IN is an rtx saying where the data are to be found before this instruction.
    OUT says where they must be stored after the instruction.
@@ -538,34 +789,11 @@ push_reload (in, out, inloc, outloc, class,
 {
   register int i;
   int dont_share = 0;
+  int dont_remove_subreg = 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 = CODE_FOR_nothing;
+  enum insn_code secondary_out_icode = CODE_FOR_nothing;
 
   /* INMODE and/or OUTMODE could be VOIDmode if no mode
      has been specified for the operand.  In that case,
@@ -613,13 +841,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 +861,36 @@ 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.
 
-  if (in != 0 && GET_CODE (in) == SUBREG
+     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 SUBREG_WORD is nonzero, we
+     cannot reload just the inside since we might end up with the wrong
+     register class.  */
+
+  if (in != 0 && GET_CODE (in) == SUBREG && SUBREG_WORD (in) == 0
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+      && class != CLASS_CANNOT_CHANGE_SIZE
+#endif
       && (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 +913,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.  */
@@ -695,45 +944,52 @@ push_reload (in, out, inloc, outloc, class,
      However, we must reload the inner reg *as well as* the subreg in
      that case.  */
 
+  /* Similar issue for (SUBREG constant ...) if it was not handled by the
+     code above.  This can happen if SUBREG_WORD != 0.  */
+
   if (in != 0 && GET_CODE (in) == SUBREG
-      && GET_CODE (SUBREG_REG (in)) == REG
-      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
-      && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
-         || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
-             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
-                 > UNITS_PER_WORD)
-             && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
-                  / UNITS_PER_WORD)
-                 != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
-                                      GET_MODE (SUBREG_REG (in)))))))
+      && (CONSTANT_P (SUBREG_REG (in))
+         || (GET_CODE (SUBREG_REG (in)) == REG
+             && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+             && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in))
+                                       + SUBREG_WORD (in),
+                                       inmode)
+                 || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+                     && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                         > UNITS_PER_WORD)
+                     && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                          / UNITS_PER_WORD)
+                         != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
+                                              GET_MODE (SUBREG_REG (in)))))))))
     {
+      /* This relies on the fact that emit_reload_insns outputs the
+        instructions for input reloads of type RELOAD_OTHER in the same
+        order as the reloads.  Thus if the outer reload is also of type
+        RELOAD_OTHER, we are guaranteed that this inner reload will be
+        output before the outer reload.  */
       push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
-                  GENERAL_REGS, VOIDmode, VOIDmode, 0, 0, opnum, type);
+                  find_valid_class (inmode, SUBREG_WORD (in)),
+                  VOIDmode, VOIDmode, 0, 0, opnum, type);
+      dont_remove_subreg = 1;
     }
 
-
   /* Similarly for paradoxical and problematical SUBREGs on the output.
      Note that there is no reason we need worry about the previous value
      of SUBREG_REG (out); even if wider than out,
      storing in a subreg is entitled to clobber it all
      (except in the case of STRICT_LOW_PART,
      and in that case the constraint should label it input-output.)  */
-  if (out != 0 && GET_CODE (out) == SUBREG
+  if (out != 0 && GET_CODE (out) == SUBREG && SUBREG_WORD (out) == 0
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+      && class != CLASS_CANNOT_CHANGE_SIZE
+#endif
       && (CONSTANT_P (SUBREG_REG (out))
          || strict_low
          || (((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 +1009,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 ();
@@ -766,6 +1031,39 @@ push_reload (in, out, inloc, outloc, class,
       outmode = GET_MODE (out);
     }
 
+  /* 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.
+
+     However, we must reload the inner reg *as well as* the subreg in
+     that case.  In this case, the inner reg is an in-out reload.  */
+
+  if (out != 0 && GET_CODE (out) == SUBREG
+      && GET_CODE (SUBREG_REG (out)) == REG
+      && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
+      && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)) + SUBREG_WORD (out),
+                               outmode)
+         || (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
+                 > UNITS_PER_WORD)
+             && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
+                  / UNITS_PER_WORD)
+                 != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)),
+                                      GET_MODE (SUBREG_REG (out)))))))
+    {
+      /* This relies on the fact that emit_reload_insns outputs the
+        instructions for output reloads of type RELOAD_OTHER in reverse
+        order of the reloads.  Thus if the outer reload is also of type
+        RELOAD_OTHER, we are guaranteed that this inner reload will be
+        output after the outer reload.  */
+      dont_remove_subreg = 1;
+      push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
+                  &SUBREG_REG (out),
+                  find_valid_class (outmode, SUBREG_WORD (out)),
+                  VOIDmode, VOIDmode, 0, 0,
+                  opnum, RELOAD_OTHER);
+    }
+
   /* If IN appears in OUT, we can't share any input-only reload for IN.  */
   if (in != 0 && out != 0 && GET_CODE (out) == MEM
       && (GET_CODE (in) == REG || GET_CODE (in) == MEM)
@@ -776,14 +1074,16 @@ push_reload (in, out, inloc, outloc, class,
      simplifies some of the cases below.  */
 
   if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
-      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER)
+      && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+      && ! dont_remove_subreg)
     in = gen_rtx (REG, GET_MODE (in),
                  REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
 
   /* Similarly for OUT.  */
   if (out != 0 && GET_CODE (out) == SUBREG
       && GET_CODE (SUBREG_REG (out)) == REG
-      && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER)
+      && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
+      && ! dont_remove_subreg)
     out = gen_rtx (REG, GET_MODE (out),
                  REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
 
@@ -878,7 +1178,7 @@ push_reload (in, out, inloc, outloc, class,
             && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in))))
        && (reg_class_size[(int) class] == 1
 #ifdef SMALL_REGISTER_CLASSES
-           || 1
+           || SMALL_REGISTER_CLASSES
 #endif
            )
        && MERGABLE_RELOADS (type, reload_when_needed[i],
@@ -914,7 +1214,7 @@ push_reload (in, out, inloc, outloc, class,
               && MATCHES (XEXP (in, 0), reload_in[i])))
          && (reg_class_size[(int) class] == 1
 #ifdef SMALL_REGISTER_CLASSES
-             || 1
+             || SMALL_REGISTER_CLASSES
 #endif
              )
          && MERGABLE_RELOADS (type, reload_when_needed[i],
@@ -929,250 +1229,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);
-
-         /* 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.  */
-
-         if (type == RELOAD_FOR_INPUT && secondary_class == class)
-           abort ();
-
-         /* 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;
@@ -1185,8 +1263,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++;
@@ -1213,9 +1293,13 @@ push_reload (in, out, inloc, outloc, class,
         For example, we may now have both IN and OUT
         while the old one may have just one of them.  */
 
-      if (inmode != VOIDmode)
+      /* The modes can be different.  If they are, we want to reload in
+        the larger mode, so that the value is valid for both modes.  */
+      if (inmode != VOIDmode
+         && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (reload_inmode[i]))
        reload_inmode[i] = inmode;
-      if (outmode != VOIDmode)
+      if (outmode != VOIDmode
+         && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
        reload_outmode[i] = outmode;
       if (in != 0)
        reload_in[i] = in;
@@ -1294,7 +1378,9 @@ 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,
-                                            reload_reg_class[i], i);
+                                            inmode, outmode,
+                                            reload_reg_class[i], i,
+                                            earlyclobber_operand_p (out));
 
       /* If the outgoing register already contains the same value
         as the incoming one, we can dispense with loading it.
@@ -1424,6 +1510,7 @@ combine_reloads ()
 {
   int i;
   int output_reload = -1;
+  int secondary_out = -1;
   rtx note;
 
   /* Find the output reload; return unless there is exactly one
@@ -1446,10 +1533,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?  */
 
@@ -1457,31 +1542,32 @@ combine_reloads ()
     if (reload_in[i] && ! reload_optional[i] && ! reload_nocombine[i]
        /* Life span of this reload must not extend past main insn.  */
        && reload_when_needed[i] != RELOAD_FOR_OUTPUT_ADDRESS
+       && reload_when_needed[i] != RELOAD_FOR_OUTADDR_ADDRESS
        && reload_when_needed[i] != RELOAD_OTHER
        && (CLASS_MAX_NREGS (reload_reg_class[i], reload_inmode[i])
            == CLASS_MAX_NREGS (reload_reg_class[output_reload],
                                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]],
                            secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]))
 #endif
+       && (
 #ifdef SMALL_REGISTER_CLASSES
-       && reload_reg_class[i] == reload_reg_class[output_reload]
+           SMALL_REGISTER_CLASSES
 #else
-       && (reg_class_subset_p (reload_reg_class[i],
-                               reload_reg_class[output_reload])
-           || reg_class_subset_p (reload_reg_class[output_reload],
-                                  reload_reg_class[i]))
+           0
 #endif
+             ? reload_reg_class[i] == reload_reg_class[output_reload]
+             : (reg_class_subset_p (reload_reg_class[i],
+                                    reload_reg_class[output_reload])
+                || reg_class_subset_p (reload_reg_class[output_reload],
+                                       reload_reg_class[i])))
        && (MATCHES (reload_in[i], reload_out[output_reload])
            /* Args reversed because the first arg seems to be
               the one that we imagine being modified
@@ -1499,7 +1585,7 @@ combine_reloads ()
                                                             reload_out[output_reload]))))
        && (reg_class_size[(int) reload_reg_class[i]]
 #ifdef SMALL_REGISTER_CLASSES
-            || 1
+            || SMALL_REGISTER_CLASSES
 #endif
            )
        /* We will allow making things slightly worse by combining an
@@ -1516,16 +1602,22 @@ combine_reloads ()
        reload_out[output_reload] = 0;
        /* 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 the output reload had a secondary reload, copy it.  */
+       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)
          secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]]
            = secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]];
 #endif
-       /* If required, minimize the register class. */
+       /* If required, minimize the register class.  */
        if (reg_class_subset_p (reload_reg_class[output_reload],
                                reload_reg_class[i]))
          reload_reg_class[i] = reload_reg_class[output_reload];
@@ -1566,6 +1658,16 @@ combine_reloads ()
                              REGNO (XEXP (note, 0)))
        && (HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
            <= HARD_REGNO_NREGS (REGNO (XEXP (note, 0)), GET_MODE (XEXP (note, 0))))
+       /* Ensure that a secondary or tertiary reload for this output
+          won't want this register.  */
+        && ((secondary_out = reload_secondary_out_reload[output_reload]) == -1
+            || (! (TEST_HARD_REG_BIT
+                   (reg_class_contents[(int) reload_reg_class[secondary_out]],
+                    REGNO (XEXP (note, 0))))
+               && ((secondary_out = reload_secondary_out_reload[secondary_out]) == -1
+                   ||  ! (TEST_HARD_REG_BIT
+                          (reg_class_contents[(int) reload_reg_class[secondary_out]],
+                           REGNO (XEXP (note, 0)))))))
        && ! fixed_regs[REGNO (XEXP (note, 0))])
       {
        reload_reg_rtx[output_reload] = gen_rtx (REG,
@@ -1588,14 +1690,22 @@ combine_reloads ()
    to be computed, clear out reload_out[FOR_REAL].
 
    If FOR_REAL is -1, this should not be done, because this call
-   is just to see if a register can be found, not to find and install it.  */
+   is just to see if a register can be found, not to find and install it.
+
+   EARLYCLOBBER is non-zero if OUT is an earlyclobber operand.  This
+   puts an additional constraint on being able to use IN for OUT since
+   IN must not appear elsewhere in the insn (it is assumed that IN itself
+   is safe from the earlyclobber).  */
 
 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, earlyclobber)
      rtx real_in, real_out;
      rtx *inloc, *outloc;
+     enum machine_mode inmode, outmode;
      enum reg_class class;
      int for_real;
+     int earlyclobber;
 {
   rtx in = real_in;
   rtx out = real_out;
@@ -1605,9 +1715,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.  */
@@ -1631,7 +1741,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,
@@ -1666,7 +1776,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);
            }
        }
 
@@ -1677,7 +1787,8 @@ find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
      or if OUT dies in this insn (like the quotient in a divmod insn).
      We can't use IN unless it is dies in this insn,
      which means we must know accurately which hard regs are live.
-     Also, the result can't go in IN if IN is used within OUT.  */
+     Also, the result can't go in IN if IN is used within OUT,
+     or if OUT is an earlyclobber and IN appears elsewhere in the insn.  */
   if (hard_regs_live_known
       && GET_CODE (in) == REG
       && REGNO (in) < FIRST_PSEUDO_REGISTER
@@ -1685,14 +1796,23 @@ 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,
-                                   PATTERN (this_insn)))
+                                   PATTERN (this_insn))
+         && (! earlyclobber
+             || ! refers_to_regno_for_reload_p (regno, regno + nwords,
+                                                PATTERN (this_insn), inloc)))
        {
          int i;
          for (i = 0; i < nwords; i++)
@@ -1710,7 +1830,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);
            }
        }
     }
@@ -1722,6 +1842,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.
@@ -1916,7 +2051,7 @@ operands_match_p (x, y)
 
 int
 n_occurrences (c, s)
-     char c;
+     int c;
      char *s;
 {
   int n = 0;
@@ -2085,10 +2220,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.  */
@@ -2213,7 +2350,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.
@@ -2264,7 +2401,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)
@@ -2405,11 +2543,28 @@ 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],
-                               i, operand_type[i], ind_levels);
+                               i, operand_type[i], ind_levels, insn);
+
+         /* If we now have a simple operand where we used to have a 
+            PLUS or MULT, re-recognize and try again.  */
+         if ((GET_RTX_CLASS (GET_CODE (*recog_operand_loc[i])) == 'o'
+              || GET_CODE (*recog_operand_loc[i]) == SUBREG)
+             && (GET_CODE (recog_operand[i]) == MULT
+                 || GET_CODE (recog_operand[i]) == PLUS))
+           {
+             INSN_CODE (insn) = -1;
+             find_reloads (insn, replace, ind_levels, live_known,
+                           reload_reg_p);
+             return;
+           }
+
          substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
        }
       else if (code == MEM)
@@ -2418,7 +2573,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                                    recog_operand_loc[i],
                                    XEXP (recog_operand[i], 0),
                                    &XEXP (recog_operand[i], 0),
-                                   i, address_type[i], ind_levels))
+                                   i, address_type[i], ind_levels, insn))
            address_reloaded[i] = 1;
          substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
        }
@@ -2428,6 +2583,13 @@ 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 || GET_RTX_CLASS (code) == '1')
+       /* We can get a PLUS as an "operand" as a result of register
+          elimination.  See eliminate_regs and gen_reload.  We handle
+          a unary operator by reloading the operand.  */
+       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.
@@ -2451,7 +2613,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            {
              /* If reg_equiv_address is not a constant address, copy it,
                 since it may be shared.  */
-             rtx address = reg_equiv_address[regno];
+             /* We must rerun eliminate_regs, in case the elimination
+                offsets have changed.  */
+             rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno],
+                                                 0, NULL_RTX, 0),
+                                 0);
 
              if (rtx_varies_p (address))
                address = copy_rtx (address);
@@ -2475,7 +2641,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                                    recog_operand_loc[i],
                                    XEXP (recog_operand[i], 0),
                                    &XEXP (recog_operand[i], 0),
-                                   i, address_type[i], ind_levels);
+                                   i, address_type[i], ind_levels, insn);
              substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
            }
        }
@@ -2554,8 +2720,16 @@ 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 predicate accepts a unary operator, it means that
+             we need to reload the operand.  */
+         if (GET_RTX_CLASS (GET_CODE (operand)) == '1')
+           operand = XEXP (operand, 0);
+
          /* If the operand is a SUBREG, extract
             the REG or MEM (or maybe even a constant) within.
             (Constants can occur as a result of reg_equiv_constant.)  */
@@ -2564,25 +2738,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.  */
@@ -2690,7 +2882,9 @@ 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],
-                                          this_alternative[c], -1);
+                                          operand_mode[i], operand_mode[c],
+                                          this_alternative[c], -1,
+                                          this_alternative_earlyclobber[c]);
 
                    if (value != 0)
                      losers--;
@@ -2699,12 +2893,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;
 
@@ -2718,6 +2923,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  win = 1;
                if (CONSTANT_P (operand))
                  badop = 0;
+               constmemok = 1;
                break;
 
              case '<':
@@ -2763,6 +2969,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                        reject that case.  */
                     && (ind_levels ? offsettable_memref_p (operand)
                         : offsettable_nonstrict_memref_p (operand)))
+                   /* A reloaded auto-increment address is offsettable,
+                      because it is now just a simple register indirect.  */
+                   || (GET_CODE (operand) == MEM
+                       && address_reloaded[i]
+                       && (GET_CODE (XEXP (operand, 0)) == PRE_INC
+                           || GET_CODE (XEXP (operand, 0)) == PRE_DEC
+                           || GET_CODE (XEXP (operand, 0)) == POST_INC
+                           || GET_CODE (XEXP (operand, 0)) == POST_DEC))
                    /* Certain mem addresses will become offsettable
                       after they themselves are reloaded.  This is important;
                       we don't want our own handling of unoffsettables
@@ -2773,10 +2987,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;
 
@@ -2787,12 +3009,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                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 (operand) != VOIDmode && ! flag_pretend_float)
                  break;
+#endif
                if (GET_CODE (operand) == CONST_DOUBLE)
                  win = 1;
                break;
@@ -2910,6 +3134,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)
@@ -2930,12 +3156,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 choosing 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++;
            }
 
@@ -2953,18 +3218,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],
@@ -3138,7 +3401,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
@@ -3243,6 +3507,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)
@@ -3257,6 +3523,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])
@@ -3266,7 +3538,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)
@@ -3284,11 +3560,20 @@ 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)
-             for (j = 0; j < n_reloads; j++)
-               if (reload_opnum[j] == i
-                   && reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
-                 reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
+           if (modified[i] == RELOAD_WRITE)
+             {
+               for (j = 0; j < n_reloads; j++)
+                 {
+                   if (reload_opnum[j] == i)
+                     {
+                       if (reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
+                         reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
+                       else if (reload_when_needed[j]
+                                == RELOAD_FOR_OUTADDR_ADDRESS)
+                         reload_when_needed[j] = RELOAD_FOR_INPADDR_ADDRESS;
+                     }
+                 }
+             }
          }
        else if (goal_alternative_matched[i] == -1)
          operand_reloadnum[i] =
@@ -3415,12 +3700,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.
@@ -3473,7 +3752,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   /* If we have a pair of reloads for parts of an address, they are reloading
      the same object, the operands themselves were not reloaded, and they
      are for two operands that are supposed to match, merge the reloads and
-     change the type of the surviving reload to RELOAD_FOR_OPERAND_ADDRESS. */
+     change the type of the surviving reload to RELOAD_FOR_OPERAND_ADDRESS.  */
 
   for (i = 0; i < n_reloads; i++)
     {
@@ -3481,9 +3760,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
       for (j = i + 1; j < n_reloads; j++)
        if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
-            || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
+            || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+            || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+            || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
            && (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
-               || reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
+               || reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS
+               || reload_when_needed[j] == RELOAD_FOR_INPADDR_ADDRESS
+               || reload_when_needed[j] == RELOAD_FOR_OUTADDR_ADDRESS)
            && rtx_equal_p (reload_in[i], reload_in[j])
            && (operand_reloadnum[reload_opnum[i]] < 0
                || reload_optional[operand_reloadnum[reload_opnum[i]]])
@@ -3497,7 +3780,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              if (replacements[k].what == j)
                replacements[k].what = i;
 
-           reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+           if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+               || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
+             reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+           else
+             reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
            reload_in[j] = 0;
          }
     }
@@ -3526,12 +3813,55 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        reload_when_needed[i] = address_type[reload_opnum[i]];
 
       if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
-          || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
+          || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+          || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+          || reload_when_needed[i] == RELOAD_FOR_OUTADDR_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_when_needed[i] == RELOAD_FOR_INPADDR_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_when_needed[i] == RELOAD_FOR_OUTADDR_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;
+           }
+         if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+             || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
+           reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+         else
+           reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+       }
 
-      if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+      if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+          || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
          && operand_reloadnum[reload_opnum[i]] >= 0
          && (reload_when_needed[operand_reloadnum[reload_opnum[i]]] 
              == RELOAD_OTHER))
@@ -3549,6 +3879,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   for (i = 0; i < n_reloads; i++)
     if (reload_in[i] != 0 && reload_out[i] == 0
        && (reload_when_needed[i] == RELOAD_FOR_OPERAND_ADDRESS
+           || reload_when_needed[i] == RELOAD_FOR_OPADDR_ADDR
            || reload_when_needed[i] == RELOAD_FOR_OTHER_ADDRESS))
       for (j = 0; j < n_reloads; j++)
        if (i != j && reload_in[j] != 0 && reload_out[j] == 0
@@ -3632,7 +3963,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        if (insn_operand_address_p[insn_code_number][i])
          find_reloads_address (VOIDmode, NULL_PTR,
                                recog_operand[i], recog_operand_loc[i],
-                               i, RELOAD_FOR_INPUT, ind_levels);
+                               i, RELOAD_FOR_INPUT, ind_levels, insn);
 
       /* In these cases, we can't tell if the operand is an input
         or an output, so be conservative.  In practice it won't be
@@ -3643,7 +3974,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                              recog_operand_loc[i],
                              XEXP (recog_operand[i], 0),
                              &XEXP (recog_operand[i], 0),
-                             i, RELOAD_OTHER, ind_levels);
+                             i, RELOAD_OTHER, ind_levels, insn);
       if (code == SUBREG)
        recog_operand[i] = *recog_operand_loc[i]
          = find_reloads_toplev (recog_operand[i], i, RELOAD_OTHER,
@@ -3736,7 +4067,11 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
       else if (reg_equiv_address[regno] != 0)
        {
          /* If reg_equiv_address varies, it may be shared, so copy it.  */
-         rtx addr = reg_equiv_address[regno];
+         /* We must rerun eliminate_regs, in case the elimination
+            offsets have changed.  */
+         rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
+                                          NULL_RTX, 0),
+                          0);
 
          if (rtx_varies_p (addr))
            addr = copy_rtx (addr);
@@ -3745,7 +4080,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
          find_reloads_address (GET_MODE (x), NULL_PTR,
                                XEXP (x, 0),
-                               &XEXP (x, 0), opnum, type, ind_levels);
+                               &XEXP (x, 0), opnum, type, ind_levels, 0);
        }
       return x;
     }
@@ -3753,7 +4088,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
     {
       rtx tem = x;
       find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
-                           opnum, type, ind_levels);
+                           opnum, type, ind_levels, 0);
       return tem;
     }
 
@@ -3805,7 +4140,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
@@ -3816,21 +4151,25 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
                           || ! offsettable_memref_p (reg_equiv_mem[regno])))))
        {
          int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
-         rtx addr = (reg_equiv_address[regno] ? reg_equiv_address[regno]
-                     : XEXP (reg_equiv_mem[regno], 0));
-#if BYTES_BIG_ENDIAN
-         int size;
-         size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
-         offset += MIN (size, UNITS_PER_WORD);
-         size = GET_MODE_SIZE (GET_MODE (x));
-         offset -= MIN (size, UNITS_PER_WORD);
-#endif
+         /* We must rerun eliminate_regs, in case the elimination
+            offsets have changed.  */
+         rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
+                                          NULL_RTX, 0),
+                          0);
+         if (BYTES_BIG_ENDIAN)
+           {
+             int size;
+             size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
+             offset += MIN (size, UNITS_PER_WORD);
+             size = GET_MODE_SIZE (GET_MODE (x));
+             offset -= MIN (size, UNITS_PER_WORD);
+           }
          addr = plus_constant (addr, offset);
          x = gen_rtx (MEM, GET_MODE (x), addr);
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
          find_reloads_address (GET_MODE (x), NULL_PTR,
                                XEXP (x, 0),
-                               &XEXP (x, 0), opnum, type, ind_levels);
+                               &XEXP (x, 0), opnum, type, ind_levels, 0);
        }
 
     }
@@ -3853,7 +4192,10 @@ make_memloc (ad, regno)
      int regno;
 {
   register int i;
-  rtx tem = reg_equiv_address[regno];
+  /* We must rerun eliminate_regs, in case the elimination
+     offsets have changed.  */
+  rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX, 0),
+                 0);
 
 #if 0 /* We cannot safely reuse a memloc made here;
         if the pseudo appears twice, and its mem needs a reload,
@@ -3887,6 +4229,9 @@ make_memloc (ad, regno)
    IND_LEVELS says how many levels of indirect addressing this machine
    supports.
 
+   INSN, if nonzero, is the insn in which we do the reload.  It is used
+   to determine if we may generate output reloads.
+
    Value is nonzero if this address is reloaded or replaced as a whole.
    This is interesting to the caller if the address is an autoincrement.
 
@@ -3897,7 +4242,7 @@ make_memloc (ad, regno)
    to a hard register, and frame pointer elimination.  */
 
 static int
-find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
+find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
      enum machine_mode mode;
      rtx *memrefloc;
      rtx ad;
@@ -3905,6 +4250,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
      int opnum;
      enum reload_type type;
      int ind_levels;
+     rtx insn;
 {
   register int regno;
   rtx tem;
@@ -3928,8 +4274,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
        {
          tem = make_memloc (ad, regno);
          find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
-                               &XEXP (tem, 0), opnum, type, ind_levels);
-         push_reload (tem, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
+                               &XEXP (tem, 0), opnum, ADDR_TYPE (type),
+                               ind_levels, insn);
+         push_reload (tem, NULL_RTX, loc, NULL_PTR,
+                      reload_address_base_reg_class,
                       GET_MODE (ad), VOIDmode, 0, 0,
                       opnum, type);
          return 1;
@@ -3945,19 +4293,20 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
               && (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
                   || (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
                       && GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
-                      && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)))))
+                      && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 1)))))
        return 0;
 
       /* The only remaining case where we can avoid a reload is if this is a
         hard register that is valid as a base register and which is not the
         subject of a CLOBBER in this insn.  */
 
-      else if (regno < FIRST_PSEUDO_REGISTER && REGNO_OK_FOR_BASE_P (regno)
+      else if (regno < FIRST_PSEUDO_REGISTER
+              && REGNO_MODE_OK_FOR_BASE_P (regno, mode)
               && ! regno_clobbered_p (regno, this_insn))
        return 0;
 
       /* If we do not have one of the cases above, we must do the reload.  */
-      push_reload (ad, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
+      push_reload (ad, NULL_RTX, loc, NULL_PTR, reload_address_base_reg_class,
                   GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
       return 1;
     }
@@ -4001,7 +4350,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
         indirect addresses are valid, reload the MEM into a register.  */
       tem = ad;
       find_reloads_address (GET_MODE (ad), &tem, XEXP (ad, 0), &XEXP (ad, 0),
-                           opnum, type, ind_levels == 0 ? 0 : ind_levels - 1);
+                           opnum, ADDR_TYPE (type),
+                           ind_levels == 0 ? 0 : ind_levels - 1, insn);
 
       /* If tem was changed, then we must create a new memory reference to
         hold it and store it back into memrefloc.  */
@@ -4027,7 +4377,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
          /* Must use TEM here, not AD, since it is the one that will
             have any subexpressions reloaded, if needed.  */
          push_reload (tem, NULL_RTX, loc, NULL_PTR,
-                      BASE_REG_CLASS, GET_MODE (tem), VOIDmode, 0,
+                      reload_address_base_reg_class, GET_MODE (tem),
+                      VOIDmode, 0,
                       0, opnum, type);
          return 1;
        }
@@ -4035,20 +4386,20 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
        return 0;
     }
 
-  /* If we have address of a stack slot but it's not valid
-     (displacement is too large), compute the sum in a register.  */
+  /* If we have address of a stack slot but it's not valid because the
+     displacement is too large, compute the sum in a register.
+     Handle all base registers here, not just fp/ap/sp, because on some
+     targets (namely SH) we can also get too large displacements from
+     big-endian corrections.  */
   else if (GET_CODE (ad) == PLUS
-          && (XEXP (ad, 0) == frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || XEXP (ad, 0) == arg_pointer_rtx
-#endif
-              || XEXP (ad, 0) == stack_pointer_rtx)
+          && GET_CODE (XEXP (ad, 0)) == REG
+          && REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
+          && REG_MODE_OK_FOR_BASE_P (XEXP (ad, 0), mode)
           && GET_CODE (XEXP (ad, 1)) == CONST_INT)
     {
       /* Unshare the MEM rtx so we can safely alter it.  */
       if (memrefloc)
        {
-         rtx oldref = *memrefloc;
          *memrefloc = copy_rtx (*memrefloc);
          loc = &XEXP (*memrefloc, 0);
        }
@@ -4059,16 +4410,16 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
          /* Reload the displacement into an index reg.
             We assume the frame pointer or arg pointer is a base reg.  */
          find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
-                                    INDEX_REG_CLASS, GET_MODE (ad), opnum,
-                                    type, ind_levels);
+                                    reload_address_index_reg_class,
+                                    GET_MODE (ad), opnum, type, ind_levels);
        }
       else
        {
          /* If the sum of two regs is not necessarily valid,
             reload the sum into a base reg.
             That will at least work.  */
-         find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode,
-                                    opnum, type, ind_levels);
+         find_reloads_address_part (ad, loc, reload_address_base_reg_class,
+                                    Pmode, opnum, type, ind_levels);
        }
       return 1;
     }
@@ -4105,6 +4456,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
@@ -4115,9 +4469,11 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
                           plus_constant (XEXP (XEXP (ad, 0), 0),
                                          INTVAL (XEXP (ad, 1))),
                           XEXP (XEXP (ad, 0), 1));
-      find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+      find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0),
+                                reload_address_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 (mode, XEXP (ad, 1), 1, &XEXP (ad, 1), opnum,
+                             type, 0, insn);
 
       return 1;
     }
@@ -4125,6 +4481,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
@@ -4132,12 +4491,14 @@ 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),
+                                reload_address_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 (mode, XEXP (ad, 0), 1, &XEXP (ad, 0), opnum,
+                             type, 0, insn);
 
       return 1;
     }
@@ -4174,17 +4535,18 @@ 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);
        }
 
-      find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode, opnum, type,
+      find_reloads_address_part (ad, loc, reload_address_base_reg_class,
+                                Pmode, opnum, type,
                                 ind_levels);
       return 1;
     }
 
-  return find_reloads_address_1 (ad, 0, loc, opnum, type, ind_levels);
+  return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels,
+                                insn);
 }
 \f
 /* Find all pseudo regs appearing in AD
@@ -4347,9 +4709,11 @@ subst_indexed_address (addr)
   return addr;
 }
 \f
-/* Record the pseudo registers we must reload into hard registers
-   in a subexpression of a would-be memory address, X.
-   (This function is not called if the address we find is strictly valid.)
+/* Record the pseudo registers we must reload into hard registers in a
+   subexpression of a would-be memory address, X referring to a value
+   in mode MODE.  (This function is not called if the address we find
+   is strictly valid.)
+
    CONTEXT = 1 means we are considering regs as index regs,
    = 0 means we are considering them as base regs.
 
@@ -4358,6 +4722,9 @@ subst_indexed_address (addr)
    IND_LEVELS says how many levels of indirect addressing are
    supported at this point in the address.
 
+   INSN, if nonzero, is the insn in which we do the reload.  It is used
+   to determine if we may generate output reloads.
+
    We return nonzero if X, as a whole, is reloaded or replaced.  */
 
 /* Note that we take shortcuts assuming that no multi-reg machine mode
@@ -4367,88 +4734,127 @@ subst_indexed_address (addr)
    could have addressing modes that this does not handle right.  */
 
 static int
-find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
+find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
+     enum machine_mode mode;
      rtx x;
      int context;
      rtx *loc;
      int opnum;
      enum reload_type type;
      int ind_levels;
+     rtx insn;
 {
   register RTX_CODE code = GET_CODE (x);
 
-  if (code == PLUS)
-    {
-      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, 
-                                   ind_levels);
-         else if (REG_OK_FOR_BASE_P (op0))
-           find_reloads_address_1 (op1, 1, &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,
-                                   ind_levels);
-         else if (REG_OK_FOR_INDEX_P (op0))
-           find_reloads_address_1 (op1, 0, &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,
-                                 ind_levels);
-         find_reloads_address_1 (op0, 0, &XEXP (x, 0), opnum, type,
-                                 ind_levels);
-       }
-    }
-  else if (code == POST_INC || code == POST_DEC
-          || code == PRE_INC || code == PRE_DEC)
+  switch (code)
     {
+    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 (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
+             op0 = gen_rtx (REG, word_mode,
+                            REGNO (op0) + SUBREG_WORD (orig_op0));
+         }
+
+       if (GET_CODE (op1) == SUBREG)
+         {
+           op1 = SUBREG_REG (op1);
+           code1 = GET_CODE (op1);
+           if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
+             op1 = gen_rtx (REG, GET_MODE (op1),
+                            REGNO (op1) + SUBREG_WORD (orig_op1));
+         }
+
+       if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE 
+           || code0 == ZERO_EXTEND || code1 == MEM)
+         {
+           find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+                                   type, ind_levels, insn);
+           find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+                                   type, ind_levels, insn);
+         }
+
+       else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
+                || code1 == ZERO_EXTEND || code0 == MEM)
+         {
+           find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+                                   type, ind_levels, insn);
+           find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+                                   type, ind_levels, insn);
+         }
+
+       else if (code0 == CONST_INT || code0 == CONST
+                || code0 == SYMBOL_REF || code0 == LABEL_REF)
+         find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+                                 type, ind_levels, insn);
+
+       else if (code1 == CONST_INT || code1 == CONST
+                || code1 == SYMBOL_REF || code1 == LABEL_REF)
+         find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+                                 type, ind_levels, insn);
+
+       else if (code0 == REG && code1 == REG)
+         {
+           if (REG_OK_FOR_INDEX_P (op0)
+               && REG_MODE_OK_FOR_BASE_P (op1, mode))
+             return 0;
+           else if (REG_OK_FOR_INDEX_P (op1)
+                    && REG_MODE_OK_FOR_BASE_P (op0, mode))
+             return 0;
+           else if (REG_MODE_OK_FOR_BASE_P (op1, mode))
+             find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+                                     type, ind_levels, insn);
+           else if (REG_MODE_OK_FOR_BASE_P (op0, mode))
+             find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+                                     type, ind_levels, insn);
+           else if (REG_OK_FOR_INDEX_P (op1))
+             find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+                                     type, ind_levels, insn);
+           else if (REG_OK_FOR_INDEX_P (op0))
+             find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+                                     type, ind_levels, insn);
+           else
+             {
+               find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+                                       type, ind_levels, insn);
+               find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+                                       type, ind_levels, insn);
+             }
+         }
+
+       else if (code0 == REG)
+         {
+           find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+                                   type, ind_levels, insn);
+           find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+                                   type, ind_levels, insn);
+         }
+
+       else if (code1 == REG)
+         {
+           find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+                                   type, ind_levels, insn);
+           find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+                                   type, ind_levels, insn);
+         }
+      }
+
+      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));
@@ -4465,9 +4871,13 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
          if (reg_equiv_address[regno] != 0)
            {
              rtx tem = make_memloc (XEXP (x, 0), regno);
-             /* First reload the memory location's address.  */
+             /* First reload the memory location's address.
+                We can't use ADDR_TYPE (type) here, because we need to
+                write back the value after reading it, hence we actually
+                need two registers.  */
              find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
-                                   &XEXP (tem, 0), opnum, type, ind_levels);
+                                   &XEXP (tem, 0), opnum, type,
+                                   ind_levels, insn);
              /* Put this inside a new increment-expression.  */
              x = gen_rtx (GET_CODE (x), GET_MODE (x), tem);
              /* Proceed to reload that, as if it contained a register.  */
@@ -4488,19 +4898,53 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
            regno = reg_renumber[regno];
          if ((regno >= FIRST_PSEUDO_REGISTER
               || !(context ? REGNO_OK_FOR_INDEX_P (regno)
-                   : REGNO_OK_FOR_BASE_P (regno))))
+                   : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
            {
              register rtx link;
-
-             int reloadnum
-               = push_reload (x, NULL_RTX, loc, NULL_PTR,
-                              context ? INDEX_REG_CLASS : BASE_REG_CLASS,
-                              GET_MODE (x), GET_MODE (x), VOIDmode, 0,
-                              opnum, type);
-             reload_inc[reloadnum]
-               = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
-
-             value = 1;
+             int reloadnum;
+
+             /* If we can output the register afterwards, do so, this
+                saves the extra update.
+                We can do so if we have an INSN - i.e. no JUMP_INSN nor
+                CALL_INSN - and it does not set CC0.
+                But don't do this if we cannot directly address the
+                memory location, since this will make it harder to
+                reuse address reloads, and increses register pressure.
+                Also don't do this if we can probably update x directly.  */
+             rtx equiv = reg_equiv_mem[regno];
+             int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
+             if (insn && GET_CODE (insn) == INSN && equiv
+#ifdef HAVE_cc0
+                 && ! sets_cc0_p (PATTERN (insn))
+#endif
+                 && ! (icode != CODE_FOR_nothing
+                       && (*insn_operand_predicate[icode][0]) (equiv, Pmode)
+                       && (*insn_operand_predicate[icode][1]) (equiv, Pmode)))
+               {
+                 loc = &XEXP (x, 0);
+                 x = XEXP (x, 0);
+                 reloadnum
+                   = push_reload (x, x, loc, loc,
+                                  (context
+                                   ? reload_address_index_reg_class
+                                   : reload_address_base_reg_class),
+                                   GET_MODE (x), GET_MODE (x), VOIDmode, 0,
+                                   opnum, RELOAD_OTHER);
+               }
+             else
+               {
+                 reloadnum
+                   = push_reload (x, NULL_RTX, loc, NULL_PTR,
+                                  (context
+                                   ? reload_address_index_reg_class
+                                   : reload_address_base_reg_class),
+                                  GET_MODE (x), GET_MODE (x), VOIDmode, 0,
+                                  opnum, type);
+                 reload_inc[reloadnum]
+                   = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
+    
+                 value = 1;
+               }
 
 #ifdef AUTO_INC_DEC
              /* Update the REG_INC notes.  */
@@ -4514,6 +4958,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,12 +4975,17 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
             Note that this is actually conservative:  it would be slightly
             more efficient to use the value of SPILL_INDIRECT_LEVELS from
             reload1.c here.  */
+         /* We can't use ADDR_TYPE (type) here, because we need to
+            write back the value after reading it, hence we actually
+            need two registers.  */
          find_reloads_address (GET_MODE (x), &XEXP (x, 0),
                                XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
-                               opnum, type, ind_levels);
+                               opnum, type, ind_levels, insn);
 
          reloadnum = push_reload (x, NULL_RTX, loc, NULL_PTR,
-                                  context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                                  (context
+                                   ? reload_address_index_reg_class
+                                   : reload_address_base_reg_class),
                                   GET_MODE (x), VOIDmode, 0, 0, opnum, type);
          reload_inc[reloadnum]
            = find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
@@ -4546,95 +4996,146 @@ 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
         reload1.c here.  */
 
       find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
-                           opnum, type, ind_levels);
-
+                           opnum, ADDR_TYPE (type), ind_levels, insn);
       push_reload (*loc, NULL_RTX, loc, NULL_PTR,
-                  context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                  (context ? reload_address_index_reg_class
+                   : reload_address_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
+                                       ? reload_address_index_reg_class
+                                       : reload_address_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
+                         ? reload_address_index_reg_class
+                         : reload_address_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, ADDR_TYPE (type), ind_levels, insn);
+         }
 
-      /* 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_MODE_OK_FOR_BASE_P (regno, mode))))
+         {
+           push_reload (x, NULL_RTX, loc, NULL_PTR,
+                        (context
+                         ? reload_address_index_reg_class
+                         : reload_address_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
+                         ? reload_address_index_reg_class
+                         : reload_address_base_reg_class),
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
+      }
+      return 0;
+
+    case SUBREG:
+      if (GET_CODE (SUBREG_REG (x)) == REG)
        {
-         if (fmt[i] == 'e')
-           find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
-                                   opnum, type, ind_levels);
+         /* 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 (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
+           {
+             int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+
+             if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
+                    : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
+               {
+                 push_reload (x, NULL_RTX, loc, NULL_PTR,
+                              (context
+                               ? reload_address_index_reg_class
+                               : reload_address_base_reg_class),
+                              GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+                 return 1;
+               }
+           }
+         /* If this is a SUBREG of a pseudo-register, and the pseudo-register
+            is larger than the class size, then reload the whole SUBREG.  */
+         else
+           {
+             enum reg_class class = (context
+                                     ? reload_address_index_reg_class
+                                     : reload_address_base_reg_class);
+             if (CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
+                 > reg_class_size[class])
+               {
+                 push_reload (x, NULL_RTX, loc, NULL_PTR, 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 (mode, XEXP (x, i), context, &XEXP (x, i),
+                                 opnum, type, ind_levels, insn);
+      }
+  }
+
   return 0;
 }
 \f
@@ -4669,7 +5170,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
     {
       rtx tem = x = force_const_mem (mode, x);
       find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
-                           opnum, type, ind_levels);
+                           opnum, type, ind_levels, 0);
     }
 
   else if (GET_CODE (x) == PLUS
@@ -4681,7 +5182,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
 
       x = gen_rtx (PLUS, GET_MODE (x), XEXP (x, 0), tem);
       find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
-                           opnum, type, ind_levels);
+                           opnum, type, ind_levels, 0);
     }
 
   push_reload (x, NULL_RTX, loc, NULL_PTR, class,
@@ -4821,7 +5322,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.
@@ -4898,7 +5399,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 output 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;
@@ -5118,7 +5622,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
       if (p == 0 || GET_CODE (p) == CODE_LABEL)
        return 0;
       if (GET_CODE (p) == INSN
-         /* If we don't want spill regs ... */
+         /* If we don't want spill regs ...  */
          && (! (reload_reg_p != 0
                 && reload_reg_p != (short *) (HOST_WIDE_INT) 1)
          /* ... then ignore insns introduced by reload; they aren't useful
@@ -5207,7 +5711,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
 
   /* If we propose to get the value from the stack pointer or if GOAL is
      a MEM based on the stack pointer, we need a stable SP.  */
-  if (valueno == STACK_POINTER_REGNUM
+  if (valueno == STACK_POINTER_REGNUM || regno == STACK_POINTER_REGNUM
       || (goal_mem && reg_overlap_mentioned_for_reload_p (stack_pointer_rtx,
                                                          goal)))
     need_stable_sp = 1;
@@ -5219,7 +5723,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
   /* Reject VALUE if it was loaded from GOAL
      and is also a register that appears in the address of GOAL.  */
 
-  if (goal_mem && value == SET_DEST (PATTERN (where))
+  if (goal_mem && value == SET_DEST (single_set (where))
       && refers_to_regno_for_reload_p (valueno,
                                       (valueno
                                        + HARD_REGNO_NREGS (valueno, mode)),
@@ -5300,6 +5804,12 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
              || need_stable_sp))
        return 0;
 
+#ifdef NON_SAVING_SETJMP 
+      if (NON_SAVING_SETJMP && GET_CODE (p) == NOTE
+         && NOTE_LINE_NUMBER (p) == NOTE_INSN_SETJMP)
+       return 0;
+#endif
+
 #ifdef INSN_CLOBBERS_REGNO_P
       if ((valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
          && INSN_CLOBBERS_REGNO_P (p, valueno))
@@ -5344,6 +5854,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
              else if (goal_mem && GET_CODE (dest) == MEM
                       && ! push_operand (dest, GET_MODE (dest)))
                return 0;
+             else if (GET_CODE (dest) == MEM && regno >= FIRST_PSEUDO_REGISTER
+                      && reg_equiv_memory_loc[regno] != 0)
+               return 0;
              else if (need_stable_sp && push_operand (dest, GET_MODE (dest)))
                return 0;
            }
@@ -5390,6 +5903,51 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
                }
            }
 
+         if (GET_CODE (p) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (p))
+           {
+             rtx link;
+
+             for (link = CALL_INSN_FUNCTION_USAGE (p); XEXP (link, 1) != 0;
+                  link = XEXP (link, 1))
+               {
+                 pat = XEXP (link, 0);
+                 if (GET_CODE (pat) == CLOBBER)
+                   {
+                     register rtx dest = SET_DEST (pat);
+                     while (GET_CODE (dest) == SUBREG
+                            || GET_CODE (dest) == ZERO_EXTRACT
+                            || GET_CODE (dest) == SIGN_EXTRACT
+                            || GET_CODE (dest) == STRICT_LOW_PART)
+                       dest = XEXP (dest, 0);
+                     if (GET_CODE (dest) == REG)
+                       {
+                         register int xregno = REGNO (dest);
+                         int xnregs;
+                         if (REGNO (dest) < FIRST_PSEUDO_REGISTER)
+                           xnregs = HARD_REGNO_NREGS (xregno, GET_MODE (dest));
+                         else
+                           xnregs = 1;
+                         if (xregno < regno + nregs
+                             && xregno + xnregs > regno)
+                           return 0;
+                         if (xregno < valueno + valuenregs
+                             && xregno + xnregs > valueno)
+                           return 0;
+                         if (goal_mem_addr_varies
+                             && reg_overlap_mentioned_for_reload_p (dest,
+                                                                    goal))
+                           return 0;
+                       }
+                     else if (goal_mem && GET_CODE (dest) == MEM
+                              && ! push_operand (dest, GET_MODE (dest)))
+                       return 0;
+                     else if (need_stable_sp
+                              && push_operand (dest, GET_MODE (dest)))
+                       return 0;
+                   }
+               }
+           }
+
 #ifdef AUTO_INC_DEC
          /* If this insn auto-increments or auto-decrements
             either regno or valueno, return 0 now.
@@ -5491,3 +6049,115 @@ regno_clobbered_p (regno, insn)
 
   return 0;
 }
+
+static char *reload_when_needed_name[] =
+{
+  "RELOAD_FOR_INPUT", 
+  "RELOAD_FOR_OUTPUT", 
+  "RELOAD_FOR_INSN",
+  "RELOAD_FOR_INPUT_ADDRESS",
+  "RELOAD_FOR_INPADDR_ADDRESS",
+  "RELOAD_FOR_OUTPUT_ADDRESS",
+  "RELOAD_FOR_OUTADDR_ADDRESS",
+  "RELOAD_FOR_OPERAND_ADDRESS", 
+  "RELOAD_FOR_OPADDR_ADDR",
+  "RELOAD_OTHER", 
+  "RELOAD_FOR_OTHER_ADDRESS"
+};
+
+static char *reg_class_names[] = REG_CLASS_NAMES;
+
+/* This function is used to print the variables set by 'find_reloads' */
+
+void
+debug_reload()
+{
+  int r;
+
+  fprintf (stderr, "\nn_reloads = %d\n", n_reloads);
+
+  for (r = 0; r < n_reloads; r++)
+    {
+      fprintf (stderr, "\nRELOAD %d\n", r);
+
+      if (reload_in[r])
+       {
+         fprintf (stderr, "\nreload_in (%s) = ",
+                  GET_MODE_NAME (reload_inmode[r]));
+         debug_rtx (reload_in[r]);
+       }
+
+      if (reload_out[r])
+       {
+         fprintf (stderr, "\nreload_out (%s) = ",
+                  GET_MODE_NAME (reload_outmode[r]));
+         debug_rtx (reload_out[r]);
+       }
+
+      fprintf (stderr, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
+
+      fprintf (stderr, "%s (opnum = %d)",
+              reload_when_needed_name[(int)reload_when_needed[r]],
+              reload_opnum[r]);
+
+      if (reload_optional[r])
+       fprintf (stderr, ", optional");
+
+      if (reload_in[r])
+       fprintf (stderr, ", inc by %d\n", reload_inc[r]);
+
+      if (reload_nocombine[r])
+       fprintf (stderr, ", can't combine");
+
+      if (reload_secondary_p[r])
+       fprintf (stderr, ", secondary_reload_p");
+
+      if (reload_in_reg[r])
+       {
+         fprintf (stderr, "\nreload_in_reg:\t\t\t");
+         debug_rtx (reload_in_reg[r]);
+       }
+
+      if (reload_reg_rtx[r])
+       {
+         fprintf (stderr, "\nreload_reg_rtx:\t\t\t");
+         debug_rtx (reload_reg_rtx[r]);
+       }
+
+      if (reload_secondary_in_reload[r] != -1)
+       {
+         fprintf (stderr, "\nsecondary_in_reload = ");
+         fprintf (stderr, "%d ", reload_secondary_in_reload[r]);
+       }
+
+      if (reload_secondary_out_reload[r] != -1)
+       {
+         if (reload_secondary_in_reload[r] != -1)
+           fprintf (stderr, ", secondary_out_reload = ");
+         else
+           fprintf (stderr, "\nsecondary_out_reload = ");
+
+         fprintf (stderr, "%d", reload_secondary_out_reload[r]);
+       }
+
+
+      if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
+       {
+         fprintf (stderr, "\nsecondary_in_icode = ");
+         fprintf (stderr, "%s", insn_name[r]);
+       }
+
+      if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
+       {
+         if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
+           fprintf (stderr, ", secondary_out_icode = ");
+         else
+           fprintf (stderr, "\nsecondary_out_icode = ");
+
+         fprintf (stderr, "%s ", insn_name[r]);
+       }
+      fprintf (stderr, "\n");
+    }
+
+  fprintf (stderr, "\n");
+}