OSDN Git Service

2006-11-22 Antony King <anthony.king@st.com>
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 236afce..88b89fe 100644 (file)
@@ -1,6 +1,7 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+   Inc.
 
 This file is part of GCC.
 
@@ -35,6 +36,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "expr.h"
 #include "optabs.h"
 #include "regs.h"
+#include "addresses.h"
 #include "basic-block.h"
 #include "reload.h"
 #include "recog.h"
@@ -43,6 +45,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "toplev.h"
 #include "except.h"
 #include "tree.h"
+#include "target.h"
 
 /* This file contains the reload pass of the compiler, which is
    run after register allocation has been done.  It checks that
@@ -84,7 +87,7 @@ static rtx *reg_last_reload_reg;
 
 /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
    for an output reload that stores into reg N.  */
-static char *reg_has_output_reload;
+static regset_head reg_has_output_reload;
 
 /* Indicates which hard regs are reload-registers for an output reload
    in the current insn.  */
@@ -96,6 +99,11 @@ static HARD_REG_SET reg_is_output_reload;
    with the constant it stands for.  */
 rtx *reg_equiv_constant;
 
+/* Element N is an invariant value to which pseudo reg N is equivalent.
+   eliminate_regs_in_insn uses this to replace pseudos in particular
+   contexts.  */
+rtx *reg_equiv_invariant;
+
 /* Element N is a memory location to which pseudo reg N is equivalent,
    prior to any register elimination (such as frame pointer to stack
    pointer).  Depending on whether or not it is a valid address, this value
@@ -104,7 +112,7 @@ rtx *reg_equiv_memory_loc;
 
 /* We allocate reg_equiv_memory_loc inside a varray so that the garbage
    collector can keep track of what is inside.  */
-varray_type reg_equiv_memory_loc_varray;
+VEC(rtx,gc) *reg_equiv_memory_loc_vec;
 
 /* Element N is the address of stack slot to which pseudo reg N is equivalent.
    This is used when the address is not valid as a memory address
@@ -115,6 +123,10 @@ rtx *reg_equiv_address;
    or zero if pseudo reg N is not equivalent to a memory slot.  */
 rtx *reg_equiv_mem;
 
+/* Element N is an EXPR_LIST of REG_EQUIVs containing MEMs with
+   alternate representations of the location of pseudo reg N.  */
+rtx *reg_equiv_alt_mem_list;
+
 /* Widest width in which each pseudo reg is referred to (via subreg).  */
 static unsigned int *reg_max_ref_width;
 
@@ -396,6 +408,7 @@ static void count_pseudo (int);
 static void order_regs_for_reload (struct insn_chain *);
 static void reload_as_needed (int);
 static void forget_old_reloads_1 (rtx, rtx, void *);
+static void forget_marked_reloads (regset);
 static int reload_reg_class_lower (const void *, const void *);
 static void mark_reload_reg_in_use (unsigned int, int, enum reload_type,
                                    enum machine_mode);
@@ -432,6 +445,7 @@ static void add_auto_inc_notes (rtx, rtx);
 static void copy_eh_notes (rtx, rtx);
 static int reloads_conflict (int, int);
 static rtx gen_reload (rtx, rtx, int, enum reload_type);
+static rtx emit_insn_if_valid_for_reload (rtx);
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -487,7 +501,6 @@ init_reload (void)
 
   INIT_REG_SET (&spilled_pseudos);
   INIT_REG_SET (&pseudos_counted);
-  VARRAY_RTX_INIT (reg_equiv_memory_loc_varray, 0, "reg_equiv_memory_loc");
 }
 
 /* List of insn chains that are currently unused.  */
@@ -692,14 +705,16 @@ reload (rtx first, int global)
      Record memory equivalents in reg_mem_equiv so they can
      be substituted eventually by altering the REG-rtx's.  */
 
-  reg_equiv_constant = xcalloc (max_regno, sizeof (rtx));
-  reg_equiv_mem = xcalloc (max_regno, sizeof (rtx));
-  reg_equiv_address = xcalloc (max_regno, sizeof (rtx));
-  reg_max_ref_width = xcalloc (max_regno, sizeof (int));
-  reg_old_renumber = xcalloc (max_regno, sizeof (short));
+  reg_equiv_constant = XCNEWVEC (rtx, max_regno);
+  reg_equiv_invariant = XCNEWVEC (rtx, max_regno);
+  reg_equiv_mem = XCNEWVEC (rtx, max_regno);
+  reg_equiv_alt_mem_list = XCNEWVEC (rtx, max_regno);
+  reg_equiv_address = XCNEWVEC (rtx, max_regno);
+  reg_max_ref_width = XCNEWVEC (unsigned int, max_regno);
+  reg_old_renumber = XCNEWVEC (short, max_regno);
   memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
-  pseudo_forbidden_regs = xmalloc (max_regno * sizeof (HARD_REG_SET));
-  pseudo_previous_regs = xcalloc (max_regno, sizeof (HARD_REG_SET));
+  pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno);
+  pseudo_previous_regs = XCNEWVEC (HARD_REG_SET, max_regno);
 
   CLEAR_HARD_REG_SET (bad_spill_regs_global);
 
@@ -762,13 +777,12 @@ reload (rtx first, int global)
                    {
                      /* This is PLUS of frame pointer and a constant,
                         and might be shared.  Unshare it.  */
-                     reg_equiv_constant[i] = copy_rtx (x);
+                     reg_equiv_invariant[i] = copy_rtx (x);
                      num_eliminable_invariants++;
                    }
-                 else if (x == frame_pointer_rtx
-                          || x == arg_pointer_rtx)
+                 else if (x == frame_pointer_rtx || x == arg_pointer_rtx)
                    {
-                     reg_equiv_constant[i] = x;
+                     reg_equiv_invariant[i] = x;
                      num_eliminable_invariants++;
                    }
                  else if (LEGITIMATE_CONSTANT_P (x))
@@ -810,8 +824,8 @@ reload (rtx first, int global)
   /* We used to use alloca here, but the size of what it would try to
      allocate would occasionally cause it to exceed the stack limit and
      cause a core dump.  */
-  offsets_known_at = xmalloc (num_labels);
-  offsets_at = xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
+  offsets_known_at = XNEWVEC (char, num_labels);
+  offsets_at = (HOST_WIDE_INT (*)[NUM_ELIMINABLE_REGS]) xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (HOST_WIDE_INT));
 
   /* Alter each pseudo-reg rtx to contain its hard reg number.
      Assign stack slots to the pseudos that lack hard regs or equivalents.
@@ -981,6 +995,8 @@ reload (rtx first, int global)
        HARD_REG_SET to_spill;
        CLEAR_HARD_REG_SET (to_spill);
        update_eliminables (&to_spill);
+       AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill);
+
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
          if (TEST_HARD_REG_BIT (to_spill, i))
            {
@@ -1151,6 +1167,20 @@ reload (rtx first, int global)
       {
        rtx *pnote;
 
+       /* Clean up invalid ASMs so that they don't confuse later passes.
+          See PR 21299.  */
+       if (asm_noperands (PATTERN (insn)) >= 0)
+         {
+           extract_insn (insn);
+           if (!constrain_operands (1))
+             {
+               error_for_asm (insn,
+                              "%<asm%> operand has impossible constraints");
+               delete_insn (insn);
+               continue;
+             }
+         }
+
        if (CALL_P (insn))
          replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn),
                              VOIDmode, CALL_INSN_FUNCTION_USAGE (insn));
@@ -1238,8 +1268,11 @@ reload (rtx first, int global)
   /* Indicate that we no longer have known memory locations or constants.  */
   if (reg_equiv_constant)
     free (reg_equiv_constant);
+  if (reg_equiv_invariant)
+    free (reg_equiv_invariant);
   reg_equiv_constant = 0;
-  VARRAY_GROW (reg_equiv_memory_loc_varray, 0);
+  reg_equiv_invariant = 0;
+  VEC_free (rtx, gc, reg_equiv_memory_loc_vec);
   reg_equiv_memory_loc = 0;
 
   if (offsets_known_at)
@@ -1247,6 +1280,11 @@ reload (rtx first, int global)
   if (offsets_at)
     free (offsets_at);
 
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (reg_equiv_alt_mem_list[i])
+      free_EXPR_LIST_list (&reg_equiv_alt_mem_list[i]);
+  free (reg_equiv_alt_mem_list);
+
   free (reg_equiv_mem);
   reg_equiv_init = 0;
   free (reg_equiv_address);
