OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index ba5d075..5a82d99 100644 (file)
@@ -1,6 +1,6 @@
 /* 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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -88,6 +88,8 @@ a register with any other reload.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -242,7 +244,7 @@ static int push_secondary_reload PARAMS ((int, rtx, int, int, enum reg_class,
 #endif
 static enum reg_class find_valid_class PARAMS ((enum machine_mode, int,
                                                unsigned int));
-static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode));
+static int reload_inner_reg_of_subreg PARAMS ((rtx, enum machine_mode, int));
 static void push_replacement   PARAMS ((rtx *, int, enum machine_mode));
 static void dup_replacements   PARAMS ((rtx *, rtx *));
 static void combine_reloads    PARAMS ((void));
@@ -258,6 +260,7 @@ static int alternative_allows_memconst PARAMS ((const char *, int));
 static rtx find_reloads_toplev PARAMS ((rtx, int, enum reload_type, int,
                                         int, rtx, int *));
 static rtx make_memloc         PARAMS ((rtx, int));
+static int maybe_memory_address_p PARAMS ((enum machine_mode, rtx, rtx *));
 static int find_reloads_address        PARAMS ((enum machine_mode, rtx *, rtx, rtx *,
                                       int, enum reload_type, int, rtx));
 static rtx subst_reg_equivs    PARAMS ((rtx, rtx));
@@ -379,11 +382,13 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
        insn_class = ALL_REGS;
       else
        {
-         char insn_letter
-           = insn_data[(int) icode].operand[!in_p].constraint[in_p];
+         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_LETTER ((unsigned char) insn_letter));
+              : REG_CLASS_FROM_CONSTRAINT ((unsigned char) insn_letter,
+                                           insn_constraint));
 
           if (insn_class == NO_REGS)
            abort ();
@@ -401,11 +406,14 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
        mode = insn_data[(int) icode].operand[2].mode;
       else
        {
-         char t_letter = insn_data[(int) icode].operand[2].constraint[2];
+         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_LETTER ((unsigned char) t_letter));
+                    : REG_CLASS_FROM_CONSTRAINT ((unsigned char) t_letter,
+                                                 t_constraint));
          t_icode = icode;
          icode = CODE_FOR_nothing;
        }
@@ -670,13 +678,13 @@ static enum reg_class
 find_valid_class (m1, n, dest_regno)
      enum machine_mode m1 ATTRIBUTE_UNUSED;
      int n;
-     unsigned int dest_regno;
+     unsigned int dest_regno ATTRIBUTE_UNUSED;
 {
   int best_cost = -1;
   int class;
   int regno;
   enum reg_class best_class = NO_REGS;
-  enum reg_class dest_class = REGNO_REG_CLASS (dest_regno);
+  enum reg_class dest_class ATTRIBUTE_UNUSED = REGNO_REG_CLASS (dest_regno);
   unsigned int best_size = 0;
   int cost;
 
@@ -795,9 +803,10 @@ find_reusable_reload (p_in, out, class, type, opnum, dont_share)
    SUBREG_REG expression.  */
 
 static int
-reload_inner_reg_of_subreg (x, mode)
+reload_inner_reg_of_subreg (x, mode, output)
      rtx x;
      enum machine_mode mode;
