Fix consistency problems with reg_equiv_{mem,address};
authorJ"orn Rennecke <amylaar@cygnus.co.uk>
Fri, 16 Oct 1998 19:54:38 +0000 (19:54 +0000)
committerJeff Law <law@gcc.gnu.org>
Fri, 16 Oct 1998 19:54:38 +0000 (13:54 -0600)
        Improve reload inheritance;
        * reload.c (reload_out_reg): New variable.
        (loc_mentioned_in_p, remove_address_replacements): New functions.
        (remove_replacements): Deleted.
        (push_reload): Set reload_out_reg[i].
        When merging, also set reload_{in,out}_reg[i], and remove
        duplicate address reloads.
        (combine_reloads): Copy reload_out_reg[i].
        (find_reloads): Do make_memloc substitution also when
        reg_equiv_memory_loc[regno] and num_not_at_initial_offset
        are both nonzero.
        Include *recog_operand_loc in commutativity operand changes.
        Generate optional output reloads.
        Delete reference to n_memlocs.  Don't set *recog_operand_loc before
        processing operands.  Call make_memloc in reg_equiv_address code.
        Set *recog_operand_loc only after processing operands, and only
        if replace is true.  Return a value.
        When changing address reload types for operands that didn't get
        reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
        RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
        Don't emit USEs for pseudo SUBREGs when not replacing.
        (find_reloads_address): Do make_memloc substitution also when
        reg_equiv_memory_loc[regno] and num_not_at_initial_offset
        are both nonzero.
        (find_reloads_toplev): Likewise.
        Call make_memloc in reg_equiv_address code.
        (debug_reload_to_stream): Add code to output reload_out_reg.
        (make_memloc): Delete local variable i, ifdefed out code, and
        references to memlocs and n_memlocs.
        (memlocs, n_memlocs): Delete.
        (push_secondary_reload): Clear reload_out_reg.
        (find_reloads_address_1): Provide memrefloc argument to all calls
        to find_reloads_address.
        In AUTO_INC code, handle non-directly addressable equivalences properly.
        * reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
        (find_reloads): Add return type.
        (remove_address_replacements, deallocate_reload_reg): Declare.
        * reload1.c (num_not_at_initial_offset): No longer static.
        (delete_address_reloads, delete_address_reloads_1): Likewise.
        (deallocate_reload_reg): New function.
        (spill_reg_stored_to): New array.
        (eliminate_regs): Don't substitute from reg_equiv_memory_loc.
        (eliminate_regs_in_insn): Move assignments of previous_offset and
        max_offset fields, and recalculation of num_not_at_initial_offset
        into new static function:
        (update_eliminable_offsets) .
        (reload_as_needed): Call update_eliminable_offsetss after calling
        find_reloads.
        Call forget_old_reloads_1 with contents of reloaded auto_inc
        expressions if the actual addressing can't be changed to match the
        auto_inc.
        (choose_reload_regs): For inheritance, replace
        reload_reg_free_before_p test with reload_reg_ions.
        (emit_reload_insns): If reload_in is a MEM, set OLD to
        reload_in_reg[j].
        Don't reload directly from oldequiv; if it's a pseudo with a
        stack slot, use reload_in[j].
        Check that reload_in_reg[j] is a MEM before replacing reload_in
        from reg_reloaded_contents.
        Include non-spill registers in reload inheritance processing.
        Also try to use reload_out_reg to set spill_reg_store /
        reg_last_reload_reg.
        In code to set new_spill_reg_store, use single_set to find out if
        there is a single set.
        Add code that allows to delete optional output reloads.
        Add code to allow deletion of output reloads that use no spill reg.
        At the end, set reload_override_in to oldequiv.
        Also call delete_output_reload if reload_out_reg is equal to old
        in oldequiv code.
        Add code to call delete_output_reload for stores with no matching load.
        Set / use spill_reg_stored_to.
        Handle case where secondary output reload uses a temporary, but
        actual store isn't found.
        When looking for a store of a value not loaded in order to call
        delete_output_reload, count_occurences should return 0 for no
        loads; but discount inherited input reloadill_reg_stored_to.
        Do checks for extra uses of REG.  Changed all
        callers.
        Use delete_address_reloads.
        (reload): Take return value of find_reloads into account.
        If a no-op set needs more than one reload, delete it.
        (reload_reg_free_before_p): RELOAD_FOR_INPUT
        can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
        for the same operand.
        (clear_reload_reg_in_use): Check for other reloads that keep a
        register in use.
        (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
        RELOAD_FOR_OPADDR_ADDR.
        Take into account when an address address reload is only needed
        for the address reload we are considering.
        (count_occurrences): Use rtx_equal_p for MEMs.
        (inc_for_reload): Return instruction that stores into RELOADREG.
        New argument two, IN, and rtx.  Changed all callers.
        (calculate_needs_all_insns, reload_as_needed):
        Don't clear after_call for a CLOBBER.
        Keep track of how many hard registers need to be copied from
        after_call, and don't clear after_call before we have seen
        that much copies, or we see a different instruction.

From-SVN: r23143

gcc/ChangeLog
gcc/reload.c
gcc/reload.h
gcc/reload1.c

index df1abe7be42b53861c0199512554b2348555c965..04da772f4aa66b5b7c7048684056db33f96bcc5a 100644 (file)
@@ -1,3 +1,114 @@
+Fri Oct 16 20:40:50 1998  J"orn Rennecke <amylaar@cygnus.co.uk>
+
+       Fix consistency problems with reg_equiv_{mem,address};
+       Improve reload inheritance;
+
+       * reload.c (reload_out_reg): New variable.
+       (loc_mentioned_in_p, remove_address_replacements): New functions.
+       (remove_replacements): Deleted.
+       (push_reload): Set reload_out_reg[i].
+       When merging, also set reload_{in,out}_reg[i], and remove
+       duplicate address reloads.
+       (combine_reloads): Copy reload_out_reg[i].
+       (find_reloads): Do make_memloc substitution also when
+       reg_equiv_memory_loc[regno] and num_not_at_initial_offset
+       are both nonzero.
+       Include *recog_operand_loc in commutativity operand changes.
+       Generate optional output reloads.
+       Delete reference to n_memlocs.  Don't set *recog_operand_loc before
+       processing operands.  Call make_memloc in reg_equiv_address code.
+       Set *recog_operand_loc only after processing operands, and only
+       if replace is true.  Return a value.
+       When changing address reload types for operands that didn't get
+       reloaded, use RELOAD_FOR_OPADDR_ADDRESS for
+       RELOAD_FOR_INPADDR_ADDRESS / RELOAD_FOR_OUTADDR_ADDRESS reloads.
+       Don't emit USEs for pseudo SUBREGs when not replacing.
+       (find_reloads_address): Do make_memloc substitution also when
+       reg_equiv_memory_loc[regno] and num_not_at_initial_offset
+       are both nonzero.
+       (find_reloads_toplev): Likewise.
+       Call make_memloc in reg_equiv_address code.
+       (debug_reload_to_stream): Add code to output reload_out_reg.
+       (make_memloc): Delete local variable i, ifdefed out code, and
+       references to memlocs and n_memlocs.
+       (memlocs, n_memlocs): Delete.
+       (push_secondary_reload): Clear reload_out_reg.
+       (find_reloads_address_1): Provide memrefloc argument to all calls
+       to find_reloads_address.
+       In AUTO_INC code, handle non-directly addressable equivalences properly.
+       * reload.h (reload_out_reg, num_not_at_initial_offset): Declare.
+       (find_reloads): Add return type.
+       (remove_address_replacements, deallocate_reload_reg): Declare.
+       * reload1.c (num_not_at_initial_offset): No longer static.
+       (delete_address_reloads, delete_address_reloads_1): Likewise.
+       (deallocate_reload_reg): New function.
+       (spill_reg_stored_to): New array.
+       (eliminate_regs): Don't substitute from reg_equiv_memory_loc.
+       (eliminate_regs_in_insn): Move assignments of previous_offset and
+       max_offset fields, and recalculation of num_not_at_initial_offset
+       into new static function:
+       (update_eliminable_offsets) .
+       (reload_as_needed): Call update_eliminable_offsetss after calling
+       find_reloads.
+       Call forget_old_reloads_1 with contents of reloaded auto_inc
+       expressions if the actual addressing can't be changed to match the
+       auto_inc.
+       (choose_reload_regs): For inheritance, replace
+       reload_reg_free_before_p test with reload_reg_used_at_all test, and
+       remove stand-alone reload_reg_used_at_all test.
+       Use reload_out_reg to determine which reload regs have output reloads.
+       Treat reload_override_in more similar to inherited reloads.
+       Handle (subreg (reg... for inheritance.
+       For flag_expensive_optimizations, add an extra pass to remove
+       unnecessary reloads from known working inheritance.
+       Delete obsolete code for pseudos replaced with MEMs.
+       Handle inheritance from auto_inc expressions.
+       (emit_reload_insns): If reload_in is a MEM, set OLD to 
+       reload_in_reg[j].
+       Don't reload directly from oldequiv; if it's a pseudo with a
+       stack slot, use reload_in[j].
+       Check that reload_in_reg[j] is a MEM before replacing reload_in
+       from reg_reloaded_contents.
+       Include non-spill registers in reload inheritance processing.
+       Also try to use reload_out_reg to set spill_reg_store /
+       reg_last_reload_reg.
+       In code to set new_spill_reg_store, use single_set to find out if
+       there is a single set.
+       Add code that allows to delete optional output reloads.
+       Add code to allow deletion of output reloads that use no spill reg.
+       At the end, set reload_override_in to oldequiv.
+       Also call delete_output_reload if reload_out_reg is equal to old
+       in oldequiv code.
+       Add code to call delete_output_reload for stores with no matching load.
+       Set / use spill_reg_stored_to.
+        Handle case where secondary output reload uses a temporary, but
+       actual store isn't found.
+       When looking for a store of a value not loaded in order to call
+       delete_output_reload, count_occurences should return 0 for no
+       loads; but discount inherited input reloadill_reg_stored_to.
+       Do checks for extra uses of REG.  Changed all
+       callers.
+       Use delete_address_reloads.
+       (reload): Take return value of find_reloads into account.
+       If a no-op set needs more than one reload, delete it.
+       (reload_reg_free_before_p): RELOAD_FOR_INPUT
+       can ignore RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS
+       for the same operand.
+       (clear_reload_reg_in_use): Check for other reloads that keep a
+       register in use.
+       (reload_reg_free_for_value_p): handle RELOAD_FOR_OPERAND_ADDRESS /
+       RELOAD_FOR_OPADDR_ADDR.
+       Take into account when an address address reload is only needed
+       for the address reload we are considering.
+       (count_occurrences): Use rtx_equal_p for MEMs.
+       (inc_for_reload): Return instruction that stores into RELOADREG.
+       New argument two, IN, and rtx.  Changed all callers.
+       (calculate_needs_all_insns, reload_as_needed):
+       Don't clear after_call for a CLOBBER.
+       Keep track of how many hard registers need to be copied from
+       after_call, and don't clear after_call before we have seen
+       that much copies, or we see a different instruction.
+
 Fri Oct 16 10:58:23 1998  Jeffrey A Law  (law@cygnus.com)
 
        * flow.c (find_basic_blocks_1): Do not delete unreachable blocks
index 1e438e17b318a031bc6b92502bd42c35ebf9114d..6f3ba43b26ac45797207b4f4490fee25c35415dd 100644 (file)
@@ -181,6 +181,7 @@ char reload_optional[MAX_RELOADS];
 char reload_nongroup[MAX_RELOADS];
 int reload_inc[MAX_RELOADS];
 rtx reload_in_reg[MAX_RELOADS];
+rtx reload_out_reg[MAX_RELOADS];
 char reload_nocombine[MAX_RELOADS];
 int reload_opnum[MAX_RELOADS];
 enum reload_type reload_when_needed[MAX_RELOADS];
@@ -232,11 +233,6 @@ struct decomposition
   HOST_WIDE_INT end;   /* Ending offset or register number.  */
 };
 
-/* MEM-rtx's created for pseudo-regs in stack slots not directly addressable;
-   (see reg_equiv_address).  */
-static rtx memlocs[MAX_RECOG_OPERANDS * ((MAX_REGS_PER_ADDRESS * 2) + 1)];
-static int n_memlocs;
-
 #ifdef SECONDARY_MEMORY_NEEDED
 
 /* Save MEMs needed to copy from one class of registers to another.  One MEM
@@ -329,11 +325,11 @@ static int hard_reg_set_here_p    PROTO((int, int, rtx));
 static struct decomposition decompose PROTO((rtx));
 static int immune_p            PROTO((rtx, rtx, struct decomposition));
 static int alternative_allows_memconst PROTO((char *, int));
-static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
+static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int, rtx));
 static rtx make_memloc         PROTO((rtx, int));
 static int find_reloads_address        PROTO((enum machine_mode, rtx *, rtx, rtx *,
                                       int, enum reload_type, int, rtx));
-static rtx subst_reg_equivs    PROTO((rtx));
+static rtx subst_reg_equivs    PROTO((rtx, rtx));
 static rtx subst_indexed_address PROTO((rtx));
 static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
                                         int, enum reload_type,int, rtx));
@@ -341,6 +337,7 @@ static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
                                             enum machine_mode, int,
                                             enum reload_type, int));
 static int find_inc_amount     PROTO((rtx, rtx));
+static int loc_mentioned_in_p  PROTO((rtx *, rtx));
 \f
 #ifdef HAVE_SECONDARY_RELOADS
 
@@ -536,6 +533,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
          /* Maybe we could combine these, but it seems too tricky.  */
          reload_nocombine[t_reload] = 1;
          reload_in_reg[t_reload] = 0;
+         reload_out_reg[t_reload] = 0;
          reload_opnum[t_reload] = opnum;
          reload_when_needed[t_reload] = secondary_type;
          reload_secondary_in_reload[t_reload] = -1;
@@ -605,6 +603,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
       /* Maybe we could combine these, but it seems too tricky.  */
       reload_nocombine[s_reload] = 1;
       reload_in_reg[s_reload] = 0;
+      reload_out_reg[s_reload] = 0;
       reload_opnum[s_reload] = opnum;
       reload_when_needed[s_reload] = secondary_type;
       reload_secondary_in_reload[s_reload] = in_p ? t_reload : -1;
@@ -1170,7 +1169,11 @@ push_reload (in, out, inloc, outloc, class,
        }
     }
 
-  if (class == NO_REGS)
+  /* Optional output reloads are always OK even if we have no register class,
+     since the function of these reloads is only to have spill_reg_store etc.
+     set, so that the storing insn can be deleted later.  */
+  if (class == NO_REGS
+      && (optional == 0 || type != RELOAD_FOR_OUTPUT))
     abort ();
 
   /* We can use an existing reload if the class is right
@@ -1281,6 +1284,7 @@ push_reload (in, out, inloc, outloc, class,
       reload_inc[i] = 0;
       reload_nocombine[i] = 0;
       reload_in_reg[i] = inloc ? *inloc : 0;
+      reload_out_reg[i] = outloc ? *outloc : 0;
       reload_opnum[i] = opnum;
       reload_when_needed[i] = type;
       reload_secondary_in_reload[i] = secondary_in_reload;
@@ -1315,9 +1319,32 @@ push_reload (in, out, inloc, outloc, class,
          && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
        reload_outmode[i] = outmode;
       if (in != 0)
-       reload_in[i] = in;
+       {
+         /* If we merge reloads for two distinct rtl expressions that
+            are identical in content, there might be duplicate address
+            reloads.  Remove the extra set now, so that if we later find
+            that we can inherit this reload, we can get rid of the
+            address reloads altogether.  */
+         if (reload_in[i] != in && rtx_equal_p (in, reload_in[i]))
+           {
+             /* We must keep the address reload with the lower operand
+                number alive.  */
+             if (opnum > reload_opnum[i])
+               {
+                 remove_address_replacements (in);
+                 in = reload_in[i];
+               }
+             else
+               remove_address_replacements (reload_in[i]);
+           }
+         reload_in[i] = in;
+         reload_in_reg[i] = inloc ? *inloc : 0;
+       }
       if (out != 0)
