OSDN Git Service

* testsuite/lib/libgomp-dg.exp (libgomp_init): Compute multilib-related
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index f3c5978..ceb12ba 100644 (file)
@@ -1,6 +1,7 @@
 /* Search an insn for pseudo regs that must be in hard regs and are not.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation,
+   Inc.
 
 This file is part of GCC.
 
@@ -16,8 +17,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 /* This file contains subroutines used only from the file reload1.c.
    It knows how to scan one insn for operands and values
@@ -108,19 +109,18 @@ a register with any other reload.  */
 #include "params.h"
 #include "target.h"
 
-#ifndef REGNO_MODE_OK_FOR_BASE_P
-#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
-#endif
-
-#ifndef REG_MODE_OK_FOR_BASE_P
-#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
-#endif
-
 /* True if X is a constant that can be forced into the constant pool.  */
 #define CONST_POOL_OK_P(X)                     \
   (CONSTANT_P (X)                              \
    && GET_CODE (X) != HIGH                     \
    && !targetm.cannot_force_const_mem (X))
+
+/* True if C is a non-empty register class that has too few registers
+   to be safely used as a reload target class.  */
+#define SMALL_REGISTER_CLASS_P(C) \
+  (reg_class_size [(C)] == 1 \
+   || (reg_class_size [(C)] >= 1 && CLASS_LIKELY_SPILLED_P (C)))
+
 \f
 /* All reloads of the current insn are recorded here.  See reload.h for
    comments.  */
@@ -243,12 +243,11 @@ static int output_reloadnum;
       ? RELOAD_FOR_OUTADDR_ADDRESS                     \
       : (type)))
 
-#ifdef HAVE_SECONDARY_RELOADS
 static int push_secondary_reload (int, rtx, int, int, enum reg_class,
                                  enum machine_mode, enum reload_type,
-                                 enum insn_code *);
-#endif
-static enum reg_class find_valid_class (enum machine_mode, int, unsigned int);
+                                 enum insn_code *, secondary_reload_info *);
+static enum reg_class find_valid_class (enum machine_mode, enum machine_mode,
+                                       int, unsigned int);
 static int reload_inner_reg_of_subreg (rtx, enum machine_mode, int);
 static void push_replacement (rtx *, int, enum machine_mode);
 static void dup_replacements (rtx *, rtx *);
@@ -279,9 +278,10 @@ static rtx find_reloads_subreg_address (rtx, int, int, enum reload_type,
                                        int, rtx);
 static void copy_replacements_1 (rtx *, rtx *, int);
 static int find_inc_amount (rtx, rtx);
+static int refers_to_mem_for_reload_p (rtx);
+static int refers_to_regno_for_reload_p (unsigned int, unsigned int,
+                                        rtx, rtx *);
 \f
-#ifdef HAVE_SECONDARY_RELOADS
-
 /* Determine if any secondary reloads are needed for loading (if IN_P is
    nonzero) or storing (if IN_P is zero) X to or from a reload register of
    register class RELOAD_CLASS in mode RELOAD_MODE.  If secondary reloads
@@ -295,16 +295,18 @@ static int
 push_secondary_reload (int in_p, rtx x, int opnum, int optional,
                       enum reg_class reload_class,
                       enum machine_mode reload_mode, enum reload_type type,
-                      enum insn_code *picode)
+                      enum insn_code *picode, secondary_reload_info *prev_sri)
 {
   enum reg_class class = NO_REGS;
+  enum reg_class scratch_class;
   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;
   enum reload_type secondary_type;
   int s_reload, t_reload = -1;
+  const char *scratch_constraint;
+  char letter;
+  secondary_reload_info sri;
 
   if (type == RELOAD_FOR_INPUT_ADDRESS
       || type == RELOAD_FOR_OUTPUT_ADDRESS
@@ -336,36 +338,21 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
       && reg_equiv_mem[REGNO (x)] != 0)
     x = reg_equiv_mem[REGNO (x)];
 
-#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
+  sri.icode = CODE_FOR_nothing;
+  sri.prev_sri = prev_sri;
+  class = targetm.secondary_reload (in_p, x, reload_class, reload_mode, &sri);
+  icode = sri.icode;
 
   /* If we don't need any secondary registers, done.  */
-  if (class == NO_REGS)
+  if (class == NO_REGS && icode == CODE_FOR_nothing)
     return -1;
 