+     int output;
 {
   rtx inner;
 
@@ -825,6 +834,7 @@ reload_inner_reg_of_subreg (x, mode)
      word and the number of regs for INNER is not the same as the
      number of words in INNER, then INNER will need reloading.  */
   return (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+         && output
          && GET_MODE_SIZE (GET_MODE (inner)) > UNITS_PER_WORD
          && ((GET_MODE_SIZE (GET_MODE (inner)) / UNITS_PER_WORD)
              != (int) HARD_REGNO_NREGS (REGNO (inner), GET_MODE (inner))));
@@ -965,9 +975,8 @@ push_reload (in, out, inloc, outloc, class,
 
   if (in != 0 && GET_CODE (in) == SUBREG
       && (subreg_lowpart_p (in) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
-      && (class != CLASS_CANNOT_CHANGE_MODE
-         || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+      && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, class)
 #endif
       && (CONSTANT_P (SUBREG_REG (in))
          || GET_CODE (SUBREG_REG (in)) == PLUS
@@ -1014,14 +1023,11 @@ push_reload (in, out, inloc, outloc, class,
                                                SUBREG_REG (in))
                  == NO_REGS))
 #endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
          || (GET_CODE (SUBREG_REG (in)) == REG
              && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
-             && (TEST_HARD_REG_BIT
-                 (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-                  REGNO (SUBREG_REG (in))))
-             && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)),
-                                            inmode))
+             && REG_CANNOT_CHANGE_MODE_P
+             (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode))
 #endif
          ))
     {
@@ -1048,7 +1054,7 @@ push_reload (in, out, inloc, outloc, class,
   /* Similar issue for (SUBREG constant ...) if it was not handled by the
      code above.  This can happen if SUBREG_BYTE != 0.  */
 
-  if (in != 0 && reload_inner_reg_of_subreg (in, inmode))
+  if (in != 0 && reload_inner_reg_of_subreg (in, inmode, 0))
     {
       enum reg_class in_class = class;
 
@@ -1079,10 +1085,8 @@ push_reload (in, out, inloc, outloc, class,
      and in that case the constraint should label it input-output.)  */
   if (out != 0 && GET_CODE (out) == SUBREG
       && (subreg_lowpart_p (out) || strict_low)
-#ifdef CLASS_CANNOT_CHANGE_MODE
-      && (class != CLASS_CANNOT_CHANGE_MODE
-         || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
-                                          outmode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+      && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, class)
 #endif
       && (CONSTANT_P (SUBREG_REG (out))
          || strict_low
@@ -1116,14 +1120,12 @@ push_reload (in, out, inloc, outloc, class,
                                                 SUBREG_REG (out))
                  == NO_REGS))
 #endif
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
          || (GET_CODE (SUBREG_REG (out)) == REG
              && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
-             && (TEST_HARD_REG_BIT
-                 (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-                  REGNO (SUBREG_REG (out))))
-             && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)),
-                                            outmode))
+             && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)),
+                                          GET_MODE (SUBREG_REG (out)), 
+                                          outmode))
 #endif
          ))
     {
@@ -1145,7 +1147,7 @@ push_reload (in, out, inloc, outloc, class,
      However, we must reload the inner reg *as well as* the subreg in
      that case.  In this case, the inner reg is an in-out reload.  */
 
-  if (out != 0 && reload_inner_reg_of_subreg (out, outmode))
+  if (out != 0 && reload_inner_reg_of_subreg (out, outmode, 1))
     {
       /* This relies on the fact that emit_reload_insns outputs the
         instructions for output reloads of type RELOAD_OTHER in reverse
@@ -1285,9 +1287,9 @@ push_reload (in, out, inloc, outloc, class,
 
 #ifdef SECONDARY_MEMORY_NEEDED
       /* If a memory location is needed for the copy, make one.  */
-      if (in != 0 && GET_CODE (in) == REG
-         && REGNO (in) < FIRST_PSEUDO_REGISTER
-         && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
+      if (in != 0 && (GET_CODE (in) == REG || GET_CODE (in) == SUBREG)
+         && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
+         && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
                                      class, inmode))
        get_secondary_mem (in, inmode, opnum, type);
 #endif
@@ -1315,9 +1317,10 @@ push_reload (in, out, inloc, outloc, class,
       n_reloads++;
 
 #ifdef SECONDARY_MEMORY_NEEDED
-      if (out != 0 && GET_CODE (out) == REG
-         && REGNO (out) < FIRST_PSEUDO_REGISTER
-         && SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)),
+      if (out != 0 && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG)
+         && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
+         && SECONDARY_MEMORY_NEEDED (class,
+                                     REGNO_REG_CLASS (reg_or_subregno (out)),
                                      outmode))
        get_secondary_mem (out, outmode, opnum, type);
 #endif
@@ -1732,7 +1735,8 @@ combine_reloads ()
                && ! (GET_CODE (rld[i].in) == REG
                      && reg_overlap_mentioned_for_reload_p (rld[i].in,
                                                             rld[output_reload].out))))
-       && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode)
+       && ! reload_inner_reg_of_subreg (rld[i].in, rld[i].inmode,
+                                        rld[i].when_needed != RELOAD_FOR_INPUT)
        && (reg_class_size[(int) rld[i].class]
            || SMALL_REGISTER_CLASSES)
        /* We will allow making things slightly worse by combining an
@@ -2133,23 +2137,23 @@ operands_match_p (x, y)
         (reg:SI 1) will be considered the same register.  */
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
          && i < FIRST_PSEUDO_REGISTER)
