re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / reload.c
index f4f3ed03d859fb59a251cc3bfc32fe592d041b2d..1dc04bf0eb96df901aad7d043f58f4d6066c4cbe 100644 (file)
@@ -1,7 +1,5 @@
 /* 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, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -97,16 +95,32 @@ a register with any other reload.  */
 #include "rtl-error.h"
 #include "tm_p.h"
 #include "insn-config.h"
+#include "symtab.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "rtl.h"
+#include "flags.h"
+#include "alias.h"
+#include "tree.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
+#include "insn-codes.h"
 #include "optabs.h"
 #include "recog.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "predict.h"
+#include "basic-block.h"
 #include "df.h"
 #include "reload.h"
 #include "regs.h"
 #include "addresses.h"
-#include "hard-reg-set.h"
-#include "flags.h"
-#include "function.h"
 #include "params.h"
 #include "target.h"
 #include "ira.h"
@@ -158,7 +172,7 @@ struct replacement
 {
   rtx *where;                  /* Location to store in */
   int what;                    /* which reload this is for */
-  enum machine_mode mode;      /* mode it must have */
+  machine_mode mode;   /* mode it must have */
 };
 
 static struct replacement replacements[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
@@ -193,7 +207,7 @@ static int secondary_memlocs_elim_used = 0;
 
 /* The instruction we are doing reloads for;
    so we can test whether a register dies in it.  */
-static rtx this_insn;
+static rtx_insn *this_insn;
 
 /* Nonzero if this instruction is a user-specified asm with operands.  */
 static int this_insn_is_asm;
@@ -251,39 +265,39 @@ static int output_reloadnum;
       : (type)))
 
 static int push_secondary_reload (int, rtx, int, int, enum reg_class,
-                                 enum machine_mode, enum reload_type,
+                                 machine_mode, enum reload_type,
                                  enum insn_code *, secondary_reload_info *);
-static enum reg_class find_valid_class (enum machine_mode, enum machine_mode,
+static enum reg_class find_valid_class (machine_mode, machine_mode,
                                        int, unsigned int);
-static void push_replacement (rtx *, int, enum machine_mode);
+static void push_replacement (rtx *, int, machine_mode);
 static void dup_replacements (rtx *, rtx *);
 static void combine_reloads (void);
 static int find_reusable_reload (rtx *, rtx, enum reg_class,
                                 enum reload_type, int, int);
-static rtx find_dummy_reload (rtx, rtx, rtx *, rtx *, enum machine_mode,
-                             enum machine_mode, reg_class_t, int, int);
+static rtx find_dummy_reload (rtx, rtx, rtx *, rtx *, machine_mode,
+                             machine_mode, reg_class_t, int, int);
 static int hard_reg_set_here_p (unsigned int, unsigned int, rtx);
 static struct decomposition decompose (rtx);
 static int immune_p (rtx, rtx, struct decomposition);
 static bool alternative_allows_const_pool_ref (rtx, const char *, int);
-static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx,
-                               int *);
+static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int,
+                               rtx_insn *, int *);
 static rtx make_memloc (rtx, int);
-static int maybe_memory_address_addr_space_p (enum machine_mode, rtx,
+static int maybe_memory_address_addr_space_p (machine_mode, rtx,
                                              addr_space_t, rtx *);
-static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *,
-                                int, enum reload_type, int, rtx);
-static rtx subst_reg_equivs (rtx, rtx);
+static int find_reloads_address (machine_mode, rtx *, rtx, rtx *,
+                                int, enum reload_type, int, rtx_insn *);
+static rtx subst_reg_equivs (rtx, rtx_insn *);
 static rtx subst_indexed_address (rtx);
-static void update_auto_inc_notes (rtx, int, int);
-static int find_reloads_address_1 (enum machine_mode, addr_space_t, rtx, int,
+static void update_auto_inc_notes (rtx_insn *, int, int);
+static int find_reloads_address_1 (machine_mode, addr_space_t, rtx, int,
                                   enum rtx_code, enum rtx_code, rtx *,
-                                  int, enum reload_type,int, rtx);
+                                  int, enum reload_type,int, rtx_insn *);
 static void find_reloads_address_part (rtx, rtx *, enum reg_class,
-                                      enum machine_mode, int,
+                                      machine_mode, int,
                                       enum reload_type, int);
-static rtx find_reloads_subreg_address (rtx, int, int, enum reload_type,
-                                       int, rtx, int *);
+static rtx find_reloads_subreg_address (rtx, int, enum reload_type,
+                                       int, rtx_insn *, int *);
 static void copy_replacements_1 (rtx *, rtx *, int);
 static int find_inc_amount (rtx, rtx);
 static int refers_to_mem_for_reload_p (rtx);
@@ -319,18 +333,17 @@ push_reg_equiv_alt_mem (int regno, rtx mem)
 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,
+                      machine_mode reload_mode, enum reload_type type,
                       enum insn_code *picode, secondary_reload_info *prev_sri)
 {
   enum reg_class rclass = NO_REGS;
   enum reg_class scratch_class;
-  enum machine_mode mode = reload_mode;
+  machine_mode mode = reload_mode;
   enum insn_code icode = CODE_FOR_nothing;
   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
@@ -401,10 +414,8 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
       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));
+      scratch_class = (reg_class_for_constraint
+                      (lookup_constraint (scratch_constraint)));
 
       rclass = scratch_class;
       mode = insn_data[(int) icode].operand[2].mode;