@@ -1364,7 +1402,7 @@ maybe_fix_stack_asms (void)
 
                case 'p':
                  cls = (int) reg_class_subunion[cls]
-                   [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+                     [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
                  break;
 
                case 'g':
@@ -1375,7 +1413,7 @@ maybe_fix_stack_asms (void)
                default:
                  if (EXTRA_ADDRESS_CONSTRAINT (c, p))
                    cls = (int) reg_class_subunion[cls]
-                     [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+                     [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
                  else
                    cls = (int) reg_class_subunion[cls]
                      [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
@@ -1454,7 +1492,9 @@ calculate_needs_all_insns (int global)
          /* Skip insns that only set an equivalence.  */
          if (set && REG_P (SET_DEST (set))
              && reg_renumber[REGNO (SET_DEST (set))] < 0
-             && reg_equiv_constant[REGNO (SET_DEST (set))])
+             && (reg_equiv_constant[REGNO (SET_DEST (set))]
+                 || (reg_equiv_invariant[REGNO (SET_DEST (set))]))
+                     && reg_equiv_init[REGNO (SET_DEST (set))])
            continue;
 
          /* If needed, eliminate any eliminable registers.  */
@@ -1819,6 +1859,8 @@ find_reload_regs (struct insn_chain *chain)
          && rld[r].regno == -1)
        if (! find_reg (chain, i))
          {
+           if (dump_file)
+             fprintf (dump_file, "reload failure for reload %d\n", r);
            spill_failure (chain->insn, rld[r].class);
            failure = 1;
            return;
@@ -1887,6 +1929,12 @@ spill_failure (rtx insn, enum reg_class class)
     {
       error ("unable to find a register to spill in class %qs",
             reg_class_names[class]);
+
+      if (dump_file)
+       {
+         fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
+         debug_reload_to_stream (dump_file);
+       }
       fatal_insn ("this is the insn:", insn);
     }
 }
@@ -1944,11 +1992,15 @@ alter_reg (int i, int from_reg)
   if (reg_renumber[i] < 0
       && REG_N_REFS (i) > 0
       && reg_equiv_constant[i] == 0
+      && (reg_equiv_invariant[i] == 0 || reg_equiv_init[i] == 0)
       && reg_equiv_memory_loc[i] == 0)
     {
       rtx x;
+      enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
       unsigned int inherent_size = PSEUDO_REGNO_BYTES (i);
+      unsigned int inherent_align = GET_MODE_ALIGNMENT (mode);
       unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
+      unsigned int min_align = reg_max_ref_width[i] * BITS_PER_UNIT;
       int adjust = 0;
 
       /* Each pseudo reg has an inherent size which comes from its own mode,
@@ -1962,8 +2014,9 @@ alter_reg (int i, int from_reg)
       if (from_reg == -1)
        {
          /* No known place to spill from => no slot to reuse.  */
-         x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
-                                 inherent_size == total_size ? 0 : -1);
+         x = assign_stack_local (mode, total_size,
+                                 min_align > inherent_align
+                                 || total_size > inherent_size ? -1 : 0);
          if (BYTES_BIG_ENDIAN)
            /* Cancel the  big-endian correction done in assign_stack_local.
               Get the address of the beginning of the slot.
@@ -1979,7 +2032,8 @@ alter_reg (int i, int from_reg)
       else if (spill_stack_slot[from_reg] != 0
               && spill_stack_slot_width[from_reg] >= total_size
               && (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
-                  >= inherent_size))
+                  >= inherent_size)
+              && MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align)
        x = spill_stack_slot[from_reg];
 
       /* Allocate a bigger slot.  */
@@ -1987,7 +2041,6 @@ alter_reg (int i, int from_reg)
        {
          /* Compute maximum size needed, both for inherent size
             and for total size.  */
-         enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
          rtx stack_slot;
 
          if (spill_stack_slot[from_reg])
@@ -1997,11 +2050,14 @@ alter_reg (int i, int from_reg)
                mode = GET_MODE (spill_stack_slot[from_reg]);
              if (spill_stack_slot_width[from_reg] > total_size)
                total_size = spill_stack_slot_width[from_reg];
+             if (MEM_ALIGN (spill_stack_slot[from_reg]) > min_align)
+               min_align = MEM_ALIGN (spill_stack_slot[from_reg]);
            }
 
          /* Make a slot with that size.  */
          x = assign_stack_local (mode, total_size,
-                                 inherent_size == total_size ? 0 : -1);
+                                 min_align > inherent_align
+                                 || total_size > inherent_size ? -1 : 0);
          stack_slot = x;
 
          /* All pseudos mapped to this slot can alias each other.  */
@@ -2252,8 +2308,9 @@ set_label_offsets (rtx x, rtx insn, int initial_p)
    encounter, return the actual location so that find_reloads will do
    the proper thing.  */
 
-rtx
-eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
+static rtx
+eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn,
+                 bool may_use_invariant)
 {
   enum rtx_code code = GET_CODE (x);
   struct elim_table *ep;
@@ -2296,10 +2353,16 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
 
        }
       else if (reg_renumber && reg_renumber[regno] < 0
-              && reg_equiv_constant && reg_equiv_constant[regno]
-              && ! CONSTANT_P (reg_equiv_constant[regno]))
-       return eliminate_regs (copy_rtx (reg_equiv_constant[regno]),
-                              mem_mode, insn);
+              && reg_equiv_invariant && reg_equiv_invariant[regno])
+       {
+         if (may_use_invariant)
+           return eliminate_regs_1 (copy_rtx (reg_equiv_invariant[regno]),
+                                    mem_mode, insn, true);
+         /* There exists at least one use of REGNO that cannot be
+            eliminated.  Prevent the defining insn from being deleted.  */
+         reg_equiv_init[regno] = NULL_RTX;
+         alter_reg (regno, -1);
+       }
       return x;
 
     /* You might think handling MINUS in a manner similar to PLUS is a
@@ -2359,8 +2422,8 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         operand of a load-address insn.  */
 
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+       rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
+       rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
 
        if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)))
          {
@@ -2432,9 +2495,9 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     case GE:       case GT:       case GEU:    case GTU:
     case LE:       case LT:       case LEU:    case LTU:
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1
-         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
+       rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
+       rtx new1 = XEXP (x, 1)
+                  ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false) : 0;
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
@@ -2445,7 +2508,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
       /* If we have something in XEXP (x, 0), the usual case, eliminate it.  */
       if (XEXP (x, 0))
        {
-         new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true);
          if (new != XEXP (x, 0))
            {
              /* If this is a REG_DEAD note, it is not valid anymore.
@@ -2453,7 +2516,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
                 REG_DEAD note for the stack or frame pointer.  */
              if (GET_MODE (x) == REG_DEAD)
                return (XEXP (x, 1)
-                       ? eliminate_regs (XEXP (x, 1), mem_mode, insn)
+                       ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true)
                        : NULL_RTX);
 
              x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new, XEXP (x, 1));
@@ -2468,7 +2531,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         strictly needed, but it simplifies the code.  */
       if (XEXP (x, 1))
        {
-         new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true);
          if (new != XEXP (x, 1))
            return
              gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
@@ -2492,7 +2555,8 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     case CTZ:
     case POPCOUNT:
     case PARITY:
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+    case BSWAP:
+      new = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false);
       if (new != XEXP (x, 0))
        return gen_rtx_fmt_e (code, GET_MODE (x), new);
       return x;
@@ -2513,7 +2577,7 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
          new = SUBREG_REG (x);
        }
       else
-       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
+       new = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false);
 
       if (new != SUBREG_REG (x))
        {
@@ -2549,12 +2613,12 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
         case more efficiently.  */
       return
        replace_equiv_address_nv (x,
-                                 eliminate_regs (XEXP (x, 0),
-                                                 GET_MODE (x), insn));
+                                 eliminate_regs_1 (XEXP (x, 0), GET_MODE (x),
+                                                   insn, true));
 
     case USE:
       /* Handle insn_list USE that a call to a pure function may generate.  */
-      new = eliminate_regs (XEXP (x, 0), 0, insn);
+      new = eliminate_regs_1 (XEXP (x, 0), 0, insn, false);
       if (new != XEXP (x, 0))
        return gen_rtx_USE (GET_MODE (x), new);
       return x;
