OSDN Git Service

Don't assume a SUBREG can not conflict with a MEM
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 3c15a7f..61b8d01 100644 (file)
@@ -1,5 +1,5 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
-   Copyright (C) 1987, 88, 89, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <stdio.h>
@@ -33,6 +34,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "recog.h"
 #include "basic-block.h"
 #include "output.h"
+#include "real.h"
 
 /* This file contains the reload pass of the compiler, which is
    run after register allocation has been done.  It checks that
@@ -77,7 +79,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #endif
 \f
 /* During reload_as_needed, element N contains a REG rtx for the hard reg
-   into which reg N has been reloaded (perhaps for a previous insn). */
+   into which reg N has been reloaded (perhaps for a previous insn).  */
 static rtx *reg_last_reload_reg;
 
 /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
@@ -168,6 +170,18 @@ static HARD_REG_SET bad_spill_regs;
    elements that are actually valid; new ones are added at the end.  */
 static short spill_regs[FIRST_PSEUDO_REGISTER];
 
+/* This reg set indicates those registers that have been used a spill
+   registers.  This information is used in reorg.c, to help figure out
+   what registers are live at any point.  It is assumed that all spill_regs
+   are dead at every CODE_LABEL.  */
+
+HARD_REG_SET used_spill_regs;
+
+/* Index of last register assigned as a spill register.  We allocate in
+   a round-robin fashion.  */
+
+static int last_spill_reg;
+
 /* Describes order of preference for putting regs into spill_regs.
    Contains the numbers of all the hard regs, in order most preferred first.
    This order is different for each function.
@@ -239,6 +253,18 @@ int reload_first_uid;
 
 int caller_save_needed;
 
+/* The register class to use for a base register when reloading an
+   address.  This is normally BASE_REG_CLASS, but it may be different
+   when using SMALL_REGISTER_CLASSES and passing parameters in
+   registers.  */
+enum reg_class reload_address_base_reg_class;
+
+/* The register class to use for an index register when reloading an
+   address.  This is normally INDEX_REG_CLASS, but it may be different
+   when using SMALL_REGISTER_CLASSES and passing parameters in
+   registers.  */
+enum reg_class reload_address_index_reg_class;
+
 /* Set to 1 while reload_as_needed is operating.
    Required by some machines to handle any generated moves differently.  */
 
@@ -263,6 +289,9 @@ char *reload_firstobj;
 
 /* List of labels that must never be deleted.  */
 extern rtx forced_labels;
+
+/* Allocation number table from global register allocation.  */
+extern int *reg_allocno;
 \f
 /* This structure is used to record information about register eliminations.
    Each array entry describes one possible way of eliminating a register
@@ -271,22 +300,22 @@ extern rtx forced_labels;
 
 static struct elim_table
 {
-  int from;                    /* Register number to be eliminated. */
-  int to;                      /* Register number used as replacement. */
-  int initial_offset;          /* Initial difference between values. */
-  int can_eliminate;           /* Non-zero if this elimination can be done. */
+  int from;                    /* Register number to be eliminated.  */
+  int to;                      /* Register number used as replacement.  */
+  int initial_offset;          /* Initial difference between values.  */
+  int can_eliminate;           /* Non-zero if this elimination can be done.  */
   int can_eliminate_previous;  /* Value of CAN_ELIMINATE in previous scan over
-                                  insns made by reload. */
-  int offset;                  /* Current offset between the two regs. */
-  int max_offset;              /* Maximum offset between the two regs. */
-  int previous_offset;         /* Offset at end of previous insn. */
-  int ref_outside_mem;         /* "to" has been referenced outside a MEM. */
+                                  insns made by reload.  */
+  int offset;                  /* Current offset between the two regs.  */
+  int max_offset;              /* Maximum offset between the two regs.  */
+  int previous_offset;         /* Offset at end of previous insn.  */
+  int ref_outside_mem;         /* "to" has been referenced outside a MEM.  */
   rtx from_rtx;                        /* REG rtx for the register to be eliminated.
                                   We cannot simply compare the number since
                                   we might then spuriously replace a hard
                                   register corresponding to a pseudo
-                                  assigned to the reg to be eliminated. */
-  rtx to_rtx;                  /* REG rtx for the replacement. */
+                                  assigned to the reg to be eliminated.  */
+  rtx to_rtx;                  /* REG rtx for the replacement.  */
 } reg_eliminate[] =
 
 /* If a set of eliminable registers was specified, define the table from it.
@@ -327,7 +356,7 @@ struct hard_reg_n_uses { int regno; int uses; };
 \f
 static int possible_group_p            PROTO((int, int *));
 static void count_possible_groups      PROTO((int *, enum machine_mode *,
-                                              int *));
+                                              int *, int));
 static int modes_equiv_for_class_p     PROTO((enum machine_mode,
                                               enum machine_mode,
                                               enum reg_class));
@@ -342,12 +371,12 @@ static int eliminate_regs_in_insn PROTO((rtx, int));
 static void mark_not_eliminable                PROTO((rtx, rtx));
 static int spill_hard_reg              PROTO((int, int, FILE *, int));
 static void scan_paradoxical_subregs   PROTO((rtx));
-static int hard_reg_use_compare                PROTO((struct hard_reg_n_uses *,
-                                              struct hard_reg_n_uses *));
-static void order_regs_for_reload      PROTO((void));
+static int hard_reg_use_compare                PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void order_regs_for_reload      PROTO((int));
+static int compare_spill_regs          PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void reload_as_needed           PROTO((rtx, int));
 static void forget_old_reloads_1       PROTO((rtx, rtx));
-static int reload_reg_class_lower      PROTO((short *, short *));
+static int reload_reg_class_lower      PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void mark_reload_reg_in_use     PROTO((int, int, enum reload_type,
                                               enum machine_mode));
 static void clear_reload_reg_in_use    PROTO((int, int, enum reload_type,
@@ -355,6 +384,7 @@ static void clear_reload_reg_in_use PROTO((int, int, enum reload_type,
 static int reload_reg_free_p           PROTO((int, int, enum reload_type));
 static int reload_reg_free_before_p    PROTO((int, int, enum reload_type));
 static int reload_reg_reaches_end_p    PROTO((int, int, enum reload_type));
+static int reloads_conflict            PROTO((int, int));
 static int allocate_reload_reg         PROTO((int, rtx, int, int));
 static void choose_reload_regs         PROTO((rtx, rtx));
 static void merge_assigned_reloads     PROTO((rtx));
@@ -363,6 +393,17 @@ static void delete_output_reload   PROTO((rtx, int, rtx));
 static void inc_for_reload             PROTO((rtx, rtx, int));
 static int constraint_accepts_reg_p    PROTO((char *, rtx));
 static int count_occurrences           PROTO((rtx, rtx));
+static void reload_cse_invalidate_regno        PROTO((int, enum machine_mode, int));
+static int reload_cse_mem_conflict_p   PROTO((rtx, rtx, enum machine_mode,
+                                              rtx));
+static void reload_cse_invalidate_mem  PROTO((rtx));
+static void reload_cse_invalidate_rtx  PROTO((rtx, rtx));
+static void reload_cse_regs            PROTO((rtx));
+static int reload_cse_regno_equal_p    PROTO((int, rtx, enum machine_mode));
+static int reload_cse_noop_set_p       PROTO((rtx, rtx));
+static void reload_cse_simplify_set    PROTO((rtx, rtx));
+static void reload_cse_check_clobber   PROTO((rtx, rtx));
+static void reload_cse_record_set      PROTO((rtx, rtx));
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -410,9 +451,69 @@ init_reload ()
        }
     }
 
-  /* Initialize obstack for our rtl allocation. */
+  /* Initialize obstack for our rtl allocation.  */
   gcc_obstack_init (&reload_obstack);
   reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+  /* Decide which register class should be used when reloading
+     addresses.  If we are using SMALL_REGISTER_CLASSES, and any
+     parameters are passed in registers, then we do not want to use
+     those registers when reloading an address.  Otherwise, if a
+     function argument needs a reload, we may wind up clobbering
+     another argument to the function which was already computed.  If
+     we find a subset class which simply avoids those registers, we
+     use it instead.  ??? It would be better to only use the
+     restricted class when we actually are loading function arguments,
+     but that is hard to determine.  */
+  reload_address_base_reg_class = BASE_REG_CLASS;
+  reload_address_index_reg_class = INDEX_REG_CLASS;
+#ifdef SMALL_REGISTER_CLASSES
+  if (SMALL_REGISTER_CLASSES)
+    {
+      int regno;
+      HARD_REG_SET base, index;
+      enum reg_class *p;
+
+      COPY_HARD_REG_SET (base, reg_class_contents[BASE_REG_CLASS]);
+      COPY_HARD_REG_SET (index, reg_class_contents[INDEX_REG_CLASS]);
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       {
+         if (FUNCTION_ARG_REGNO_P (regno))
+           {
+             CLEAR_HARD_REG_BIT (base, regno);
+             CLEAR_HARD_REG_BIT (index, regno);
+           }
+       }
+      
+      GO_IF_HARD_REG_EQUAL (base, reg_class_contents[BASE_REG_CLASS],
+                           baseok);
+      for (p = reg_class_subclasses[BASE_REG_CLASS];
+          *p != LIM_REG_CLASSES;
+          p++)
+       {
+         GO_IF_HARD_REG_EQUAL (base, reg_class_contents[*p], usebase);
+         continue;
+       usebase:
+         reload_address_base_reg_class = *p;
+         break;
+       }
+    baseok:;
+
+      GO_IF_HARD_REG_EQUAL (index, reg_class_contents[INDEX_REG_CLASS],
+                           indexok);
+      for (p = reg_class_subclasses[INDEX_REG_CLASS];
+          *p != LIM_REG_CLASSES;
+          p++)
+       {
+         GO_IF_HARD_REG_EQUAL (index, reg_class_contents[*p], useindex);
+         continue;
+       useindex:
+         reload_address_index_reg_class = *p;
+         break;
+       }
+    indexok:;
+    }
+#endif /* SMALL_REGISTER_CLASSES */
 }
 
 /* Main entry point for the reload pass.
@@ -440,7 +541,7 @@ reload (first, global, dumpfile)
      FILE *dumpfile;
 {
   register int class;
-  register int i, j;
+  register int i, j, k;
   register rtx insn;
   register struct elim_table *ep;
 
@@ -477,8 +578,8 @@ reload (first, global, dumpfile)
   bcopy (regs_ever_live, regs_explicitly_used, sizeof regs_ever_live);
 
   /* We don't have a stack slot for any spill reg yet.  */
-  bzero (spill_stack_slot, sizeof spill_stack_slot);
-  bzero (spill_stack_slot_width, sizeof spill_stack_slot_width);
+  bzero ((char *) spill_stack_slot, sizeof spill_stack_slot);
+  bzero ((char *) spill_stack_slot_width, sizeof spill_stack_slot_width);
 
   /* Initialize the save area information for caller-save, in case some
      are needed.  */
@@ -488,10 +589,18 @@ reload (first, global, dumpfile)
      as homes for pseudo registers.
      This is done here rather than (eg) in global_alloc
      because this point is reached even if not optimizing.  */
-
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     mark_home_live (i);
 
+  /* A function that receives a nonlocal goto must save all call-saved
+     registers.  */
+  if (current_function_has_nonlocal_label)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      {
+       if (! call_used_regs[i] && ! fixed_regs[i])
+         regs_ever_live[i] = 1;
+      }
+
   for (i = 0; i < scratch_list_length; i++)
     if (scratch_list[i])
       mark_scratch_live (scratch_list[i]);
@@ -511,28 +620,42 @@ reload (first, global, dumpfile)
      be substituted eventually by altering the REG-rtx's.  */
 
   reg_equiv_constant = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_equiv_constant, max_regno * sizeof (rtx));
+  bzero ((char *) reg_equiv_constant, max_regno * sizeof (rtx));
   reg_equiv_memory_loc = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_equiv_memory_loc, max_regno * sizeof (rtx));
+  bzero ((char *) reg_equiv_memory_loc, max_regno * sizeof (rtx));
   reg_equiv_mem = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_equiv_mem, max_regno * sizeof (rtx));
+  bzero ((char *) reg_equiv_mem, max_regno * sizeof (rtx));
   reg_equiv_init = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_equiv_init, max_regno * sizeof (rtx));
+  bzero ((char *) reg_equiv_init, max_regno * sizeof (rtx));
   reg_equiv_address = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_equiv_address, max_regno * sizeof (rtx));
+  bzero ((char *) reg_equiv_address, max_regno * sizeof (rtx));
   reg_max_ref_width = (int *) alloca (max_regno * sizeof (int));
-  bzero (reg_max_ref_width, max_regno * sizeof (int));
+  bzero ((char *) reg_max_ref_width, max_regno * sizeof (int));
   cannot_omit_stores = (char *) alloca (max_regno);
   bzero (cannot_omit_stores, max_regno);
 
+#ifdef SMALL_REGISTER_CLASSES
+  if (SMALL_REGISTER_CLASSES)
+    CLEAR_HARD_REG_SET (forbidden_regs);
+#endif
+
   /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
-     Also find all paradoxical subregs
-     and find largest such for each pseudo.  */
+     Also find all paradoxical subregs and find largest such for each pseudo.
+     On machines with small register classes, record hard registers that
+     are used for user variables.  These can never be used for spills. 
+     Also look for a "constant" NOTE_INSN_SETJMP.  This means that all
+     caller-saved registers must be marked live.  */
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       rtx set = single_set (insn);
 
+      if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+         if (! call_used_regs[i])
+           regs_ever_live[i] = 1;
+
       if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
        {
          rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
@@ -607,8 +730,7 @@ reload (first, global, dumpfile)
     {
       ep->can_eliminate = ep->can_eliminate_previous
        = (CAN_ELIMINATE (ep->from, ep->to)
-          && (ep->from != HARD_FRAME_POINTER_REGNUM 
-              || ! frame_pointer_needed));
+          && ! (ep->to == STACK_POINTER_REGNUM && frame_pointer_needed));
     }
 #else
   reg_eliminate[0].can_eliminate = reg_eliminate[0].can_eliminate_previous
@@ -644,11 +766,6 @@ reload (first, global, dumpfile)
   for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
     alter_reg (i, -1);
 
-  /* Round size of stack frame to BIGGEST_ALIGNMENT.  This must be done here
-     because the stack size may be a part of the offset computation for
-     register elimination.   */
-  assign_stack_local (BLKmode, 0, 0);
-
   /* If we have some registers we think can be eliminated, scan all insns to
      see if there is an insn that sets one of these registers to something
      other than itself plus a constant.  If so, the register cannot be
@@ -678,35 +795,39 @@ reload (first, global, dumpfile)
   /* Compute the order of preference for hard registers to spill.
      Store them by decreasing preference in potential_reload_regs.  */
 
-  order_regs_for_reload ();
+  order_regs_for_reload (global);
 
   /* So far, no hard regs have been spilled.  */
   n_spills = 0;
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     spill_reg_order[i] = -1;
 
+  /* Initialize to -1, which means take the first spill register.  */
+  last_spill_reg = -1;
+
   /* On most machines, we can't use any register explicitly used in the
      rtl as a spill register.  But on some, we have to.  Those will have
      taken care to keep the life of hard regs as short as possible.  */
 
 #ifdef SMALL_REGISTER_CLASSES
-  CLEAR_HARD_REG_SET (forbidden_regs);
-#else
-  COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
+  if (! SMALL_REGISTER_CLASSES)
 #endif
+    COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
 
   /* Spill any hard regs that we know we can't eliminate.  */
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     if (! ep->can_eliminate)
-      {
-       spill_hard_reg (ep->from, global, dumpfile, 1);
-       regs_ever_live[ep->from] = 1;
-      }
+      spill_hard_reg (ep->from, global, dumpfile, 1);
+
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+  if (frame_pointer_needed)
+    spill_hard_reg (HARD_FRAME_POINTER_REGNUM, global, dumpfile, 1);
+#endif
 
   if (global)
     for (i = 0; i < N_REG_CLASSES; i++)
       {
-       basic_block_needs[i] = (char *)alloca (n_basic_blocks);
+       basic_block_needs[i] = (char *) alloca (n_basic_blocks);
        bzero (basic_block_needs[i], n_basic_blocks);
       }
 
@@ -754,17 +875,18 @@ reload (first, global, dumpfile)
       rtx max_groups_insn[N_REG_CLASSES];
       rtx max_nongroups_insn[N_REG_CLASSES];
       rtx x;
-      int starting_frame_size = get_frame_size ();
+      HOST_WIDE_INT starting_frame_size;
+      int previous_frame_pointer_needed = frame_pointer_needed;
       static char *reg_class_names[] = REG_CLASS_NAMES;
 
       something_changed = 0;
-      bzero (max_needs, sizeof max_needs);
-      bzero (max_groups, sizeof max_groups);
-      bzero (max_nongroups, sizeof max_nongroups);
-      bzero (max_needs_insn, sizeof max_needs_insn);
-      bzero (max_groups_insn, sizeof max_groups_insn);
-      bzero (max_nongroups_insn, sizeof max_nongroups_insn);
-      bzero (group_size, sizeof group_size);
+      bzero ((char *) max_needs, sizeof max_needs);
+      bzero ((char *) max_groups, sizeof max_groups);
+      bzero ((char *) max_nongroups, sizeof max_nongroups);
+      bzero ((char *) max_needs_insn, sizeof max_needs_insn);
+      bzero ((char *) max_groups_insn, sizeof max_groups_insn);
+      bzero ((char *) max_nongroups_insn, sizeof max_nongroups_insn);
+      bzero ((char *) group_size, sizeof group_size);
       for (i = 0; i < N_REG_CLASSES; i++)
        group_mode[i] = VOIDmode;
 
@@ -775,6 +897,14 @@ reload (first, global, dumpfile)
         changes from 0 to 1 in this pass.  */
       new_basic_block_needs = 0;
 
+      /* Round size of stack frame to BIGGEST_ALIGNMENT.  This must be done
+        here because the stack size may be a part of the offset computation
+        for register elimination, and there might have been new stack slots
+        created in the last iteration of this loop.   */
+      assign_stack_local (BLKmode, 0, 0);
+
+      starting_frame_size = get_frame_size ();
+
       /* Reset all offsets on eliminable registers to their initial values.  */
 #ifdef ELIMINABLE_REGS
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -797,7 +927,7 @@ reload (first, global, dumpfile)
 
       num_not_at_initial_offset = 0;
 
-      bzero (&offsets_known_at[get_first_label_num ()], num_labels);
+      bzero ((char *) &offsets_known_at[get_first_label_num ()], num_labels);
 
       /* Set a known offset for each forced label to be at the initial offset
         of each elimination.  We do this because we assume that all
@@ -835,7 +965,7 @@ reload (first, global, dumpfile)
       for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
        if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i])
          {
-           rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX);
+           rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX, 0);
 
            if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]),
                                         XEXP (x, 0)))
@@ -906,10 +1036,9 @@ reload (first, global, dumpfile)
              int old_code = INSN_CODE (insn);
              rtx old_notes = REG_NOTES (insn);
              int did_elimination = 0;
-             int max_total_input_groups = 0, max_total_output_groups = 0;
 
              /* To compute the number of reload registers of each class 
-                needed for an insn, we must similate what choose_reload_regs
+                needed for an insn, we must simulate what choose_reload_regs
                 can do.  We do this by splitting an insn into an "input" and
                 an "output" part.  RELOAD_OTHER reloads are used in both. 
                 The input part uses those reloads, RELOAD_FOR_INPUT reloads,
@@ -926,65 +1055,27 @@ reload (first, global, dumpfile)
                 The total number of registers needed is the maximum of the
                 inputs and outputs.  */
 