@@ -519,7 +530,7 @@ push_secondary_reload (int in_p, rtx x, int opnum, int optional,
    register and a scratch register is needed, we return the class of the
    intermediate register.  */
 reg_class_t
-secondary_reload_class (bool in_p, reg_class_t rclass, enum machine_mode mode,
+secondary_reload_class (bool in_p, reg_class_t rclass, machine_mode mode,
                        rtx x)
 {
   enum insn_code icode;
@@ -550,7 +561,6 @@ enum reg_class
 scratch_reload_class (enum insn_code icode)
 {
   const char *scratch_constraint;
-  char scratch_letter;
   enum reg_class rclass;
 
   gcc_assert (insn_data[(int) icode].n_operands == 3);
@@ -559,11 +569,7 @@ scratch_reload_class (enum insn_code icode)
   scratch_constraint++;
   if (*scratch_constraint == '&')
     scratch_constraint++;
-  scratch_letter = *scratch_constraint;
-  if (scratch_letter == 'r')
-    return GENERAL_REGS;
-  rclass = REG_CLASS_FROM_CONSTRAINT ((unsigned char) scratch_letter,
-                                    scratch_constraint);
+  rclass = reg_class_for_constraint (lookup_constraint (scratch_constraint));
   gcc_assert (rclass != NO_REGS);
   return rclass;
 }
@@ -575,7 +581,7 @@ scratch_reload_class (enum insn_code icode)
    call find_reloads_address on the location being returned.  */
 
 rtx
-get_secondary_mem (rtx x ATTRIBUTE_UNUSED, enum machine_mode mode,
+get_secondary_mem (rtx x ATTRIBUTE_UNUSED, machine_mode mode,
                   int opnum, enum reload_type type)
 {
   rtx loc;
@@ -660,8 +666,8 @@ clear_secondary_mem (void)
    into REGNO.  Such a class must exist.  */
 
 static enum reg_class
-find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
-                 enum machine_mode inner ATTRIBUTE_UNUSED, int n,
+find_valid_class (machine_mode outer ATTRIBUTE_UNUSED,
+                 machine_mode inner ATTRIBUTE_UNUSED, int n,
                  unsigned int dest_regno ATTRIBUTE_UNUSED)
 {
   int best_cost = -1;
@@ -682,8 +688,8 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
            if (HARD_REGNO_MODE_OK (regno, inner))
              {
                good = 1;
-               if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
-                   || ! HARD_REGNO_MODE_OK (regno + n, outer))
+               if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno + n)
+                   && ! HARD_REGNO_MODE_OK (regno + n, outer))
                  bad = 1;
              }
          }
@@ -709,13 +715,13 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED,
 }
 
 /* We are trying to reload a subreg of something that is not a register.
-   Find the largest class which has at least one register valid in
+   Find the largest class which contains only registers valid in
    mode MODE.  OUTER is the mode of the subreg, DEST_CLASS the class in
    which we would eventually like to obtain the object.  */
 
 static enum reg_class
-find_valid_class_1 (enum machine_mode outer ATTRIBUTE_UNUSED,
-                   enum machine_mode mode ATTRIBUTE_UNUSED,
+find_valid_class_1 (machine_mode outer ATTRIBUTE_UNUSED,
+                   machine_mode mode ATTRIBUTE_UNUSED,
                    enum reg_class dest_class ATTRIBUTE_UNUSED)
 {
   int best_cost = -1;
@@ -729,10 +735,12 @@ find_valid_class_1 (enum machine_mode outer ATTRIBUTE_UNUSED,
     {
       int bad = 0;
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++)
-       if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno)
-           && !HARD_REGNO_MODE_OK (regno, mode))
-         bad = 1;
-
+       {
+         if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno)
+             && !HARD_REGNO_MODE_OK (regno, mode))
+           bad = 1;
+       }
+      
       if (bad)
        continue;
 
@@ -843,7 +851,7 @@ find_reusable_reload (rtx *p_in, rtx out, enum reg_class rclass,
    the function is invoked for the output part of an enclosing reload.  */
 
 static bool
-reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, bool output)
+reload_inner_reg_of_subreg (rtx x, machine_mode mode, bool output)
 {
   rtx inner;
 
@@ -891,11 +899,12 @@ reload_inner_reg_of_subreg (rtx x, enum machine_mode mode, bool output)
    patterns by register elimination and substituting pseudos without a home
    by their function-invariant equivalences.  */
 static int
-can_reload_into (rtx in, int regno, enum machine_mode mode)
+can_reload_into (rtx in, int regno, machine_mode mode)
 {
-  rtx dst, test_insn;
+  rtx dst;
+  rtx_insn *test_insn;
   int r = 0;
-  struct recog_data save_recog_data;
+  struct recog_data_d save_recog_data;
 
   /* For matching constraints, we often get notional input reloads where
      we want to use the original register as the reload register.  I.e.
@@ -915,12 +924,12 @@ can_reload_into (rtx in, int regno, enum machine_mode mode)
   /* If we can make a simple SET insn that does the job, everything should
      be fine.  */
   dst =  gen_rtx_REG (mode, regno);
-  test_insn = make_insn_raw (gen_rtx_SET (VOIDmode, dst, in));
+  test_insn = make_insn_raw (gen_rtx_SET (dst, in));
   save_recog_data = recog_data;
   if (recog_memoized (test_insn) >= 0)
     {
       extract_insn (test_insn);
-      r = constrain_operands (1);
+      r = constrain_operands (1, get_enabled_alternatives (test_insn));
     }
   recog_data = save_recog_data;
   return r;
@@ -961,8 +970,8 @@ can_reload_into (rtx in, int regno, enum machine_mode mode)
 
 int
 push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
-            enum reg_class rclass, enum machine_mode inmode,
-            enum machine_mode outmode, int strict_low, int optional,
+            enum reg_class rclass, machine_mode inmode,
+            machine_mode outmode, int strict_low, int optional,
             int opnum, enum reload_type type)
 {
   int i;
@@ -1314,7 +1323,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
      is specified.  */
   if (this_insn_is_asm)
     {
-      enum machine_mode mode;
+      machine_mode mode;
       if (GET_MODE_SIZE (inmode) > GET_MODE_SIZE (outmode))
        mode = inmode;
       else
@@ -1603,7 +1612,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
     {
       rtx note;
       int regno;
-      enum machine_mode rel_mode = inmode;
+      machine_mode rel_mode = inmode;
 
       if (out && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (inmode))
        rel_mode = outmode;
@@ -1615,13 +1624,14 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
            && reg_mentioned_p (XEXP (note, 0), in)
            /* Check that a former pseudo is valid; see find_dummy_reload.  */
            && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
-               || (! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+               || (! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
                                    ORIGINAL_REGNO (XEXP (note, 0)))
                    && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1))
            && ! refers_to_regno_for_reload_p (regno,
                                               end_hard_regno (rel_mode,
                                                               regno),
                                               PATTERN (this_insn), inloc)
+           && ! find_reg_fusage (this_insn, USE, XEXP (note, 0))
            /* If this is also an output reload, IN cannot be used as
               the reload register if it is set in this insn unless IN
               is also OUT.  */
@@ -1678,7 +1688,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
    This is used in insn patterns that use match_dup.  */
 
 static void
-push_replacement (rtx *loc, int reloadnum, enum machine_mode mode)
+push_replacement (rtx *loc, int reloadnum, machine_mode mode)
 {
   if (replace_reloads)
     {
@@ -1939,7 +1949,7 @@ combine_reloads (void)
        && !fixed_regs[regno]
        /* Check that a former pseudo is valid; see find_dummy_reload.  */
        && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
-           || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+           || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
                               ORIGINAL_REGNO (XEXP (note, 0)))
                && hard_regno_nregs[regno][GET_MODE (XEXP (note, 0))] == 1)))
       {
@@ -1971,7 +1981,7 @@ combine_reloads (void)
 
 static rtx
 find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
-                  enum machine_mode inmode, enum machine_mode outmode,
+                  machine_mode inmode, machine_mode outmode,
                   reg_class_t rclass, int for_real, int earlyclobber)
 {
   rtx in = real_in;
@@ -2036,7 +2046,12 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
         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.  */
+        so it might not go through this reload.  
+
+         We also need to avoid using OUT if it, or part of it, is a
+         fixed register.  Modifying such registers, even transiently,
+         may have undefined effects on the machine, such as modifying
+         the stack pointer.  */
       saved_rtx = *inloc;
       *inloc = const0_rtx;
 
@@ -2049,7 +2064,8 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
 
          for (i = 0; i < nwords; i++)
            if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
-                                    regno + i))
+                                    regno + i)
+               || fixed_regs[regno + i])
              break;
 
          if (i == nwords)