-       reload_out[i] = out;
+       {
+         reload_out[i] = out;
+         reload_out_reg[i] = outloc ? *outloc : 0;
+       }
       if (reg_class_subset_p (class, reload_reg_class[i]))
        reload_reg_class[i] = class;
       reload_optional[i] &= optional;
@@ -1506,19 +1533,67 @@ transfer_replacements (to, from)
       replacements[i].what = to;
 }
 \f
-/* Remove all replacements in reload FROM.  */
-void
-remove_replacements (from)
-     int from;
+/* IN_RTX is the value loaded by a reload that we now decided to inherit,
+   or a subpart of it.  If we have any replacements registered for IN_RTX,
+   cancel the reloads that were supposed to load them.
+   Return non-zero if we canceled any reloads.  */
+int
+remove_address_replacements (in_rtx)
+     rtx in_rtx;
 {
   int i, j;
+  char reload_flags[MAX_RELOADS];
+  int something_changed = 0;
 
+  bzero (reload_flags, sizeof reload_flags);
   for (i = 0, j = 0; i < n_replacements; i++)
     {
-      if (replacements[i].what == from)
-        continue;
-      replacements[j++] = replacements[i];
+      if (loc_mentioned_in_p (replacements[i].where, in_rtx))
+       reload_flags[replacements[i].what] |= 1;
+      else
+       {
+         replacements[j++] = replacements[i];
+         reload_flags[replacements[i].what] |= 2;
+       }
+    }
+  /* Note that the following store must be done before the recursive calls.  */
+  n_replacements = j;
+
+  for (i = n_reloads - 1; i >= 0; i--)
+    {
+      if (reload_flags[i] == 1)
+       {
+         deallocate_reload_reg (i);
+         remove_address_replacements (reload_in[i]);
+         reload_in[i] = 0;
+         something_changed = 1;
+       }
+    }
+  return something_changed;
+}
+
+/* Return non-zero if IN contains a piece of rtl that has the address LOC */
+static int
+loc_mentioned_in_p (loc, in)
+     rtx *loc, in;
+{
+  enum rtx_code code = GET_CODE (in);
+  char *fmt = GET_RTX_FORMAT (code);
+  int i, j;
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (loc == &XEXP (in, i))
+       return 1;
+      if (fmt[i] == 'e')
+       if (loc_mentioned_in_p (loc, XEXP (in, i)))
+         return 1;
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (in, i) - 1; i >= 0; i--)
+         if (loc_mentioned_in_p (loc, XVECEXP (in, i, j)))
+           return 1;
     }
+  return 0;
 }
 \f
 /* If there is only one output reload, and it is not for an earlyclobber
@@ -1617,6 +1692,7 @@ combine_reloads ()
 
        /* We have found a reload to combine with!  */
        reload_out[i] = reload_out[output_reload];
+       reload_out_reg[i] = reload_out_reg[output_reload];
        reload_outmode[i] = reload_outmode[output_reload];
        /* Mark the old output reload as inoperative.  */
        reload_out[output_reload] = 0;
@@ -2299,9 +2375,12 @@ safe_from_earlyclobber (op, clobber)
    RELOAD_REG_P if nonzero is a vector indexed by hard reg number
    which is nonnegative if the reg has been commandeered for reloading into.
    It is copied into STATIC_RELOAD_REG_P and referenced from there
-   by various subroutines.  */
+   by various subroutines.
 
-void
+   Return TRUE if some operands need to be changed, because of swapping
+   commutative operands, reg_equiv_address substitution, or whatever.  */
+
+int
 find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
      rtx insn;
      int replace, ind_levels;
@@ -2357,6 +2436,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   rtx set = single_set (insn);
   int goal_earlyclobber, this_earlyclobber;
   enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+  int retval = 0;
   /* Cache the last regno for the last pseudo we did an output reload
      for in case the next insn uses it.  */
   static int last_output_reload_regno = -1;
@@ -2365,7 +2445,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   this_insn_is_asm = 0;                /* Tentative.  */
   n_reloads = 0;
   n_replacements = 0;
-  n_memlocs = 0;
   n_earlyclobbers = 0;
   replace_reloads = replace;
   hard_regs_live_known = live_known;
@@ -2406,7 +2485,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
     case ASM_INPUT:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
-      return;
+      return 0;
 
     case SET:
       /* Dispose quickly of (set (reg..) (reg..)) if both have hard regs and it
@@ -2418,7 +2497,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
          && REGNO (SET_SRC (body)) < FIRST_PSEUDO_REGISTER
          && REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (SET_SRC (body))),
                                 REGNO_REG_CLASS (REGNO (SET_DEST (body)))) == 2)
-       return;
+       return 0;
     case PARALLEL:
     case ASM_OPERANDS:
       reload_n_operands = noperands = asm_noperands (body);
@@ -2458,7 +2537,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       n_alternatives = insn_n_alternatives[insn_code_number];
       /* Just return "no reloads" if insn has no operands with constraints.  */
       if (n_alternatives == 0)
-       return;
+       return 0;
       insn_extract (insn);
       for (i = 0; i < noperands; i++)
        {
@@ -2469,7 +2548,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
     }
 
   if (noperands == 0)
-    return;
+    return 0;
 
   commutative = -1;
 
@@ -2577,9 +2656,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  || GET_CODE (recog_operand[i]) == PLUS))
            {
              INSN_CODE (insn) = -1;
-             find_reloads (insn, replace, ind_levels, live_known,
-                           reload_reg_p);
-             return;
+             retval = find_reloads (insn, replace, ind_levels, live_known,
+                                    reload_reg_p);
+             return retval;
            }
 
          substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
@@ -2601,14 +2680,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            = find_reloads_toplev (recog_operand[i], i, address_type[i],
                                   ind_levels,
                                   set != 0
-                                  && &SET_DEST (set) == recog_operand_loc[i]);
+                                  && &SET_DEST (set) == recog_operand_loc[i],
+                                  insn);
 
          /* If we made a MEM to load (a part of) the stackslot of a pseudo
             that didn't get a hard register, emit a USE with a REG_EQUAL
             note in front so that we might inherit a previous, possibly
             wider reload.  */
             
-         if (GET_CODE (op) == MEM
+         if (replace
+             && GET_CODE (op) == MEM
              && GET_CODE (reg) == REG
              && (GET_MODE_SIZE (GET_MODE (reg))
                  >= GET_MODE_SIZE (GET_MODE (op))))
@@ -2616,15 +2697,15 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
               = gen_rtx_EXPR_LIST (REG_EQUAL,
                                   reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
 
-         substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
+         substed_operand[i] = recog_operand[i] = op;
        }
       else if (code == PLUS || GET_RTX_CLASS (code) == '1')
        /* We can get a PLUS as an "operand" as a result of register
           elimination.  See eliminate_regs and gen_reload.  We handle
           a unary operator by reloading the operand.  */
-       substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
+       substed_operand[i] = recog_operand[i]
          = find_reloads_toplev (recog_operand[i], i, address_type[i],
-                                ind_levels, 0);
+                                ind_levels, 0, insn);
       else if (code == REG)
        {
          /* This is equivalent to calling find_reloads_toplev.
@@ -2646,44 +2727,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
              substed_operand[i] = recog_operand[i]
                = reg_equiv_constant[regno];
            }
-#if 0 /* This might screw code in reload1.c to delete prior output-reload
-        that feeds this insn.  */
-         if (reg_equiv_mem[regno] != 0)
+         if (reg_equiv_memory_loc[regno] != 0
+             && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
+           /* We need not give a valid is_set_dest argument since the case
+              of a constant equivalence was checked above.  */
            substed_operand[i] = recog_operand[i]
-             = reg_equiv_mem[regno];
-#endif
-         if (reg_equiv_address[regno] != 0)
-           {
-             /* If reg_equiv_address is not a constant address, copy it,
-                since it may be shared.  */
-             /* We must rerun eliminate_regs, in case the elimination
-                offsets have changed.  */
-             rtx address = XEXP (eliminate_regs (reg_equiv_memory_loc[regno],
-                                                 0, NULL_RTX),
-                                 0);
-
-             if (rtx_varies_p (address))
-               address = copy_rtx (address);
-
-             /* Emit a USE that shows what register is being used/modified.  */
-             REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
-                                                       recog_operand[i]),
-                                          insn))
-               = gen_rtx_EXPR_LIST (REG_EQUAL,
-                                    reg_equiv_memory_loc[regno],
-                                    NULL_RTX);
-
-             *recog_operand_loc[i] = recog_operand[i]
-               = gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
-             RTX_UNCHANGING_P (recog_operand[i])
-               = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
-             find_reloads_address (GET_MODE (recog_operand[i]),
-                                   recog_operand_loc[i],
-                                   XEXP (recog_operand[i], 0),
-                                   &XEXP (recog_operand[i], 0),
-                                   i, address_type[i], ind_levels, insn);
-             substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
-           }
+             = find_reloads_toplev (recog_operand[i], i, address_type[i],
+                                    ind_levels, 0, insn);
        }
       /* If the operand is still a register (we didn't replace it with an
         equivalent), get the preferred class to reload it into.  */
@@ -3511,7 +3561,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       /* Avoid further trouble with this insn.  */
       PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
       n_reloads = 0;
-      return;
+      return 0;
     }
 
   /* Jump to `finish' from above if all operands are valid already.
@@ -3546,6 +3596,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
       tem = recog_operand[commutative];
       recog_operand[commutative] = recog_operand[commutative + 1];
       recog_operand[commutative + 1] = tem;
+      tem = *recog_operand_loc[commutative];
+      *recog_operand_loc[commutative] = *recog_operand_loc[commutative+1];
+      *recog_operand_loc[commutative+1] = tem;
 
       for (i = 0; i < n_reloads; i++)
        {
@@ -3556,14 +3609,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        }
     }
 
-  /* Perform whatever substitutions on the operands we are supposed
-     to make due to commutativity or replacement of registers
-     with equivalent constants or memory slots.  */
-
   for (i = 0; i < noperands; i++)
     {
-      *recog_operand_loc[i] = substed_operand[i];
-      /* While we are looping on operands, initialize this.  */
       operand_reloadnum[i] = -1;
 
       /* If this is an earlyclobber operand, we need to widen the scope.
@@ -3605,7 +3652,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        *recog_operand_loc[i] = recog_operand[i]
          = find_reloads_toplev (force_const_mem (operand_mode[i],
                                                  recog_operand[i]),
-                                i, address_type[i], ind_levels, 0);
+                                i, address_type[i], ind_levels, 0, insn);
        if (alternative_allows_memconst (constraints1[i],
                                         goal_alternative_number))
          goal_alternative_win[i] = 1;
@@ -3730,7 +3777,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
            /* Avoid further trouble with this insn.  */
            PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
            n_reloads = 0;
-           return;
+           return 0;
          }
       }
     else if (goal_alternative_matched[i] < 0
@@ -3748,13 +3795,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
        if ((GET_CODE (operand) == MEM
             || (GET_CODE (operand) == REG
                 && REGNO (operand) >= FIRST_PSEUDO_REGISTER))
-           && (enum reg_class) goal_alternative[i] != NO_REGS
+           /* If this is only for an output, the optional reload would not
+              actually cause us to use a register now, just note that
+              something is stored here.  */
+           && ((enum reg_class) goal_alternative[i] != NO_REGS
+               || modified[i] == RELOAD_WRITE)
            && ! no_input_reloads
-           /* Optional output reloads don't do anything and we mustn't
-              make in-out reloads on insns that are not permitted output
-              reloads.  */
+           /* An optional output reload might allow to delete INSN later.
+              We mustn't make in-out reloads on insns that are not permitted
+              output reloads.
+              If this is an asm, we can't delete it; we must not even call
+              push_reload for an optional output reload in this case,
+              because we can't be sure that the constraint allows a register,
+              and push_reload verifies the constraints for asms.  */
            && (modified[i] == RELOAD_READ
-               || (modified[i] == RELOAD_READ_WRITE && ! no_output_reloads)))
+               || (! no_output_reloads && ! this_insn_is_asm)))
          operand_reloadnum[i]
            = push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
                           modified[i] != RELOAD_READ ? recog_operand[i] : 0,
@@ -3770,6 +3825,24 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                           (insn_code_number < 0 ? 0
                            : insn_operand_strict_low[insn_code_number][i]),
                           1, i, operand_type[i]);
+       /* If a memory reference remains, yet we can't make an optional
+          reload, check if this is actually a pseudo register reference;
+          we then need to emit a USE and/or a CLOBBER so that reload
+          inheritance will do the right thing.  */
+       else if (replace && GET_CODE (operand) == MEM)
+         {
+           operand = *recog_operand_loc[i];
+
+           while (GET_CODE (operand) == SUBREG)
+             operand = XEXP (operand, 0);
+           if (GET_CODE (operand) == REG)
+             {
+               if (modified[i] != RELOAD_WRITE)
+                 emit_insn_before (gen_rtx_USE (VOIDmode, operand), insn);
+               if (modified[i] != RELOAD_READ)
+                 emit_insn_after (gen_rtx_CLOBBER (VOIDmode, operand), insn);
+             }
+         }
       }
     else if (goal_alternative_matches[i] >= 0
             && goal_alternative_win[goal_alternative_matches[i]]
@@ -3801,6 +3874,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                           0, 1, goal_alternative_matches[i], RELOAD_OTHER);
       }
   
+  /* Perform whatever substitutions on the operands we are supposed
+     to make due to commutativity or replacement of registers
+     with equivalent constants or memory slots.  */
+
+  for (i = 0; i < noperands; i++)
+    {
+      /* We only do this on the last pass through reload, because it is
+       possible for some data (like reg_equiv_address) to be changed during
+       later passes.  Moreover, we loose the opportunity to get a useful
+       reload_{in,out}_reg when we do these replacements.  */
+
+      if (replace)
+       *recog_operand_loc[i] = substed_operand[i];
+      else
+       retval |= (substed_operand[i] != *recog_operand_loc[i]);
+    }
+
   /* If this insn pattern contains any MATCH_DUP's, make sure that
      they will be substituted if the operands they match are substituted.
      Also do now any substitutions we already did on the operands.
@@ -3955,7 +4045,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
                  = RELOAD_FOR_OPADDR_ADDR;
            }
 
-         reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+         if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+             || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
+           reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+         else
+           reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
        }
 
       if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
@@ -4170,6 +4264,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   int goal_earlyclobber = 0; /* Always 0, to make combine_reloads happen.  */
   register int i;
   rtx body = PATTERN (insn);
+  int retval = 0;
 
   n_reloads = 0;
   n_replacements = 0;