-             /* These just count RELOAD_OTHER.  */
-             int insn_needs[N_REG_CLASSES];
-             int insn_groups[N_REG_CLASSES];
-             int insn_total_groups = 0;
-
-             /* Count RELOAD_FOR_INPUT reloads.  */
-             int insn_needs_for_inputs[N_REG_CLASSES];
-             int insn_groups_for_inputs[N_REG_CLASSES];
-             int insn_total_groups_for_inputs = 0;
-
-             /* Count RELOAD_FOR_OUTPUT reloads.  */
-             int insn_needs_for_outputs[N_REG_CLASSES];
-             int insn_groups_for_outputs[N_REG_CLASSES];
-             int insn_total_groups_for_outputs = 0;
-
-             /* Count RELOAD_FOR_INSN reloads.  */
-             int insn_needs_for_insn[N_REG_CLASSES];
-             int insn_groups_for_insn[N_REG_CLASSES];
-             int insn_total_groups_for_insn = 0;
-
-             /* Count RELOAD_FOR_OTHER_ADDRESS reloads.  */
-             int insn_needs_for_other_addr[N_REG_CLASSES];
-             int insn_groups_for_other_addr[N_REG_CLASSES];
-             int insn_total_groups_for_other_addr = 0;
-
-             /* Count RELOAD_FOR_INPUT_ADDRESS reloads.  */
-             int insn_needs_for_in_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
-             int insn_groups_for_in_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
-             int insn_total_groups_for_in_addr[MAX_RECOG_OPERANDS];
-
-             /* Count RELOAD_FOR_OUTPUT_ADDRESS reloads.  */
-             int insn_needs_for_out_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
-             int insn_groups_for_out_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
-             int insn_total_groups_for_out_addr[MAX_RECOG_OPERANDS];
-
-             /* Count RELOAD_FOR_OPERAND_ADDRESS reloads.  */
-             int insn_needs_for_op_addr[N_REG_CLASSES];
-             int insn_groups_for_op_addr[N_REG_CLASSES];
-             int insn_total_groups_for_op_addr = 0;
-
-#if 0  /* This wouldn't work nowadays, since optimize_bit_field
-         looks for non-strict memory addresses.  */
-             /* Optimization: a bit-field instruction whose field
-                happens to be a byte or halfword in memory
-                can be changed to a move instruction.  */
-
-             if (GET_CODE (PATTERN (insn)) == SET)
+             struct needs
                {
-                 rtx dest = SET_DEST (PATTERN (insn));
-                 rtx src = SET_SRC (PATTERN (insn));
-
-                 if (GET_CODE (dest) == ZERO_EXTRACT
-                     || GET_CODE (dest) == SIGN_EXTRACT)
-                   optimize_bit_field (PATTERN (insn), insn, reg_equiv_mem);
-                 if (GET_CODE (src) == ZERO_EXTRACT
-                     || GET_CODE (src) == SIGN_EXTRACT)
-                   optimize_bit_field (PATTERN (insn), insn, reg_equiv_mem);
-               }
-#endif
+                 /* [0] is normal, [1] is nongroup.  */
+                 int regs[2][N_REG_CLASSES];
+                 int groups[N_REG_CLASSES];
+               };
+
+             /* Each `struct needs' corresponds to one RELOAD_... type.  */
+             struct {
+               struct needs other;
+               struct needs input;
+               struct needs output;
+               struct needs insn;
+               struct needs other_addr;
+               struct needs op_addr;
+               struct needs op_addr_reload;
+               struct needs in_addr[MAX_RECOG_OPERANDS];
+               struct needs in_addr_addr[MAX_RECOG_OPERANDS];
+               struct needs out_addr[MAX_RECOG_OPERANDS];
+               struct needs out_addr_addr[MAX_RECOG_OPERANDS];
+             } insn_needs;
 
              /* If needed, eliminate any eliminable registers.  */
              if (num_eliminable)
@@ -993,7 +1084,7 @@ reload (first, global, dumpfile)
 #ifdef SMALL_REGISTER_CLASSES
              /* Set avoid_return_reg if this is an insn
                 that might use the value of a function call.  */
-             if (GET_CODE (insn) == CALL_INSN)
+             if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
                {
                  if (GET_CODE (PATTERN (insn)) == SET)
                    after_call = SET_DEST (PATTERN (insn));
@@ -1003,11 +1094,12 @@ reload (first, global, dumpfile)
                  else
                    after_call = 0;
                }
-             else if (after_call != 0
+             else if (SMALL_REGISTER_CLASSES
+                      && after_call != 0
                       && !(GET_CODE (PATTERN (insn)) == SET
                            && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
                {
-                 if (reg_mentioned_p (after_call, PATTERN (insn)))
+                 if (reg_referenced_p (after_call, PATTERN (insn)))
                    avoid_return_reg = after_call;
                  after_call = 0;
                }
@@ -1056,32 +1148,8 @@ reload (first, global, dumpfile)
                continue;
 
              something_needs_reloads = 1;
+             bzero ((char *) &insn_needs, sizeof insn_needs);
 
-             for (i = 0; i < N_REG_CLASSES; i++)
-               {
-                 insn_needs[i] = 0, insn_groups[i] = 0;
-                 insn_needs_for_inputs[i] = 0, insn_groups_for_inputs[i] = 0;
-                 insn_needs_for_outputs[i] = 0, insn_groups_for_outputs[i] = 0;
-                 insn_needs_for_insn[i] = 0, insn_groups_for_insn[i] = 0;
-                 insn_needs_for_op_addr[i] = 0, insn_groups_for_op_addr[i] = 0;
-                 insn_needs_for_other_addr[i] = 0;
-                 insn_groups_for_other_addr[i] = 0;
-               }
-
-             for (i = 0; i < reload_n_operands; i++)
-               {
-                 insn_total_groups_for_in_addr[i] = 0;
-                 insn_total_groups_for_out_addr[i] = 0;
-
-                 for (j = 0; j < N_REG_CLASSES; j++)
-                   {
-                     insn_needs_for_in_addr[i][j] = 0;
-                     insn_needs_for_out_addr[i][j] = 0;
-                     insn_groups_for_in_addr[i][j] = 0;
-                     insn_groups_for_out_addr[i][j] = 0;
-                   }
-               }
-                   
              /* Count each reload once in every class
                 containing the reload's own class.  */
 
@@ -1091,9 +1159,8 @@ reload (first, global, dumpfile)
                  enum reg_class class = reload_reg_class[i];
                  int size;
                  enum machine_mode mode;
-                 int *this_groups;
-                 int *this_needs;
-                 int *this_total_groups;
+                 int nongroup_need;
+                 struct needs *this_needs;
 
                  /* Don't count the dummy reloads, for which one of the
                     regs mentioned in the insn can be used for reloading.
@@ -1115,75 +1182,85 @@ reload (first, global, dumpfile)
                      new_basic_block_needs = 1;
                    }
 
+
+                 mode = reload_inmode[i];
+                 if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+                   mode = reload_outmode[i];
+                 size = CLASS_MAX_NREGS (class, mode);
+
+                 /* If this class doesn't want a group, determine if we have
+                    a nongroup need or a regular need.  We have a nongroup
+                    need if this reload conflicts with a group reload whose
+                    class intersects with this reload's class.  */
+
+                 nongroup_need = 0;
+                 if (size == 1)
+                   for (j = 0; j < n_reloads; j++)
+                     if ((CLASS_MAX_NREGS (reload_reg_class[j],
+                                           (GET_MODE_SIZE (reload_outmode[j])
+                                            > GET_MODE_SIZE (reload_inmode[j]))
+                                           ? reload_outmode[j]
+                                           : reload_inmode[j])
+                          > 1)
+                         && (!reload_optional[j])
+                         && (reload_in[j] != 0 || reload_out[j] != 0
+                             || reload_secondary_p[j])
+                         && reloads_conflict (i, j)
+                         && reg_classes_intersect_p (class,
+                                                     reload_reg_class[j]))
+                       {
+                         nongroup_need = 1;
+                         break;
+                       }
+
                  /* Decide which time-of-use to count this reload for.  */
                  switch (reload_when_needed[i])
                    {
                    case RELOAD_OTHER:
-                     this_needs = insn_needs;
-                     this_groups = insn_groups;
-                     this_total_groups = &insn_total_groups;
+                     this_needs = &insn_needs.other;
                      break;
-
                    case RELOAD_FOR_INPUT:
-                     this_needs = insn_needs_for_inputs;
-                     this_groups = insn_groups_for_inputs;
-                     this_total_groups = &insn_total_groups_for_inputs;
+                     this_needs = &insn_needs.input;
                      break;
-
                    case RELOAD_FOR_OUTPUT:
-                     this_needs = insn_needs_for_outputs;
-                     this_groups = insn_groups_for_outputs;
-                     this_total_groups = &insn_total_groups_for_outputs;
+                     this_needs = &insn_needs.output;
                      break;
-
                    case RELOAD_FOR_INSN:
-                     this_needs = insn_needs_for_insn;
-                     this_groups = insn_groups_for_insn;
-                     this_total_groups = &insn_total_groups_for_insn;
+                     this_needs = &insn_needs.insn;
                      break;
-
                    case RELOAD_FOR_OTHER_ADDRESS:
-                     this_needs = insn_needs_for_other_addr;
-                     this_groups = insn_groups_for_other_addr;
-                     this_total_groups = &insn_total_groups_for_other_addr;
+                     this_needs = &insn_needs.other_addr;
                      break;
-
                    case RELOAD_FOR_INPUT_ADDRESS:
-                     this_needs = insn_needs_for_in_addr[reload_opnum[i]];
-                     this_groups = insn_groups_for_in_addr[reload_opnum[i]];
-                     this_total_groups
-                       = &insn_total_groups_for_in_addr[reload_opnum[i]];
+                     this_needs = &insn_needs.in_addr[reload_opnum[i]];
+                     break;
+                   case RELOAD_FOR_INPADDR_ADDRESS:
+                     this_needs = &insn_needs.in_addr_addr[reload_opnum[i]];
                      break;
-
                    case RELOAD_FOR_OUTPUT_ADDRESS:
-                     this_needs = insn_needs_for_out_addr[reload_opnum[i]];
-                     this_groups = insn_groups_for_out_addr[reload_opnum[i]];
-                     this_total_groups
-                       = &insn_total_groups_for_out_addr[reload_opnum[i]];
+                     this_needs = &insn_needs.out_addr[reload_opnum[i]];
+                     break;
+                   case RELOAD_FOR_OUTADDR_ADDRESS:
+                     this_needs = &insn_needs.out_addr_addr[reload_opnum[i]];
                      break;
-
                    case RELOAD_FOR_OPERAND_ADDRESS:
-                     this_needs = insn_needs_for_op_addr;
-                     this_groups = insn_groups_for_op_addr;
-                     this_total_groups = &insn_total_groups_for_op_addr;
+                     this_needs = &insn_needs.op_addr;
+                     break;
+                   case RELOAD_FOR_OPADDR_ADDR:
+                     this_needs = &insn_needs.op_addr_reload;
                      break;
                    }
 
-                 mode = reload_inmode[i];
-                 if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
-                   mode = reload_outmode[i];
-                 size = CLASS_MAX_NREGS (class, mode);
                  if (size > 1)
                    {
                      enum machine_mode other_mode, allocate_mode;
 
                      /* Count number of groups needed separately from
                         number of individual regs needed.  */
-                     this_groups[(int) class]++;
+                     this_needs->groups[(int) class]++;
                      p = reg_class_superclasses[(int) class];
                      while (*p != LIM_REG_CLASSES)
-                       this_groups[(int) *p++]++;
-                     (*this_total_groups)++;
+                       this_needs->groups[(int) *p++]++;
 
                      /* Record size and mode of a group of this class.  */
                      /* If more than one size group is needed,
@@ -1205,19 +1282,18 @@ reload (first, global, dumpfile)
                      /* Crash if two dissimilar machine modes both need
                         groups of consecutive regs of the same class.  */
 
-                     if (other_mode != VOIDmode
-                         && other_mode != allocate_mode
+                     if (other_mode != VOIDmode && other_mode != allocate_mode
                          && ! modes_equiv_for_class_p (allocate_mode,
-                                                       other_mode,
-                                                       class))
-                       abort ();
+                                                       other_mode, class))
+                       fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class",
+                                   insn);
                    }
                  else if (size == 1)
                    {
-                     this_needs[(int) class] += 1;
+                     this_needs->regs[nongroup_need][(int) class] += 1;
                      p = reg_class_superclasses[(int) class];
                      while (*p != LIM_REG_CLASSES)
-                       this_needs[(int) *p++] += 1;
+                       this_needs->regs[nongroup_need][(int) *p++] += 1;
                    }
                  else
                    abort ();
@@ -1232,81 +1308,81 @@ reload (first, global, dumpfile)
                {
                  int in_max, out_max;
 
-                 for (in_max = 0, out_max = 0, j = 0;
-                      j < reload_n_operands; j++)
+                 /* Compute normal and nongroup needs.  */
+                 for (j = 0; j <= 1; j++)
                    {
-                     in_max = MAX (in_max, insn_needs_for_in_addr[j][i]);
-                     out_max = MAX (out_max, insn_needs_for_out_addr[j][i]);
-                   }
+                     for (in_max = 0, out_max = 0, k = 0;
+                          k < reload_n_operands; k++)
+                       {
+                         in_max
+                           = MAX (in_max, insn_needs.in_addr[k].regs[j][i]);
+                         in_max
+                           = MAX (in_max,
+                                  insn_needs.in_addr_addr[k].regs[j][i]);
+                         out_max
+                           = MAX (out_max, insn_needs.out_addr[k].regs[j][i]);
+                         out_max
+                           = MAX (out_max,
+                                  insn_needs.out_addr_addr[k].regs[j][i]);
+                       }
+
+                     /* RELOAD_FOR_INSN reloads conflict with inputs, outputs,
+                        and operand addresses but not things used to reload
+                        them.  Similarly, RELOAD_FOR_OPERAND_ADDRESS reloads
+                        don't conflict with things needed to reload inputs or
+                        outputs.  */
 
-                 /* RELOAD_FOR_INSN reloads conflict with inputs, outputs,
-                    and operand addresses but not things used to reload them.
-                    Similarly, RELOAD_FOR_OPERAND_ADDRESS reloads don't
-                    conflict with things needed to reload inputs or
-                    outputs. */
+                     in_max = MAX (MAX (insn_needs.op_addr.regs[j][i],
+                                        insn_needs.op_addr_reload.regs[j][i]),
+                                   in_max);
 
-                 in_max = MAX (in_max, insn_needs_for_op_addr[i]);
-                 out_max = MAX (out_max, insn_needs_for_insn[i]);
+                     out_max = MAX (out_max, insn_needs.insn.regs[j][i]);
 
-                 insn_needs_for_inputs[i]
-                   = MAX (insn_needs_for_inputs[i]
-                          + insn_needs_for_op_addr[i]
-                          + insn_needs_for_insn[i],
-                          in_max + insn_needs_for_inputs[i]);
+                     insn_needs.input.regs[j][i]
+                       = MAX (insn_needs.input.regs[j][i]
+                              + insn_needs.op_addr.regs[j][i]
+                              + insn_needs.insn.regs[j][i],
+                              in_max + insn_needs.input.regs[j][i]);
 
-                 insn_needs_for_outputs[i] += out_max;
-                 insn_needs[i] += MAX (MAX (insn_needs_for_inputs[i],
-                                            insn_needs_for_outputs[i]),
-                                       insn_needs_for_other_addr[i]);
+                     insn_needs.output.regs[j][i] += out_max;
+                     insn_needs.other.regs[j][i]
+                       += MAX (MAX (insn_needs.input.regs[j][i],
+                                    insn_needs.output.regs[j][i]),
+                               insn_needs.other_addr.regs[j][i]);
 
+                   }
+
+                 /* Now compute group needs.  */
                  for (in_max = 0, out_max = 0, j = 0;
                       j < reload_n_operands; j++)
                    {
-                     in_max = MAX (in_max, insn_groups_for_in_addr[j][i]);
-                     out_max = MAX (out_max, insn_groups_for_out_addr[j][i]);
+                     in_max = MAX (in_max, insn_needs.in_addr[j].groups[i]);
+                     in_max = MAX (in_max,
+                                    insn_needs.in_addr_addr[j].groups[i]);
+                     out_max
+                       = MAX (out_max, insn_needs.out_addr[j].groups[i]);
+                     out_max
+                       = MAX (out_max, insn_needs.out_addr_addr[j].groups[i]);
                    }
 
-                 in_max = MAX (in_max, insn_groups_for_op_addr[i]);
-                 out_max = MAX (out_max, insn_groups_for_insn[i]);
-
-                 insn_groups_for_inputs[i]
-                   = MAX (insn_groups_for_inputs[i]
-                          + insn_groups_for_op_addr[i]
-                          + insn_groups_for_insn[i],
-                          in_max + insn_groups_for_inputs[i]);
-
-                 insn_groups_for_outputs[i] += out_max;
-                 insn_groups[i] += MAX (MAX (insn_groups_for_inputs[i],
-                                             insn_groups_for_outputs[i]),
-                                        insn_groups_for_other_addr[i]);
+                 in_max = MAX (MAX (insn_needs.op_addr.groups[i],
+                                    insn_needs.op_addr_reload.groups[i]),
+                               in_max);
+                 out_max = MAX (out_max, insn_needs.insn.groups[i]);
+
+                 insn_needs.input.groups[i]
+                   = MAX (insn_needs.input.groups[i]
+                          + insn_needs.op_addr.groups[i]
+                          + insn_needs.insn.groups[i],
+                          in_max + insn_needs.input.groups[i]);
+
+                 insn_needs.output.groups[i] += out_max;
+                 insn_needs.other.groups[i]
+                   += MAX (MAX (insn_needs.input.groups[i],
+                                insn_needs.output.groups[i]),
+                           insn_needs.other_addr.groups[i]);
                }
 
-             for (i = 0; i < reload_n_operands; i++)
-               {
-                 max_total_input_groups
-                   = MAX (max_total_input_groups,
-                          insn_total_groups_for_in_addr[i]);
-                 max_total_output_groups
-                   = MAX (max_total_output_groups,
-                          insn_total_groups_for_out_addr[i]);
-               }
-
-             max_total_input_groups = MAX (max_total_input_groups,
-                                           insn_total_groups_for_op_addr);
-             max_total_output_groups = MAX (max_total_output_groups,
-                                            insn_total_groups_for_insn);
-
-             insn_total_groups_for_inputs
-               = MAX (max_total_input_groups + insn_total_groups_for_op_addr
-                      + insn_total_groups_for_insn,
-                      max_total_input_groups + insn_total_groups_for_inputs);
-
-             insn_total_groups_for_outputs += max_total_output_groups;
-
-             insn_total_groups += MAX (MAX (insn_total_groups_for_outputs,
-                                            insn_total_groups_for_inputs),
-                                       insn_total_groups_for_other_addr);
-
              /* If this is a CALL_INSN and caller-saves will need
                 a spill register, act as if the spill register is
                 needed for this insn.   However, the spill register
@@ -1326,8 +1402,29 @@ reload (first, global, dumpfile)
              if (GET_CODE (insn) == CALL_INSN
                  && caller_save_spill_class != NO_REGS)
                {
-                 int *caller_save_needs
-                   = (caller_save_group_size > 1 ? insn_groups : insn_needs);
+                 /* See if this register would conflict with any reload
+                    that needs a group.  */
+                 int nongroup_need = 0;
+                 int *caller_save_needs;
+
+                 for (j = 0; j < n_reloads; j++)
+                   if ((CLASS_MAX_NREGS (reload_reg_class[j],
+                                         (GET_MODE_SIZE (reload_outmode[j])
+                                          > GET_MODE_SIZE (reload_inmode[j]))
+                                         ? reload_outmode[j]
+                                         : reload_inmode[j])
+                        > 1)
+                       && reg_classes_intersect_p (caller_save_spill_class,
+                                                   reload_reg_class[j]))
+                     {
+                       nongroup_need = 1;
+                       break;
+                     }
+
+                 caller_save_needs 
+                   = (caller_save_group_size > 1
+                      ? insn_needs.other.groups
+                      : insn_needs.other.regs[nongroup_need]); 
 
                  if (caller_save_needs[(int) caller_save_spill_class] == 0)
                    {
@@ -1340,21 +1437,17 @@ reload (first, global, dumpfile)
                        caller_save_needs[(int) *p++] += 1;
                    }
 
-                 if (caller_save_group_size > 1)
-                   insn_total_groups = MAX (insn_total_groups, 1);
-
-
-                /* Show that this basic block will need a register of
+                 /* Show that this basic block will need a register of
                    this class.  */
 