-       i += (GET_MODE_SIZE (GET_MODE (x)) / UNITS_PER_WORD) - 1;
+       i += HARD_REGNO_NREGS (i, GET_MODE (x)) - 1;
       if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (y)) > UNITS_PER_WORD
          && j < FIRST_PSEUDO_REGISTER)
-       j += (GET_MODE_SIZE (GET_MODE (y)) / UNITS_PER_WORD) - 1;
+       j += HARD_REGNO_NREGS (j, GET_MODE (y)) - 1;
 
       return i == j;
     }
   /* If two operands must match, because they are really a single
      operand of an assembler insn, then two postincrements are invalid
      because the assembler insn would increment only once.
-     On the other hand, an postincrement matches ordinary indexing
+     On the other hand, a postincrement matches ordinary indexing
      if the postincrement is the output operand.  */
   if (code == POST_DEC || code == POST_INC || code == POST_MODIFY)
     return operands_match_p (XEXP (x, 0), y);
   /* Two preincrements are invalid
      because the assembler insn would increment only once.
-     On the other hand, an preincrement matches ordinary indexing
+     On the other hand, a preincrement matches ordinary indexing
      if the preincrement is the input operand.
      In this case, return 2, since some callers need to do special
      things when this happens.  */
@@ -2472,6 +2476,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   char pref_or_nothing[MAX_RECOG_OPERANDS];
   /* Nonzero for a MEM operand whose entire address needs a reload.  */
   int address_reloaded[MAX_RECOG_OPERANDS];
+  /* Nonzero for an address operand that needs to be completely reloaded.  */
+  int address_operand_reloaded[MAX_RECOG_OPERANDS];
   /* Value of enum reload_type to use for operand.  */
   enum reload_type operand_type[MAX_RECOG_OPERANDS];
   /* Value of enum reload_type to use within address of operand.  */
@@ -2585,8 +2591,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       /* Scan this operand's constraint to see if it is an output operand,
         an in-out operand, is commutative, or should match another.  */
 
-      while ((c = *p++))
+      while ((c = *p))
        {
+         p += CONSTRAINT_LEN (c, p);
          if (c == '=')
            modified[i] = RELOAD_WRITE;
          else if (c == '+')
@@ -2650,6 +2657,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       RTX_CODE code = GET_CODE (recog_data.operand[i]);
 
       address_reloaded[i] = 0;
+      address_operand_reloaded[i] = 0;
       operand_type[i] = (modified[i] == RELOAD_READ ? RELOAD_FOR_INPUT
                         : modified[i] == RELOAD_WRITE ? RELOAD_FOR_OUTPUT
                         : RELOAD_OTHER);
@@ -2662,12 +2670,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        /* Ignore things like match_operator operands.  */
        ;
       else if (constraints[i][0] == 'p'
-              || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0]))
+              || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))
        {
-         find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
-                               recog_data.operand[i],
-                               recog_data.operand_loc[i],
-                               i, operand_type[i], ind_levels, insn);
+         address_operand_reloaded[i]
+           = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
+                                   recog_data.operand[i],
+                                   recog_data.operand_loc[i],
+                                   i, operand_type[i], ind_levels, insn);
 
          /* If we now have a simple operand where we used to have a
             PLUS or MULT, re-recognize and try again.  */
@@ -2684,6 +2693,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
 
          recog_data.operand[i] = *recog_data.operand_loc[i];
          substed_operand[i] = recog_data.operand[i];