@@ -2092,7 +2108,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
             can ignore the conflict).  We must never introduce writes
             to such hardregs, as they would clobber the other live
             pseudo.  See PR 20973.  */
-          || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+         || (!bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR_FOR_FN (cfun)),
                             ORIGINAL_REGNO (in))
              /* Similarly, only do this if we can be sure that the death
                 note is still valid.  global can assign some hardreg to
@@ -2197,7 +2213,7 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x)
    proper kind of hard reg.  */
 
 int
-strict_memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+strict_memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED,
                                    rtx addr, addr_space_t as)
 {
 #ifdef GO_IF_LEGITIMATE_ADDRESS
@@ -2322,7 +2338,7 @@ operands_match_p (rtx x, rtx y)
       return 0;
 
     case LABEL_REF:
-      return XEXP (x, 0) == XEXP (y, 0);
+      return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
     case SYMBOL_REF:
       return XSTR (x, 0) == XSTR (y, 0);
 
@@ -2611,7 +2627,7 @@ safe_from_earlyclobber (rtx op, rtx clobber)
    commutative operands, reg_equiv_address substitution, or whatever.  */
 
 int
-find_reloads (rtx insn, int replace, int ind_levels, int live_known,
+find_reloads (rtx_insn *insn, int replace, int ind_levels, int live_known,
              short *reload_reg_p)
 {
   int insn_code_number;
@@ -2662,7 +2678,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
   rtx body = PATTERN (insn);
   rtx set = single_set (insn);
   int goal_earlyclobber = 0, this_earlyclobber;
-  enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+  machine_mode operand_mode[MAX_RECOG_OPERANDS];
   int retval = 0;
 
   this_insn = insn;
@@ -2679,12 +2695,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
   if (JUMP_P (insn) || CALL_P (insn))
     no_output_reloads = 1;
 
-#ifdef HAVE_cc0
-  if (reg_referenced_p (cc0_rtx, PATTERN (insn)))
+  if (HAVE_cc0 && reg_referenced_p (cc0_rtx, PATTERN (insn)))
     no_input_reloads = 1;
-  if (reg_set_p (cc0_rtx, PATTERN (insn)))
+  if (HAVE_cc0 && reg_set_p (cc0_rtx, PATTERN (insn)))
     no_output_reloads = 1;
-#endif
 
 #ifdef SECONDARY_MEMORY_NEEDED
   /* The eliminated forms of any secondary memory locations are per-insn, so
@@ -2724,7 +2738,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
   this_insn_is_asm = insn_code_number < 0;
 
   memcpy (operand_mode, recog_data.operand_mode,
-         noperands * sizeof (enum machine_mode));
+         noperands * sizeof (machine_mode));
   memcpy (constraints, recog_data.constraints,
          noperands * sizeof (const char *));
 
@@ -2845,8 +2859,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
       if (*constraints[i] == 0)
        /* Ignore things like match_operator operands.  */
        ;
-      else if (constraints[i][0] == 'p'
-              || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
+      else if (insn_extra_address_constraint
+              (lookup_constraint (constraints[i])))
        {
          address_operand_reloaded[i]
            = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
@@ -2998,13 +3012,14 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
      First loop over alternatives.  */
 
+  alternative_mask enabled = get_enabled_alternatives (insn);
   for (this_alternative_number = 0;
        this_alternative_number < n_alternatives;
        this_alternative_number++)
     {
       int swapped;
 
-      if (!recog_data.alternative_enabled_p[this_alternative_number])
+      if (!TEST_BIT (enabled, this_alternative_number))
        {
          int i;
 
@@ -3038,9 +3053,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
          if (swapped)
            {
-             enum reg_class tclass;
-             int t;
-
              recog_data.operand[commutative] = substed_operand[commutative + 1];
              recog_data.operand[commutative + 1] = substed_operand[commutative];
              /* Swap the duplicates too.  */
@@ -3050,17 +3062,12 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                  *recog_data.dup_loc[i]
                    = recog_data.operand[(int) recog_data.dup_num[i]];
 
-             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;
-
-             t = address_reloaded[commutative];
-             address_reloaded[commutative] = address_reloaded[commutative + 1];
-             address_reloaded[commutative + 1] = t;
+             std::swap (preferred_class[commutative],
+                        preferred_class[commutative + 1]);
+             std::swap (pref_or_nothing[commutative],
+                        pref_or_nothing[commutative + 1]);
+             std::swap (address_reloaded[commutative],
+                        address_reloaded[commutative + 1]);
            }
 
          this_earlyclobber = 0;
@@ -3088,6 +3095,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                 operand.  */
              int constmemok = 0;
              int earlyclobber = 0;
+             enum constraint_num cn;
+             enum reg_class cl;
 
              /* If the predicate accepts a unary operator, it means that
                 we need to reload the operand, but do not do this for
@@ -3201,14 +3210,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                    c = '\0';
                    break;
 
-                 case '=':  case '+':  case '*':
-                   break;
-
-                 case '%':
-                   /* We only support one commutative marker, the first
-                      one.  We already set commutative above.  */
-                   break;
-
                  case '?':
                    reject += 6;
                    break;
@@ -3318,7 +3319,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                      for (j = 0; j < i; j++)
                        if (this_alternative_matches[j]
                            == this_alternative_matches[i])
-                         badop = 1;
+                         {
+                           badop = 1;
+                           break;
+                         }
                    break;
 
                  case 'p':
@@ -3414,49 +3418,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                    earlyclobber = 1, this_earlyclobber = 1;
                    break;
 
-                 case 'E':
-                 case 'F':
-                   if (CONST_DOUBLE_AS_FLOAT_P (operand)
-                       || (GET_CODE (operand) == CONST_VECTOR
-                           && (GET_MODE_CLASS (GET_MODE (operand))
-                               == MODE_VECTOR_FLOAT)))
-                     win = 1;
-                   break;
-
-                 case 'G':
-                 case 'H':
-                   if (CONST_DOUBLE_AS_FLOAT_P (operand)
-                       && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
-                     win = 1;
-                   break;
-
-                 case 's':
-                   if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
-                     break;
-                 case 'i':
-                   if (CONSTANT_P (operand)
-                       && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (operand)))
-                     win = 1;
-                   break;
-
-                 case 'n':
-                   if (CONST_INT_P (operand) || CONST_DOUBLE_AS_INT_P (operand))
-                     win = 1;
-                   break;
-
-                 case 'I':
-                 case 'J':
-                 case 'K':
-                 case 'L':
-                 case 'M':
-                 case 'N':
-                 case 'O':
-                 case 'P':
-                   if (CONST_INT_P (operand)
-                       && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
-                     win = 1;
-                   break;
-
                  case 'X':
                    force_reload = 0;
                    win = 1;
@@ -3477,74 +3438,81 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                            || (REGNO (operand) >= FIRST_PSEUDO_REGISTER
                                && reg_renumber[REGNO (operand)] < 0)))
                      win = 1;
-                   /* Drop through into 'r' case.  */
-
-                 case 'r':
-                   this_alternative[i]
-                     = reg_class_subunion[this_alternative[i]][(int) GENERAL_REGS];
+                   cl = GENERAL_REGS;
                    goto reg;
 
                  default:
-                   if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
+                   cn = lookup_constraint (p);
+                   switch (get_constraint_type (cn))
                      {
-#ifdef EXTRA_CONSTRAINT_STR
-                       if (EXTRA_MEMORY_CONSTRAINT (c, p))
-                         {
-                           if (force_reload)
-                             break;
-                           if (EXTRA_CONSTRAINT_STR (operand, c, p))
-                             win = 1;
-                           /* If the address was already reloaded,
-                              we win as well.  */
-                           else if (MEM_P (operand)
-                                    && address_reloaded[i] == 1)
-                             win = 1;
-                           /* Likewise if the address will be reloaded because
-                              reg_equiv_address is nonzero.  For reg_equiv_mem
-                              we have to check.  */
-                           else if (REG_P (operand)
-                                    && REGNO (operand) >= FIRST_PSEUDO_REGISTER
-                                    && reg_renumber[REGNO (operand)] < 0
-                                    && ((reg_equiv_mem (REGNO (operand)) != 0
-                                         && EXTRA_CONSTRAINT_STR (reg_equiv_mem (REGNO (operand)), c, p))
-                                        || (reg_equiv_address (REGNO (operand)) != 0)))
-                             win = 1;
-
-                           /* If we didn't already win, we can reload
-                              constants via force_const_mem, and other
-                              MEMs by reloading the address like for 'o'.  */
-                           if (CONST_POOL_OK_P (operand_mode[i], operand)
-                               || MEM_P (operand))
-                             badop = 0;
-                           constmemok = 1;
-                           offmemok = 1;
-                           break;
-                         }
-                       if (EXTRA_ADDRESS_CONSTRAINT (c, p))
-                         {
-                           if (EXTRA_CONSTRAINT_STR (operand, c, p))
-                             win = 1;
-
-                           /* If we didn't already win, we can reload
-                              the address into a base register.  */
-                           this_alternative[i]
-                             = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
-                                               ADDRESS, SCRATCH);
-                           badop = 0;
-                           break;
-                         }
+                     case CT_REGISTER:
+                       cl = reg_class_for_constraint (cn);
+                       if (cl != NO_REGS)
+                         goto reg;
+                       break;
 
-                       if (EXTRA_CONSTRAINT_STR (operand, c, p))
+                     case CT_CONST_INT:
+                       if (CONST_INT_P (operand)
+                           && (insn_const_int_ok_for_constraint
+                               (INTVAL (operand), cn)))
+                         win = true;
+                       break;
+
+                     case CT_MEMORY:
+                       if (force_reload)
+                         break;
+                       if (constraint_satisfied_p (operand, cn))
+                         win = 1;
+                       /* If the address was already reloaded,
+                          we win as well.  */
+                       else if (MEM_P (operand) && address_reloaded[i] == 1)
+                         win = 1;
+                       /* Likewise if the address will be reloaded because
+                          reg_equiv_address is nonzero.  For reg_equiv_mem
+                          we have to check.  */
+                       else if (REG_P (operand)
+                                && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+                                && reg_renumber[REGNO (operand)] < 0
+                                && ((reg_equiv_mem (REGNO (operand)) != 0
+                                     && (constraint_satisfied_p
+                                         (reg_equiv_mem (REGNO (operand)),
+                                          cn)))
+                                    || (reg_equiv_address (REGNO (operand))
+                                        != 0)))
+                         win = 1;
+
+                       /* If we didn't already win, we can reload
+                          constants via force_const_mem, and other
+                          MEMs by reloading the address like for 'o'.  */
+                       if (CONST_POOL_OK_P (operand_mode[i], operand)
+                           || MEM_P (operand))
+                         badop = 0;
+                       constmemok = 1;
+                       offmemok = 1;
+                       break;
+
+                     case CT_ADDRESS:
+                       if (constraint_satisfied_p (operand, cn))
+                         win = 1;
+
+                       /* If we didn't already win, we can reload
+                          the address into a base register.  */
+                       this_alternative[i]
+                         = base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+                                           ADDRESS, SCRATCH);
+                       badop = 0;
+                       break;
+
+                     case CT_FIXED_FORM:
+                       if (constraint_satisfied_p (operand, cn))
                          win = 1;
-#endif
                        break;
                      }
+                   break;
 
-                   this_alternative[i]
-                     = (reg_class_subunion
-                        [this_alternative[i]]
-                        [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
                  reg:
+                   this_alternative[i]
+                     = reg_class_subunion[this_alternative[i]][cl];
                    if (GET_MODE (operand) == BLKmode)
                      break;
                    winreg = 1;
@@ -3831,9 +3799,6 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
          if (swapped)
            {
-             enum reg_class tclass;
-             int t;
-
              /* If the commutative operands have been swapped, swap
                 them back in order to check the next alternative.  */
              recog_data.operand[commutative] = substed_operand[commutative];
@@ -3846,17 +3811,12 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                    = recog_data.operand[(int) recog_data.dup_num[i]];
 
              /* Unswap the operand related information as well.  */
-             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;
-
-             t = address_reloaded[commutative];
-             address_reloaded[commutative] = address_reloaded[commutative + 1];
-             address_reloaded[commutative + 1] = t;
+             std::swap (preferred_class[commutative],
+                        preferred_class[commutative + 1]);
+             std::swap (pref_or_nothing[commutative],
+                        pref_or_nothing[commutative + 1]);
+             std::swap (address_reloaded[commutative],
+                        address_reloaded[commutative + 1]);
            }
        }
     }
@@ -3905,18 +3865,18 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
   if (goal_alternative_swapped)
     {
-      rtx tem;
-
-      tem = substed_operand[commutative];
-      substed_operand[commutative] = substed_operand[commutative + 1];
-      substed_operand[commutative + 1] = tem;
-      tem = recog_data.operand[commutative];
-      recog_data.operand[commutative] = recog_data.operand[commutative + 1];
-      recog_data.operand[commutative + 1] = tem;
-      tem = *recog_data.operand_loc[commutative];
-      *recog_data.operand_loc[commutative]
-       = *recog_data.operand_loc[commutative + 1];
-      *recog_data.operand_loc[commutative + 1] = tem;
+      std::swap (substed_operand[commutative],
+                substed_operand[commutative + 1]);
+      std::swap (recog_data.operand[commutative],
+                recog_data.operand[commutative + 1]);
+      std::swap (*recog_data.operand_loc[commutative],
+                *recog_data.operand_loc[commutative + 1]);
+
+      for (i = 0; i < recog_data.n_dups; i++)
+       if (recog_data.dup_num[i] == commutative
+           || recog_data.dup_num[i] == commutative + 1)
+         *recog_data.dup_loc[i]
+           = recog_data.operand[(int) recog_data.dup_num[i]];
 
       for (i = 0; i < n_reloads; i++)
        {
@@ -3962,7 +3922,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
        rtx op = recog_data.operand[i];
        rtx subreg = NULL_RTX;
        rtx plus = NULL_RTX;
-       enum machine_mode mode = operand_mode[i];
+       machine_mode mode = operand_mode[i];
 
        /* Reloads of SUBREGs of CONSTANT RTXs are handled later in
           push_reload so we have to let them pass here.  */
@@ -4040,7 +4000,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
               use the default address mode as mode of the reload register,
               as would have been done by find_reloads_address.  */
            addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]);
-           enum machine_mode address_mode;
+           machine_mode address_mode;
 
            address_mode = get_address_mode (recog_data.operand[i]);
            operand_reloadnum[i]
@@ -4261,16 +4221,17 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
             this instruction.  */
          if (GET_CODE (substitution) == LABEL_REF
              && !find_reg_note (insn, REG_LABEL_OPERAND,
-                                XEXP (substitution, 0))
+                                LABEL_REF_LABEL (substitution))
              /* For a JUMP_P, if it was a branch target it must have
                 already been recorded as such.  */
              && (!JUMP_P (insn)
-                 || !label_is_jump_target_p (XEXP (substitution, 0),
+                 || !label_is_jump_target_p (LABEL_REF_LABEL (substitution),
                                              insn)))
            {
-             add_reg_note (insn, REG_LABEL_OPERAND, XEXP (substitution, 0));
-             if (LABEL_P (XEXP (substitution, 0)))
-               ++LABEL_NUSES (XEXP (substitution, 0));
+             add_reg_note (insn, REG_LABEL_OPERAND,
+                           LABEL_REF_LABEL (substitution));
+             if (LABEL_P (LABEL_REF_LABEL (substitution)))
+               ++LABEL_NUSES (LABEL_REF_LABEL (substitution));
            }
 
        }
@@ -4589,16 +4550,14 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
            rld[j].in = 0;
          }
 
-#ifdef HAVE_cc0
   /* If we made any reloads for addresses, see if they violate a
      "no input reloads" requirement for this insn.  But loads that we
      do after the insn (such as for output addresses) are fine.  */
-  if (no_input_reloads)
+  if (HAVE_cc0 && no_input_reloads)
     for (i = 0; i < n_reloads; i++)
       gcc_assert (rld[i].in == 0
                  || rld[i].when_needed == RELOAD_FOR_OUTADDR_ADDRESS
                  || rld[i].when_needed == RELOAD_FOR_OUTPUT_ADDRESS);
-#endif
 
   /* Compute reload_mode and reload_nregs.  */
   for (i = 0; i < n_reloads; i++)
@@ -4634,7 +4593,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
            for (nri = 1; nri < nr; nri ++)
              if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].rclass], regno + nri))
