OSDN Git Service

PR tree-optimization/32772
[pf3gnuchains/gcc-fork.git] / gcc / reload.c
index 8a76c0e..e88a82d 100644 (file)
@@ -1,13 +1,13 @@
 /* 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  Free Software Foundation,
-   Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file contains subroutines used only from the file reload1.c.
    It knows how to scan one insn for operands and values
@@ -88,6 +87,9 @@ a register with any other reload.  */
 
 #define REG_OK_STRICT
 
+/* We do not enable this with ENABLE_CHECKING, since it is awfully slow.  */
+#undef DEBUG_RELOAD
+
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -109,6 +111,7 @@ a register with any other reload.  */
 #include "toplev.h"
 #include "params.h"
 #include "target.h"
+#include "df.h"
 
 /* True if X is a constant that can be forced into the constant pool.  */
 #define CONST_POOL_OK_P(X)                     \
@@ -283,6 +286,23 @@ static int find_inc_amount (rtx, rtx);
 static int refers_to_mem_for_reload_p (rtx);
 static int refers_to_regno_for_reload_p (unsigned int, unsigned int,
                                         rtx, rtx *);
+
+/* Add NEW to reg_equiv_alt_mem_list[REGNO] if it's not present in the
+   list yet.  */
+
+static void
+push_reg_equiv_alt_mem (int regno, rtx mem)
+{
+  rtx it;
+
+  for (it = reg_equiv_alt_mem_list [regno]; it; it = XEXP (it, 1))
+    if (rtx_equal_p (XEXP (it, 0), mem))
+      return;
+
+  reg_equiv_alt_mem_list [regno]
+    = alloc_EXPR_LIST (REG_EQUIV, mem,
+                      reg_equiv_alt_mem_list [regno]);
+}
 \f
 /* Determine if any secondary reloads are needed for loading (if IN_P is
    nonzero) or storing (if IN_P is zero) X to or from a reload register of
@@ -1163,7 +1183,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
   /* If IN appears in OUT, we can't share any input-only reload for IN.  */
   if (in != 0 && out != 0 && MEM_P (out)
-      && (REG_P (in) || MEM_P (in))
+      && (REG_P (in) || MEM_P (in) || GET_CODE (in) == PLUS)
       && reg_overlap_mentioned_for_reload_p (in, XEXP (out, 0)))
     dont_share = 1;
 
@@ -1239,22 +1259,25 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
        }
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (HARD_REGNO_MODE_OK (i, mode)
-           && TEST_HARD_REG_BIT (reg_class_contents[(int) class], i))
-         {
-           int nregs = hard_regno_nregs[i][mode];
-
-           int j;
-           for (j = 1; j < nregs; j++)
-             if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], i + j))
-               break;
-           if (j == nregs)
-             break;
-         }
+           && in_hard_reg_set_p (reg_class_contents[(int) class], mode, i))
+         break;
       if (i == FIRST_PSEUDO_REGISTER)
        {
          error_for_asm (this_insn, "impossible register constraint "
                         "in %<asm%>");
-         class = ALL_REGS;
+         /* Avoid further trouble with this insn.  */
+         PATTERN (this_insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+         /* We used to continue here setting class to ALL_REGS, but it triggers
+            sanity check on i386 for:
+            void foo(long double d)
+            {
+              asm("" :: "a" (d));
+            }
+            Returning zero here ought to be safe as we take care in
+            find_reloads to not process the reloads when instruction was
+            replaced by USE.  */
+           
+         return 0;
        }
     }
 
@@ -1286,7 +1309,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
 #ifdef SECONDARY_MEMORY_NEEDED
       /* If a memory location is needed for the copy, make one.  */
-      if (in != 0 && (REG_P (in) || GET_CODE (in) == SUBREG)
+      if (in != 0
+         && (REG_P (in)
+             || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in))))
          && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
                                      class, inmode))
@@ -1316,7 +1341,9 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
       n_reloads++;
 
 #ifdef SECONDARY_MEMORY_NEEDED