-  /* 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 (class != NO_REGS)
+    t_reload = push_secondary_reload (in_p, x, opnum, optional, class,
+                                     reload_mode, type, &t_icode, &sri);
 
-  if (icode != CODE_FOR_nothing
-      && insn_data[(int) icode].operand[in_p].predicate
-      && (! (insn_data[(int) icode].operand[in_p].predicate) (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 we will be using an insn, the secondary reload is for a
+     scratch register.  */
 
   if (icode != CODE_FOR_nothing)
     {
@@ -374,45 +361,29 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
         in operand 1.  Outputs should have an initial "=", which we must
         skip.  */
 
-      enum reg_class insn_class;
-
-      if (insn_data[(int) icode].operand[!in_p].constraint[0] == 0)
-       insn_class = ALL_REGS;
-      else
-       {
-         const char *insn_constraint
-           = &insn_data[(int) icode].operand[!in_p].constraint[in_p];
-         char insn_letter = *insn_constraint;
-         insn_class
-           = (insn_letter == 'r' ? GENERAL_REGS
-              : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
-                                           insn_constraint));
-
-          gcc_assert (insn_class != NO_REGS);
-         gcc_assert (!in_p
-                     || insn_data[(int) icode].operand[!in_p].constraint[0]
-                        == '=');
-       }
-
-      /* The scratch register's constraint must start with "=&".  */
-      gcc_assert (insn_data[(int) icode].operand[2].constraint[0] == '='
-                 && insn_data[(int) icode].operand[2].constraint[1] == '&');
-
-      if (reg_class_subset_p (reload_class, insn_class))
-       mode = insn_data[(int) icode].operand[2].mode;
-      else
-       {
-         const char *t_constraint
-           = &insn_data[(int) icode].operand[2].constraint[2];
-         char t_letter = *t_constraint;
-         class = insn_class;
-         t_mode = insn_data[(int) icode].operand[2].mode;
-         t_class = (t_letter == 'r' ? GENERAL_REGS
-                    : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter,
-                                                 t_constraint));
-         t_icode = icode;
-         icode = CODE_FOR_nothing;
-       }
+      /* ??? It would be useful to be able to handle only two, or more than
+        three, operands, but for now we can only handle the case of having
+        exactly three: output, input and one temp/scratch.  */
+      gcc_assert (insn_data[(int) icode].n_operands == 3);
+
+      /* ??? We currently have no way to represent a reload that needs
+        an icode to reload from an intermediate tertiary reload register.
+        We should probably have a new field in struct reload to tag a
+        chain of scratch operand reloads onto.   */
+      gcc_assert (class == NO_REGS);
+
+      scratch_constraint = insn_data[(int) icode].operand[2].constraint;
+      gcc_assert (*scratch_constraint == '=');
+      scratch_constraint++;
+      if (*scratch_constraint == '&')
+       scratch_constraint++;
+      letter = *scratch_constraint;
+      scratch_class = (letter == 'r' ? GENERAL_REGS
+                      : REG_CLASS_FROM_CONSTRAINT ((unsigned char) letter,
+                                                  scratch_constraint));
+
+      class = scratch_class;
+      mode = insn_data[(int) icode].operand[2].mode;
     }
 
   /* This case isn't valid, so fail.  Reload is allowed to use the same
@@ -432,68 +403,6 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
   gcc_assert (!in_p || class != reload_class || icode != CODE_FOR_nothing
              || t_icode != CODE_FOR_nothing);
 
-  /* If we need a tertiary reload, see if we have one we can reuse or else
-     make a new one.  */
-
-  if (t_class != NO_REGS)
-    {
-      for (t_reload = 0; t_reload < n_reloads; t_reload++)
-       if (rld[t_reload].secondary_p
-           && (reg_class_subset_p (t_class, rld[t_reload].class)
-               || reg_class_subset_p (rld[t_reload].class, t_class))
-           && ((in_p && rld[t_reload].inmode == t_mode)
-               || (! in_p && rld[t_reload].outmode == t_mode))
-           && ((in_p && (rld[t_reload].secondary_in_icode
-                         == CODE_FOR_nothing))
-               || (! in_p &&(rld[t_reload].secondary_out_icode
-                             == CODE_FOR_nothing)))
-           && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES)
-           && MERGABLE_RELOADS (secondary_type,
-                                rld[t_reload].when_needed,
-                                opnum, rld[t_reload].opnum))
-         {
-           if (in_p)
-             rld[t_reload].inmode = t_mode;
-           if (! in_p)
-             rld[t_reload].outmode = t_mode;
-
-           if (reg_class_subset_p (t_class, rld[t_reload].class))
-             rld[t_reload].class = t_class;
-
-           rld[t_reload].opnum = MIN (rld[t_reload].opnum, opnum);
-           rld[t_reload].optional &= optional;
-           rld[t_reload].secondary_p = 1;
-           if (MERGE_TO_OTHER (secondary_type, rld[t_reload].when_needed,
-                               opnum, rld[t_reload].opnum))
-             rld[t_reload].when_needed = RELOAD_OTHER;
-         }
-
-      if (t_reload == n_reloads)
-       {
-         /* We need to make a new tertiary reload for this register class.  */
-         rld[t_reload].in = rld[t_reload].out = 0;
-         rld[t_reload].class = t_class;
-         rld[t_reload].inmode = in_p ? t_mode : VOIDmode;
-         rld[t_reload].outmode = ! in_p ? t_mode : VOIDmode;
-         rld[t_reload].reg_rtx = 0;
-         rld[t_reload].optional = optional;
-         rld[t_reload].inc = 0;
-         /* Maybe we could combine these, but it seems too tricky.  */
-         rld[t_reload].nocombine = 1;
-         rld[t_reload].in_reg = 0;
-         rld[t_reload].out_reg = 0;
-         rld[t_reload].opnum = opnum;
-         rld[t_reload].when_needed = secondary_type;
-         rld[t_reload].secondary_in_reload = -1;
-         rld[t_reload].secondary_out_reload = -1;
-         rld[t_reload].secondary_in_icode = CODE_FOR_nothing;
-         rld[t_reload].secondary_out_icode = CODE_FOR_nothing;
-         rld[t_reload].secondary_p = 1;
-
-         n_reloads++;
-       }
-    }
-
   /* See if we can reuse an existing secondary reload.  */
   for (s_reload = 0; s_reload < n_reloads; s_reload++)
     if (rld[s_reload].secondary_p
@@ -505,7 +414,7 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
            || (! in_p && rld[s_reload].secondary_out_reload == t_reload))
        && ((in_p && rld[s_reload].secondary_in_icode == t_icode)
            || (! in_p && rld[s_reload].secondary_out_icode == t_icode))