-                if (global
-                    && ! (basic_block_needs[(int) caller_save_spill_class]
-                          [this_block]))
-                  {
-                    basic_block_needs[(int) caller_save_spill_class]
-                      [this_block] = 1;
-                    new_basic_block_needs = 1;
-                  }
+                 if (global
+                     && ! (basic_block_needs[(int) caller_save_spill_class]
+                           [this_block]))
+                   {
+                     basic_block_needs[(int) caller_save_spill_class]
+                       [this_block] = 1;
+                     new_basic_block_needs = 1;
+                   }
                }
 
 #ifdef SMALL_REGISTER_CLASSES
@@ -1365,7 +1458,8 @@ reload (first, global, dumpfile)
                 then add add an extra need in that class.
                 This makes sure we have a register available that does
                 not overlap the return value.  */
-             if (avoid_return_reg)
+
+             if (SMALL_REGISTER_CLASSES && avoid_return_reg)
                {
                  int regno = REGNO (avoid_return_reg);
                  int nregs
@@ -1377,8 +1471,10 @@ reload (first, global, dumpfile)
                     need only in the smallest class in which it
                     is required.  */
 
-                 bcopy (insn_needs, basic_needs, sizeof basic_needs);
-                 bcopy (insn_groups, basic_groups, sizeof basic_groups);
+                 bcopy ((char *) insn_needs.other.regs[0],
+                        (char *) basic_needs, sizeof basic_needs);
+                 bcopy ((char *) insn_needs.other.groups,
+                        (char *) basic_groups, sizeof basic_groups);
 
                  for (i = 0; i < N_REG_CLASSES; i++)
                    {
@@ -1396,26 +1492,30 @@ reload (first, global, dumpfile)
                    }
 
                  /* Now count extra regs if there might be a conflict with
-                    the return value register.
+                    the return value register.  */
 
-                    ??? This is not quite correct because we don't properly
-                    handle the case of groups, but if we end up doing
-                    something wrong, it either will end up not mattering or
-                    we will abort elsewhere.  */
-                  
                  for (r = regno; r < regno + nregs; r++)
                    if (spill_reg_order[r] >= 0)
                      for (i = 0; i < N_REG_CLASSES; i++)
                        if (TEST_HARD_REG_BIT (reg_class_contents[i], r))
                          {
-                           if (basic_needs[i] > 0 || basic_groups[i] > 0)
+                           if (basic_needs[i] > 0)
+                             {
+                               enum reg_class *p;
+
+                               insn_needs.other.regs[0][i]++;
+                               p = reg_class_superclasses[i];
+                               while (*p != LIM_REG_CLASSES)
+                                 insn_needs.other.regs[0][(int) *p++]++;
+                             }
+                           if (basic_groups[i] > 0)
                              {
                                enum reg_class *p;
 
-                               insn_needs[i]++;
+                               insn_needs.other.groups[i]++;
                                p = reg_class_superclasses[i];
                                while (*p != LIM_REG_CLASSES)
-                                 insn_needs[(int) *p++]++;
+                                 insn_needs.other.groups[(int) *p++]++;
                              }
                          }
                }
@@ -1425,22 +1525,21 @@ reload (first, global, dumpfile)
 
              for (i = 0; i < N_REG_CLASSES; i++)
                {
-                 if (max_needs[i] < insn_needs[i])
+                 if (max_needs[i] < insn_needs.other.regs[0][i])
                    {
-                     max_needs[i] = insn_needs[i];
+                     max_needs[i] = insn_needs.other.regs[0][i];
                      max_needs_insn[i] = insn;
                    }
-                 if (max_groups[i] < insn_groups[i])
+                 if (max_groups[i] < insn_needs.other.groups[i])
                    {
-                     max_groups[i] = insn_groups[i];
+                     max_groups[i] = insn_needs.other.groups[i];
                      max_groups_insn[i] = insn;
                    }
-                 if (insn_total_groups > 0)
-                   if (max_nongroups[i] < insn_needs[i])
-                     {
-                       max_nongroups[i] = insn_needs[i];
-                       max_nongroups_insn[i] = insn;
-                     }
+                 if (max_nongroups[i] < insn_needs.other.regs[1][i])
+                   {
+                     max_nongroups[i] = insn_needs.other.regs[1][i];
+                     max_nongroups_insn[i] = insn;
+                   }
                }
            }
          /* Note that there is a continue statement above.  */
@@ -1475,19 +1574,26 @@ reload (first, global, dumpfile)
       /* If we have caller-saves, set up the save areas and see if caller-save
         will need a spill register.  */
 
-      if (caller_save_needed
-         && ! setup_save_areas (&something_changed)
-         && caller_save_spill_class  == NO_REGS)
+      if (caller_save_needed)
        {
-         /* The class we will need depends on whether the machine
-            supports the sum of two registers for an address; see
-            find_address_reloads for details.  */
-
-         caller_save_spill_class
-           = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
-         caller_save_group_size
-           = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
-         something_changed = 1;
+         /* Set the offsets for setup_save_areas.  */
+         for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+              ep++)
+           ep->previous_offset = ep->max_offset;
+
+         if ( ! setup_save_areas (&something_changed)
+             && caller_save_spill_class  == NO_REGS)
+           {
+             /* The class we will need depends on whether the machine
+                supports the sum of two registers for an address; see
+             find_address_reloads for details.  */
+
+             caller_save_spill_class
+               = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
+             caller_save_group_size
+               = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
+             something_changed = 1;
+           }
        }
 
       /* See if anything that happened changes which eliminations are valid.
@@ -1554,12 +1660,21 @@ reload (first, global, dumpfile)
            {
              ep->can_eliminate_previous = 0;
              spill_hard_reg (ep->from, global, dumpfile, 1);
-             regs_ever_live[ep->from] = 1;
              something_changed = 1;
              num_eliminable--;
            }
        }
 
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+      /* If we didn't need a frame pointer last time, but we do now, spill
+        the hard frame pointer.  */
+      if (frame_pointer_needed && ! previous_frame_pointer_needed)
+       {
+         spill_hard_reg (HARD_FRAME_POINTER_REGNUM, global, dumpfile, 1);
+         something_changed = 1;
+       }
+#endif
+
       /* If all needs are met, we win.  */
 
       for (i = 0; i < N_REG_CLASSES; i++)
@@ -1572,7 +1687,7 @@ reload (first, global, dumpfile)
 
       /* Put all registers spilled so far back in potential_reload_regs, but
         put them at the front, since we've already spilled most of the
-        psuedos in them (we might have left some pseudos unspilled if they
+        pseudos in them (we might have left some pseudos unspilled if they
         were in a block that didn't need any spill registers of a conflicting
         class.  We used to try to mark off the need for those registers,
         but doing so properly is very complex and reallocating them is the
@@ -1642,7 +1757,8 @@ reload (first, global, dumpfile)
              /* If any single spilled regs happen to form groups,
                 count them now.  Maybe we don't really need
                 to spill another group.  */
-             count_possible_groups (group_size, group_mode, max_groups);
+             count_possible_groups (group_size, group_mode, max_groups,
+                                    class);
 
              if (max_groups[class] <= 0)
                break;
@@ -1686,7 +1802,11 @@ reload (first, global, dumpfile)
                          max_groups[class]--;
                          p = reg_class_superclasses[class];
                          while (*p != LIM_REG_CLASSES)
-                           max_groups[(int) *p++]--;
+                           {
+                             if (group_size [(int) *p] <= group_size [class])
+                               max_groups[(int) *p]--;
+                             p++;
+                           }
 
                          /* Indicate both these regs are part of a group.  */
                          SET_HARD_REG_BIT (counted_for_groups, j);
@@ -1697,7 +1817,7 @@ reload (first, global, dumpfile)
                  /* We can't complete a group, so start one.  */
 #ifdef SMALL_REGISTER_CLASSES
                  /* Look for a pair neither of which is explicitly used.  */
-                 if (i == FIRST_PSEUDO_REGISTER)
+                 if (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER)
                    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                      {
                        int k;
@@ -1801,8 +1921,12 @@ reload (first, global, dumpfile)
                              max_groups[class]--;
                              p = reg_class_superclasses[class];
                              while (*p != LIM_REG_CLASSES)
-                               max_groups[(int) *p++]--;
-
+                               {
+                                 if (group_size [(int) *p]
+                                     <= group_size [class])
+                                   max_groups[(int) *p]--;
+                                 p++;
+                               }
                              break;
                            }
                        }
@@ -1823,10 +1947,6 @@ reload (first, global, dumpfile)
 
          while (max_needs[class] > 0 || max_nongroups[class] > 0)
            {
-#ifdef SMALL_REGISTER_CLASSES
-             /* This should be right for all machines, but only the 386
-                is known to need it, so this conditional plays safe.
-                ??? For 2.5, try making this unconditional.  */
              /* If we spilled enough regs, but they weren't counted
                 against the non-group need, see if we can count them now.
                 If so, we can avoid some actual spilling.  */
@@ -1850,7 +1970,6 @@ reload (first, global, dumpfile)
                    }
              if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
                break;
-#endif
 
              /* Consider the potential reload regs that aren't
                 yet in use as reload regs, in order of preference.
@@ -2006,6 +2125,10 @@ reload (first, global, dumpfile)
        }
     }
 
+  /* Do a very simple CSE pass over just the hard registers.  */
+  if (optimize > 0)
+    reload_cse_regs (first);
+
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
   /* Make a pass over all the insns and remove death notes for things that
      are no longer registers or no longer die in the insn (e.g., an input
@@ -2038,6 +2161,10 @@ reload (first, global, dumpfile)
     free (scratch_block);
   scratch_block = 0;
 
+  CLEAR_HARD_REG_SET (used_spill_regs);
+  for (i = 0; i < n_spills; i++)
+    SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
+
   return failure;
 }
 \f
@@ -2102,68 +2229,69 @@ possible_group_p (regno, max_groups)
   return 0;
 }
 \f
-/* Count any groups that can be formed from the registers recently spilled.
-   This is done class by class, in order of ascending class number.  */
+/* Count any groups of CLASS that can be formed from the registers recently
+   spilled.  */
 
 static void
-count_possible_groups (group_size, group_mode, max_groups)
+count_possible_groups (group_size, group_mode, max_groups, class)
      int *group_size;
      enum machine_mode *group_mode;
      int *max_groups;
+     int class;
 {
-  int i;
+  HARD_REG_SET new;
+  int i, j;
+
   /* Now find all consecutive groups of spilled registers
      and mark each group off against the need for such groups.
      But don't count them against ordinary need, yet.  */
 
-  for (i = 0; i < N_REG_CLASSES; i++)
-    if (group_size[i] > 1)
+  if (group_size[class] == 0)
+    return;
+
+  CLEAR_HARD_REG_SET (new);
+
+  /* Make a mask of all the regs that are spill regs in class I.  */
+  for (i = 0; i < n_spills; i++)
+    if (TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
+       && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i])
+       && ! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]))
+      SET_HARD_REG_BIT (new, spill_regs[i]);
+
+  /* Find each consecutive group of them.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER && max_groups[class] > 0; i++)
+    if (TEST_HARD_REG_BIT (new, i)
+       && i + group_size[class] <= FIRST_PSEUDO_REGISTER
+       && HARD_REGNO_MODE_OK (i, group_mode[class]))
       {
-       HARD_REG_SET new;
-       int j;
-
-       CLEAR_HARD_REG_SET (new);
-
-       /* Make a mask of all the regs that are spill regs in class I.  */
-       for (j = 0; j < n_spills; j++)
-         if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j])
-             && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j])
-             && ! TEST_HARD_REG_BIT (counted_for_nongroups,
-                                     spill_regs[j]))
-           SET_HARD_REG_BIT (new, spill_regs[j]);
-
-       /* Find each consecutive group of them.  */
-       for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++)
-         if (TEST_HARD_REG_BIT (new, j)
-             && j + group_size[i] <= FIRST_PSEUDO_REGISTER
-             /* Next line in case group-mode for this class
-                demands an even-odd pair.  */
-             && HARD_REGNO_MODE_OK (j, group_mode[i]))
-           {
-             int k;
-             for (k = 1; k < group_size[i]; k++)
-               if (! TEST_HARD_REG_BIT (new, j + k))
-                 break;
-             if (k == group_size[i])
-               {
-                 /* We found a group.  Mark it off against this class's
-                    need for groups, and against each superclass too.  */
-                 register enum reg_class *p;
-                 max_groups[i]--;
-                 p = reg_class_superclasses[i];
-                 while (*p != LIM_REG_CLASSES)
-                   max_groups[(int) *p++]--;
-                 /* Don't count these registers again.  */
-                 for (k = 0; k < group_size[i]; k++)
-                   SET_HARD_REG_BIT (counted_for_groups, j + k);
-               }
-             /* Skip to the last reg in this group.  When j is incremented
-                above, it will then point to the first reg of the next
-                possible group.  */
-             j += k - 1;
-           }
-      }
+       for (j = 1; j < group_size[class]; j++)
+         if (! TEST_HARD_REG_BIT (new, i + j))
+           break;
+
+       if (j == group_size[class])
+         {
+           /* We found a group.  Mark it off against this class's need for
+              groups, and against each superclass too.  */
+           register enum reg_class *p;
+
+           max_groups[class]--;
+           p = reg_class_superclasses[class];
+           while (*p != LIM_REG_CLASSES)
+             {
+               if (group_size [(int) *p] <= group_size [class])
+                 max_groups[(int) *p]--;
+               p++;
+             }
 
+           /* Don't count these registers again.  */
+           for (j = 0; j < group_size[class]; j++)
+             SET_HARD_REG_BIT (counted_for_groups, i + j);
+         }
+
+       /* Skip to the last reg in this group.  When i is incremented above,
+          it will then point to the first reg of the next possible group.  */
+       i += j - 1;
+      }
 }
 \f
 /* ALLOCATE_MODE is a register mode that needs to be reloaded.  OTHER_MODE is
@@ -2204,7 +2332,7 @@ spill_failure (insn)
   if (asm_noperands (PATTERN (insn)) >= 0)
     error_for_asm (insn, "`asm' needs too many reloads");
   else
-    abort ();
+    fatal_insn ("Unable to find a register to spill.", insn);
 }
 
 /* Add a new register to the tables of available spill-registers
@@ -2234,7 +2362,8 @@ new_spill_reg (i, class, max_needs, max_nongroups, global, dumpfile)
 
   if (fixed_regs[regno] || TEST_HARD_REG_BIT (forbidden_regs, regno))
     fatal ("fixed or forbidden register was spilled.\n\
-This may be due to a compiler bug or to impossible asm statements.");
+This may be due to a compiler bug or to impossible asm\n\
+statements or clauses.");
 
   /* Make reg REGNO an additional reload reg.  */
 
@@ -2362,14 +2491,16 @@ alter_reg (i, from_reg)
       if (from_reg == -1)
        {
          /* No known place to spill from => no slot to reuse.  */
-         x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
-#if BYTES_BIG_ENDIAN
-         /* Cancel the  big-endian correction done in assign_stack_local.
-            Get the address of the beginning of the slot.
-            This is so we can do a big-endian correction unconditionally
-            below.  */
-         adjust = inherent_size - total_size;
-#endif
+         x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
+                                 inherent_size == total_size ? 0 : -1);
+         if (BYTES_BIG_ENDIAN)
+           /* Cancel the  big-endian correction done in assign_stack_local.
+              Get the address of the beginning of the slot.
+              This is so we can do a big-endian correction unconditionally
+              below.  */
+           adjust = inherent_size - total_size;
+
+         RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
        }
       /* Reuse a stack slot if possible.  */
       else if (spill_stack_slot[from_reg] != 0
@@ -2383,6 +2514,7 @@ alter_reg (i, from_reg)
          /* Compute maximum size needed, both for inherent size
             and for total size.  */
          enum machine_mode mode = GET_MODE (regno_reg_rtx[i]);
+         rtx stack_slot;
          if (spill_stack_slot[from_reg])
            {
              if (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
@@ -2392,24 +2524,30 @@ alter_reg (i, from_reg)
                total_size = spill_stack_slot_width[from_reg];
            }
          /* Make a slot with that size.  */
-         x = assign_stack_local (mode, total_size, -1);
-#if BYTES_BIG_ENDIAN
-         /* Cancel the  big-endian correction done in assign_stack_local.
-            Get the address of the beginning of the slot.
-            This is so we can do a big-endian correction unconditionally
-            below.  */
-         adjust = GET_MODE_SIZE (mode) - total_size;
-#endif
-         spill_stack_slot[from_reg] = x;
+         x = assign_stack_local (mode, total_size,
+                                 inherent_size == total_size ? 0 : -1);
+         stack_slot = x;
+         if (BYTES_BIG_ENDIAN)
+           {
+             /* Cancel the  big-endian correction done in assign_stack_local.
+                Get the address of the beginning of the slot.
+                This is so we can do a big-endian correction unconditionally
+                below.  */
+             adjust = GET_MODE_SIZE (mode) - total_size;
+             if (adjust)
+               stack_slot = gen_rtx (MEM, mode_for_size (total_size
+                                                         * BITS_PER_UNIT,
+                                                         MODE_INT, 1),
+                                     plus_constant (XEXP (x, 0), adjust));
+           }
+         spill_stack_slot[from_reg] = stack_slot;
          spill_stack_slot_width[from_reg] = total_size;
        }
 
-#if BYTES_BIG_ENDIAN
       /* On a big endian machine, the "address" of the slot
         is the address of the low part that fits its inherent mode.  */
-      if (inherent_size < total_size)
+      if (BYTES_BIG_ENDIAN && inherent_size < total_size)
        adjust += (total_size - inherent_size);
-#endif /* BYTES_BIG_ENDIAN */
 
       /* If we have any adjustment to make, or if the stack slot is the
         wrong mode, make a new stack slot.  */
@@ -2484,7 +2622,7 @@ set_label_offsets (x, insn, initial_p)
 
       x = XEXP (x, 0);
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case CODE_LABEL:
       /* If we know nothing about this label, set the desired offsets.  Note
@@ -2539,7 +2677,7 @@ set_label_offsets (x, insn, initial_p)
     case JUMP_INSN:
       set_label_offsets (PATTERN (insn), insn, initial_p);
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case INSN:
     case CALL_INSN:
@@ -2644,10 +2782,11 @@ static struct rtvec_def *old_asm_operands_vec, *new_asm_operands_vec;
    the proper thing.  */
 
 rtx
-eliminate_regs (x, mem_mode, insn)
+eliminate_regs (x, mem_mode, insn, storing)
      rtx x;
      enum machine_mode mem_mode;
      rtx insn;
+     int storing;
 {
   enum rtx_code code = GET_CODE (x);
   struct elim_table *ep;
@@ -2704,7 +2843,7 @@ eliminate_regs (x, mem_mode, insn)
             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);
+                               mem_mode, insn, 0);
          if (new != reg_equiv_memory_loc[regno])
            {
              cannot_omit_stores[regno] = 1;
@@ -2766,8 +2905,8 @@ eliminate_regs (x, mem_mode, insn)
         reload.  This is the desired action.  */
 
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
+       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0);
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          {
@@ -2800,16 +2939,63 @@ eliminate_regs (x, mem_mode, insn)
       }
       return x;
 
+    case MULT:
+      /* If this is the product of an eliminable register and a 
+        constant, apply the distribute law and move the constant out
+        so that we have (plus (mult ..) ..).  This is needed in order
+        to keep load-address insns valid.   This case is pathological.
+        We ignore the possibility of overflow here.  */
+      if (GET_CODE (XEXP (x, 0)) == REG
+         && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
+         && GET_CODE (XEXP (x, 1)) == CONST_INT)
+       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+            ep++)
+         if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate)
+           {
+             if (! mem_mode
+                 /* Refs inside notes don't count for this purpose.  */
+                 && ! (insn != 0 && (GET_CODE (insn) == EXPR_LIST
+                                     || GET_CODE (insn) == INSN_LIST)))
+               ep->ref_outside_mem = 1;
+
+             return
+               plus_constant (gen_rtx (MULT, Pmode, ep->to_rtx, XEXP (x, 1)),
+                              ep->previous_offset * INTVAL (XEXP (x, 1)));
+           }
+
+      /* ... fall through ...  */
+
+    case CALL:
+    case COMPARE:
+    case MINUS:
+    case DIV:      case UDIV:
+    case MOD:      case UMOD:
+    case AND:      case IOR:      case XOR:
+    case ROTATERT: case ROTATE:
+    case ASHIFTRT: case LSHIFTRT: case ASHIFT:
+    case NE:       case EQ:
+    case GE:       case GT:       case GEU:    case GTU:
+    case LE:       case LT:       case LEU:    case LTU:
+      {
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
+       rtx new1
+         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn, 0) : 0;
+
+       if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
+         return gen_rtx (code, GET_MODE (x), new0, new1);
+      }
+      return x;
+
     case EXPR_LIST:
       /* If we have something in XEXP (x, 0), the usual case, eliminate it.  */
       if (XEXP (x, 0))
        {
-         new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+         new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
          if (new != XEXP (x, 0))
            x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1));
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case INSN_LIST:
       /* Now do eliminations in the rest of the chain.  If this was
@@ -2817,34 +3003,12 @@ eliminate_regs (x, mem_mode, insn)
         strictly needed, but it simplifies the code.  */
       if (XEXP (x, 1))
        {
-         new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+         new = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0);
          if (new != XEXP (x, 1))
            return gen_rtx (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
        }
       return x;
 