-               ok = 0;
+               {
+                 ok = 0;
+                 break;
+               }
 
            if (ok)
              rld[i].reg_rtx = dest;
@@ -4673,13 +4635,10 @@ alternative_allows_const_pool_ref (rtx mem ATTRIBUTE_UNUSED,
   for (; (c = *constraint) && c != ',' && c != '#';
        constraint += CONSTRAINT_LEN (c, constraint))
     {
-      if (c == TARGET_MEM_CONSTRAINT || c == 'o')
+      enum constraint_num cn = lookup_constraint (constraint);
+      if (insn_extra_memory_constraint (cn)
+         && (mem == NULL || constraint_satisfied_p (mem, cn)))
        return true;
-#ifdef EXTRA_CONSTRAINT_STR
-      if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
-         && (mem == NULL || EXTRA_CONSTRAINT_STR (mem, c, constraint)))
-       return true;
-#endif
     }
   return false;
 }
@@ -4708,7 +4667,7 @@ alternative_allows_const_pool_ref (rtx mem ATTRIBUTE_UNUSED,
 
 static rtx
 find_reloads_toplev (rtx x, int opnum, enum reload_type type,
-                    int ind_levels, int is_set_dest, rtx insn,
+                    int ind_levels, int is_set_dest, rtx_insn *insn,
                     int *address_reloaded)
 {
   RTX_CODE code = GET_CODE (x);
@@ -4804,31 +4763,19 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
        }
 
       /* 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 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.  */
+        attempt to convert the whole subreg to a (narrower or wider)
+        memory reference instead.  If this succeeds, we're done --
+        otherwise fall through to check whether the inner reg still
+        needs address reloads anyway.  */
 
       if (regno >= FIRST_PSEUDO_REGISTER
-#ifdef LOAD_EXTEND_OP
-         && !paradoxical_subreg_p (x)
-#endif
-         && (reg_equiv_address (regno) != 0
-             || (reg_equiv_mem (regno) != 0
-                 && (! strict_memory_address_addr_space_p
-                     (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
-                      MEM_ADDR_SPACE (reg_equiv_mem (regno)))
-                     || ! offsettable_memref_p (reg_equiv_mem (regno))
-                     || num_not_at_initial_offset))))
-       x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels,
-                                          insn, address_reloaded);
+         && reg_equiv_memory_loc (regno) != 0)
+       {
+         tem = find_reloads_subreg_address (x, opnum, type, ind_levels,
+                                            insn, address_reloaded);
+         if (tem)
+           return tem;
+       }
     }
 
   for (copied = 0, i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@@ -4886,7 +4833,7 @@ make_memloc (rtx ad, int regno)
    by PART into a register.  */
 
 static int
-maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad,
+maybe_memory_address_addr_space_p (machine_mode mode, rtx ad,
                                   addr_space_t as, rtx *part)
 {
   int retv;
@@ -4926,9 +4873,9 @@ maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad,
    to a hard register, and frame pointer elimination.  */
 
 static int
-find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
+find_reloads_address (machine_mode mode, rtx *memrefloc, rtx ad,
                      rtx *loc, int opnum, enum reload_type type,
-                     int ind_levels, rtx insn)
+                     int ind_levels, rtx_insn *insn)
 {
   addr_space_t as = memrefloc? MEM_ADDR_SPACE (*memrefloc)
                             : ADDR_SPACE_GENERIC;
@@ -5232,9 +5179,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
 #if !HARD_FRAME_POINTER_IS_FRAME_POINTER
           || operand == hard_frame_pointer_rtx
 #endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-          || operand == arg_pointer_rtx
-#endif
+          || (FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+              && operand == arg_pointer_rtx)
           || operand == stack_pointer_rtx)
          && ! maybe_memory_address_addr_space_p
                (mode, ad, as, &XEXP (XEXP (ad, 0), 1 - op_index)))
