Initial revision
authorRichard Kenner <kenner@gcc.gnu.org>
Fri, 28 Feb 1992 10:23:25 +0000 (05:23 -0500)
committerRichard Kenner <kenner@gcc.gnu.org>
Fri, 28 Feb 1992 10:23:25 +0000 (05:23 -0500)
From-SVN: r363

gcc/reload.c [new file with mode: 0644]

diff --git a/gcc/reload.c b/gcc/reload.c
new file mode 100644 (file)
index 0000000..abb874f
--- /dev/null
@@ -0,0 +1,4770 @@
+/* Search an insn for pseudo regs that must be in hard regs and are not.
+   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+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.  */
+
+
+/* This file contains subroutines used only from the file reload1.c.
+   It knows how to scan one insn for operands and values
+   that need to be copied into registers to make valid code.
+   It also finds other operands and values which are valid
+   but for which equivalent values in registers exist and
+   ought to be used instead.
+
+   Before processing the first insn of the function, call `init_reload'.
+
+   To scan an insn, call `find_reloads'.  This does two things:
+   1. sets up tables describing which values must be reloaded
+   for this insn, and what kind of hard regs they must be reloaded into;
+   2. optionally record the locations where those values appear in
+   the data, so they can be replaced properly later.
+   This is done only if the second arg to `find_reloads' is nonzero.
+
+   The third arg to `find_reloads' specifies the number of levels
+   of indirect addressing supported by the machine.  If it is zero,
+   indirect addressing is not valid.  If it is one, (MEM (REG n))
+   is valid even if (REG n) did not get a hard register; if it is two,
+   (MEM (MEM (REG n))) is also valid even if (REG n) did not get a
+   hard register, and similarly for higher values.
+
+   Then you must choose the hard regs to reload those pseudo regs into,
+   and generate appropriate load insns before this insn and perhaps
+   also store insns after this insn.  Set up the array `reload_reg_rtx'
+   to contain the REG rtx's for the registers you used.  In some
+   cases `find_reloads' will return a nonzero value in `reload_reg_rtx'
+   for certain reloads.  Then that tells you which register to use,
+   so you do not need to allocate one.  But you still do need to add extra
+   instructions to copy the value into and out of that register.
+
+   Finally you must call `subst_reloads' to substitute the reload reg rtx's
+   into the locations already recorded.
+
+NOTE SIDE EFFECTS:
+
+   find_reloads can alter the operands of the instruction it is called on.
+
+   1. Two operands of any sort may be interchanged, if they are in a
+   commutative instruction.
+   This happens only if find_reloads thinks the instruction will compile
+   better that way.
+
+   2. Pseudo-registers that are equivalent to constants are replaced
+   with those constants if they are not in hard registers.
+
+1 happens every time find_reloads is called.
+2 happens only when REPLACE is 1, which is only when
+actually doing the reloads, not when just counting them.
+
+
+Using a reload register for several reloads in one insn:
+
+When an insn has reloads, it is considered as having three parts:
+the input reloads, the insn itself after reloading, and the output reloads.
+Reloads of values used in memory addresses are often needed for only one part.
+
+When this is so, reload_when_needed records which part needs the reload.
+Two reloads for different parts of the insn can share the same reload
+register.
+
+When a reload is used for addresses in multiple parts, or when it is
+an ordinary operand, it is classified as RELOAD_OTHER, and cannot share
+a register with any other reload.  */
+
+#define REG_OK_STRICT
+
+#include "config.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "insn-codes.h"
+#include "recog.h"
+#include "reload.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "real.h"
+
+#ifndef REGISTER_MOVE_COST
+#define REGISTER_MOVE_COST(x, y) 2
+#endif
+\f
+/* The variables set up by `find_reloads' are:
+
+   n_reloads             number of distinct reloads needed; max reload # + 1
+       tables indexed by reload number
+   reload_in             rtx for value to reload from
+   reload_out            rtx for where to store reload-reg afterward if nec
+                          (often the same as reload_in)
+   reload_reg_class      enum reg_class, saying what regs to reload into
+   reload_inmode         enum machine_mode; mode this operand should have
+                          when reloaded, on input.
+   reload_outmode        enum machine_mode; mode this operand should have
+                          when reloaded, on output.
+   reload_strict_low     char; currently always zero; used to mean that this
+                         reload is inside a STRICT_LOW_PART, but we don't
+                         need to know this anymore.
+   reload_optional       char, nonzero for an optional reload.
+                          Optional reloads are ignored unless the
+                          value is already sitting in a register.
+   reload_inc            int, positive amount to increment or decrement by if
+                          reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC.
+                          Ignored otherwise (don't assume it is zero).
+   reload_in_reg         rtx.  A reg for which reload_in is the equivalent.
+                          If reload_in is a symbol_ref which came from
+                          reg_equiv_constant, then this is the pseudo
+                          which has that symbol_ref as equivalent.
+   reload_reg_rtx        rtx.  This is the register to reload into.
+                          If it is zero when `find_reloads' returns,
+                          you must find a suitable register in the class
+                          specified by reload_reg_class, and store here
+                          an rtx for that register with mode from
+                          reload_inmode or reload_outmode.
+   reload_nocombine      char, nonzero if this reload shouldn't be
+                          combined with another reload.
+   reload_needed_for      rtx, operand this reload is needed for address of.
+                          0 means it isn't needed for addressing.
+   reload_needed_for_multiple
+                         int, 1 if this reload needed for more than one thing.
+   reload_when_needed     enum, classifies reload as needed either for
+                          addressing an input reload, addressing an output,
+                          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,
+                          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
+                          intermediate register.  */
+int n_reloads;
+
+rtx reload_in[MAX_RELOADS];
+rtx reload_out[MAX_RELOADS];
+enum reg_class reload_reg_class[MAX_RELOADS];
+enum machine_mode reload_inmode[MAX_RELOADS];
+enum machine_mode reload_outmode[MAX_RELOADS];
+char reload_strict_low[MAX_RELOADS];
+rtx reload_reg_rtx[MAX_RELOADS];
+char reload_optional[MAX_RELOADS];
+int reload_inc[MAX_RELOADS];
+rtx reload_in_reg[MAX_RELOADS];
+char reload_nocombine[MAX_RELOADS];
+int reload_needed_for_multiple[MAX_RELOADS];
+rtx reload_needed_for[MAX_RELOADS];
+enum reload_when_needed 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];
+
+/* All the "earlyclobber" operands of the current insn
+   are recorded here.  */
+int n_earlyclobbers;
+rtx reload_earlyclobbers[MAX_RECOG_OPERANDS];
+
+/* Replacing reloads.
+
+   If `replace_reloads' is nonzero, then as each reload is recorded
+   an entry is made for it in the table `replacements'.
+   Then later `subst_reloads' can look through that table and
+   perform all the replacements needed.  */
+
+/* Nonzero means record the places to replace.  */
+static int replace_reloads;
+
+/* Each replacement is recorded with a structure like this.  */
+struct replacement
+{
+  rtx *where;                  /* Location to store in */
+  rtx *subreg_loc;             /* Location of SUBREG if WHERE is inside
+                                  a SUBREG; 0 otherwise.  */
+  int what;                    /* which reload this is for */
+  enum machine_mode mode;      /* mode it must have */
+};
+
+static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
+
+/* Number of replacements currently recorded.  */
+static int n_replacements;
+
+/* MEM-rtx's created for pseudo-regs in stack slots not directly addressable;
+   (see reg_equiv_address).  */
+static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
+static int n_memlocs;
+
+/* The instruction we are doing reloads for;
+   so we can test whether a register dies in it.  */
+static rtx this_insn;
+
+/* Nonzero if this instruction is a user-specified asm with operands.  */
+static int this_insn_is_asm;
+
+/* If hard_regs_live_known is nonzero,
+   we can tell which hard regs are currently live,
+   at least enough to succeed in choosing dummy reloads.  */
+static int hard_regs_live_known;
+
+/* Indexed by hard reg number,
+   element is nonegative if hard reg has been spilled.
+   This vector is passed to `find_reloads' as an argument
+   and is not changed here.  */
+static short *static_reload_reg_p;
+
+/* Set to 1 in subst_reg_equivs if it changes anything.  */
+static int subst_reg_equivs_changed;
+
+/* On return from push_reload, holds the reload-number for the OUT
+   operand, which can be different for that from the input operand.  */
+static int output_reloadnum;
+
+static int alternative_allows_memconst ();
+static rtx find_dummy_reload ();
+static rtx find_reloads_toplev ();
+static int find_reloads_address ();
+static int find_reloads_address_1 ();
+static void find_reloads_address_part ();
+static int hard_reg_set_here_p ();
+/* static rtx forget_volatility (); */
+static rtx subst_reg_equivs ();
+static rtx subst_indexed_address ();
+rtx find_equiv_reg ();
+static int find_inc_amount ();
+\f
+#ifdef HAVE_SECONDARY_RELOADS
+
+/* Determine if any secondary reloads are needed for loading (if IN_P is
+   non-zero) or storing (if IN_P is zero) X to or from a reload register of
+   register class RELOAD_CLASS in mode RELOAD_MODE.
+
+   Return the register class of a secondary reload register, or NO_REGS if
+   none.  *PMODE is set to the mode that the register is required in.
+   If the reload register is needed as a scratch register instead of an
+   intermediate register, *PICODE is set to the insn_code of the insn to be
+   used to load or store the primary reload register; otherwise *PICODE
+   is set to CODE_FOR_nothing.
+
+   In some cases (such as storing MQ into an external memory location on
+   the RT), both an intermediate register and a scratch register.  In that
+   case, *PICODE is set to CODE_FOR_nothing, the class for the intermediate
+   register is returned, and the *PTERTIARY_... variables are set to describe
+   the scratch register.  */
+
+static enum reg_class
+find_secondary_reload (x, reload_class, reload_mode, in_p, picode, pmode,
+                     ptertiary_class, ptertiary_icode, ptertiary_mode)
+     rtx x;
+     enum reg_class reload_class;
+     enum machine_mode reload_mode;
+     int in_p;
+     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;
+  enum insn_code icode = CODE_FOR_nothing;
+  enum reg_class t_class = NO_REGS;
+  enum machine_mode t_mode = VOIDmode;
+  enum insn_code t_icode = CODE_FOR_nothing;
+
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+  if (in_p)
+    class = SECONDARY_INPUT_RELOAD_CLASS (reload_class, reload_mode, x);
+#endif
+
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+  if (! in_p)
+    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 (class == NO_REGS)
+    return NO_REGS;
+
+  /* Get a possible insn to use.  If the predicate doesn't accept X, don't
+     use the insn.  */
+
+  icode = (in_p ? reload_in_optab[(int) reload_mode]
+          : reload_out_optab[(int) reload_mode]);
+
+  if (icode != CODE_FOR_nothing
+      && insn_operand_predicate[(int) icode][in_p]
+      && (! (insn_operand_predicate[(int) icode][in_p]) (x, reload_mode)))
+    icode = CODE_FOR_nothing;
+
+  /* If we will be using an insn, see if it can directly handle the reload
+     register we will be using.  If it can, the secondary reload is for a
+     scratch register.  If it can't, we will use the secondary reload for
+     an intermediate register and require a tertiary reload for the scratch
+     register.  */
+
+  if (icode != CODE_FOR_nothing)
+    {
+      /* If IN_P is non-zero, the reload register will be the output in 
+        operand 0.  If IN_P is zero, the reload register will be the input
+        in operand 1.  Outputs should have an initial "=", which we must
+        skip.  */
+
+      enum reg_class insn_class
+       = REG_CLASS_FROM_LETTER (insn_operand_constraint[(int) icode][!in_p][in_p]);
+
+      if (insn_class == NO_REGS
+         || (in_p && insn_operand_constraint[(int) icode][!in_p][0] != '=')
+         /* The scratch register's constraint must start with "=&".  */
+         || insn_operand_constraint[(int) icode][2][0] != '='
+         || insn_operand_constraint[(int) icode][2][1] != '&')
+       abort ();
+
+      if (reg_class_subset_p (reload_class, insn_class))
+       mode = insn_operand_mode[(int) icode][2];
+      else
+       {
+         class = insn_class;
+         t_mode = insn_operand_mode[(int) icode][2];
+         t_class
+           = REG_CLASS_FROM_LETTER (insn_operand_constraint[(int) icode][2][2]);
+         t_icode = icode;
+         icode = CODE_FOR_nothing;
+       }
+    }
+
+  *pmode = mode;
+  *picode = icode;
+  *ptertiary_class = t_class;
+  *ptertiary_mode = t_mode;
+  *ptertiary_icode = t_icode;
+
+  return class;
+}
+#endif /* HAVE_SECONDARY_RELOADS */
+\f
+/* Record one (sometimes two) 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.
+   (IN is zero for data not read, and OUT is zero for data not written.)
+   INLOC and OUTLOC point to the places in the instructions where
+   IN and OUT were found.
+   CLASS is a register class required for the reloaded data.
+   INMODE is the machine mode that the instruction requires
+   for the reg that replaces IN and OUTMODE is likewise for OUT.
+
+   If IN is zero, then OUT's location and mode should be passed as
+   INLOC and INMODE.
+
+   STRICT_LOW is the 1 if there is a containing STRICT_LOW_PART rtx.
+
+   OPTIONAL nonzero means this reload does not need to be performed:
+   it can be discarded if that is more convenient.
+
+   The return value is the reload-number for this reload.
+
+   If both IN and OUT are nonzero, in some rare cases we might
+   want to make two separate reloads.  (Actually we never do this now.)
+   Therefore, the reload-number for OUT is stored in
+   output_reloadnum when we return; the return value applies to IN.
+   Usually (presently always), when IN and OUT are nonzero,
+   the two reload-numbers are equal, but the caller should be careful to
+   distinguish them.  */
+
+static int
+push_reload (in, out, inloc, outloc, class,
+            inmode, outmode, strict_low, optional, needed_for)
+     register rtx in, out;
+     rtx *inloc, *outloc;
+     enum reg_class class;
+     enum machine_mode inmode, outmode;
+     int strict_low;
+     int optional;
+     rtx needed_for;
+{
+  register int i;
+  int dont_share = 0;
+  rtx *in_subreg_loc = 0, *out_subreg_loc = 0;
+  int secondary_reload = -1;
+  enum insn_code secondary_icode = CODE_FOR_nothing;
+
+  /* Compare two RTX's.  */
+#define MATCHES(x, y) \
+ (x == y || (x != 0 && (GET_CODE (x) == REG                            \
+                       ? GET_CODE (y) == REG && REGNO (x) == REGNO (y) \
+                       : rtx_equal_p (x, y) && ! side_effects_p (x))))
+
+  /* INMODE and/or OUTMODE could be VOIDmode if no mode
+     has been specified for the operand.  In that case,
+     use the operand's mode as the mode to reload.  */
+  if (inmode == VOIDmode && in != 0)
+    inmode = GET_MODE (in);
+  if (outmode == VOIDmode && out != 0)
+    outmode = GET_MODE (out);
+
+  /* If IN is a pseudo register everywhere-equivalent to a constant, and 
+     it is not in a hard register, reload straight from the constant,
+     since we want to get rid of such pseudo registers.
+     Often this is done earlier, but not always in find_reloads_address.  */
+  if (in != 0 && GET_CODE (in) == REG)
+    {
+      register int regno = REGNO (in);
+
+      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0)
+       in = reg_equiv_constant[regno];
+    }
+
+  /* Likewise for OUT.  Of course, OUT will never be equivalent to
+     an actual constant, but it might be equivalent to a memory location
+     (in the case of a parameter).  */
+  if (out != 0 && GET_CODE (out) == REG)
+    {
+      register int regno = REGNO (out);
+
+      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0)
+       out = reg_equiv_constant[regno];
+    }
+
+  /* If we have a read-write operand with an address side-effect,
+     change either IN or OUT so the side-effect happens only once.  */
+  if (in != 0 && out != 0 && GET_CODE (in) == MEM && rtx_equal_p (in, out))
+    {
+      if (GET_CODE (XEXP (in, 0)) == POST_INC
+         || GET_CODE (XEXP (in, 0)) == POST_DEC)
+       in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0));
+      if (GET_CODE (XEXP (in, 0)) == PRE_INC
+         || GET_CODE (XEXP (in, 0)) == PRE_DEC)
+       out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0));
+    }
+
+  /* If we are reloading a (SUBREG (MEM ...) ...) or (SUBREG constant ...),
+     really reload just the inside expression in its own mode.
+     If we have (SUBREG:M1 (REG:M2 ...) ...) with M1 wider than M2 and the
+     register is a pseudo, this will become the same as the above case.
+     Do the same 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.
+     Note that the case of (SUBREG (CONST_INT...)...) is handled elsewhere;
+     we can't handle it here because CONST_INT does not indicate a mode.
+
+     Similarly, we must reload the inside expression if we have a
+     STRICT_LOW_PART (presumably, in == out in the cas).  */
+
+  if (in != 0 && GET_CODE (in) == SUBREG
+      && (GET_CODE (SUBREG_REG (in)) != REG
+         || strict_low
+         || (GET_CODE (SUBREG_REG (in)) == REG
+             && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER
+             && (GET_MODE_SIZE (inmode)
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))))
+         || (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)))))))))
+    {
+      in_subreg_loc = inloc;
+      inloc = &SUBREG_REG (in);
+      in = *inloc;
+      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.  */
+       if (GET_MODE_SIZE (GET_MODE (in)) > GET_MODE_SIZE (inmode))
+         abort ();
+      inmode = GET_MODE (in);
+    }
+
+  /* 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
+      && (GET_CODE (SUBREG_REG (out)) != REG
+         || strict_low
+         || (GET_CODE (SUBREG_REG (out)) == REG
+             && REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER
+             && (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
+             && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (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)))))))))
+    {
+      out_subreg_loc = outloc;
+      outloc = &SUBREG_REG (out);
+      out = *outloc;
+      if (GET_CODE (out) == MEM
+         && GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
+       abort ();
+      outmode = GET_MODE (out);
+    }
+
+  /* That's all we use STRICT_LOW for, so clear it.  At some point,
+     we may want to get rid of reload_strict_low.  */
+  strict_low = 0;
+
+  /* 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)
+      && reg_overlap_mentioned_p (in, XEXP (out, 0)))
+    dont_share = 1;
+
+  /* Narrow down the class of register wanted if that is
+     desirable on this machine for efficiency.  */
+  if (in != 0)
+    class = PREFERRED_RELOAD_CLASS (in, class);
+
+  /* Make sure we use a class that can handle the actual pseudo
+     inside any subreg.  For example, on the 386, QImode regs
+     can appear within SImode subregs.  Although GENERAL_REGS
+     can handle SImode, QImode needs a smaller class.  */
+#ifdef LIMIT_RELOAD_CLASS
+  if (in_subreg_loc)
+    class = LIMIT_RELOAD_CLASS (inmode, class);
+  else if (in != 0 && GET_CODE (in) == SUBREG)
+    class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (in)), class);
+
+  if (out_subreg_loc)
+    class = LIMIT_RELOAD_CLASS (outmode, class);
+  if (out != 0 && GET_CODE (out) == SUBREG)
+    class = LIMIT_RELOAD_CLASS (GET_MODE (SUBREG_REG (out)), class);
+#endif
+
+  if (class == NO_REGS)
+    abort ();
+
+  /* Verify that this class is at least possible for the mode that
+     is specified.  */
+  if (this_insn_is_asm)
+    {
+      enum machine_mode mode;
+      if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
+       mode = inmode;
+      else
+       mode = outmode;
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (HARD_REGNO_MODE_OK (i, mode)
+           && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i))
+         {
+           int nregs = HARD_REGNO_NREGS (i, mode);
+
+           int j;
+           for (j = 1; j < nregs; j++)
+             if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j))
+               break;
+           if (j == nregs)
+             break;
+         }
+      if (i == FIRST_PSEUDO_REGISTER)
+       {
+         error_for_asm (this_insn, "impossible register constraint in `asm'");
+         class = ALL_REGS;
+       }
+    }
+
+  /* We can use an existing reload if the class is right
+     and at least one of IN and OUT is a match
+     and the other is at worst neutral.
+     (A zero compared against anything is neutral.)  */
+  for (i = 0; i < n_reloads; i++)
+    if ((reg_class_subset_p (class, reload_reg_class[i])
+        || reg_class_subset_p (reload_reg_class[i], class))
+       && reload_strict_low[i] == strict_low
+       /* If the existing reload has a register, it must fit our class.  */
+       && (reload_reg_rtx[i] == 0
+           || TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                 true_regnum (reload_reg_rtx[i])))
+       && ((in != 0 && MATCHES (reload_in[i], in) && ! dont_share
+            && (out == 0 || reload_out[i] == 0 || MATCHES (reload_out[i], out)))
+           ||
+           (out != 0 && MATCHES (reload_out[i], out)
+            && (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in)))))
+      break;
+
+  /* Reloading a plain reg for input can match a reload to postincrement
+     that reg, since the postincrement's value is the right value.
+     Likewise, it can match a preincrement reload, since we regard
+     the preincrementation as happening before any ref in this insn
+     to that register.  */
+  if (i == n_reloads)
+    for (i = 0; i < n_reloads; i++)
+      if ((reg_class_subset_p (class, reload_reg_class[i])
+          || reg_class_subset_p (reload_reg_class[i], class))
+         /* If the existing reload has a register, it must fit our class.  */
+         && (reload_reg_rtx[i] == 0
+             || TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                   true_regnum (reload_reg_rtx[i])))
+         && reload_strict_low[i] == strict_low
+         && out == 0 && reload_out[i] == 0 && reload_in[i] != 0
+         && ((GET_CODE (in) == REG
+              && (GET_CODE (reload_in[i]) == POST_INC
+                  || GET_CODE (reload_in[i]) == POST_DEC
+                  || GET_CODE (reload_in[i]) == PRE_INC
+                  || GET_CODE (reload_in[i]) == PRE_DEC)
+              && MATCHES (XEXP (reload_in[i], 0), in))
+             ||
+             (GET_CODE (reload_in[i]) == REG
+              && (GET_CODE (in) == POST_INC
+                  || GET_CODE (in) == POST_DEC
+                  || GET_CODE (in) == PRE_INC
+                  || GET_CODE (in) == PRE_DEC)
+              && MATCHES (XEXP (in, 0), reload_in[i]))))
+       {
+         /* Make sure reload_in ultimately has the increment,
+            not the plain register.  */
+         if (GET_CODE (in) == REG)
+           in = reload_in[i];
+         break;
+       }
+
+  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.  */
+
+#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);
+#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 (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))
+       {
+         push_reload (0, out, 0, outloc, class, VOIDmode, outmode,
+                      strict_low, optional, needed_for);
+         out = 0;
+         outloc = 0;
+         outmode = VOIDmode;
+       }
+
+      /* 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)
+       {
+         /* 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))
+                   
+                 {
+                   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 (reload_needed_for[tertiary_reload] != needed_for)
+                     reload_needed_for_multiple[tertiary_reload] = 1;
+                   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;
+                 reload_strict_low[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_needed_for[tertiary_reload] = needed_for;
+                 reload_needed_for_multiple[tertiary_reload] = 0;
+                 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)
+             {
+               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 (reload_needed_for[secondary_reload] != needed_for)
+                 reload_needed_for_multiple[secondary_reload] = 1;
+               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;
+             reload_strict_low[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_needed_for[secondary_reload] = needed_for;
+             reload_needed_for_multiple[secondary_reload] = 0;
+             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;
+           }
+       }
+#endif
+
+      /* We found no existing reload suitable for re-use.
+        So add an additional reload.  */
+
+      reload_in[i] = in;
+      reload_out[i] = out;
+      reload_reg_class[i] = class;
+      reload_inmode[i] = inmode;
+      reload_outmode[i] = outmode;
+      reload_reg_rtx[i] = 0;
+      reload_optional[i] = optional;
+      reload_inc[i] = 0;
+      reload_strict_low[i] = strict_low;
+      reload_nocombine[i] = 0;
+      reload_in_reg[i] = inloc ? *inloc : 0;
+      reload_needed_for[i] = needed_for;
+      reload_needed_for_multiple[i] = 0;
+      reload_secondary_reload[i] = secondary_reload;
+      reload_secondary_icode[i] = secondary_icode;
+      reload_secondary_p[i] = 0;
+
+      n_reloads++;
+    }
+  else
+    {
+      /* We are reusing an existing reload,
+        but we may have additional information for it.
+        For example, we may now have both IN and OUT
+        while the old one may have just one of them.  */
+
+      if (inmode != VOIDmode)
+       reload_inmode[i] = inmode;
+      if (outmode != VOIDmode)
+       reload_outmode[i] = outmode;
+      if (in != 0)
+       reload_in[i] = in;
+      if (out != 0)
+       reload_out[i] = out;
+      if (reg_class_subset_p (class, reload_reg_class[i]))
+       reload_reg_class[i] = class;
+      reload_optional[i] &= optional;
+      if (reload_needed_for[i] != needed_for)
+       reload_needed_for_multiple[i] = 1;
+    }
+
+  /* If the ostensible rtx being reload differs from the rtx found
+     in the location to substitute, this reload is not safe to combine
+     because we cannot reliably tell whether it appears in the insn.  */
+
+  if (in != 0 && in != *inloc)
+    reload_nocombine[i] = 1;
+
+#if 0
+  /* This was replaced by changes in find_reloads_address_1 and the new
+     function inc_for_reload, which go with a new meaning of reload_inc.  */
+
+  /* If this is an IN/OUT reload in an insn that sets the CC,
+     it must be for an autoincrement.  It doesn't work to store
+     the incremented value after the insn because that would clobber the CC.
+     So we must do the increment of the value reloaded from,
+     increment it, store it back, then decrement again.  */
+  if (out != 0 && sets_cc0_p (PATTERN (this_insn)))
+    {
+      out = 0;
+      reload_out[i] = 0;
+      reload_inc[i] = find_inc_amount (PATTERN (this_insn), in);
+      /* If we did not find a nonzero amount-to-increment-by,
+        that contradicts the belief that IN is being incremented
+        in an address in this insn.  */
+      if (reload_inc[i] == 0)
+       abort ();
+    }
+#endif
+
+  /* If we will replace IN and OUT with the reload-reg,
+     record where they are located so that substitution need
+     not do a tree walk.  */
+
+  if (replace_reloads)
+    {
+      if (inloc != 0)
+       {
+         register struct replacement *r = &replacements[n_replacements++];
+         r->what = i;
+         r->subreg_loc = in_subreg_loc;
+         r->where = inloc;
+         r->mode = inmode;
+       }
+      if (outloc != 0 && outloc != inloc)
+       {
+         register struct replacement *r = &replacements[n_replacements++];
+         r->what = i;
+         r->where = outloc;
+         r->subreg_loc = out_subreg_loc;
+         r->mode = outmode;
+       }
+    }
+
+  /* If this reload is just being introduced and it has both
+     an incoming quantity and an outgoing quantity that are
+     supposed to be made to match, see if either one of the two
+     can serve as the place to reload into.
+
+     If one of them is acceptable, set reload_reg_rtx[i]
+     to that one.  */
+
+  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);
+
+      /* If the outgoing register already contains the same value
+        as the incoming one, we can dispense with loading it.
+        The easiest way to tell the caller that is to give a phony
+        value for the incoming operand (same as outgoing one).  */
+      if (reload_reg_rtx[i] == out
+         && (GET_CODE (in) == REG || CONSTANT_P (in))
+         && 0 != find_equiv_reg (in, this_insn, 0, REGNO (out),
+                                 static_reload_reg_p, i, inmode))
+       reload_in[i] = out;
+    }
+
+  /* If this is an input reload and the operand contains a register that
+     dies in this insn and is used nowhere else, see if it is the right class
+     to be used for this reload.  Use it if so.  (This occurs most commonly
+     in the case of paradoxical SUBREGs and in-out reloads).  We cannot do
+     this if it is also an output reload that mentions the register unless
+     the output is a SUBREG that clobbers an entire register.
+
+     Note that the operand might be one of the spill regs, if it is a
+     pseudo reg and we are in a block where spilling has not taken place.
+     But if there is no spilling in this block, that is OK.
+     An explicitly used hard reg cannot be a spill reg.  */
+
+  if (reload_reg_rtx[i] == 0 && in != 0)
+    {
+      rtx note;
+      int regno;
+
+      for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
+       if (REG_NOTE_KIND (note) == REG_DEAD
+           && GET_CODE (XEXP (note, 0)) == REG
+           && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER
+           && reg_mentioned_p (XEXP (note, 0), in)
+           && ! refers_to_regno_for_reload_p (regno,
+                                              (regno
+                                               + HARD_REGNO_NREGS (regno,
+                                                                   inmode)),
+                                              PATTERN (this_insn), inloc)
+           && (in != out
+               || (GET_CODE (in) == SUBREG
+                   && (((GET_MODE_SIZE (GET_MODE (in)) + (UNITS_PER_WORD - 1))
+                        / UNITS_PER_WORD)
+                       == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+                            + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
+           /* Make sure the operand fits in the reg that dies.  */
+           && GET_MODE_SIZE (inmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+           && HARD_REGNO_MODE_OK (regno, inmode)
+           && GET_MODE_SIZE (outmode) <= GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+           && HARD_REGNO_MODE_OK (regno, outmode)
+           && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
+           && !fixed_regs[regno])
+         {
+           reload_reg_rtx[i] = gen_rtx (REG, inmode, regno);
+           break;
+         }
+    }
+
+  if (out)
+    output_reloadnum = i;
+
+  return i;
+}
+
+/* Record an additional place we must replace a value
+   for which we have already recorded a reload.
+   RELOADNUM is the value returned by push_reload
+   when the reload was recorded.
+   This is used in insn patterns that use match_dup.  */
+
+static void
+push_replacement (loc, reloadnum, mode)
+     rtx *loc;
+     int reloadnum;
+     enum machine_mode mode;
+{
+  if (replace_reloads)
+    {
+      register struct replacement *r = &replacements[n_replacements++];
+      r->what = reloadnum;
+      r->where = loc;
+      r->subreg_loc = 0;
+      r->mode = mode;
+    }
+}
+\f
+/* If there is only one output reload, and it is not for an earlyclobber
+   operand, try to combine it with a (logically unrelated) input reload
+   to reduce the number of reload registers needed.
+
+   This is safe if the input reload does not appear in
+   the value being output-reloaded, because this implies
+   it is not needed any more once the original insn completes.
+
+   If that doesn't work, see we can use any of the registers that
+   die in this insn as a reload register.  We can if it is of the right
+   class and does not appear in the value being output-reloaded.  */
+
+static void
+combine_reloads ()
+{
+  int i;
+  int output_reload = -1;
+  rtx note;
+
+  /* Find the output reload; return unless there is exactly one
+     and that one is mandatory.  */
+
+  for (i = 0; i < n_reloads; i++)
+    if (reload_out[i] != 0)
+      {
+       if (output_reload >= 0)
+         return;
+       output_reload = i;
+      }
+
+  if (output_reload < 0 || reload_optional[output_reload])
+    return;
+
+  /* An input-output reload isn't combinable.  */
+
+  if (reload_in[output_reload] != 0)
+    return;
+
+  /* If this reload is for an earlyclobber operand, we can't do anyting.  */
+
+  for (i = 0; i < n_earlyclobbers; i++)
+    if (reload_out[output_reload] == reload_earlyclobbers[i])
+      return;
+
+  /* Check each input reload; can we combine it?  */
+
+  for (i = 0; i < n_reloads; i++)
+    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_RELOAD_ADDRESS
+       && reload_inmode[i] == reload_outmode[output_reload]
+       && reload_inc[i] == 0
+       && reload_reg_rtx[i] == 0
+       && reload_strict_low[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)
+       && (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
+              while the second is the one that might be affected.  */
+           || (! reg_overlap_mentioned_p (reload_out[output_reload],
+                                          reload_in[i])
+               /* However, if the input is a register that appears inside
+                  the output, then we also can't share.
+                  Imagine (set (mem (reg 69)) (plus (reg 69) ...)).
+                  If the same reload reg is used for both reg 69 and the
+                  result to be stored in memory, then that result
+                  will clobber the address of the memory ref.  */
+               && ! (GET_CODE (reload_in[i]) == REG
+                     && reg_overlap_mentioned_p (reload_in[i],
+                                                 reload_out[output_reload])))))
+      {
+       int j;
+
+       /* We have found a reload to combine with!  */
+       reload_out[i] = reload_out[output_reload];
+       reload_outmode[i] = reload_outmode[output_reload];
+       /* Mark the old output reload as inoperative.  */
+       reload_out[output_reload] = 0;
+       /* The combined reload is needed for the entire insn.  */
+       reload_needed_for_multiple[i] = 1;
+       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 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];
+
+       /* Transfer all replacements from the old reload to the combined.  */
+       for (j = 0; j < n_replacements; j++)
+         if (replacements[j].what == output_reload)
+           replacements[j].what = i;
+
+       return;
+      }
+
+  /* If this insn has only one operand that is modified or written (assumed
+     to be the first),  it must be the one corresponding to this reload.  It
+     is safe to use anything that dies in this insn for that output provided
+     that it does not occur in the output (we already know it isn't an
+     earlyclobber.  If this is an asm insn, give up.  */
+
+  if (INSN_CODE (this_insn) == -1)
+    return;
+
+  for (i = 1; i < insn_n_operands[INSN_CODE (this_insn)]; i++)
+    if (insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '='
+       || insn_operand_constraint[INSN_CODE (this_insn)][i][0] == '+')
+      return;
+
+  /* See if some hard register that dies in this insn and is not used in
+     the output is the right class.  Only works if the register we pick
+     up can fully hold our output reload.  */
+  for (note = REG_NOTES (this_insn); note; note = XEXP (note, 1))
+    if (REG_NOTE_KIND (note) == REG_DEAD
+       && GET_CODE (XEXP (note, 0)) == REG
+       && ! reg_overlap_mentioned_p (XEXP (note, 0),
+                                     reload_out[output_reload])
+       && REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
+       && HARD_REGNO_MODE_OK (REGNO (XEXP (note, 0)), reload_outmode[output_reload])
+       && TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[output_reload]],
+                             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))))
+       && ! fixed_regs[REGNO (XEXP (note, 0))])
+      {
+       reload_reg_rtx[output_reload] = gen_rtx (REG,
+                                                reload_outmode[output_reload],
+                                                REGNO (XEXP (note, 0)));
+       return;
+      }
+}
+\f
+/* Try to find a reload register for an in-out reload (expressions IN and OUT).
+   See if one of IN and OUT is a register that may be used;
+   this is desirable since a spill-register won't be needed.
+   If so, return the register rtx that proves acceptable.
+
+   INLOC and OUTLOC are locations where IN and OUT appear in the insn.
+   CLASS is the register class required for the reload.
+
+   If FOR_REAL is >= 0, it is the number of the reload,
+   and in some cases when it can be discovered that OUT doesn't need
+   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.  */
+
+static rtx
+find_dummy_reload (real_in, real_out, inloc, outloc, class, for_real)
+     rtx real_in, real_out;
+     rtx *inloc, *outloc;
+     enum reg_class class;
+     int for_real;
+{
+  rtx in = real_in;
+  rtx out = real_out;
+  int in_offset = 0;
+  int out_offset = 0;
+  rtx value = 0;
+
+  /* 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))
+    return 0;
+
+  /* Find the inside of any subregs.  */
+  while (GET_CODE (out) == SUBREG)
+    {
+      out_offset = SUBREG_WORD (out);
+      out = SUBREG_REG (out);
+    }
+  while (GET_CODE (in) == SUBREG)
+    {
+      in_offset = SUBREG_WORD (in);
+      in = SUBREG_REG (in);
+    }
+
+  /* Narrow down the reg class, the same way push_reload will;
+     otherwise we might find a dummy now, but push_reload won't.  */
+  class = PREFERRED_RELOAD_CLASS (in, class);
+
+  /* See if OUT will do.  */
+  if (GET_CODE (out) == REG
+      && REGNO (out) < FIRST_PSEUDO_REGISTER)
+    {
+      register int regno = REGNO (out) + out_offset;
+      int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_out));
+
+      /* When we consider whether the insn uses OUT,
+        ignore references within IN.  They don't prevent us
+        from copying IN into OUT, because those refs would
+        move into the insn that reloads IN.
+
+        However, we only ignore IN in its role as this reload.
+        If the insn uses IN elsewhere and it contains OUT,
+        that counts.  We can't be sure it's the "same" operand
+        so it might not go through this reload.  */
+      *inloc = const0_rtx;
+
+      if (regno < FIRST_PSEUDO_REGISTER
+         /* A fixed reg that can overlap other regs better not be used
+            for reloading in any way.  */
+#ifdef OVERLAPPING_REGNO_P
+         && ! (fixed_regs[regno] && OVERLAPPING_REGNO_P (regno))
+#endif
+         && ! refers_to_regno_for_reload_p (regno, regno + nwords,
+                                            PATTERN (this_insn), outloc))
+       {
+         int i;
+         for (i = 0; i < nwords; i++)
+           if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                    regno + i))
+             break;
+
+         if (i == nwords)
+           {
+             if (GET_CODE (real_out) == REG)
+               value = real_out;
+             else
+               value = gen_rtx (REG, GET_MODE (real_out), regno);
+           }
+       }
+
+      *inloc = real_in;
+    }
+
+  /* Consider using IN if OUT was not acceptable
+     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.  */
+  if (hard_regs_live_known
+      && GET_CODE (in) == REG
+      && REGNO (in) < FIRST_PSEUDO_REGISTER
+      && (value == 0
+         || 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)))
+    {
+      register int regno = REGNO (in) + in_offset;
+      int nwords = HARD_REGNO_NREGS (regno, GET_MODE (real_in));
+
+      if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, 0)
+         && ! hard_reg_set_here_p (regno, regno + nwords,
+                                   PATTERN (this_insn)))
+       {
+         int i;
+         for (i = 0; i < nwords; i++)
+           if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                    regno + i))
+             break;
+
+         if (i == nwords)
+           {
+             /* If we were going to use OUT as the reload reg
+                and changed our mind, it means OUT is a dummy that
+                dies here.  So don't bother copying value to it.  */
+             if (for_real >= 0 && value == real_out)
+               reload_out[for_real] = 0;
+             if (GET_CODE (real_in) == REG)
+               value = real_in;
+             else
+               value = gen_rtx (REG, GET_MODE (real_in), regno);
+           }
+       }
+    }
+
+  return value;
+}
+\f
+/* This page contains subroutines used mainly for determining
+   whether the IN or an OUT of a reload can serve as the
+   reload register.  */
+
+/* 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.
+   X should be the body of an instruction.  */
+
+static int
+hard_reg_set_here_p (beg_regno, end_regno, x)
+     register int beg_regno, end_regno;
+     rtx x;
+{
+  if (GET_CODE (x) == SET || GET_CODE (x) == CLOBBER)
+    {
+      register rtx op0 = SET_DEST (x);
+      while (GET_CODE (op0) == SUBREG)
+       op0 = SUBREG_REG (op0);
+      if (GET_CODE (op0) == REG)
+       {
+         register int r = REGNO (op0);
+         /* See if this reg overlaps range under consideration.  */
+         if (r < end_regno
+             && r + HARD_REGNO_NREGS (r, GET_MODE (op0)) > beg_regno)
+           return 1;
+       }
+    }
+  else if (GET_CODE (x) == PARALLEL)
+    {
+      register int i = XVECLEN (x, 0) - 1;
+      for (; i >= 0; i--)
+       if (hard_reg_set_here_p (beg_regno, end_regno, XVECEXP (x, 0, i)))
+         return 1;
+    }
+
+  return 0;
+}
+
+/* Return 1 if ADDR is a valid memory address for mode MODE,
+   and check that each pseudo reg has the proper kind of
+   hard reg.  */
+
+int
+strict_memory_address_p (mode, addr)
+     enum machine_mode mode;
+     register rtx addr;
+{
+  GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
+  return 0;
+
+ win:
+  return 1;
+}
+
+\f
+/* Like rtx_equal_p except that it allows a REG and a SUBREG to match
+   if they are the same hard reg, and has special hacks for
+   autoincrement and autodecrement.
+   This is specifically intended for find_reloads to use
+   in determining whether two operands match.
+   X is the operand whose number is the lower of the two.
+
+   The value is 2 if Y contains a pre-increment that matches
+   a non-incrementing address in X.  */
+
+/* ??? To be completely correct, we should arrange to pass
+   for X the output operand and for Y the input operand.
+   For now, we assume that the output operand has the lower number
+   because that is natural in (SET output (... input ...)).  */
+
+int
+operands_match_p (x, y)
+     register rtx x, y;
+{
+  register int i;
+  register RTX_CODE code = GET_CODE (x);
+  register char *fmt;
+  int success_2;
+      
+  if (x == y)
+    return 1;
+  if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
+      && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
+                                 && GET_CODE (SUBREG_REG (y)) == REG)))
+    {
+      register int j;
+
+      if (code == SUBREG)
+       {
+         i = REGNO (SUBREG_REG (x));
+         if (i >= FIRST_PSEUDO_REGISTER)
+           goto slow;
+         i += SUBREG_WORD (x);
+       }
+      else
+       i = REGNO (x);
+
+      if (GET_CODE (y) == SUBREG)
+       {
+         j = REGNO (SUBREG_REG (y));
+         if (j >= FIRST_PSEUDO_REGISTER)
+           goto slow;
+         j += SUBREG_WORD (y);
+       }
+      else
+       j = REGNO (y);
+
+      return i == j;
+    }
+  /* If two operands must match, because they are really a single
+     operand of an assembler insn, then two postincrements are invalid
+     because the assembler insn would increment only once.
+     On the other hand, an postincrement matches ordinary indexing
+     if the postincrement is the output operand.  */
+  if (code == POST_DEC || code == POST_INC)
+    return operands_match_p (XEXP (x, 0), y);
+  /* Two preincrements are invalid
+     because the assembler insn would increment only once.
+     On the other hand, an preincrement matches ordinary indexing
+     if the preincrement is the input operand.
+     In this case, return 2, since some callers need to do special
+     things when this happens.  */
+  if (GET_CODE (y) == PRE_DEC || GET_CODE (y) == PRE_INC)
+    return operands_match_p (x, XEXP (y, 0)) ? 2 : 0;
+
+ slow:
+
+  /* Now we have disposed of all the cases 
+     in which different rtx codes can match.  */
+  if (code != GET_CODE (y))
+    return 0;
+  if (code == LABEL_REF)
+    return XEXP (x, 0) == XEXP (y, 0);
+  if (code == SYMBOL_REF)
+    return XSTR (x, 0) == XSTR (y, 0);
+
+  /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.  */
+
+  if (GET_MODE (x) != GET_MODE (y))
+    return 0;
+
+  /* Compare the elements.  If any pair of corresponding elements
+     fail to match, return 0 for the whole things.  */
+
+  success_2 = 0;
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      int val;
+      switch (fmt[i])
+       {
+       case 'i':
+         if (XINT (x, i) != XINT (y, i))
+           return 0;
+         break;
+
+       case 'e':
+         val = operands_match_p (XEXP (x, i), XEXP (y, i));
+         if (val == 0)
+           return 0;
+         /* If any subexpression returns 2,
+            we should return 2 if we are successful.  */
+         if (val == 2)
+           success_2 = 1;
+         break;
+
+       case '0':
+         break;
+
+         /* It is believed that rtx's at this level will never
+            contain anything but integers and other rtx's,
+            except for within LABEL_REFs and SYMBOL_REFs.  */
+       default:
+         abort ();
+       }
+    }
+  return 1 + success_2;
+}
+\f
+/* Return the number of times character C occurs in string S.  */
+
+static int
+n_occurrences (c, s)
+     char c;
+     char *s;
+{
+  int n = 0;
+  while (*s)
+    n += (*s++ == c);
+  return n;
+}
+\f
+struct decomposition
+{
+  int reg_flag;
+  int safe;
+  rtx base;
+  int start;
+  int end;
+};
+
+/* Describe the range of registers or memory referenced by X.
+   If X is a register, set REG_FLAG and put the first register 
+   number into START and the last plus one into END.
+   If X is a memory reference, put a base address into BASE 
+   and a range of integer offsets into START and END.
+   If X is pushing on the stack, we can assume it causes no trouble, 
+   so we set the SAFE field.  */
+
+static struct decomposition
+decompose (x)
+     rtx x;
+{
+  struct decomposition val;
+  int all_const = 0;
+
+  val.reg_flag = 0;
+  val.safe = 0;
+  if (GET_CODE (x) == MEM)
+    {
+      rtx base, offset = 0;
+      rtx addr = XEXP (x, 0);
+
+      if (GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+         || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+       {
+         val.base = XEXP (addr, 0);
+         val.start = - GET_MODE_SIZE (GET_MODE (x));
+         val.end = GET_MODE_SIZE (GET_MODE (x));
+         val.safe = REGNO (val.base) == STACK_POINTER_REGNUM;
+         return val;
+       }
+
+      if (GET_CODE (addr) == CONST)
+       {
+         addr = XEXP (addr, 0);
+         all_const = 1;
+       }
+      if (GET_CODE (addr) == PLUS)
+       {
+         if (CONSTANT_P (XEXP (addr, 0)))
+           {
+             base = XEXP (addr, 1);
+             offset = XEXP (addr, 0);
+           }
+         else if (CONSTANT_P (XEXP (addr, 1)))
+           {
+             base = XEXP (addr, 0);
+             offset = XEXP (addr, 1);
+           }
+       }
+
+      if (offset == 0)
+       {
+         base = addr;
+         offset = const0_rtx;
+       } 
+      if (GET_CODE (offset) == CONST)
+       offset = XEXP (offset, 0);
+      if (GET_CODE (offset) == PLUS)
+       {
+         if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
+           {
+             base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 1));
+             offset = XEXP (offset, 0);
+           }
+         else if (GET_CODE (XEXP (offset, 1)) == CONST_INT)
+           {
+             base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 0));
+             offset = XEXP (offset, 1);
+           }
+         else
+           {
+             base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+             offset = const0_rtx;
+           }
+       }
+      else if (GET_CODE (offset) != CONST_INT)
+       {
+         base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+         offset = const0_rtx;
+       }
+
+      if (all_const && GET_CODE (base) == PLUS)
+       base = gen_rtx (CONST, GET_MODE (base), base);
+
+      if (GET_CODE (offset) != CONST_INT)
+       abort ();
+
+      val.start = INTVAL (offset);
+      val.end = val.start + GET_MODE_SIZE (GET_MODE (x));
+      val.base = base;
+      return val;
+    }
+  else if (GET_CODE (x) == REG)
+    {
+      val.reg_flag = 1;
+      val.start = true_regnum (x); 
+      if (val.start < 0)
+       {
+         /* A pseudo with no hard reg.  */
+         val.start = REGNO (x);
+         val.end = val.start + 1;
+       }
+      else
+       /* A hard reg.  */
+       val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x));
+    }
+  else if (GET_CODE (x) == SUBREG)
+    {
+      if (GET_CODE (SUBREG_REG (x)) != REG)
+       /* This could be more precise, but it's good enough.  */
+       return decompose (SUBREG_REG (x));
+      val.reg_flag = 1;
+      val.start = true_regnum (x); 
+      if (val.start < 0)
+       return decompose (SUBREG_REG (x));
+      else
+       /* A hard reg.  */
+       val.end = val.start + HARD_REGNO_NREGS (val.start, GET_MODE (x));
+    }
+  else if (CONSTANT_P (x)
+          /* This hasn't been assigned yet, so it can't conflict yet.  */
+          || GET_CODE (x) == SCRATCH)
+    val.safe = 1;
+  else
+    abort ();
+  return val;
+}
+
+/* Return 1 if altering Y will not modify the value of X.
+   Y is also described by YDATA, which should be decompose (Y).  */
+
+static int
+immune_p (x, y, ydata)
+     rtx x, y;
+     struct decomposition ydata;
+{
+  struct decomposition xdata;
+
+  if (ydata.reg_flag)
+    return !refers_to_regno_for_reload_p (ydata.start, ydata.end, x, 0);
+  if (ydata.safe)
+    return 1;
+
+  if (GET_CODE (y) != MEM)
+    abort ();
+  /* If Y is memory and X is not, Y can't affect X.  */
+  if (GET_CODE (x) != MEM)
+    return 1;
+
+  xdata =  decompose (x);
+
+  if (! rtx_equal_p (xdata.base, ydata.base))
+    {
+      /* If bases are distinct symbolic constants, there is no overlap.  */
+      if (CONSTANT_P (xdata.base) && CONSTANT_P (ydata.base))
+       return 1;
+      /* Constants and stack slots never overlap.  */
+      if (CONSTANT_P (xdata.base)
+         && (ydata.base == frame_pointer_rtx
+             || ydata.base == stack_pointer_rtx))
+       return 1;
+      if (CONSTANT_P (ydata.base)
+         && (xdata.base == frame_pointer_rtx
+             || xdata.base == stack_pointer_rtx))
+       return 1;
+      /* If either base is variable, we don't know anything.  */
+      return 0;
+    }
+
+
+  return (xdata.start >= ydata.end || ydata.start >= xdata.end);
+}
+\f
+/* Main entry point of this file: search the body of INSN
+   for values that need reloading and record them with push_reload.
+   REPLACE nonzero means record also where the values occur
+   so that subst_reloads can be used.
+
+   IND_LEVELS says how many levels of indirection are supported by this
+   machine; a value of zero means that a memory reference is not a valid
+   memory address.
+
+   LIVE_KNOWN says we have valid information about which hard
+   regs are live at each point in the program; this is true when
+   we are called from global_alloc but false when stupid register
+   allocation has been done.
+
+   RELOAD_REG_P if nonzero is a vector indexed by hard reg number
+   which is nonnegative if the reg has been commandeered for reloading into.
+   It is copied into STATIC_RELOAD_REG_P and referenced from there
+   by various subroutines.  */
+
+void
+find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
+     rtx insn;
+     int replace, ind_levels;
+     int live_known;
+     short *reload_reg_p;
+{
+  rtx non_reloaded_operands[MAX_RECOG_OPERANDS];
+  int n_non_reloaded_operands = 0;
+#ifdef REGISTER_CONSTRAINTS
+
+  enum reload_modified { RELOAD_NOTHING, RELOAD_READ, RELOAD_READ_WRITE, RELOAD_WRITE };
+
+  register int insn_code_number;
+  register int i;
+  int noperands;
+  /* These are the constraints for the insn.  We don't change them.  */
+  char *constraints1[MAX_RECOG_OPERANDS];
+  /* These start out as the constraints for the insn
+     and they are chewed up as we consider alternatives.  */
+  char *constraints[MAX_RECOG_OPERANDS];
+  /* These are the preferred classes for an operand, or NO_REGS if it isn't
+     a register.  */
+  enum reg_class preferred_class[MAX_RECOG_OPERANDS];
+  char pref_or_nothing[MAX_RECOG_OPERANDS];
+  /* Nonzero for a MEM operand whose entire address needs a reload.  */
+  int address_reloaded[MAX_RECOG_OPERANDS];
+  int no_input_reloads = 0, no_output_reloads = 0;
+  int n_alternatives;
+  int this_alternative[MAX_RECOG_OPERANDS];
+  char this_alternative_win[MAX_RECOG_OPERANDS];
+  char this_alternative_offmemok[MAX_RECOG_OPERANDS];
+  char this_alternative_earlyclobber[MAX_RECOG_OPERANDS];
+  int this_alternative_matches[MAX_RECOG_OPERANDS];
+  int swapped;
+  int goal_alternative[MAX_RECOG_OPERANDS];
+  int this_alternative_number;
+  int goal_alternative_number;
+  int operand_reloadnum[MAX_RECOG_OPERANDS];
+  int goal_alternative_matches[MAX_RECOG_OPERANDS];
+  int goal_alternative_matched[MAX_RECOG_OPERANDS];
+  char goal_alternative_win[MAX_RECOG_OPERANDS];
+  char goal_alternative_offmemok[MAX_RECOG_OPERANDS];
+  char goal_alternative_earlyclobber[MAX_RECOG_OPERANDS];
+  int goal_alternative_swapped;
+  enum reload_modified modified[MAX_RECOG_OPERANDS];
+  int best;
+  int commutative;
+  char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
+  rtx substed_operand[MAX_RECOG_OPERANDS];
+  rtx body = PATTERN (insn);
+  rtx set = single_set (insn);
+  int goal_earlyclobber, this_earlyclobber;
+  enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+
+  this_insn = insn;
+  this_insn_is_asm = 0;                /* Tentative.  */
+  n_reloads = 0;
+  n_replacements = 0;
+  n_memlocs = 0;
+  n_earlyclobbers = 0;
+  replace_reloads = replace;
+  hard_regs_live_known = live_known;
+  static_reload_reg_p = reload_reg_p;
+
+  /* JUMP_INSNs and CALL_INSNs are not allowed to have any output reloads;
+     neither are insns that SET cc0.  Insns that use CC0 are not allowed
+     to have any input reloads.  */
+  if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN)
+    no_output_reloads = 1;
+
+#ifdef HAVE_cc0
+  if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
+    no_input_reloads = 1;
+  if (reg_set_p (cc0_rtx, PATTERN (insn)))
+    no_output_reloads = 1;
+#endif
+     
+  /* Find what kind of insn this is.  NOPERANDS gets number of operands.
+     Make OPERANDS point to a vector of operand values.
+     Make OPERAND_LOCS point to a vector of pointers to
+     where the operands were found.
+     Fill CONSTRAINTS and CONSTRAINTS1 with pointers to the
+     constraint-strings for this insn.
+     Return if the insn needs no reload processing.  */
+
+  switch (GET_CODE (body))
+    {
+    case USE:
+    case CLOBBER:
+    case ASM_INPUT:
+    case ADDR_VEC:
+    case ADDR_DIFF_VEC:
+      return;
+
+    case SET:
+      /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
+        is cheap to move between them.  If it is not, there may not be an insn
+        to do the copy, so we may need a reload.  */
+      if (GET_CODE (SET_DEST (body)) == REG
+         && REGNO (SET_DEST (body)) < FIRST_PSEUDO_REGISTER
+         && GET_CODE (SET_SRC (body)) == REG
+         && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
+         && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
+                                REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
+       return;
+    case PARALLEL:
+    case ASM_OPERANDS:
+      noperands = asm_noperands (body);
+      if (noperands >= 0)
+       {
+         /* This insn is an `asm' with operands.  */
+
+         insn_code_number = -1;
+         this_insn_is_asm = 1;
+
+         /* expand_asm_operands makes sure there aren't too many operands.  */
+         if (noperands > MAX_RECOG_OPERANDS)
+           abort ();
+
+         /* Now get the operand values and constraints out of the insn.  */
+
+         decode_asm_operands (body, recog_operand, recog_operand_loc,
+                              constraints, operand_mode);
+         if (noperands > 0)
+           {
+             bcopy (constraints, constraints1, noperands * sizeof (char *));
+             n_alternatives = n_occurrences (',', constraints[0]) + 1;
+             for (i = 1; i < noperands; i++)
+               if (n_alternatives != n_occurrences (',', constraints[0]) + 1)
+                 {
+                   error_for_asm (insn, "operand constraints differ in number of alternatives");
+                   /* Avoid further trouble with this insn.  */
+                   PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+                   n_reloads = 0;
+                   return;
+                 }
+           }
+         break;
+       }
+
+    default:
+      /* Ordinary insn: recognize it, get the operands via insn_extract
+        and get the constraints.  */
+
+      insn_code_number = recog_memoized (insn);
+      if (insn_code_number < 0)
+       fatal_insn_not_found (insn);
+
+      noperands = insn_n_operands[insn_code_number];
+      n_alternatives = insn_n_alternatives[insn_code_number];
+      /* Just return "no reloads" if insn has no operands with constraints.  */
+      if (n_alternatives == 0)
+       return;
+      insn_extract (insn);
+      for (i = 0; i < noperands; i++)
+       {
+         constraints[i] = constraints1[i]
+           = insn_operand_constraint[insn_code_number][i];
+         operand_mode[i] = insn_operand_mode[insn_code_number][i];
+       }
+    }
+
+  if (noperands == 0)
+    return;
+
+  commutative = -1;
+
+  /* If we will need to know, later, whether some pair of operands
+     are the same, we must compare them now and save the result.
+     Reloading the base and index registers will clobber them
+     and afterward they will fail to match.  */
+
+  for (i = 0; i < noperands; i++)
+    {
+      register char *p;
+      register int c;
+
+      substed_operand[i] = recog_operand[i];
+      p = constraints[i];
+
+      /* Scan this operand's constraint to see if it should match another.  */
+
+      while (c = *p++)
+       if (c == '%')
+         {
+           /* The last operand should not be marked commutative.  This
+              problem is hard to detect, so make it obvious by calling
+              abort here.  */
+           if (i == noperands - 1)
+             abort ();
+
+           commutative = i;
+         }
+       else if (c >= '0' && c <= '9')
+         {
+           c -= '0';
+           operands_match[c][i]
+             = operands_match_p (recog_operand[c], recog_operand[i]);
+           /* If C can be commuted with C+1, and C might need to match I,
+              then C+1 might also need to match I.  */
+           if (commutative >= 0)
+             {
+               if (c == commutative || c == commutative + 1)
+                 {
+                   int other = c + (c == commutative ? 1 : -1);
+                   operands_match[other][i]
+                     = operands_match_p (recog_operand[other], recog_operand[i]);
+                 }
+               if (i == commutative || i == commutative + 1)
+                 {
+                   int other = i + (i == commutative ? 1 : -1);
+                   operands_match[c][other]
+                     = operands_match_p (recog_operand[c], recog_operand[other]);
+                 }
+               /* Note that C is supposed to be less than I.
+                  No need to consider altering both C and I
+                  because in that case we would alter one into the other.  */
+             }
+         }
+    }
+
+  /* Examine each operand that is a memory reference or memory address
+     and reload parts of the addresses into index registers.
+     While we are at it, initialize the array `modified'.
+     Also here any references to pseudo regs that didn't get hard regs
+     but are equivalent to constants get replaced in the insn itself
+     with those constants.  Nobody will ever see them again. 
+
+     Finally, set up the preferred classes of each operand.  */
+
+  for (i = 0; i < noperands; i++)
+    {
+      register RTX_CODE code = GET_CODE (recog_operand[i]);
+      modified[i] = RELOAD_READ;
+      address_reloaded[i] = 0;
+      preferred_class[i]
+       = ((code == REG && REGNO (recog_operand[i]) > FIRST_PSEUDO_REGISTER)
+          ? reg_preferred_class (REGNO (recog_operand[i])) : NO_REGS);
+      pref_or_nothing[i]
+       = (code == REG && REGNO (recog_operand[i]) > FIRST_PSEUDO_REGISTER
+          && reg_preferred_or_nothing (REGNO (recog_operand[i])));
+
+      if (constraints[i][0] == 'p')
+       {
+         find_reloads_address (VOIDmode, 0,
+                               recog_operand[i], recog_operand_loc[i],
+                               recog_operand[i], ind_levels);
+         substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
+       }
+      else if (code == MEM)
+       {
+         if (find_reloads_address (GET_MODE (recog_operand[i]),
+                                   recog_operand_loc[i],
+                                   XEXP (recog_operand[i], 0),
+                                   &XEXP (recog_operand[i], 0),
+                                   recog_operand[i], ind_levels))
+           address_reloaded[i] = 1;
+         substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
+       }
+      else if (code == SUBREG)
+       substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
+         = find_reloads_toplev (recog_operand[i], ind_levels,
+                                set != 0
+                                && &SET_DEST (set) == recog_operand_loc[i]);
+      else if (code == REG)
+       {
+         /* This is equivalent to calling find_reloads_toplev.
+            The code is duplicated for speed.
+            When we find a pseudo always equivalent to a constant,
+            we replace it by the constant.  We must be sure, however,
+            that we don't try to replace it in the insn in which it
+            is being set.   */
+         register int regno = REGNO (recog_operand[i]);
+         if (reg_equiv_constant[regno] != 0
+             && (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
+           substed_operand[i] = recog_operand[i]
+             = reg_equiv_constant[regno];
+#if 0 /* This might screw code in reload1.c to delete prior output-reload
+        that feeds this insn.  */
+         if (reg_equiv_mem[regno] != 0)
+           substed_operand[i] = recog_operand[i]
+             = reg_equiv_mem[regno];
+#endif
+         if (reg_equiv_address[regno] != 0)
+           {
+             /* If reg_equiv_address is not a constant address, copy it,
+                since it may be shared.  */
+             rtx address = reg_equiv_address[regno];
+
+             if (rtx_varies_p (address))
+               address = copy_rtx (address);
+
+             /* If this is an output operand, we must output a CLOBBER
+                after INSN so find_equiv_reg knows REGNO is being written. */
+             if (constraints[i][0] == '='
+                 || constraints[i][0] == '+')
+               emit_insn_after (gen_rtx (CLOBBER, VOIDmode, recog_operand[i]),
+                                insn);
+
+             *recog_operand_loc[i] = recog_operand[i]
+               = gen_rtx (MEM, GET_MODE (recog_operand[i]), address);
+             RTX_UNCHANGING_P (recog_operand[i])
+               = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
+             find_reloads_address (GET_MODE (recog_operand[i]),
+                                   recog_operand_loc[i],
+                                   XEXP (recog_operand[i], 0),
+                                   &XEXP (recog_operand[i], 0),
+                                   recog_operand[i], ind_levels);
+             substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
+           }
+       }
+    }
+
+  /* If this is simply a copy from operand 1 to operand 0, merge the
+     preferred classes for the operands.  */
+  if (set != 0 && noperands >= 2 && recog_operand[0] == SET_DEST (set)
+      && recog_operand[1] == SET_SRC (set))
+    {
+      preferred_class[0] = preferred_class[1]
+       = reg_class_subunion[(int) preferred_class[0]][(int) preferred_class[1]];
+      pref_or_nothing[0] |= pref_or_nothing[1];
+      pref_or_nothing[1] |= pref_or_nothing[0];
+    }
+
+  /* Now see what we need for pseudo-regs that didn't get hard regs
+     or got the wrong kind of hard reg.  For this, we must consider
+     all the operands together against the register constraints.  */
+
+  best = MAX_RECOG_OPERANDS + 300;
+
+  swapped = 0;
+  goal_alternative_swapped = 0;
+ try_swapped:
+
+  /* The constraints are made of several alternatives.
+     Each operand's constraint looks like foo,bar,... with commas
+     separating the alternatives.  The first alternatives for all
+     operands go together, the second alternatives go together, etc.
+
+     First loop over alternatives.  */
+
+  for (this_alternative_number = 0;
+       this_alternative_number < n_alternatives;
+       this_alternative_number++)
+    {
+      /* Loop over operands for one constraint alternative.  */
+      /* LOSERS counts those that don't fit this alternative
+        and would require loading.  */
+      int losers = 0;
+      /* BAD is set to 1 if it some operand can't fit this alternative
+        even after reloading.  */
+      int bad = 0;
+      /* REJECT is a count of how undesirable this alternative says it is
+        if any reloading is required.  If the alternative matches exactly
+        then REJECT is ignored, but otherwise it gets this much
+        counted against it in addition to the reloading needed.  Each 
+        ? counts three times here since we want the disparaging caused by
+        a bad register class to only count 1/3 as much.  */
+      int reject = 0;
+
+      this_earlyclobber = 0;
+
+      for (i = 0; i < noperands; i++)
+       {
+         register char *p = constraints[i];
+         register int win = 0;
+         /* 0 => this operand can be reloaded somehow for this alternative */
+         int badop = 1;
+         /* 0 => this operand can be reloaded if the alternative allows regs.  */
+         int winreg = 0;
+         int c;
+         register rtx operand = recog_operand[i];
+         int offset = 0;
+         /* Nonzero means this is a MEM that must be reloaded into a reg
+            regardless of what the constraint says.  */
+         int force_reload = 0;
+         int offmemok = 0;
+         int earlyclobber = 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.)  */
+
+         while (GET_CODE (operand) == SUBREG)
+           {
+             offset += SUBREG_WORD (operand);
+             operand = SUBREG_REG (operand);
+             /* Force reload if this is not a register or if there may may
+                be a problem accessing the register in the outer mode.  */
+             if (GET_CODE (operand) != REG
+#ifdef BYTE_LOADS_ZERO_EXTEND
+                 /* Nonparadoxical subreg of a pseudoreg.
+                    Don't to load the full width if on this machine
+                    we expected the fetch to zero-extend.  */
+                 || ((GET_MODE_SIZE (operand_mode[i])
+                      > GET_MODE_SIZE (GET_MODE (operand)))
+                     && REGNO (operand) >= FIRST_PSEUDO_REGISTER)
+#endif /* BYTE_LOADS_ZERO_EXTEND */
+                 /* 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.  */
+                 || (REGNO (operand) < FIRST_PSEUDO_REGISTER
+                     && (! HARD_REGNO_MODE_OK (REGNO (operand),
+                                               operand_mode[i])
+                         || (GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
+                             && (GET_MODE_SIZE (GET_MODE (operand))
+                                 > UNITS_PER_WORD)
+                             && ((GET_MODE_SIZE (GET_MODE (operand))
+                                  / UNITS_PER_WORD)
+                                 != HARD_REGNO_NREGS (REGNO (operand),
+                                                      GET_MODE (operand)))))))
+               force_reload = 1;
+           }
+
+         this_alternative[i] = (int) NO_REGS;
+         this_alternative_win[i] = 0;
+         this_alternative_offmemok[i] = 0;
+         this_alternative_earlyclobber[i] = 0;
+         this_alternative_matches[i] = -1;
+
+         /* An empty constraint or empty alternative
+            allows anything which matched the pattern.  */
+         if (*p == 0 || *p == ',')
+           win = 1, badop = 0;
+
+         /* Scan this alternative's specs for this operand;
+            set WIN if the operand fits any letter in this alternative.
+            Otherwise, clear BADOP if this operand could
+            fit some letter after reloads,
+            or set WINREG if this operand could fit after reloads
+            provided the constraint allows some registers.  */
+
+         while (*p && (c = *p++) != ',')
+           switch (c)
+             {
+             case '=':
+               modified[i] = RELOAD_WRITE;
+               break;
+
+             case '+':
+               modified[i] = RELOAD_READ_WRITE;
+               break;
+
+             case '*':
+               break;
+
+             case '%':
+               commutative = i;
+               break;
+
+             case '?':
+               reject += 3;
+               break;
+
+             case '!':
+               reject = 300;
+               break;
+
+             case '#':
+               /* Ignore rest of this alternative as far as
+                  reloading is concerned.  */
+               while (*p && *p != ',') p++;
+               break;
+
+             case '0':
+             case '1':
+             case '2':
+             case '3':
+             case '4':
+               c -= '0';
+               this_alternative_matches[i] = c;
+               /* We are supposed to match a previous operand.
+                  If we do, we win if that one did.
+                  If we do not, count both of the operands as losers.
+                  (This is too conservative, since most of the time
+                  only a single reload insn will be needed to make
+                  the two operands win.  As a result, this alternative
+                  may be rejected when it is actually desirable.)  */
+               if ((swapped && (c != commutative || i != commutative + 1))
+                   /* If we are matching as if two operands were swapped,
+                      also pretend that operands_match had been computed
+                      with swapped.
+                      But if I is the second of those and C is the first,
+                      don't exchange them, because operands_match is valid
+                      only on one side of its diagonal.  */
+                   ? (operands_match
+                       [(c == commutative || c == commutative + 1)
+                        ? 2*commutative + 1 - c : c]
+                       [(i == commutative || i == commutative + 1)
+                        ? 2*commutative + 1 - i : i])
+                   : operands_match[c][i])
+                 win = this_alternative_win[c];
+               else
+                 {
+                   /* Operands don't match.  */
+                   rtx value;
+                   /* Retroactively mark the operand we had to match
+                      as a loser, if it wasn't already.  */
+                   if (this_alternative_win[c])
+                     losers++;
+                   this_alternative_win[c] = 0;
+                   if (this_alternative[c] == (int) NO_REGS)
+                     bad = 1;
+                   /* But count the pair only once in the total badness of
+                      this alternative, if the pair can be a dummy reload.  */
+                   value
+                     = find_dummy_reload (recog_operand[i], recog_operand[c],
+                                          recog_operand_loc[i], recog_operand_loc[c],
+                                          this_alternative[c], -1);
+
+                   if (value != 0)
+                     losers--;
+                 }
+               /* This can be fixed with reloads if the operand
+                  we are supposed to match can be fixed with reloads.  */
+               badop = 0;
+               this_alternative[i] = this_alternative[c];
+               break;
+
+             case 'p':
+               /* All necessary reloads for an address_operand
+                  were handled in find_reloads_address.  */
+               this_alternative[i] = (int) ALL_REGS;
+               win = 1;
+               break;
+
+             case 'm':
+               if (force_reload)
+                 break;
+               if (GET_CODE (operand) == MEM
+                   || (GET_CODE (operand) == REG
+                       && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+                       && reg_renumber[REGNO (operand)] < 0))
+                 win = 1;
+               if (CONSTANT_P (operand))
+                 badop = 0;
+               break;
+
+             case '<':
+               if (GET_CODE (operand) == MEM
+                   && ! address_reloaded[i]
+                   && (GET_CODE (XEXP (operand, 0)) == PRE_DEC
+                       || GET_CODE (XEXP (operand, 0)) == POST_DEC))
+                 win = 1;
+               break;
+
+             case '>':
+               if (GET_CODE (operand) == MEM
+                   && ! address_reloaded[i]
+                   && (GET_CODE (XEXP (operand, 0)) == PRE_INC
+                       || GET_CODE (XEXP (operand, 0)) == POST_INC))
+                 win = 1;
+               break;
+
+               /* Memory operand whose address is not offsettable.  */
+             case 'V':
+               if (force_reload)
+                 break;
+               if (GET_CODE (operand) == MEM
+                   && ! (ind_levels ? offsettable_memref_p (operand)
+                         : offsettable_nonstrict_memref_p (operand))
+                   /* Certain mem addresses will become offsettable
+                      after they themselves are reloaded.  This is important;
+                      we don't want our own handling of unoffsettables
+                      to override the handling of reg_equiv_address.  */
+                   && !(GET_CODE (XEXP (operand, 0)) == REG
+                        && (ind_levels == 0
+                            || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0)))
+                 win = 1;
+               break;
+
+               /* Memory operand whose address is offsettable.  */
+             case 'o':
+               if (force_reload)
+                 break;
+               if ((GET_CODE (operand) == MEM
+                    /* If IND_LEVELS, find_reloads_address won't reload a
+                       pseudo that didn't get a hard reg, so we have to
+                       reject that case.  */
+                    && (ind_levels ? offsettable_memref_p (operand)
+                        : offsettable_nonstrict_memref_p (operand)))
+                   /* Certain mem addresses will become offsettable
+                      after they themselves are reloaded.  This is important;
+                      we don't want our own handling of unoffsettables
+                      to override the handling of reg_equiv_address.  */
+                   || (GET_CODE (operand) == MEM
+                       && GET_CODE (XEXP (operand, 0)) == REG
+                       && (ind_levels == 0
+                           || reg_equiv_address[REGNO (XEXP (operand, 0))] != 0))
+                   || (GET_CODE (operand) == REG
+                       && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+                       && reg_renumber[REGNO (operand)] < 0))
+                 win = 1;
+               if (CONSTANT_P (operand) || GET_CODE (operand) == MEM)
+                 badop = 0;
+               offmemok = 1;
+               break;
+
+             case '&':
+               /* Output operand that is stored before the need for the
+                  input operands (and their index registers) is over.  */
+               earlyclobber = 1, this_earlyclobber = 1;
+               break;
+
+             case 'E':
+               /* 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_INT != BITS_PER_WORD)
+                   && GET_MODE (operand) != VOIDmode && ! flag_pretend_float)
+                 break;
+               if (GET_CODE (operand) == CONST_DOUBLE)
+                 win = 1;
+               break;
+
+             case 'F':
+               if (GET_CODE (operand) == CONST_DOUBLE)
+                 win = 1;
+               break;
+
+             case 'G':
+             case 'H':
+               if (GET_CODE (operand) == CONST_DOUBLE
+                   && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
+                 win = 1;
+               break;
+
+             case 's':
+               if (GET_CODE (operand) == CONST_INT
+                   || (GET_CODE (operand) == CONST_DOUBLE
+                       && GET_MODE (operand) == VOIDmode))
+                 break;
+             case 'i':
+               if (CONSTANT_P (operand)
+#ifdef LEGITIMATE_PIC_OPERAND_P
+                   && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand))
+#endif
+                   )
+                 win = 1;
+               break;
+
+             case 'n':
+               if (GET_CODE (operand) == CONST_INT
+                   || (GET_CODE (operand) == CONST_DOUBLE
+                       && GET_MODE (operand) == VOIDmode))
+                 win = 1;
+               break;
+
+             case 'I':
+             case 'J':
+             case 'K':
+             case 'L':
+             case 'M':
+             case 'N':
+             case 'O':
+             case 'P':
+               if (GET_CODE (operand) == CONST_INT
+                   && CONST_OK_FOR_LETTER_P (INTVAL (operand), c))
+                 win = 1;
+               break;
+
+             case 'X':
+               win = 1;
+               break;
+
+             case 'g':
+               if (! force_reload
+                   /* A PLUS is never a valid operand, but reload can make
+                      it from a register when eliminating registers.  */
+                   && GET_CODE (operand) != PLUS
+                   /* A SCRATCH is not a valid operand.  */
+                   && GET_CODE (operand) != SCRATCH
+#ifdef LEGITIMATE_PIC_OPERAND_P
+                   && (! CONSTANT_P (operand) 
+                       || ! flag_pic 
+                       || LEGITIMATE_PIC_OPERAND_P (operand))
+#endif
+                   && (GENERAL_REGS == ALL_REGS
+                       || GET_CODE (operand) != REG
+                       || (REGNO (operand) >= FIRST_PSEUDO_REGISTER
+                           && reg_renumber[REGNO (operand)] < 0)))
+                 win = 1;
+               /* Drop through into 'r' case */
+
+             case 'r':
+               this_alternative[i]
+                 = (int) reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
+               goto reg;
+
+#ifdef EXTRA_CONSTRAINT
+              case 'Q':
+              case 'R':
+              case 'S':
+              case 'T':
+              case 'U':
+               if (EXTRA_CONSTRAINT (operand, c))
+                 win = 1;
+               break;
+#endif
+  
+             default:
+               this_alternative[i]
+                 = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
+               
+             reg:
+               if (GET_MODE (operand) == BLKmode)
+                 break;
+               winreg = 1;
+               if (GET_CODE (operand) == REG
+                   && reg_fits_class_p (operand, this_alternative[i],
+                                        offset, GET_MODE (recog_operand[i])))
+                 win = 1;
+               break;
+             }
+
+         constraints[i] = p;
+
+         /* If this operand could be handled with a reg,
+            and some reg is allowed, then this operand can be handled.  */
+         if (winreg && this_alternative[i] != (int) NO_REGS)
+           badop = 0;
+
+         /* Record which operands fit this alternative.  */
+         this_alternative_earlyclobber[i] = earlyclobber;
+         if (win && ! force_reload)
+           this_alternative_win[i] = 1;
+         else
+           {
+             this_alternative_offmemok[i] = offmemok;
+             losers++;
+             if (badop)
+               bad = 1;
+             /* Alternative loses if it has no regs for a reg operand.  */
+             if (GET_CODE (operand) == REG
+                 && this_alternative[i] == (int) NO_REGS
+                 && this_alternative_matches[i] < 0)
+               bad = 1;
+
+             /* Alternative loses if it requires a type of reload not
+                permitted for this insn.  We can always reload SCRATCH
+                and objects with a REG_UNUSED note.  */
+             if (GET_CODE (operand) != SCRATCH && modified[i] != RELOAD_READ
+                 && no_output_reloads
+                 && ! find_reg_note (insn, REG_UNUSED, operand))
+               bad = 1;
+             else if (modified[i] != RELOAD_WRITE && no_input_reloads)
+               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)
+               reject++;
+           }
+
+         /* If this operand is a pseudo register that didn't get a hard 
+            reg and this alternative accepts some register, see if the
+            class that we want is a subset of the preferred class for this
+            register.  If not, but it intersects that class, use the
+            preferred class instead.  If it does not intersect the preferred
+            class, show that usage of this alternative should be discouraged;
+            it will be discouraged more still if the register is `preferred
+            or nothing'.  We do this because it increases the chance of
+            reusing our spill register in a later insn and avoiding a pair
+            of memory stores and loads.
+
+            Don't bother with this if this alternative will accept this
+            operand.
+
+            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
+             && reg_class_size[(int) preferred_class[i]] > 1)
+           {
+             if (! reg_class_subset_p (this_alternative[i],
+                                       preferred_class[i]))
+               {
+                 /* Since we don't have a way of forming the intersection,
+                    we just do something special if the preferred class
+                    is a subset of the class we have; that's the most 
+                    common case anyway.  */
+                 if (reg_class_subset_p (preferred_class[i],
+                                         this_alternative[i]))
+                   this_alternative[i] = (int) preferred_class[i];
+                 else
+                   reject += (1 + pref_or_nothing[i]);
+               }
+           }
+       }
+
+      /* Now see if any output operands that are marked "earlyclobber"
+        in this alternative conflict with any input operands
+        or any memory addresses.  */
+
+      for (i = 0; i < noperands; i++)
+       if (this_alternative_earlyclobber[i]
+           && this_alternative_win[i])
+         {
+           struct decomposition early_data; 
+           int j;
+
+           early_data = decompose (recog_operand[i]);
+
+           if (modified[i] == RELOAD_READ)
+             {
+               if (this_insn_is_asm)
+                 warning_for_asm (this_insn,
+                                  "`&' constraint used with input operand");
+               else
+                 abort ();
+               continue;
+             }
+           
+           if (this_alternative[i] == NO_REGS)
+             {
+               this_alternative_earlyclobber[i] = 0;
+               if (this_insn_is_asm)
+                 error_for_asm (this_insn,
+                                "`&' constraint used with no register class");
+               else
+                 abort ();
+             }
+
+           for (j = 0; j < noperands; j++)
+             /* Is this an input operand or a memory ref?  */
+             if ((GET_CODE (recog_operand[j]) == MEM
+                  || modified[j] != RELOAD_WRITE)
+                 && j != i
+                 /* Ignore things like match_operator operands.  */
+                 && *constraints1[j] != 0
+                 /* Don't count an input operand that is constrained to match
+                    the early clobber operand.  */
+                 && ! (this_alternative_matches[j] == i
+                       && rtx_equal_p (recog_operand[i], recog_operand[j]))
+                 /* Is it altered by storing the earlyclobber operand?  */
+                 && !immune_p (recog_operand[j], recog_operand[i], early_data))
+               {
+                 /* If the output is in a single-reg class,
+                    it's costly to reload it, so reload the input instead.  */
+                 if (reg_class_size[this_alternative[i]] == 1
+                     && (GET_CODE (recog_operand[j]) == REG
+                         || GET_CODE (recog_operand[j]) == SUBREG))
+                   {
+                     losers++;
+                     this_alternative_win[j] = 0;
+                   }
+                 else
+                   break;
+               }
+           /* If an earlyclobber operand conflicts with something,
+              it must be reloaded, so request this and count the cost.  */
+           if (j != noperands)
+             {
+               losers++;
+               this_alternative_win[i] = 0;
+               for (j = 0; j < noperands; j++)
+                 if (this_alternative_matches[j] == i
+                     && this_alternative_win[j])
+                   {
+                     this_alternative_win[j] = 0;
+                     losers++;
+                   }
+             }
+         }
+
+      /* If one alternative accepts all the operands, no reload required,
+        choose that alternative; don't consider the remaining ones.  */
+      if (losers == 0)
+       {
+         /* Unswap these so that they are never swapped at `finish'.  */
+         if (commutative >= 0)
+           {
+             recog_operand[commutative] = substed_operand[commutative];
+             recog_operand[commutative + 1]
+               = substed_operand[commutative + 1];
+           }
+         for (i = 0; i < noperands; i++)
+           {
+             goal_alternative_win[i] = 1;
+             goal_alternative[i] = this_alternative[i];
+             goal_alternative_offmemok[i] = this_alternative_offmemok[i];
+             goal_alternative_matches[i] = this_alternative_matches[i];
+             goal_alternative_earlyclobber[i]
+               = this_alternative_earlyclobber[i];
+           }
+         goal_alternative_number = this_alternative_number;
+         goal_alternative_swapped = swapped;
+         goal_earlyclobber = this_earlyclobber;
+         goto finish;
+       }
+
+      /* REJECT, set by the ! and ? constraint characters and when a register
+        would be reloaded into a non-preferred class, discourages the use of
+        this alternative for a reload goal.  REJECT is incremented by three
+        for each ? and one for each non-preferred class.  */
+      losers = losers * 3 + reject;
+
+      /* If this alternative can be made to work by reloading,
+        and it needs less reloading than the others checked so far,
+        record it as the chosen goal for reloading.  */
+      if (! bad && best > losers)
+       {
+         for (i = 0; i < noperands; i++)
+           {
+             goal_alternative[i] = this_alternative[i];
+             goal_alternative_win[i] = this_alternative_win[i];
+             goal_alternative_offmemok[i] = this_alternative_offmemok[i];
+             goal_alternative_matches[i] = this_alternative_matches[i];
+             goal_alternative_earlyclobber[i]
+               = this_alternative_earlyclobber[i];
+           }
+         goal_alternative_swapped = swapped;
+         best = losers;
+         goal_alternative_number = this_alternative_number;
+         goal_earlyclobber = this_earlyclobber;
+       }
+    }
+
+  /* If insn is commutative (it's safe to exchange a certain pair of operands)
+     then we need to try each alternative twice,
+     the second time matching those two operands
+     as if we had exchanged them.
+     To do this, really exchange them in operands.
+
+     If we have just tried the alternatives the second time,
+     return operands to normal and drop through.  */
+
+  if (commutative >= 0)
+    {
+      swapped = !swapped;
+      if (swapped)
+       {
+         register enum reg_class tclass;
+         register int t;
+
+         recog_operand[commutative] = substed_operand[commutative + 1];
+         recog_operand[commutative + 1] = substed_operand[commutative];
+
+         tclass = preferred_class[commutative];
+         preferred_class[commutative] = preferred_class[commutative + 1];
+         preferred_class[commutative + 1] = tclass;
+
+         t = pref_or_nothing[commutative];
+         pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
+         pref_or_nothing[commutative + 1] = t;
+
+         bcopy (constraints1, constraints, noperands * sizeof (char *));
+         goto try_swapped;
+       }
+      else
+       {
+         recog_operand[commutative] = substed_operand[commutative];
+         recog_operand[commutative + 1] = substed_operand[commutative + 1];
+       }
+    }
+
+  /* The operands don't meet the constraints.
+     goal_alternative describes the alternative
+     that we could reach by reloading the fewest operands.
+     Reload so as to fit it.  */
+
+  if (best == MAX_RECOG_OPERANDS + 300)
+    {
+      /* No alternative works with reloads??  */
+      if (insn_code_number >= 0)
+       abort ();
+      error_for_asm (insn, "inconsistent operand constraints in an `asm'");
+      /* Avoid further trouble with this insn.  */
+      PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+      n_reloads = 0;
+      return;
+    }
+
+  /* Jump to `finish' from above if all operands are valid already.
+     In that case, goal_alternative_win is all 1.  */
+ finish:
+
+  /* Right now, for any pair of operands I and J that are required to match,
+     with I < J,
+     goal_alternative_matches[J] is I.
+     Set up goal_alternative_matched as the inverse function:
+     goal_alternative_matched[I] = J.  */
+
+  for (i = 0; i < noperands; i++)
+    goal_alternative_matched[i] = -1;
+
+  for (i = 0; i < noperands; i++)
+    if (! goal_alternative_win[i]
+       && goal_alternative_matches[i] >= 0)
+      goal_alternative_matched[goal_alternative_matches[i]] = i;
+
+  /* If the best alternative is with operands 1 and 2 swapped,
+     consider them swapped before reporting the reloads.  */
+
+  if (goal_alternative_swapped)
+    {
+      register rtx tem;
+
+      tem = substed_operand[commutative];
+      substed_operand[commutative] = substed_operand[commutative + 1];
+      substed_operand[commutative + 1] = tem;
+      tem = recog_operand[commutative];
+      recog_operand[commutative] = recog_operand[commutative + 1];
+      recog_operand[commutative + 1] = tem;
+    }
+
+  /* Perform whatever substitutions on the operands we are supposed
+     to make due to commutativity or replacement of registers
+     with equivalent constants or memory slots.  */
+
+  for (i = 0; i < noperands; i++)
+    {
+      *recog_operand_loc[i] = substed_operand[i];
+      /* While we are looping on operands, initialize this.  */
+      operand_reloadnum[i] = -1;
+    }
+
+  /* Any constants that aren't allowed and can't be reloaded
+     into registers are here changed into memory references.  */
+  for (i = 0; i < noperands; i++)
+    if (! goal_alternative_win[i]
+       && CONSTANT_P (recog_operand[i])
+       && (PREFERRED_RELOAD_CLASS (recog_operand[i],
+                                   (enum reg_class) goal_alternative[i])
+           == NO_REGS)
+       && operand_mode[i] != VOIDmode)
+      {
+       *recog_operand_loc[i] = recog_operand[i]
+         = find_reloads_toplev (force_const_mem (operand_mode[i],
+                                                 recog_operand[i]),
+                                ind_levels, 0);
+       if (alternative_allows_memconst (constraints1[i],
+                                        goal_alternative_number))
+         goal_alternative_win[i] = 1;
+      }
+
+  /* Now record reloads for all the operands that need them.  */
+  for (i = 0; i < noperands; i++)
+    if (! goal_alternative_win[i])
+      {
+       /* Operands that match previous ones have already been handled.  */
+       if (goal_alternative_matches[i] >= 0)
+         ;
+       /* Handle an operand with a nonoffsettable address
+          appearing where an offsettable address will do
+          by reloading the address into a base register.  */
+       else if (goal_alternative_matched[i] == -1
+                && goal_alternative_offmemok[i]
+                && GET_CODE (recog_operand[i]) == MEM)
+         {
+           operand_reloadnum[i]
+             = push_reload (XEXP (recog_operand[i], 0), 0,
+                            &XEXP (recog_operand[i], 0), 0,
+                            BASE_REG_CLASS, GET_MODE (XEXP (recog_operand[i], 0)),
+                            VOIDmode, 0, 0, 0);
+           reload_inc[operand_reloadnum[i]]
+             = GET_MODE_SIZE (GET_MODE (recog_operand[i]));
+         }
+       else if (goal_alternative_matched[i] == -1)
+         operand_reloadnum[i] =
+           push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
+                        modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+                        modified[i] != RELOAD_WRITE ? recog_operand_loc[i] : 0,
+                        modified[i] != RELOAD_READ ? recog_operand_loc[i] : 0,
+                        (enum reg_class) goal_alternative[i],
+                        (modified[i] == RELOAD_WRITE ? VOIDmode : operand_mode[i]),
+                        (modified[i] == RELOAD_READ ? VOIDmode : operand_mode[i]),
+                        (insn_code_number < 0 ? 0
+                         : insn_operand_strict_low[insn_code_number][i]),
+                        0, 0);
+       /* In a matching pair of operands, one must be input only
+          and the other must be output only.
+          Pass the input operand as IN and the other as OUT.  */
+       else if (modified[i] == RELOAD_READ
+                && modified[goal_alternative_matched[i]] == RELOAD_WRITE)
+         {
+           operand_reloadnum[i]
+             = push_reload (recog_operand[i],
+                            recog_operand[goal_alternative_matched[i]],
+                            recog_operand_loc[i],
+                            recog_operand_loc[goal_alternative_matched[i]],
+                            (enum reg_class) goal_alternative[i],
+                            operand_mode[i],
+                            operand_mode[goal_alternative_matched[i]],
+                            0, 0, 0);
+           operand_reloadnum[goal_alternative_matched[i]] = output_reloadnum;
+         }
+       else if (modified[i] == RELOAD_WRITE
+                && modified[goal_alternative_matched[i]] == RELOAD_READ)
+         {
+           operand_reloadnum[goal_alternative_matched[i]]
+             = push_reload (recog_operand[goal_alternative_matched[i]],
+                            recog_operand[i],
+                            recog_operand_loc[goal_alternative_matched[i]],
+                            recog_operand_loc[i],
+                            (enum reg_class) goal_alternative[i],
+                            operand_mode[goal_alternative_matched[i]],
+                            operand_mode[i],
+                            0, 0, 0);
+           operand_reloadnum[i] = output_reloadnum;
+         }
+       else if (insn_code_number >= 0)
+         abort ();
+       else
+         {
+           error_for_asm (insn, "inconsistent operand constraints in an `asm'");
+           /* Avoid further trouble with this insn.  */
+           PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+           n_reloads = 0;
+           return;
+         }
+      }
+    else if (goal_alternative_matched[i] < 0
+            && goal_alternative_matches[i] < 0
+            && optimize)
+      {
+       rtx operand = recog_operand[i];
+       /* For each non-matching operand that's a pseudo-register 
+          that didn't get a hard register, make an optional reload.
+          This may get done even if the insn needs no reloads otherwise.  */
+       /* (It would be safe to make an optional reload for a matching pair
+          of operands, but we don't bother yet.)  */
+       while (GET_CODE (operand) == SUBREG)
+         operand = XEXP (operand, 0);
+       if (GET_CODE (operand) == REG
+           && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+           && reg_renumber[REGNO (operand)] < 0
+           && (enum reg_class) goal_alternative[i] != NO_REGS
+           /* Don't make optional output reloads for jump insns
+              (such as aobjeq on the vax).  */
+           && (modified[i] == RELOAD_READ
+               || GET_CODE (insn) != JUMP_INSN))
+         operand_reloadnum[i]
+           = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
+                          modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+                          modified[i] != RELOAD_WRITE ? recog_operand_loc[i] : 0,
+                          modified[i] != RELOAD_READ ? recog_operand_loc[i] : 0,
+                          (enum reg_class) goal_alternative[i],
+                          (modified[i] == RELOAD_WRITE ? VOIDmode : operand_mode[i]),
+                          (modified[i] == RELOAD_READ ? VOIDmode : operand_mode[i]),
+                          (insn_code_number < 0 ? 0
+                           : insn_operand_strict_low[insn_code_number][i]),
+                          1, 0);
+       /* Make an optional reload for an explicit mem ref.  */
+       else if (GET_CODE (operand) == MEM
+                && (enum reg_class) goal_alternative[i] != NO_REGS
+                /* Don't make optional output reloads for jump insns
+                   (such as aobjeq on the vax).  */
+                && (modified[i] == RELOAD_READ
+                    || GET_CODE (insn) != JUMP_INSN))
+         operand_reloadnum[i]
+           = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
+                          modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+                          modified[i] != RELOAD_WRITE ? recog_operand_loc[i] : 0,
+                          modified[i] != RELOAD_READ ? recog_operand_loc[i] : 0,
+                          (enum reg_class) goal_alternative[i],
+                          (modified[i] == RELOAD_WRITE ? VOIDmode : operand_mode[i]),
+                          (modified[i] == RELOAD_READ ? VOIDmode : operand_mode[i]),
+                          (insn_code_number < 0 ? 0
+                           : insn_operand_strict_low[insn_code_number][i]),
+                          1, 0);
+       else
+         non_reloaded_operands[n_non_reloaded_operands++] = recog_operand[i];
+      }
+    else if (goal_alternative_matched[i] < 0
+            && goal_alternative_matches[i] < 0)
+      non_reloaded_operands[n_non_reloaded_operands++] = recog_operand[i];
+
+  /* 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.
+
+     Don't do this if we aren't making replacements because we might be
+     propagating things allocated by frame pointer elimination into places
+     it doesn't expect.  */
+
+  if (insn_code_number >= 0 && replace)
+    for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
+      {
+       int opno = recog_dup_num[i];
+       *recog_dup_loc[i] = *recog_operand_loc[opno];
+       if (operand_reloadnum[opno] >= 0)
+         push_replacement (recog_dup_loc[i], operand_reloadnum[opno],
+                           insn_operand_mode[insn_code_number][opno]);
+      }
+
+#if 0
+  /* This loses because reloading of prior insns can invalidate the equivalence
+     (or at least find_equiv_reg isn't smart enough to find it any more),
+     causing this insn to need more reload regs than it needed before.
+     It may be too late to make the reload regs available.
+     Now this optimization is done safely in choose_reload_regs.  */
+
+  /* For each reload of a reg into some other class of reg,
+     search for an existing equivalent reg (same value now) in the right class.
+     We can use it as long as we don't need to change its contents.  */
+  for (i = 0; i < n_reloads; i++)
+    if (reload_reg_rtx[i] == 0
+       && reload_in[i] != 0
+       && GET_CODE (reload_in[i]) == REG
+       && reload_out[i] == 0)
+      {
+       reload_reg_rtx[i]
+         = find_equiv_reg (reload_in[i], insn, reload_reg_class[i], -1,
+                           static_reload_reg_p, 0, reload_inmode[i]);
+       /* Prevent generation of insn to load the value
+          because the one we found already has the value.  */
+       if (reload_reg_rtx[i])
+         reload_in[i] = reload_reg_rtx[i];
+      }
+#endif
+
+#else /* no REGISTER_CONSTRAINTS */
+  int noperands;
+  int insn_code_number;
+  int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen.  */
+  register int i;
+  rtx body = PATTERN (insn);
+
+  n_reloads = 0;
+  n_replacements = 0;
+  n_earlyclobbers = 0;
+  replace_reloads = replace;
+  this_insn = insn;
+
+  /* Find what kind of insn this is.  NOPERANDS gets number of operands.
+     Store the operand values in RECOG_OPERAND and the locations
+     of the words in the insn that point to them in RECOG_OPERAND_LOC.
+     Return if the insn needs no reload processing.  */
+
+  switch (GET_CODE (body))
+    {
+    case USE:
+    case CLOBBER:
+    case ASM_INPUT:
+    case ADDR_VEC:
+    case ADDR_DIFF_VEC:
+      return;
+
+    case PARALLEL:
+    case SET:
+      noperands = asm_noperands (body);
+      if (noperands >= 0)
+       {
+         /* This insn is an `asm' with operands.
+            First, find out how many operands, and allocate space.  */
+
+         insn_code_number = -1;
+         /* ??? This is a bug! ???
+            Give up and delete this insn if it has too many operands.  */
+         if (noperands > MAX_RECOG_OPERANDS)
+           abort ();
+
+         /* Now get the operand values out of the insn.  */
+
+         decode_asm_operands (body, recog_operand, recog_operand_loc, 0, 0);
+         break;
+       }
+
+    default:
+      /* Ordinary insn: recognize it, allocate space for operands and
+        constraints, and get them out via insn_extract.  */
+
+      insn_code_number = recog_memoized (insn);
+      noperands = insn_n_operands[insn_code_number];
+      insn_extract (insn);
+    }
+
+  if (noperands == 0)
+    return;
+
+  for (i = 0; i < noperands; i++)
+    {
+      register RTX_CODE code = GET_CODE (recog_operand[i]);
+      int is_set_dest = GET_CODE (body) == SET && (i == 0);
+
+      if (insn_code_number >= 0)
+       if (insn_operand_address_p[insn_code_number][i])
+         find_reloads_address (VOIDmode, 0,
+                               recog_operand[i], recog_operand_loc[i],
+                               recog_operand[i], ind_levels);
+      if (code == MEM)
+       find_reloads_address (GET_MODE (recog_operand[i]),
+                             recog_operand_loc[i],
+                             XEXP (recog_operand[i], 0),
+                             &XEXP (recog_operand[i], 0),
+                             recog_operand[i], ind_levels);
+      if (code == SUBREG)
+       recog_operand[i] = *recog_operand_loc[i]
+         = find_reloads_toplev (recog_operand[i], ind_levels, is_set_dest);
+      if (code == REG)
+       {
+         register int regno = REGNO (recog_operand[i]);
+         if (reg_equiv_constant[regno] != 0 && !is_set_dest)
+           recog_operand[i] = *recog_operand_loc[i]
+             = reg_equiv_constant[regno];
+#if 0 /* This might screw code in reload1.c to delete prior output-reload
+        that feeds this insn.  */
+         if (reg_equiv_mem[regno] != 0)
+           recog_operand[i] = *recog_operand_loc[i]
+             = reg_equiv_mem[regno];
+#endif
+       }
+      /* All operands are non-reloaded.  */
+      non_reloaded_operands[n_non_reloaded_operands++] = recog_operand[i];
+    }
+#endif /* no REGISTER_CONSTRAINTS */
+
+  /* Determine which part of the insn each reload is needed for,
+     based on which operand the reload is needed for.
+     Reloads of entire operands are classified as RELOAD_OTHER.
+     So are reloads for which a unique purpose is not known.  */
+
+  for (i = 0; i < n_reloads; i++)
+    {
+      reload_when_needed[i] = RELOAD_OTHER;
+
+      if (reload_needed_for[i] != 0 && ! reload_needed_for_multiple[i])
+       {
+         int j;
+         int output_address = 0;
+         int input_address = 0;
+         int operand_address = 0;
+
+         /* This reload is needed only for the address of something.
+            Determine whether it is needed for addressing an operand
+            being reloaded for input, whether it is needed for an
+            operand being reloaded for output, and whether it is needed
+            for addressing an operand that won't really be reloaded.
+
+            Note that we know that this reload is needed in only one address,
+            but we have not yet checked for the case where that same address
+            is used in both input and output reloads.
+            The following code detects this case.  */
+
+         for (j = 0; j < n_reloads; j++)
+           if (reload_needed_for[i] == reload_in[j]
+               || reload_needed_for[i] == reload_out[j])
+             {
+               if (reload_optional[j])
+                 operand_address = 1;
+               else
+                 {
+                   if (reload_needed_for[i] == reload_in[j])
+                     input_address = 1;
+                   if (reload_needed_for[i] == reload_out[j])
+                     output_address = 1;
+                 }
+             }
+         /* Don't ignore memrefs without optional reloads.  */
+         for (j = 0; j < n_non_reloaded_operands; j++)
+           if (reload_needed_for[i] == non_reloaded_operands[j])
+             operand_address = 1;
+
+         /* If it is needed for only one of those, record which one.  */
+
+         if (input_address && ! output_address && ! operand_address)
+           reload_when_needed[i] = RELOAD_FOR_INPUT_RELOAD_ADDRESS;
+         if (output_address && ! input_address && ! operand_address)
+           reload_when_needed[i] = RELOAD_FOR_OUTPUT_RELOAD_ADDRESS;
+         if (operand_address && ! input_address && ! output_address)
+           reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+
+         /* Indicate those RELOAD_OTHER reloads which, though they have
+            0 for reload_output, still cannot overlap an output reload.  */
+
+         if (output_address && reload_when_needed[i] == RELOAD_OTHER)
+           reload_needed_for_multiple[i] = 1;
+       }
+    }
+
+  /* Perhaps an output reload can be combined with another
+     to reduce needs by one.  */
+  if (!goal_earlyclobber)
+    combine_reloads ();
+}
+
+/* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
+   accepts a memory operand with constant address.  */
+
+static int
+alternative_allows_memconst (constraint, altnum)
+     char *constraint;
+     int altnum;
+{
+  register int c;
+  /* Skip alternatives before the one requested.  */
+  while (altnum > 0)
+    {
+      while (*constraint++ != ',');
+      altnum--;
+    }
+  /* Scan the requested alternative for 'm' or 'o'.
+     If one of them is present, this alternative accepts memory constants.  */
+  while ((c = *constraint++) && c != ',' && c != '#')
+    if (c == 'm' || c == 'o')
+      return 1;
+  return 0;
+}
+\f
+/* Scan X for memory references and scan the addresses for reloading.
+   Also checks for references to "constant" regs that we want to eliminate
+   and replaces them with the values they stand for.
+   We may alter X descructively if it contains a reference to such.
+   If X is just a constant reg, we return the equivalent value
+   instead of X.
+
+   IND_LEVELS says how many levels of indirect addressing this machine
+   supports.
+
+   IS_SET_DEST is true if X is the destination of a SET, which is not
+   appropriate to be replaced by a constant.  */
+
+static rtx
+find_reloads_toplev (x, ind_levels, is_set_dest)
+     rtx x;
+     int ind_levels;
+     int is_set_dest;
+{
+  register RTX_CODE code = GET_CODE (x);
+
+  register char *fmt = GET_RTX_FORMAT (code);
+  register int i;
+
+  if (code == REG)
+    {
+      /* This code is duplicated for speed in find_reloads.  */
+      register int regno = REGNO (x);
+      if (reg_equiv_constant[regno] != 0 && !is_set_dest)
+       x = reg_equiv_constant[regno];
+#if 0
+/*  This creates (subreg (mem...)) which would cause an unnecessary
+    reload of the mem.  */
+      else if (reg_equiv_mem[regno] != 0)
+       x = reg_equiv_mem[regno];
+#endif
+      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];
+
+         if (rtx_varies_p (addr))
+           addr = copy_rtx (addr);
+
+         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), 0,
+                               XEXP (x, 0),
+                               &XEXP (x, 0), x, ind_levels);
+       }
+      return x;
+    }
+  if (code == MEM)
+    {
+      rtx tem = x;
+      find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
+                           x, ind_levels);
+      return tem;
+    }
+
+  if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG)
+    {
+      /* Check for SUBREG containing a REG that's equivalent to a constant. 
+        If the constant has a known value, truncate it right now.
+        Similarly if we are extracting a single-word of a multi-word
+        constant.  If the constant is symbolic, allow it to be substituted
+        normally.  push_reload will strip the subreg later.  If the
+        constant is VOIDmode, abort because we will lose the mode of
+        the register (this should never happen because one of the cases
+        above should handle it).  */
+
+      register int regno = REGNO (SUBREG_REG (x));
+      rtx tem;
+
+      if (subreg_lowpart_p (x)
+         && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0
+         && (tem = gen_lowpart_common (GET_MODE (x),
+                                       reg_equiv_constant[regno])) != 0)
+       return tem;
+
+      if (GET_MODE_BITSIZE (GET_MODE (x)) == BITS_PER_WORD
+         && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0
+         && (tem = operand_subword (reg_equiv_constant[regno],
+                                    SUBREG_WORD (x), 0,
+                                    GET_MODE (SUBREG_REG (x)))) != 0)
+       return tem;
+
+      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0
+         && GET_MODE (reg_equiv_constant[regno]) == VOIDmode)
+       abort ();
+
+      /* If the subreg contains a reg that will be converted to a mem,
+        convert the subreg to a narrower memref now.
+        Otherwise, we would get (subreg (mem ...) ...),
+        which would force reload of the mem.
+
+        We also need to do this if there is an equivalent MEM that is
+        not offsettable.  In that case, alter_subreg would produce an
+        invalid address on big-endian machines.
+
+        For machines that zero-extend byte loads, we must not reload using
+        a wider mode if we have a paradoxical SUBREG.  find_reloads will
+        force a reload in that case.  So we should not do anything here.  */
+
+      else if (regno >= FIRST_PSEUDO_REGISTER
+#ifdef BYTE_LOADS_ZERO_EXTEND
+              && (GET_MODE_SIZE (GET_MODE (x))
+                  <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+#endif
+              && (reg_equiv_address[regno] != 0
+                  || (reg_equiv_mem[regno] != 0
+                      && ! 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
+         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), 0,
+                               XEXP (x, 0),
+                               &XEXP (x, 0), x, ind_levels);
+       }
+
+    }
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       XEXP (x, i) = find_reloads_toplev (XEXP (x, i),
+                                          ind_levels, is_set_dest);
+    }
+  return x;
+}
+
+static rtx
+make_memloc (ad, regno)
+     rtx ad;
+     int regno;
+{
+  register int i;
+  rtx tem = reg_equiv_address[regno];
+  for (i = 0; i < n_memlocs; i++)
+    if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
+      return memlocs[i];
+
+  /* If TEM might contain a pseudo, we must copy it to avoid
+     modifying it when we do the substitution for the reload.  */
+  if (rtx_varies_p (tem))
+    tem = copy_rtx (tem);
+
+  tem = gen_rtx (MEM, GET_MODE (ad), tem);
+  RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
+  memlocs[n_memlocs++] = tem;
+  return tem;
+}
+
+/* Record all reloads needed for handling memory address AD
+   which appears in *LOC in a memory reference to mode MODE
+   which itself is found in location  *MEMREFLOC.
+   Note that we take shortcuts assuming that no multi-reg machine mode
+   occurs as part of an address.
+
+   OPERAND is the operand of the insn within which this address appears.
+
+   IND_LEVELS says how many levels of indirect addressing this machine
+   supports.
+
+   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.
+
+   Note that there is no verification that the address will be valid after
+   this routine does its work.  Instead, we rely on the fact that the address
+   was valid when reload started.  So we need only undo things that reload
+   could have broken.  These are wrong register types, pseudos not allocated
+   to a hard register, and frame pointer elimination.  */
+
+static int
+find_reloads_address (mode, memrefloc, ad, loc, operand, ind_levels)
+     enum machine_mode mode;
+     rtx *memrefloc;
+     rtx ad;
+     rtx *loc;
+     rtx operand;
+     int ind_levels;
+{
+  register int regno;
+  rtx tem;
+
+  /* If the address is a register, see if it is a legitimate address and
+     reload if not.  We first handle the cases where we need not reload
+     or where we must reload in a non-standard way.  */
+
+  if (GET_CODE (ad) == REG)
+    {
+      regno = REGNO (ad);
+
+      if (reg_equiv_constant[regno] != 0
+         && strict_memory_address_p (mode, reg_equiv_constant[regno]))
+       {
+         *loc = ad = reg_equiv_constant[regno];
+         return 1;
+       }
+
+      else if (reg_equiv_address[regno] != 0)
+       {
+         tem = make_memloc (ad, regno);
+         find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
+                               &XEXP (tem, 0), operand, ind_levels);
+         push_reload (tem, 0, loc, 0, BASE_REG_CLASS,
+                      GET_MODE (ad), VOIDmode, 0, 0,
+                      operand);
+         return 1;
+       }
+
+      else if (reg_equiv_mem[regno] != 0)
+       {
+         tem = XEXP (reg_equiv_mem[regno], 0);
+
+         /* If we can't indirect any more, a pseudo must be reloaded.
+            If the pseudo's address in its MEM is a SYMBOL_REF, it
+            must be reloaded unless indirect_symref_ok.  Otherwise, it
+            can be reloaded if the address is REG or REG + CONST_INT.  */
+
+         if (ind_levels > 0
+             && ! (GET_CODE (tem) == SYMBOL_REF && ! indirect_symref_ok)
+             && ((GET_CODE (tem) == REG
+                  && REGNO (tem) < FIRST_PSEUDO_REGISTER)
+                 || (GET_CODE (tem) == PLUS
+                     && GET_CODE (XEXP (tem, 0)) == REG
+                     && REGNO (XEXP (tem, 0)) < FIRST_PSEUDO_REGISTER
+                     && GET_CODE (XEXP (tem, 1)) == CONST_INT)))
+           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)
+              && ! 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, 0, loc, 0, BASE_REG_CLASS,
+                  GET_MODE (ad), VOIDmode, 0, 0, operand);
+      return 1;
+    }
+
+  if (strict_memory_address_p (mode, ad))
+    {
+      /* The address appears valid, so reloads are not needed.
+        But the address may contain an eliminable register.
+        This can happen because a machine with indirect addressing
+        may consider a pseudo register by itself a valid address even when
+        it has failed to get a hard reg.
+        So do a tree-walk to find and eliminate all such regs.  */
+
+      /* But first quickly dispose of a common case.  */
+      if (GET_CODE (ad) == PLUS
+         && GET_CODE (XEXP (ad, 1)) == CONST_INT
+         && GET_CODE (XEXP (ad, 0)) == REG
+         && reg_equiv_constant[REGNO (XEXP (ad, 0))] == 0)
+       return 0;
+
+      subst_reg_equivs_changed = 0;
+      *loc = subst_reg_equivs (ad);
+
+      if (! subst_reg_equivs_changed)
+       return 0;
+
+      /* Check result for validity after substitution.  */
+      if (strict_memory_address_p (mode, ad))
+       return 0;
+    }
+
+  /* The address is not valid.  We have to figure out why.  One possibility
+     is that it is itself a MEM.  This can happen when the frame pointer is
+     being eliminated, a pseudo is not allocated to a hard register, and the
+     offset between the frame and stack pointers is not its initial value.
+     In that case the psuedo will have been replaced by a MEM referring to
+     the stack pointer.  */
+  if (GET_CODE (ad) == MEM)
+    {
+      /* First ensure that the address in this MEM is valid.  Then, unless
+        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),
+                           operand, ind_levels == 0 ? 0 : ind_levels - 1);
+      /* Check similar cases as for indirect addresses as above except
+        that we can allow pseudos and a MEM since they should have been
+        taken care of above.  */
+
+      if (ind_levels == 0
+         || (GET_CODE (XEXP (tem, 0)) == SYMBOL_REF && ! indirect_symref_ok)
+         || GET_CODE (XEXP (tem, 0)) == MEM
+         || ! (GET_CODE (XEXP (tem, 0)) == REG
+               || (GET_CODE (XEXP (tem, 0)) == PLUS
+                   && GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
+                   && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)))
+       {
+         /* Must use TEM here, not AD, since it is the one that will
+            have any subexpressions reloaded, if needed.  */
+         push_reload (tem, 0, loc, 0,
+                      BASE_REG_CLASS, GET_MODE (tem), VOIDmode, 0,
+                      0, operand);
+         return 1;
+       }
+      else
+       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.  */
+  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, 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);
+         if (operand == oldref)
+           operand = *memrefloc;
+       }
+      if (double_reg_address_ok)
+       {
+         /* Unshare the sum as well.  */
+         *loc = ad = copy_rtx (ad);
+         /* 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), operand,
+                                    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,
+                                    operand, ind_levels);
+       }
+      return 1;
+    }
+
+  /* If we have an indexed stack slot, there are three possible reasons why
+     it might be invalid: The index might need to be reloaded, the address
+     might have been made by frame pointer elimination and hence have a
+     constant out of range, or both reasons might apply.  
+
+     We can easily check for an index needing reload, but even if that is the
+     case, we might also have an invalid constant.  To avoid making the
+     conservative assumption and requiring two reloads, we see if this address
+     is valid when not interpreted strictly.  If it is, the only problem is
+     that the index needs a reload and find_reloads_address_1 will take care
+     of it.
+
+     There is still a case when we might generate an extra reload,
+     however.  In certain cases eliminate_regs will return a MEM for a REG
+     (see the code there for details).  In those cases, memory_address_p
+     applied to our address will return 0 so we will think that our offset
+     must be too large.  But it might indeed be valid and the only problem
+     is that a MEM is present where a REG should be.  This case should be
+     very rare and there doesn't seem to be any way to avoid it.
+
+     If we decide to do something here, it must be that
+     `double_reg_address_ok' is true and that this address rtl was made by
+     eliminate_regs.  We generate a reload of the fp/sp/ap + constant and
+     rework the sum so that the reload register will be added to the index.
+     This is safe because we know the address isn't shared.
+
+     We check for fp/ap/sp as both the first and second operand of the
+     innermost PLUS.  */
+
+  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 != ARG_POINTER_REGNUM
+              || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
+#endif
+              || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
+          && ! memory_address_p (mode, ad))
+    {
+      *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
+                          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,
+                                GET_MODE (ad), operand, ind_levels);
+      find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), operand, 0);
+
+      return 1;
+    }
+                          
+  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 FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+              || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
+#endif
+              || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
+          && ! memory_address_p (mode, ad))
+    {
+      *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
+                          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,
+                                GET_MODE (ad), operand, ind_levels);
+      find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), operand, 0);
+
+      return 1;
+    }
+                          
+  /* See if address becomes valid when an eliminable register
+     in a sum is replaced.  */
+
+  tem = ad;
+  if (GET_CODE (ad) == PLUS)
+    tem = subst_indexed_address (ad);
+  if (tem != ad && strict_memory_address_p (mode, tem))
+    {
+      /* Ok, we win that way.  Replace any additional eliminable
+        registers.  */
+
+      subst_reg_equivs_changed = 0;
+      tem = subst_reg_equivs (tem);
+
+      /* Make sure that didn't make the address invalid again.  */
+
+      if (! subst_reg_equivs_changed || strict_memory_address_p (mode, tem))
+       {
+         *loc = tem;
+         return 0;
+       }
+    }
+
+  /* If constants aren't valid addresses, reload the constant address
+     into a register.  */
+  if (CONSTANT_ADDRESS_P (ad) && ! strict_memory_address_p (mode, ad))
+    {
+      /* If AD is in address in the constant pool, the MEM rtx may be shared.
+        Unshare it so we can safely alter it.  */
+      if (memrefloc && GET_CODE (ad) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (ad))
+       {
+         rtx oldref = *memrefloc;
+         *memrefloc = copy_rtx (*memrefloc);
+         loc = &XEXP (*memrefloc, 0);
+         if (operand == oldref)
+           operand = *memrefloc;
+       }
+
+      find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode, operand,
+                                ind_levels);
+      return 1;
+    }
+
+  return find_reloads_address_1 (ad, 0, loc, operand, ind_levels);
+}
+\f
+/* Find all pseudo regs appearing in AD
+   that are eliminable in favor of equivalent values
+   and do not have hard regs; replace them by their equivalents.  */
+
+static rtx
+subst_reg_equivs (ad)
+     rtx ad;
+{
+  register RTX_CODE code = GET_CODE (ad);
+  register int i;
+  register char *fmt;
+
+  switch (code)
+    {
+    case HIGH:
+    case CONST_INT:
+    case CONST:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case PC:
+    case CC0:
+      return ad;
+
+    case REG:
+      {
+       register int regno = REGNO (ad);
+
+       if (reg_equiv_constant[regno] != 0)
+         {
+           subst_reg_equivs_changed = 1;
+           return reg_equiv_constant[regno];
+         }
+      }
+      return ad;
+
+    case PLUS:
+      /* Quickly dispose of a common case.  */
+      if (XEXP (ad, 0) == frame_pointer_rtx
+         && GET_CODE (XEXP (ad, 1)) == CONST_INT)
+       return ad;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i));
+  return ad;
+}
+\f
+/* Compute the sum of X and Y, making canonicalizations assumed in an
+   address, namely: sum constant integers, surround the sum of two
+   constants with a CONST, put the constant as the second operand, and
+   group the constant on the outermost sum.
+
+   This routine assumes both inputs are already in canonical form.  */
+
+rtx
+form_sum (x, y)
+     rtx x, y;
+{
+  rtx tem;
+
+  if (GET_CODE (x) == CONST_INT)
+    return plus_constant (y, INTVAL (x));
+  else if (GET_CODE (y) == CONST_INT)
+    return plus_constant (x, INTVAL (y));
+  else if (CONSTANT_P (x))
+    tem = x, x = y, y = tem;
+
+  if (GET_CODE (x) == PLUS && CONSTANT_P (XEXP (x, 1)))
+    return form_sum (XEXP (x, 0), form_sum (XEXP (x, 1), y));
+
+  /* Note that if the operands of Y are specified in the opposite
+     order in the recursive calls below, infinite recursion will occur.  */
+  if (GET_CODE (y) == PLUS && CONSTANT_P (XEXP (y, 1)))
+    return form_sum (form_sum (x, XEXP (y, 0)), XEXP (y, 1));
+
+  /* If both constant, encapsulate sum.  Otherwise, just form sum.  A
+     constant will have been placed second.  */
+  if (CONSTANT_P (x) && CONSTANT_P (y))
+    {
+      if (GET_CODE (x) == CONST)
+       x = XEXP (x, 0);
+      if (GET_CODE (y) == CONST)
+       y = XEXP (y, 0);
+
+      return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, Pmode, x, y));
+    }
+
+  return gen_rtx (PLUS, Pmode, x, y);
+}
+\f
+/* If ADDR is a sum containing a pseudo register that should be
+   replaced with a constant (from reg_equiv_constant),
+   return the result of doing so, and also apply the associative
+   law so that the result is more likely to be a valid address.
+   (But it is not guaranteed to be one.)
+
+   Note that at most one register is replaced, even if more are
+   replaceable.  Also, we try to put the result into a canonical form
+   so it is more likely to be a valid address.
+
+   In all other cases, return ADDR.  */
+
+static rtx
+subst_indexed_address (addr)
+     rtx addr;
+{
+  rtx op0 = 0, op1 = 0, op2 = 0;
+  rtx tem;
+  int regno;
+
+  if (GET_CODE (addr) == PLUS)
+    {
+      /* Try to find a register to replace.  */
+      op0 = XEXP (addr, 0), op1 = XEXP (addr, 1), op2 = 0;
+      if (GET_CODE (op0) == REG
+         && (regno = REGNO (op0)) >= FIRST_PSEUDO_REGISTER
+         && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0)
+       op0 = reg_equiv_constant[regno];
+      else if (GET_CODE (op1) == REG
+         && (regno = REGNO (op1)) >= FIRST_PSEUDO_REGISTER
+         && reg_renumber[regno] < 0
+         && reg_equiv_constant[regno] != 0)
+       op1 = reg_equiv_constant[regno];
+      else if (GET_CODE (op0) == PLUS
+              && (tem = subst_indexed_address (op0)) != op0)
+       op0 = tem;
+      else if (GET_CODE (op1) == PLUS
+              && (tem = subst_indexed_address (op1)) != op1)
+       op1 = tem;
+      else
+       return addr;
+
+      /* Pick out up to three things to add.  */
+      if (GET_CODE (op1) == PLUS)
+       op2 = XEXP (op1, 1), op1 = XEXP (op1, 0);
+      else if (GET_CODE (op0) == PLUS)
+       op2 = op1, op1 = XEXP (op0, 1), op0 = XEXP (op0, 0);
+
+      /* Compute the sum.  */
+      if (op2 != 0)
+       op1 = form_sum (op1, op2);
+      if (op1 != 0)
+       op0 = form_sum (op0, op1);
+
+      return op0;
+    }
+  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.)
+   CONTEXT = 1 means we are considering regs as index regs,
+   = 0 means we are considering them as base regs.
+
+   OPERAND is the operand of the insn within which this address appears.
+
+   IND_LEVELS says how many levels of indirect addressing are
+   supported at this point in the address.
+
+   We return nonzero if X, as a whole, is reloaded or replaced.  */
+
+/* Note that we take shortcuts assuming that no multi-reg machine mode
+   occurs as part of an address.
+   Also, this is not fully machine-customizable; it works for machines
+   such as vaxes and 68000's and 32000's, but other possible machines
+   could have addressing modes that this does not handle right.  */
+
+static int
+find_reloads_address_1 (x, context, loc, operand, ind_levels)
+     rtx x;
+     int context;
+     rtx *loc;
+     rtx operand;
+     int ind_levels;
+{
+  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), operand, ind_levels);
+         find_reloads_address_1 (op1, 0, &XEXP (x, 1), operand, ind_levels);
+       }
+      else if (code1 == MULT || code1 == SIGN_EXTEND || code0 == MEM)
+       {
+         find_reloads_address_1 (op0, 0, &XEXP (x, 0), operand, ind_levels);
+         find_reloads_address_1 (op1, 1, &XEXP (x, 1), operand, ind_levels);
+       }
+      else if (code0 == CONST_INT || code0 == CONST
+              || code0 == SYMBOL_REF || code0 == LABEL_REF)
+       {
+         find_reloads_address_1 (op1, 0, &XEXP (x, 1), operand, ind_levels);
+       }
+      else if (code1 == CONST_INT || code1 == CONST
+              || code1 == SYMBOL_REF || code1 == LABEL_REF)
+       {
+         find_reloads_address_1 (op0, 0, &XEXP (x, 0), operand, 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), operand, ind_levels);
+         else if (REG_OK_FOR_BASE_P (op0))
+           find_reloads_address_1 (op1, 1, &XEXP (x, 1), operand, ind_levels);
+         else if (REG_OK_FOR_INDEX_P (op1))
+           find_reloads_address_1 (op0, 0, &XEXP (x, 0), operand, ind_levels);
+         else if (REG_OK_FOR_INDEX_P (op0))
+           find_reloads_address_1 (op1, 0, &XEXP (x, 1), operand, ind_levels);
+         else
+           {
+             find_reloads_address_1 (op0, 1, &XEXP (x, 0), operand,
+                                     ind_levels);
+             find_reloads_address_1 (op1, 0, &XEXP (x, 1), operand,
+                                     ind_levels);
+           }
+       }
+      else if (code0 == REG)
+       {
+         find_reloads_address_1 (op0, 1, &XEXP (x, 0), operand, ind_levels);
+         find_reloads_address_1 (op1, 0, &XEXP (x, 1), operand, ind_levels);
+       }
+      else if (code1 == REG)
+       {
+         find_reloads_address_1 (op1, 1, &XEXP (x, 1), operand, ind_levels);
+         find_reloads_address_1 (op0, 0, &XEXP (x, 0), operand, ind_levels);
+       }
+    }
+  else if (code == POST_INC || code == POST_DEC
+          || code == PRE_INC || code == PRE_DEC)
+    {
+      if (GET_CODE (XEXP (x, 0)) == REG)
+       {
+         register int regno = REGNO (XEXP (x, 0));
+         int value = 0;
+         rtx x_orig = x;
+
+         /* A register that is incremented cannot be constant!  */
+         if (regno >= FIRST_PSEUDO_REGISTER
+             && reg_equiv_constant[regno] != 0)
+           abort ();
+
+         /* Handle a register that is equivalent to a memory location
+            which cannot be addressed directly.  */
+         if (reg_equiv_address[regno] != 0)
+           {
+             rtx tem = make_memloc (XEXP (x, 0), regno);
+             /* First reload the memory location's address.  */
+             find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
+                                   &XEXP (tem, 0), operand, ind_levels);
+             /* 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.  */
+           }
+
+         /* If we have a hard register that is ok as an index,
+            don't make a reload.  If an autoincrement of a nice register
+            isn't "valid", it must be that no autoincrement is "valid".
+            If that is true and something made an autoincrement anyway,
+            this must be a special context where one is allowed.
+            (For example, a "push" instruction.)
+            We can't improve this address, so leave it alone.  */
+
+         /* Otherwise, reload the autoincrement into a suitable hard reg
+            and record how much to increment by.  */
+
+         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))))
+           {
+             register rtx link;
+
+             int reloadnum
+               = push_reload (x, 0, loc, 0,
+                              context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                              GET_MODE (x), GET_MODE (x), VOIDmode, 0, operand);
+             reload_inc[reloadnum]
+               = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
+
+             value = 1;
+
+#ifdef AUTO_INC_DEC
+             /* Update the REG_INC notes.  */
+
+             for (link = REG_NOTES (this_insn);
+                  link; link = XEXP (link, 1))
+               if (REG_NOTE_KIND (link) == REG_INC
+                   && REGNO (XEXP (link, 0)) == REGNO (XEXP (x_orig, 0)))
+                 push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
+#endif
+           }
+         return value;
+       }
+      else if (GET_CODE (XEXP (x, 0)) == 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.  */
+         rtx tem = XEXP (x, 0);
+         register rtx link;
+         int reloadnum;
+
+         /* 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), &XEXP (x, 0),
+                               XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
+                               operand, ind_levels);
+
+         reloadnum = push_reload (x, 0, loc, 0,
+                                  context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                                  GET_MODE (x), VOIDmode, 0, 0, operand);
+         reload_inc[reloadnum]
+           = find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
+
+         link = FIND_REG_INC_NOTE (this_insn, tem);
+         if (link != 0)
+           push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
+
+         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.
+
+        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),
+                           operand, ind_levels);
+
+      push_reload (*loc, 0, loc, 0,
+                  context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                  GET_MODE (x), VOIDmode, 0, 0, operand);
+      return 1;
+    }
+  else if (code == REG)
+    {
+      register int regno = REGNO (x);
+
+      if (reg_equiv_constant[regno] != 0)
+       {
+         push_reload (reg_equiv_constant[regno], 0, loc, 0,
+                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                      GET_MODE (x), VOIDmode, 0, 0, operand);
+         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], 0, loc, 0,
+                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                      GET_MODE (x), VOIDmode, 0, 0, operand);
+         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),
+                               operand, 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, 0, loc, 0,
+                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                      GET_MODE (x), VOIDmode, 0, 0, operand);
+         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, 0, loc, 0,
+                      context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+                      GET_MODE (x), VOIDmode, 0, 0, operand);
+         return 1;
+       }
+    }
+  else
+    {
+      register char *fmt = GET_RTX_FORMAT (code);
+      register int i;
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       {
+         if (fmt[i] == 'e')
+           find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
+                                   operand, ind_levels);
+       }
+    }
+
+  return 0;
+}
+\f
+/* X, which is found at *LOC, is a part of an address that needs to be
+   reloaded into a register of class CLASS.  If X is a constant, or if
+   X is a PLUS that contains a constant, check that the constant is a
+   legitimate operand and that we are supposed to be able to load
+   it into the register.
+
+   If not, force the constant into memory and reload the MEM instead.
+
+   MODE is the mode to use, in case X is an integer constant.
+
+   NEEDED_FOR says which operand this reload is needed for.
+
+   IND_LEVELS says how many levels of indirect addressing this machine
+   supports.  */
+
+static void
+find_reloads_address_part (x, loc, class, mode, needed_for, ind_levels)
+     rtx x;
+     rtx *loc;
+     enum reg_class class;
+     enum machine_mode mode;
+     rtx needed_for;
+     int ind_levels;
+{
+  if (CONSTANT_P (x)
+      && (! LEGITIMATE_CONSTANT_P (x)
+         || PREFERRED_RELOAD_CLASS (x, class) == NO_REGS))
+    {
+      rtx tem = x = force_const_mem (mode, x);
+      find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+                           needed_for, ind_levels);
+    }
+
+  else if (GET_CODE (x) == PLUS
+          && CONSTANT_P (XEXP (x, 1))
+          && (! LEGITIMATE_CONSTANT_P (XEXP (x, 1))
+              || PREFERRED_RELOAD_CLASS (XEXP (x, 1), class) == NO_REGS))
+    {
+      rtx tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
+
+      x = gen_rtx (PLUS, GET_MODE (x), XEXP (x, 0), tem);
+      find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+                           needed_for, ind_levels);
+    }
+
+  push_reload (x, 0, loc, 0, class, mode, VOIDmode, 0, 0, needed_for);
+}
+\f
+/* Substitute into X the registers into which we have reloaded
+   the things that need reloading.  The array `replacements'
+   says contains the locations of all pointers that must be changed
+   and says what to replace them with.
+
+   Return the rtx that X translates into; usually X, but modified.  */
+
+void
+subst_reloads ()
+{
+  register int i;
+
+  for (i = 0; i < n_replacements; i++)
+    {
+      register struct replacement *r = &replacements[i];
+      register rtx reloadreg = reload_reg_rtx[r->what];
+      if (reloadreg)
+       {
+         /* Encapsulate RELOADREG so its machine mode matches what
+            used to be there.  */
+         if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
+           reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+
+         /* If we are putting this into a SUBREG and RELOADREG is a
+            SUBREG, we would be making nested SUBREGs, so we have to fix
+            this up.  Note that r->where == &SUBREG_REG (*r->subreg_loc).  */
+
+         if (r->subreg_loc != 0 && GET_CODE (reloadreg) == SUBREG)
+           {
+             if (GET_MODE (*r->subreg_loc)
+                 == GET_MODE (SUBREG_REG (reloadreg)))
+               *r->subreg_loc = SUBREG_REG (reloadreg);
+             else
+               {
+                 *r->where = SUBREG_REG (reloadreg);
+                 SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg);
+               }
+           }
+         else
+           *r->where = reloadreg;
+       }
+      /* If reload got no reg and isn't optional, something's wrong.  */
+      else if (! reload_optional[r->what])
+       abort ();
+    }
+}
+\f
+/* Make a copy of any replacements being done into X and move those copies
+   to locations in Y, a copy of X.  We only look at the highest level of
+   the RTL.  */
+
+void
+copy_replacements (x, y)
+     rtx x;
+     rtx y;
+{
+  int i, j;
+  enum rtx_code code = GET_CODE (x);
+  char *fmt = GET_RTX_FORMAT (code);
+  struct replacement *r;
+
+  /* We can't support X being a SUBREG because we might then need to know its
+     location if something inside it was replaced.  */
+  if (code == SUBREG)
+    abort ();
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      for (j = 0; j < n_replacements; j++)
+       {
+         if (replacements[j].subreg_loc == &XEXP (x, i))
+           {
+             r = &replacements[n_replacements++];
+             r->where = replacements[j].where;
+             r->subreg_loc = &XEXP (y, i);
+             r->what = replacements[j].what;
+             r->mode = replacements[j].mode;
+           }
+         else if (replacements[j].where == &XEXP (x, i))
+           {
+             r = &replacements[n_replacements++];
+             r->where = &XEXP (y, i);
+             r->subreg_loc = 0;
+             r->what = replacements[j].what;
+             r->mode = replacements[j].mode;
+           }
+       }
+}
+\f
+/* Return nonzero if register in range [REGNO, ENDREGNO)
+   appears either explicitly or implicitly in X
+   other than being stored into.
+
+   References contained within the substructure at LOC do not count.
+   LOC may be zero, meaning don't ignore anything.
+
+   This is similar to refers_to_regno_p in rtlanal.c except that we
+   look at equivalences for pseudos that didn't get hard registers.  */
+
+int
+refers_to_regno_for_reload_p (regno, endregno, x, loc)
+     int regno, endregno;
+     rtx x;
+     rtx *loc;
+{
+  register int i;
+  register RTX_CODE code;
+  register char *fmt;
+
+  if (x == 0)
+    return 0;
+
+ repeat:
+  code = GET_CODE (x);
+
+  switch (code)
+    {
+    case REG:
+      i = REGNO (x);
+
+      if (i >= FIRST_PSEUDO_REGISTER && reg_renumber[i] == -1
+         && ((reg_equiv_address[i]
+              && refers_to_regno_for_reload_p (regno, endregno,
+                                               reg_equiv_address[i], 0))
+             || (reg_equiv_mem[i]
+                 && refers_to_regno_for_reload_p (regno, endregno,
+                                                  XEXP (reg_equiv_mem[i], 0),
+                                                  0))))
+       return 1;
+
+      return (endregno > i
+             && regno < i + (i < FIRST_PSEUDO_REGISTER 
+                             ? HARD_REGNO_NREGS (i, GET_MODE (x))
+                             : 1));
+
+    case SUBREG:
+      /* If this is a SUBREG of a hard reg, we can see exactly which
+        registers are being modified.  Otherwise, handle normally.  */
+      if (GET_CODE (SUBREG_REG (x)) == REG
+         && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
+       {
+         int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
+         int inner_endregno
+           = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
+                            ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
+
+         return endregno > inner_regno && regno < inner_endregno;
+       }
+      break;
+
+    case CLOBBER:
+    case SET:
+      if (&SET_DEST (x) != loc
+         /* Note setting a SUBREG counts as referring to the REG it is in for
+            a pseudo but not for hard registers since we can
+            treat each word individually.  */
+         && ((GET_CODE (SET_DEST (x)) == SUBREG
+              && loc != &SUBREG_REG (SET_DEST (x))
+              && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG
+              && REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER
+              && refers_to_regno_for_reload_p (regno, endregno,
+                                               SUBREG_REG (SET_DEST (x)),
+                                               loc))
+             || (GET_CODE (SET_DEST (x)) != REG
+                 && refers_to_regno_for_reload_p (regno, endregno,
+                                                  SET_DEST (x), loc))))
+       return 1;
+
+      if (code == CLOBBER || loc == &SET_SRC (x))
+       return 0;
+      x = SET_SRC (x);
+      goto repeat;
+    }
+
+  /* X does not match, so try its subexpressions.  */
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e' && loc != &XEXP (x, i))
+       {
+         if (i == 0)
+           {
+             x = XEXP (x, 0);
+             goto repeat;
+           }
+         else
+           if (refers_to_regno_for_reload_p (regno, endregno,
+                                             XEXP (x, i), loc))
+             return 1;
+       }
+      else if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (x, i) - 1; j >=0; j--)
+           if (loc != &XVECEXP (x, i, j)
+               && refers_to_regno_for_reload_p (regno, endregno,
+                                                XVECEXP (x, i, j), loc))
+             return 1;
+       }
+    }
+  return 0;
+}
+\f
+#if 0
+
+/* [[This function is currently obsolete, now that volatility
+   is represented by a special bit `volatil' so VOLATILE is never used;
+   and UNCHANGING has never been brought into use.]]
+
+   Alter X by eliminating all VOLATILE and UNCHANGING expressions.
+   Each of them is replaced by its operand.
+   Thus, (PLUS (VOLATILE (MEM (REG 5))) (CONST_INT 4))
+   becomes (PLUS (MEM (REG 5)) (CONST_INT 4)).
+
+   If X is itself a VOLATILE expression,
+   we return the expression that should replace it
+   but we do not modify X.  */
+
+static rtx
+forget_volatility (x)
+     register rtx x;
+{
+  enum rtx_code code = GET_CODE (x);
+  register char *fmt;
+  register int i;
+  register rtx value = 0;
+
+  switch (code)
+    {
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST:
+    case REG:
+    case CC0:
+    case PC:
+      return x;
+
+    case VOLATILE:
+    case UNCHANGING:
+      return XEXP (x, 0);
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       XEXP (x, i) = forget_volatility (XEXP (x, i));
+      if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           XVECEXP (x, i, j) = forget_volatility (XVECEXP (x, i, j));
+       }
+    }
+
+  return x;
+}
+
+#endif
+\f
+/* Check the insns before INSN to see if there is a suitable register
+   containing the same value as GOAL.
+   If OTHER is -1, look for a register in class CLASS.
+   Otherwise, just see if register number OTHER shares GOAL's value.
+
+   Return an rtx for the register found, or zero if none is found.
+
+   If RELOAD_REG_P is (short *)1,
+   we reject any hard reg that appears in reload_reg_rtx
+   because such a hard reg is also needed coming into this insn.
+
+   If RELOAD_REG_P is any other nonzero value,
+   it is a vector indexed by hard reg number
+   and we reject any hard reg whose element in the vector is nonnegative
+   as well as any that appears in reload_reg_rtx.
+
+   If GOAL is zero, then GOALREG is a register number; we look
+   for an equivalent for that register.
+
+   MODE is the machine mode of the value we want an equivalence for.
+   If GOAL is nonzero and not VOIDmode, then it must have mode MODE.
+
+   This function is used by jump.c as well as in the reload pass.
+
+   If GOAL is the sum of the stack pointer and a constant, we treat it
+   as if it were a constant except that sp is required to be unchanging.  */
+
+rtx
+find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
+     register rtx goal;
+     rtx insn;
+     enum reg_class class;
+     register int other;
+     short *reload_reg_p;
+     int goalreg;
+     enum machine_mode mode;
+{
+  register rtx p = insn;
+  rtx valtry, value, where;
+  register rtx pat;
+  register int regno = -1;
+  int valueno;
+  int goal_mem = 0;
+  int goal_const = 0;
+  int goal_mem_addr_varies = 0;
+  int need_stable_sp = 0;
+  int nregs;
+  int valuenregs;
+
+  if (goal == 0)
+    regno = goalreg;
+  else if (GET_CODE (goal) == REG)
+    regno = REGNO (goal);
+  else if (GET_CODE (goal) == MEM)
+    {
+      enum rtx_code code = GET_CODE (XEXP (goal, 0));
+      if (MEM_VOLATILE_P (goal))
+       return 0;
+      if (flag_float_store && GET_MODE_CLASS (GET_MODE (goal)) == MODE_FLOAT)
+       return 0;
+      /* An address with side effects must be reexecuted.  */
+      switch (code)
+       {
+       case POST_INC:
+       case PRE_INC:
+       case POST_DEC:
+       case PRE_DEC:
+         return 0;
+       }
+      goal_mem = 1;
+    }
+  else if (CONSTANT_P (goal))
+    goal_const = 1;
+  else if (GET_CODE (goal) == PLUS
+          && XEXP (goal, 0) == stack_pointer_rtx
+          && CONSTANT_P (XEXP (goal, 1)))
+    goal_const = need_stable_sp = 1;
+  else
+    return 0;
+
+  /* On some machines, certain regs must always be rejected
+     because they don't behave the way ordinary registers do.  */
+  
+#ifdef OVERLAPPING_REGNO_P
+   if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
+       && OVERLAPPING_REGNO_P (regno))
+     return 0;
+#endif      
+
+  /* Scan insns back from INSN, looking for one that copies
+     a value into or out of GOAL.
+     Stop and give up if we reach a label.  */
+
+  while (1)
+    {
+      p = PREV_INSN (p);
+      if (p == 0 || GET_CODE (p) == CODE_LABEL)
+       return 0;
+      if (GET_CODE (p) == INSN
+         /* If we don't want spill regs ... */
+         && (! (reload_reg_p != 0 && reload_reg_p != (short *)1)
+         /* ... then ignore insns introduced by reload; they aren't useful
+            and can cause results in reload_as_needed to be different
+            from what they were when calculating the need for spills.
+            If we notice an input-reload insn here, we will reject it below,
+            but it might hide a usable equivalent.  That makes bad code.
+            It may even abort: perhaps no reg was spilled for this insn
+            because it was assumed we would find that equivalent.  */
+             || INSN_UID (p) < reload_first_uid))
+       {
+         pat = single_set (p);
+         /* First check for something that sets some reg equal to GOAL.  */
+         if (pat != 0
+             && ((regno >= 0
+                  && true_regnum (SET_SRC (pat)) == regno
+                  && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
+                 ||
+                 (regno >= 0
+                  && true_regnum (SET_DEST (pat)) == regno
+                  && (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0)
+                 ||
+                 (goal_const && rtx_equal_p (SET_SRC (pat), goal)
+                  && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
+                 || (goal_mem
+                     && (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0
+                     && rtx_renumbered_equal_p (goal, SET_SRC (pat)))
+                 || (goal_mem
+                     && (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0
+                     && rtx_renumbered_equal_p (goal, SET_DEST (pat)))))
+           if (other >= 0
+               ? valueno == other
+               : ((unsigned) valueno < FIRST_PSEUDO_REGISTER
+                  && TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+                                        valueno)))
+             {
+               value = valtry;
+               where = p;
+               break;
+             }
+       }
+    }
+
+  /* We found a previous insn copying GOAL into a suitable other reg VALUE
+     (or copying VALUE into GOAL, if GOAL is also a register).
+     Now verify that VALUE is really valid.  */
+
+  /* VALUENO is the register number of VALUE; a hard register.  */
+
+  /* Don't try to re-use something that is killed in this insn.  We want
+     to be able to trust REG_UNUSED notes.  */
+  if (find_reg_note (where, REG_UNUSED, value))
+    return 0;
+
+  /* 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
+      || (goal_mem && reg_overlap_mentioned_p (stack_pointer_rtx, goal)))
+    need_stable_sp = 1;
+
+  /* Reject VALUE if the copy-insn moved the wrong sort of datum.  */
+  if (GET_MODE (value) != mode)
+    return 0;
+
+  /* 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))
+      && refers_to_regno_p (valueno,
+                           valueno + HARD_REGNO_NREGS (valueno, mode),
+                           goal, 0))
+    return 0;
+
+  /* Reject registers that overlap GOAL.  */
+
+  if (!goal_mem && !goal_const
+      && regno + HARD_REGNO_NREGS (regno, mode) > valueno
+      && regno < valueno + HARD_REGNO_NREGS (valueno, mode))
+    return 0;
+
+  /* Reject VALUE if it is one of the regs reserved for reloads.
+     Reload1 knows how to reuse them anyway, and it would get
+     confused if we allocated one without its knowledge.
+     (Now that insns introduced by reload are ignored above,
+     this case shouldn't happen, but I'm not positive.)  */
+
+  if (reload_reg_p != 0 && reload_reg_p != (short *)1
+      && reload_reg_p[valueno] >= 0)
+    return 0;
+
+  /* On some machines, certain regs must always be rejected
+     because they don't behave the way ordinary registers do.  */
+  
+#ifdef OVERLAPPING_REGNO_P
+  if (OVERLAPPING_REGNO_P (valueno))
+    return 0;
+#endif      
+
+  nregs = HARD_REGNO_NREGS (regno, mode);
+  valuenregs = HARD_REGNO_NREGS (valueno, mode);
+
+  /* Reject VALUE if it is a register being used for an input reload
+     even if it is not one of those reserved.  */
+
+  if (reload_reg_p != 0)
+    {
+      int i;
+      for (i = 0; i < n_reloads; i++)
+       if (reload_reg_rtx[i] != 0 && reload_in[i])
+         {
+           int regno1 = REGNO (reload_reg_rtx[i]);
+           int nregs1 = HARD_REGNO_NREGS (regno1,
+                                          GET_MODE (reload_reg_rtx[i]));
+           if (regno1 < valueno + valuenregs
+               && regno1 + nregs1 > valueno)
+             return 0;
+         }
+    }
+
+  if (goal_mem)
+    goal_mem_addr_varies = rtx_addr_varies_p (goal);
+
+  /* Now verify that the values of GOAL and VALUE remain unaltered
+     until INSN is reached.  */
+
+  p = insn;
+  while (1)
+    {
+      p = PREV_INSN (p);
+      if (p == where)
+       return value;
+
+      /* Don't trust the conversion past a function call
+        if either of the two is in a call-clobbered register, or memory.  */
+      if (GET_CODE (p) == CALL_INSN
+         && ((regno >= 0 && regno < FIRST_PSEUDO_REGISTER
+              && call_used_regs[regno])
+             ||
+             (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
+              && call_used_regs[valueno])
+             ||
+             goal_mem
+             || need_stable_sp))
+       return 0;
+
+#ifdef INSN_CLOBBERS_REGNO_P
+      if ((valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER
+         && INSN_CLOBBERS_REGNO_P (p, valueno))
+         || (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
+         && INSN_CLOBBERS_REGNO_P (p, regno)))
+       return 0;
+#endif
+
+      if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+       {
+         /* If this insn P stores in either GOAL or VALUE, return 0.
+            If GOAL is a memory ref and this insn writes memory, return 0.
+            If GOAL is a memory ref and its address is not constant,
+            and this insn P changes a register used in GOAL, return 0.  */
+
+         pat = PATTERN (p);
+         if (GET_CODE (pat) == SET || 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_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;
+           }
+         else if (GET_CODE (pat) == PARALLEL)
+           {
+             register int i;
+             for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
+               {
+                 register rtx v1 = XVECEXP (pat, 0, i);
+                 if (GET_CODE (v1) == SET || GET_CODE (v1) == CLOBBER)
+                   {
+                     register rtx dest = SET_DEST (v1);
+                     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_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.
+            If GOAL is a memory ref and its address is not constant,
+            and this insn P increments a register used in GOAL, return 0.  */
+         {
+           register rtx link;
+
+           for (link = REG_NOTES (p); link; link = XEXP (link, 1))
+             if (REG_NOTE_KIND (link) == REG_INC
+                 && GET_CODE (XEXP (link, 0)) == REG)
+               {
+                 register int incno = REGNO (XEXP (link, 0));
+                 if (incno < regno + nregs && incno >= regno)
+                   return 0;
+                 if (incno < valueno + valuenregs && incno >= valueno)
+                   return 0;
+                 if (goal_mem_addr_varies
+                     && reg_overlap_mentioned_p (XEXP (link, 0), goal))
+                   return 0;
+               }
+         }
+#endif
+       }
+    }
+}
+\f
+/* Find a place where INCED appears in an increment or decrement operator
+   within X, and return the amount INCED is incremented or decremented by.
+   The value is always positive.  */
+
+static int
+find_inc_amount (x, inced)
+     rtx x, inced;
+{
+  register enum rtx_code code = GET_CODE (x);
+  register char *fmt;
+  register int i;
+
+  if (code == MEM)
+    {
+      register rtx addr = XEXP (x, 0);
+      if ((GET_CODE (addr) == PRE_DEC
+          || GET_CODE (addr) == POST_DEC
+          || GET_CODE (addr) == PRE_INC
+          || GET_CODE (addr) == POST_INC)
+         && XEXP (addr, 0) == inced)
+       return GET_MODE_SIZE (GET_MODE (x));
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         register int tem = find_inc_amount (XEXP (x, i), inced);
+         if (tem != 0)
+           return tem;
+       }
+      if (fmt[i] == 'E')
+       {
+         register int j;
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           {
+             register int tem = find_inc_amount (XVECEXP (x, i, j), inced);
+             if (tem != 0)
+               return tem;
+           }
+       }
+    }
+
+  return 0;
+}
+\f
+/* Return 1 if register REGNO is the subject of a clobber in insn INSN.  */
+
+int
+regno_clobbered_p (regno, insn)
+     int regno;
+     rtx insn;
+{
+  if (GET_CODE (PATTERN (insn)) == CLOBBER
+      && GET_CODE (XEXP (PATTERN (insn), 0)) == REG)
+    return REGNO (XEXP (PATTERN (insn), 0)) == regno;
+
+  if (GET_CODE (PATTERN (insn)) == PARALLEL)
+    {
+      int i = XVECLEN (PATTERN (insn), 0) - 1;
+
+      for (; i >= 0; i--)
+       {
+         rtx elt = XVECEXP (PATTERN (insn), 0, i);
+         if (GET_CODE (elt) == CLOBBER && GET_CODE (XEXP (elt, 0)) == REG
+             && REGNO (XEXP (elt, 0)) == regno)
+           return 1;
+       }
+    }
+
+  return 0;
+}