-    case CALL:
-    case COMPARE:
-    case MINUS:
-    case MULT:
-    case DIV:      case UDIV:
-    case MOD:      case UMOD:
-    case AND:      case IOR:      case XOR:
-    case LSHIFT:   case ASHIFT:   case ROTATE:
-    case ASHIFTRT: case LSHIFTRT: case ROTATERT:
-    case NE:       case EQ:
-    case GE:       case GT:       case GEU:    case GTU:
-    case LE:       case LT:       case LEU:    case LTU:
-      {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1
-         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
-
-       if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
-         return gen_rtx (code, GET_MODE (x), new0, new1);
-      }
-      return x;
-
     case PRE_INC:
     case POST_INC:
     case PRE_DEC:
@@ -2866,7 +3030,6 @@ eliminate_regs (x, mem_mode, insn)
          }
 
       /* Fall through to generic unary operation case.  */
-    case USE:
     case STRICT_LOW_PART:
     case NEG:          case NOT:
     case SIGN_EXTEND:  case ZERO_EXTEND:
@@ -2876,7 +3039,7 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
       if (new != XEXP (x, 0))
        return gen_rtx (code, GET_MODE (x), new);
       return x;
@@ -2895,43 +3058,65 @@ eliminate_regs (x, mem_mode, insn)
          && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
        {
          new = eliminate_regs (reg_equiv_memory_loc[REGNO (SUBREG_REG (x))],
-                               mem_mode, insn);
+                               mem_mode, insn, 0);
 
          /* If we didn't change anything, we must retain the pseudo.  */
          if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))])
-           new = XEXP (x, 0);
+           new = SUBREG_REG (x);
          else
-           /* Otherwise, ensure NEW isn't shared in case we have to reload
-              it.  */
-           new = copy_rtx (new);
+           {
+             /* Otherwise, ensure NEW isn't shared in case we have to reload
+                it.  */
+             new = copy_rtx (new);
+
+             /* In this case, we must show that the pseudo is used in this
+                insn so that delete_output_reload will do the right thing.  */
+             if (insn != 0 && GET_CODE (insn) != EXPR_LIST
+                 && GET_CODE (insn) != INSN_LIST)
+               emit_insn_before (gen_rtx (USE, VOIDmode, SUBREG_REG (x)),
+                                 insn);
+           }
        }
       else