-       && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
+       && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
        && MERGABLE_RELOADS (secondary_type, rld[s_reload].when_needed,
                             opnum, rld[s_reload].opnum))
       {
@@ -578,7 +487,58 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
   *picode = icode;
   return s_reload;
 }
-#endif /* HAVE_SECONDARY_RELOADS */
+
+/* If a secondary reload is needed, return its class.  If both an intermediate
+   register and a scratch register is needed, we return the class of the
+   intermediate register.  */
+enum reg_class
+secondary_reload_class (bool in_p, enum reg_class class,
+                       enum machine_mode mode, rtx x)
+{
+  enum insn_code icode;
+  secondary_reload_info sri;
+
+  sri.icode = CODE_FOR_nothing;
+  sri.prev_sri = NULL;
+  class = targetm.secondary_reload (in_p, x, class, mode, &sri);
+  icode = sri.icode;
+
+  /* If there are no secondary reloads at all, we return NO_REGS.
+     If an intermediate register is needed, we return its class.  */
+  if (icode == CODE_FOR_nothing || class != NO_REGS)
+    return class;
+
+  /* No intermediate register is needed, but we have a special reload
+     pattern, which we assume for now needs a scratch register.  */
+  return scratch_reload_class (icode);
+}
+
+/* ICODE is the insn_code of a reload pattern.  Check that it has exactly
+   three operands, verify that operand 2 is an output operand, and return
+   its register class.
+   ??? We'd like to be able to handle any pattern with at least 2 operands,
+   for zero or more scratch registers, but that needs more infrastructure.  */
+enum reg_class
+scratch_reload_class (enum insn_code icode)
+{
+  const char *scratch_constraint;
+  char scratch_letter;
+  enum reg_class class;
+
+  gcc_assert (insn_data[(int) icode].n_operands == 3);
+  scratch_constraint = insn_data[(int) icode].operand[2].constraint;
+  gcc_assert (*scratch_constraint == '=');
+  scratch_constraint++;
+  if (*scratch_constraint == '&')
+    scratch_constraint++;
+  scratch_letter = *scratch_constraint;
+  if (scratch_letter == 'r')
+    return GENERAL_REGS;
+  class = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
+                                    scratch_constraint);
+  gcc_assert (class != NO_REGS);
+  return class;
+}
 \f
 #ifdef SECONDARY_MEMORY_NEEDED
 
@@ -664,12 +624,15 @@ clear_secondary_mem (void)
 }
 #endif /* SECONDARY_MEMORY_NEEDED */
 \f
-/* Find the largest class for which every register number plus N is valid in
-   M1 (if in range) and is cheap to move into REGNO.
-   Abort if no such class exists.  */
+
+/* Find the largest class which has at least one register valid in
+   mode INNER, and which for every such register, that register number
+   plus N is also valid in OUTER (if in range) and is cheap to move
+   into REGNO.  Such a class must exist.  */
 
 static enum reg_class
-find_valid_class (enum machine_mode m1 ATTRIBUTE_UNUSED, int n,
+find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
+                 enum machine_mode inner ATTRIBUTE_UNUSED, int n,
                  unsigned int dest_regno ATTRIBUTE_UNUSED)
 {
   int best_cost = -1;
@@ -683,15 +646,22 @@ find_valid_class (enum machine_mode m1 ATTRIBUTE_UNUSED, int n,
   for (class = 1; class < N_REG_CLASSES; class++)
     {
       int bad = 0;
-      for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++)
-       if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
-           && TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
-           && ! HARD_REGNO_MODE_OK (regno + n, m1))
-         bad = 1;
+      int good = 0;
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER - n && ! bad; regno++)
+       if (TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+         {
+           if (HARD_REGNO_MODE_OK (regno, inner))
+             {
+               good = 1;
+               if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
+                   || ! HARD_REGNO_MODE_OK (regno + n, outer))
+                 bad = 1;
+             }
+         }
 
-      if (bad)
+      if (bad || !good)
        continue;
-      cost = REGISTER_MOVE_COST (m1, class, dest_class);
+      cost = REGISTER_MOVE_COST (outer, class, dest_class);
 
       if ((reg_class_size[class] > best_size
           && (best_cost < 0 || best_cost >= cost))
@@ -699,7 +669,7 @@ find_valid_class (enum machine_mode m1 ATTRIBUTE_UNUSED, int n,
        {
          best_class = class;
          best_size = reg_class_size[class];
-         best_cost = REGISTER_MOVE_COST (m1, class, dest_class);
+         best_cost = REGISTER_MOVE_COST (outer, class, dest_class);
        }
     }
 
@@ -749,7 +719,7 @@ find_reusable_reload (rtx *p_in, rtx out, enum reg_class class,
            || (out != 0 && MATCHES (rld[i].out, out)
                && (in == 0 || rld[i].in == 0 || MATCHES (rld[i].in, in))))
        && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
-       && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
+       && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
        && MERGABLE_RELOADS (type, rld[i].when_needed, opnum, rld[i].opnum))
       return i;
 