@@ -2575,12 +2639,10 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
     {
       if (*fmt == 'e')
        {
-         new = eliminate_regs (XEXP (x, i), mem_mode, insn);
+         new = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false);
          if (new != XEXP (x, i) && ! copied)
            {
-             rtx new_x = rtx_alloc (code);
-             memcpy (new_x, x, RTX_SIZE (code));
-             x = new_x;
+             x = shallow_copy_rtx (x);
              copied = 1;
            }
          XEXP (x, i) = new;
@@ -2590,16 +2652,14 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
          int copied_vec = 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
+             new = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false);
              if (new != XVECEXP (x, i, j) && ! copied_vec)
                {
                  rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
                                             XVEC (x, i)->elem);
                  if (! copied)
                    {
-                     rtx new_x = rtx_alloc (code);
-                     memcpy (new_x, x, RTX_SIZE (code));
-                     x = new_x;
+                     x = shallow_copy_rtx (x);
                      copied = 1;
                    }
                  XVEC (x, i) = new_v;
@@ -2613,6 +2673,12 @@ eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
   return x;
 }
 
+rtx
+eliminate_regs (rtx x, enum machine_mode mem_mode, rtx insn)
+{
+  return eliminate_regs_1 (x, mem_mode, insn, false);
+}
+
 /* Scan rtx X for modifications of elimination target registers.  Update
    the table of eliminables to reflect the changed state.  MEM_MODE is
    the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM.  */
@@ -2710,6 +2776,7 @@ elimination_effects (rtx x, enum machine_mode mem_mode)
     case CTZ:
     case POPCOUNT:
     case PARITY:
+    case BSWAP:
       elimination_effects (XEXP (x, 0), mem_mode);
       return;
 
@@ -2870,7 +2937,7 @@ eliminate_regs_in_insn (rtx insn, int replace)
   rtx substed_operand[MAX_RECOG_OPERANDS];
   rtx orig_operand[MAX_RECOG_OPERANDS];
   struct elim_table *ep;
-  rtx plus_src;
+  rtx plus_src, plus_cst_src;
 
   if (! insn_is_asm && icode < 0)
     {
@@ -2975,44 +3042,62 @@ eliminate_regs_in_insn (rtx insn, int replace)
   /* We allow one special case which happens to work on all machines we
      currently support: a single set with the source or a REG_EQUAL
      note being a PLUS of an eliminable register and a constant.  */
-  plus_src = 0;
+  plus_src = plus_cst_src = 0;
   if (old_set && REG_P (SET_DEST (old_set)))
     {
-      /* First see if the source is of the form (plus (reg) CST).  */
-      if (GET_CODE (SET_SRC (old_set)) == PLUS
-         && REG_P (XEXP (SET_SRC (old_set), 0))
-         && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
-         && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+      if (GET_CODE (SET_SRC (old_set)) == PLUS)
        plus_src = SET_SRC (old_set);
-      else if (REG_P (SET_SRC (old_set)))
+      /* First see if the source is of the form (plus (...) CST).  */
+      if (plus_src
+         && GET_CODE (XEXP (plus_src, 1)) == CONST_INT)
+       plus_cst_src = plus_src;
+      else if (REG_P (SET_SRC (old_set))
+              || plus_src)
        {
          /* Otherwise, see if we have a REG_EQUAL note of the form
-            (plus (reg) CST).  */
+            (plus (...) CST).  */
          rtx links;
          for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
            {
              if (REG_NOTE_KIND (links) == REG_EQUAL
                  && GET_CODE (XEXP (links, 0)) == PLUS
-                 && REG_P (XEXP (XEXP (links, 0), 0))
-                 && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT
-                 && REGNO (XEXP (XEXP (links, 0), 0)) < FIRST_PSEUDO_REGISTER)
+                 && GET_CODE (XEXP (XEXP (links, 0), 1)) == CONST_INT)
                {
-                 plus_src = XEXP (links, 0);
+                 plus_cst_src = XEXP (links, 0);
                  break;
                }
            }
        }
+
+      /* Check that the first operand of the PLUS is a hard reg or
+        the lowpart subreg of one.  */
+      if (plus_cst_src)
+       {
+         rtx reg = XEXP (plus_cst_src, 0);
+         if (GET_CODE (reg) == SUBREG && subreg_lowpart_p (reg))
+           reg = SUBREG_REG (reg);
+
+         if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+           plus_cst_src = 0;
+       }
     }
-  if (plus_src)
+  if (plus_cst_src)
     {
-      rtx reg = XEXP (plus_src, 0);
-      HOST_WIDE_INT offset = INTVAL (XEXP (plus_src, 1));
+      rtx reg = XEXP (plus_cst_src, 0);
+      HOST_WIDE_INT offset = INTVAL (XEXP (plus_cst_src, 1));
+
+      if (GET_CODE (reg) == SUBREG)
+       reg = SUBREG_REG (reg);
 
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
        if (ep->from_rtx == reg && ep->can_eliminate)
          {
+           rtx to_rtx = ep->to_rtx;
            offset += ep->offset;
 
+           if (GET_CODE (XEXP (plus_cst_src, 0)) == SUBREG)
+             to_rtx = gen_lowpart (GET_MODE (XEXP (plus_cst_src, 0)),
+                                   to_rtx);
            if (offset == 0)
              {
                int num_clobbers;
@@ -3022,7 +3107,7 @@ eliminate_regs_in_insn (rtx insn, int replace)
                   There's not much we can do if that doesn't work.  */
                PATTERN (insn) = gen_rtx_SET (VOIDmode,
                                              SET_DEST (old_set),
-                                             ep->to_rtx);
+                                             to_rtx);
                num_clobbers = 0;
                INSN_CODE (insn) = recog (PATTERN (insn), insn, &num_clobbers);
                if (num_clobbers)
@@ -3038,9 +3123,9 @@ eliminate_regs_in_insn (rtx insn, int replace)
            /* If we have a nonzero offset, and the source is already
               a simple REG, the following transformation would
               increase the cost of the insn by replacing a simple REG
-              with (plus (reg sp) CST).  So try only when plus_src
-              comes from old_set proper, not REG_NOTES.  */
-           else if (SET_SRC (old_set) == plus_src)
+              with (plus (reg sp) CST).  So try only when we already
+              had a PLUS before.  */
+           else if (plus_src)
              {
                new_body = old_body;
                if (! replace)
@@ -3052,7 +3137,7 @@ eliminate_regs_in_insn (rtx insn, int replace)
                PATTERN (insn) = new_body;
                old_set = single_set (insn);
 
-               XEXP (SET_SRC (old_set), 0) = ep->to_rtx;
+               XEXP (SET_SRC (old_set), 0) = to_rtx;
                XEXP (SET_SRC (old_set), 1) = GEN_INT (offset);
              }
            else
@@ -3079,6 +3164,8 @@ eliminate_regs_in_insn (rtx insn, int replace)
       /* For an asm statement, every operand is eliminable.  */
       if (insn_is_asm || insn_data[icode].operand[i].eliminable)
        {
+         bool is_set_src, in_plus;
+
          /* Check for setting a register that we know about.  */
          if (recog_data.operand_type[i] != OP_IN
              && REG_P (orig_operand[i]))
@@ -3093,8 +3180,21 @@ eliminate_regs_in_insn (rtx insn, int replace)
                  ep->can_eliminate = 0;
            }
 
-         substed_operand[i] = eliminate_regs (recog_data.operand[i], 0,
-                                              replace ? insn : NULL_RTX);
+         /* Companion to the above plus substitution, we can allow
+            invariants as the source of a plain move.  */
+         is_set_src = false;
+         if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set))
+           is_set_src = true;
+         in_plus = false;
+         if (plus_src
+             && (recog_data.operand_loc[i] == &XEXP (plus_src, 0)
+                 || recog_data.operand_loc[i] == &XEXP (plus_src, 1)))
+           in_plus = true;
+
+         substed_operand[i]
+           = eliminate_regs_1 (recog_data.operand[i], 0,
+                               replace ? insn : NULL_RTX,
+                               is_set_src || in_plus);
          if (substed_operand[i] != orig_operand[i])
            val = 1;
          /* Terminate the search in check_eliminable_occurrences at
@@ -3174,8 +3274,8 @@ eliminate_regs_in_insn (rtx insn, int replace)
              || GET_CODE (SET_SRC (old_set)) == PLUS))
        {
          int new_icode = recog (PATTERN (insn), insn, 0);
-         if (new_icode < 0)
-           INSN_CODE (insn) = icode;
+         if (new_icode >= 0)
+           INSN_CODE (insn) = new_icode;
        }
     }
 
@@ -3222,7 +3322,8 @@ eliminate_regs_in_insn (rtx insn, int replace)
      of spill registers to be needed in the final reload pass than in
      the pre-passes.  */
   if (val && REG_NOTES (insn) != 0)
-    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn));
+    REG_NOTES (insn)
+      = eliminate_regs_1 (REG_NOTES (insn), 0, REG_NOTES (insn), true);
 
   return val;
 }