-       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
+       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn, 0);
 
       if (new != XEXP (x, 0))
        {
-         if (GET_CODE (new) == MEM
-             && (GET_MODE_SIZE (GET_MODE (x))
-                 <= GET_MODE_SIZE (GET_MODE (new)))
+         int x_size = GET_MODE_SIZE (GET_MODE (x));
+         int new_size = GET_MODE_SIZE (GET_MODE (new));
+
+         /* When asked to spill a partial word subreg, we need to go
+            ahead and spill the whole thing against the possibility
+            that we reload the whole reg and find garbage at the top.  */
+         if (storing
+             && GET_CODE (new) == MEM
+             && x_size < new_size
+             && ((x_size + UNITS_PER_WORD-1) / UNITS_PER_WORD
+                 == (new_size + UNITS_PER_WORD-1) / UNITS_PER_WORD))
+           return new;
+         else if (GET_CODE (new) == MEM
+                  && x_size <= new_size
 #ifdef LOAD_EXTEND_OP
-             /* On these machines we will be reloading what is
-                inside the SUBREG if it originally was a pseudo and
-                the inner and outer modes are both a word or
-                smaller.  So leave the SUBREG then.  */
-             && ! (GET_CODE (SUBREG_REG (x)) == REG
-                   && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
-                   && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+                  /* On these machines we will be reloading what is
+                     inside the SUBREG if it originally was a pseudo and
+                     the inner and outer modes are both a word or
+                     smaller.  So leave the SUBREG then.  */
+                  && ! (GET_CODE (SUBREG_REG (x)) == REG
+                        && x_size <= UNITS_PER_WORD
+                        && new_size <= UNITS_PER_WORD
+                        && x_size > new_size
+                        && INTEGRAL_MODE_P (GET_MODE (new))
+                        && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
 #endif
-             )
+                  )
            {
              int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
              enum machine_mode mode = GET_MODE (x);
 
-#if BYTES_BIG_ENDIAN
-             offset += (MIN (UNITS_PER_WORD,
-                             GET_MODE_SIZE (GET_MODE (new)))
-                        - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-#endif
+             if (BYTES_BIG_ENDIAN)
+               offset += (MIN (UNITS_PER_WORD,
+                               GET_MODE_SIZE (GET_MODE (new)))
+                          - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
 
              PUT_MODE (new, mode);
              XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
@@ -2943,6 +3128,19 @@ eliminate_regs (x, mem_mode, insn)
 
       return x;
 
+    case USE:
+      /* If using a register that is the source of an eliminate we still
+        think can be performed, note it cannot be performed since we don't
+        know how this register is used.  */
+      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+       if (ep->from_rtx == XEXP (x, 0))
+         ep->can_eliminate = 0;
+
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
+      if (new != XEXP (x, 0))
+       return gen_rtx (code, GET_MODE (x), new);
+      return x;
+
     case CLOBBER:
       /* If clobbering a register that is the replacement register for an
         elimination we still think can be performed, note that it cannot
@@ -2951,7 +3149,7 @@ eliminate_regs (x, mem_mode, insn)
        if (ep->to_rtx == XEXP (x, 0))
          ep->can_eliminate = 0;
 
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
       if (new != XEXP (x, 0))
        return gen_rtx (code, GET_MODE (x), new);
       return x;
@@ -2969,7 +3167,7 @@ eliminate_regs (x, mem_mode, insn)
            temp_vec = (rtx *) alloca (XVECLEN (x, 3) * sizeof (rtx));
            for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
              temp_vec[i] = eliminate_regs (ASM_OPERANDS_INPUT (x, i),
-                                           mem_mode, insn);
+                                           mem_mode, insn, 0);
 
            for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
              if (temp_vec[i] != ASM_OPERANDS_INPUT (x, i))
@@ -3040,8 +3238,8 @@ eliminate_regs (x, mem_mode, insn)
 
       /* Now avoid the loop below in this common case.  */
       {
-       rtx new0 = eliminate_regs (SET_DEST (x), 0, insn);
-       rtx new1 = eliminate_regs (SET_SRC (x), 0, insn);
+       rtx new0 = eliminate_regs (SET_DEST (x), 0, insn, 1);
+       rtx new1 = eliminate_regs (SET_SRC (x), 0, insn, 0);
 
        /* If SET_DEST changed from a REG to a MEM and INSN is an insn,
           write a CLOBBER insn.  */
@@ -3060,7 +3258,7 @@ eliminate_regs (x, mem_mode, insn)
       /* Our only special processing is to pass the mode of the MEM to our
         recursive call and copy the flags.  While we are here, handle this
         case more efficiently.  */
-      new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn);
+      new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn, 0);
       if (new != XEXP (x, 0))
        {
          new = gen_rtx (MEM, GET_MODE (x), new);
@@ -3080,13 +3278,13 @@ eliminate_regs (x, mem_mode, insn)
     {
       if (*fmt == 'e')
        {
-         new = eliminate_regs (XEXP (x, i), mem_mode, insn);
+         new = eliminate_regs (XEXP (x, i), mem_mode, insn, 0);
          if (new != XEXP (x, i) && ! copied)
            {
              rtx new_x = rtx_alloc (code);
-             bcopy (x, new_x, (sizeof (*new_x) - sizeof (new_x->fld)
-                               + (sizeof (new_x->fld[0])
-                                  * GET_RTX_LENGTH (code))));
+             bcopy ((char *) x, (char *) new_x,
+                    (sizeof (*new_x) - sizeof (new_x->fld)
+                     + sizeof (new_x->fld[0]) * GET_RTX_LENGTH (code)));
              x = new_x;
              copied = 1;
            }
@@ -3097,17 +3295,18 @@ eliminate_regs (x, mem_mode, insn)
          int copied_vec = 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
+             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn, 0);
              if (new != XVECEXP (x, i, j) && ! copied_vec)
                {
-                 rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
-                                            &XVECEXP (x, i, 0));
+                 rtvec new_v = gen_rtvec_vv (XVECLEN (x, i),
+                                             XVEC (x, i)->elem);
                  if (! copied)
                    {
                      rtx new_x = rtx_alloc (code);
-                     bcopy (x, new_x, (sizeof (*new_x) - sizeof (new_x->fld)
-                                       + (sizeof (new_x->fld[0])
-                                          * GET_RTX_LENGTH (code))));
+                     bcopy ((char *) x, (char *) new_x,
+                            (sizeof (*new_x) - sizeof (new_x->fld)
+                             + (sizeof (new_x->fld[0])
+                                * GET_RTX_LENGTH (code))));
                      x = new_x;
                      copied = 1;
                    }
@@ -3141,6 +3340,7 @@ eliminate_regs_in_insn (insn, replace)
      int replace;
 {
   rtx old_body = PATTERN (insn);
+  rtx old_set = single_set (insn);
   rtx new_body;
   int val = 0;
   struct elim_table *ep;
@@ -3148,18 +3348,79 @@ eliminate_regs_in_insn (insn, replace)
   if (! replace)
     push_obstacks (&reload_obstack, &reload_obstack);
 
-  if (GET_CODE (old_body) == SET && GET_CODE (SET_DEST (old_body)) == REG
-      && REGNO (SET_DEST (old_body)) < FIRST_PSEUDO_REGISTER)
+  if (old_set != 0 && GET_CODE (SET_DEST (old_set)) == REG
+      && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER)
     {
       /* Check for setting an eliminable register.  */
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
-       if (ep->from_rtx == SET_DEST (old_body) && ep->can_eliminate)
+       if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate)
          {
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+           /* If this is setting the frame pointer register to the
+              hardware frame pointer register and this is an elimination
+              that will be done (tested above), this insn is really
+              adjusting the frame pointer downward to compensate for
+              the adjustment done before a nonlocal goto.  */
+           if (ep->from == FRAME_POINTER_REGNUM
+               && ep->to == HARD_FRAME_POINTER_REGNUM)
+             {
+               rtx src = SET_SRC (old_set);
+               int offset, ok = 0;
+               rtx prev_insn, prev_set;
+
+               if (src == ep->to_rtx)
+                 offset = 0, ok = 1;
+               else if (GET_CODE (src) == PLUS
+                        && GET_CODE (XEXP (src, 0)) == CONST_INT)
+                 offset = INTVAL (XEXP (src, 0)), ok = 1;
+               else if ((prev_insn = prev_nonnote_insn (insn)) != 0
+                        && (prev_set = single_set (prev_insn)) != 0
+                        && rtx_equal_p (SET_DEST (prev_set), src))
+                 {
+                   src = SET_SRC (prev_set);
+                   if (src == ep->to_rtx)
+                     offset = 0, ok = 1;
+                   else if (GET_CODE (src) == PLUS
+                            && GET_CODE (XEXP (src, 0)) == CONST_INT
+                            && XEXP (src, 1) == ep->to_rtx)
+                     offset = INTVAL (XEXP (src, 0)), ok = 1;
+                   else if (GET_CODE (src) == PLUS
+                            && GET_CODE (XEXP (src, 1)) == CONST_INT
+                            && XEXP (src, 0) == ep->to_rtx)
+                     offset = INTVAL (XEXP (src, 1)), ok = 1;
+                 }
+
+               if (ok)
+                 {
+                   if (replace)
+                     {
+                       rtx src
+                         = plus_constant (ep->to_rtx, offset - ep->offset);
+
+                       /* First see if this insn remains valid when we
+                          make the change.  If not, keep the INSN_CODE
+                          the same and let reload fit it up.  */
+                       validate_change (insn, &SET_SRC (old_set), src, 1);
+                       validate_change (insn, &SET_DEST (old_set),
+                                        ep->to_rtx, 1);
+                       if (! apply_change_group ())
+                         {
+                           SET_SRC (old_set) = src;
+                           SET_DEST (old_set) = ep->to_rtx;
+                         }
+                     }
+
+                   val = 1;
+                   goto done;
+                 }
+             }
+#endif
+
            /* In this case this insn isn't serving a useful purpose.  We
               will delete it in reload_as_needed once we know that this
               elimination is, in fact, being done.
 
-              If REPLACE isn't set, we can't delete this insn, but neededn't
+              If REPLACE isn't set, we can't delete this insn, but needn't
               process it since it won't be used unless something changes.  */
            if (replace)
              delete_dead_insn (insn);
@@ -3174,22 +3435,25 @@ eliminate_regs_in_insn (insn, replace)
         We have to do this here, rather than in eliminate_regs, do that we can
         change the insn code.  */
 
-      if (GET_CODE (SET_SRC (old_body)) == PLUS
-         && GET_CODE (XEXP (SET_SRC (old_body), 0)) == REG
-         && GET_CODE (XEXP (SET_SRC (old_body), 1)) == CONST_INT)
+      if (GET_CODE (SET_SRC (old_set)) == PLUS
+         && GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
+         && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT)
        for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
             ep++)
-         if (ep->from_rtx == XEXP (SET_SRC (old_body), 0)
+         if (ep->from_rtx == XEXP (SET_SRC (old_set), 0)
              && ep->can_eliminate)
            {
              /* We must stop at the first elimination that will be used.
                 If this one would replace the PLUS with a REG, do it
                 now.  Otherwise, quit the loop and let eliminate_regs
                 do its normal replacement.  */
-             if (ep->offset == - INTVAL (XEXP (SET_SRC (old_body), 1)))
+             if (ep->offset == - INTVAL (XEXP (SET_SRC (old_set), 1)))
                {
+                 /* We assume here that we don't need a PARALLEL of
+                    any CLOBBERs for this assignment.  There's not
+                    much we can do if we do need it.  */
                  PATTERN (insn) = gen_rtx (SET, VOIDmode,
-                                           SET_DEST (old_body), ep->to_rtx);
+                                           SET_DEST (old_set), ep->to_rtx);
                  INSN_CODE (insn) = -1;
                  val = 1;
                  goto done;
@@ -3207,37 +3471,40 @@ eliminate_regs_in_insn (insn, replace)
      If we are replacing a body that was a (set X (plus Y Z)), try to
      re-recognize the insn.  We do this in case we had a simple addition
      but now can do this as a load-address.  This saves an insn in this
-     common case. */
+     common case.  */
 
-  new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX);
+  new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX, 0);
   if (new_body != old_body)
     {
       /* If we aren't replacing things permanently and we changed something,
         make another copy to ensure that all the RTL is new.  Otherwise
         things can go wrong if find_reload swaps commutative operands
-        and one is inside RTL that has been copied while the other is not. */
+        and one is inside RTL that has been copied while the other is not.  */
 
       /* Don't copy an asm_operands because (1) there's no need and (2)
         copy_rtx can't do it properly when there are multiple outputs.  */
       if (! replace && asm_noperands (old_body) < 0)
        new_body = copy_rtx (new_body);
 
-      /* If we had a move insn but now we don't, rerecognize it.  */
-      if ((GET_CODE (old_body) == SET && GET_CODE (SET_SRC (old_body)) == REG
-          && (GET_CODE (new_body) != SET
-              || GET_CODE (SET_SRC (new_body)) != REG))
-         /* If this was a load from or store to memory, compare
-            the MEM in recog_operand to the one in the insn.  If they
-            are not equal, then rerecognize the insn.  */
-         || (GET_CODE (old_body) == SET
-             && ((GET_CODE (SET_SRC (old_body)) == MEM
-                  && SET_SRC (old_body) != recog_operand[1])
-                 || (GET_CODE (SET_DEST (old_body)) == MEM
-                     && SET_DEST (old_body) != recog_operand[0])))
-         /* If this was an add insn before, rerecognize.  */
-         ||
-         (GET_CODE (old_body) == SET
-          && GET_CODE (SET_SRC (old_body)) == PLUS))
+      /* If we had a move insn but now we don't, rerecognize it.  This will
+        cause spurious re-recognition if the old move had a PARALLEL since
+        the new one still will, but we can't call single_set without
+        having put NEW_BODY into the insn and the re-recognition won't
+        hurt in this rare case.  */
+      if (old_set != 0
+         && ((GET_CODE (SET_SRC (old_set)) == REG
+              && (GET_CODE (new_body) != SET
+                  || GET_CODE (SET_SRC (new_body)) != REG))
+             /* If this was a load from or store to memory, compare
+                the MEM in recog_operand to the one in the insn.  If they
+                are not equal, then rerecognize the insn.  */
+             || (old_set != 0
+                 && ((GET_CODE (SET_SRC (old_set)) == MEM
+                      && SET_SRC (old_set) != recog_operand[1])
+                     || (GET_CODE (SET_DEST (old_set)) == MEM
+                         && SET_DEST (old_set) != recog_operand[0])))
+             /* If this was an add insn before, rerecognize.  */
+             || GET_CODE (SET_SRC (old_set)) == PLUS))
        {
          if (! validate_change (insn, &PATTERN (insn), new_body, 0))
            /* If recognition fails, store the new body anyway.
@@ -3289,13 +3556,13 @@ eliminate_regs_in_insn (insn, replace)
     }
 
  done:
-  /* If we changed something, perform elmination in REG_NOTES.  This is
+  /* If we changed something, perform elimination in REG_NOTES.  This is
      needed even when REPLACE is zero because a REG_DEAD note might refer
      to a register that we eliminate and could cause a different number
      of spill registers to be needed in the final reload pass than in
      the pre-passes.  */
   if (val && REG_NOTES (insn) != 0)
-    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn));
+    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn), 0);
 
   if (! replace)
     pop_obstacks ();
@@ -3371,6 +3638,9 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
 
   SET_HARD_REG_BIT (forbidden_regs, regno);
 
+  if (cant_eliminate)
+    regs_ever_live[regno] = 1;
+
   /* Spill every pseudo reg that was allocated to this reg
      or to something that overlaps this reg.  */
 
@@ -3408,7 +3678,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
        /* We will need to scan everything again.  */
        something_changed = 1;
        if (global)
-           retry_global_alloc (i, forbidden_regs);
+         retry_global_alloc (i, forbidden_regs);
 
        alter_reg (i, regno);
        if (dumpfile)
@@ -3447,7 +3717,9 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
   return something_changed;
 }
 \f
-/* Find all paradoxical subregs within X and update reg_max_ref_width.  */
+/* Find all paradoxical subregs within X and update reg_max_ref_width. 
+   Also mark any hard registers used to store user variables as
+   forbidden from being used for spill registers.  */
 
 static void
 scan_paradoxical_subregs (x)
@@ -3459,6 +3731,15 @@ scan_paradoxical_subregs (x)
 
   switch (code)
     {
+    case REG:
+#ifdef SMALL_REGISTER_CLASSES
+      if (SMALL_REGISTER_CLASSES
+         && REGNO (x) < FIRST_PSEUDO_REGISTER
+         && REG_USERVAR_P (x))
+       SET_HARD_REG_BIT (forbidden_regs, REGNO (x));
+#endif
+      return;
+
     case CONST_INT:
     case CONST:
     case SYMBOL_REF:
@@ -3466,7 +3747,6 @@ scan_paradoxical_subregs (x)
     case CONST_DOUBLE:
     case CC0:
     case PC:
-    case REG:
     case USE:
     case CLOBBER:
       return;
@@ -3494,9 +3774,12 @@ scan_paradoxical_subregs (x)
 }
 \f
 static int
-hard_reg_use_compare (p1, p2)
-     struct hard_reg_n_uses *p1, *p2;
+hard_reg_use_compare (p1p, p2p)
+  const GENERIC_PTR p1p;
+  const GENERIC_PTR p2p;
 {
+  struct hard_reg_n_uses *p1 = (struct hard_reg_n_uses *)p1p,
+                        *p2 = (struct hard_reg_n_uses *)p2p;
   int tem = p1->uses - p2->uses;
   if (tem != 0) return tem;
   /* If regs are equally good, sort by regno,
@@ -3509,7 +3792,8 @@ hard_reg_use_compare (p1, p2)
    Store them in order of decreasing preference in potential_reload_regs.  */
 
 static void
-order_regs_for_reload ()
+order_regs_for_reload (global)
+     int global;
 {
   register int i;
   register int o = 0;
@@ -3538,7 +3822,15 @@ order_regs_for_reload ()
        {
          int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
          while (regno < lim)
-           hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+           {
+             /* If allocated by local-alloc, show more uses since
+                we're not going to be able to reallocate it, but
+                we might if allocated by global alloc.  */
+             if (global && reg_allocno[i] < 0)
+               hard_reg_n_uses[regno].uses += (reg_n_refs[i] + 1) / 2;
+
+             hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+           }
        }
       large += reg_n_refs[i];
     }
@@ -3557,14 +3849,15 @@ order_regs_for_reload ()
       else if (regs_explicitly_used[i])
        {
          hard_reg_n_uses[i].uses += large + 1;
-#ifndef SMALL_REGISTER_CLASSES
          /* ??? We are doing this here because of the potential that
             bad code may be generated if a register explicitly used in
             an insn was used as a spill register for that insn.  But
             not using these are spill registers may lose on some machine.
             We'll have to see how this works out.  */
-         SET_HARD_REG_BIT (bad_spill_regs, i);
+#ifdef SMALL_REGISTER_CLASSES
+         if (! SMALL_REGISTER_CLASSES)
 #endif
+           SET_HARD_REG_BIT (bad_spill_regs, i);
        }
     }
   hard_reg_n_uses[HARD_FRAME_POINTER_REGNUM].uses += 2 * large + 2;
@@ -3617,6 +3910,17 @@ order_regs_for_reload ()
       potential_reload_regs[o++] = hard_reg_n_uses[i].regno;
 }
 \f
+/* Used in reload_as_needed to sort the spilled regs.  */
+
+static int
+compare_spill_regs (r1p, r2p)
+     const GENERIC_PTR r1p;
+     const GENERIC_PTR r2p;
+{
+  short r1 = *(short *)r1p, r2 = *(short *)r2p;
+  return r1 - r2;
+}
+
 /* Reload pseudo-registers into hard regs around each insn as needed.
    Additional register load insns are output before the insn that needs it
    and perhaps store insns after insns that modify the reloaded pseudo reg.
@@ -3637,9 +3941,10 @@ reload_as_needed (first, live_known)
   rtx x;
   rtx after_call = 0;
 
-  bzero (spill_reg_rtx, sizeof spill_reg_rtx);
+  bzero ((char *) spill_reg_rtx, sizeof spill_reg_rtx);
+  bzero ((char *) spill_reg_store, sizeof spill_reg_store);
   reg_last_reload_reg = (rtx *) alloca (max_regno * sizeof (rtx));
-  bzero (reg_last_reload_reg, max_regno * sizeof (rtx));
+  bzero ((char *) reg_last_reload_reg, max_regno * sizeof (rtx));
   reg_has_output_reload = (char *) alloca (max_regno);
   for (i = 0; i < n_spills; i++)
     {
@@ -3664,6 +3969,15 @@ reload_as_needed (first, live_known)
 
   num_not_at_initial_offset = 0;
 
+  /* Order the spilled regs, so that allocate_reload_regs can guarantee to
+     pack registers with group needs.  */
+  if (n_spills > 1)
+    {
+      qsort (spill_regs, n_spills, sizeof (short), compare_spill_regs);
+      for (i = 0; i < n_spills; i++)
+       spill_reg_order[spill_regs[i]] = i;
+    }
+
   for (insn = first; insn;)
     {
       register rtx next = NEXT_INSN (insn);
@@ -3692,11 +4006,12 @@ reload_as_needed (first, live_known)
       else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
        {
          rtx avoid_return_reg = 0;
+         rtx oldpat = PATTERN (insn);
 
 #ifdef SMALL_REGISTER_CLASSES
          /* Set avoid_return_reg if this is an insn
             that might use the value of a function call.  */
-         if (GET_CODE (insn) == CALL_INSN)
+         if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
            {
              if (GET_CODE (PATTERN (insn)) == SET)
                after_call = SET_DEST (PATTERN (insn));
@@ -3706,11 +4021,12 @@ reload_as_needed (first, live_known)
              else
                after_call = 0;
            }
-         else if (after_call != 0
+         else if (SMALL_REGISTER_CLASSES
+                  && after_call != 0
                   && !(GET_CODE (PATTERN (insn)) == SET
                        && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
            {
-             if (reg_mentioned_p (after_call, PATTERN (insn)))
+             if (reg_referenced_p (after_call, PATTERN (insn)))
                avoid_return_reg = after_call;
              after_call = 0;
            }
@@ -3724,7 +4040,8 @@ reload_as_needed (first, live_known)
              && GET_CODE (XEXP (PATTERN (insn), 0)) == MEM)
            XEXP (XEXP (PATTERN (insn), 0), 0)
              = eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0),
-                               GET_MODE (XEXP (PATTERN (insn), 0)), NULL_RTX);
+                               GET_MODE (XEXP (PATTERN (insn), 0)),
+                               NULL_RTX, 0);
 
          /* If we need to do register elimination processing, do so.
             This might delete the insn, in which case we are done.  */
@@ -3772,7 +4089,7 @@ reload_as_needed (first, live_known)
                        && ! reload_optional[i]
                        && (reload_in[i] != 0 || reload_out[i] != 0
                            || reload_secondary_p[i] != 0))
-                     abort ();
+                     fatal_insn ("Non-optional registers need a spill register", insn);
 
              /* Now compute which reload regs to reload them into.  Perhaps
                 reusing reload regs from previous insns, or else output
@@ -3784,7 +4101,8 @@ reload_as_needed (first, live_known)
              /* Merge any reloads that we didn't combine for fear of 
                 increasing the number of spill registers needed but now
                 discover can be safely merged.  */
-             merge_assigned_reloads (insn);
+             if (SMALL_REGISTER_CLASSES)
+               merge_assigned_reloads (insn);
 #endif
 
              /* Generate the insns to reload operands into or out of
@@ -3821,7 +4139,7 @@ reload_as_needed (first, live_known)
             for this insn in order to be stored in
             (obeying register constraints).  That is correct; such reload
             registers ARE still valid.  */
-         note_stores (PATTERN (insn), forget_old_reloads_1);
+         note_stores (oldpat, forget_old_reloads_1);
 
          /* There may have been CLOBBER insns placed after INSN.  So scan
             between INSN and NEXT and use them to forget old reloads.  */
@@ -3956,10 +4274,11 @@ static int reload_nregs[MAX_RELOADS];
    should be handled first.  *P1 and *P2 are the reload numbers.  */
 
 static int
-reload_reg_class_lower (p1, p2)
-     short *p1, *p2;
+reload_reg_class_lower (r1p, r2p)
+     const GENERIC_PTR r1p;
+     const GENERIC_PTR r2p;
 {
-  register int r1 = *p1, r2 = *p2;
+  register int r1 = *(short *)r1p, r2 = *(short *)r2p;
   register int t;
 
   /* Consider required reloads before optional ones.  */
@@ -3995,14 +4314,20 @@ reload_reg_class_lower (p1, p2)
 static HARD_REG_SET reload_reg_used;
 /* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I.  */
 static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_INPADDR_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
 /* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I.  */
 static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_OUTADDR_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
 /* If reg is in use for a RELOAD_FOR_INPUT reload for operand I.  */
 static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS];
 /* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I.  */
 static HARD_REG_SET reload_reg_used_in_output[MAX_RECOG_OPERANDS];
 /* If reg is in use for a RELOAD_FOR_OPERAND_ADDRESS reload.  */
 static HARD_REG_SET reload_reg_used_in_op_addr;
+/* If reg is in use for a RELOAD_FOR_OPADDR_ADDR reload.  */
+static HARD_REG_SET reload_reg_used_in_op_addr_reload;
 /* If reg is in use for a RELOAD_FOR_INSN reload.  */
 static HARD_REG_SET reload_reg_used_in_insn;
 /* If reg is in use for a RELOAD_FOR_OTHER_ADDRESS reload.  */
@@ -4041,14 +4366,26 @@ mark_reload_reg_in_use (regno, opnum, type, mode)
          SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_INPADDR_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OUTPUT_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_OUTADDR_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OPERAND_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
          break;
 
+       case RELOAD_FOR_OPADDR_ADDR:
+         SET_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i);
+         break;
+
        case RELOAD_FOR_OTHER_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
          break;
@@ -4094,14 +4431,26 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
          CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_INPADDR_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OUTPUT_ADDRESS:
          CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_OUTADDR_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OPERAND_ADDRESS:
          CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
          break;
 
+       case RELOAD_FOR_OPADDR_ADDR:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, i);
+         break;
+
        case RELOAD_FOR_OTHER_ADDRESS:
          CLEAR_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
          break;
@@ -4132,26 +4481,38 @@ reload_reg_free_p (regno, opnum, type)
 {
   int i;
 
-  /* In use for a RELOAD_OTHER means it's not available for anything except
-     RELOAD_FOR_OTHER_ADDRESS.  Recall that RELOAD_FOR_OTHER_ADDRESS is known
-     to be used only for inputs.  */
-
-  if (type != RELOAD_FOR_OTHER_ADDRESS
-      && TEST_HARD_REG_BIT (reload_reg_used, regno))
+  /* In use for a RELOAD_OTHER means it's not available for anything.  */
+  if (TEST_HARD_REG_BIT (reload_reg_used, regno))
     return 0;
 
   switch (type)
     {
     case RELOAD_OTHER:
-      /* In use for anything means not available for a RELOAD_OTHER.  */
-      return ! TEST_HARD_REG_BIT (reload_reg_used_at_all, regno);
+      /* In use for anything means we can't use it for RELOAD_OTHER.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
+       return 0;
+
+      for (i = 0; i < reload_n_operands; 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)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      return 1;
 
-      /* The other kinds of use can sometimes share a register.  */
     case RELOAD_FOR_INPUT:
       if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
          || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
        return 0;
 
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
+       return 0;
+
       /* If it is used for some other input, can't use it.  */
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
@@ -4159,7 +4520,8 @@ reload_reg_free_p (regno, opnum, type)
 
       /* If it is used in a later operand's address, can't use it.  */
       for (i = opnum + 1; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       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;
 
       return 1;
@@ -4167,7 +4529,21 @@ reload_reg_free_p (regno, opnum, type)
     case RELOAD_FOR_INPUT_ADDRESS:
       /* Can't use a register if it is used for an input address for this
         operand or used as an input in an earlier one.  */
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno))
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
+       return 0;
+
+      for (i = 0; i < opnum; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      return 1;
+
+    case RELOAD_FOR_INPADDR_ADDRESS:
+      /* Can't use a register if it is used for an input address
+         address for this operand or used as an input in an earlier
+         one.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
        return 0;
 
       for (i = 0; i < opnum; i++)
@@ -4188,6 +4564,19 @@ reload_reg_free_p (regno, opnum, type)
 
       return 1;
 
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      /* Can't use a register if it is used for an output address
+         address for this operand or used as an output in this or a
+         later operand.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
+       return 0;
+
+      for (i = opnum; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      return 1;
+
     case RELOAD_FOR_OPERAND_ADDRESS:
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
@@ -4196,6 +4585,13 @@ reload_reg_free_p (regno, opnum, type)
       return (! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
              && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
 
+    case RELOAD_FOR_OPADDR_ADDR:
+      for (i = 0; i < reload_n_operands; i++)
+        if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+          return 0;
+
+      return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno));
+
     case RELOAD_FOR_OUTPUT:
       /* This cannot share a register with RELOAD_FOR_INSN reloads, other
         outputs, or an operand address for this or an earlier output.  */
@@ -4207,7 +4603,8 @@ reload_reg_free_p (regno, opnum, type)
          return 0;
 
       for (i = 0; i <= opnum; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
 
       return 1;
@@ -4261,12 +4658,14 @@ reload_reg_free_before_p (regno, opnum, type)
         the first place, since we know that it was allocated.  */
 
     case RELOAD_FOR_OUTPUT_ADDRESS:
+    case RELOAD_FOR_OUTADDR_ADDRESS:
       /* Earlier reloads are for earlier outputs or their addresses,
         any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any
         RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with
         RELOAD_OTHER)..  */
       for (i = 0; i < opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4275,6 +4674,7 @@ reload_reg_free_before_p (regno, opnum, type)
 
       for (i = 0; i < reload_n_operands; 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)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
@@ -4287,16 +4687,19 @@ reload_reg_free_before_p (regno, opnum, type)
         anything that can't be used for it, except that we've already
         tested for RELOAD_FOR_INSN objects.  */
 
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
        return 0;
 
       for (i = 0; i < opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
       for (i = 0; i < reload_n_operands; 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)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
          return 0;
@@ -4304,12 +4707,20 @@ reload_reg_free_before_p (regno, opnum, type)
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
 
     case RELOAD_FOR_OPERAND_ADDRESS:
+      /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
+       return 0;
+
+      /* ... fall through ...  */
+
+    case RELOAD_FOR_OPADDR_ADDR:
     case RELOAD_FOR_INSN:
       /* These can't conflict with inputs, or each other, so all we have to
         test is input addresses and the addresses of OTHER items.  */
 
       for (i = 0; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       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;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4320,16 +4731,19 @@ reload_reg_free_before_p (regno, opnum, type)
         with), and addresses of RELOAD_OTHER objects.  */
 
       for (i = 0; i <= opnum; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       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;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
 
     case RELOAD_FOR_INPUT_ADDRESS:
+    case RELOAD_FOR_INPADDR_ADDRESS:
       /* Similarly, all we have to check is for use in earlier inputs'
         addresses.  */
       for (i = 0; i < opnum; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       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;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4371,8 +4785,10 @@ reload_reg_reaches_end_p (regno, opnum, type)
 
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
@@ -4381,6 +4797,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
              && ! TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INPUT_ADDRESS:
+    case RELOAD_FOR_INPADDR_ADDRESS:
       /* Similar, except that we check only for this and subsequent inputs
         and the address of only subsequent inputs and we do not need
         to check for RELOAD_OTHER objects since they are known not to
@@ -4391,14 +4808,19 @@ reload_reg_reaches_end_p (regno, opnum, type)
          return 0;
 
       for (i = opnum + 1; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       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;
 
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
+       return 0;
+
       return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
              && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno));
 
@@ -4410,35 +4832,49 @@ reload_reg_reaches_end_p (regno, opnum, type)
 
       for (i = opnum + 1; i < reload_n_operands; 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)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case RELOAD_FOR_OPERAND_ADDRESS:
       /* Check outputs and their addresses.  */
 
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
       return 1;
 
+    case RELOAD_FOR_OPADDR_ADDR:
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+             && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno));
+
     case RELOAD_FOR_INSN:
-      /* These conflict with other outputs with with RELOAD_OTHER.  So
+      /* These conflict with other outputs with RELOAD_OTHER.  So
         we need only check for output addresses.  */
 
       opnum = -1;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case RELOAD_FOR_OUTPUT:
     case RELOAD_FOR_OUTPUT_ADDRESS:
+    case RELOAD_FOR_OUTADDR_ADDRESS:
       /* We already know these can't conflict with a later output.  So the
         only thing to check are later output addresses.  */
       for (i = opnum + 1; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
 
       return 1;
@@ -4447,6 +4883,83 @@ reload_reg_reaches_end_p (regno, opnum, type)
   abort ();
 }
 \f
+/* Return 1 if the reloads denoted by R1 and R2 cannot share a register.
+   Return 0 otherwise.
+
+   This function uses the same algorithm as reload_reg_free_p above.  */
+
+static int
+reloads_conflict (r1, r2)
+     int r1, r2;
+{
+  enum reload_type r1_type = reload_when_needed[r1];
+  enum reload_type r2_type = reload_when_needed[r2];
+  int r1_opnum = reload_opnum[r1];
+  int r2_opnum = reload_opnum[r2];
+
+  /* RELOAD_OTHER conflicts with everything.  */
+  if (r2_type == RELOAD_OTHER)
+    return 1;
+
+  /* Otherwise, check conflicts differently for each type.  */
+
+  switch (r1_type)
+    {
+    case RELOAD_FOR_INPUT:
+      return (r2_type == RELOAD_FOR_INSN 
+             || r2_type == RELOAD_FOR_OPERAND_ADDRESS
+             || r2_type == RELOAD_FOR_OPADDR_ADDR
+             || r2_type == RELOAD_FOR_INPUT
+             || ((r2_type == RELOAD_FOR_INPUT_ADDRESS
+                  || r2_type == RELOAD_FOR_INPADDR_ADDRESS)
+                 && r2_opnum > r1_opnum));
+
+    case RELOAD_FOR_INPUT_ADDRESS:
+      return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum)
+             || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+
+    case RELOAD_FOR_INPADDR_ADDRESS:
+      return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum)
+             || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+
+    case RELOAD_FOR_OUTPUT_ADDRESS:
+      return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum)
+             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum)
+             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+
+    case RELOAD_FOR_OPERAND_ADDRESS:
+      return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
+             || r2_type == RELOAD_FOR_OPERAND_ADDRESS);
+
+    case RELOAD_FOR_OPADDR_ADDR:
+      return (r2_type == RELOAD_FOR_INPUT 
+             || r2_type == RELOAD_FOR_OPADDR_ADDR);
+
+    case RELOAD_FOR_OUTPUT:
+      return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT
+             || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+                  || r2_type == RELOAD_FOR_OUTADDR_ADDRESS)
+                 && r2_opnum >= r1_opnum));
+
+    case RELOAD_FOR_INSN:
+      return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_OUTPUT
+             || r2_type == RELOAD_FOR_INSN
+             || r2_type == RELOAD_FOR_OPERAND_ADDRESS);
+
+    case RELOAD_FOR_OTHER_ADDRESS:
+      return r2_type == RELOAD_FOR_OTHER_ADDRESS;
+
+    case RELOAD_OTHER:
+      return 1;
+
+    default:
+      abort ();
+    }
+}
+\f
 /* Vector of reload-numbers showing the order in which the reloads should
    be processed.  */
 short reload_order[MAX_RELOADS];
@@ -4467,11 +4980,6 @@ rtx reload_override_in[MAX_RELOADS];
    or -1 if we did not need one of the spill registers for this reload.  */
 int reload_spill_index[MAX_RELOADS];
 