@@ -4269,6 +4364,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
   if (!goal_earlyclobber)
     combine_reloads ();
 #endif /* no REGISTER_CONSTRAINTS */
+  return retval;
 }
 
 /* Return 1 if alternative number ALTNUM in constraint-string CONSTRAINT
@@ -4307,15 +4403,20 @@ alternative_allows_memconst (constraint, altnum)
    OPNUM and TYPE identify the purpose of the reload.
 
    IS_SET_DEST is true if X is the destination of a SET, which is not
-   appropriate to be replaced by a constant.  */
+   appropriate to be replaced by a constant.
+
+   INSN, if nonzero, is the insn in which we do the reload.  It is used
+   to determine if we may generate output reloads, and where to put USEs
+   for pseudos that we have to replace with stack slots.  */
 
 static rtx
-find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
+find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn)
      rtx x;
      int opnum;
      enum reload_type type;
      int ind_levels;
      int is_set_dest;
+     rtx insn;
 {
   register RTX_CODE code = GET_CODE (x);
 
@@ -4334,23 +4435,22 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
       else if (reg_equiv_mem[regno] != 0)
        x = reg_equiv_mem[regno];
 #endif
-      else if (reg_equiv_address[regno] != 0)
+      else if (reg_equiv_memory_loc[regno]
+              && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
        {
-         /* If reg_equiv_address varies, it may be shared, so copy it.  */
-         /* We must rerun eliminate_regs, in case the elimination
-            offsets have changed.  */
-         rtx addr = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0,
-                                          NULL_RTX),
-                          0);
-
-         if (rtx_varies_p (addr))
-           addr = copy_rtx (addr);
-
-         x = gen_rtx_MEM (GET_MODE (x), addr);
-         RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
-         find_reloads_address (GET_MODE (x), NULL_PTR,
-                               XEXP (x, 0),
-                               &XEXP (x, 0), opnum, type, ind_levels, 0);
+         rtx mem = make_memloc (x, regno);
+         if (reg_equiv_address[regno]
+             || ! rtx_equal_p (mem, reg_equiv_mem[regno]))
+           {
+             /* If this is not a toplevel operand, find_reloads doesn't see
+                this substitution.  We have to emit a USE of the pseudo so
+                that delete_output_reload can see it.  */
+             if (replace_reloads && recog_operand[opnum] != x)
+               emit_insn_before (gen_rtx_USE (VOIDmode, x), insn);
+             x = mem;
+             find_reloads_address (GET_MODE (x), &x, XEXP (x, 0), &XEXP (x, 0),
+                                   opnum, type, ind_levels, insn);
+           }
        }
       return x;
     }
@@ -4358,7 +4458,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
     {
       rtx tem = x;
       find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
-                           opnum, type, ind_levels, 0);
+                           opnum, type, ind_levels, insn);
       return tem;
     }
 
@@ -4452,7 +4552,8 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
                   || (reg_equiv_mem[regno] != 0
                       && (! strict_memory_address_p (GET_MODE (x), 
                                                      XEXP (reg_equiv_mem[regno], 0))
-                          || ! offsettable_memref_p (reg_equiv_mem[regno])))))
+                          || ! offsettable_memref_p (reg_equiv_mem[regno])
+                          || num_not_at_initial_offset))))
        {
          int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
          /* We must rerun eliminate_regs, in case the elimination
@@ -4473,7 +4574,12 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
          find_reloads_address (GET_MODE (x), NULL_PTR,
                                XEXP (x, 0),
-                               &XEXP (x, 0), opnum, type, ind_levels, 0);
+                               &XEXP (x, 0), opnum, type, ind_levels, insn);
+         /* If this is not a toplevel operand, find_reloads doesn't see this
+            substitution.  We have to emit a USE of the pseudo so that
+            delete_output_reload can see it.  */
+         if (replace_reloads && recog_operand[opnum] != x)
+           emit_insn_before (gen_rtx_USE (VOIDmode, SUBREG_REG (x)), insn);
        }
 
     }
@@ -4482,7 +4588,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
     {
       if (fmt[i] == 'e')
        XEXP (x, i) = find_reloads_toplev (XEXP (x, i), opnum, type,
-                                          ind_levels, is_set_dest);
+                                          ind_levels, is_set_dest, insn);
     }
   return x;
 }
@@ -4495,22 +4601,10 @@ make_memloc (ad, regno)
      rtx ad;
      int regno;
 {
-#if 0
-  register int i;
-#endif
   /* We must rerun eliminate_regs, in case the elimination
      offsets have changed.  */
-  rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
-
-#if 0 /* We cannot safely reuse a memloc made here;
-        if the pseudo appears twice, and its mem needs a reload,
-        it gets two separate reloads assigned, but it only
-        gets substituted with the second of them;
-        then it can get used before that reload reg gets loaded up.  */
-  for (i = 0; i < n_memlocs; i++)
-    if (rtx_equal_p (tem, XEXP (memlocs[i], 0)))
-      return memlocs[i];
-#endif
+  rtx tem
+    = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
 
   /* If TEM might contain a pseudo, we must copy it to avoid
      modifying it when we do the substitution for the reload.  */
@@ -4519,7 +4613,6 @@ make_memloc (ad, regno)
 
   tem = gen_rtx_MEM (GET_MODE (ad), tem);
   RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
-  memlocs[n_memlocs++] = tem;
   return tem;
 }
 
@@ -4535,7 +4628,8 @@ make_memloc (ad, regno)
    supports.
 
    INSN, if nonzero, is the insn in which we do the reload.  It is used
-   to determine if we may generate output reloads.
+   to determine if we may generate output reloads, and where to put USEs
+   for pseudos that we have to replace with stack slots.
 
    Value is nonzero if this address is reloaded or replaced as a whole.
    This is interesting to the caller if the address is an autoincrement.
@@ -4575,32 +4669,48 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
          return 1;
        }
 
-      else if (reg_equiv_address[regno] != 0)
+      tem = reg_equiv_memory_loc[regno];
+      if (tem != 0)
        {
-         tem = make_memloc (ad, regno);
-         find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
-                               &XEXP (tem, 0), opnum, ADDR_TYPE (type),
-                               ind_levels, insn);
-         push_reload (tem, NULL_RTX, loc, NULL_PTR,
-                      reload_address_base_reg_class,
-                      GET_MODE (ad), VOIDmode, 0, 0,
-                      opnum, type);
-         return 1;
+         if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
+           {
+             tem = make_memloc (ad, regno);
+             if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
+               {
+                 find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
+                                       &XEXP (tem, 0), opnum, ADDR_TYPE (type),
+                                       ind_levels, insn);
+               }
+             /* We can avoid a reload if the register's equivalent memory
+                expression is valid as an indirect memory address.
+                But not all addresses are valid in a mem used as an indirect
+                address: only reg or reg+constant.  */
+
+             if (ind_levels > 0
+                 && strict_memory_address_p (mode, tem)
+                 && (GET_CODE (XEXP (tem, 0)) == REG
+                     || (GET_CODE (XEXP (tem, 0)) == PLUS
+                         && GET_CODE (XEXP (XEXP (tem, 0), 0)) == REG
+                         && CONSTANT_P (XEXP (XEXP (tem, 0), 1)))))
+               {
+                 /* TEM is not the same as what we'll be replacing the
+                    pseudo with after reload, put a USE in front of INSN
+                    in the final reload pass.  */
+                 if (replace_reloads
+                     && num_not_at_initial_offset
+                     && ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+                   {
+                     *loc = tem;
+                     emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+                     /* This doesn't really count as replacing the address
+                        as a whole, since it is still a memory access.  */
+                   }
+                 return 0;
+               }
+             ad = tem;
+           }
        }
 
-      /* We can avoid a reload if the register's equivalent memory expression
-        is valid as an indirect memory address.
-        But not all addresses are valid in a mem used as an indirect address:
-        only reg or reg+constant.  */
-
-      else if (reg_equiv_mem[regno] != 0 && ind_levels > 0
-              && strict_memory_address_p (mode, reg_equiv_mem[regno])
-              && (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == REG
-                  || (GET_CODE (XEXP (reg_equiv_mem[regno], 0)) == PLUS
-                      && GET_CODE (XEXP (XEXP (reg_equiv_mem[regno], 0), 0)) == REG
-                      && CONSTANT_P (XEXP (XEXP (reg_equiv_mem[regno], 0), 1)))))
-       return 0;
-
       /* The only remaining case where we can avoid a reload is if this is a
         hard register that is valid as a base register and which is not the
         subject of a CLOBBER in this insn.  */
@@ -4633,7 +4743,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
        return 0;
 
       subst_reg_equivs_changed = 0;
-      *loc = subst_reg_equivs (ad);
+      *loc = subst_reg_equivs (ad, insn);
 
       if (! subst_reg_equivs_changed)
        return 0;
@@ -4838,7 +4948,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
         registers.  */
 
       subst_reg_equivs_changed = 0;
-      tem = subst_reg_equivs (tem);
+      tem = subst_reg_equivs (tem, insn);
 
       /* Make sure that didn't make the address invalid again.  */
 
@@ -4874,11 +4984,14 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
 \f
 /* Find all pseudo regs appearing in AD
    that are eliminable in favor of equivalent values
-   and do not have hard regs; replace them by their equivalents.  */
+   and do not have hard regs; replace them by their equivalents.
+   INSN, if nonzero, is the insn in which we do the reload.  We put USEs in
+   front of it for pseudos that we have to replace with stack slots.  */
 
 static rtx
-subst_reg_equivs (ad)
+subst_reg_equivs (ad, insn)
      rtx ad;
+     rtx insn;
 {
   register RTX_CODE code = GET_CODE (ad);
   register int i;
@@ -4905,6 +5018,16 @@ subst_reg_equivs (ad)
            subst_reg_equivs_changed = 1;
            return reg_equiv_constant[regno];
          }
+       if (reg_equiv_memory_loc[regno] && num_not_at_initial_offset)
+         {
+           rtx mem = make_memloc (ad, regno);
+           if (! rtx_equal_p (mem, reg_equiv_mem[regno]))
+             {
+               subst_reg_equivs_changed = 1;
+               emit_insn_before (gen_rtx_USE (VOIDmode, ad), insn);
+               return mem;
+             }
+         }
       }
       return ad;
 
@@ -4922,7 +5045,7 @@ subst_reg_equivs (ad)
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
     if (fmt[i] == 'e')
-      XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i));
+      XEXP (ad, i) = subst_reg_equivs (XEXP (ad, i), insn);
   return ad;
 }
 \f
@@ -5195,19 +5318,24 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
 
          /* Handle a register that is equivalent to a memory location
             which cannot be addressed directly.  */
-         if (reg_equiv_address[regno] != 0)
+         if (reg_equiv_memory_loc[regno] != 0
+             && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
            {
              rtx tem = make_memloc (XEXP (x, 0), regno);
-             /* 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
-                need two registers.  */
-             find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
-                                   &XEXP (tem, 0), opnum, type,
-                                   ind_levels, insn);
-             /* 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.  */
+             if (reg_equiv_address[regno]
+                 || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+               {
+                 /* 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
+                    need two registers.  */
+                 find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
+                                       &XEXP (tem, 0), opnum, type,
+                                       ind_levels, insn);
+                 /* 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.  */
+               }
            }
 
          /* If we have a hard register that is ok as an index,
@@ -5240,9 +5368,12 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
                 memory location, since this will make it harder to
                 reuse address reloads, and increases register pressure.
                 Also don't do this if we can probably update x directly.  */
-             rtx equiv = reg_equiv_mem[regno];
+             rtx equiv = (GET_CODE (XEXP (x, 0)) == MEM
+                          ? XEXP (x, 0)
+                          : reg_equiv_mem[regno]);
              int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
              if (insn && GET_CODE (insn) == INSN && equiv
+                 && memory_operand (equiv, GET_MODE (equiv))
 #ifdef HAVE_cc0
                  && ! sets_cc0_p (PATTERN (insn))
 #endif
@@ -5375,11 +5506,18 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
          }
 #endif
 
-       if (reg_equiv_address[regno] != 0)
+       if (reg_equiv_memory_loc[regno]
+           && (reg_equiv_address[regno] != 0 || num_not_at_initial_offset))
          {
-           x = make_memloc (x, regno);
-           find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
-                                 opnum, ADDR_TYPE (type), ind_levels, insn);
+           rtx tem = make_memloc (x, regno);
+           if (reg_equiv_address[regno] != 0
+               || ! rtx_equal_p (tem, reg_equiv_mem[regno]))
+             {
+               x = tem;
+               find_reloads_address (GET_MODE (x), &x, XEXP (x, 0),
+                                     &XEXP (x, 0), opnum, ADDR_TYPE (type),
+                                     ind_levels, insn);
+             }
          }
 
        if (reg_renumber[regno] >= 0)
@@ -6517,6 +6655,12 @@ debug_reload_to_stream (f)
          print_inline_rtx (f, reload_in_reg[r], 24);
        }
 