@@ -3736,7 +3837,8 @@ scan_paradoxical_subregs (rtx x)
 
     case SUBREG:
       if (REG_P (SUBREG_REG (x))
-         && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+         && (GET_MODE_SIZE (GET_MODE (x))
+             > reg_max_ref_width[REGNO (SUBREG_REG (x))]))
        reg_max_ref_width[REGNO (SUBREG_REG (x))]
          = GET_MODE_SIZE (GET_MODE (x));
       return;
@@ -3788,24 +3890,6 @@ fixup_eh_region_note (rtx insn, rtx prev, rtx next)
        REG_NOTES (i)
          = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0), REG_NOTES (i));
       }
-
-  /* ??? Since we entered with one eh insn, we should exit with one eh insn;
-     otherwise we're unsure that we're not losing an exception.  Except that
-     the instruction stream incoming to reload doesn't pass the "if 
-     reg_eh_region is present, may_trap_p is true" smoke test.
-
-     Worse, even if it did, rtx_addr_can_trap_p returns false for some forms
-     of address that include constants regardless of the actual value of the
-     constant.  If we decide that "int a[3]; a[100000]" should be considered
-     non-trapping, we should get that story straight across more of the
-     compiler.  If we decide that it should trap, then we cannot decide
-     may_trap_p on the basis of rtx_addr_can_trap_p at all.  Which may not
-     be such a big thing -- it doesn't seem hard to get MEM_NOTRAP_P set
-     correctly in the first place.
-
-     Fixing all that is not in the cards for gcc 4.2, so for the nonce we
-     allow all eh insns to evaporate.  */
-  gcc_assert (trap_count <= 1);
 }
 
 /* Reload pseudo-registers into hard regs around each insn as needed.
@@ -3828,8 +3912,8 @@ reload_as_needed (int live_known)
 
   memset (spill_reg_rtx, 0, sizeof spill_reg_rtx);
   memset (spill_reg_store, 0, sizeof spill_reg_store);
-  reg_last_reload_reg = xcalloc (max_regno, sizeof (rtx));
-  reg_has_output_reload = xmalloc (max_regno);
+  reg_last_reload_reg = XCNEWVEC (rtx, max_regno);
+  INIT_REG_SET (&reg_has_output_reload);
   CLEAR_HARD_REG_SET (reg_reloaded_valid);
   CLEAR_HARD_REG_SET (reg_reloaded_call_part_clobbered);
 
@@ -3848,7 +3932,9 @@ reload_as_needed (int live_known)
 
       else if (INSN_P (insn))
        {
-         rtx oldpat = copy_rtx (PATTERN (insn));
+         regset_head regs_to_forget;
+         INIT_REG_SET (&regs_to_forget);
+         note_stores (PATTERN (insn), forget_old_reloads_1, &regs_to_forget);
 
          /* If this is a USE and CLOBBER of a MEM, ensure that any
             references to eliminable registers have been removed.  */
@@ -3869,6 +3955,7 @@ reload_as_needed (int live_known)
              if (NOTE_P (insn))
                {
                  update_eliminable_offsets ();
+                 CLEAR_REG_SET (&regs_to_forget);
                  continue;
                }
            }
@@ -3889,7 +3976,7 @@ reload_as_needed (int live_known)
             rtx's for those pseudo regs.  */
          else
            {
-             memset (reg_has_output_reload, 0, max_regno);
+             CLEAR_REG_SET (&reg_has_output_reload);
              CLEAR_HARD_REG_SET (reg_is_output_reload);
 
              find_reloads (insn, 1, spill_indirect_levels, live_known,
@@ -3955,7 +4042,8 @@ reload_as_needed (int live_known)
             for this insn in order to be stored in
             (obeying register constraints).  That is correct; such reload
             registers ARE still valid.  */
-         note_stores (oldpat, forget_old_reloads_1, NULL);
+         forget_marked_reloads (&regs_to_forget);
+         CLEAR_REG_SET (&regs_to_forget);
 
          /* There may have been CLOBBER insns placed after INSN.  So scan
             between INSN and NEXT and use them to forget old reloads.  */
@@ -4042,7 +4130,8 @@ reload_as_needed (int live_known)
                             the reload for inheritance.  */
                          SET_HARD_REG_BIT (reg_is_output_reload,
                                            REGNO (reload_reg));
-                         reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1;
+                         SET_REGNO_REG_SET (&reg_has_output_reload,
+                                            REGNO (XEXP (in_reg, 0)));
                        }
                      else
                        forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX,
@@ -4058,7 +4147,8 @@ reload_as_needed (int live_known)
                    {
                      SET_HARD_REG_BIT (reg_is_output_reload,
                                        REGNO (rld[i].reg_rtx));
-                     reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1;
+                     SET_REGNO_REG_SET (&reg_has_output_reload,
+                                        REGNO (XEXP (in_reg, 0)));
                    }
                }
            }
@@ -4096,7 +4186,7 @@ reload_as_needed (int live_known)
 
   /* Clean up.  */
   free (reg_last_reload_reg);
-  free (reg_has_output_reload);
+  CLEAR_REG_SET (&reg_has_output_reload);
 }
 
 /* Discard all record of any value reloaded from X,
@@ -4104,14 +4194,18 @@ reload_as_needed (int live_known)
    unless X is an output reload reg of the current insn.
 
    X may be a hard reg (the reload reg)
-   or it may be a pseudo reg that was reloaded from.  */
+   or it may be a pseudo reg that was reloaded from.  
+
+   When DATA is non-NULL just mark the registers in regset
+   to be forgotten later.  */
 
 static void
 forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
-                     void *data ATTRIBUTE_UNUSED)
+                     void *data)
 {
   unsigned int regno;
   unsigned int nr;
+  regset regs = (regset) data;
 
   /* note_stores does give us subregs of hard regs,
      subreg_regno_offset requires a hard reg.  */
@@ -4139,26 +4233,58 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
         This can happen if a block-local pseudo is allocated to that reg
         and it wasn't spilled because this block's total need is 0.
         Then some insn might have an optional reload and use this reg.  */
-      for (i = 0; i < nr; i++)
-       /* But don't do this if the reg actually serves as an output
-          reload reg in the current instruction.  */
+      if (!regs)
+       for (i = 0; i < nr; i++)
+         /* But don't do this if the reg actually serves as an output
+            reload reg in the current instruction.  */
+         if (n_reloads == 0
+             || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+           {
+             CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+             CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
+             spill_reg_store[regno + i] = 0;
+           }
+    }
+
+  if (regs)
+    while (nr-- > 0)
+      SET_REGNO_REG_SET (regs, regno + nr);
+  else
+    {
+      /* Since value of X has changed,
+        forget any value previously copied from it.  */
+
+      while (nr-- > 0)
+       /* But don't forget a copy if this is the output reload
+          that establishes the copy's validity.  */
        if (n_reloads == 0
-           || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+           || !REGNO_REG_SET_P (&reg_has_output_reload, regno + nr))
+         reg_last_reload_reg[regno + nr] = 0;
+     }
+}
+
+/* Forget the reloads marked in regset by previous function.  */
+static void
+forget_marked_reloads (regset regs)
+{
+  unsigned int reg;
+  reg_set_iterator rsi;
+  EXECUTE_IF_SET_IN_REG_SET (regs, 0, reg, rsi)
+    {
+      if (reg < FIRST_PSEUDO_REGISTER
+         /* But don't do this if the reg actually serves as an output
+            reload reg in the current instruction.  */
+         && (n_reloads == 0
+             || ! TEST_HARD_REG_BIT (reg_is_output_reload, reg)))
          {
-           CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
-           CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, regno + i);
-           spill_reg_store[regno + i] = 0;
+           CLEAR_HARD_REG_BIT (reg_reloaded_valid, reg);
+           CLEAR_HARD_REG_BIT (reg_reloaded_call_part_clobbered, reg);
+           spill_reg_store[reg] = 0;
          }
+      if (n_reloads == 0
+         || !REGNO_REG_SET_P (&reg_has_output_reload, reg))
+       reg_last_reload_reg[reg] = 0;
     }