@@ -5298,7 +5244,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
      into a register.  */
   if (CONSTANT_P (ad) && ! strict_memory_address_addr_space_p (mode, ad, as))
     {
-      enum machine_mode address_mode = GET_MODE (ad);
+      machine_mode address_mode = GET_MODE (ad);
       if (address_mode == VOIDmode)
        address_mode = targetm.addr_space.address_mode (as);
 
@@ -5330,7 +5276,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
    front of it for pseudos that we have to replace with stack slots.  */
 
 static rtx
-subst_reg_equivs (rtx ad, rtx insn)
+subst_reg_equivs (rtx ad, rtx_insn *insn)
 {
   RTX_CODE code = GET_CODE (ad);
   int i;
@@ -5399,7 +5345,7 @@ subst_reg_equivs (rtx ad, rtx insn)
    This routine assumes both inputs are already in canonical form.  */
 
 rtx
-form_sum (enum machine_mode mode, rtx x, rtx y)
+form_sum (machine_mode mode, rtx x, rtx y)
 {
   rtx tem;
 
@@ -5506,7 +5452,7 @@ subst_indexed_address (rtx addr)
    RELOADNUM is the reload number.  */
 
 static void
-update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
+update_auto_inc_notes (rtx_insn *insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
                       int reloadnum ATTRIBUTE_UNUSED)
 {
 #ifdef AUTO_INC_DEC
@@ -5550,11 +5496,11 @@ update_auto_inc_notes (rtx insn ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED,
    handles those cases gracefully.  */
 
 static int
-find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
+find_reloads_address_1 (machine_mode mode, addr_space_t as,
                        rtx x, int context,
                        enum rtx_code outer_code, enum rtx_code index_code,
                        rtx *loc, int opnum, enum reload_type type,
-                       int ind_levels, rtx insn)
+                       int ind_levels, rtx_insn *insn)
 {
 #define REG_OK_FOR_CONTEXT(CONTEXT, REGNO, MODE, AS, OUTER, INDEX)     \
   ((CONTEXT) == 0                                                      \
@@ -5563,6 +5509,7 @@ find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
 
   enum reg_class context_reg_class;
   RTX_CODE code = GET_CODE (x);
+  bool reloaded_inner_of_autoinc = false;
 
   if (context == 1)
     context_reg_class = INDEX_REG_CLASS;
@@ -5850,6 +5797,7 @@ find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
                  find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
                                        &XEXP (tem, 0), opnum, type,
                                        ind_levels, insn);
+                 reloaded_inner_of_autoinc = true;
                  if (!rtx_equal_p (tem, orig))
                    push_reg_equiv_alt_mem (regno, tem);
                  /* Put this inside a new increment-expression.  */
@@ -5893,12 +5841,15 @@ find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
              enum insn_code icode = optab_handler (add_optab, GET_MODE (x));
              if (insn && NONJUMP_INSN_P (insn) && equiv
                  && memory_operand (equiv, GET_MODE (equiv))
-#ifdef HAVE_cc0
+#if HAVE_cc0
                  && ! sets_cc0_p (PATTERN (insn))
 #endif
                  && ! (icode != CODE_FOR_nothing
                        && insn_operand_matches (icode, 0, equiv)
-                       && insn_operand_matches (icode, 1, equiv)))
+                       && insn_operand_matches (icode, 1, equiv))
+                 /* Using RELOAD_OTHER means we emit this and the reload we
+                    made earlier in the wrong order.  */
+                 && !reloaded_inner_of_autoinc)
                {
                  /* We use the original pseudo for loc, so that
                     emit_reload_insns() knows which pseudo this
@@ -6064,12 +6015,31 @@ find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
              if (ira_reg_class_max_nregs [rclass][GET_MODE (SUBREG_REG (x))]
                  > reg_class_size[(int) rclass])
                {
-                 x = find_reloads_subreg_address (x, 0, opnum,
-                                                  ADDR_TYPE (type),
-                                                  ind_levels, insn, NULL);
-                 push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
-                              GET_MODE (x), VOIDmode, 0, 0, opnum, type);
-                 return 1;
+                 /* If the inner register will be replaced by a memory
+                    reference, we can do this only if we can replace the
+                    whole subreg by a (narrower) memory reference.  If
+                    this is not possible, fall through and reload just
+                    the inner register (including address reloads).  */
+                 if (reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0)
+                   {
+                     rtx tem = find_reloads_subreg_address (x, opnum,
+                                                            ADDR_TYPE (type),
+                                                            ind_levels, insn,
+                                                            NULL);
+                     if (tem)
+                       {
+                         push_reload (tem, NULL_RTX, loc, (rtx*) 0, rclass,
+                                      GET_MODE (tem), VOIDmode, 0, 0,
+                                      opnum, type);
+                         return 1;
+                       }
+                   }
+                 else
+                   {
+                     push_reload (x, NULL_RTX, loc, (rtx*) 0, rclass,
+                                  GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+                     return 1;
+                   }
                }
            }
        }
@@ -6115,7 +6085,7 @@ find_reloads_address_1 (enum machine_mode mode, addr_space_t as,
 
 static void
 find_reloads_address_part (rtx x, rtx *loc, enum reg_class rclass,
-                          enum machine_mode mode, int opnum,
+                          machine_mode mode, int opnum,
                           enum reload_type type, int ind_levels)
 {
   if (CONSTANT_P (x)
@@ -6146,17 +6116,12 @@ find_reloads_address_part (rtx x, rtx *loc, enum reg_class rclass,
 }
 \f
 /* X, a subreg of a pseudo, is a part of an address that needs to be
-   reloaded.
-
-   If the pseudo is equivalent to a memory location that cannot be directly
-   addressed, make the necessary address reloads.
+   reloaded, and the pseusdo is equivalent to a memory location.
 
-   If address reloads have been necessary, or if the address is changed
-   by register elimination, return the rtx of the memory location;
-   otherwise, return X.
-
-   If FORCE_REPLACE is nonzero, unconditionally replace the subreg with the
-   memory location.
+   Attempt to replace the whole subreg by a (possibly narrower or wider)
+   memory reference.  If this is possible, return this new memory
+   reference, and push all required address reloads.  Otherwise,
+   return NULL.
 
    OPNUM and TYPE identify the purpose of the reload.
 
@@ -6168,131 +6133,107 @@ find_reloads_address_part (rtx x, rtx *loc, enum reg_class rclass,
    stack slots.  */
 
 static rtx
-find_reloads_subreg_address (rtx x, int force_replace, int opnum,
-                            enum reload_type type, int ind_levels, rtx insn,
+find_reloads_subreg_address (rtx x, int opnum, enum reload_type type,
+                            int ind_levels, rtx_insn *insn,
                             int *address_reloaded)
 {
+  machine_mode outer_mode = GET_MODE (x);
+  machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
   int regno = REGNO (SUBREG_REG (x));
   int reloaded = 0;
+  rtx tem, orig;
+  int offset;
 
-  if (reg_equiv_memory_loc (regno))
-    {
-      /* If the address is not directly addressable, or if the address is not
-        offsettable, then it must be replaced.  */
-      if (! force_replace
-         && (reg_equiv_address (regno)
-             || ! offsettable_memref_p (reg_equiv_mem (regno))))
-       force_replace = 1;
-
-      if (force_replace || num_not_at_initial_offset)
-       {
-         rtx tem = make_memloc (SUBREG_REG (x), regno);
+  gcc_assert (reg_equiv_memory_loc (regno) != 0);
 
-         /* If the address changes because of register elimination, then
-            it must be replaced.  */
-         if (force_replace
-             || ! rtx_equal_p (tem, reg_equiv_mem (regno)))
-           {
-             unsigned outer_size = GET_MODE_SIZE (GET_MODE (x));
-             unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)));
-             int offset;
-             rtx orig = tem;
-
-             /* For big-endian paradoxical subregs, SUBREG_BYTE does not
-                hold the correct (negative) byte offset.  */
-             if (BYTES_BIG_ENDIAN && outer_size > inner_size)
-               offset = inner_size - outer_size;
-             else
-               offset = SUBREG_BYTE (x);
-
-             XEXP (tem, 0) = plus_constant (GET_MODE (XEXP (tem, 0)),
-                                            XEXP (tem, 0), offset);
-             PUT_MODE (tem, GET_MODE (x));
-             if (MEM_OFFSET_KNOWN_P (tem))
-               set_mem_offset (tem, MEM_OFFSET (tem) + offset);
-             if (MEM_SIZE_KNOWN_P (tem)
-                 && MEM_SIZE (tem) != (HOST_WIDE_INT) outer_size)
-               set_mem_size (tem, outer_size);
-
-             /* 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)
-               {
-                 rtx base;
+  /* We cannot replace the subreg with a modified memory reference if:
 
-                 base = XEXP (tem, 0);
-                 if (GET_CODE (base) == PLUS)
-                   {
-                     if (CONST_INT_P (XEXP (base, 1))
-                         && INTVAL (XEXP (base, 1)) % outer_size != 0)
-                       return x;
-                     base = XEXP (base, 0);
-                   }
-                 if (!REG_P (base)
-                     || (REGNO_POINTER_ALIGN (REGNO (base))
-                         < outer_size * BITS_PER_UNIT))
-                   return x;
-               }
+     - we have a paradoxical subreg that implicitly acts as a zero or
+       sign extension operation due to LOAD_EXTEND_OP;
 
-             reloaded = find_reloads_address (GET_MODE (tem), &tem,
-                                              XEXP (tem, 0), &XEXP (tem, 0),
-                                              opnum, type, ind_levels, insn);
-             /* ??? Do we need to handle nonzero offsets somehow?  */
-             if (!offset && !rtx_equal_p (tem, orig))
-               push_reg_equiv_alt_mem (regno, tem);
-
-             /* For some processors an address may be valid in the
-                original mode but not in a smaller mode.  For
-                example, ARM accepts a scaled index register in
-                SImode but not in HImode.  Note that this is only
-                a problem if the address in reg_equiv_mem is already
-                invalid in the new mode; other cases would be fixed
-                by find_reloads_address as usual.
-
-                ??? We attempt to handle such cases here by doing an
-                additional reload of the full address after the
-                usual processing by find_reloads_address.  Note that
-                this may not work in the general case, but it seems
-                to cover the cases where this situation currently
-                occurs.  A more general fix might be to reload the
-                *value* instead of the address, but this would not
-                be expected by the callers of this routine as-is.
-
-                If find_reloads_address already completed replaced
-                the address, there is nothing further to do.  */
-             if (reloaded == 0
-                 && reg_equiv_mem (regno) != 0
-                 && !strict_memory_address_addr_space_p
-                       (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
-                        MEM_ADDR_SPACE (reg_equiv_mem (regno))))
-               {
-                 push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
-                              base_reg_class (GET_MODE (tem),
-                                              MEM_ADDR_SPACE (tem),
-                                              MEM, SCRATCH),
-                              GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
-                              opnum, type);
-                 reloaded = 1;
-               }
-             /* If this is not a toplevel operand, find_reloads doesn't see
-                this substitution.  We have to emit a USE of the pseudo so
-                that delete_output_reload can see it.  */
-             if (replace_reloads && recog_data.operand[opnum] != x)
-               /* We mark the USE with QImode so that we recognize it
-                  as one that can be safely deleted at the end of
-                  reload.  */
-               PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode,
-                                                        SUBREG_REG (x)),
-                                           insn), QImode);
-             x = tem;
-           }
-       }
+     - we have a subreg that is implicitly supposed to act on the full
+       register due to WORD_REGISTER_OPERATIONS (see also eliminate_regs);
+
+     - the address of the equivalent memory location is mode-dependent;  or
+
+     - we have a paradoxical subreg and the resulting memory is not
+       sufficiently aligned to allow access in the wider mode.
+
+    In addition, we choose not to perform the replacement for *any*
+    paradoxical subreg, even if it were possible in principle.  This
+    is to avoid generating wider memory references than necessary.
+
+    This corresponds to how previous versions of reload used to handle
+    paradoxical subregs where no address reload was required.  */
+
+  if (paradoxical_subreg_p (x))
+    return NULL;
+
+#ifdef WORD_REGISTER_OPERATIONS
+  if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode)
+      && ((GET_MODE_SIZE (outer_mode) - 1) / UNITS_PER_WORD
+          == (GET_MODE_SIZE (inner_mode) - 1) / UNITS_PER_WORD))
+    return NULL;
+#endif
+
+  /* Since we don't attempt to handle paradoxical subregs, we can just
+     call into simplify_subreg, which will handle all remaining checks
+     for us.  */
+  orig = make_memloc (SUBREG_REG (x), regno);
+  offset = SUBREG_BYTE (x);
+  tem = simplify_subreg (outer_mode, orig, inner_mode, offset);
+  if (!tem || !MEM_P (tem))
+    return NULL;
+
+  /* Now push all required address reloads, if any.  */
+  reloaded = find_reloads_address (GET_MODE (tem), &tem,
+                                  XEXP (tem, 0), &XEXP (tem, 0),
+                                  opnum, type, ind_levels, insn);
+  /* ??? Do we need to handle nonzero offsets somehow?  */
+  if (!offset && !rtx_equal_p (tem, orig))
+    push_reg_equiv_alt_mem (regno, tem);
+
+  /* For some processors an address may be valid in the original mode but
+     not in a smaller mode.  For example, ARM accepts a scaled index register
+     in SImode but not in HImode.  Note that this is only a problem if the
+     address in reg_equiv_mem is already invalid in the new mode; other
+     cases would be fixed by find_reloads_address as usual.
+
+     ??? We attempt to handle such cases here by doing an additional reload
+     of the full address after the usual processing by find_reloads_address.
+     Note that this may not work in the general case, but it seems to cover
+     the cases where this situation currently occurs.  A more general fix
+     might be to reload the *value* instead of the address, but this would
+     not be expected by the callers of this routine as-is.
+
+     If find_reloads_address already completed replaced the address, there
+     is nothing further to do.  */
+  if (reloaded == 0
+      && reg_equiv_mem (regno) != 0
+      && !strict_memory_address_addr_space_p
+               (GET_MODE (x), XEXP (reg_equiv_mem (regno), 0),
+                MEM_ADDR_SPACE (reg_equiv_mem (regno))))
+    {
+      push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
+                  base_reg_class (GET_MODE (tem), MEM_ADDR_SPACE (tem),
+                                  MEM, SCRATCH),
+                  GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0, opnum, type);
+      reloaded = 1;
     }