+      if (reload_out_reg[r] != 0)
+       {
+         fprintf (f, "\n\treload_out_reg: ");
+         print_inline_rtx (f, reload_out_reg[r], 24);
+       }
+
       if (reload_reg_rtx[r] != 0)
        {
          fprintf (f, "\n\treload_reg_rtx: ");
index 41d66164db49a0efd1a160e9e169c870d95c879f..e49da9abc344ee8977ae2a609948d2d48ec509d6 100644 (file)
@@ -55,6 +55,7 @@ extern enum reg_class reload_address_index_reg_class;
 extern rtx reload_in[MAX_RELOADS];
 extern rtx reload_out[MAX_RELOADS];
 extern rtx reload_in_reg[MAX_RELOADS];
+extern rtx reload_out_reg[MAX_RELOADS];
 extern enum reg_class reload_reg_class[MAX_RELOADS];
 extern enum machine_mode reload_inmode[MAX_RELOADS];
 extern enum machine_mode reload_outmode[MAX_RELOADS];
@@ -134,6 +135,8 @@ extern char indirect_symref_ok;
 /* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid.  */
 extern char double_reg_address_ok;
 
+extern int num_not_at_initial_offset;
+
 #ifdef MAX_INSN_CODE
 /* These arrays record the insn_code of insns that may be needed to
    perform input and output reloads of special objects.  They provide a
@@ -233,8 +236,11 @@ extern void clear_secondary_mem PROTO((void));
    reload TO.  */
 extern void transfer_replacements PROTO((int, int));
 
-/* Remove all replacements in reload FROM.  */
-extern void remove_replacements PROTO((int));
+/* IN_RTX is the value loaded by a reload that we now decided to inherit,
+   or a subpart of it.  If we have any replacements registered for IN_RTX,
+   chancel the reloads that were supposed to load them.
+   Return non-zero if we chanceled any reloads.  */
+extern int remove_address_replacements PROTO((rtx in_rtx));
 
 /* Like rtx_equal_p except that it allows a REG and a SUBREG to match
    if they are the same hard reg, and has special hacks for
@@ -250,7 +256,7 @@ extern int safe_from_earlyclobber PROTO((rtx, rtx));
 /* Search the body of INSN for values that need reloading and record them
    with push_reload.  REPLACE nonzero means record also where the values occur
    so that subst_reloads can be used.  */
-extern void find_reloads PROTO((rtx, int, int, int, short *));
+extern int find_reloads PROTO((rtx, int, int, int, short *));
 
 /* Compute the sum of X and Y, making canonicalizations assumed in an
    address, namely: sum constant integers, surround the sum of two
@@ -319,6 +325,9 @@ extern rtx eliminate_regs PROTO((rtx, enum machine_mode, rtx));
    OPNUM with reload type TYPE.  */
 extern rtx gen_reload PROTO((rtx, rtx, int, enum reload_type));
 
+/* Deallocate the reload register used by reload number R.  */
+extern void deallocate_reload_reg PROTO((int r));
+
 /* Functions in caller-save.c:  */
 
 /* Initialize for caller-save.  */
index 06bc9ddbc5b0b995d09a7862983850e1a2fad7ce..d4a5cd6561a5ce8646fbea4db3bec3b1f22948e0 100644 (file)
@@ -148,6 +148,11 @@ static rtx spill_reg_rtx[FIRST_PSEUDO_REGISTER];
    The precise value is the insn generated to do the store.  */
 static rtx spill_reg_store[FIRST_PSEUDO_REGISTER];
 
+/* This is the register that was stored with spill_reg_store.  This is a
+   copy of reload_out / reload_out_reg when the value was stored; if
+   reload_out is a MEM, spill_reg_stored_to will be set to reload_out_reg.  */
+static rtx spill_reg_stored_to[FIRST_PSEUDO_REGISTER];
+
 /* This table is the inverse mapping of spill_regs:
    indexed by hard reg number,
    it contains the position of that reg in spill_regs,
@@ -335,7 +340,7 @@ static struct elim_table
 /* Record the number of pending eliminations that have an offset not equal
    to their initial offset.  If non-zero, we use a new copy of each
    replacement result in any insns encountered.  */
-static int num_not_at_initial_offset;
+int num_not_at_initial_offset;
 
 /* Count the number of registers that we may be able to eliminate.  */
 static int num_eliminable;
@@ -377,6 +382,7 @@ static void delete_dead_insn                PROTO((rtx));
 static void alter_reg                          PROTO((int, int));
 static void set_label_offsets          PROTO((rtx, rtx, int));
 static int eliminate_regs_in_insn      PROTO((rtx, int));
+static void update_eliminable_offsets  PROTO((void));
 static void mark_not_eliminable                PROTO((rtx, rtx));
 static void set_initial_elim_offsets   PROTO((void));
 static void init_elim_table            PROTO((void));
@@ -402,8 +408,10 @@ static int allocate_reload_reg             PROTO((struct insn_chain *, int, int, int));
 static void choose_reload_regs         PROTO((struct insn_chain *, rtx));
 static void merge_assigned_reloads     PROTO((rtx));
 static void emit_reload_insns          PROTO((struct insn_chain *));
-static void delete_output_reload       PROTO((rtx, int, rtx));
-static void inc_for_reload             PROTO((rtx, rtx, int));
+static void delete_output_reload       PROTO((rtx, int, int));
+static void delete_address_reloads     PROTO((rtx, rtx));
+static void delete_address_reloads_1   PROTO((rtx, rtx, rtx));
+static rtx inc_for_reload              PROTO((rtx, rtx, rtx, int));
 static int constraint_accepts_reg_p    PROTO((char *, rtx));
 static void reload_cse_regs_1          PROTO((rtx));
 static void reload_cse_invalidate_regno        PROTO((int, enum machine_mode, int));
@@ -582,6 +590,8 @@ compute_use_by_pseudos (to, from)
 
 /* Set during calculate_needs if an insn needs register elimination.  */
 static int something_needs_elimination;
+/* Set during calculate_needs if an insn needs an operand changed.  */
+int something_needs_operands_changed;
 
 /* For each class, number of reload regs needed in that class.
    This is the maximum over all insns of the needs in that class
@@ -920,6 +930,7 @@ reload (first, global, dumpfile)
   /* This flag is set if there are any insns that require register
      eliminations.  */
   something_needs_elimination = 0;
+  something_needs_operands_changed = 0;
   while (something_changed)
     {
       HOST_WIDE_INT starting_frame_size;
@@ -1399,6 +1410,7 @@ calculate_needs_all_insns (global)
 {
   int something_changed = 0;
   rtx after_call = 0;
+  int after_call_nregs;
   struct insn_chain **pprev_reload = &insns_need_reload;
   struct insn_chain *chain;
 
@@ -1424,6 +1436,7 @@ calculate_needs_all_insns (global)
          int old_code = INSN_CODE (insn);
          rtx old_notes = REG_NOTES (insn);
          int did_elimination = 0;
+         int operands_changed = 0;
 
          /* Nonzero means don't use a reload reg that overlaps
             the place where a function value can be returned.  */
@@ -1434,21 +1447,44 @@ calculate_needs_all_insns (global)
          if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
            {
              if (GET_CODE (PATTERN (insn)) == SET)
-               after_call = SET_DEST (PATTERN (insn));
+               {
+                 after_call = SET_DEST (PATTERN (insn));
+                 after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
+                                                      GET_MODE (after_call));
+               }
              else if (GET_CODE (PATTERN (insn)) == PARALLEL
                       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
-               after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+               {
+                 after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+                 after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
+                                                      GET_MODE (after_call));
+               }
              else
                after_call = 0;
            }
          else if (SMALL_REGISTER_CLASSES && after_call != 0
                   && !(GET_CODE (PATTERN (insn)) == SET
                        && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+                  && GET_CODE (PATTERN (insn)) != CLOBBER
                   && GET_CODE (PATTERN (insn)) != USE)
            {
              if (reg_referenced_p (after_call, PATTERN (insn)))
-               avoid_return_reg = after_call;
-             after_call = 0;
+               {
+                 avoid_return_reg = after_call;
+                 if (! --after_call_nregs)
+                   after_call = 0;
+                 else
+                   {
+                     /* If INSN copies the return register in a single chunk,
+                        clear after_call now.  */
+                     rtx set = single_set (insn);
+                     if (set && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
+                                 == GET_MODE_SIZE (GET_MODE (after_call))))
+                       after_call = 0;
+                   }
+               }
+             else
+               after_call = 0;
            }
 
          /* If needed, eliminate any eliminable registers.  */
@@ -1456,13 +1492,37 @@ calculate_needs_all_insns (global)
            did_elimination = eliminate_regs_in_insn (insn, 0);
 
          /* Analyze the instruction.  */
-         find_reloads (insn, 0, spill_indirect_levels, global,
-                       spill_reg_order);
+         operands_changed = find_reloads (insn, 0, spill_indirect_levels,
+                                          global, spill_reg_order);
+
+         /* If a no-op set needs more than one reload, this is likely
+            to be something that needs input address reloads.  We
+            can't get rid of this cleanly later, and it is of no use
+            anyway, so discard it now.
+            We only do this when expensive_optimizations is enabled,
+            since this complements reload inheritance / output
+            reload deletion, and it can make debugging harder.  */
+         if (flag_expensive_optimizations && n_reloads > 1)
+           {
+             rtx set = single_set (insn);
+             if (set
+                 && SET_SRC (set) == SET_DEST (set)
+                 && GET_CODE (SET_SRC (set)) == REG
+                 && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
+               {
+                 PUT_CODE (insn, NOTE);
+                 NOTE_SOURCE_FILE (insn) = 0;
+                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+                 continue;
+               }
+           }
+         if (num_eliminable)
+           update_eliminable_offsets ();
 
          /* Remember for later shortcuts which insns had any reloads or
             register eliminations.  */
          chain->need_elim = did_elimination;
-         chain->need_reload = n_reloads > 0;
+         chain->need_reload = (n_reloads > 0 | operands_changed);
 
          /* Discard any register replacements done.  */
          if (did_elimination)
@@ -1474,6 +1534,8 @@ calculate_needs_all_insns (global)
              something_needs_elimination = 1;
            }
 
+         something_needs_operands_changed |= operands_changed;
+
          if (n_reloads != 0)
            {
              *pprev_reload = chain;
@@ -2895,27 +2957,6 @@ eliminate_regs (x, mem_mode, insn)
              }
 
        }
-      else if (reg_equiv_memory_loc && reg_equiv_memory_loc[regno]
-              && (reg_equiv_address[regno] || num_not_at_initial_offset))
-       {
-         /* In this case, find_reloads would attempt to either use an
-            incorrect address (if something is not at its initial offset)
-            or substitute an replaced address into an insn (which loses
-            if the offset is changed by some later action).  So we simply
-            return the replaced stack slot (assuming it is changed by
-            elimination) and ignore the fact that this is actually a
-            reference to the pseudo.  Ensure we make a copy of the
-            address in case it is shared.  */
-         new = eliminate_regs (reg_equiv_memory_loc[regno], mem_mode, insn);
-         if (new != reg_equiv_memory_loc[regno])
-           {
-             if (insn != 0 && GET_CODE (insn) != EXPR_LIST
-                 && GET_CODE (insn) != INSN_LIST)
-               REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, x), insn))
-                 = gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
-             return copy_rtx (new);
-           }
-       }
       return x;
 
     case PLUS:
@@ -3123,6 +3164,7 @@ eliminate_regs (x, mem_mode, insn)
          && reg_equiv_memory_loc != 0
          && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
        {
+#if 0
          new = eliminate_regs (reg_equiv_memory_loc[REGNO (SUBREG_REG (x))],
                                mem_mode, insn);
 
@@ -3143,6 +3185,9 @@ eliminate_regs (x, mem_mode, insn)
              /* Ensure NEW isn't shared in case we have to reload it.  */
              new = copy_rtx (new);
            }
+#else
+         new = SUBREG_REG (x);
+#endif
        }
       else
        new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
@@ -3505,7 +3550,7 @@ eliminate_regs_in_insn (insn, replace)
         in the insn is the negative of the offset in FROM.  Substitute
         (set (reg) (reg to)) for the insn and change its code.
 
-        We have to do this here, rather than in eliminate_regs, do that we can
+        We have to do this here, rather than in eliminate_regs, so that we can
         change the insn code.  */
 
       if (GET_CODE (SET_SRC (old_set)) == PLUS
@@ -3592,11 +3637,7 @@ eliminate_regs_in_insn (insn, replace)
       val = 1;
     }
 
-  /* Loop through all elimination pairs.  See if any have changed and
-     recalculate the number not at initial offset.
-
-     Compute the maximum offset (minimum offset if the stack does not
-     grow downward) for each elimination pair.
+  /* Loop through all elimination pairs.  See if any have changed.
 
      We also detect a cases where register elimination cannot be done,
      namely, if a register would be both changed and referenced outside a MEM
@@ -3607,7 +3648,6 @@ eliminate_regs_in_insn (insn, replace)
 
      If anything changes, return nonzero.  */
 
-  num_not_at_initial_offset = 0;
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     {
       if (ep->previous_offset != ep->offset && ep->ref_outside_mem)
@@ -3617,16 +3657,6 @@ eliminate_regs_in_insn (insn, replace)
 
       if (ep->previous_offset != ep->offset)
        val = 1;
-
-      ep->previous_offset = ep->offset;
-      if (ep->can_eliminate && ep->offset != ep->initial_offset)
-       num_not_at_initial_offset++;
-
-#ifdef STACK_GROWS_DOWNWARD
-      ep->max_offset = MAX (ep->max_offset, ep->offset);
-#else
-      ep->max_offset = MIN (ep->max_offset, ep->offset);
-#endif
     }
 
  done:
@@ -3644,6 +3674,32 @@ eliminate_regs_in_insn (insn, replace)
   return val;
 }
 
+/* Loop through all elimination pairs.
+   Recalculate the number not at initial offset.
+
+   Compute the maximum offset (minimum offset if the stack does not
+   grow downward) for each elimination pair.  */
+
+static void
+update_eliminable_offsets ()
+{
+  struct elim_table *ep;
+
+  num_not_at_initial_offset = 0;
+  for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+    {
+      ep->previous_offset = ep->offset;
+      if (ep->can_eliminate && ep->offset != ep->initial_offset)
+       num_not_at_initial_offset++;
+
+#ifdef STACK_GROWS_DOWNWARD
+      ep->max_offset = MAX (ep->max_offset, ep->offset);
+#else
+      ep->max_offset = MIN (ep->max_offset, ep->offset);
+#endif
+    }
+}
+
 /* Given X, a SET or CLOBBER of DEST, if DEST is the target of a register
    replacement we currently believe is valid, mark it as not eliminable if X
    modifies DEST in any way other than by adding a constant integer to it.
@@ -4170,6 +4226,7 @@ reload_as_needed (live_known)
   register int i;
   rtx x;
   rtx after_call = 0;
+  int after_call_nregs;
 
   bzero ((char *) spill_reg_rtx, sizeof spill_reg_rtx);
   bzero ((char *) spill_reg_store, sizeof spill_reg_store);
@@ -4208,6 +4265,7 @@ reload_as_needed (live_known)
     {
       rtx insn = chain->insn;
       rtx old_next = NEXT_INSN (insn);
+      rtx prev;
 
       /* If we pass a label, copy the offsets from the label information
         into the current offsets of each elimination.  */
@@ -4235,21 +4293,44 @@ reload_as_needed (live_known)
          if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
            {
              if (GET_CODE (PATTERN (insn)) == SET)
-               after_call = SET_DEST (PATTERN (insn));
+               {
+                 after_call = SET_DEST (PATTERN (insn));
+                 after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
+                                                      GET_MODE (after_call));
+               }
              else if (GET_CODE (PATTERN (insn)) == PARALLEL
                       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
-               after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+               {
+                 after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+                 after_call_nregs = HARD_REGNO_NREGS (REGNO (after_call),
+                                                      GET_MODE (after_call));
+               }
              else
                after_call = 0;
            }
          else if (SMALL_REGISTER_CLASSES && after_call != 0
                   && !(GET_CODE (PATTERN (insn)) == SET
                        && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+                  && GET_CODE (PATTERN (insn)) != CLOBBER
                   && GET_CODE (PATTERN (insn)) != USE)
            {
              if (reg_referenced_p (after_call, PATTERN (insn)))
-               avoid_return_reg = after_call;
-             after_call = 0;
+               {
+                 avoid_return_reg = after_call;
+                 if (! --after_call_nregs)
+                   after_call = 0;
+                 else
+                   {
+                     /* If INSN copies the return register in a single chunk,
+                        clear after_call now.  */
+                     rtx set = single_set (insn);
+                     if (set && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
+                                 == GET_MODE_SIZE (GET_MODE (after_call))))
+                       after_call = 0;
+                   }
+               }
+             else
+               after_call = 0;
            }
 
          /* If this is a USE and CLOBBER of a MEM, ensure that any
@@ -4269,7 +4350,10 @@ reload_as_needed (live_known)
            {
              eliminate_regs_in_insn (insn, 1);
              if (GET_CODE (insn) == NOTE)
-               continue;
+               {
+                 update_eliminable_offsets ();
+                 continue;
+               }
            }
 
          /* If need_elim is nonzero but need_reload is zero, one might think
@@ -4294,12 +4378,17 @@ reload_as_needed (live_known)
                            spill_reg_order);
            }
 
+         if (num_eliminable && GET_MODE (insn) == QImode)
+           update_eliminable_offsets ();
+
          if (n_reloads > 0)
            {
-             rtx prev = PREV_INSN (insn), next = NEXT_INSN (insn);
+             rtx next = NEXT_INSN (insn);
              rtx p;
              int class;
 
+             prev = PREV_INSN (insn);
+
              /* If this block has not had spilling done for a
                 particular clas and we have any non-optionals that need a
                 spill reg in that class, abort.  */