-
-  /* Since value of X has changed,
-     forget any value previously copied from it.  */
-
-  while (nr-- > 0)
-    /* But don't forget a copy if this is the output reload
-       that establishes the copy's validity.  */
-    if (n_reloads == 0 || reg_has_output_reload[regno + nr] == 0)
-      reg_last_reload_reg[regno + nr] = 0;
 }
 \f
 /* The following HARD_REG_SETs indicate when each hard register is
@@ -4668,6 +4794,51 @@ reload_reg_reaches_end_p (unsigned int regno, int opnum, enum reload_type type)
     }
 }
 \f
+
+/*  Returns whether R1 and R2 are uniquely chained: the value of one
+    is used by the other, and that value is not used by any other
+    reload for this insn.  This is used to partially undo the decision
+    made in find_reloads when in the case of multiple
+    RELOAD_FOR_OPERAND_ADDRESS reloads it converts all
+    RELOAD_FOR_OPADDR_ADDR reloads into RELOAD_FOR_OPERAND_ADDRESS
+    reloads.  This code tries to avoid the conflict created by that
+    change.  It might be cleaner to explicitly keep track of which
+    RELOAD_FOR_OPADDR_ADDR reload is associated with which
+    RELOAD_FOR_OPERAND_ADDRESS reload, rather than to try to detect
+    this after the fact. */
+static bool
+reloads_unique_chain_p (int r1, int r2)
+{
+  int i;
+
+  /* We only check input reloads.  */
+  if (! rld[r1].in || ! rld[r2].in)
+    return false;
+
+  /* Avoid anything with output reloads.  */
+  if (rld[r1].out || rld[r2].out)
+    return false;
+
+  /* "chained" means one reload is a component of the other reload,
+     not the same as the other reload.  */
+  if (rld[r1].opnum != rld[r2].opnum
+      || rtx_equal_p (rld[r1].in, rld[r2].in)
+      || rld[r1].optional || rld[r2].optional
+      || ! (reg_mentioned_p (rld[r1].in, rld[r2].in)
+           || reg_mentioned_p (rld[r2].in, rld[r1].in)))
+    return false;
+
+  for (i = 0; i < n_reloads; i ++)
+    /* Look for input reloads that aren't our two */
+    if (i != r1 && i != r2 && rld[i].in)
+      {
+       /* If our reload is mentioned at all, it isn't a simple chain.  */
+       if (reg_mentioned_p (rld[r1].in, rld[i].in))
+         return false;
+      }
+  return true;
+}
+
 /* Return 1 if the reloads denoted by R1 and R2 cannot share a register.
    Return 0 otherwise.
 
@@ -4716,7 +4887,8 @@ reloads_conflict (int r1, int r2)
 
     case RELOAD_FOR_OPERAND_ADDRESS:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
-             || r2_type == RELOAD_FOR_OPERAND_ADDRESS);
+             || (r2_type == RELOAD_FOR_OPERAND_ADDRESS
+                 && !reloads_unique_chain_p (r1, r2)));
 
     case RELOAD_FOR_OPADDR_ADDR:
       return (r2_type == RELOAD_FOR_INPUT
@@ -5457,10 +5629,7 @@ choose_reload_regs (struct insn_chain *chain)
                  mode = GET_MODE (rld[r].in_reg);
                }
 #ifdef AUTO_INC_DEC
-             else if ((GET_CODE (rld[r].in_reg) == PRE_INC
-                       || GET_CODE (rld[r].in_reg) == PRE_DEC
-                       || GET_CODE (rld[r].in_reg) == POST_INC
-                       || GET_CODE (rld[r].in_reg) == POST_DEC)
+             else if (GET_RTX_CLASS (GET_CODE (rld[r].in_reg)) == RTX_AUTOINC
                       && REG_P (XEXP (rld[r].in_reg, 0)))
                {
                  regno = REGNO (XEXP (rld[r].in_reg, 0));
@@ -5514,11 +5683,9 @@ choose_reload_regs (struct insn_chain *chain)
                             enough.  */
                          || ((REGISTER_MOVE_COST (mode, last_class, class)
                               < MEMORY_MOVE_COST (mode, class, 1))
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
-                             && (SECONDARY_INPUT_RELOAD_CLASS (class, mode,
-                                                               last_reg)
+                             && (secondary_reload_class (1, class, mode,
+                                                         last_reg)
                                  == NO_REGS)
-#endif
 #ifdef SECONDARY_MEMORY_NEEDED
                              && ! SECONDARY_MEMORY_NEEDED (last_class, class,
                                                            mode)
@@ -5731,7 +5898,7 @@ choose_reload_regs (struct insn_chain *chain)
 
              if (equiv != 0)
                {
-                 if (regno_clobbered_p (regno, insn, rld[r].mode, 0))
+                 if (regno_clobbered_p (regno, insn, rld[r].mode, 2))
                    switch (rld[r].when_needed)
                      {
                      case RELOAD_FOR_OTHER_ADDRESS:
@@ -5991,7 +6158,8 @@ choose_reload_regs (struct insn_chain *chain)
            nr = hard_regno_nregs[nregno][rld[r].mode];
 
          while (--nr >= 0)
-           reg_has_output_reload[nregno + nr] = 1;
+           SET_REGNO_REG_SET (&reg_has_output_reload,
+                              nregno + nr);
 
          if (i >= 0)
            {
@@ -6101,6 +6269,8 @@ merge_assigned_reloads (rtx insn)
       if (j == n_reloads
          && max_input_address_opnum <= min_conflicting_input_opnum)
        {
+         gcc_assert (rld[i].when_needed != RELOAD_FOR_OUTPUT);
+
          for (j = 0; j < n_reloads; j++)
            if (i != j && rld[j].reg_rtx != 0
                && rtx_equal_p (rld[i].reg_rtx, rld[j].reg_rtx)
@@ -6119,16 +6289,17 @@ merge_assigned_reloads (rtx insn)
             if they were for inputs, RELOAD_OTHER for outputs.  Note that
             this test is equivalent to looking for reloads for this operand
             number.  */
-         /* We must take special care when there are two or more reloads to
-            be merged and a RELOAD_FOR_OUTPUT_ADDRESS reload that loads the
-            same value or a part of it; we must not change its type if there
-            is a conflicting input.  */
+         /* We must take special care with RELOAD_FOR_OUTPUT_ADDRESS; it may
+            share registers with a RELOAD_FOR_INPUT, so we can not change it
+            to RELOAD_FOR_OTHER_ADDRESS.  We should never need to, since we
+            do not modify RELOAD_FOR_OUTPUT.  */
 
          if (rld[i].when_needed == RELOAD_OTHER)
            for (j = 0; j < n_reloads; j++)
              if (rld[j].in != 0
                  && rld[j].when_needed != RELOAD_OTHER
                  && rld[j].when_needed != RELOAD_FOR_OTHER_ADDRESS
+                 && rld[j].when_needed != RELOAD_FOR_OUTPUT_ADDRESS
                  && (! conflicting_input
                      || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
                      || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
@@ -6176,6 +6347,55 @@ static rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
 static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
 static HARD_REG_SET reg_reloaded_died;
 
+/* Check if *RELOAD_REG is suitable as an intermediate or scratch register
+   of class NEW_CLASS with mode NEW_MODE.  Or alternatively, if alt_reload_reg
+   is nonzero, if that is suitable.  On success, change *RELOAD_REG to the
+   adjusted register, and return true.  Otherwise, return false.  */
+static bool
+reload_adjust_reg_for_temp (rtx *reload_reg, rtx alt_reload_reg,
+                           enum reg_class new_class,
+                           enum machine_mode new_mode)
+
+{
+  rtx reg;
+
+  for (reg = *reload_reg; reg; reg = alt_reload_reg, alt_reload_reg = 0)
+    {
+      unsigned regno = REGNO (reg);
+
+      if (!TEST_HARD_REG_BIT (reg_class_contents[(int) new_class], regno))
+       continue;
+      if (GET_MODE (reg) != new_mode)
+       {
+         if (!HARD_REGNO_MODE_OK (regno, new_mode))
+           continue;
+         if (hard_regno_nregs[regno][new_mode]
+             > hard_regno_nregs[regno][GET_MODE (reg)])
+           continue;
+         reg = reload_adjust_reg_for_mode (reg, new_mode);
+       }
+      *reload_reg = reg;
+      return true;
+    }
+  return false;
+}
+
+/* Check if *RELOAD_REG is suitable as a scratch register for the reload
+   pattern with insn_code ICODE, or alternatively, if alt_reload_reg is
+   nonzero, if that is suitable.  On success, change *RELOAD_REG to the
+   adjusted register, and return true.  Otherwise, return false.  */
+static bool
+reload_adjust_reg_for_icode (rtx *reload_reg, rtx alt_reload_reg,
+                            enum insn_code icode)
+
+{
+  enum reg_class new_class = scratch_reload_class (icode);
+  enum machine_mode new_mode = insn_data[(int) icode].operand[2].mode;
+
+  return reload_adjust_reg_for_temp (reload_reg, alt_reload_reg,
+                                    new_class, new_mode);
+}
+
 /* Generate insns to perform reload RL, which is for the insn in CHAIN and
    has the number J.  OLD contains the value to be used as input.  */
 
@@ -6227,76 +6447,11 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
   if (mode == VOIDmode)
     mode = rl->inmode;
 
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
-  /* If we need a secondary register for this operation, see if
-     the value is already in a register in that class.  Don't
-     do this if the secondary register will be used as a scratch
-     register.  */
-
-  if (rl->secondary_in_reload >= 0
-      && rl->secondary_in_icode == CODE_FOR_nothing
-      && optimize)
-    oldequiv
-      = find_equiv_reg (old, insn,
-                       rld[rl->secondary_in_reload].class,
-                       -1, NULL, 0, mode);
-#endif
-
-  /* If reloading from memory, see if there is a register
-     that already holds the same value.  If so, reload from there.
-     We can pass 0 as the reload_reg_p argument because
-     any other reload has either already been emitted,
-     in which case find_equiv_reg will see the reload-insn,
-     or has yet to be emitted, in which case it doesn't matter
-     because we will use this equiv reg right away.  */
-
-  if (oldequiv == 0 && optimize
-      && (MEM_P (old)
-         || (REG_P (old)
-             && REGNO (old) >= FIRST_PSEUDO_REGISTER
-             && reg_renumber[REGNO (old)] < 0)))
-    oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
-
-  if (oldequiv)
-    {
-      unsigned int regno = true_regnum (oldequiv);
-
-      /* Don't use OLDEQUIV if any other reload changes it at an
-        earlier stage of this insn or at this stage.  */
-      if (! free_for_value_p (regno, rl->mode, rl->opnum, rl->when_needed,
-                             rl->in, const0_rtx, j, 0))
-       oldequiv = 0;
-
-      /* If it is no cheaper to copy from OLDEQUIV into the
-        reload register than it would be to move from memory,
-        don't use it. Likewise, if we need a secondary register
-        or memory.  */
-
-      if (oldequiv != 0
-         && (((enum reg_class) REGNO_REG_CLASS (regno) != rl->class
-              && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
-                                      rl->class)
-                  >= MEMORY_MOVE_COST (mode, rl->class, 1)))
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
-             || (SECONDARY_INPUT_RELOAD_CLASS (rl->class,
-                                               mode, oldequiv)
-                 != NO_REGS)
-#endif
-#ifdef SECONDARY_MEMORY_NEEDED
-             || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
-                                         rl->class,
-                                         mode)
-#endif
-             ))
-       oldequiv = 0;
-    }
-
   /* delete_output_reload is only invoked properly if old contains
      the original pseudo register.  Since this is replaced with a
      hard reg when RELOAD_OVERRIDE_IN is set, see if we can
      find the pseudo in RELOAD_IN_REG.  */
-  if (oldequiv == 0
-      && reload_override_in[j]
+  if (reload_override_in[j]
       && REG_P (rl->in_reg))
     {
       oldequiv = old;
@@ -6467,7 +6622,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
 
   /* We can't do that, so output an insn to load RELOADREG.  */
 
-#ifdef SECONDARY_INPUT_RELOAD_CLASS
   /* If we have a secondary reload, pick up the secondary register
      and icode, if any.  If OLDEQUIV and OLD are different or
      if this is an in-out reload, recompute whether or not we
@@ -6482,11 +6636,13 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
   if (! special && rl->secondary_in_reload >= 0)
     {
       rtx second_reload_reg = 0;
+      rtx third_reload_reg = 0;
       int secondary_reload = rl->secondary_in_reload;
       rtx real_oldequiv = oldequiv;
       rtx real_old = old;
       rtx tmp;
       enum insn_code icode;
+      enum insn_code tertiary_icode = CODE_FOR_nothing;
 
       /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
         and similarly for OLD.
@@ -6534,53 +6690,89 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
        }
 
       second_reload_reg = rld[secondary_reload].reg_rtx;
+      if (rld[secondary_reload].secondary_in_reload >= 0)
+       {
+         int tertiary_reload = rld[secondary_reload].secondary_in_reload;
+
+         third_reload_reg = rld[tertiary_reload].reg_rtx;
+         tertiary_icode = rld[secondary_reload].secondary_in_icode;
+         /* We'd have to add more code for quartary reloads.  */
+         gcc_assert (rld[tertiary_reload].secondary_in_reload < 0);
+       }
       icode = rl->secondary_in_icode;
 
       if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
          || (rl->in != 0 && rl->out != 0))
        {
-         enum reg_class new_class
-           = SECONDARY_INPUT_RELOAD_CLASS (rl->class,
-                                           mode, real_oldequiv);
+         secondary_reload_info sri, sri2;
+         enum reg_class new_class, new_t_class;
+
+         sri.icode = CODE_FOR_nothing;
+         sri.prev_sri = NULL;
+         new_class = targetm.secondary_reload (1, real_oldequiv, rl->class,
+                                               mode, &sri);
 
-         if (new_class == NO_REGS)
+         if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing)
            second_reload_reg = 0;
-         else
+         else if (new_class == NO_REGS)
            {
-             enum insn_code new_icode;
-             enum machine_mode new_mode;
-
-             if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
-                                      REGNO (second_reload_reg)))
-               oldequiv = old, real_oldequiv = real_old;
+             if (reload_adjust_reg_for_icode (&second_reload_reg,
+                                              third_reload_reg, sri.icode))
+               icode = sri.icode, third_reload_reg = 0;
              else
+               oldequiv = old, real_oldequiv = real_old;
+           }
+         else if (sri.icode != CODE_FOR_nothing)
+           /* We currently lack a way to express this in reloads.  */
+           gcc_unreachable ();
+         else
+           {
+             sri2.icode = CODE_FOR_nothing;
+             sri2.prev_sri = &sri;
+             new_t_class = targetm.secondary_reload (1, real_oldequiv,
+                                                     new_class, mode, &sri);
+             if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing)
                {
-                 new_icode = reload_in_optab[(int) mode];
-                 if (new_icode != CODE_FOR_nothing
-                     && ((insn_data[(int) new_icode].operand[0].predicate
-                          && ! ((*insn_data[(int) new_icode].operand[0].predicate)
-                                (reloadreg, mode)))
-                         || (insn_data[(int) new_icode].operand[1].predicate
-                             && ! ((*insn_data[(int) new_icode].operand[1].predicate)
-                                   (real_oldequiv, mode)))))
-                   new_icode = CODE_FOR_nothing;
-
-                 if (new_icode == CODE_FOR_nothing)
-                   new_mode = mode;
+                 if (reload_adjust_reg_for_temp (&second_reload_reg,
+                                                 third_reload_reg,
+                                                 new_class, mode))
+                   third_reload_reg = 0, tertiary_icode = sri2.icode;
                  else
-                   new_mode = insn_data[(int) new_icode].operand[2].mode;
+                   oldequiv = old, real_oldequiv = real_old;
+               }
+             else if (new_t_class == NO_REGS && sri2.icode != CODE_FOR_nothing)
+               {
+                 rtx intermediate = second_reload_reg;
 
-                 if (GET_MODE (second_reload_reg) != new_mode)
+                 if (reload_adjust_reg_for_temp (&intermediate, NULL,
+                                                 new_class, mode)
+                     && reload_adjust_reg_for_icode (&third_reload_reg, NULL,
+                                                     sri2.icode))
                    {
-                     if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
-                                              new_mode))
-                       oldequiv = old, real_oldequiv = real_old;
-                     else
-                       second_reload_reg
-                         = reload_adjust_reg_for_mode (second_reload_reg,
-                                                       new_mode);
+                     second_reload_reg = intermediate;
+                     tertiary_icode = sri2.icode;
+                   }
+                 else
+                   oldequiv = old, real_oldequiv = real_old;
+               }
+             else if (new_t_class != NO_REGS && sri2.icode == CODE_FOR_nothing)
+               {
+                 rtx intermediate = second_reload_reg;
+
+                 if (reload_adjust_reg_for_temp (&intermediate, NULL,
+                                                 new_class, mode)
+                     && reload_adjust_reg_for_temp (&third_reload_reg, NULL,
+                                                     new_t_class, mode))
+                   {
+                     second_reload_reg = intermediate;
+                     tertiary_icode = sri2.icode;
                    }
+                 else
+                   oldequiv = old, real_oldequiv = real_old;
                }
+             else
+               /* This could be handled more intelligently too.  */
+               oldequiv = old, real_oldequiv = real_old;
            }
        }
 