+
+         /* Address operands are reloaded in their existing mode,
+            no matter what is specified in the machine description.  */
+         operand_mode[i] = GET_MODE (recog_data.operand[i]);
        }
       else if (code == MEM)
        {
@@ -2827,6 +2840,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       for (i = 0; i < noperands; i++)
        {
          char *p = constraints[i];
+         char *end;
+         int len;
          int win = 0;
          int did_match = 0;
          /* 0 => this operand can be reloaded somehow for this alternative.  */
@@ -2834,6 +2849,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          /* 0 => this operand can be reloaded if the alternative allows regs.  */
          int winreg = 0;
          int c;
+         int m;
          rtx operand = recog_data.operand[i];
          int offset = 0;
          /* Nonzero means this is a MEM that must be reloaded into a reg
@@ -2864,6 +2880,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              if (GET_CODE (SUBREG_REG (operand)) == REG
                  && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
                {
+                 if (!subreg_offset_representable_p
+                       (REGNO (SUBREG_REG (operand)),
+                        GET_MODE (SUBREG_REG (operand)),
+                        SUBREG_BYTE (operand),
+                        GET_MODE (operand)))
+                    force_reload = 1;
                  offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
                                                 GET_MODE (SUBREG_REG (operand)),
                                                 SUBREG_BYTE (operand),
@@ -2896,7 +2918,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                     by forcing the reload.
 
                     ??? When is it right at this stage to have a subreg
-                    of a mem that is _not_ to be handled specialy?  IMO
+                    of a mem that is _not_ to be handled specially?  IMO
                     those should have been reduced to just a mem.  */
                  || ((GET_CODE (operand) == MEM
                       || (GET_CODE (operand)== REG
@@ -2919,26 +2941,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                          )
 #endif
                      )
-                 /* This following hunk of code should no longer be
-                    needed at all with SUBREG_BYTE.  If you need this
-                    code back, please explain to me why so I can
-                    fix the real problem.  -DaveM */
-#if 0
-                 /* Subreg of a hard reg which can't handle the subreg's mode
-                    or which would handle that mode in the wrong number of
-                    registers for subregging to work.  */
-                 || (GET_CODE (operand) == REG
-                     && REGNO (operand) < FIRST_PSEUDO_REGISTER
-                     && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
-                          && (GET_MODE_SIZE (GET_MODE (operand))
-                              > UNITS_PER_WORD)
-                          && ((GET_MODE_SIZE (GET_MODE (operand))
-                               / UNITS_PER_WORD)
-                              != HARD_REGNO_NREGS (REGNO (operand),
-                                                   GET_MODE (operand))))
-                         || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
-                                                  operand_mode[i])))
-#endif
                  )
                force_reload = 1;
            }
@@ -2962,9 +2964,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
             or set WINREG if this operand could fit after reloads
             provided the constraint allows some registers.  */
 