-      if (out != 0 && (REG_P (out) || GET_CODE (out) == SUBREG)
+      if (out != 0
+          && (REG_P (out)
+             || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out))))
          && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
          && SECONDARY_MEMORY_NEEDED (class,
                                      REGNO_REG_CLASS (reg_or_subregno (out)),
@@ -1494,21 +1521,18 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
            /* Check that we don't use a hardreg for an uninitialized
               pseudo.  See also find_dummy_reload().  */
            && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
-               || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
+               || ! bitmap_bit_p (DF_RA_LIVE_OUT (ENTRY_BLOCK_PTR),
                                   ORIGINAL_REGNO (XEXP (note, 0))))
            && ! refers_to_regno_for_reload_p (regno,
-                                              (regno
-                                               + hard_regno_nregs[regno]
-                                                                 [rel_mode]),
+                                              end_hard_regno (rel_mode,
+                                                              regno),
                                               PATTERN (this_insn), inloc)
            /* 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.  */
            && (out == 0 || in == out
                || ! hard_reg_set_here_p (regno,
-                                         (regno
-                                          + hard_regno_nregs[regno]
-                                                            [rel_mode]),
+                                         end_hard_regno (rel_mode, regno),
                                          PATTERN (this_insn)))
            /* ??? Why is this code so different from the previous?
               Is there any simple coherent way to describe the two together?
@@ -1537,8 +1561,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
            if (offs == nregs
                && (! (refers_to_regno_for_reload_p
-                      (regno, (regno + hard_regno_nregs[regno][inmode]),
-                               in, (rtx *)0))
+                      (regno, end_hard_regno (inmode, regno), in, (rtx *) 0))
                    || can_reload_into (in, regno, inmode)))
              {
                rld[i].reg_rtx = gen_rtx_REG (rel_mode, regno);
@@ -1684,7 +1707,7 @@ combine_reloads (void)
     return;
 
   /* If there is a reload for part of the address of this operand, we would
-     need to chnage it to RELOAD_FOR_OTHER_ADDRESS.  But that would extend
+     need to change it to RELOAD_FOR_OTHER_ADDRESS.  But that would extend
      its life to the point where doing this combine would not lower the
      number of spill registers needed.  */
   for (i = 0; i < n_reloads; i++)
@@ -1820,7 +1843,12 @@ combine_reloads (void)
                    ||  ! (TEST_HARD_REG_BIT
                           (reg_class_contents[(int) rld[secondary_out].class],
                            REGNO (XEXP (note, 0)))))))
-       && ! fixed_regs[REGNO (XEXP (note, 0))])
+       && ! fixed_regs[REGNO (XEXP (note, 0))]
+       /* Check that we don't use a hardreg for an uninitialized
+          pseudo.  See also find_dummy_reload().  */
+       && (ORIGINAL_REGNO (XEXP (note, 0)) < FIRST_PSEUDO_REGISTER
+           || ! bitmap_bit_p (DF_LR_OUT (ENTRY_BLOCK_PTR),
+                              ORIGINAL_REGNO (XEXP (note, 0)))))
       {
        rld[output_reload].reg_rtx
          = gen_rtx_REG (rld[output_reload].outmode,
@@ -1972,7 +2000,7 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
           as they would clobber the other live pseudo using the same.
           See also PR20973.  */
       && (ORIGINAL_REGNO (in) < FIRST_PSEUDO_REGISTER
-          || ! bitmap_bit_p (ENTRY_BLOCK_PTR->il.rtl->global_live_at_end,
+          || ! bitmap_bit_p (DF_RA_LIVE_OUT (ENTRY_BLOCK_PTR),
                             ORIGINAL_REGNO (in))))
     {
       unsigned int regno = REGNO (in) + in_offset;
@@ -2048,7 +2076,7 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x)
 
          /* See if this reg overlaps range under consideration.  */
          if (r < end_regno
-             && r + hard_regno_nregs[r][GET_MODE (op0)] > beg_regno)
+             && end_hard_regno (GET_MODE (op0), r) > beg_regno)
            return 1;
        }
     }
@@ -2182,6 +2210,7 @@ operands_match_p (rtx x, rtx y)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_FIXED:
       return 0;
 
     case LABEL_REF:
@@ -2368,7 +2397,7 @@ decompose (rtx x)
        }
       else
        /* A hard reg.  */
-       val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)];
+       val.end = end_hard_regno (GET_MODE (x), val.start);
       break;
 
     case SUBREG:
@@ -2381,7 +2410,7 @@ decompose (rtx x)
        return decompose (SUBREG_REG (x));
       else
        /* A hard reg.  */
-       val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)];
+       val.end = val.start + subreg_nregs (x);
       break;
 
     case SCRATCH:
@@ -2766,7 +2795,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
              && MEM_P (op)
              && REG_P (reg)
              && (GET_MODE_SIZE (GET_MODE (reg))
-                 >= GET_MODE_SIZE (GET_MODE (op))))
+                 >= GET_MODE_SIZE (GET_MODE (op)))
+             && reg_equiv_constant[REGNO (reg)] == 0)
            set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg),
                                                   insn),
                                 REG_EQUAL, reg_equiv_memory_loc[REGNO (reg)]);
@@ -3271,6 +3301,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                break;
 
              case 'X':
+               force_reload = 0;
                win = 1;
                break;
 
@@ -3850,11 +3881,19 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
                 && goal_alternative_offmemok[i]
                 && MEM_P (recog_data.operand[i]))
          {
+           /* If the address to be reloaded is a VOIDmode constant,
+              use Pmode as mode of the reload register, as would have
+              been done by find_reloads_address.  */
+           enum machine_mode address_mode;
+           address_mode = GET_MODE (XEXP (recog_data.operand[i], 0));
+           if (address_mode == VOIDmode)
+             address_mode = Pmode;
+
            operand_reloadnum[i]
              = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX,
                             &XEXP (recog_data.operand[i], 0), (rtx*) 0,
                             base_reg_class (VOIDmode, MEM, SCRATCH),
-                            GET_MODE (XEXP (recog_data.operand[i], 0)),
+                            address_mode,
                             VOIDmode, 0, 0, i, RELOAD_FOR_INPUT);
            rld[operand_reloadnum[i]].inc
              = GET_MODE_SIZE (GET_MODE (recog_data.operand[i]));
@@ -4064,13 +4103,18 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 
          *recog_data.operand_loc[i] = substitution;
 
-         /* If we're replacing an operand with a LABEL_REF, we need
-            to make sure that there's a REG_LABEL note attached to
+         /* If we're replacing an operand with a LABEL_REF, we need to
+            make sure that there's a REG_LABEL_OPERAND note attached to
             this instruction.  */
-         if (!JUMP_P (insn)
-             && GET_CODE (substitution) == LABEL_REF
-             && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
-           REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+         if (GET_CODE (substitution) == LABEL_REF
+             && !find_reg_note (insn, REG_LABEL_OPERAND,
+                                XEXP (substitution, 0))
+             /* 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),
+                                             insn)))
+           REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
                                                  XEXP (substitution, 0),
                                                  REG_NOTES (insn));
        }
@@ -4120,6 +4164,12 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
       }
 #endif
 
+  /* If we detected error and replaced asm instruction by USE, forget about the
+     reloads.  */
+  if (GET_CODE (PATTERN (insn)) == USE
+      && GET_CODE (XEXP (PATTERN (insn), 0)) == CONST_INT)
+    n_reloads = 0;
+
   /* Perhaps an output reload can be combined with another
      to reduce needs by one.  */
   if (!goal_earlyclobber)
@@ -4412,7 +4462,8 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
     if (rld[i].when_needed == RELOAD_FOR_INPUT
        && GET_CODE (PATTERN (insn)) == SET
        && REG_P (SET_DEST (PATTERN (insn)))
-       && SET_SRC (PATTERN (insn)) == rld[i].in)
+       && SET_SRC (PATTERN (insn)) == rld[i].in
+       && !elimination_target_reg_p (SET_DEST (PATTERN (insn))))
       {
        rtx dest = SET_DEST (PATTERN (insn));
        unsigned int regno = REGNO (dest);
@@ -4522,6 +4573,8 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
              x = mem;
              i = find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
                                        opnum, type, ind_levels, insn);
+             if (!rtx_equal_p (x, mem))
+               push_reg_equiv_alt_mem (regno, x);
              if (address_reloaded)
                *address_reloaded = i;
            }