@@ -774,7 +744,7 @@ find_reusable_reload (rtx *p_in, rtx out, enum reg_class class,
                && GET_RTX_CLASS (GET_CODE (in)) == RTX_AUTOINC
                && MATCHES (XEXP (in, 0), rld[i].in)))
        && (rld[i].out == 0 || ! earlyclobber_operand_p (rld[i].out))
-       && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
+       && (SMALL_REGISTER_CLASS_P (class) || SMALL_REGISTER_CLASSES)
        && MERGABLE_RELOADS (type, rld[i].when_needed,
                             opnum, rld[i].opnum))
       {
@@ -1045,13 +1015,10 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
                       != (int) hard_regno_nregs[REGNO (SUBREG_REG (in))]
                                                [GET_MODE (SUBREG_REG (in))]))
                  || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode)))
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
-         || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS
-             && (SECONDARY_INPUT_RELOAD_CLASS (class,
-                                               GET_MODE (SUBREG_REG (in)),
-                                               SUBREG_REG (in))
+         || (secondary_reload_class (1, class, inmode, in) != NO_REGS
+             && (secondary_reload_class (1, class, GET_MODE (SUBREG_REG (in)),
+                                         SUBREG_REG (in))
                  == NO_REGS))
-#endif
 #ifdef CANNOT_CHANGE_MODE_CLASS
          || (REG_P (SUBREG_REG (in))
              && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
@@ -1088,7 +1055,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
       if (REG_P (SUBREG_REG (in)))
        in_class
-         = find_valid_class (inmode,
+         = find_valid_class (inmode, GET_MODE (SUBREG_REG (in)),
                              subreg_regno_offset (REGNO (SUBREG_REG (in)),
                                                   GET_MODE (SUBREG_REG (in)),
                                                   SUBREG_BYTE (in),
@@ -1141,13 +1108,10 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
                       != (int) hard_regno_nregs[REGNO (SUBREG_REG (out))]
                                                [GET_MODE (SUBREG_REG (out))]))
                  || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode)))
-#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-         || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS
-             && (SECONDARY_OUTPUT_RELOAD_CLASS (class,
-                                                GET_MODE (SUBREG_REG (out)),
-                                                SUBREG_REG (out))
+         || (secondary_reload_class (0, class, outmode, out) != NO_REGS
+             && (secondary_reload_class (0, class, GET_MODE (SUBREG_REG (out)),
+                                         SUBREG_REG (out))
                  == NO_REGS))
-#endif
 #ifdef CANNOT_CHANGE_MODE_CLASS
          || (REG_P (SUBREG_REG (out))
              && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
@@ -1185,7 +1149,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
       dont_remove_subreg = 1;
       push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
                   &SUBREG_REG (out),
-                  find_valid_class (outmode,
+                  find_valid_class (outmode, GET_MODE (SUBREG_REG (out)),
                                     subreg_regno_offset (REGNO (SUBREG_REG (out)),
                                                          GET_MODE (SUBREG_REG (out)),
                                                          SUBREG_BYTE (out),
@@ -1297,19 +1261,14 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
         and IN or CLASS and OUT.  Get the icode and push any required reloads
         needed for each of them if so.  */
 
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
       if (in != 0)
        secondary_in_reload
          = push_secondary_reload (1, in, opnum, optional, class, inmode, type,
-                                  &secondary_in_icode);
-#endif
-
-#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+                                  &secondary_in_icode, NULL);
       if (out != 0 && GET_CODE (out) != SCRATCH)
        secondary_out_reload
          = push_secondary_reload (0, out, opnum, optional, class, outmode,
-                                  type, &secondary_out_icode);
-#endif
+                                  type, &secondary_out_icode, NULL);
 
       /* We found no existing reload suitable for re-use.
         So add an additional reload.  */
@@ -1507,7 +1466,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
      But if there is no spilling in this block, that is OK.
      An explicitly used hard reg cannot be a spill reg.  */
 
-  if (rld[i].reg_rtx == 0 && in != 0)
+  if (rld[i].reg_rtx == 0 && in != 0 && hard_regs_live_known)
     {
       rtx note;
       int regno;
@@ -1521,6 +1480,11 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
            && REG_P (XEXP (note, 0))
            && (regno = REGNO (XEXP (note, 0))) < FIRST_PSEUDO_REGISTER
            && reg_mentioned_p (XEXP (note, 0), in)
+           /* Check that we don't use a hardreg for an uninitialized
+              pseudo.  See also find_dummy_reload().  */
+           && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
+               || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
+                                  ORIGINAL_REGNO (XEXP (note, 0))))
            && ! refers_to_regno_for_reload_p (regno,
                                               (regno
                                                + hard_regno_nregs[regno]
@@ -1984,7 +1948,17 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
                                is a subreg, and in that case, out
                                has a real mode.  */
                             (GET_MODE (out) != VOIDmode
-                             ? GET_MODE (out) : outmode)))
+                             ? GET_MODE (out) : outmode))
+        /* But only do all this if we can be sure, that this input
+           operand doesn't correspond with an uninitialized pseudoreg.
+           global can assign some hardreg to it, which is the same as
+          a different pseudo also currently live (as it can ignore the
+          conflict).  So we never must introduce writes to such hardregs,
+          as they would clobber the other live pseudo using the same.
+          See also PR20973.  */
+      && (ORIGINAL_REGNO (in) < FIRST_PSEUDO_REGISTER
+          || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
+                            ORIGINAL_REGNO (in))))
     {
       unsigned int regno = REGNO (in) + in_offset;
       unsigned int nwords = hard_regno_nregs[regno][inmode];
@@ -2147,12 +2121,15 @@ operands_match_p (rtx x, rtx y)
        j = REGNO (y);
 
       /* On a WORDS_BIG_ENDIAN machine, point to the last register of a
-        multiple hard register group, so that for example (reg:DI 0) and
-        (reg:SI 1) will be considered the same register.  */
+        multiple hard register group of scalar integer registers, so that
+        for example (reg:DI 0) and (reg:SI 1) will be considered the same
+        register.  */
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
+         && SCALAR_INT_MODE_P (GET_MODE (x))
          && i < FIRST_PSEUDO_REGISTER)
        i += hard_regno_nregs[i][GET_MODE (x)] - 1;
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD
+         && SCALAR_INT_MODE_P (GET_MODE (y))
          && j < FIRST_PSEUDO_REGISTER)
        j += hard_regno_nregs[j][GET_MODE (y)] - 1;
 