@@ -4370,6 +4459,54 @@ reload_as_needed (live_known)
              note_stores (PATTERN (x), forget_old_reloads_1);
 
 #ifdef AUTO_INC_DEC
+         /* Likewise for regs altered by auto-increment in this insn.
+            REG_INC notes have been changed by reloading:
+            find_reloads_address_1 records substitutions for them,
+            which have been performed by subst_reloads above.  */
+         for (i = n_reloads - 1; i >= 0; i--)
+           {
+             rtx in_reg = reload_in_reg[i];
+             if (in_reg)
+               {
+                 enum rtx_code code = GET_CODE (in_reg);
+                 /* PRE_INC / PRE_DEC will have the reload register ending up
+                    with the same value as the stack slot, but that doesn't
+                    hold true for POST_INC / POST_DEC.  Either we have to
+                    convert the memory access to a true POST_INC / POST_DEC,
+                    or we can't use the reload register for inheritance.  */
+                 if ((code == POST_INC || code == POST_DEC)
+                     && TEST_HARD_REG_BIT (reg_reloaded_valid,
+                                           REGNO (reload_reg_rtx[i])))
+                   {
+                     rtx reload_reg = reload_reg_rtx[i];
+                     enum machine_mode mode = GET_MODE (reload_reg);
+                     int n = 0;
+                     rtx p;
+
+                     for (p = PREV_INSN (old_next); p != prev; p = PREV_INSN (p))
+                       {
+                         /* We really want to ignore REG_INC notes here, so
+                            use PATTERN (p) as argument to reg_set_p .  */
+                         if (reg_set_p (reload_reg, PATTERN (p)))
+                           break;
+                         n = count_occurrences (PATTERN (p), reload_reg);
+                         if (! n)
+                           continue;
+                         if (n == 1)
+                           n = validate_replace_rtx (reload_reg,
+                                                     gen_rtx (code, mode,
+                                                              reload_reg), p);
+                         break;
+                       }
+                     if (n == 1)
+                       REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_INC, reload_reg,
+                                                          REG_NOTES (p));
+                     else
+                       forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX);
+                   }
+               }
+           }
+#if 0 /* ??? Is this code obsolete now?  Need to check carefully. */
          /* Likewise for regs altered by auto-increment in this insn.
             But note that the reg-notes are not changed by reloading:
             they still contain the pseudo-regs, not the spill regs.  */
@@ -4386,6 +4523,7 @@ reload_as_needed (live_known)
                if (i == n_reloads)
                  forget_old_reloads_1 (XEXP (x, 0), NULL_RTX);
              }
+#endif
 #endif
        }
       /* A reload reg's contents are unknown after a label.  */
@@ -4622,57 +4760,104 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
      enum machine_mode mode;
 {
   int nregs = HARD_REGNO_NREGS (regno, mode);
+  int start_regno, end_regno;
   int i;
+  /* A complication is that for some reload types, inheritance might
+     allow multiple reloads of the same types to share a reload register.
+     We set check_opnum if we have to check only reloads with the same
+     operand number, and check_any if we have to check all reloads.  */
+  int check_opnum = 0;
+  int check_any = 0;
+  HARD_REG_SET *used_in_set;
 
-  for (i = regno; i < nregs + regno; i++)
+  switch (type)
     {
-      switch (type)
-       {
-       case RELOAD_OTHER:
-         CLEAR_HARD_REG_BIT (reload_reg_used, i);
-         break;
+    case RELOAD_OTHER:
+      used_in_set = &reload_reg_used;
+      break;
 
-       case RELOAD_FOR_INPUT_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
-         break;
+    case RELOAD_FOR_INPUT_ADDRESS:
+      used_in_set = &reload_reg_used_in_input_addr[opnum];
+      break;
 
-       case RELOAD_FOR_INPADDR_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
-         break;
+    case RELOAD_FOR_INPADDR_ADDRESS:
+      check_opnum = 1;
+      used_in_set = &reload_reg_used_in_inpaddr_addr[opnum];
+      break;
 
-       case RELOAD_FOR_OUTPUT_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
-         break;
+    case RELOAD_FOR_OUTPUT_ADDRESS:
+      used_in_set = &reload_reg_used_in_output_addr[opnum];
+      break;
 
-       case RELOAD_FOR_OUTADDR_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
-         break;
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      check_opnum = 1;
+      used_in_set = &reload_reg_used_in_outaddr_addr[opnum];
+      break;
 
-       case RELOAD_FOR_OPERAND_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
-         break;
+    case RELOAD_FOR_OPERAND_ADDRESS:
+      used_in_set = &reload_reg_used_in_op_addr;
+      break;
 
-       case RELOAD_FOR_OPADDR_ADDR:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i);
-         break;
+    case RELOAD_FOR_OPADDR_ADDR:
+      check_any = 1;
+      used_in_set = &reload_reg_used_in_op_addr_reload;
+      break;
 
-       case RELOAD_FOR_OTHER_ADDRESS:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
-         break;
+    case RELOAD_FOR_OTHER_ADDRESS:
+      used_in_set = &reload_reg_used_in_other_addr;
+      check_any = 1;
+      break;
 
-       case RELOAD_FOR_INPUT:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
-         break;
+    case RELOAD_FOR_INPUT:
+      used_in_set = &reload_reg_used_in_input[opnum];
+      break;
 
-       case RELOAD_FOR_OUTPUT:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
-         break;
+    case RELOAD_FOR_OUTPUT:
+      used_in_set = &reload_reg_used_in_output[opnum];
+      break;
 
-       case RELOAD_FOR_INSN:
-         CLEAR_HARD_REG_BIT (reload_reg_used_in_insn, i);
-         break;
+    case RELOAD_FOR_INSN:
+      used_in_set = &reload_reg_used_in_insn;
+      break;
+    default:
+      abort ();
+    }
+  /* We resolve conflicts with remaining reloads of the same type by
+     excluding the intervals of of reload registers by them from the
+     interval of freed reload registers.  Since we only keep track of
+     one set of interval bounds, we might have to exclude somewhat
+     more then what would be necessary if we used a HARD_REG_SET here.
+     But this should only happen very infrequently, so there should
+     be no reason to worry about it.  */
+    
+  start_regno = regno;
+  end_regno = regno + nregs;
+  if (check_opnum || check_any)
+    {
+      for (i = n_reloads - 1; i >= 0; i--)
+       {
+         if (reload_when_needed[i] == type
+             && (check_any || reload_opnum[i] == opnum)
+             && reload_reg_rtx[i])
+           {
+             int conflict_start = true_regnum (reload_reg_rtx[i]);
+             int conflict_end
+               = (conflict_start
+                  + HARD_REGNO_NREGS (conflict_start, reload_mode[i]));
+
+             /* If there is an overlap with the first to-be-freed register,
+                adjust the interval start.  */
+             if (conflict_start <= start_regno && conflict_end > start_regno)
+               start_regno = conflict_end;
+             /* Otherwise, if there is a conflict with one of the other
+                to-be-freed registers, adjust the interval end.  */
+             if (conflict_start > start_regno && conflict_start < end_regno)
+               end_regno = conflict_start;
+           }
        }
     }
+  for (i = start_regno; i < end_regno; i++)
+    CLEAR_HARD_REG_BIT (*used_in_set, i);
 }
 
 /* 1 if reg REGNO is free as a reload reg for a reload of the sort
@@ -4953,9 +5138,11 @@ reload_reg_free_before_p (regno, opnum, type, equiv)
 
       /* The only things earlier are the address for this and
         earlier inputs, other inputs (which we know we don't conflict
-        with), and addresses of RELOAD_OTHER objects.  */
+        with), and addresses of RELOAD_OTHER objects.
+        We can ignore the conflict with addresses of this operand, since
+         when we inherit this operand, its address reloads are discarded.  */
 
-      for (i = 0; i <= opnum; i++)
+      for (i = 0; i < opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
          return 0;
@@ -5268,18 +5455,26 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
     case RELOAD_FOR_INPUT_ADDRESS:
       time1 = opnum * 4 + 2;
       break;
+    case RELOAD_FOR_OPADDR_ADDR:
+    /* opnum * 4 + 3 < opnum * 4 + 4
+       <= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
+      time1 = MAX_RECOG_OPERANDS * 4;
+      break;
     case RELOAD_FOR_INPUT:
       /* All RELOAD_FOR_INPUT reloads remain live till just before the
         instruction is executed.  */
-      time1 = (MAX_RECOG_OPERANDS - 1) * 4 + 3;
+      time1 = MAX_RECOG_OPERANDS * 4 + 1;
+      break;
+    case RELOAD_FOR_OPERAND_ADDRESS:
+      /* RELOAD_FOR_OPERAND_ADDRESS reloads are live even while the insn
+        is executed.  */
+      time1 = MAX_RECOG_OPERANDS * 4 + 2;
       break;
-    /* opnum * 4 + 3 < opnum * 4 + 4
-       <= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
     case RELOAD_FOR_OUTPUT_ADDRESS:
-      time1 = MAX_RECOG_OPERANDS * 4 + opnum;
+      time1 = MAX_RECOG_OPERANDS * 4 + 3 + opnum;
       break;
     default:
-      time1 = MAX_RECOG_OPERANDS * 5;
+      time1 = MAX_RECOG_OPERANDS * 5 + 3;
     }
 
   for (i = 0; i < n_reloads; i++)
@@ -5305,6 +5500,14 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
                  time2 = 0;
                  break;
                case RELOAD_FOR_INPADDR_ADDRESS:
+                 /* find_reloads makes sure that a
+                    RELOAD_FOR_{INP,OP,OUT}ADDR_ADDRESS reload is only used
+                    by at most one - the first -
+                    RELOAD_FOR_{INPUT,OPERAND,OUTPUT}_ADDRESS .  If the
+                    address reload is inherited, the address address reload
+                    goes away, so we can ignore this conflict.  */
+                 if (type == RELOAD_FOR_INPUT_ADDRESS && reloadnum == i + 1)
+                   continue;
                  time2 = reload_opnum[i] * 4 + 1;
                  break;
                case RELOAD_FOR_INPUT_ADDRESS:
@@ -5313,20 +5516,32 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
                case RELOAD_FOR_INPUT:
                  time2 = reload_opnum[i] * 4 + 3;
                  break;
+               case RELOAD_FOR_OPADDR_ADDR:
+                 if (type == RELOAD_FOR_OPERAND_ADDRESS && reloadnum == i + 1)
+                   continue;
+                 time2 = MAX_RECOG_OPERANDS * 4;
+                 break;
+               case RELOAD_FOR_OPERAND_ADDRESS:
+                 time2 = MAX_RECOG_OPERANDS * 4 + 1;
+                 break;
                case RELOAD_FOR_OUTPUT:
                /* All RELOAD_FOR_OUTPUT reloads become live just after the
                   instruction is executed.  */
-                 time2 = MAX_RECOG_OPERANDS * 4;
+                 time2 = MAX_RECOG_OPERANDS * 4 + 3;
                  break;
+               case RELOAD_FOR_OUTADDR_ADDRESS:
+                 if (type == RELOAD_FOR_OUTPUT_ADDRESS && reloadnum == i + 1)
+                   continue;
+               /* fall through. */
                /* The first RELOAD_FOR_OUTPUT_ADDRESS reload conflicts with the
                   RELOAD_FOR_OUTPUT reloads, so assign it the same time value.  */
                case RELOAD_FOR_OUTPUT_ADDRESS:
-                 time2 = MAX_RECOG_OPERANDS * 4 + reload_opnum[i];
+                 time2 = MAX_RECOG_OPERANDS * 4 + 3 + reload_opnum[i];
                  break;
                case RELOAD_OTHER:
                  if (! reload_in[i] || rtx_equal_p (reload_in[i], value))
                    {
-                     time2 = MAX_RECOG_OPERANDS * 4;
+                     time2 = MAX_RECOG_OPERANDS * 4 + 3;
                      break;
                    }
                default:
@@ -5566,6 +5781,7 @@ choose_reload_regs (chain, avoid_return_reg)
   int max_group_size = 1;
   enum reg_class group_class = NO_REGS;
   int inheritance;
+  int pass;
 
   rtx save_reload_reg_rtx[MAX_RELOADS];
   char save_reload_inherited[MAX_RELOADS];
@@ -5823,6 +6039,7 @@ choose_reload_regs (chain, avoid_return_reg)
 
          if (inheritance)
            {
+             int word = 0;
              register int regno = -1;
              enum machine_mode mode;
 
@@ -5838,33 +6055,27 @@ choose_reload_regs (chain, avoid_return_reg)
                  regno = REGNO (reload_in_reg[r]);
                  mode = GET_MODE (reload_in_reg[r]);
                }
-             else if (GET_CODE (reload_in[r]) == MEM)
+             else if (GET_CODE (reload_in_reg[r]) == SUBREG
+                      && GET_CODE (SUBREG_REG (reload_in_reg[r])) == REG)
                {
-                 rtx prev = prev_nonnote_insn (insn), note;
-
-                 if (prev && GET_CODE (prev) == INSN
-                     && GET_CODE (PATTERN (prev)) == USE
-                     && GET_CODE (XEXP (PATTERN (prev), 0)) == REG
-                     && (REGNO (XEXP (PATTERN (prev), 0))
-                         >= FIRST_PSEUDO_REGISTER)
-                     && (note = find_reg_note (prev, REG_EQUAL, NULL_RTX))
-                     && GET_CODE (XEXP (note, 0)) == MEM)
-                   {
-                     rtx addr = XEXP (XEXP (note, 0), 0);
-                     int size_diff
-                       = (GET_MODE_SIZE (GET_MODE (addr))
-                          - GET_MODE_SIZE (GET_MODE (reload_in[r])));
-                     if (size_diff >= 0
-                         && rtx_equal_p ((BYTES_BIG_ENDIAN
-                                          ? plus_constant (addr, size_diff)
-                                          : addr),
-                                         XEXP (reload_in[r], 0)))
-                       {
-                         regno = REGNO (XEXP (PATTERN (prev), 0));
-                         mode = GET_MODE (reload_in[r]);
-                       }
-                   }
+                 word = SUBREG_WORD (reload_in_reg[r]);
+                 regno = REGNO (SUBREG_REG (reload_in_reg[r]));
+                 if (regno < FIRST_PSEUDO_REGISTER)
+                   regno += word;
+                 mode = GET_MODE (reload_in_reg[r]);
+               }
+#ifdef AUTO_INC_DEC
+             else if ((GET_CODE (reload_in_reg[r]) == PRE_INC
+                       || GET_CODE (reload_in_reg[r]) == PRE_DEC
+                       || GET_CODE (reload_in_reg[r]) == POST_INC
+                       || GET_CODE (reload_in_reg[r]) == POST_DEC)
+                      && GET_CODE (XEXP (reload_in_reg[r], 0)) == REG)
+               {
+                 regno = REGNO (XEXP (reload_in_reg[r], 0));
+                 mode = GET_MODE (XEXP (reload_in_reg[r], 0));
+                 reload_out[r] = reload_in[r];
                }
+#endif
 #if 0
              /* This won't work, since REGNO can be a pseudo reg number.
                 Also, it takes much more hair to keep track of all the things
@@ -5876,15 +6087,34 @@ choose_reload_regs (chain, avoid_return_reg)
 
              if (regno >= 0 && reg_last_reload_reg[regno] != 0)
                {
-                 i = REGNO (reg_last_reload_reg[regno]);
-
-                 if (reg_reloaded_contents[i] == regno
+                 enum reg_class class = reload_reg_class[r], last_class;
+                 rtx last_reg = reg_last_reload_reg[regno];
+                 
+                 i = REGNO (last_reg) + word;
+                 last_class = REGNO_REG_CLASS (i);
+                 if ((GET_MODE_SIZE (GET_MODE (last_reg))
+                      >= GET_MODE_SIZE (mode) + word * UNITS_PER_WORD)
+                     && reg_reloaded_contents[i] == regno
                      && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
-                     && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
-                         >= GET_MODE_SIZE (mode))
                      && HARD_REGNO_MODE_OK (i, reload_mode[r])
-                     && TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
-                                           i)
+                     && (TEST_HARD_REG_BIT (reg_class_contents[(int) class], i)
+                         /* Even if we can't use this register as a reload
+                            register, we might use it for reload_override_in,
+                            if copying it to the desired class is cheap
+                            enough.  */
+                         || ((REGISTER_MOVE_COST (last_class, class)
+                              < MEMORY_MOVE_COST (mode, class, 1))
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+                             && (SECONDARY_INPUT_RELOAD_CLASS (class, mode,
+                                                               last_reg)
+                                 == NO_REGS)
+#endif
+#ifdef SECONDARY_MEMORY_NEEDED
+                             && ! SECONDARY_MEMORY_NEEDED (last_class, class,
+                                                           mode)
+#endif
+                             ))
+
                      && (reload_nregs[r] == max_group_size
                          || ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
                                                  i))