@@ -6595,6 +6787,9 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
        {
          if (icode != CODE_FOR_nothing)
            {
+             /* We'd have to add extra code to handle this case.  */
+             gcc_assert (!third_reload_reg);
+
              emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
                                          second_reload_reg));
              special = 1;
@@ -6603,18 +6798,21 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
            {
              /* See if we need a scratch register to load the
                 intermediate register (a tertiary reload).  */
-             enum insn_code tertiary_icode
-               = rld[secondary_reload].secondary_in_icode;
-
              if (tertiary_icode != CODE_FOR_nothing)
                {
-                 rtx third_reload_reg
-                   = rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
-
                  emit_insn ((GEN_FCN (tertiary_icode)
                              (second_reload_reg, real_oldequiv,
                               third_reload_reg)));
                }
+             else if (third_reload_reg)
+               {
+                 gen_reload (third_reload_reg, real_oldequiv,
+                             rl->opnum,
+                             rl->when_needed);
+                 gen_reload (second_reload_reg, third_reload_reg,
+                             rl->opnum,
+                             rl->when_needed);
+               }
              else
                gen_reload (second_reload_reg, real_oldequiv,
                            rl->opnum,
@@ -6624,7 +6822,6 @@ emit_input_reload_insns (struct insn_chain *chain, struct reload *rl,
            }
        }
     }