@@ -2177,20 +2154,30 @@ operands_match_p (rtx x, rtx y)
 
  slow:
 
-  /* Now we have disposed of all the cases
-     in which different rtx codes can match.  */
+  /* 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;
 
+  switch (code)
+    {
+    case CONST_INT:
+    case CONST_DOUBLE:
+      return 0;
+
+    case LABEL_REF:
+      return XEXP (x, 0) == XEXP (y, 0);
+    case SYMBOL_REF:
+      return XSTR (x, 0) == XSTR (y, 0);
+
+    default:
+      break;
+    }
+
   /* Compare the elements.  If any pair of corresponding elements
      fail to match, return 0 for the whole things.  */
 
@@ -2358,7 +2345,7 @@ decompose (rtx x)
     case REG:
       val.reg_flag = 1;
       val.start = true_regnum (x);
-      if (val.start < 0)
+      if (val.start < 0 || val.start >= FIRST_PSEUDO_REGISTER)
        {
          /* A pseudo with no hard reg.  */
          val.start = REGNO (x);
@@ -2375,7 +2362,7 @@ decompose (rtx x)
        return decompose (SUBREG_REG (x));
       val.reg_flag = 1;
       val.start = true_regnum (x);
-      if (val.start < 0)
+      if (val.start < 0 || val.start >= FIRST_PSEUDO_REGISTER)
        return decompose (SUBREG_REG (x));
       else
        /* A hard reg.  */
@@ -3478,7 +3465,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
          if (! win && ! did_match
              && this_alternative[i] != (int) NO_REGS
              && GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-             && reg_class_size[(int) preferred_class[i]] > 1)
+             && reg_class_size [(int) preferred_class[i]] > 0
+             && ! SMALL_REGISTER_CLASS_P (preferred_class[i]))
            {
              if (! reg_class_subset_p (this_alternative[i],
                                        preferred_class[i]))
@@ -3534,9 +3522,9 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                  && !immune_p (recog_data.operand[j], recog_data.operand[i],
                                early_data))
                {
-                 /* If the output is in a single-reg class,
+                 /* If the output is in a non-empty few-regs class,
                     it's costly to reload it, so reload the input instead.  */
-                 if (reg_class_size[this_alternative[i]] == 1
+                 if (SMALL_REGISTER_CLASS_P (this_alternative[i])
                      && (REG_P (recog_data.operand[j])
                          || GET_CODE (recog_data.operand[j]) == SUBREG))
                    {
@@ -3654,6 +3642,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
          pref_or_nothing[commutative] = pref_or_nothing[commutative + 1];
          pref_or_nothing[commutative + 1] = t;
 
+         t = address_reloaded[commutative];
+         address_reloaded[commutative] = address_reloaded[commutative + 1];
+         address_reloaded[commutative + 1] = t;
+
          memcpy (constraints, recog_data.constraints,
                  noperands * sizeof (char *));
          goto try_swapped;
@@ -3786,6 +3778,27 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
          goal_alternative_win[i] = 1;
       }
 
+  /* Likewise any invalid constants appearing as operand of a PLUS
+     that is to be reloaded.  */
+  for (i = 0; i < noperands; i++)
+    if (! goal_alternative_win[i]
+       && GET_CODE (recog_data.operand[i]) == PLUS
+       && CONST_POOL_OK_P (XEXP (recog_data.operand[i], 1))
+       && (PREFERRED_RELOAD_CLASS (XEXP (recog_data.operand[i], 1),
+                                   (enum reg_class) goal_alternative[i])
+            == NO_REGS)
+       && operand_mode[i] != VOIDmode)
+      {
+       rtx tem = force_const_mem (operand_mode[i],
+                                  XEXP (recog_data.operand[i], 1));
+       tem = gen_rtx_PLUS (operand_mode[i],
+                           XEXP (recog_data.operand[i], 0), tem);
+
+       substed_operand[i] = recog_data.operand[i]
+         = find_reloads_toplev (tem, i, address_type[i],
+                                ind_levels, 0, insn, NULL);
+      }
+
   /* Record the values of the earlyclobber operands for the caller.  */
   if (goal_earlyclobber)
     for (i = 0; i < noperands; i++)
@@ -4015,7 +4028,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
     {
       /* We only do this on the last pass through reload, because it is
         possible for some data (like reg_equiv_address) to be changed during
-        later passes.  Moreover, we loose the opportunity to get a useful
+        later passes.  Moreover, we lose the opportunity to get a useful
         reload_{in,out}_reg when we do these replacements.  */
 
       if (replace)
@@ -4502,14 +4515,14 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
 
   if (code == SUBREG && REG_P (SUBREG_REG (x)))
     {
-      /* 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).  */
+      /* 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.  The constant must not be VOIDmode, because we
+        will lose the mode of the register (this should never happen
+        because one of the cases above should handle it).  */
 
       int regno = REGNO (SUBREG_REG (x));
       rtx tem;
@@ -5227,7 +5240,8 @@ update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
    is strictly valid.)
 
    CONTEXT = 1 means we are considering regs as index regs,
-   = 0 means we are considering them as base regs.
+   = 0 means we are considering them as base regs, = 2 means we
+   are considering them as base regs for REG + REG.
 
    OPNUM and TYPE specify the purpose of any reloads made.
 
@@ -5243,15 +5257,32 @@ update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
    occurs as part of an address.
    Also, this is not fully machine-customizable; it works for machines
    such as VAXen and 68000's and 32000's, but other possible machines
-   could have addressing modes that this does not handle right.  */
+   could have addressing modes that this does not handle right.
+   If you add push_reload calls here, you need to make sure gen_reload
+   handles those cases gracefully.  */
 
 static int
 find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                        rtx *loc, int opnum, enum reload_type type,
                        int ind_levels, rtx insn)
 {
+#define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE)               \
+  ((CONTEXT) == 2                                      \
+   ? REGNO_MODE_OK_FOR_REG_BASE_P (REGNO, MODE)                \
+   : (CONTEXT) == 1                                    \
+   ? REGNO_OK_FOR_INDEX_P (REGNO)                      \
+   : REGNO_MODE_OK_FOR_BASE_P (REGNO, MODE))
+
+  enum reg_class context_reg_class;
   RTX_CODE code = GET_CODE (x);
 
+  if (context == 2)
+    context_reg_class = MODE_BASE_REG_REG_CLASS (mode);
+  else if (context == 1)
+    context_reg_class = INDEX_REG_CLASS;
+  else
+    context_reg_class = MODE_BASE_REG_CLASS (mode);
+
   switch (code)
     {
     case PLUS:
@@ -5294,12 +5325,12 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
           register remateralization for expression like &localvar*4.  Reload it.
           It may be possible to combine the displacement on the outer level,
           but it is probably not worthwhile to do so.  */
-       if (context)
+       if (context == 1)
          {
            find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
                                  opnum, ADDR_TYPE (type), ind_levels, insn);
            push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
-                        (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+                        context_reg_class,
                         GET_MODE (x), VOIDmode, 0, 0, opnum, type);
            return 1;
          }
@@ -5335,22 +5366,22 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        else if (code0 == REG && code1 == REG)
          {
            if (REG_OK_FOR_INDEX_P (op0)
-               && REG_MODE_OK_FOR_BASE_P (op1, mode))
+               && REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
              return 0;
            else if (REG_OK_FOR_INDEX_P (op1)
-                    && REG_MODE_OK_FOR_BASE_P (op0, mode))
+                    && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
              return 0;
-           else if (REG_MODE_OK_FOR_BASE_P (op1, mode))
+           else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
              find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
                                      type, ind_levels, insn);
-           else if (REG_MODE_OK_FOR_BASE_P (op0, mode))
+           else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
              find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
                                      type, ind_levels, insn);
            else if (REG_OK_FOR_INDEX_P (op1))
-             find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+             find_reloads_address_1 (mode, orig_op0, 2, &XEXP (x, 0), opnum,
                                      type, ind_levels, insn);
            else if (REG_OK_FOR_INDEX_P (op0))
-             find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+             find_reloads_address_1 (mode, orig_op1, 2, &XEXP (x, 1), opnum,
                                      type, ind_levels, insn);
            else
              {
@@ -5514,9 +5545,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
 
          if (reg_renumber[regno] >= 0)
            regno = reg_renumber[regno];
-         if ((regno >= FIRST_PSEUDO_REGISTER
-              || !(context ? REGNO_OK_FOR_INDEX_P (regno)
-                   : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
+         if (regno >= FIRST_PSEUDO_REGISTER
+             || !REG_OK_FOR_CONTEXT (context, regno, mode))
            {
              int reloadnum;
 
@@ -5552,8 +5582,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                  x = XEXP (x, 0);
                  reloadnum
                    = push_reload (x, x, loc, loc,
-                                  (context ? INDEX_REG_CLASS :
-                                   MODE_BASE_REG_CLASS (mode)),
+                                  context_reg_class,
                                   GET_MODE (x), GET_MODE (x), 0, 0,
                                   opnum, RELOAD_OTHER);
                }
@@ -5561,8 +5590,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                {
                  reloadnum
                    = push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                                  (context ? INDEX_REG_CLASS :
-                                   MODE_BASE_REG_CLASS (mode)),
+                                  context_reg_class,
                                   GET_MODE (x), GET_MODE (x), 0, 0,
                                   opnum, type);
                  rld[reloadnum].inc
@@ -5602,8 +5630,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                                opnum, type, ind_levels, insn);
 
          reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                                  (context ? INDEX_REG_CLASS :
-                                   MODE_BASE_REG_CLASS (mode)),
+                                  context_reg_class,
                                   GET_MODE (x), VOIDmode, 0, 0, opnum, type);
          rld[reloadnum].inc
            = find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
@@ -5616,6 +5643,24 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        }
       return 0;
 
+    case TRUNCATE:
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      /* Look for parts to reload in the inner expression and reload them
+        too, in addition to this operation.  Reloading all inner parts in
+        addition to this one shouldn't be necessary, but at this point,
+        we don't know if we can possibly omit any part that *can* be
+        reloaded.  Targets that are better off reloading just either part
+        (or perhaps even a different part of an outer expression), should
+        define LEGITIMIZE_RELOAD_ADDRESS.  */
+      find_reloads_address_1 (GET_MODE (XEXP (x, 0)), XEXP (x, 0),
+                             context, &XEXP (x, 0), opnum,
+                             type, ind_levels, insn);
+      push_reload (x, NULL_RTX, loc, (rtx*) 0,
+                  context_reg_class,
+                  GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+      return 1;
+
     case MEM:
       /* This is probably the result of a substitution, by eliminate_regs, of
         an equivalent address for a pseudo that was not allocated to a hard
@@ -5632,7 +5677,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
       find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
                            opnum, ADDR_TYPE (type), ind_levels, insn);
       push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
-                  (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+                  context_reg_class,
                   GET_MODE (x), VOIDmode, 0, 0, opnum, type);
       return 1;
 
@@ -5643,8 +5688,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        if (reg_equiv_constant[regno] != 0)
          {
            find_reloads_address_part (reg_equiv_constant[regno], loc,
-                                      (context ? INDEX_REG_CLASS :
-                                       MODE_BASE_REG_CLASS (mode)),
+                                      context_reg_class,
                                       GET_MODE (x), opnum, type, ind_levels);
            return 1;
          }
@@ -5654,8 +5698,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        if (reg_equiv_mem[regno] != 0)
          {
            push_reload (reg_equiv_mem[regno], NULL_RTX, loc, (rtx*) 0,
-                        (context ? INDEX_REG_CLASS :
-                         MODE_BASE_REG_CLASS (mode)),
+                        context_reg_class,
                         GET_MODE (x), VOIDmode, 0, 0, opnum, type);
            return 1;
          }
@@ -5678,12 +5721,11 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        if (reg_renumber[regno] >= 0)
          regno = reg_renumber[regno];
 
-       if ((regno >= FIRST_PSEUDO_REGISTER
-            || !(context ? REGNO_OK_FOR_INDEX_P (regno)
-                 : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
+       if (regno >= FIRST_PSEUDO_REGISTER
+           || !REG_OK_FOR_CONTEXT (context, regno, mode))
          {
            push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                        (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+                        context_reg_class,
                         GET_MODE (x), VOIDmode, 0, 0, opnum, type);
            return 1;
          }
@@ -5695,7 +5737,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        if (regno_clobbered_p (regno, this_insn, GET_MODE (x), 0))
          {
            push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                        (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+                        context_reg_class,
                         GET_MODE (x), VOIDmode, 0, 0, opnum, type);
            return 1;
          }
@@ -5712,12 +5754,10 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
            {
              int regno ATTRIBUTE_UNUSED = subreg_regno (x);
 
-             if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
-                    : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
+             if (! REG_OK_FOR_CONTEXT (context, regno, mode))
                {
                  push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                              (context ? INDEX_REG_CLASS :
-                               MODE_BASE_REG_CLASS (mode)),
+                              context_reg_class,
                               GET_MODE (x), VOIDmode, 0, 0, opnum, type);
                  return 1;
                }
@@ -5726,12 +5766,12 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
             is larger than the class size, then reload the whole SUBREG.  */
          else
            {
-             enum reg_class class = (context ? INDEX_REG_CLASS
-                                     : MODE_BASE_REG_CLASS (mode));
+             enum reg_class class = context_reg_class;
              if ((unsigned) CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
                  > reg_class_size[class])
                {
-                 x = find_reloads_subreg_address (x, 0, opnum, type,
+                 x = find_reloads_subreg_address (x, 0, opnum, 
+                                                  ADDR_TYPE (type),
                                                   ind_levels, insn);
                  push_reload (x, NULL_RTX, loc, (rtx*) 0, class,
                               GET_MODE (x), VOIDmode, 0, 0, opnum, type);
@@ -5757,6 +5797,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
       }
   }
 
+#undef REG_OK_FOR_CONTEXT
   return 0;
 }
 \f
@@ -5871,7 +5912,7 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
              /* If this was a paradoxical subreg that we replaced, the
                 resulting memory must be sufficiently aligned to allow
                 us to widen the mode of the memory.  */
-             if (outer_size > inner_size && STRICT_ALIGNMENT)
+             if (outer_size > inner_size)
                {
                  rtx base;
 
@@ -5890,7 +5931,7 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
                }
 
              find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
-                                   &XEXP (tem, 0), opnum, ADDR_TYPE (type),
+                                   &XEXP (tem, 0), opnum, type,
                                    ind_levels, insn);
 
              /* If this is not a toplevel operand, find_reloads doesn't see
@@ -5958,9 +5999,12 @@ subst_reloads (rtx insn)
             register refers to.  */
          if (GET_CODE (*r->where) == LABEL_REF
              && JUMP_P (insn))
-           REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
-                                                 XEXP (*r->where, 0),
-                                                 REG_NOTES (insn));
+           {
+             REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+                                                   XEXP (*r->where, 0),
+                                                   REG_NOTES (insn));
+             JUMP_LABEL (insn) = XEXP (*r->where, 0);
+          }
 
          /* Encapsulate RELOADREG so its machine mode matches what
             used to be there.  Note that gen_lowpart_common will
@@ -6151,7 +6195,7 @@ find_replacement (rtx *loc)
    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
+static int
 refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno,
                              rtx x, rtx *loc)
 {
@@ -6180,7 +6224,7 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno,
                                                 reg_equiv_memory_loc[r],
                                                 (rtx*) 0);
 
-         gcc_assert (reg_equiv_constant[r]);
+         gcc_assert (reg_equiv_constant[r] || reg_equiv_invariant[r]);
          return 0;
        }
 
@@ -6286,6 +6330,8 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
   /* If either argument is a constant, then modifying X can not affect IN.  */
   if (CONSTANT_P (x) || CONSTANT_P (in))
     return 0;
+  else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == MEM)
+    return refers_to_mem_for_reload_p (in);
   else if (GET_CODE (x) == SUBREG)
     {
       regno = REGNO (SUBREG_REG (x));
@@ -6344,7 +6390,7 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
 /* Return nonzero if anything in X contains a MEM.  Look also for pseudo
    registers.  */
 
-int
+static int
 refers_to_mem_for_reload_p (rtx x)
 {
   const char *fmt;
@@ -6420,7 +6466,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
       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)
+      if (flag_float_store && SCALAR_FLOAT_MODE_P (GET_MODE (goal)))
        return 0;
       /* An address with side effects must be reexecuted.  */
       switch (code)
@@ -6472,7 +6518,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
                 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
+                That makes bad code.  It may even fail: perhaps no reg was
                 spilled for this insn because it was assumed we would find
                 that equivalent.  */
              || INSN_UID (p) < reload_first_uid))