@@ -5913,6 +6143,9 @@ choose_reload_regs (chain, avoid_return_reg)
                        {
                          int i1;
 
+                         last_reg = (GET_MODE (last_reg) == mode
+                                     ? last_reg : gen_rtx_REG (mode, i));
+
                          /* We found a register that contains the
                             value we need.  If this register is the
                             same as an `earlyclobber' operand of the
@@ -5935,13 +6168,20 @@ choose_reload_regs (chain, avoid_return_reg)
                                 if we need it wider than we've got it.  */
                              || (GET_MODE_SIZE (reload_mode[r])
                                  > GET_MODE_SIZE (mode))
+                             || ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
+                                                     i)
+
                              /* If find_reloads chose reload_out as reload
                                 register, stay with it - that leaves the
                                 inherited register for subsequent reloads.  */
                              || (reload_out[r] && reload_reg_rtx
                                  && rtx_equal_p (reload_out[r],
                                                  reload_reg_rtx[r])))
-                           reload_override_in[r] = reg_last_reload_reg[regno];
+                           {
+                             reload_override_in[r] = last_reg;
+                             reload_inheritance_insn[r]
+                               = reg_reloaded_insn[i];
+                           }
                          else
                            {
                              int k;
@@ -5952,7 +6192,7 @@ choose_reload_regs (chain, avoid_return_reg)
                                                      reload_opnum[r],
                                                      reload_when_needed[r],
                                                      reload_mode[r]);
-                             reload_reg_rtx[r] = reg_last_reload_reg[regno];
+                             reload_reg_rtx[r] = last_reg;
                              reload_inherited[r] = 1;
                              reload_inheritance_insn[r]
                                = reg_reloaded_insn[i];
@@ -6003,21 +6243,15 @@ choose_reload_regs (chain, avoid_return_reg)
              /* If we found a spill reg, reject it unless it is free
                 and of the desired class.  */
              if (equiv != 0
-                 && ((spill_reg_order[regno] >= 0
-                      && ! (reload_reg_free_before_p (regno, reload_opnum[r],
-                                                      reload_when_needed[r], 1)
-                            || reload_reg_free_for_value_p (regno,
-                                                            reload_opnum[r],
-                                                            reload_when_needed[r],
-                                                            reload_in[r],
-                                                            reload_out[r], r)))
+                 && ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
+                      && ! reload_reg_free_for_value_p (regno, reload_opnum[r],
+                                                        reload_when_needed[r],
+                                                        reload_in[r],
+                                                        reload_out[r], r))
                      || ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
                                              regno)))
                equiv = 0;
 
-             if (equiv != 0 && TEST_HARD_REG_BIT (reload_reg_used_at_all, regno))
-               equiv = 0;
-
              if (equiv != 0 && ! HARD_REGNO_MODE_OK (regno, reload_mode[r]))
                equiv = 0;
 
@@ -6204,75 +6438,57 @@ choose_reload_regs (chain, avoid_return_reg)
 
   /* If we thought we could inherit a reload, because it seemed that
      nothing else wanted the same reload register earlier in the insn,
-     verify that assumption, now that all reloads have been assigned.  */
+     verify that assumption, now that all reloads have been assigned.
+     Likewise for reloads where reload_override_in has been set.  */
 
-  for (j = 0; j < n_reloads; j++)
+  /* If doing expensive optimizations, do one preliminary pass that doesn't
+     cancel any inheritance, but removes reloads that have been needed only
+     for reloads that we know can be inherited.  */
+  for (pass = flag_expensive_optimizations; pass >= 0; pass--)
     {
-      register int r = reload_order[j];
-
-      if (reload_inherited[r] && reload_reg_rtx[r] != 0
-         && ! (reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
-                                         reload_opnum[r],
-                                         reload_when_needed[r], 0)
-               || reload_reg_free_for_value_p (true_regnum (reload_reg_rtx[r]),
-                                               reload_opnum[r],
-                                               reload_when_needed[r],
-                                               reload_in[r],
-                                               reload_out[r], r)))
-       reload_inherited[r] = 0;
-      /* If we can inherit a RELOAD_FOR_INPUT, then we do not need its related
-        RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads.
-        ??? This could be extended to other reload types, but these are
-         more tricky to handle:
-        RELOAD_FOR_OTHER_ADDRESS reloads might have been merged, so we
-        can't eliminate them without a check that *all* references are
-        now unused due to inheritance.
-        While RELOAD_FOR_INPADDR_ADDRESS and RELOAD_FOR_OUTADDR_ADDRESS are
-        not merged, we can't be sure that we have eliminated the use of
-        that particular reload if we have seen just one
-        RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS being inherited,
-        since there might be multiple of the latter two reloads for a single
-        operand.
-        RELOAD_FOR_OPADDR_ADDR reloads for different operands are not
-        merged, but might share the same register by courtesy of
-        reload_reg_free_for_value_p.  reload_reg_used_in_op_addr_reload
-        does not differentiate by opnum, thus calling clear_reload_reg_in_use
-        for one of these reloads would mark the register as free even though
-        another RELOAD_FOR_OPADDR_ADDR reload might still use it.  */
-      else if (reload_inherited[r] && reload_when_needed[r] == RELOAD_FOR_INPUT)
+      for (j = 0; j < n_reloads; j++)
        {
-         for (i = 0; i < n_reloads; i++)
+         register int r = reload_order[j];
+         rtx check_reg;
+
+         if (reload_inherited[r] && reload_reg_rtx[r])
+           check_reg = reload_reg_rtx[r];
+         else if (reload_override_in[r]
+                  && (GET_CODE (reload_override_in[r]) == REG
+                            || GET_CODE (reload_override_in[r]) == SUBREG))
+           check_reg = reload_override_in[r];
+         else
+           continue;
+         if (! (reload_reg_free_before_p (true_regnum (check_reg),
+                                      reload_opnum[r], reload_when_needed[r],
+                                      ! reload_inherited[r])
+                || reload_reg_free_for_value_p (true_regnum (check_reg),
+                                            reload_opnum[r],
+                                            reload_when_needed[r],
+                                            reload_in[r],
+                                            reload_out[r], r)))
            {
-             if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
-                  || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
-                 && reload_opnum[i] == reload_opnum[r]
-                 && reload_in[i] && reload_reg_rtx[i])
-               {
-                 int regno = true_regnum (reload_reg_rtx[i]);
-
-                 reload_in[i] = 0;
-                 if (spill_reg_order[regno] >= 0)
-                   clear_reload_reg_in_use (regno, reload_opnum[i],
-                                            reload_when_needed[i],
-                                            reload_mode[i]);
-                 reload_reg_rtx[i] = 0;
-                 reload_spill_index[i] = -1;
-                 remove_replacements (i);
-               }
+             if (pass)
+               continue;
+             reload_inherited[r] = 0;
+             reload_override_in[r] = 0;
            }
-       }
-
-      /* If we found a better place to reload from,
-        validate it in the same fashion, if it is a reload reg.  */
-      if (reload_override_in[r]
-         && (GET_CODE (reload_override_in[r]) == REG
-             || GET_CODE (reload_override_in[r]) == SUBREG))
-       {
-         int regno = true_regnum (reload_override_in[r]);
-         if (spill_reg_order[regno] >= 0
-             && ! reload_reg_free_before_p (regno, reload_opnum[r],
-                                            reload_when_needed[r], 1))
-           reload_override_in[r] = 0;
+         /* If we can inherit a RELOAD_FOR_INPUT, or can use a
+            reload_override_in, then we do not need its related
+            RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads;
+            likewise for other reload types.
+            We handle this by removing a reload when its only replacement
+            is mentioned in reload_in of the reload we are going to inherit.
+            A special case are auto_inc expressions; even if the input is
+            inherited, we still need the address for the output.  We can
+            recognize them because they have RELOAD_OUT set but not
+            RELOAD_OUT_REG.
+            If we suceeded removing some reload and we are doing a preliminary
+            pass just to remove such reloads, make another pass, since the
+            removal of one reload might allow us to inherit another one.  */
+         else if ((! reload_out[r] || reload_out_reg[r])
+                  && remove_address_replacements (reload_in[r]) && pass)
+           pass = 2;
        }
     }
 
@@ -6309,10 +6525,10 @@ choose_reload_regs (chain, avoid_return_reg)
       /* I is nonneg if this reload uses a register.
         If reload_reg_rtx[r] is 0, this is an optional reload
         that we opted to ignore.  */
-      if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG
+      if (reload_out_reg[r] != 0 && GET_CODE (reload_out_reg[r]) == REG
          && reload_reg_rtx[r] != 0)
        {
-         register int nregno = REGNO (reload_out[r]);
+         register int nregno = REGNO (reload_out_reg[r]);
          int nr = 1;
 
          if (nregno < FIRST_PSEUDO_REGISTER)
@@ -6335,6 +6551,24 @@ choose_reload_regs (chain, avoid_return_reg)
        }
     }
 }
+
+/* Deallocate the reload register for reload R.  This is called from
+   remove_address_replacements.  */
+void
+deallocate_reload_reg (r)
+     int r;
+{
+  int regno;
+
+  if (! reload_reg_rtx[r])
+    return;
+  regno = true_regnum (reload_reg_rtx[r]);
+  reload_reg_rtx[r] = 0;
+  if (spill_reg_order[regno] >= 0)
+    clear_reload_reg_in_use (regno, reload_opnum[r], reload_when_needed[r],
+                            reload_mode[r]);
+  reload_spill_index[r] = -1;
+}
 \f
 /* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
    reloads of the same item for fear that we might not have enough reload
@@ -6495,11 +6729,17 @@ emit_reload_insns (chain)
       rtx this_reload_insn = 0;
       int expect_occurrences = 1;
 
-      if (reload_spill_index[j] >= 0)
-       new_spill_reg_store[reload_spill_index[j]] = 0;
+      if (reload_reg_rtx[j]
+         && REGNO (reload_reg_rtx[j]) < FIRST_PSEUDO_REGISTER)
+       new_spill_reg_store[REGNO (reload_reg_rtx[j])] = 0;
+
+      old = (reload_in[j] && GET_CODE (reload_in[j]) == MEM
+            ? reload_in_reg[j] : reload_in[j]);
 
-      old = reload_in[j];
-      if (old != 0 && ! reload_inherited[j]
+      if (old != 0
+         /* AUTO_INC reloads need to be handled even if inherited.  We got an
+            AUTO_INC reload if reload_out is set but reload_out_reg isn't.  */
+         && (! reload_inherited[j] || (reload_out[j] && ! reload_out_reg[j]))
          && ! rtx_equal_p (reload_reg_rtx[j], old)
          && reload_reg_rtx[j] != 0)
        {
@@ -6628,6 +6868,17 @@ emit_reload_insns (chain)
                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]
+             && GET_CODE (reload_in_reg[j]) == REG)
+           {
+             oldequiv = old;
+             old = reload_in_reg[j];
+           }
          if (oldequiv == 0)
            oldequiv = old;
          else if (GET_CODE (oldequiv) == REG)
@@ -6642,11 +6893,11 @@ emit_reload_insns (chain)
          if (optimize && GET_CODE (oldequiv) == REG
              && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
              && spill_reg_store[REGNO (oldequiv)]
-             && GET_CODE (old) == REG && dead_or_set_p (insn, old)
-             /* This is unsafe if operand occurs more than once in current
-                insn.  Perhaps some occurrences weren't reloaded.  */
-             && count_occurrences (PATTERN (insn), old) == 1)
-           delete_output_reload (insn, j, spill_reg_store[REGNO (oldequiv)]);
+             && GET_CODE (old) == REG
+             && (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
+                 || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
+                                 reload_out_reg[j])))
+           delete_output_reload (insn, j, REGNO (oldequiv));
 
          /* Encapsulate both RELOADREG and OLDEQUIV into that mode,
             then load RELOADREG from OLDEQUIV.  Note that we cannot use
@@ -6700,20 +6951,35 @@ emit_reload_insns (chain)
          special = 0;
 
          /* Auto-increment addresses must be reloaded in a special way.  */
-         if (GET_CODE (oldequiv) == POST_INC
-             || GET_CODE (oldequiv) == POST_DEC
-             || GET_CODE (oldequiv) == PRE_INC
-             || GET_CODE (oldequiv) == PRE_DEC)
+         if (reload_out[j] && ! reload_out_reg[j])
            {
              /* We are not going to bother supporting the case where a
                 incremented register can't be copied directly from
                 OLDEQUIV since this seems highly unlikely.  */
              if (reload_secondary_in_reload[j] >= 0)
                abort ();
+
+             if (reload_inherited[j])
+               oldequiv = reloadreg;
+
+             old = XEXP (reload_in_reg[j], 0);
+
+             if (optimize && GET_CODE (oldequiv) == REG
+                 && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
+                 && spill_reg_store[REGNO (oldequiv)]
+                 && GET_CODE (old) == REG
+                 && (dead_or_set_p (insn,
+                                    spill_reg_stored_to[REGNO (oldequiv)])
+                     || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
+                                     old)))
+               delete_output_reload (insn, j, REGNO (oldequiv));
+
              /* Prevent normal processing of this reload.  */
              special = 1;
              /* Output a special code sequence for this case.  */
-             inc_for_reload (reloadreg, oldequiv, reload_inc[j]);
+             new_spill_reg_store[REGNO (reloadreg)]
+               = inc_for_reload (reloadreg, oldequiv, reload_out[j],
+                                 reload_inc[j]);
            }
 
          /* If we are reloading a pseudo-register that was set by the previous
@@ -6789,15 +7055,31 @@ emit_reload_insns (chain)
                  /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
                     and similarly for OLD.
                     See comments in get_secondary_reload in reload.c.  */