-         while (*p && (c = *p++) != ',')
-           switch (c)
+         do
+           switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
              {
+             case '\0':
+               len = 0;
+               break;
+             case ',':
+               c = '\0';
+               break;
+
              case '=':  case '+':  case '*':
                break;
 
@@ -2985,15 +2994,19 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              case '#':
                /* Ignore rest of this alternative as far as
                   reloading is concerned.  */
-               while (*p && *p != ',')
+               do
                  p++;
+               while (*p && *p != ',');
+               len = 0;
                break;
 
              case '0':  case '1':  case '2':  case '3':  case '4':
              case '5':  case '6':  case '7':  case '8':  case '9':
-               c = strtoul (p - 1, &p, 10);
+               m = strtoul (p, &end, 10);
+               p = end;
+               len = 0;
 
-               this_alternative_matches[i] = c;
+               this_alternative_matches[i] = m;
                /* We are supposed to match a previous operand.
                   If we do, we win if that one did.
                   If we do not, count both of the operands as losers.
@@ -3001,7 +3014,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                   only a single reload insn will be needed to make
                   the two operands win.  As a result, this alternative
                   may be rejected when it is actually desirable.)  */
-               if ((swapped && (c != commutative || i != commutative + 1))
+               if ((swapped && (m != commutative || i != commutative + 1))
                    /* If we are matching as if two operands were swapped,
                       also pretend that operands_match had been computed
                       with swapped.
@@ -3009,22 +3022,22 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                       don't exchange them, because operands_match is valid
                       only on one side of its diagonal.  */
                    ? (operands_match
-                      [(c == commutative || c == commutative + 1)
-                      ? 2 * commutative + 1 - c : c]
+                      [(m == commutative || m == commutative + 1)
+                      ? 2 * commutative + 1 - m : m]
                       [(i == commutative || i == commutative + 1)
                       ? 2 * commutative + 1 - i : i])
-                   : operands_match[c][i])
+                   : operands_match[m][i])
                  {
                    /* If we are matching a non-offsettable address where an
                       offsettable address was expected, then we must reject
                       this combination, because we can't reload it.  */
-                   if (this_alternative_offmemok[c]
-                       && GET_CODE (recog_data.operand[c]) == MEM
-                       && this_alternative[c] == (int) NO_REGS
-                       && ! this_alternative_win[c])
+                   if (this_alternative_offmemok[m]
+                       && GET_CODE (recog_data.operand[m]) == MEM
+                       && this_alternative[m] == (int) NO_REGS
+                       && ! this_alternative_win[m])
                      bad = 1;
 
-                   did_match = this_alternative_win[c];
+                   did_match = this_alternative_win[m];
                  }
                else
                  {
@@ -3032,21 +3045,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                    rtx value;
                    /* Retroactively mark the operand we had to match
                       as a loser, if it wasn't already.  */
-                   if (this_alternative_win[c])
+                   if (this_alternative_win[m])
                      losers++;
-                   this_alternative_win[c] = 0;
-                   if (this_alternative[c] == (int) NO_REGS)
+                   this_alternative_win[m] = 0;
+                   if (this_alternative[m] == (int) NO_REGS)
                      bad = 1;
                    /* But count the pair only once in the total badness of
                       this alternative, if the pair can be a dummy reload.  */
                    value
                      = find_dummy_reload (recog_data.operand[i],
-                                          recog_data.operand[c],
+                                          recog_data.operand[m],
                                           recog_data.operand_loc[i],
-                                          recog_data.operand_loc[c],
-                                          operand_mode[i], operand_mode[c],
-                                          this_alternative[c], -1,
-                                          this_alternative_earlyclobber[c]);
+                                          recog_data.operand_loc[m],
+                                          operand_mode[i], operand_mode[m],
+                                          this_alternative[m], -1,
+                                          this_alternative_earlyclobber[m]);
 
                    if (value != 0)
                      losers--;
@@ -3054,7 +3067,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                /* This can be fixed with reloads if the operand
                   we are supposed to match can be fixed with reloads.  */
                badop = 0;
-               this_alternative[i] = this_alternative[c];
+               this_alternative[i] = this_alternative[m];
 
                /* If we have to reload this operand and some previous
                   operand also had to match the same thing as this
@@ -3173,7 +3186,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              case 'G':
              case 'H':
                if (GET_CODE (operand) == CONST_DOUBLE
-                   && CONST_DOUBLE_OK_FOR_LETTER_P (operand, c))
+                   && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (operand, c, p))
                  win = 1;
                break;
 
@@ -3207,7 +3220,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              case 'O':
              case 'P':
                if (GET_CODE (operand) == CONST_INT
-                   && CONST_OK_FOR_LETTER_P (INTVAL (operand), c))
+                   && CONST_OK_FOR_CONSTRAINT_P (INTVAL (operand), c, p))
                  win = 1;
                break;
 
@@ -3240,14 +3253,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                goto reg;
 
              default:
-               if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+               if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS)
                  {
-#ifdef EXTRA_CONSTRAINT
-                   if (EXTRA_MEMORY_CONSTRAINT (c))
+#ifdef EXTRA_CONSTRAINT_STR
+                   if (EXTRA_MEMORY_CONSTRAINT (c, p))
                      {
                        if (force_reload)
                          break;
-                       if (EXTRA_CONSTRAINT (operand, c))
+                       if (EXTRA_CONSTRAINT_STR (operand, c, p))
                          win = 1;
                        /* If the address was already reloaded,
                           we win as well.  */
@@ -3260,7 +3273,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                            && REGNO (operand) >= FIRST_PSEUDO_REGISTER
                            && reg_renumber[REGNO (operand)] < 0
                            && ((reg_equiv_mem[REGNO (operand)] != 0
-                                && EXTRA_CONSTRAINT (reg_equiv_mem[REGNO (operand)], c))
+                                && EXTRA_CONSTRAINT_STR (reg_equiv_mem[REGNO (operand)], c, p))
                                || (reg_equiv_address[REGNO (operand)] != 0)))
                          win = 1;
 
@@ -3274,9 +3287,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                        offmemok = 1;
                        break;
                      }