@@ -6511,8 +6557,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
                               = true_regnum (valtry = SET_DEST (pat))) >= 0)
                          || (REG_P (SET_DEST (pat))
                              && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
-                             && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0)))
-                                 == MODE_FLOAT)
+                             && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
                              && GET_CODE (goal) == CONST_INT
                              && 0 != (goaltry
                                       = operand_subword (XEXP (tem, 0), 0, 0,
@@ -6526,8 +6571,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
                                                          NULL_RTX))
                      && REG_P (SET_DEST (pat))
                      && GET_CODE (XEXP (tem, 0)) == CONST_DOUBLE
-                     && (GET_MODE_CLASS (GET_MODE (XEXP (tem, 0)))
-                         == MODE_FLOAT)
+                     && SCALAR_FLOAT_MODE_P (GET_MODE (XEXP (tem, 0)))
                      && GET_CODE (goal) == CONST_INT
                      && 0 != (goaltry = operand_subword (XEXP (tem, 0), 1, 0,
                                                          VOIDmode))
@@ -6663,17 +6707,15 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
 
          if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER)
            for (i = 0; i < nregs; ++i)
-             if (call_used_regs[regno + i])
+             if (call_used_regs[regno + i]
+                 || HARD_REGNO_CALL_PART_CLOBBERED (regno + i, mode))
                return 0;
 
          if (valueno >= 0 && valueno < FIRST_PSEUDO_REGISTER)
            for (i = 0; i < valuenregs; ++i)