-/* Index of last register assigned as a spill register.  We allocate in
-   a round-robin fashio.  */
-
-static int last_spill_reg = 0;
-
 /* Find a spill register to use as a reload register for reload R.
    LAST_RELOAD is non-zero if this is the last reload for the insn being
    processed.
@@ -4526,9 +5034,19 @@ allocate_reload_reg (r, insn, last_reload, noerror)
       /* I is the index in spill_regs.
         We advance it round-robin between insns to use all spill regs
         equally, so that inherited reloads have a chance
-        of leapfrogging each other.  */
-
-      for (count = 0, i = last_spill_reg; count < n_spills; count++)
+        of leapfrogging each other.  Don't do this, however, when we have
+        group needs and failure would be fatal; if we only have a relatively
+        small number of spill registers, and more than one of them has
+        group needs, then by starting in the middle, we may end up 
+        allocating the first one in such a way that we are not left with
+        sufficient groups to handle the rest.  */
+
+      if (noerror || ! force_group)
+       i = last_spill_reg;
+      else
+       i = -1;
+         
+      for (count = 0; count < n_spills; count++)
        {
          int class = (int) reload_reg_class[r];
 
@@ -4646,7 +5164,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
  failure:
   if (asm_noperands (PATTERN (insn)) < 0)
     /* It's the compiler's fault.  */
-    abort ();
+    fatal_insn ("Could not find a spill register", insn);
 
   /* It's the user's fault; the operand's mode and constraint
      don't match.  Disable this reload so we don't crash in final.  */
@@ -4685,21 +5203,25 @@ choose_reload_regs (insn, avoid_return_reg)
   int save_reload_spill_index[MAX_RELOADS];
   HARD_REG_SET save_reload_reg_used;
   HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
   HARD_REG_SET save_reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
   HARD_REG_SET save_reload_reg_used_in_input[MAX_RECOG_OPERANDS];
   HARD_REG_SET save_reload_reg_used_in_output[MAX_RECOG_OPERANDS];
   HARD_REG_SET save_reload_reg_used_in_op_addr;
+  HARD_REG_SET save_reload_reg_used_in_op_addr_reload;
   HARD_REG_SET save_reload_reg_used_in_insn;
   HARD_REG_SET save_reload_reg_used_in_other_addr;
   HARD_REG_SET save_reload_reg_used_at_all;
 
   bzero (reload_inherited, MAX_RELOADS);
-  bzero (reload_inheritance_insn, MAX_RELOADS * sizeof (rtx));
-  bzero (reload_override_in, MAX_RELOADS * sizeof (rtx));
+  bzero ((char *) reload_inheritance_insn, MAX_RELOADS * sizeof (rtx));
+  bzero ((char *) reload_override_in, MAX_RELOADS * sizeof (rtx));
 
   CLEAR_HARD_REG_SET (reload_reg_used);
   CLEAR_HARD_REG_SET (reload_reg_used_at_all);
   CLEAR_HARD_REG_SET (reload_reg_used_in_op_addr);
+  CLEAR_HARD_REG_SET (reload_reg_used_in_op_addr_reload);
   CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
   CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
 
@@ -4708,13 +5230,15 @@ choose_reload_regs (insn, avoid_return_reg)
       CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
       CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]);
       CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i]);
       CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
     }
 
 #ifdef SMALL_REGISTER_CLASSES
   /* Don't bother with avoiding the return reg
      if we have no mandatory reload that could use it.  */
-  if (avoid_return_reg)
+  if (SMALL_REGISTER_CLASSES && avoid_return_reg)
     {
       int do_avoid = 0;
       int regno = REGNO (avoid_return_reg);
@@ -4747,7 +5271,8 @@ choose_reload_regs (insn, avoid_return_reg)
   {
     int tem = 0;
 #ifdef SMALL_REGISTER_CLASSES
-    int tem = (avoid_return_reg != 0);
+    if (SMALL_REGISTER_CLASSES)
+      tem = (avoid_return_reg != 0);
 #endif
     for (j = 0; j < n_reloads; j++)
       if (! reload_optional[j]
@@ -4764,7 +5289,7 @@ choose_reload_regs (insn, avoid_return_reg)
 #ifdef SMALL_REGISTER_CLASSES
   /* Don't use the subroutine call return reg for a reload
      if we are supposed to avoid it.  */
-  if (avoid_return_reg)
+  if (SMALL_REGISTER_CLASSES && avoid_return_reg)
     {
       int regno = REGNO (avoid_return_reg);
       int nregs
@@ -4815,18 +5340,24 @@ choose_reload_regs (insn, avoid_return_reg)
   if (n_reloads > 1)
     qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower);
 
-  bcopy (reload_reg_rtx, save_reload_reg_rtx, sizeof reload_reg_rtx);
+  bcopy ((char *) reload_reg_rtx, (char *) save_reload_reg_rtx,
+        sizeof reload_reg_rtx);
   bcopy (reload_inherited, save_reload_inherited, sizeof reload_inherited);
-  bcopy (reload_inheritance_insn, save_reload_inheritance_insn,
+  bcopy ((char *) reload_inheritance_insn,
+        (char *) save_reload_inheritance_insn,
         sizeof reload_inheritance_insn);
-  bcopy (reload_override_in, save_reload_override_in,
+  bcopy ((char *) reload_override_in, (char *) save_reload_override_in,
         sizeof reload_override_in);
-  bcopy (reload_spill_index, save_reload_spill_index,
+  bcopy ((char *) reload_spill_index, (char *) save_reload_spill_index,
         sizeof reload_spill_index);
   COPY_HARD_REG_SET (save_reload_reg_used, reload_reg_used);
   COPY_HARD_REG_SET (save_reload_reg_used_at_all, reload_reg_used_at_all);
   COPY_HARD_REG_SET (save_reload_reg_used_in_op_addr,
                     reload_reg_used_in_op_addr);
+
+  COPY_HARD_REG_SET (save_reload_reg_used_in_op_addr_reload,
+                    reload_reg_used_in_op_addr_reload);
+
   COPY_HARD_REG_SET (save_reload_reg_used_in_insn,
                     reload_reg_used_in_insn);
   COPY_HARD_REG_SET (save_reload_reg_used_in_other_addr,
@@ -4840,8 +5371,12 @@ choose_reload_regs (insn, avoid_return_reg)
                         reload_reg_used_in_input[i]);
       COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr[i],
                         reload_reg_used_in_input_addr[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_inpaddr_addr[i],
+                        reload_reg_used_in_inpaddr_addr[i]);
       COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i],
                         reload_reg_used_in_output_addr[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_outaddr_addr[i],
+                        reload_reg_used_in_outaddr_addr[i]);
     }
 
   /* If -O, try first with inheritance, then turning it off.
@@ -4964,7 +5499,7 @@ choose_reload_regs (insn, avoid_return_reg)
                                                   reload_when_needed[r]))
                    {
                      /* If a group is needed, verify that all the subsequent
-                        registers still have their values intact. */
+                        registers still have their values intact.  */
                      int nr
                        = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
                      int k;
@@ -5044,9 +5579,12 @@ choose_reload_regs (insn, avoid_return_reg)
                    regno = REGNO (equiv);
                  else if (GET_CODE (equiv) == SUBREG)
                    {
-                     regno = REGNO (SUBREG_REG (equiv));
-                     if (regno < FIRST_PSEUDO_REGISTER)
-                       regno += SUBREG_WORD (equiv);
+                     /* This must be a SUBREG of a hard register.
+                        Make a new REG since this might be used in an
+                        address and not all machines support SUBREGs
+                        there.  */
+                     regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv);
+                     equiv = gen_rtx (REG, reload_mode[r], regno);
                    }
                  else
                    abort ();
@@ -5083,8 +5621,9 @@ choose_reload_regs (insn, avoid_return_reg)
                      break;
                    }
 
-             /* JRV: If the equiv register we have found is explicitly
-                clobbered in the current insn, mark but don't use, as above. */
+             /* JRV: If the equiv register we have found is
+                explicitly clobbered in the current insn, mark but
+                don't use, as above.  */
 
              if (equiv != 0 && regno_clobbered_p (regno, insn))
                {
@@ -5096,20 +5635,24 @@ choose_reload_regs (insn, avoid_return_reg)
                 to load it, and use it as our reload reg.  */
              if (equiv != 0 && regno != HARD_FRAME_POINTER_REGNUM)
                {
+                 int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
+                 int k;
                  reload_reg_rtx[r] = equiv;
                  reload_inherited[r] = 1;
-                 /* If it is a spill reg,
-                    mark the spill reg as in use for this insn.  */
-                 i = spill_reg_order[regno];
-                 if (i >= 0)
+
+                 /* If any of the hard registers in EQUIV are spill
+                    registers, mark them as in use for this insn.  */
+                 for (k = 0; k < nr; k++)
                    {
-                     int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
-                     int k;
-                     mark_reload_reg_in_use (regno, reload_opnum[r],
-                                             reload_when_needed[r],
-                                             reload_mode[r]);
-                     for (k = 0; k < nr; k++)
-                       SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno + k);
+                     i = spill_reg_order[regno + k];
+                     if (i >= 0)
+                       {
+                         mark_reload_reg_in_use (regno, reload_opnum[r],
+                                                 reload_when_needed[r],
+                                                 reload_mode[r]);
+                         SET_HARD_REG_BIT (reload_reg_used_for_inherit,
+                                           regno + k);
+                       }
                    }
                }
            }
@@ -5165,7 +5708,7 @@ choose_reload_regs (insn, avoid_return_reg)
            continue;
 
          /* Skip reloads that already have a register allocated or are
-            optional. */
+            optional.  */
          if (reload_reg_rtx[r] != 0 || reload_optional[r])
            continue;
 
@@ -5181,18 +5724,23 @@ choose_reload_regs (insn, avoid_return_reg)
       /* Loop around and try without any inheritance.  */
       /* First undo everything done by the failed attempt
         to allocate with inheritance.  */
-      bcopy (save_reload_reg_rtx, reload_reg_rtx, sizeof reload_reg_rtx);
-      bcopy (save_reload_inherited, reload_inherited, sizeof reload_inherited);
-      bcopy (save_reload_inheritance_insn, reload_inheritance_insn,
+      bcopy ((char *) save_reload_reg_rtx, (char *) reload_reg_rtx,
+            sizeof reload_reg_rtx);
+      bcopy ((char *) save_reload_inherited, (char *) reload_inherited,
+            sizeof reload_inherited);
+      bcopy ((char *) save_reload_inheritance_insn,
+            (char *) reload_inheritance_insn,
             sizeof reload_inheritance_insn);
-      bcopy (save_reload_override_in, reload_override_in,
+      bcopy ((char *) save_reload_override_in, (char *) reload_override_in,
             sizeof reload_override_in);
-      bcopy (save_reload_spill_index, reload_spill_index,
+      bcopy ((char *) save_reload_spill_index, (char *) reload_spill_index,
             sizeof reload_spill_index);
       COPY_HARD_REG_SET (reload_reg_used, save_reload_reg_used);
       COPY_HARD_REG_SET (reload_reg_used_at_all, save_reload_reg_used_at_all);
       COPY_HARD_REG_SET (reload_reg_used_in_op_addr,
                         save_reload_reg_used_in_op_addr);
+      COPY_HARD_REG_SET (reload_reg_used_in_op_addr_reload,
+                        save_reload_reg_used_in_op_addr_reload);
       COPY_HARD_REG_SET (reload_reg_used_in_insn,
                         save_reload_reg_used_in_insn);
       COPY_HARD_REG_SET (reload_reg_used_in_other_addr,
@@ -5206,8 +5754,12 @@ choose_reload_regs (insn, avoid_return_reg)
                             save_reload_reg_used_in_output[i]);
          COPY_HARD_REG_SET (reload_reg_used_in_input_addr[i],
                             save_reload_reg_used_in_input_addr[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i],
+                            save_reload_reg_used_in_inpaddr_addr[i]);
          COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i],
                             save_reload_reg_used_in_output_addr[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i],
+                            save_reload_reg_used_in_outaddr_addr[i]);
        }
     }
 
@@ -5381,8 +5933,9 @@ merge_assigned_reloads (insn)
                  && reg_overlap_mentioned_for_reload_p (reload_in[j],
                                                         reload_in[i]))
                reload_when_needed[j]
-                 = reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
-                   ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER;
+                 = ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+                     || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+                    ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
        }
     }
 }          
@@ -5399,9 +5952,13 @@ emit_reload_insns (insn)
   rtx other_input_address_reload_insns = 0;
   rtx other_input_reload_insns = 0;
   rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
   rtx output_reload_insns[MAX_RECOG_OPERANDS];
   rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
   rtx operand_reload_insns = 0;
+  rtx other_operand_reload_insns = 0;
+  rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
   rtx following_insn = NEXT_INSN (insn);
   rtx before_insn = insn;
   int special;
@@ -5410,26 +5967,10 @@ emit_reload_insns (insn)
 
   for (j = 0; j < reload_n_operands; j++)
     input_reload_insns[j] = input_address_reload_insns[j]
-      = output_reload_insns[j] = output_address_reload_insns[j] = 0;
-
-  /* If this is a CALL_INSN preceded by USE insns, any reload insns
-     must go in front of the first USE insn, not in front of INSN.  */
-
-  if (GET_CODE (insn) == CALL_INSN && GET_CODE (PREV_INSN (insn)) == INSN
-      && GET_CODE (PATTERN (PREV_INSN (insn))) == USE)
-    while (GET_CODE (PREV_INSN (before_insn)) == INSN
-          && GET_CODE (PATTERN (PREV_INSN (before_insn))) == USE)
-      before_insn = PREV_INSN (before_insn);
-
-  /* If INSN is followed by any CLOBBER insns made by find_reloads,
-     put our reloads after them since they may otherwise be 
-     misinterpreted.  */
-
-  while (GET_CODE (following_insn) == INSN
-        && GET_MODE (following_insn) == DImode
-        && GET_CODE (PATTERN (following_insn)) == CLOBBER
-        && NEXT_INSN (following_insn) != 0)
-    following_insn = NEXT_INSN (following_insn);
+      = inpaddr_address_reload_insns[j]
+      = output_reload_insns[j] = output_address_reload_insns[j]
+      = outaddr_address_reload_insns[j]
+      = other_output_reload_insns[j] = 0;
 
   /* Now output the instructions to copy the data into and out of the
      reload registers.  Do these in the order that the reloads were reported,
@@ -5440,7 +5981,10 @@ emit_reload_insns (insn)
     {
       register rtx old;
       rtx oldequiv_reg = 0;
-      rtx store_insn = 0;
+      rtx this_reload_insn = 0;
+
+      if (reload_spill_index[j] >= 0)
+       new_spill_reg_store[reload_spill_index[j]] = 0;
 
       old = reload_in[j];
       if (old != 0 && ! reload_inherited[j]
@@ -5579,6 +6123,21 @@ emit_reload_insns (insn)
          else if (GET_CODE (oldequiv) == SUBREG)
            oldequiv_reg = SUBREG_REG (oldequiv);
 
+         /* If we are reloading from a register that was recently stored in
+            with an output-reload, see if we can prove there was
+            actually no need to store the old value in it.  */
+
+         if (optimize && GET_CODE (oldequiv) == REG
+             && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
+             && spill_reg_order[REGNO (oldequiv)] >= 0
+             && spill_reg_store[spill_reg_order[REGNO (oldequiv)]] != 0
+             && find_reg_note (insn, REG_DEAD, 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]) == 1)
+           delete_output_reload
+             (insn, j, spill_reg_store[spill_reg_order[REGNO (oldequiv)]]);
+
          /* Encapsulate both RELOADREG and OLDEQUIV into that mode,
             then load RELOADREG from OLDEQUIV.  Note that we cannot use
             gen_lowpart_common since it can do the wrong thing when
@@ -5605,12 +6164,21 @@ emit_reload_insns (insn)
            case RELOAD_FOR_INPUT_ADDRESS:
              where = &input_address_reload_insns[reload_opnum[j]];
              break;
+           case RELOAD_FOR_INPADDR_ADDRESS:
+             where = &inpaddr_address_reload_insns[reload_opnum[j]];
+             break;
            case RELOAD_FOR_OUTPUT_ADDRESS:
              where = &output_address_reload_insns[reload_opnum[j]];
              break;
+           case RELOAD_FOR_OUTADDR_ADDRESS:
+             where = &outaddr_address_reload_insns[reload_opnum[j]];
+             break;
            case RELOAD_FOR_OPERAND_ADDRESS:
              where = &operand_reload_insns;
              break;
+           case RELOAD_FOR_OPADDR_ADDR:
+             where = &other_operand_reload_insns;
+             break;
            case RELOAD_FOR_OTHER_ADDRESS:
              where = &other_input_address_reload_insns;
              break;
@@ -5804,9 +6372,9 @@ emit_reload_insns (insn)
                                           third_reload_reg)));
                            }
                          else
-                           gen_input_reload (second_reload_reg, oldequiv,
-                                             reload_opnum[j],
-                                             reload_when_needed[j]);
+                           gen_reload (second_reload_reg, oldequiv,
+                                       reload_opnum[j],
+                                       reload_when_needed[j]);
 
                          oldequiv = second_reload_reg;
                        }
@@ -5814,9 +6382,9 @@ emit_reload_insns (insn)
                }
 #endif
 
-             if (! special)
-               gen_input_reload (reloadreg, oldequiv, reload_opnum[j],
-                                 reload_when_needed[j]);
+             if (! special && ! rtx_equal_p (reloadreg, oldequiv))
+               gen_reload (reloadreg, oldequiv, reload_opnum[j],
+                           reload_when_needed[j]);
 
 #if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
              /* We may have to make a REG_DEAD note for the secondary reload
@@ -5842,6 +6410,7 @@ emit_reload_insns (insn)
 #endif
            }
 
+         this_reload_insn = get_last_insn ();
          /* End this sequence.  */
          *where = get_insns ();
          end_sequence ();
@@ -6010,6 +6579,16 @@ emit_reload_insns (insn)
              XEXP (note, 0) = reload_reg_rtx[j];
              continue;
            }
+         /* Likewise for a SUBREG of an operand that dies.  */
+         else if (GET_CODE (old) == SUBREG
+                  && GET_CODE (SUBREG_REG (old)) == REG
+                  && 0 != (note = find_reg_note (insn, REG_UNUSED,
+                                                 SUBREG_REG (old))))
+           {
+             XEXP (note, 0) = gen_lowpart_common (GET_MODE (old),
+                                                  reload_reg_rtx[j]);
+             continue;
+           }
          else if (GET_CODE (old) == SCRATCH)
            /* If we aren't optimizing, there won't be a REG_UNUSED note,
               but we don't want to make an output reload.  */
@@ -6029,7 +6608,10 @@ emit_reload_insns (insn)
          if (GET_CODE (insn) == JUMP_INSN)
            abort ();
 
-         push_to_sequence (output_reload_insns[reload_opnum[j]]);
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           start_sequence ();
+         else
+           push_to_sequence (output_reload_insns[reload_opnum[j]]);
 
          /* Determine the mode to reload in.
             See comments above (for input reloading).  */
@@ -6040,7 +6622,7 @@ emit_reload_insns (insn)
              /* VOIDmode should never happen for an output.  */
              if (asm_noperands (PATTERN (insn)) < 0)
                /* It's the compiler's fault.  */
-               abort ();
+               fatal_insn ("VOIDmode on an output", insn);
              error_for_asm (insn, "output operand is constant in `asm'");
              /* Prevent crash--use something we know is valid.  */
              mode = word_mode;
@@ -6053,7 +6635,7 @@ emit_reload_insns (insn)
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
          /* If we need two reload regs, set RELOADREG to the intermediate
-            one, since it will be stored into OUT.  We might need a secondary
+            one, since it will be stored into OLD.  We might need a secondary
             register only for an input reload, so check again here.  */
 
          if (reload_secondary_out_reload[j] >= 0)
@@ -6083,10 +6665,10 @@ emit_reload_insns (insn)
                    {
                      /* See if we need both a scratch and intermediate reload
                         register.  */
+
                      int secondary_reload = reload_secondary_out_reload[j];
                      enum insn_code tertiary_icode
                        = reload_secondary_out_icode[secondary_reload];
-                     rtx pat;
 
                      if (GET_MODE (reloadreg) != mode)
                        reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
@@ -6095,44 +6677,36 @@ emit_reload_insns (insn)
                        {
                          rtx third_reloadreg
                            = reload_reg_rtx[reload_secondary_out_reload[secondary_reload]];
-                         pat = (GEN_FCN (tertiary_icode)
-                                (reloadreg, second_reloadreg, third_reloadreg));
-                       }
-#ifdef SECONDARY_MEMORY_NEEDED
-                     /* If we need a memory location to do the move, do it that way.  */
-                     else if (GET_CODE (reloadreg) == REG
-                              && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER
-                              && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)),
-                                          REGNO_REG_CLASS (REGNO (second_reloadreg)),
-                                          GET_MODE (second_reloadreg)))
-                       {
-                         /* Get the memory to use and rewrite both registers
-                            to its mode.  */
-                         rtx loc
-                           = get_secondary_mem (reloadreg,
-                                                GET_MODE (second_reloadreg),
-                                                reload_opnum[j],
-                                                reload_when_needed[j]);
-                         rtx tmp_reloadreg;
-                           
-                         if (GET_MODE (loc) != GET_MODE (second_reloadreg))
-                           second_reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                                       REGNO (second_reloadreg));
-                         
-                         if (GET_MODE (loc) != GET_MODE (reloadreg))
-                           tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                                    REGNO (reloadreg));
-                         else
-                           tmp_reloadreg = reloadreg;
-                         
-                         emit_move_insn (loc, second_reloadreg);
-                         pat = gen_move_insn (tmp_reloadreg, loc);
+                         rtx tem;
+
+                         /* Copy primary reload reg to secondary reload reg.
+                            (Note that these have been swapped above, then
+                            secondary reload reg to OLD using our insn.  */
+
+                         /* If REAL_OLD is a paradoxical SUBREG, remove it
+                            and try to put the opposite SUBREG on
+                            RELOADREG.  */
+                         if (GET_CODE (real_old) == SUBREG
+                             && (GET_MODE_SIZE (GET_MODE (real_old))
+                                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (real_old))))
+                             && 0 != (tem = gen_lowpart_common
+                                      (GET_MODE (SUBREG_REG (real_old)),
+                                       reloadreg)))
+                           real_old = SUBREG_REG (real_old), reloadreg = tem;
+
+                         gen_reload (reloadreg, second_reloadreg,
+                                     reload_opnum[j], reload_when_needed[j]);
+                         emit_insn ((GEN_FCN (tertiary_icode)
+                                     (real_old, reloadreg, third_reloadreg)));
+                         special = 1;
                        }