+                 /* If it is a pseudo that cannot be replaced with its
+                    equivalent MEM, we must fall back to reload_in, which
+                    will have all the necessary substitutions registered.  */
+                               
                  if (GET_CODE (oldequiv) == REG
                      && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
-                     && reg_equiv_mem[REGNO (oldequiv)] != 0)
-                   real_oldequiv = reg_equiv_mem[REGNO (oldequiv)];
+                     && reg_equiv_memory_loc[REGNO (oldequiv)] != 0)
+                   {
+                     if (reg_equiv_address[REGNO (oldequiv)]
+                         || num_not_at_initial_offset)
+                       real_oldequiv = reload_in[j];
+                     else
+                       real_oldequiv = reg_equiv_mem[REGNO (oldequiv)];
+                   }
 
                  if (GET_CODE (old) == REG
                      && REGNO (old) >= FIRST_PSEUDO_REGISTER
-                     && reg_equiv_mem[REGNO (old)] != 0)
-                   real_old = reg_equiv_mem[REGNO (old)];
+                     && reg_equiv_memory_loc[REGNO (old)] != 0)
+                   {
+                     if (reg_equiv_address[REGNO (old)]
+                         || num_not_at_initial_offset)
+                       real_old = reload_in[j];
+                     else
+                       real_old = reg_equiv_mem[REGNO (old)];
+                   }
 
                  second_reload_reg = reload_reg_rtx[secondary_reload];
                  icode = reload_secondary_in_icode[j];
@@ -6882,7 +7164,7 @@ emit_reload_insns (chain)
                                           third_reload_reg)));
                            }
                          else
-                           gen_reload (second_reload_reg, oldequiv,
+                           gen_reload (second_reload_reg, real_oldequiv,
                                        reload_opnum[j],
                                        reload_when_needed[j]);
 
@@ -6893,8 +7175,22 @@ emit_reload_insns (chain)
 #endif
 
              if (! special && ! rtx_equal_p (reloadreg, oldequiv))
-               gen_reload (reloadreg, oldequiv, reload_opnum[j],
-                           reload_when_needed[j]);
+               {
+                 rtx real_oldequiv = oldequiv;
+
+                 if ((GET_CODE (oldequiv) == REG
+                      && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
+                      && reg_equiv_memory_loc[REGNO (oldequiv)] != 0)
+                     || (GET_CODE (oldequiv) == SUBREG
+                         && GET_CODE (SUBREG_REG (oldequiv)) == REG
+                         && (REGNO (SUBREG_REG (oldequiv))
+                             >= FIRST_PSEUDO_REGISTER)
+                         && (reg_equiv_memory_loc
+                             [REGNO (SUBREG_REG (oldequiv))] != 0)))
+                   real_oldequiv = reload_in[j];
+                 gen_reload (reloadreg, real_oldequiv, reload_opnum[j],
+                             reload_when_needed[j]);
+               }
 
            }
 
@@ -6902,6 +7198,11 @@ emit_reload_insns (chain)
          /* End this sequence.  */
          *where = get_insns ();
          end_sequence ();
+
+         /* Update reload_override_in so that delete_address_reloads_1
+            can see the actual register usage.  */
+         if (oldequiv_reg)
+           reload_override_in[j] = oldequiv;
        }
 
       /* When inheriting a wider reload, we have a MEM in reload_in[j],
@@ -6909,6 +7210,7 @@ emit_reload_insns (chain)
         (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10)))  */
       if (optimize && reload_inherited[j] && reload_in[j]
          && GET_CODE (reload_in[j]) == MEM
+         && GET_CODE (reload_in_reg[j]) == MEM
          && reload_spill_index[j] >= 0
          && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
        {
@@ -6922,27 +7224,26 @@ emit_reload_insns (chain)
         output-reload, see if we can prove there was
         actually no need to store the old value in it.  */
 
-      if (optimize && reload_inherited[j] && reload_spill_index[j] >= 0
-         && reload_in[j] != 0
-         && GET_CODE (reload_in[j]) == REG
+      if (optimize
+         && (reload_inherited[j] || reload_override_in[j])
+         && reload_reg_rtx[j]
+         && GET_CODE (reload_reg_rtx[j]) == REG
+         && spill_reg_store[REGNO (reload_reg_rtx[j])] != 0
 #if 0
          /* There doesn't seem to be any reason to restrict this to pseudos
             and doing so loses in the case where we are copying from a
             register of the wrong class.  */
-         && REGNO (reload_in[j]) >= FIRST_PSEUDO_REGISTER
+         && REGNO (spill_reg_stored_to[REGNO (reload_reg_rtx[j])])
+            >= FIRST_PSEUDO_REGISTER
 #endif
-         && spill_reg_store[reload_spill_index[j]] != 0
-         /* This is unsafe if some other reload uses the same reg first.  */
-         && reload_reg_free_before_p (reload_spill_index[j],
-                                      reload_opnum[j], reload_when_needed[j],
-                                      0)
-         && dead_or_set_p (insn, reload_in[j])
-         /* This is unsafe if operand occurs more than once in current
-            insn.  Perhaps some occurrences weren't reloaded.  */
-         && (count_occurrences (PATTERN (insn), reload_in[j])
-             == expect_occurrences))
-       delete_output_reload (insn, j,
-                             spill_reg_store[reload_spill_index[j]]);
+            /* The insn might have already some references to stackslots
+               replaced by MEMs, while reload_out_reg still names the
+               original pseudo.  */
+         && (dead_or_set_p (insn,
+                            spill_reg_stored_to[REGNO (reload_reg_rtx[j])])
+             || rtx_equal_p (spill_reg_stored_to[REGNO (reload_reg_rtx[j])],
+                             reload_out_reg[j])))
+       delete_output_reload (insn, j, REGNO (reload_reg_rtx[j]));
 
       /* Input-reloading is done.  Now do output-reloading,
         storing the value from the reload-register after the main insn
@@ -6950,7 +7251,33 @@ emit_reload_insns (chain)
 
         ??? At some point we need to support handling output reloads of
         JUMP_INSNs or insns that set cc0.  */
-      old = reload_out[j];
+
+      /* If this is an output reload that stores something that is
+        not loaded in this same reload, see if we can eliminate a previous
+        store.  */
+      {
+       rtx pseudo = reload_out_reg[j];
+         
+       if (pseudo
+           && GET_CODE (pseudo) == REG
+           && ! rtx_equal_p (reload_in_reg[j], pseudo)
+           && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
+           && reg_last_reload_reg[REGNO (pseudo)])
+         {
+           int pseudo_no = REGNO (pseudo);
+           int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
+
+           /* We don't need to test full validity of last_regno for
+              inherit here; we only want to know if the store actually
+              matches the pseudo.  */
+           if (reg_reloaded_contents[last_regno] == pseudo_no
+               && spill_reg_store[last_regno]
+               && rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
+             delete_output_reload (insn, j, last_regno);
+         }
+      }
+
+      old = reload_out_reg[j];
       if (old != 0
          && reload_reg_rtx[j] != old
          && reload_reg_rtx[j] != 0)
@@ -7006,6 +7333,8 @@ emit_reload_insns (chain)
          else
            push_to_sequence (output_reload_insns[reload_opnum[j]]);
 
+         old = reload_out[j];
+
          /* Determine the mode to reload in.
             See comments above (for input reloading).  */
 
@@ -7136,21 +7465,22 @@ emit_reload_insns (chain)
 
                if (reg_mentioned_p (reload_reg_rtx[j], pat))
                  {
+                   rtx set = single_set (insn);
                    if (reload_spill_index[j] < 0
-                       && GET_CODE (pat) == SET
-                       && SET_SRC (pat) == reload_reg_rtx[j])
+                       && set
+                       && SET_SRC (set) == reload_reg_rtx[j])
                      {
-                       int src = REGNO (SET_SRC (pat));
+                       int src = REGNO (SET_SRC (set));
 
                        reload_spill_index[j] = src;
                        SET_HARD_REG_BIT (reg_is_output_reload, src);
                        if (find_regno_note (insn, REG_DEAD, src))
                          SET_HARD_REG_BIT (reg_reloaded_died, src);
                      }
-                   if (reload_spill_index[j] >= 0)
+                   if (REGNO (reload_reg_rtx[j]) < FIRST_PSEUDO_REGISTER)
                      {
                        int s = reload_secondary_out_reload[j];
-                       rtx set = single_set (p);
+                       set = single_set (p);
                        /* If this reload copies only to the secondary reload
                           register, the secondary reload does the actual
                           store.  */
@@ -7169,13 +7499,18 @@ emit_reload_insns (chain)
                            rtx s_reg = reload_reg_rtx[s];
                            rtx next = NEXT_INSN (p);
                            reload_out[s] = reload_out[j];
+                           reload_out_reg[s] = reload_out_reg[j];
                            set = single_set (next);
                            if (set && SET_SRC (set) == s_reg
                                && ! new_spill_reg_store[REGNO (s_reg)])
-                             new_spill_reg_store[REGNO (s_reg)] = next;
+                             {
+                               SET_HARD_REG_BIT (reg_is_output_reload,
+                                                 REGNO (s_reg));
+                               new_spill_reg_store[REGNO (s_reg)] = next;
+                             }
                          }
                        else
-                         new_spill_reg_store[reload_spill_index[j]] = p;
+                         new_spill_reg_store[REGNO (reload_reg_rtx[j])] = p;
                      }
                  }
              }
@@ -7292,14 +7627,25 @@ emit_reload_insns (chain)
                CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
 
              /* Maybe the spill reg contains a copy of reload_out.  */
-             if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+             if (reload_out[r] != 0
+                 && (GET_CODE (reload_out[r]) == REG
+#ifdef AUTO_INC_DEC
+                     || ! reload_out_reg[r]
+#endif
+                     || GET_CODE (reload_out_reg[r]) == REG))
                {
-                 register int nregno = REGNO (reload_out[r]);
+                 rtx out = (GET_CODE (reload_out[r]) == REG
+                            ? reload_out[r]
+                            : reload_out_reg[r]
+                            ? reload_out_reg[r]
+/* AUTO_INC */              : XEXP (reload_in_reg[r], 0));
+                 register int nregno = REGNO (out);
                  int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
                             : HARD_REGNO_NREGS (nregno,
                                                 GET_MODE (reload_reg_rtx[r])));
 
                  spill_reg_store[i] = new_spill_reg_store[i];
+                 spill_reg_stored_to[i] = out;
                  reg_last_reload_reg[nregno] = reload_reg_rtx[r];
 
                  /* If NREGNO is a hard register, it may occupy more than
@@ -7332,21 +7678,25 @@ emit_reload_insns (chain)
              /* Maybe the spill reg contains a copy of reload_in.  Only do
                 something if there will not be an output reload for
                 the register being reloaded.  */
-             else if (reload_out[r] == 0
+             else if (reload_out_reg[r] == 0
                       && reload_in[r] != 0
-                      && spill_reg_order[i] >= 0
                       && ((GET_CODE (reload_in[r]) == REG
+                           && REGNO (reload_in[r]) >= FIRST_PSEUDO_REGISTER
                            && ! reg_has_output_reload[REGNO (reload_in[r])])
                           || (GET_CODE (reload_in_reg[r]) == REG
-                              && ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
+                              && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))
+                      && ! reg_set_p (reload_reg_rtx[r], PATTERN (insn)))
                {
                  register int nregno;
                  int nnr;
 
-                 if (GET_CODE (reload_in[r]) == REG)
+                 if (GET_CODE (reload_in[r]) == REG
+                     && REGNO (reload_in[r]) >= FIRST_PSEUDO_REGISTER)
                    nregno = REGNO (reload_in[r]);
-                 else
+                 else if (GET_CODE (reload_in_reg[r]) == REG)
                    nregno = REGNO (reload_in_reg[r]);
+                 else
+                   nregno = REGNO (XEXP (reload_in_reg[r], 0));
 
                  nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
                         : HARD_REGNO_NREGS (nregno,
@@ -7363,8 +7713,11 @@ emit_reload_insns (chain)
                           : 0);
 
                  /* Unless we inherited this reload, show we haven't
-                    recently done a store.  */
-                 if (! reload_inherited[r])
+                    recently done a store.
+                    Previous stores of inherited auto_inc expressions
+                    also have to be discarded.  */
+                 if (! reload_inherited[r]
+                     || (reload_out[r] && ! reload_out_reg[r]))
                    spill_reg_store[i] = 0;
 
                  for (k = 0; k < nr; k++)
@@ -7400,11 +7753,76 @@ emit_reload_insns (chain)
         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 && reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+      if (i < 0 && reload_out[r] != 0
+         && (GET_CODE (reload_out[r]) == REG
+             || (GET_CODE (reload_out[r]) == MEM
+                 && GET_CODE (reload_out_reg[r]) == REG)))
        {
-         register int nregno = REGNO (reload_out[r]);
+         rtx out = (GET_CODE (reload_out[r]) == REG
+                    ? reload_out[r] : reload_out_reg[r]);
+         register int nregno = REGNO (out);
          if (nregno >= FIRST_PSEUDO_REGISTER)
-           reg_last_reload_reg[nregno] = 0;
+           {
+             rtx src_reg, store_insn;
+
+             reg_last_reload_reg[nregno] = 0;
+
+             /* If we can find a hard register that is stored, record
+                the storing insn so that we may delete this insn with
+                delete_output_reload.  */
+             src_reg = reload_reg_rtx[r];
+
+             /* If this is an optional reload, try to find the source reg
+                from an input reload.  */
+             if (! src_reg)
+               {
+                 rtx set = single_set (insn);
+                 if (SET_DEST (set) == reload_out[r])
+                   {
+                     int k;
+
+                     src_reg = SET_SRC (set);
+                     store_insn = insn;
+                     for (k = 0; k < n_reloads; k++)
+                       {
+                         if (reload_in[k] == src_reg)
+                           {
+                             src_reg = reload_reg_rtx[k];
+                             break;
+                           }
+                       }
+                   }
+               }
+             else
+               store_insn = new_spill_reg_store[REGNO (src_reg)];
+             if (src_reg && GET_CODE (src_reg) == REG
+                 && REGNO (src_reg) < FIRST_PSEUDO_REGISTER)
+               {
+                 int src_regno = REGNO (src_reg);
+                 int nr = HARD_REGNO_NREGS (src_regno, reload_mode[r]);
+                 /* The place where to find a death note varies with
+                    PRESERVE_DEATH_INFO_REGNO_P .  The condition is not
+                    necessarily checked exactly in the code that moves
+                    notes, so just check both locations.  */
+                 rtx note = find_regno_note (insn, REG_DEAD, src_regno);
+                 if (! note)
+                   note = find_regno_note (store_insn, REG_DEAD, src_regno);
+                 while (nr-- > 0)
+                   {
+                     spill_reg_store[src_regno + nr] = store_insn;
+                     spill_reg_stored_to[src_regno + nr] = out;
+                     reg_reloaded_contents[src_regno + nr] = nregno;
+                     reg_reloaded_insn[src_regno + nr] = store_insn;
+                     SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + nr);
+                     SET_HARD_REG_BIT (reg_is_output_reload, src_regno + nr);
+                     if (note)
+                       SET_HARD_REG_BIT (reg_reloaded_died, src_regno);
+                     else
+                       CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
+                   }
+                 reg_last_reload_reg[nregno] = src_reg;
+               }
+           }
          else
            {
              int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (reload_out[r]));
@@ -7630,22 +8048,66 @@ gen_reload (out, in, opnum, type)
    First we double-check.
 
    INSN is the insn now being processed.
-   OUTPUT_RELOAD_INSN is the insn of the output reload.
-   J is the reload-number for this insn.  */
+   LAST_RELOAD_REG is the hard register number for which we want to delete
+   the last output reload.
+   J is the reload-number that originally used REG.  The caller has made
+   certain that reload J doesn't use REG any longer for input.  */
 
 static void
-delete_output_reload (insn, j, output_reload_insn)
+delete_output_reload (insn, j, last_reload_reg)
      rtx insn;
      int j;
-     rtx output_reload_insn;
+     int last_reload_reg;
 {
+  rtx output_reload_insn = spill_reg_store[last_reload_reg];
+  rtx reg = spill_reg_stored_to[last_reload_reg];
+  int k;
+  int n_occurrences;
+  int n_inherited = 0;
   register rtx i1;
-
+  rtx substed;
+  
   /* Get the raw pseudo-register referred to.  */
 
-  rtx reg = reload_in[j];
   while (GET_CODE (reg) == SUBREG)
     reg = SUBREG_REG (reg);
+  substed = reg_equiv_memory_loc[REGNO (reg)];
+
+  /* This is unsafe if the operand occurs more often in the current
+     insn than it is inherited.  */
+  for (k = n_reloads - 1; k >= 0; k--)
+    {
+      rtx reg2 = reload_in[k];
+      if (! reg2)
+       continue;
+      if (GET_CODE (reg2) == MEM || reload_override_in[k])
+       reg2 = reload_in_reg[k];
+#ifdef AUTO_INC_DEC
+      if (reload_out[k] && ! reload_out_reg[k])
+       reg2 = XEXP (reload_in_reg[k], 0);
+#endif
+      while (GET_CODE (reg2) == SUBREG)
+       reg2 = SUBREG_REG (reg2);
+      if (rtx_equal_p (reg2, reg))
+       if (reload_inherited[k] || reload_override_in[k] || k == j)
+         {
+           n_inherited++;
+           reg2 = reload_out_reg[k];
+           if (! reg2)
+             continue;
+           while (GET_CODE (reg2) == SUBREG)
+             reg2 = XEXP (reg2, 0);
+           if (rtx_equal_p (reg2, reg))
+             n_inherited++;
+         }
+       else
+         return;
+    }
+  n_occurrences = count_occurrences (PATTERN (insn), reg);
+  if (substed)
+    n_occurrences += count_occurrences (PATTERN (insn), substed);
+  if (n_occurrences > n_inherited)
+    return;
 
   /* If the pseudo-reg we are reloading is no longer referenced
      anywhere between the store into it and here,
@@ -7660,21 +8122,14 @@ delete_output_reload (insn, j, output_reload_insn)
       if ((GET_CODE (i1) == INSN || GET_CODE (i1) == CALL_INSN)
          && reg_mentioned_p (reg, PATTERN (i1)))
        {
-         /* If this is just a single USE with an REG_EQUAL note in front
-            of INSN, this is no problem, because this mentions just the
-            address that we are using here.
-            But if there is more than one such USE, the insn might use
-            the operand directly, or another reload might do that.
-            This is analogous to the count_occurences check in the callers.  */
-         int num_occurences = 0;
-
-         while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE
-                && find_reg_note (i1, REG_EQUAL, NULL_RTX))
+         /* If this is USE in front of INSN, we only have to check that
+            there are no more references than accounted for by inheritance.  */
+         while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE)
            {
-             num_occurences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
+             n_occurrences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
              i1 = NEXT_INSN (i1);
            }
-         if (num_occurences == 1 && i1 == insn)
+         if (n_occurrences <= n_inherited && i1 == insn)
            break;
          return;
        }