-             if (call_used_regs[valueno + i])
+             if (call_used_regs[valueno + i]
+                 || HARD_REGNO_CALL_PART_CLOBBERED (valueno + i, mode))
                return 0;
-#ifdef NON_SAVING_SETJMP
-         if (NON_SAVING_SETJMP && find_reg_note (p, REG_SETJMP, NULL))
-           return 0;
-#endif
        }
 
       if (INSN_P (p))
@@ -6696,7 +6738,6 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
              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 (REG_P (dest))
@@ -6740,7 +6781,6 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
                      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 (REG_P (dest))
@@ -6902,14 +6942,20 @@ find_inc_amount (rtx x, rtx inced)
 }
 \f
 /* Return 1 if register REGNO is the subject of a clobber in insn INSN.
-   If SETS is nonzero, also consider SETs.  */
+   If SETS is nonzero, also consider SETs.  REGNO must refer to a hard
+   register.  */
 
 int
 regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode,
                   int sets)
 {
-  unsigned int nregs = hard_regno_nregs[regno][mode];
-  unsigned int endregno = regno + nregs;
+  unsigned int nregs, endregno;
+
+  /* regno must be a hard register.  */
+  gcc_assert (regno < FIRST_PSEUDO_REGISTER);
+
+  nregs = hard_regno_nregs[regno][mode];
+  endregno = regno + nregs;
 
   if ((GET_CODE (PATTERN (insn)) == CLOBBER
        || (sets && GET_CODE (PATTERN (insn)) == SET))
@@ -6975,8 +7021,6 @@ static const char *const reload_when_needed_name[] =
   "RELOAD_FOR_OTHER_ADDRESS"
 };
 
-static const char * const reg_class_names[] = REG_CLASS_NAMES;
-
 /* These functions are used to print the variables set by 'find_reloads' */
 
 void