-#endif
+
                      else
-                       pat = gen_move_insn (reloadreg, second_reloadreg);
+                       /* Copy between the reload regs here and then to
+                          OUT later.  */
 
-                     emit_insn (pat);
+                       gen_reload (reloadreg, second_reloadreg,
+                                   reload_opnum[j], reload_when_needed[j]);
                    }
                }
            }
@@ -6140,34 +6714,8 @@ emit_reload_insns (insn)
 
          /* Output the last reload insn.  */
          if (! special)
-           {
-#ifdef SECONDARY_MEMORY_NEEDED
-             /* If we need a memory location to do the move, do it that way.  */
-             if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER
-                 && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)),
-                                             REGNO_REG_CLASS (REGNO (reloadreg)),
-                                             GET_MODE (reloadreg)))
-               {
-                 /* Get the memory to use and rewrite both registers to
-                    its mode.  */
-                 rtx loc = get_secondary_mem (old, GET_MODE (reloadreg),
-                                              reload_opnum[j],
-                                              reload_when_needed[j]);
-
-                 if (GET_MODE (loc) != GET_MODE (reloadreg))
-                   reloadreg = gen_rtx (REG, GET_MODE (loc),
-                                        REGNO (reloadreg));
-
-                 if (GET_MODE (loc) != GET_MODE (old))
-                   old = gen_rtx (REG, GET_MODE (loc), REGNO (old));
-
-                 emit_insn (gen_move_insn (loc, reloadreg));
-                 emit_insn (gen_move_insn (old, loc));
-               }
-             else
-#endif
-               emit_insn (gen_move_insn (old, reloadreg));
-           }
+           gen_reload (old, reloadreg, reload_opnum[j],
+                       reload_when_needed[j]);
 
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
          /* If final will look at death notes for this reg,
@@ -6182,7 +6730,7 @@ emit_reload_insns (insn)
                                         reloadreg, REG_NOTES (p));
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-         if (! special
+         if (! special && second_reloadreg
              && PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
            for (p = get_last_insn (); p; p = PREV_INSN (p))
              if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
@@ -6202,17 +6750,21 @@ emit_reload_insns (insn)
                   reg_has_output_reload will make this do nothing.  */
                note_stores (PATTERN (p), forget_old_reloads_1);
 
-               if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p)))
-                 store_insn = p;
+               if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
+                   && reload_spill_index[j] >= 0)
+                 new_spill_reg_store[reload_spill_index[j]] = p;
              }
 
-         output_reload_insns[reload_opnum[j]] = get_insns ();
-         end_sequence ();
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           {
+             emit_insns (other_output_reload_insns[reload_opnum[j]]);
+             other_output_reload_insns[reload_opnum[j]] = get_insns ();
+           }
+         else
+           output_reload_insns[reload_opnum[j]] = get_insns ();
 
+         end_sequence ();
        }
-
-      if (reload_spill_index[j] >= 0)
-       new_spill_reg_store[reload_spill_index[j]] = store_insn;
     }
 
   /* Now write all the insns we made for reloads in the order expected by
@@ -6223,31 +6775,41 @@ emit_reload_insns (insn)
 
      RELOAD_OTHER reloads.
 
-     For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
-     the RELOAD_FOR_INPUT reload for the operand.
+     For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed
+     by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the
+     RELOAD_FOR_INPUT reload for the operand.
+
+     RELOAD_FOR_OPADDR_ADDRS reloads.
 
      RELOAD_FOR_OPERAND_ADDRESS reloads.
 
      After the insn being reloaded, we write the following:
 
-     For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
-     the RELOAD_FOR_OUTPUT reload for that operand.  */
+     For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed
+     by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the
+     RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output
+     reloads for the operand.  The RELOAD_OTHER output reloads are
+     output in descending order by reload number.  */
 
   emit_insns_before (other_input_address_reload_insns, before_insn);
   emit_insns_before (other_input_reload_insns, before_insn);
 
   for (j = 0; j < reload_n_operands; j++)
     {
+      emit_insns_before (inpaddr_address_reload_insns[j], before_insn);
       emit_insns_before (input_address_reload_insns[j], before_insn);
       emit_insns_before (input_reload_insns[j], before_insn);
     }
 
+  emit_insns_before (other_operand_reload_insns, before_insn);
   emit_insns_before (operand_reload_insns, before_insn);
 
   for (j = 0; j < reload_n_operands; j++)
     {
+      emit_insns_before (outaddr_address_reload_insns[j], following_insn);
       emit_insns_before (output_address_reload_insns[j], following_insn);
       emit_insns_before (output_reload_insns[j], following_insn);
+      emit_insns_before (other_output_reload_insns[j], following_insn);
     }
 
   /* Move death notes from INSN
@@ -6308,105 +6870,139 @@ emit_reload_insns (insn)
 
       /* I is nonneg if this reload used one of the spill regs.
         If reload_reg_rtx[r] is 0, this is an optional reload
-        that we opted to ignore.
-
-        Also ignore reloads that don't reach the end of the insn,
-        since we will eventually see the one that does.  */
+        that we opted to ignore.  */
 
-      if (i >= 0 && reload_reg_rtx[r] != 0
-         && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
-                                      reload_when_needed[r]))
+      if (i >= 0 && reload_reg_rtx[r] != 0)
        {
-         /* First, clear out memory of what used to be in this spill reg.
-            If consecutive registers are used, clear them all.  */
          int nr
            = HARD_REGNO_NREGS (spill_regs[i], GET_MODE (reload_reg_rtx[r]));
          int k;
+         int part_reaches_end = 0;
+         int all_reaches_end = 1;
 
+         /* For a multi register reload, we need to check if all or part
+            of the value lives to the end.  */
          for (k = 0; k < nr; k++)
            {
-             reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
-             reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+             if (reload_reg_reaches_end_p (spill_regs[i] + k, reload_opnum[r],
+                                           reload_when_needed[r]))
+               part_reaches_end = 1;
+             else
+               all_reaches_end = 0;
            }
 
-         /* Maybe the spill reg contains a copy of reload_out.  */
-         if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+         /* Ignore reloads that don't reach the end of the insn in
+            entirety.  */
+         if (all_reaches_end)
            {
-             register int nregno = REGNO (reload_out[r]);
-             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];
-             reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+             /* First, clear out memory of what used to be in this spill reg.
+                If consecutive registers are used, clear them all.  */
 
-             /* If NREGNO is a hard register, it may occupy more than
-                one register.  If it does, say what is in the 
-                rest of the registers assuming that both registers
-                agree on how many words the object takes.  If not,
-                invalidate the subsequent registers.  */
-
-             if (nregno < FIRST_PSEUDO_REGISTER)
-               for (k = 1; k < nnr; k++)
-                 reg_last_reload_reg[nregno + k]
-                   = (nr == nnr ? gen_rtx (REG, word_mode,
-                                           REGNO (reload_reg_rtx[r]) + k)
-                      : 0);
-
-             /* Now do the inverse operation.  */
              for (k = 0; k < nr; k++)
                {
-                 reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
-                   = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
-                      : nregno + k);
-                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+                 reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
                }
-           }
-
-         /* 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
-                  && reload_in[r] != 0
-                  && ((GET_CODE (reload_in[r]) == REG
-                       && ! reg_has_output_reload[REGNO (reload_in[r])]
-                      || (GET_CODE (reload_in_reg[r]) == REG
-                          && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
-           {
-             register int nregno;
-             int nnr;
-
-             if (GET_CODE (reload_in[r]) == REG)
-               nregno = REGNO (reload_in[r]);
-             else
-               nregno = REGNO (reload_in_reg[r]);
 
-             nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
-                    : HARD_REGNO_NREGS (nregno,
-                                        GET_MODE (reload_reg_rtx[r])));
+             /* Maybe the spill reg contains a copy of reload_out.  */
+             if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+               {
+                 register int nregno = REGNO (reload_out[r]);
+                 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];
+                 reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+                 /* If NREGNO is a hard register, it may occupy more than
+                    one register.  If it does, say what is in the 
+                    rest of the registers assuming that both registers
+                    agree on how many words the object takes.  If not,
+                    invalidate the subsequent registers.  */
+
+                 if (nregno < FIRST_PSEUDO_REGISTER)
+                   for (k = 1; k < nnr; k++)
+                     reg_last_reload_reg[nregno + k]
+                       = (nr == nnr
+                          ? gen_rtx (REG,
+                                     reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+                                     REGNO (reload_reg_rtx[r]) + k)
+                          : 0);
+
+                 /* Now do the inverse operation.  */
+                 for (k = 0; k < nr; k++)
+                   {
+                     reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
+                       = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+                          ? nregno
+                          : nregno + k);
+                     reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+                   }
+               }
 
-             reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+             /* 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
+                      && reload_in[r] != 0
+                      && ((GET_CODE (reload_in[r]) == REG
+                           && ! reg_has_output_reload[REGNO (reload_in[r])])
+                          || (GET_CODE (reload_in_reg[r]) == REG
+                              && ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
+               {
+                 register int nregno;
+                 int nnr;
 
-             if (nregno < FIRST_PSEUDO_REGISTER)
-               for (k = 1; k < nnr; k++)
-                 reg_last_reload_reg[nregno + k]
-                   = (nr == nnr ? gen_rtx (REG, word_mode,
-                                           REGNO (reload_reg_rtx[r]) + k)
-                      : 0);
+                 if (GET_CODE (reload_in[r]) == REG)
+                   nregno = REGNO (reload_in[r]);
+                 else
+                   nregno = REGNO (reload_in_reg[r]);
 
-             /* Unless we inherited this reload, show we haven't
-                recently done a store.  */
-             if (! reload_inherited[r])
-               spill_reg_store[i] = 0;
+                 nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+                        : HARD_REGNO_NREGS (nregno,
+                                            GET_MODE (reload_reg_rtx[r])));
+                 
+                 reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+                 if (nregno < FIRST_PSEUDO_REGISTER)
+                   for (k = 1; k < nnr; k++)
+                     reg_last_reload_reg[nregno + k]
+                       = (nr == nnr
+                          ? gen_rtx (REG,
+                                     reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+                                     REGNO (reload_reg_rtx[r]) + k)
+                          : 0);
+
+                 /* Unless we inherited this reload, show we haven't
+                    recently done a store.  */
+                 if (! reload_inherited[r])
+                   spill_reg_store[i] = 0;
+
+                 for (k = 0; k < nr; k++)
+                   {
+                     reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
+                       = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+                          ? nregno
+                          : nregno + k);
+                     reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
+                       = insn;
+                   }
+               }
+           }
 
+         /* However, if part of the reload reaches the end, then we must
+            invalidate the old info for the part that survives to the end.  */
+         else if (part_reaches_end)
+           {
              for (k = 0; k < nr; k++)
-               {
-                 reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
-                   = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
-                      : nregno + k);
-                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
-                   = insn;
-               }
+               if (reload_reg_reaches_end_p (spill_regs[i] + k,
+                                             reload_opnum[r],
+                                             reload_when_needed[r]))
+                 {
+                   reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+                   reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+                 }
            }
        }
 
@@ -6421,24 +7017,47 @@ emit_reload_insns (insn)
       if (i < 0 && reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
        {
          register int nregno = REGNO (reload_out[r]);
-         reg_last_reload_reg[nregno] = 0;
+         if (nregno >= FIRST_PSEUDO_REGISTER)
+           reg_last_reload_reg[nregno] = 0;
+         else
+           {
+             int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (reload_out[r]));
+
+             while (num_regs-- > 0)
+               reg_last_reload_reg[nregno + num_regs] = 0;
+           }
        }
     }
 }
 \f
-/* Emit code to perform an input reload of IN to RELOADREG.  IN is from
-   operand OPNUM with reload type TYPE. 
+/* Emit code to perform a reload from IN (which may be a reload register) to
+   OUT (which may also be a reload register).  IN or OUT is from operand
+   OPNUM with reload type TYPE. 
 
    Returns first insn emitted.  */
 
 rtx
-gen_input_reload (reloadreg, in, opnum, type)
-     rtx reloadreg;
+gen_reload (out, in, opnum, type)
+     rtx out;
      rtx in;
      int opnum;
      enum reload_type type;
 {
   rtx last = get_last_insn ();
+  rtx tem;
+
+  /* If IN is a paradoxical SUBREG, remove it and try to put the
+     opposite SUBREG on OUT.  Likewise for a paradoxical SUBREG on OUT.  */
+  if (GET_CODE (in) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (in))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0)
+    in = SUBREG_REG (in), out = tem;
+  else if (GET_CODE (out) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (out))
+         > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+      && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (out)), in)) != 0)
+    out = SUBREG_REG (out), in = tem;
 
   /* How to do this reload can get quite tricky.  Normally, we are being
      asked to reload a simple operand, such as a MEM, a constant, or a pseudo
@@ -6468,8 +7087,10 @@ gen_input_reload (reloadreg, in, opnum, type)
 
   if (GET_CODE (in) == PLUS
       && (GET_CODE (XEXP (in, 0)) == REG
+         || GET_CODE (XEXP (in, 0)) == SUBREG
          || GET_CODE (XEXP (in, 0)) == MEM)
       && (GET_CODE (XEXP (in, 1)) == REG
+         || GET_CODE (XEXP (in, 1)) == SUBREG
          || CONSTANT_P (XEXP (in, 1))
          || GET_CODE (XEXP (in, 1)) == MEM))
     {
@@ -6497,16 +7118,16 @@ gen_input_reload (reloadreg, in, opnum, type)
         if the add instruction is two-address and the second operand
         of the add is the same as the reload reg, which is frequently
         the case.  If the insn would be A = B + A, rearrange it so
-        it will be A = A + B as constrain_operands expects. */
+        it will be A = A + B as constrain_operands expects.  */
 
       if (GET_CODE (XEXP (in, 1)) == REG
-         && REGNO (reloadreg) == REGNO (XEXP (in, 1)))
+         && REGNO (out) == REGNO (XEXP (in, 1)))
        tem = op0, op0 = op1, op1 = tem;
 
       if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
        in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
 
-      insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+      insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
       code = recog_memoized (insn);
 
       if (code >= 0)
@@ -6530,56 +7151,77 @@ gen_input_reload (reloadreg, in, opnum, type)
         DEFINE_PEEPHOLE should be specified that recognizes the sequence
         we emit below.  */
 
-      if (CONSTANT_P (op1) || GET_CODE (op1) == MEM
+      if (CONSTANT_P (op1) || GET_CODE (op1) == MEM || GET_CODE (op1) == SUBREG
          || (GET_CODE (op1) == REG
              && REGNO (op1) >= FIRST_PSEUDO_REGISTER))
        tem = op0, op0 = op1, op1 = tem;
 
-      emit_insn (gen_move_insn (reloadreg, op0));
+      gen_reload (out, op0, opnum, type);
 
-      /* If OP0 and OP1 are the same, we can use RELOADREG for OP1.
+      /* If OP0 and OP1 are the same, we can use OUT for OP1.
         This fixes a problem on the 32K where the stack pointer cannot
         be used as an operand of an add insn.  */
 
       if (rtx_equal_p (op0, op1))
-       op1 = reloadreg;
+       op1 = out;
+
+      insn = emit_insn (gen_add2_insn (out, op1));
+
+      /* If that failed, copy the address register to the reload register.
+        Then add the constant to the reload register.  */
+
+      code = recog_memoized (insn);
+
+      if (code >= 0)
+       {
+         insn_extract (insn);
+         /* We want constrain operands to treat this insn strictly in
+            its validity determination, i.e., the way it would after reload
+            has completed.  */
+         if (constrain_operands (code, 1))
+           return insn;
+       }
+
+      delete_insns_since (last);
 
-      emit_insn (gen_add2_insn (reloadreg, op1));
+      gen_reload (out, op1, opnum, type);
+      emit_insn (gen_add2_insn (out, op0));
     }
 
 #ifdef SECONDARY_MEMORY_NEEDED
   /* If we need a memory location to do the move, do it that way.  */
   else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
+          && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER
           && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
-                                      REGNO_REG_CLASS (REGNO (reloadreg)),
-                                      GET_MODE (reloadreg)))
+                                      REGNO_REG_CLASS (REGNO (out)),
+                                      GET_MODE (out)))
     {
       /* Get the memory to use and rewrite both registers to its mode.  */
-      rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type);
+      rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
 
-      if (GET_MODE (loc) != GET_MODE (reloadreg))
-       reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg));
+      if (GET_MODE (loc) != GET_MODE (out))
+       out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
 
       if (GET_MODE (loc) != GET_MODE (in))
        in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
 
-      emit_insn (gen_move_insn (loc, in));
-      emit_insn (gen_move_insn (reloadreg, loc));
+      gen_reload (loc, in, opnum, type);
+      gen_reload (out, loc, opnum, type);
     }
 #endif
 
   /* If IN is a simple operand, use gen_move_insn.  */
   else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
-    emit_insn (gen_move_insn (reloadreg, in));
+    emit_insn (gen_move_insn (out, in));
 
 #ifdef HAVE_reload_load_address
   else if (HAVE_reload_load_address)
-    emit_insn (gen_reload_load_address (reloadreg, in));
+    emit_insn (gen_reload_load_address (out, in));
 #endif
 
-  /* Otherwise, just write (set REGLOADREG IN) and hope for the best.  */
+  /* Otherwise, just write (set OUT IN) and hope for the best.  */
   else
-    emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
+    emit_insn (gen_rtx (SET, VOIDmode, out, in));
 
   /* Return the first insn emitted.
      We can not just return get_last_insn, because there may have
@@ -6673,7 +7315,13 @@ delete_output_reload (insn, j, output_reload_insn)
          rtx set = single_set (i2);
 
          if (set != 0 && SET_DEST (set) == reg)
-           delete_insn (i2);
+           {
+             /* This might be a basic block head,
+                thus don't use delete_insn.  */
+             PUT_CODE (i2, NOTE);
+             NOTE_SOURCE_FILE (i2) = 0;
+             NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+           }
          if (GET_CODE (i2) == CODE_LABEL
              || GET_CODE (i2) == JUMP_INSN)
            break;
@@ -6726,7 +7374,7 @@ inc_for_reload (reloadreg, value, inc_amount)
     emit_insn (gen_move_insn (reloadreg, incloc));
 
   /* See if we can directly increment INCLOC.  Use a method similar to that
-     in gen_input_reload.  */
+     in gen_reload.  */
 
   last = get_last_insn ();
   add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,
@@ -6886,3 +7534,772 @@ count_occurrences (x, find)
     }
   return count;
 }