+
+  /* If this is not a toplevel operand, find_reloads doesn't see this
+     substitution.  We have to emit a USE of the pseudo so that
+     delete_output_reload can see it.  */
+  if (replace_reloads && recog_data.operand[opnum] != x)
+    /* We mark the USE with QImode so that we recognize it as one that
+       can be safely deleted at the end of reload.  */
+    PUT_MODE (emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn),
+             QImode);
+
   if (address_reloaded)
     *address_reloaded = reloaded;
 
-  return x;
+  return tem;
 }
 \f
 /* Substitute into the current INSN the registers into which we have reloaded
@@ -6303,7 +6244,7 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
    Return the rtx that X translates into; usually X, but modified.  */
 
 void
-subst_reloads (rtx insn)
+subst_reloads (rtx_insn *insn)
 {
   int i;
 
@@ -6330,14 +6271,14 @@ subst_reloads (rtx insn)
          for (check_regno = 0; check_regno < max_regno; check_regno++)
            {
 #define CHECK_MODF(ARRAY)                                              \
-             gcc_assert (!VEC_index (reg_equivs_t, reg_equivs, check_regno).ARRAY              \
+             gcc_assert (!(*reg_equivs)[check_regno].ARRAY             \
                          || !loc_mentioned_in_p (r->where,             \
-                                                 VEC_index (reg_equivs_t, reg_equivs, check_regno).ARRAY))
+                                                 (*reg_equivs)[check_regno].ARRAY))
 
-             CHECK_MODF (equiv_constant);
-             CHECK_MODF (equiv_memory_loc);
-             CHECK_MODF (equiv_address);
-             CHECK_MODF (equiv_mem);
+             CHECK_MODF (constant);
+             CHECK_MODF (memory_loc);
+             CHECK_MODF (address);
+             CHECK_MODF (mem);
 #undef CHECK_MODF
            }
 #endif /* DEBUG_RELOAD */