-                   if (EXTRA_ADDRESS_CONSTRAINT (c))
+                   if (EXTRA_ADDRESS_CONSTRAINT (c, p))
                      {
-                       if (EXTRA_CONSTRAINT (operand, c))
+                       if (EXTRA_CONSTRAINT_STR (operand, c, p))
                          win = 1;
 
                        /* If we didn't already win, we can reload
@@ -3286,14 +3299,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                        break;
                      }
 
-                   if (EXTRA_CONSTRAINT (operand, c))
+                   if (EXTRA_CONSTRAINT_STR (operand, c, p))
                      win = 1;
 #endif
                    break;
                  }
 
                this_alternative[i]
-                 = (int) reg_class_subunion[this_alternative[i]][(int) REG_CLASS_FROM_LETTER (c)];
+                 = (int) (reg_class_subunion
+                          [this_alternative[i]]
+                          [(int) REG_CLASS_FROM_CONSTRAINT (c, p)]);
              reg:
                if (GET_MODE (operand) == BLKmode)
                  break;
@@ -3304,6 +3319,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  win = 1;
                break;
              }
+         while ((p += len), c);
 
          constraints[i] = p;
 
@@ -3852,6 +3868,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       }
     else if (goal_alternative_matched[i] < 0
             && goal_alternative_matches[i] < 0
+            && !address_operand_reloaded[i]
             && optimize)
       {
        /* For each non-matching operand that's a MEM or a pseudo-register
@@ -4329,7 +4346,17 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        if (regno < FIRST_PSEUDO_REGISTER
            && TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno)
            && HARD_REGNO_MODE_OK (regno, rld[i].mode))
-         rld[i].reg_rtx = dest;
+         {
+           int nr = HARD_REGNO_NREGS (regno, rld[i].mode);
+           int ok = 1, nri;
+
+           for (nri = 1; nri < nr; nri ++)
+             if (! TEST_HARD_REG_BIT (reg_class_contents[rld[i].class], regno + nri))
+               ok = 0;
+
+           if (ok)
+             rld[i].reg_rtx = dest;
+         }
       }
 
   return retval;
@@ -4352,8 +4379,9 @@ alternative_allows_memconst (constraint, altnum)
     }
   /* Scan the requested alternative for 'm' or 'o'.
      If one of them is present, this alternative accepts memory constants.  */
-  while ((c = *constraint++) && c != ',' && c != '#')
-    if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c))
+  for (; (c = *constraint) && c != ',' && c != '#';
+       constraint += CONSTRAINT_LEN (c, constraint))
+    if (c == 'm' || c == 'o' || EXTRA_MEMORY_CONSTRAINT (c, constraint))
       return 1;
   return 0;
 }
@@ -4467,8 +4495,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn,
                                        reg_equiv_constant[regno])) != 0)
        return tem;
 
-      if (GET_MODE_BITSIZE (GET_MODE (x)) == BITS_PER_WORD
-         && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
          && reg_equiv_constant[regno] != 0)
        {
          tem =
@@ -4558,6 +4585,27 @@ make_memloc (ad, regno)
   return tem;
 }
 