-#endif
 
   if (! special && ! rtx_equal_p (reloadreg, oldequiv))
     {
@@ -6700,8 +6897,6 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
   if (GET_MODE (reloadreg) != mode)
     reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
-#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-
   /* If we need two reload regs, set RELOADREG to the intermediate
      one, since it will be stored into OLD.  We might need a secondary
      register only for an input reload, so check again here.  */
@@ -6709,22 +6904,25 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
   if (rl->secondary_out_reload >= 0)
     {
       rtx real_old = old;
+      int secondary_reload = rl->secondary_out_reload;
+      int tertiary_reload = rld[secondary_reload].secondary_out_reload;
 
       if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER
          && reg_equiv_mem[REGNO (old)] != 0)
        real_old = reg_equiv_mem[REGNO (old)];
 
-      if ((SECONDARY_OUTPUT_RELOAD_CLASS (rl->class,
-                                         mode, real_old)
-          != NO_REGS))
+      if (secondary_reload_class (0, rl->class, mode, real_old) != NO_REGS)
        {
          rtx second_reloadreg = reloadreg;
-         reloadreg = rld[rl->secondary_out_reload].reg_rtx;
+         reloadreg = rld[secondary_reload].reg_rtx;
 
          /* See if RELOADREG is to be used as a scratch register
             or as an intermediate register.  */
          if (rl->secondary_out_icode != CODE_FOR_nothing)
            {
+             /* We'd have to add extra code to handle this case.  */
+             gcc_assert (tertiary_reload < 0);
+
              emit_insn ((GEN_FCN (rl->secondary_out_icode)
                          (real_old, second_reloadreg, reloadreg)));
              special = 1;
@@ -6734,17 +6932,19 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
              /* See if we need both a scratch and intermediate reload
                 register.  */
 
-             int secondary_reload = rl->secondary_out_reload;
              enum insn_code tertiary_icode
                = rld[secondary_reload].secondary_out_icode;
 
+             /* We'd have to add more code for quartary reloads.  */
+             gcc_assert (tertiary_reload < 0
+                         || rld[tertiary_reload].secondary_out_reload < 0);
+
              if (GET_MODE (reloadreg) != mode)
                reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
              if (tertiary_icode != CODE_FOR_nothing)
                {
-                 rtx third_reloadreg
-                   = rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
+                 rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
                  rtx tem;
 
                  /* Copy primary reload reg to secondary reload reg.
@@ -6770,15 +6970,24 @@ emit_output_reload_insns (struct insn_chain *chain, struct reload *rl,
                }
 
              else
-               /* Copy between the reload regs here and then to
-                  OUT later.  */
+               {
+                 /* Copy between the reload regs here and then to
+                    OUT later.  */
+
+                 gen_reload (reloadreg, second_reloadreg,
+                             rl->opnum, rl->when_needed);
+                 if (tertiary_reload >= 0)
+                   {
+                     rtx third_reloadreg = rld[tertiary_reload].reg_rtx;
 
-               gen_reload (reloadreg, second_reloadreg,
-                           rl->opnum, rl->when_needed);
+                     gen_reload (third_reloadreg, reloadreg,
+                                 rl->opnum, rl->when_needed);
+                     reloadreg = third_reloadreg;
+                   }
+               }
            }
        }
     }
-#endif
 
   /* Output the last reload insn.  */
   if (! special)
@@ -6999,7 +7208,7 @@ do_output_reload (struct insn_chain *chain, struct reload *rl, int j)
     return;
 
   /* If is a JUMP_INSN, we can't support output reloads yet.  */
-  gcc_assert (!JUMP_P (insn));
+  gcc_assert (NONJUMP_INSN_P (insn));
 
   emit_output_reload_insns (chain, rld + j, j);
 }