@@ -6643,7 +6584,7 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
          return 0;
        }
 
-      endregno = END_HARD_REGNO (x);
+      endregno = END_REGNO (x);
 
       return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
     }
@@ -6730,11 +6671,12 @@ refers_to_mem_for_reload_p (rtx x)
    as if it were a constant except that sp is required to be unchanging.  */
 
 rtx
-find_equiv_reg (rtx goal, rtx insn, enum reg_class rclass, int other,
-               short *reload_reg_p, int goalreg, enum machine_mode mode)
+find_equiv_reg (rtx goal, rtx_insn *insn, enum reg_class rclass, int other,
+               short *reload_reg_p, int goalreg, machine_mode mode)
 {
-  rtx p = insn;
-  rtx goaltry, valtry, value, where;
+  rtx_insn *p = insn;
+  rtx goaltry, valtry, value;
+  rtx_insn *where;
   rtx pat;
   int regno = -1;
   int valueno;
@@ -7266,7 +7208,7 @@ reg_inc_found_and_valid_p (unsigned int regno, unsigned int endregno,
    REG_INC.  REGNO must refer to a hard register.  */
 
 int
-regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode,
+regno_clobbered_p (unsigned int regno, rtx_insn *insn, machine_mode mode,
                   int sets)
 {
   unsigned int nregs, endregno;
@@ -7316,7 +7258,7 @@ regno_clobbered_p (unsigned int regno, rtx insn, enum machine_mode mode,
 
 /* Find the low part, with mode MODE, of a hard regno RELOADREG.  */
 rtx
-reload_adjust_reg_for_mode (rtx reloadreg, enum machine_mode mode)
+reload_adjust_reg_for_mode (rtx reloadreg, machine_mode mode)
 {
   int regno;