+/* Returns true if AD could be turned into a valid memory reference
+   to mode MODE by reloading the part pointed to by PART into a 
+   register.  */
+
+static int
+maybe_memory_address_p (mode, ad, part)
+     enum machine_mode mode;
+     rtx ad;
+     rtx *part;
+{
+  int retv;
+  rtx tem = *part;
+  rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
+
+  *part = reg;
+  retv = memory_address_p (mode, ad);
+  *part = tem;
+
+  return retv;
+}
+
 /* Record all reloads needed for handling memory address AD
    which appears in *LOC in a memory reference to mode MODE
    which itself is found in location  *MEMREFLOC.
@@ -4838,26 +4886,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
      that the index needs a reload and find_reloads_address_1 will take care
      of it.
 
-     If we decide to do something here, it must be that
-     `double_reg_address_ok' is true and that this address rtl was made by
-     eliminate_regs.  We generate a reload of the fp/sp/ap + constant and
+     Handle all base registers here, not just fp/ap/sp, because on some
+     targets (namely Sparc) we can also get invalid addresses from preventive
+     subreg big-endian corrections made by find_reloads_toplev.
+
+     If we decide to do something, it must be that `double_reg_address_ok'
+     is true.  We generate a reload of the base register + constant and
      rework the sum so that the reload register will be added to the index.
      This is safe because we know the address isn't shared.
 
-     We check for fp/ap/sp as both the first and second operand of the
-     innermost PLUS.  */
+     We check for the base register as both the first and second operand of
+     the innermost PLUS.  */
 
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
-          && (XEXP (XEXP (ad, 0), 0) == frame_pointer_rtx
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 0) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 0) == arg_pointer_rtx
-#endif
-              || XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
-          && ! memory_address_p (mode, ad))
+          && GET_CODE (XEXP (XEXP (ad, 0), 0)) == REG
+          && REGNO (XEXP (XEXP (ad, 0), 0)) < FIRST_PSEUDO_REGISTER
+          && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 0), mode)
+          && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 1)))
     {
       *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
                                plus_constant (XEXP (XEXP (ad, 0), 0),
@@ -4874,15 +4920,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
 
   else if (GET_CODE (ad) == PLUS && GET_CODE (XEXP (ad, 1)) == CONST_INT
           && GET_CODE (XEXP (ad, 0)) == PLUS
-          && (XEXP (XEXP (ad, 0), 1) == frame_pointer_rtx
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 1) == hard_frame_pointer_rtx
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-              || XEXP (XEXP (ad, 0), 1) == arg_pointer_rtx
-#endif
-              || XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
-          && ! memory_address_p (mode, ad))
+          && GET_CODE (XEXP (XEXP (ad, 0), 1)) == REG
+          && REGNO (XEXP (XEXP (ad, 0), 1)) < FIRST_PSEUDO_REGISTER
+          && REG_MODE_OK_FOR_BASE_P (XEXP (XEXP (ad, 0), 1), mode)
+          && ! maybe_memory_address_p (mode, ad, &XEXP (XEXP (ad, 0), 0)))
     {
       *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
                                XEXP (XEXP (ad, 0), 0),
@@ -5147,7 +5188,7 @@ update_auto_inc_notes (insn, regno, reloadnum)
 
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     if (REG_NOTE_KIND (link) == REG_INC
-        && REGNO (XEXP (link, 0)) == regno)
+        && (int) REGNO (XEXP (link, 0)) == regno)
       push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
 #endif
 }
@@ -5227,6 +5268,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                                                       SUBREG_BYTE (orig_op1),
                                                       GET_MODE (orig_op1))));
          }
+       /* Plus in the index register may be created only as a result of
+          register remateralization for expresion 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)
+         {
+           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)),
+                        GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+           return 1;
+         }
 
        if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
            || code0 == ZERO_EXTEND || code1 == MEM)
@@ -5639,7 +5693,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
             needless copies if SUBREG_REG is multi-word.  */
          if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
            {
-             int regno = subreg_regno (x);
+             int regno ATTRIBUTE_UNUSED = subreg_regno (x);
 
              if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
                     : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
@@ -5902,7 +5956,7 @@ subst_reloads (insn)
             do the wrong thing if RELOADREG is multi-word.  RELOADREG
             will always be a REG here.  */
          if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
-           reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
+           reloadreg = reload_adjust_reg_for_mode (reloadreg, r->mode);
 
          /* If we are putting this into a SUBREG and RELOADREG is a
             SUBREG, we would be making nested SUBREGs, so we have to fix
@@ -6001,7 +6055,7 @@ copy_replacements_1 (px, py, orig_replacements)
     }
 }
 
-/* Change any replacements being done to *X to be done to *Y */
+/* Change any replacements being done to *X to be done to *Y */
 
 void
 move_replacements (x, y)
@@ -6882,6 +6936,26 @@ regno_clobbered_p (regno, insn, mode, sets)
   return 0;
 }
 
+/* Find the low part, with mode MODE, of a hard regno RELOADREG.  */
+rtx
+reload_adjust_reg_for_mode (reloadreg, mode)
+     rtx reloadreg;
+     enum machine_mode mode;
+{
+  int regno;
+
+  if (GET_MODE (reloadreg) == mode)
+    return reloadreg;
+
+  regno = REGNO (reloadreg);
+
+  if (WORDS_BIG_ENDIAN)
+    regno += HARD_REGNO_NREGS (regno, GET_MODE (reloadreg))
+      - HARD_REGNO_NREGS (regno, mode);
+
+  return gen_rtx_REG (mode, regno);
+}
+
 static const char *const reload_when_needed_name[] =
 {
   "RELOAD_FOR_INPUT",