+\f
+/* This array holds values which are equivalent to a hard register
+   during reload_cse_regs.  Each array element is an EXPR_LIST of
+   values.  Each time a hard register is set, we set the corresponding
+   array element to the value.  Each time a hard register is copied
+   into memory, we add the memory location to the corresponding array
+   element.  We don't store values or memory addresses with side
+   effects in this array.
+
+   If the value is a CONST_INT, then the mode of the containing
+   EXPR_LIST is the mode in which that CONST_INT was referenced.
+
+   We sometimes clobber a specific entry in a list.  In that case, we
+   just set XEXP (list-entry, 0) to 0.  */
+
+static rtx *reg_values;
+
+/* This is a preallocated REG rtx which we use as a temporary in
+   reload_cse_invalidate_regno, so that we don't need to allocate a
+   new one each time through a loop in that function.  */
+
+static rtx invalidate_regno_rtx;
+
+/* Invalidate any entries in reg_values which depend on REGNO,
+   including those for REGNO itself.  This is called if REGNO is
+   changing.  If CLOBBER is true, then always forget anything we
+   currently know about REGNO.  MODE is the mode of the assignment to
+   REGNO, which is used to determine how many hard registers are being
+   changed.  If MODE is VOIDmode, then only REGNO is being changed;
+   this is used when invalidating call clobbered registers across a
+   call.  */
+
+static void
+reload_cse_invalidate_regno (regno, mode, clobber)
+     int regno;
+     enum machine_mode mode;
+     int clobber;
+{
+  int endregno;
+  register int i;
+
+  /* Our callers don't always go through true_regnum; we may see a
+     pseudo-register here from a CLOBBER or the like.  We probably
+     won't ever see a pseudo-register that has a real register number,
+     for we check anyhow for safety.  */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    regno = reg_renumber[regno];
+  if (regno < 0)
+    return;
+
+  if (mode == VOIDmode)
+    endregno = regno + 1;
+  else
+    endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+  if (clobber)
+    for (i = regno; i < endregno; i++)
+      reg_values[i] = 0;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0
+             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_RTX))
+           {
+             /* If this is the only entry on the list, clear
+                 reg_values[i].  Otherwise, just clear this entry on
+                 the list.  */
+             if (XEXP (x, 1) == 0 && x == reg_values[i])
+               {
+                 reg_values[i] = 0;
+                 break;
+               }
+             XEXP (x, 0) = 0;
+           }
+       }
+    }
+
+  /* We must look at earlier registers, in case REGNO is part of a
+     multi word value but is not the first register.  If an earlier
+     register has a value in a mode which overlaps REGNO, then we must
+     invalidate that earlier register.  Note that we do not need to
+     check REGNO or later registers (we must not check REGNO itself,
+     because we would incorrectly conclude that there was a conflict).  */
+
+  for (i = 0; i < regno; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0)
+           {
+             PUT_MODE (invalidate_regno_rtx, GET_MODE (XEXP (x, 0)));
+             REGNO (invalidate_regno_rtx) = i;
+             if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+                                    NULL_PTR))
+               {
+                 reload_cse_invalidate_regno (i, VOIDmode, 1);
+                 break;
+               }
+           }
+       }
+    }
+}
+
+/* The memory at address (plus MEM_BASE MEM_OFFSET), where MEM_OFFSET
+   is a CONST_INT, is being changed.  MEM_MODE is the mode of the
+   memory reference.  Return whether this change will invalidate VAL.  */
+
+static int
+reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
+     rtx mem_base;
+     rtx mem_offset;
+     enum machine_mode mem_mode;
+     rtx val;
+{
+  enum rtx_code code;
+  char *fmt;
+  int i;
+
+  code = GET_CODE (val);
+  switch (code)
+    {
+      /* Get rid of a few simple cases quickly. */
+    case REG:
+    case PC:
+    case CC0:
+    case SCRATCH:
+    case CONST:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 0;
+
+    case MEM:
+      {
+       rtx val_base, val_offset;
+
+       if (mem_mode == BLKmode || GET_MODE (val) == BLKmode)
+         return 1;
+
+       val_offset = const0_rtx;
+       val_base = eliminate_constant_term (XEXP (val, 0), &val_offset);
+
+       /* If MEM_BASE and VAL_BASE are the same, but the offsets do
+          not overlap, then we do not have a conflict on this MEM.
+          For complete safety, we still need to check that VAL_BASE
+          itself does not contain an overlapping MEM.
+
+          We can't simplify the check to just OFFSET + SIZE <=
+          OTHER_OFFSET, because SIZE might cause OFFSET to wrap from
+          positive to negative.  If we used unsigned arithmetic, we
+          would have the same problem wrapping around zero.  */
+
+       if (rtx_equal_p (mem_base, val_base)
+           && ((INTVAL (mem_offset) < INTVAL (val_offset)
+                && (INTVAL (mem_offset) + GET_MODE_SIZE (mem_mode)
+                    <= INTVAL (val_offset)))
+               || (INTVAL (val_offset) < INTVAL (mem_offset)
+                   && (INTVAL (val_offset) + GET_MODE_SIZE (GET_MODE (val))
+                       <= INTVAL (mem_offset)))))
+         return reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                           val_base);
+
+       return 1;
+      }
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                        XEXP (val, i)))
+           return 1;
+       }
+      else if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = 0; j < XVECLEN (val, i); j++)
+           if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                          XVECEXP (val, i, j)))
+             return 1;
+       }
+    }
+
+  return 0;
+}
+
+/* Invalidate any entries in reg_values which are changed because of a
+   store to MEM_RTX.  If this is called because of a non-const call
+   instruction, MEM_RTX is (mem:BLK const0_rtx).  */
+
+static void
+reload_cse_invalidate_mem (mem_rtx)
+     rtx mem_rtx;
+{
+  register int i;
+  rtx mem_base, mem_offset;
+  enum machine_mode mem_mode;
+
+  /* We detect certain cases where memory addresses can not conflict:
+     if they use the same register, and the offsets do not overlap.  */
+
+  mem_offset = const0_rtx;
+  mem_base = eliminate_constant_term (XEXP (mem_rtx, 0), &mem_offset);
+  mem_mode = GET_MODE (mem_rtx);
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0
+             && reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                           XEXP (x, 0)))
+           {
+             /* If this is the only entry on the list, clear
+                 reg_values[i].  Otherwise, just clear this entry on
+                 the list.  */
+             if (XEXP (x, 1) == 0 && x == reg_values[i])
+               {
+                 reg_values[i] = 0;
+                 break;
+               }
+             XEXP (x, 0) = 0;
+           }
+       }
+    }
+}
+
+/* Invalidate DEST, which is being assigned to or clobbered.  The
+   second parameter exists so that this function can be passed to
+   note_stores; it is ignored.  */
+
+static void
+reload_cse_invalidate_rtx (dest, ignore)
+     rtx dest;
+     rtx ignore;
+{
+  while (GET_CODE (dest) == STRICT_LOW_PART
+        || GET_CODE (dest) == SIGN_EXTRACT
+        || GET_CODE (dest) == ZERO_EXTRACT
+        || GET_CODE (dest) == SUBREG)
+    dest = XEXP (dest, 0);
+
+  if (GET_CODE (dest) == REG)
+    reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1);
+  else if (GET_CODE (dest) == MEM)
+    reload_cse_invalidate_mem (dest);
+}
+
+/* Do a very simple CSE pass over the hard registers.
+
+   This function detects no-op moves where we happened to assign two
+   different pseudo-registers to the same hard register, and then
+   copied one to the other.  Reload will generate a useless
+   instruction copying a register to itself.
+
+   This function also detects cases where we load a value from memory
+   into two different registers, and (if memory is more expensive than
+   registers) changes it to simply copy the first register into the
+   second register.  */
+
+static void
+reload_cse_regs (first)
+     rtx first;
+{
+  char *firstobj;
+  rtx callmem;
+  register int i;
+  rtx insn;
+
+  reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    reg_values[i] = 0;
+
+  /* Create our EXPR_LIST structures on reload_obstack, so that we can
+     free them when we are done.  */
+  push_obstacks (&reload_obstack, &reload_obstack);
+  firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+  /* We pass this to reload_cse_invalidate_mem to invalidate all of
+     memory for a non-const call instruction.  */
+  callmem = gen_rtx (MEM, BLKmode, const0_rtx);
+
+  /* This is used in reload_cse_invalidate_regno to avoid consing a
+     new REG in a loop in that function.  */
+  invalidate_regno_rtx = gen_rtx (REG, VOIDmode, 0);
+
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    {
+      rtx body;
+
+      if (GET_CODE (insn) == CODE_LABEL)
+       {
+         /* Forget all the register values at a code label.  We don't
+             try to do anything clever around jumps.  */
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           reg_values[i] = 0;
+
+         continue;
+       }
+
+#ifdef NON_SAVING_SETJMP 
+      if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+       {
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           reg_values[i] = 0;
+
+         continue;
+       }
+#endif
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       continue;
+
+      /* If this is a call instruction, forget anything stored in a
+        call clobbered register, or, if this is not a const call, in
+        memory.  */
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (call_used_regs[i])
+             reload_cse_invalidate_regno (i, VOIDmode, 1);
+
+         if (! CONST_CALL_P (insn))
+           reload_cse_invalidate_mem (callmem);
+       }
+
+      body = PATTERN (insn);
+      if (GET_CODE (body) == SET)
+       {
+         if (reload_cse_noop_set_p (body, insn))
+           {
+             PUT_CODE (insn, NOTE);
+             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (insn) = 0;
+
+             /* We're done with this insn.  */
+             continue;
+           }
+
+         reload_cse_simplify_set (body, insn);
+         reload_cse_record_set (body, body);
+       }
+      else if (GET_CODE (body) == PARALLEL)
+       {
+         int delete;
+
+         /* If every action in a PARALLEL is a noop, we can delete
+             the entire PARALLEL.  */
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           if (GET_CODE (XVECEXP (body, 0, i)) != SET
+               || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
+             break;
+         if (i < 0)
+           {
+             PUT_CODE (insn, NOTE);
+             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (insn) = 0;
+
+             /* We're done with this insn.  */
+             continue;
+           }
+
+         /* Look through the PARALLEL and record the values being
+             set, if possible.  Also handle any CLOBBERs.  */
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           {
+             rtx x = XVECEXP (body, 0, i);
+
+             if (GET_CODE (x) == SET)
+               reload_cse_record_set (x, body);
+             else
+               note_stores (x, reload_cse_invalidate_rtx);
+           }
+       }
+      else
+       note_stores (body, reload_cse_invalidate_rtx);
+
+#ifdef AUTO_INC_DEC
+      /* Clobber any registers which appear in REG_INC notes.  We
+         could keep track of the changes to their values, but it is
+         unlikely to help.  */
+      {
+       rtx x;
+
+       for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+         if (REG_NOTE_KIND (x) == REG_INC)
+           reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX);
+      }
+#endif
+
+      /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
+         after we have processed the insn.  */
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         rtx x;
+
+         for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+           if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+             reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX);
+       }
+    }
+
+  /* Free all the temporary structures we created, and go back to the
+     regular obstacks.  */
+  obstack_free (&reload_obstack, firstobj);
+  pop_obstacks ();
+}
+
+/* Return whether the values known for REGNO are equal to VAL.  MODE
+   is the mode of the object that VAL is being copied to; this matters
+   if VAL is a CONST_INT.  */
+
+static int
+reload_cse_regno_equal_p (regno, val, mode)
+     int regno;
+     rtx val;
+     enum machine_mode mode;
+{
+  rtx x;
+
+  if (val == 0)
+    return 0;
+
+  for (x = reg_values[regno]; x; x = XEXP (x, 1))
+    if (XEXP (x, 0) != 0
+       && rtx_equal_p (XEXP (x, 0), val)
+       && (GET_CODE (val) != CONST_INT
+           || mode == GET_MODE (x)
+           || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+               && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                         GET_MODE_BITSIZE (GET_MODE (x))))))
+      return 1;
+
+  return 0;
+}
+
+/* See whether a single set is a noop.  SET is the set instruction we
+   are should check, and INSN is the instruction from which it came.  */
+
+static int
+reload_cse_noop_set_p (set, insn)
+     rtx set;
+     rtx insn;
+{
+  rtx src, dest;
+  enum machine_mode dest_mode;
+  int dreg, sreg;
+  int ret;
+
+  src = SET_SRC (set);
+  dest = SET_DEST (set);
+  dest_mode = GET_MODE (dest);
+
+  if (side_effects_p (src))
+    return 0;
+
+  dreg = true_regnum (dest);
+  sreg = true_regnum (src);
+
+  /* Check for setting a register to itself.  In this case, we don't
+     have to worry about REG_DEAD notes.  */
+  if (dreg >= 0 && dreg == sreg)
+    return 1;
+
+  ret = 0;
+  if (dreg >= 0)
+    {
+      /* Check for setting a register to itself.  */
+      if (dreg == sreg)
+       ret = 1;
+
+      /* Check for setting a register to a value which we already know
+         is in the register.  */
+      else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+       ret = 1;
+
+      /* Check for setting a register DREG to another register SREG
+         where SREG is equal to a value which is already in DREG.  */
+      else if (sreg >= 0)
+       {
+         rtx x;
+
+         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+           {
+             if (XEXP (x, 0) != 0
+                 && reload_cse_regno_equal_p (dreg, XEXP (x, 0), dest_mode))
+               {
+                 ret = 1;
+                 break;
+               }
+           }
+       }
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      /* Check for storing a register to memory when we know that the
+         register is equivalent to the memory location. */
+      if (sreg >= 0
+         && reload_cse_regno_equal_p (sreg, dest, dest_mode)
+         && ! side_effects_p (dest))
+       ret = 1;
+    }
+
+  /* If we can delete this SET, then we need to look for an earlier
+     REG_DEAD note on DREG, and remove it if it exists.  */
+  if (ret)
+    {
+      if (! find_regno_note (insn, REG_UNUSED, dreg))
+       {
+         rtx trial;
+
+         for (trial = prev_nonnote_insn (insn);
+              (trial
+               && GET_CODE (trial) != CODE_LABEL
+               && GET_CODE (trial) != BARRIER);
+              trial = prev_nonnote_insn (trial))
+           {
+             if (find_regno_note (trial, REG_DEAD, dreg))
+               {
+                 remove_death (dreg, trial);
+                 break;
+               }
+           }
+       }
+    }
+
+  return ret;
+}
+
+/* Try to simplify a single SET instruction.  SET is the set pattern.
+   INSN is the instruction it came from. */
+
+static void
+reload_cse_simplify_set (set, insn)
+     rtx set;
+     rtx insn;
+{
+  int dreg;
+  rtx src;
+  enum machine_mode dest_mode;
+  enum reg_class dclass;
+  register int i;
+
+  /* We only handle one case: if we set a register to a value which is
+     not a register, we try to find that value in some other register
+     and change the set into a register copy.  */
+
+  dreg = true_regnum (SET_DEST (set));
+  if (dreg < 0)
+    return;
+
+  src = SET_SRC (set);
+  if (side_effects_p (src) || true_regnum (src) >= 0)
+    return;
+
+  /* If memory loads are cheaper than register copies, don't change
+     them.  */
+  if (GET_CODE (src) == MEM && MEMORY_MOVE_COST (GET_MODE (src)) < 2)
+    return;
+
+  dest_mode = GET_MODE (SET_DEST (set));
+  dclass = REGNO_REG_CLASS (dreg);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (i != dreg
+         && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
+         && reload_cse_regno_equal_p (i, src, dest_mode))
+       {
+         int validated;
+
+         /* Pop back to the real obstacks while changing the insn.  */
+         pop_obstacks ();
+
+         validated = validate_change (insn, &SET_SRC (set),
+                                      gen_rtx (REG, dest_mode, i), 0);
+
+         /* Go back to the obstack we are using for temporary
+             storage.  */
+         push_obstacks (&reload_obstack, &reload_obstack);
+
+         if (validated)
+           {
+             /* We need to look for an earlier REG_DEAD note on I,
+                and remove it if it exists.  */
+             if (! find_regno_note (insn, REG_UNUSED, i))
+               {
+                 rtx trial;
+
+                 for (trial = prev_nonnote_insn (insn);
+                      (trial
+                       && GET_CODE (trial) != CODE_LABEL
+                       && GET_CODE (trial) != BARRIER);
+                      trial = prev_nonnote_insn (trial))
+                   {
+                     if (find_regno_note (trial, REG_DEAD, i))
+                       {
+                         remove_death (i, trial);
+                         break;
+                       }
+                   }
+               }
+
+             return;
+           }
+       }
+    }
+}
+
+/* These two variables are used to pass information from
+   reload_cse_record_set to reload_cse_check_clobber.  */
+
+static int reload_cse_check_clobbered;
+static rtx reload_cse_check_src;
+
+/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set
+   RELOAD_CSE_CHECK_CLOBBERED.  This is called via note_stores.  The
+   second argument, which is passed by note_stores, is ignored.  */
+
+static void
+reload_cse_check_clobber (dest, ignore)
+     rtx dest;
+     rtx ignore;
+{
+  if (reg_overlap_mentioned_p (dest, reload_cse_check_src))
+    reload_cse_check_clobbered = 1;
+}
+
+/* Record the result of a SET instruction.  SET is the set pattern.
+   BODY is the pattern of the insn that it came from.  */
+
+static void
+reload_cse_record_set (set, body)
+     rtx set;
+     rtx body;
+{
+  rtx dest, src;
+  int dreg, sreg;
+  enum machine_mode dest_mode;
+
+  dest = SET_DEST (set);
+  src = SET_SRC (set);
+  dreg = true_regnum (dest);
+  sreg = true_regnum (src);
+  dest_mode = GET_MODE (dest);
+
+  /* We can only handle an assignment to a register, or a store of a
+     register to a memory location.  For other cases, we just clobber
+     the destination.  We also have to just clobber if there are side
+     effects in SRC or DEST.  */
+  if ((dreg < 0 && GET_CODE (dest) != MEM)
+      || side_effects_p (src)
+      || side_effects_p (dest))
+    {
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+
+#ifdef HAVE_cc0
+  /* We don't try to handle values involving CC, because it's a pain
+     to keep track of when they have to be invalidated.  */
+  if (reg_mentioned_p (cc0_rtx, src)
+      || reg_mentioned_p (cc0_rtx, dest))
+    {
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+#endif
+
+  /* If BODY is a PARALLEL, then we need to see whether the source of
+     SET is clobbered by some other instruction in the PARALLEL.  */
+  if (GET_CODE (body) == PARALLEL)
+    {
+      int i;
+
+      for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+       {
+         rtx x;
+
+         x = XVECEXP (body, 0, i);
+         if (x == set)
+           continue;
+
+         reload_cse_check_clobbered = 0;
+         reload_cse_check_src = src;
+         note_stores (x, reload_cse_check_clobber);
+         if (reload_cse_check_clobbered)
+           {
+             reload_cse_invalidate_rtx (dest, NULL_RTX);
+             return;
+           }
+       }
+    }
+
+  if (dreg >= 0)
+    {
+      int i;
+
+      /* This is an assignment to a register.  Update the value we
+         have stored for the register.  */
+      if (sreg >= 0)
+       {
+         rtx x;
+
+         /* This is a copy from one register to another.  Any values
+            which were valid for SREG are now valid for DREG.  If the
+            mode changes, we use gen_lowpart_common to extract only
+            the part of the value that is copied.  */
+         reg_values[dreg] = 0;
+         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+           {
+             rtx tmp;
+
+             if (XEXP (x, 0) == 0)
+               continue;
+             if (dest_mode == GET_MODE (XEXP (x, 0)))
+               tmp = XEXP (x, 0);
+             else
+               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+             if (tmp)
+               reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, tmp,
+                                           reg_values[dreg]);
+           }         
+       }
+      else
+       reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, src, NULL_RTX);
+
+      /* We've changed DREG, so invalidate any values held by other
+         registers that depend upon it.  */
+      reload_cse_invalidate_regno (dreg, dest_mode, 0);
+
+      /* If this assignment changes more than one hard register,
+         forget anything we know about the others.  */
+      for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++)
+       reg_values[dreg + i] = 0;
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      /* Invalidate conflicting memory locations.  */
+      reload_cse_invalidate_mem (dest);
+
+      /* If we're storing a register to memory, add DEST to the list
+         in REG_VALUES.  */
+      if (sreg >= 0 && ! side_effects_p (dest))
+       reg_values[sreg] = gen_rtx (EXPR_LIST, dest_mode, dest,
+                                   reg_values[sreg]);
+    }
+  else
+    {
+      /* We should have bailed out earlier.  */
+      abort ();
+    }
+}