@@ -4554,20 +4607,23 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
       int regno = REGNO (SUBREG_REG (x));
       rtx tem;
 
-      if (subreg_lowpart_p (x)
-         && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
-         && reg_equiv_constant[regno] != 0
-         && (tem = gen_lowpart_common (GET_MODE (x),
-                                       reg_equiv_constant[regno])) != 0)
-       return tem;
-
-      if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+      if (regno >= FIRST_PSEUDO_REGISTER
+         && reg_renumber[regno] < 0
          && reg_equiv_constant[regno] != 0)
        {
          tem =
            simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno],
                                 GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
          gcc_assert (tem);
+         if (CONSTANT_P (tem) && !LEGITIMATE_CONSTANT_P (tem))
+           {
+             tem = force_const_mem (GET_MODE (x), tem);
+             i = find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
+                                       &XEXP (tem, 0), opnum, type,
+                                       ind_levels, insn);
+             if (address_reloaded)
+               *address_reloaded = i;
+           }
          return tem;
        }
 
@@ -4584,7 +4640,7 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
         a wider mode if we have a paradoxical SUBREG.  find_reloads will
         force a reload in that case.  So we should not do anything here.  */
 
-      else if (regno >= FIRST_PSEUDO_REGISTER
+      if (regno >= FIRST_PSEUDO_REGISTER
 #ifdef LOAD_EXTEND_OP
               && (GET_MODE_SIZE (GET_MODE (x))
                   <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
@@ -4728,9 +4784,13 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
              tem = make_memloc (ad, regno);
              if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
                {
+                 rtx orig = tem;
+
                  find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
                                        &XEXP (tem, 0), opnum,
                                        ADDR_TYPE (type), ind_levels, insn);
+                 if (!rtx_equal_p (tem, orig))
+                   push_reg_equiv_alt_mem (regno, tem);
                }
              /* We can avoid a reload if the register's equivalent memory
                 expression is valid as an indirect memory address.
@@ -5088,6 +5148,7 @@ subst_reg_equivs (rtx ad, rtx insn)
     case CONST_INT:
     case CONST:
     case CONST_DOUBLE:
+    case CONST_FIXED:
     case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -5359,7 +5420,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                                                       GET_MODE (orig_op1))));
          }
        /* Plus in the index register may be created only as a result of
-          register remateralization for expression like &localvar*4.  Reload it.
+          register rematerialization for expression like &localvar*4.  Reload it.
           It may be possible to combine the displacement on the outer level,
           but it is probably not worthwhile to do so.  */
        if (context == 1)
@@ -5408,16 +5469,12 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
 
        else if (code0 == REG && code1 == REG)
          {
-           if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
-               && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
+           if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
+               && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
              return 0;
-           else if (REGNO_OK_FOR_INDEX_P (REGNO (op1))
-                    && regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
+           else if (REGNO_OK_FOR_INDEX_P (REGNO (op0))
+                    && regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
              return 0;
-           else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
-             find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
-                                     &XEXP (x, 0), opnum, type, ind_levels,
-                                     insn);
            else if (regno_ok_for_base_p (REGNO (op0), mode, PLUS, REG))
              find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
                                      &XEXP (x, 1), opnum, type, ind_levels,
@@ -5426,16 +5483,20 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
              find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
                                      &XEXP (x, 0), opnum, type, ind_levels,
                                      insn);
+           else if (regno_ok_for_base_p (REGNO (op1), mode, PLUS, REG))
+             find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+                                     &XEXP (x, 0), opnum, type, ind_levels,
+                                     insn);
            else if (REGNO_OK_FOR_INDEX_P (REGNO (op0)))
              find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
                                      &XEXP (x, 1), opnum, type, ind_levels,
                                      insn);
            else
              {
-               find_reloads_address_1 (mode, orig_op0, 1, PLUS, SCRATCH,
+               find_reloads_address_1 (mode, orig_op0, 0, PLUS, REG,
                                        &XEXP (x, 0), opnum, type, ind_levels,
                                        insn);
-               find_reloads_address_1 (mode, orig_op1, 0, PLUS, REG,
+               find_reloads_address_1 (mode, orig_op1, 1, PLUS, SCRATCH,
                                        &XEXP (x, 1), opnum, type, ind_levels,
                                        insn);
              }
@@ -5485,12 +5546,22 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
        /* Require index register (or constant).  Let's just handle the
           register case in the meantime... If the target allows
           auto-modify by a constant then we could try replacing a pseudo
-          register with its equivalent constant where applicable.  */
-       if (REG_P (XEXP (op1, 1)))
-         if (!REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
-           find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
-                                   &XEXP (op1, 1), opnum, type, ind_levels,
-                                   insn);
+          register with its equivalent constant where applicable.
+
+          We also handle the case where the register was eliminated
+          resulting in a PLUS subexpression.
+
+          If we later decide to reload the whole PRE_MODIFY or
+          POST_MODIFY, inc_for_reload might clobber the reload register
+          before reading the index.  The index register might therefore
+          need to live longer than a TYPE reload normally would, so be
+          conservative and class it as RELOAD_OTHER.  */
+       if ((REG_P (XEXP (op1, 1))
+            && !REGNO_OK_FOR_INDEX_P (REGNO (XEXP (op1, 1))))
+           || GET_CODE (XEXP (op1, 1)) == PLUS)
+         find_reloads_address_1 (mode, XEXP (op1, 1), 1, code, SCRATCH,
+                                 &XEXP (op1, 1), opnum, RELOAD_OTHER,
+                                 ind_levels, insn);
 
        gcc_assert (REG_P (XEXP (op1, 0)));
 
@@ -5512,6 +5583,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
            if (reg_equiv_address[regno]
                || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
              {
+               rtx orig = tem;
+
                /* First reload the memory location's address.
                    We can't use ADDR_TYPE (type) here, because we need to
                    write back the value after reading it, hence we actually
@@ -5521,6 +5594,9 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                                      RELOAD_OTHER,
                                      ind_levels, insn);
 
+               if (!rtx_equal_p (tem, orig))
+                 push_reg_equiv_alt_mem (regno, tem);
+
                /* Then reload the memory location into a base
                   register.  */
                reloadnum = push_reload (tem, tem, &XEXP (x, 0),
@@ -5576,6 +5652,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
              if (reg_equiv_address[regno]
                  || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
                {
+                 rtx orig = tem;
+
                  /* First reload the memory location's address.
                     We can't use ADDR_TYPE (type) here, because we need to
                     write back the value after reading it, hence we actually
@@ -5583,6 +5661,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                  find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
                                        &XEXP (tem, 0), opnum, type,
                                        ind_levels, insn);
+                 if (!rtx_equal_p (tem, orig))
+                   push_reg_equiv_alt_mem (regno, tem);
                  /* Put this inside a new increment-expression.  */
                  x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
                  /* Proceed to reload that, as if it contained a register.  */
@@ -5619,7 +5699,7 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
              rtx equiv = (MEM_P (XEXP (x, 0))
                           ? XEXP (x, 0)
                           : reg_equiv_mem[regno]);
-             int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
+             int icode = (int) optab_handler (add_optab, Pmode)->insn_code;
              if (insn && NONJUMP_INSN_P (insn) && equiv
                  && memory_operand (equiv, GET_MODE (equiv))
 #ifdef HAVE_cc0
@@ -5662,43 +5742,6 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
            }
          return value;
        }
-
-      else if (MEM_P (XEXP (x, 0)))
-       {
-         /* This is probably the result of a substitution, by eliminate_regs,
-            of an equivalent address for a pseudo that was not allocated to a
-            hard register.  Verify that the specified address is valid and
-            reload it into a register.  */
-         /* Variable `tem' might or might not be used in FIND_REG_INC_NOTE.  */
-         rtx tem ATTRIBUTE_UNUSED = XEXP (x, 0);
-         rtx link;
-         int reloadnum;
-
-         /* Since we know we are going to reload this item, don't decrement
-            for the indirection level.
-
-            Note that this is actually conservative:  it would be slightly
-            more efficient to use the value of SPILL_INDIRECT_LEVELS from
-            reload1.c here.  */
-         /* We can't use ADDR_TYPE (type) here, because we need to
-            write back the value after reading it, hence we actually
-            need two registers.  */
-         find_reloads_address (GET_MODE (x), &XEXP (x, 0),
-                               XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
-                               opnum, type, ind_levels, insn);
-
-         reloadnum = push_reload (x, NULL_RTX, loc, (rtx*) 0,
-                                  context_reg_class,
-                                  GET_MODE (x), VOIDmode, 0, 0, opnum, type);
-         rld[reloadnum].inc
-           = find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
-
-         link = FIND_REG_INC_NOTE (this_insn, tem);
-         if (link != 0)
-           push_replacement (&XEXP (link, 0), reloadnum, VOIDmode);
-
-         return 1;
-       }
       return 0;
 
     case TRUNCATE:
@@ -5773,6 +5816,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context,
                find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
                                      &XEXP (x, 0), opnum, ADDR_TYPE (type),
                                      ind_levels, insn);
+               if (!rtx_equal_p (x, tem))
+                 push_reg_equiv_alt_mem (regno, x);
              }
          }
 
@@ -5887,10 +5932,8 @@ find_reloads_address_part (rtx x, rtx *loc, enum reg_class class,
       && (! LEGITIMATE_CONSTANT_P (x)
          || PREFERRED_RELOAD_CLASS (x, class) == NO_REGS))
     {
-      rtx tem;
-
-      tem = x = force_const_mem (mode, x);
-      find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+      x = force_const_mem (mode, x);
+      find_reloads_address (mode, &x, XEXP (x, 0), &XEXP (x, 0),
                            opnum, type, ind_levels, 0);
     }
 
@@ -5903,7 +5946,7 @@ find_reloads_address_part (rtx x, rtx *loc, enum reg_class class,
 
       tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
       x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
-      find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
+      find_reloads_address (mode, &XEXP (x, 1), XEXP (tem, 0), &XEXP (tem, 0),
                            opnum, type, ind_levels, 0);
     }
 
@@ -5960,6 +6003,9 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
              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;
+             enum machine_mode orig_mode = GET_MODE (orig);
+             int reloaded;
 
              /* For big-endian paradoxical subregs, SUBREG_BYTE does not
                 hold the correct (negative) byte offset.  */
@@ -5992,9 +6038,31 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
                    return x;
                }
 
-             find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
-                                   &XEXP (tem, 0), opnum, type,
-                                   ind_levels, insn);
+             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.  find_reloads_address
+                assumes that we pass it a valid address, and doesn't
+                force a reload.  This will probably be fine if
+                find_reloads_address finds some reloads.  But if it
+                doesn't find any, then we may have just converted a
+                valid address into an invalid one.  Check for that
+                here.  */
+             if (reloaded != 1
+                 && strict_memory_address_p (orig_mode, XEXP (tem, 0))
+                 && !strict_memory_address_p (GET_MODE (tem),
+                                              XEXP (tem, 0)))
+               push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
+                            base_reg_class (GET_MODE (tem), MEM, SCRATCH),
+                            GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
+                            opnum, type);
 
              /* If this is not a toplevel operand, find_reloads doesn't see
                 this substitution.  We have to emit a USE of the pseudo so
@@ -6031,8 +6099,12 @@ subst_reloads (rtx insn)
       rtx reloadreg = rld[r->what].reg_rtx;
       if (reloadreg)
        {
-#ifdef ENABLE_CHECKING
-         /* Internal consistency test.  Check that we don't modify
+#ifdef DEBUG_RELOAD
+         /* This checking takes a very long time on some platforms
+            causing the gcc.c-torture/compile/limits-fnargs.c test
+            to time out during testing.  See PR 31850.
+
+            Internal consistency test.  Check that we don't modify
             anything in the equivalence arrays.  Whenever something from
             those arrays needs to be reloaded, it must be unshared before
             being substituted into; the equivalence must not be modified.
@@ -6054,19 +6126,17 @@ subst_reloads (rtx insn)
              CHECK_MODF (reg_equiv_mem);
 #undef CHECK_MODF
            }
-#endif /* ENABLE_CHECKING */
+#endif /* DEBUG_RELOAD */
 
-         /* If we're replacing a LABEL_REF with a register, add a
-            REG_LABEL note to indicate to flow which label this
+         /* If we're replacing a LABEL_REF with a register, there must
+            already be an indication (to e.g. flow) which label this
             register refers to.  */
-         if (GET_CODE (*r->where) == LABEL_REF
-             && JUMP_P (insn))
-           {
-             REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
-                                                   XEXP (*r->where, 0),
-                                                   REG_NOTES (insn));
-             JUMP_LABEL (insn) = XEXP (*r->where, 0);
-          }
+         gcc_assert (GET_CODE (*r->where) != LABEL_REF
+                     || !JUMP_P (insn)
+                     || find_reg_note (insn,
+                                       REG_LABEL_OPERAND,
+                                       XEXP (*r->where, 0))
+                     || label_is_jump_target_p (XEXP (*r->where, 0), insn));
 
          /* Encapsulate RELOADREG so its machine mode matches what
             used to be there.  Note that gen_lowpart_common will
@@ -6304,7 +6374,7 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno,
          unsigned int inner_regno = subreg_regno (x);
          unsigned int inner_endregno
            = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
-                            ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1);
+                            ? subreg_nregs (x) : 1);
 
          return endregno > inner_regno && regno < inner_endregno;
        }
@@ -6402,6 +6472,10 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
                                      GET_MODE (SUBREG_REG (x)),
                                      SUBREG_BYTE (x),
                                      GET_MODE (x));
+      endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+                         ? subreg_nregs (x) : 1);
+
+      return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
     }
   else if (REG_P (x))
     {
@@ -6417,6 +6491,10 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
          gcc_assert (reg_equiv_constant[regno]);
          return 0;
        }
+
+      endregno = END_HARD_REGNO (x);
+
+      return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
     }
   else if (MEM_P (x))
     return refers_to_mem_for_reload_p (in);
@@ -6437,16 +6515,14 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
       if (REG_P (in))
        return 0;
       else if (GET_CODE (in) == PLUS)
-       return (reg_overlap_mentioned_for_reload_p (x, XEXP (in, 0))
+       return (rtx_equal_p (x, in)
+               || reg_overlap_mentioned_for_reload_p (x, XEXP (in, 0))
                || reg_overlap_mentioned_for_reload_p (x, XEXP (in, 1)));
       else return (reg_overlap_mentioned_for_reload_p (XEXP (x, 0), in)
                   || reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in));
     }
 
-  endregno = regno + (regno < FIRST_PSEUDO_REGISTER
-                     ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
-
-  return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
+  gcc_unreachable ();
 }
 
 /* Return nonzero if anything in X contains a MEM.  Look also for pseudo
@@ -6649,17 +6725,9 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
                }
              else if ((unsigned) valueno >= FIRST_PSEUDO_REGISTER)
                continue;
-             else
-               {
-                 int i;
-
-                 for (i = hard_regno_nregs[valueno][mode] - 1; i >= 0; i--)
-                   if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
-                                            valueno + i))
-                     break;
-                 if (i >= 0)
-                   continue;
-               }
+             else if (!in_hard_reg_set_p (reg_class_contents[(int) class],
+                                         mode, valueno))
+               continue;
              value = valtry;
              where = p;
              break;
@@ -6693,9 +6761,7 @@ find_equiv_reg (rtx goal, rtx insn, enum reg_class class, int other,
      and is also a register that appears in the address of GOAL.  */
 
   if (goal_mem && value == SET_DEST (single_set (where))
-      && refers_to_regno_for_reload_p (valueno,
-                                      (valueno
-                                       + hard_regno_nregs[valueno][mode]),
+      && refers_to_regno_for_reload_p (valueno, end_hard_regno (mode, valueno),
                                       goal, (rtx*) 0))
     return 0;