@@ -7717,7 +8172,10 @@ delete_output_reload (insn, j, output_reload_insn)
            {
              /* Some other ref remains; just delete the output reload we
                 know to be dead.  */
-             delete_insn (output_reload_insn);
+             delete_address_reloads (output_reload_insn, insn);
+             PUT_CODE (output_reload_insn, NOTE);
+             NOTE_SOURCE_FILE (output_reload_insn) = 0;
+             NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
              return;
            }
        }
@@ -7729,6 +8187,7 @@ delete_output_reload (insn, j, output_reload_insn)
 
          if (set != 0 && SET_DEST (set) == reg)
            {
+             delete_address_reloads (i2, insn);
              /* This might be a basic block head,
                 thus don't use delete_insn.  */
              PUT_CODE (i2, NOTE);
@@ -7745,22 +8204,178 @@ delete_output_reload (insn, j, output_reload_insn)
       reg_renumber[REGNO (reg)] = REGNO (reload_reg_rtx[j]);
       alter_reg (REGNO (reg), -1);
     }
-  delete_insn (output_reload_insn);
+  delete_address_reloads (output_reload_insn, insn);
+  PUT_CODE (output_reload_insn, NOTE);
+  NOTE_SOURCE_FILE (output_reload_insn) = 0;
+  NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
+
+}
 
+/* We are going to delete DEAD_INSN.  Recursively delete loads of
+   reload registers used in DEAD_INSN that are not used till CURRENT_INSN.
+   CURRENT_INSN is being reloaded, so we have to check its reloads too.  */
+static void
+delete_address_reloads (dead_insn, current_insn)
+     rtx dead_insn, current_insn;
+{
+  rtx set = single_set (dead_insn);
+  rtx set2, dst, prev, next;
+  if (set)
+    {
+      rtx dst = SET_DEST (set);
+      if (GET_CODE (dst) == MEM)
+       delete_address_reloads_1 (dead_insn, XEXP (dst, 0), current_insn);
+    }
+  /* If we deleted the store from a reloaded post_{in,de}c expression,
+     we can delete the matching adds.  */
+  prev = PREV_INSN (dead_insn);
+  next = NEXT_INSN (dead_insn);
+  if (! prev || ! next)
+    return;
+  set = single_set (next);
+  set2 = single_set (prev);
+  if (! set || ! set2
+      || GET_CODE (SET_SRC (set)) != PLUS || GET_CODE (SET_SRC (set2)) != PLUS
+      || GET_CODE (XEXP (SET_SRC (set), 1)) != CONST_INT
+      || GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT)
+    return;
+  dst = SET_DEST (set);
+  if (! rtx_equal_p (dst, SET_DEST (set2))
+      || ! rtx_equal_p (dst, XEXP (SET_SRC (set), 0))
+      || ! rtx_equal_p (dst, XEXP (SET_SRC (set2), 0))
+      || (INTVAL (XEXP (SET_SRC (set), 1))
+         != - INTVAL (XEXP (SET_SRC (set2), 1))))
+    return;
+  delete_insn (prev);
+  delete_insn (next);
+}
+
+/* Subfunction of delete_address_reloads: process registers found in X.  */
+static void
+delete_address_reloads_1 (dead_insn, x, current_insn)
+     rtx dead_insn, x, current_insn;
+{
+  rtx prev, set, dst, i2;
+  int i, j;
+  enum rtx_code code = GET_CODE (x);
+
+  if (code != REG)
+    {
+      char *fmt= GET_RTX_FORMAT (code);
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+       {
+         if (fmt[i] == 'e')
+           delete_address_reloads_1 (dead_insn, XEXP (x, i), current_insn);
+         else if (fmt[i] == 'E')
+           {
+             for (j = XVECLEN (x, i) - 1; j >=0; j--)
+               delete_address_reloads_1 (dead_insn, XVECEXP (x, i, j),
+                                         current_insn);
+           }
+       }
+      return;
+    }
+
+  if (spill_reg_order[REGNO (x)] < 0)
+    return;
+
+  /* Scan backwards for the insn that sets x.  This might be a way back due
+     to inheritance.  */
+  for (prev = PREV_INSN (dead_insn); prev; prev = PREV_INSN (prev))
+    {
+      code = GET_CODE (prev);
+      if (code == CODE_LABEL || code == JUMP_INSN)
+       return;
+      if (GET_RTX_CLASS (code) != 'i')
+       continue;
+      if (reg_set_p (x, PATTERN (prev)))
+       break;
+      if (reg_referenced_p (x, PATTERN (prev)))
+       return;
+    }
+  if (! prev || INSN_UID (prev) < reload_first_uid)
+    return;
+  /* Check that PREV only sets the reload register.  */
+  set = single_set (prev);
+  if (! set)
+    return;
+  dst = SET_DEST (set);
+  if (GET_CODE (dst) != REG
+      || ! rtx_equal_p (dst, x))
+    return;
+  if (! reg_set_p (dst, PATTERN (dead_insn)))
+    {
+      /* Check if DST was used in a later insn -
+        it might have been inherited.  */
+      for (i2 = NEXT_INSN (dead_insn); i2; i2 = NEXT_INSN (i2))
+       {
+         if (GET_CODE (i2) == CODE_LABEL)
+           break;
+         if (GET_RTX_CLASS (GET_CODE (i2)) != 'i')
+           continue;
+         if (reg_referenced_p (dst, PATTERN (i2)))
+           {
+             /* If there is a reference to the register in the current insn,
+                it might be loaded in a non-inherited reload.  If no other
+                reload uses it, that means the register is set before
+                referenced.  */
+             if (i2 == current_insn)
+               {
+                 for (j = n_reloads - 1; j >= 0; j--)
+                   if ((reload_reg_rtx[j] == dst && reload_inherited[j])
+                       || reload_override_in[j] == dst)
+                     return;
+                 for (j = n_reloads - 1; j >= 0; j--)
+                   if (reload_in[j] && reload_reg_rtx[j] == dst)
+                     break;
+                 if (j >= 0)
+                   break;
+               }
+             return;
+           }
+         if (GET_CODE (i2) == JUMP_INSN)
+           break;
+         if (reg_set_p (dst, PATTERN (i2)))
+           break;
+         /* If DST is still live at CURRENT_INSN, check if it is used for
+            any reload.  */
+         if (i2 == current_insn)
+           {
+             for (j = n_reloads - 1; j >= 0; j--)
+               if ((reload_reg_rtx[j] == dst && reload_inherited[j])
+                   || reload_override_in[j] == dst)
+                 return;
+             /* ??? We can't finish the loop here, because dst might be
+                allocated to a pseudo in this block if no reload in this
+                block needs any of the clsses containing DST - see
+                spill_hard_reg.  There is no easy way to tell this, so we
+                have to scan till the end of the basic block.  */
+           }
+       }
+    }
+  delete_address_reloads_1 (prev, SET_SRC (set), current_insn);
+  reg_reloaded_contents[REGNO (dst)] = -1;
+  /* Can't use delete_insn here because PREV might be a basic block head.  */
+  PUT_CODE (prev, NOTE);
+  NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
+  NOTE_SOURCE_FILE (prev) = 0;
 }
 \f
 /* Output reload-insns to reload VALUE into RELOADREG.
    VALUE is an autoincrement or autodecrement RTX whose operand
    is a register or memory location;
    so reloading involves incrementing that location.
+   IN is either identical to VALUE, or some cheaper place to reload from.
 
    INC_AMOUNT is the number to increment or decrement by (always positive).
-   This cannot be deduced from VALUE.  */
+   This cannot be deduced from VALUE.
 
-static void
-inc_for_reload (reloadreg, value, inc_amount)
+   Return the instruction that stores into RELOADREG.  */
+
+static rtx
+inc_for_reload (reloadreg, in, value, inc_amount)
      rtx reloadreg;
-     rtx value;
+     rtx in, value;
      int inc_amount;
 {
   /* REG or MEM to be copied and incremented.  */
@@ -7771,6 +8386,8 @@ inc_for_reload (reloadreg, value, inc_amount)
   rtx inc;
   rtx add_insn;
   int code;
+  rtx store;
+  rtx real_in = in == value ? XEXP (in, 0) : in;
 
   /* No hard register is equivalent to this register after
      inc/dec operation.  If REG_LAST_RELOAD_REG were non-zero,
@@ -7785,36 +8402,38 @@ inc_for_reload (reloadreg, value, inc_amount)
   inc = GEN_INT (inc_amount);
 
   /* If this is post-increment, first copy the location to the reload reg.  */
-  if (post)
-    emit_insn (gen_move_insn (reloadreg, incloc));
+  if (post && real_in != reloadreg)
+    emit_insn (gen_move_insn (reloadreg, real_in));
 
-  /* See if we can directly increment INCLOC.  Use a method similar to that
-     in gen_reload.  */
+  if (in == value)
+    {
+      /* See if we can directly increment INCLOC.  Use a method similar to
+        that in gen_reload.  */
 
-  last = get_last_insn ();
-  add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
-                                    gen_rtx_PLUS (GET_MODE (incloc),
-                                                  incloc, inc)));
+      last = get_last_insn ();
+      add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
+                                        gen_rtx_PLUS (GET_MODE (incloc),
+                                                      incloc, inc)));
                                                          
-  code = recog_memoized (add_insn);
-  if (code >= 0)
-    {
-      insn_extract (add_insn);
-      if (constrain_operands (code, 1))
+      code = recog_memoized (add_insn);
+      if (code >= 0)
        {
-         /* If this is a pre-increment and we have incremented the value
-            where it lives, copy the incremented value to RELOADREG to
-            be used as an address.  */
+         insn_extract (add_insn);
+         if (constrain_operands (code, 1))
+           {
+             /* If this is a pre-increment and we have incremented the value
+                where it lives, copy the incremented value to RELOADREG to
+                be used as an address.  */
 
-         if (! post)
-           emit_insn (gen_move_insn (reloadreg, incloc));
+             if (! post)
+               emit_insn (gen_move_insn (reloadreg, incloc));
 
-         return;
+             return add_insn;
+           }
        }
+      delete_insns_since (last);
     }
 
-  delete_insns_since (last);
-
   /* If couldn't do the increment directly, must increment in RELOADREG.
      The way we do this depends on whether this is pre- or post-increment.
      For pre-increment, copy INCLOC to the reload register, increment it
@@ -7822,9 +8441,10 @@ inc_for_reload (reloadreg, value, inc_amount)
 
   if (! post)
     {
-      emit_insn (gen_move_insn (reloadreg, incloc));
+      if (in != reloadreg)
+       emit_insn (gen_move_insn (reloadreg, real_in));
       emit_insn (gen_add2_insn (reloadreg, inc));
-      emit_insn (gen_move_insn (incloc, reloadreg));
+      store = emit_insn (gen_move_insn (incloc, reloadreg));
     }
   else
     {
@@ -7833,16 +8453,16 @@ inc_for_reload (reloadreg, value, inc_amount)
         may not be available after the insn in an input reload, we must do
         the incrementation before the insn being reloaded for.
 
-        We have already copied INCLOC to RELOADREG.  Increment the copy in
+        We have already copied IN to RELOADREG.  Increment the copy in
         RELOADREG, save that back, then decrement RELOADREG so it has
         the original value.  */
 
       emit_insn (gen_add2_insn (reloadreg, inc));
-      emit_insn (gen_move_insn (incloc, reloadreg));
+      store = emit_insn (gen_move_insn (incloc, reloadreg));
       emit_insn (gen_add2_insn (reloadreg, GEN_INT (-inc_amount)));
     }
 
-  return;
+  return store;
 }
 \f
 /* Return 1 if we are certain that the constraint-string STRING allows
@@ -7921,6 +8541,10 @@ count_occurrences (x, find)
     case CC0:
       return 0;
 
+    case MEM:
+      if (GET_CODE (find) == MEM && rtx_equal_p (x, find))
+       return 1;
+      break;
     case SET:
       if (SET_DEST (x) == find)
        return count_occurrences (SET_SRC (x), find);