@@ -7140,7 +7349,7 @@ emit_reload_insns (struct insn_chain *chain)
 
          if (REG_P (reg)
              && REGNO (reg) >= FIRST_PSEUDO_REGISTER
-             && ! reg_has_output_reload[REGNO (reg)])
+             && !REGNO_REG_SET_P (&reg_has_output_reload, REGNO (reg)))
            {
              int nregno = REGNO (reg);
 
@@ -7251,9 +7460,11 @@ emit_reload_insns (struct insn_chain *chain)
                       && rld[r].in != 0
                       && ((REG_P (rld[r].in)
                            && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER
-                           && ! reg_has_output_reload[REGNO (rld[r].in)])
+                           && !REGNO_REG_SET_P (&reg_has_output_reload,
+                                                REGNO (rld[r].in)))
                           || (REG_P (rld[r].in_reg)
-                              && ! reg_has_output_reload[REGNO (rld[r].in_reg)]))
+                              && !REGNO_REG_SET_P (&reg_has_output_reload,
+                                                   REGNO (rld[r].in_reg))))
                       && ! reg_set_p (rld[r].reg_rtx, PATTERN (insn)))
                {
                  int nregno;
@@ -7329,13 +7540,18 @@ emit_reload_insns (struct insn_chain *chain)
       /* If a register gets output-reloaded from a non-spill register,
         that invalidates any previous reloaded copy of it.
         But forget_old_reloads_1 won't get to see it, because
-        it thinks only about the original insn.  So invalidate it here.  */
-      if (i < 0 && rld[r].out != 0
-         && (REG_P (rld[r].out)
-             || (MEM_P (rld[r].out)
+        it thinks only about the original insn.  So invalidate it here.
+        Also do the same thing for RELOAD_OTHER constraints where the
+        output is discarded.  */
+      if (i < 0 
+         && ((rld[r].out != 0
+              && (REG_P (rld[r].out)
+                  || (MEM_P (rld[r].out)
+                      && REG_P (rld[r].out_reg))))
+             || (rld[r].out == 0 && rld[r].out_reg
                  && REG_P (rld[r].out_reg))))
        {
-         rtx out = (REG_P (rld[r].out)
+         rtx out = ((rld[r].out && REG_P (rld[r].out))
                     ? rld[r].out : rld[r].out_reg);
          int nregno = REGNO (out);
          if (nregno >= FIRST_PSEUDO_REGISTER)
@@ -7406,12 +7622,13 @@ emit_reload_insns (struct insn_chain *chain)
                  /* We have to set reg_has_output_reload here, or else 
                     forget_old_reloads_1 will clear reg_last_reload_reg
                     right away.  */
-                 reg_has_output_reload[nregno] = 1;
+                 SET_REGNO_REG_SET (&reg_has_output_reload,
+                                    nregno);
                }
            }
          else
            {
-             int num_regs = hard_regno_nregs[nregno][GET_MODE (rld[r].out)];
+             int num_regs = hard_regno_nregs[nregno][GET_MODE (out)];
 
              while (num_regs-- > 0)
                reg_last_reload_reg[nregno + num_regs] = 0;
@@ -7421,6 +7638,32 @@ emit_reload_insns (struct insn_chain *chain)
   IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
 }
 \f
+/* Go through the motions to emit INSN and test if it is strictly valid.
+   Return the emitted insn if valid, else return NULL.  */
+
+static rtx
+emit_insn_if_valid_for_reload (rtx insn)
+{
+  rtx last = get_last_insn ();
+  int code;
+
+  insn = emit_insn (insn);
+  code = recog_memoized (insn);
+
+  if (code >= 0)
+    {
+      extract_insn (insn);
+      /* We want constrain operands to treat this insn strictly in its
+        validity determination, i.e., the way it would after reload has
+        completed.  */
+      if (constrain_operands (1))
+       return insn;
+    }
+
+  delete_insns_since (last);
+  return NULL;
+}
+
 /* Emit code to perform a reload from IN (which may be a reload register) to
    OUT (which may also be a reload register).  IN or OUT is from operand
    OPNUM with reload type TYPE.
@@ -7457,6 +7700,12 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
      trying to emit a single insn to perform the add.  If it is not valid,
      we use a two insn sequence.
 
+     Or we can be asked to reload an unary operand that was a fragment of
+     an addressing mode, into a register.  If it isn't recognized as-is,
+     we try making the unop operand and the reload-register the same:
+     (set reg:X (unop:X expr:Y))
+     -> (set reg:Y expr:Y) (set reg:X (unop:X reg:Y)).
+
      Finally, we could be called to handle an 'o' constraint by putting
      an address into a register.  In that case, we first try to do this
      with a named pattern of "reload_load_address".  If no such pattern
@@ -7514,20 +7763,9 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
       if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
        in = gen_rtx_PLUS (GET_MODE (in), op0, op1);
 
-      insn = emit_insn (gen_rtx_SET (VOIDmode, out, in));
-      code = recog_memoized (insn);
-
-      if (code >= 0)
-       {
-         extract_insn (insn);
-         /* We want constrain operands to treat this insn strictly in
-            its validity determination, i.e., the way it would after reload
-            has completed.  */
-         if (constrain_operands (1))
-           return insn;
-       }
-
-      delete_insns_since (last);
+      insn = emit_insn_if_valid_for_reload (gen_rtx_SET (VOIDmode, out, in));
+      if (insn)
+       return insn;
 
       /* If that failed, we must use a conservative two-insn sequence.
 
@@ -7563,29 +7801,17 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
       if (rtx_equal_p (op0, op1))
        op1 = out;
 
-      insn = emit_insn (gen_add2_insn (out, op1));
-
-      /* If that failed, copy the address register to the reload register.
-        Then add the constant to the reload register.  */
-
-      code = recog_memoized (insn);
-
-      if (code >= 0)
+      insn = emit_insn_if_valid_for_reload (gen_add2_insn (out, op1));
+      if (insn)
        {
-         extract_insn (insn);
-         /* We want constrain operands to treat this insn strictly in
-            its validity determination, i.e., the way it would after reload
-            has completed.  */
-         if (constrain_operands (1))
-           {
-             /* Add a REG_EQUIV note so that find_equiv_reg can find it.  */
-             REG_NOTES (insn)
-               = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
-             return insn;
-           }
+         /* Add a REG_EQUIV note so that find_equiv_reg can find it.  */
+         REG_NOTES (insn)
+           = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+         return insn;
        }
 
-      delete_insns_since (last);
+      /* If that failed, copy the address register to the reload register.
+        Then add the constant to the reload register.  */
 
       gen_reload (out, op1, opnum, type);
       insn = emit_insn (gen_add2_insn (out, op0));
@@ -7615,10 +7841,54 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
       gen_reload (out, loc, opnum, type);
     }
 #endif
+  else if (REG_P (out) && UNARY_P (in))
+    {
+      rtx insn;
+      rtx op1;
+      rtx out_moded;
+      rtx set;
 
+      op1 = find_replacement (&XEXP (in, 0));
+      if (op1 != XEXP (in, 0))
+       in = gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in), op1);
+
+      /* First, try a plain SET.  */
+      set = emit_insn_if_valid_for_reload (gen_rtx_SET (VOIDmode, out, in));
+      if (set)
+       return set;
+
+      /* If that failed, move the inner operand to the reload
+        register, and try the same unop with the inner expression
+        replaced with the reload register.  */
+
+      if (GET_MODE (op1) != GET_MODE (out))
+       out_moded = gen_rtx_REG (GET_MODE (op1), REGNO (out));
+      else
+       out_moded = out;
+
+      gen_reload (out_moded, op1, opnum, type);
+
+      insn
+       = gen_rtx_SET (VOIDmode, out,
+                      gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in),
+                                     out_moded));
+      insn = emit_insn_if_valid_for_reload (insn);
+      if (insn)
+       {
+         REG_NOTES (insn)
+           = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+         return insn;
+       }
+
+      fatal_insn ("Failure trying to reload:", set);
+    }
   /* If IN is a simple operand, use gen_move_insn.  */
   else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
-    emit_insn (gen_move_insn (out, in));
+    {
+      tem = emit_insn (gen_move_insn (out, in));
+      /* IN may contain a LABEL_REF, if so add a REG_LABEL note.  */
+      mark_jump_label (in, tem, 0);
+    }
 
 #ifdef HAVE_reload_load_address
   else if (HAVE_reload_load_address)
@@ -7706,6 +7976,11 @@ delete_output_reload (rtx insn, int j, int last_reload_reg)
     n_occurrences += count_occurrences (PATTERN (insn),
                                        eliminate_regs (substed, 0,
                                                        NULL_RTX), 0);
+  for (i1 = reg_equiv_alt_mem_list [REGNO (reg)]; i1; i1 = XEXP (i1, 1))
+    {
+      gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed));
+      n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0);
+    }
   if (n_occurrences > n_inherited)
     return;
 
@@ -7972,15 +8247,16 @@ static rtx
 inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
 {
   /* REG or MEM to be copied and incremented.  */
-  rtx incloc = XEXP (value, 0);
+  rtx incloc = find_replacement (&XEXP (value, 0));
   /* Nonzero if increment after copying.  */
-  int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC);
+  int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC
+             || GET_CODE (value) == POST_MODIFY);
   rtx last;
   rtx inc;
   rtx add_insn;
   int code;
   rtx store;
-  rtx real_in = in == value ? XEXP (in, 0) : in;
+  rtx real_in = in == value ? incloc : in;
 
   /* No hard register is equivalent to this register after
      inc/dec operation.  If REG_LAST_RELOAD_REG were nonzero,
@@ -7989,10 +8265,18 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
   if (REG_P (incloc))
     reg_last_reload_reg[REGNO (incloc)] = 0;
 
-  if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC)
-    inc_amount = -inc_amount;
+  if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY)
+    {
+      gcc_assert (GET_CODE (XEXP (value, 1)) == PLUS);
+      inc = find_replacement (&XEXP (XEXP (value, 1), 1));
+    }
+  else
+    {
+      if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC)
+       inc_amount = -inc_amount;
 
-  inc = GEN_INT (inc_amount);
+      inc = GEN_INT (inc_amount);
+    }
 
   /* If this is post-increment, first copy the location to the reload reg.  */
   if (post && real_in != reloadreg)
@@ -8052,7 +8336,10 @@ inc_for_reload (rtx reloadreg, rtx in, rtx value, int inc_amount)
 
       emit_insn (gen_add2_insn (reloadreg, inc));
       store = emit_insn (gen_move_insn (incloc, reloadreg));
-      emit_insn (gen_add2_insn (reloadreg, GEN_INT (-inc_amount)));
+      if (GET_CODE (inc) == CONST_INT)
+       emit_insn (gen_add2_insn (reloadreg, GEN_INT (-INTVAL (inc))));
+      else
+       emit_insn (gen_sub2_insn (reloadreg, inc));
     }
 
   return store;
@@ -8191,6 +8478,15 @@ fixup_abnormal_edges (void)
        }
     }
 
+  /* We've possibly turned single trapping insn into multiple ones.  */
+  if (flag_non_call_exceptions)
+    {
+      sbitmap blocks;
+      blocks = sbitmap_alloc (last_basic_block);
+      sbitmap_ones (blocks);
+      find_many_sub_basic_blocks (blocks);
+    }
+
   if (inserted)
     commit_edge_insertions ();