OSDN Git Service

Add new test - do not warn about (non-)redundant friend declaration.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 2f50fb3..dbf99d6 100644 (file)
@@ -1,5 +1,6 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
-   Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,7 +19,6 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-
 #include "config.h"
 #include "system.h"
 
@@ -28,8 +28,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "obstack.h"
 #include "insn-config.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
@@ -38,6 +36,7 @@ Boston, MA 02111-1307, USA.  */
 #include "reload.h"
 #include "recog.h"
 #include "output.h"
+#include "cselib.h"
 #include "real.h"
 #include "toplev.h"
 
@@ -79,9 +78,12 @@ Boston, MA 02111-1307, USA.  */
    fixing up each insn, and generating the new insns to copy values
    into the reload registers.  */
 
-
 #ifndef REGISTER_MOVE_COST
-#define REGISTER_MOVE_COST(x, y) 2
+#define REGISTER_MOVE_COST(m, x, y) 2
+#endif
+
+#ifndef LOCAL_REGNO
+#define LOCAL_REGNO(REGNO)  0
 #endif
 \f
 /* During reload_as_needed, element N contains a REG rtx for the hard reg
@@ -118,7 +120,7 @@ rtx *reg_equiv_address;
 rtx *reg_equiv_mem;
 
 /* Widest width in which each pseudo reg is referred to (via subreg).  */
-static int *reg_max_ref_width;
+static unsigned int *reg_max_ref_width;
 
 /* Element N is the list of insns that initialized reg N from its equivalent
    constant or memory slot.  */
@@ -215,13 +217,6 @@ static HARD_REG_SET used_spill_regs;
    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.
-   It is set up by order_regs_for_reload.
-   Empty elements at the end contain -1.  */
-static short potential_reload_regs[FIRST_PSEUDO_REGISTER];
-
 /* Nonzero if indirect addressing is supported on the machine; this means
    that spilling (REG n) does not require reloading it into a register in
    order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))).  The
@@ -242,10 +237,14 @@ char double_reg_address_ok;
 static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER];
 
 /* Width allocated so far for that stack slot.  */
-static int spill_stack_slot_width[FIRST_PSEUDO_REGISTER];
+static unsigned int spill_stack_slot_width[FIRST_PSEUDO_REGISTER];
 
 /* Record which pseudos needed to be spilled.  */
-static regset spilled_pseudos;
+static regset_head spilled_pseudos;
+
+/* Used for communication between order_regs_for_reload and count_pseudo.
+   Used to avoid counting one pseudo twice.  */
+static regset_head pseudos_counted;
 
 /* First uid used by insns created by reload in this function.
    Used in find_equiv_reg.  */
@@ -275,9 +274,13 @@ struct obstack reload_obstack;
 char *reload_startobj;
 
 /* The point after all insn_chain structures.  Used to quickly deallocate
-   memory used while processing one insn.  */
+   memory allocated in copy_reloads during calculate_needs_all_insns.  */
 char *reload_firstobj;
 
+/* This points before all local rtl generated by register elimination.
+   Used to quickly free all memory after processing one insn.  */
+static char *reload_insn_firstobj;
+
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
@@ -318,10 +321,10 @@ struct elim_table
   rtx to_rtx;                  /* REG rtx for the replacement.  */
 };
 
-static struct elim_table * reg_eliminate = 0;
+static struct elim_table *reg_eliminate = 0;
 
 /* This is an intermediate structure to initialize the table.  It has
-   exactly the members provided by ELIMINABLE_REGS. */
+   exactly the members provided by ELIMINABLE_REGS.  */
 static struct elim_table_1
 {
   int from;
@@ -338,7 +341,7 @@ static struct elim_table_1
   {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}};
 #endif
 
-#define NUM_ELIMINABLE_REGS (sizeof reg_eliminate_1/sizeof reg_eliminate_1[0])
+#define NUM_ELIMINABLE_REGS ARRAY_SIZE (reg_eliminate_1)
 
 /* Record the number of pending eliminations that have an offset not equal
    to their initial offset.  If non-zero, we use a new copy of each
@@ -364,99 +367,101 @@ static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 /* Number of labels in the current function.  */
 
 static int num_labels;
-
-struct hard_reg_n_uses
-{
-  int regno;
-  unsigned int uses;
-};
 \f
-static void maybe_fix_stack_asms       PROTO((void));
-static void calculate_needs_all_insns  PROTO((int));
-static void calculate_needs            PROTO((struct insn_chain *));
-static void find_reload_regs           PROTO((struct insn_chain *chain,
-                                              FILE *));
-static void find_tworeg_group          PROTO((struct insn_chain *, int,
-                                              FILE *));
-static void find_group                 PROTO((struct insn_chain *, int,
-                                              FILE *));
-static int possible_group_p            PROTO((struct insn_chain *, int));
-static void count_possible_groups      PROTO((struct insn_chain *, int));
-static int modes_equiv_for_class_p     PROTO((enum machine_mode,
-                                              enum machine_mode,
-                                              enum reg_class));
-static void delete_caller_save_insns   PROTO((void));
-
-static void spill_failure              PROTO((rtx));
-static void new_spill_reg              PROTO((struct insn_chain *, int, int,
-                                              int, FILE *));
-static void maybe_mark_pseudo_spilled  PROTO((int));
-static void delete_dead_insn           PROTO((rtx));
-static void alter_reg                          PROTO((int, int));
-static void set_label_offsets          PROTO((rtx, rtx, int));
-static void check_eliminable_occurrences       PROTO((rtx));
-static void elimination_effects                PROTO((rtx, enum machine_mode));
-static int eliminate_regs_in_insn      PROTO((rtx, int));
-static void update_eliminable_offsets  PROTO((void));
-static void mark_not_eliminable                PROTO((rtx, rtx, void *));
-static void set_initial_elim_offsets   PROTO((void));
-static void verify_initial_elim_offsets        PROTO((void));
-static void set_initial_label_offsets  PROTO((void));
-static void set_offsets_for_label      PROTO((rtx));
-static void init_elim_table            PROTO((void));
-static void update_eliminables         PROTO((HARD_REG_SET *));
-static void spill_hard_reg             PROTO((int, FILE *, int));
-static int finish_spills               PROTO((int, FILE *));
-static void ior_hard_reg_set           PROTO((HARD_REG_SET *, HARD_REG_SET *));
-static void scan_paradoxical_subregs   PROTO((rtx));
-static int hard_reg_use_compare                PROTO((const PTR, const PTR));
-static void count_pseudo               PROTO((struct hard_reg_n_uses *, int));
-static void order_regs_for_reload      PROTO((struct insn_chain *));
-static void reload_as_needed           PROTO((int));
-static void forget_old_reloads_1       PROTO((rtx, rtx, void *));
-static int reload_reg_class_lower      PROTO((const PTR, const 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,
-                                              enum machine_mode));
-static int reload_reg_free_p           PROTO((int, int, enum reload_type));
-static int reload_reg_free_for_value_p PROTO((int, int, enum reload_type, rtx, rtx, int, int));
-static int reload_reg_reaches_end_p    PROTO((int, int, enum reload_type));
-static int allocate_reload_reg         PROTO((struct insn_chain *, int, int,
-                                              int));
-static void choose_reload_regs_init    PROTO((struct insn_chain *, rtx *));
-static void choose_reload_regs         PROTO((struct insn_chain *));
-static void merge_assigned_reloads     PROTO((rtx));
-static void emit_reload_insns          PROTO((struct insn_chain *));
-static void delete_output_reload       PROTO((rtx, int, int));
-static void delete_address_reloads     PROTO((rtx, rtx));
-static void delete_address_reloads_1   PROTO((rtx, rtx, rtx));
-static rtx inc_for_reload              PROTO((rtx, rtx, rtx, int));
-static int constraint_accepts_reg_p    PROTO((const char *, rtx));
-static void reload_cse_regs_1          PROTO((rtx));
-static void reload_cse_invalidate_regno        PROTO((int, enum machine_mode, int));
-static int reload_cse_mem_conflict_p   PROTO((rtx, rtx));
-static void reload_cse_invalidate_mem  PROTO((rtx));
-static void reload_cse_invalidate_rtx  PROTO((rtx, rtx, void *));
-static int reload_cse_regno_equal_p    PROTO((int, rtx, enum machine_mode));
-static int reload_cse_noop_set_p       PROTO((rtx, rtx));
-static int reload_cse_simplify_set     PROTO((rtx, rtx));
-static int reload_cse_simplify_operands        PROTO((rtx));
-static void reload_cse_check_clobber   PROTO((rtx, rtx, void *));
-static void reload_cse_record_set      PROTO((rtx, rtx));
-static void reload_combine PROTO((void));
-static void reload_combine_note_use PROTO((rtx *, rtx));
-static void reload_combine_note_store PROTO((rtx, rtx, void *));
-static void reload_cse_move2add PROTO((rtx));
-static void move2add_note_store PROTO((rtx, rtx, void *));
+static void replace_pseudos_in_call_usage      PARAMS((rtx *,
+                                                       enum machine_mode,
+                                                       rtx));
+static void maybe_fix_stack_asms       PARAMS ((void));
+static void copy_reloads               PARAMS ((struct insn_chain *));
+static void calculate_needs_all_insns  PARAMS ((int));
+static int find_reg                    PARAMS ((struct insn_chain *, int));
+static void find_reload_regs           PARAMS ((struct insn_chain *));
+static void select_reload_regs         PARAMS ((void));
+static void delete_caller_save_insns   PARAMS ((void));
+
+static void spill_failure              PARAMS ((rtx, enum reg_class));
+static void count_spilled_pseudo       PARAMS ((int, int, int));
+static void delete_dead_insn           PARAMS ((rtx));
+static void alter_reg                  PARAMS ((int, int));
+static void set_label_offsets          PARAMS ((rtx, rtx, int));
+static void check_eliminable_occurrences       PARAMS ((rtx));
+static void elimination_effects                PARAMS ((rtx, enum machine_mode));
+static int eliminate_regs_in_insn      PARAMS ((rtx, int));
+static void update_eliminable_offsets  PARAMS ((void));
+static void mark_not_eliminable                PARAMS ((rtx, rtx, void *));
+static void set_initial_elim_offsets   PARAMS ((void));
+static void verify_initial_elim_offsets        PARAMS ((void));
+static void set_initial_label_offsets  PARAMS ((void));
+static void set_offsets_for_label      PARAMS ((rtx));
+static void init_elim_table            PARAMS ((void));
+static void update_eliminables         PARAMS ((HARD_REG_SET *));
+static void spill_hard_reg             PARAMS ((unsigned int, int));
+static int finish_spills               PARAMS ((int));
+static void ior_hard_reg_set           PARAMS ((HARD_REG_SET *, HARD_REG_SET *));
+static void scan_paradoxical_subregs   PARAMS ((rtx));
+static void count_pseudo               PARAMS ((int));
+static void order_regs_for_reload      PARAMS ((struct insn_chain *));
+static void reload_as_needed           PARAMS ((int));
+static void forget_old_reloads_1       PARAMS ((rtx, rtx, void *));
+static int reload_reg_class_lower      PARAMS ((const PTR, const PTR));
+static void mark_reload_reg_in_use     PARAMS ((unsigned int, int,
+                                                enum reload_type,
+                                                enum machine_mode));
+static void clear_reload_reg_in_use    PARAMS ((unsigned int, int,
+                                                enum reload_type,
+                                                enum machine_mode));
+static int reload_reg_free_p           PARAMS ((unsigned int, int,
+                                                enum reload_type));
+static int reload_reg_free_for_value_p PARAMS ((int, int, int,
+                                                enum reload_type,
+                                                rtx, rtx, int, int));
+static int free_for_value_p            PARAMS ((int, enum machine_mode, int,
+                                                enum reload_type, rtx, rtx,
+                                                int, int));
+static int reload_reg_reaches_end_p    PARAMS ((unsigned int, int,
+                                                enum reload_type));
+static int allocate_reload_reg         PARAMS ((struct insn_chain *, int,
+                                                int));
+static int conflicts_with_override     PARAMS ((rtx));
+static void failed_reload              PARAMS ((rtx, int));
+static int set_reload_reg              PARAMS ((int, int));
+static void choose_reload_regs_init    PARAMS ((struct insn_chain *, rtx *));
+static void choose_reload_regs         PARAMS ((struct insn_chain *));
+static void merge_assigned_reloads     PARAMS ((rtx));
+static void emit_input_reload_insns    PARAMS ((struct insn_chain *,
+                                                struct reload *, rtx, int));
+static void emit_output_reload_insns   PARAMS ((struct insn_chain *,
+                                                struct reload *, int));
+static void do_input_reload            PARAMS ((struct insn_chain *,
+                                                struct reload *, int));
+static void do_output_reload           PARAMS ((struct insn_chain *,
+                                                struct reload *, int));
+static void emit_reload_insns          PARAMS ((struct insn_chain *));
+static void delete_output_reload       PARAMS ((rtx, int, int));
+static void delete_address_reloads     PARAMS ((rtx, rtx));
+static void delete_address_reloads_1   PARAMS ((rtx, rtx, rtx));
+static rtx inc_for_reload              PARAMS ((rtx, rtx, rtx, int));
+static int constraint_accepts_reg_p    PARAMS ((const char *, rtx));
+static void reload_cse_regs_1          PARAMS ((rtx));
+static int reload_cse_noop_set_p       PARAMS ((rtx));
+static int reload_cse_simplify_set     PARAMS ((rtx, rtx));
+static int reload_cse_simplify_operands        PARAMS ((rtx));
+static void reload_combine             PARAMS ((void));
+static void reload_combine_note_use    PARAMS ((rtx *, rtx));
+static void reload_combine_note_store  PARAMS ((rtx, rtx, void *));
+static void reload_cse_move2add                PARAMS ((rtx));
+static void move2add_note_store                PARAMS ((rtx, rtx, void *));
 #ifdef AUTO_INC_DEC
-static void add_auto_inc_notes PROTO((rtx, rtx));
+static void add_auto_inc_notes         PARAMS ((rtx, rtx));
 #endif
-static rtx gen_mode_int                        PROTO((enum machine_mode,
-                                              HOST_WIDE_INT));
-static void failed_reload              PROTO((rtx, int));
-static int set_reload_reg              PROTO((int, int));
-extern void dump_needs                 PROTO((struct insn_chain *, FILE *));
+static void copy_eh_notes              PARAMS ((rtx, rtx));
+static HOST_WIDE_INT sext_for_mode     PARAMS ((enum machine_mode,
+                                                HOST_WIDE_INT));
+static void failed_reload              PARAMS ((rtx, int));
+static int set_reload_reg              PARAMS ((int, int));
+static void reload_cse_delete_noop_set PARAMS ((rtx, rtx));
+static void reload_cse_simplify                PARAMS ((rtx));
+extern void dump_needs                 PARAMS ((struct insn_chain *));
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -509,6 +514,9 @@ init_reload ()
   /* Initialize obstack for our rtl allocation.  */
   gcc_obstack_init (&reload_obstack);
   reload_startobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+  INIT_REG_SET (&spilled_pseudos);
+  INIT_REG_SET (&pseudos_counted);
 }
 
 /* List of insn chains that are currently unused.  */
@@ -524,8 +532,8 @@ new_insn_chain ()
     {
       c = (struct insn_chain *)
        obstack_alloc (&reload_obstack, sizeof (struct insn_chain));
-      c->live_before = OBSTACK_ALLOC_REG_SET (&reload_obstack);
-      c->live_after = OBSTACK_ALLOC_REG_SET (&reload_obstack);
+      INIT_REG_SET (&c->live_throughout);
+      INIT_REG_SET (&c->dead_or_set);
     }
   else
     {
@@ -541,17 +549,20 @@ new_insn_chain ()
 
 /* Small utility function to set all regs in hard reg set TO which are
    allocated to pseudos in regset FROM.  */
+
 void
 compute_use_by_pseudos (to, from)
      HARD_REG_SET *to;
      regset from;
 {
-  int regno;
+  unsigned int regno;
+
   EXECUTE_IF_SET_IN_REG_SET
     (from, FIRST_PSEUDO_REGISTER, regno,
      {
        int r = reg_renumber[regno];
        int nregs;
+
        if (r < 0)
         {
           /* reload_combine uses the information from
@@ -569,6 +580,70 @@ compute_use_by_pseudos (to, from)
         }
      });
 }
+
+/* Replace all pseudos found in LOC with their corresponding
+   equivalences.  */
+
+static void
+replace_pseudos_in_call_usage (loc, mem_mode, usage)
+     rtx *loc;
+     enum machine_mode mem_mode;
+     rtx usage;
+{
+  rtx x = *loc;
+  enum rtx_code code;
+  const char *fmt;
+  int i, j;
+
+  if (! x)
+    return;
+
+  code = GET_CODE (x);
+  if (code == REG)
+    {
+      int regno = REGNO (x);
+
+      if (regno < FIRST_PSEUDO_REGISTER)
+       return;
+
+      x = eliminate_regs (x, mem_mode, usage);
+      if (x != *loc)
+       {
+         *loc = x;
+         replace_pseudos_in_call_usage (loc, mem_mode, usage);
+         return;
+       }
+
+      if (reg_equiv_constant[regno])
+       *loc = reg_equiv_constant[regno];
+      else if (reg_equiv_mem[regno])
+       *loc = reg_equiv_mem[regno];
+      else if (reg_equiv_address[regno])
+       *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]);
+      else if (GET_CODE (regno_reg_rtx[regno]) != REG
+              || REGNO (regno_reg_rtx[regno]) != regno)
+       *loc = regno_reg_rtx[regno];
+      else
+       abort ();
+
+      return;
+    }
+  else if (code == MEM)
+    {
+      replace_pseudos_in_call_usage (& XEXP (x, 0), GET_MODE (x), usage);
+      return;
+    }
+
+  /* Process each of our operands recursively.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+    if (*fmt == 'e')
+      replace_pseudos_in_call_usage (&XEXP (x, i), mem_mode, usage);
+    else if (*fmt == 'E')
+      for (j = 0; j < XVECLEN (x, i); j++)
+       replace_pseudos_in_call_usage (& XVECEXP (x, i, j), mem_mode, usage);
+}
+
 \f
 /* Global variables used by reload and its subroutines.  */
 
@@ -590,19 +665,13 @@ static int failure;
    If GLOBAL is zero, we do not have enough information to do that,
    so any pseudo reg that is spilled must go to the stack.
 
-   DUMPFILE is the global-reg debugging dump file stream, or 0.
-   If it is nonzero, messages are written to it to describe
-   which registers are seized as reload regs, which pseudo regs
-   are spilled from them, and where the pseudo regs are reallocated to.
-
    Return value is nonzero if reload failed
    and we must not do any more for this function.  */
 
 int
-reload (first, global, dumpfile)
+reload (first, global)
      rtx first;
      int global;
-     FILE *dumpfile;
 {
   register int i;
   register rtx insn;
@@ -610,7 +679,7 @@ reload (first, global, dumpfile)
 
   /* The two pointers used to track the true location of the memory used
      for label offsets.  */
-  char *real_known_ptr = NULL_PTR;
+  char *real_known_ptr = NULL;
   int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
 
   /* Make sure even insns with volatile mem refs are recognizable.  */
@@ -622,7 +691,7 @@ reload (first, global, dumpfile)
 
   /* Make sure that the last insn in the chain
      is not something that needs reloading.  */
-  emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  emit_note (NULL, NOTE_INSN_DELETED);
 
   /* Enable find_equiv_reg to distinguish insns made by reload.  */
   reload_first_uid = get_max_uid ();
@@ -633,8 +702,8 @@ reload (first, global, dumpfile)
 #endif
 
   /* We don't have a stack slot for any spill reg yet.  */
-  bzero ((char *) spill_stack_slot, sizeof spill_stack_slot);
-  bzero ((char *) spill_stack_slot_width, sizeof spill_stack_slot_width);
+  memset ((char *) spill_stack_slot, 0, sizeof spill_stack_slot);
+  memset ((char *) spill_stack_slot_width, 0, sizeof spill_stack_slot_width);
 
   /* Initialize the save area information for caller-save, in case some
      are needed.  */
@@ -651,10 +720,8 @@ reload (first, global, dumpfile)
      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;
-      }
+      if (! call_used_regs[i] && ! fixed_regs[i] && ! LOCAL_REGNO (i))
+       regs_ever_live[i] = 1;
 
   /* Find all the pseudo registers that didn't get hard regs
      but do have known equivalent constants or memory slots.
@@ -671,9 +738,9 @@ reload (first, global, dumpfile)
   reg_equiv_mem = (rtx *) xcalloc (max_regno, sizeof (rtx));
   reg_equiv_init = (rtx *) xcalloc (max_regno, sizeof (rtx));
   reg_equiv_address = (rtx *) xcalloc (max_regno, sizeof (rtx));
-  reg_max_ref_width = (int *) xcalloc (max_regno, sizeof (int));
+  reg_max_ref_width = (unsigned int *) xcalloc (max_regno, sizeof (int));
   reg_old_renumber = (short *) xcalloc (max_regno, sizeof (short));
-  bcopy ((PTR) reg_renumber, (PTR) reg_old_renumber, max_regno * sizeof (short));
+  memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short));
   pseudo_forbidden_regs
     = (HARD_REG_SET *) xmalloc (max_regno * sizeof (HARD_REG_SET));
   pseudo_previous_regs
@@ -770,7 +837,7 @@ reload (first, global, dumpfile)
          = gen_rtx_INSN_LIST (VOIDmode, insn,
                               reg_equiv_init[REGNO (SET_SRC (set))]);
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        scan_paradoxical_subregs (PATTERN (insn));
     }
 
@@ -817,19 +884,17 @@ reload (first, global, dumpfile)
   /* Initialize to -1, which means take the first spill register.  */
   last_spill_reg = -1;
 
-  spilled_pseudos = ALLOCA_REG_SET ();
-
   /* Spill any hard regs that we know we can't eliminate.  */
   CLEAR_HARD_REG_SET (used_spill_regs);
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     if (! ep->can_eliminate)
-      spill_hard_reg (ep->from, dumpfile, 1);
+      spill_hard_reg (ep->from, 1);
 
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
   if (frame_pointer_needed)
-    spill_hard_reg (HARD_FRAME_POINTER_REGNUM, dumpfile, 1);
+    spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1);
 #endif
-  finish_spills (global, dumpfile);
+  finish_spills (global);
 
   /* From now on, we may need to generate moves differently.  We may also
      allow modifications of insns which cause them to not be recognized.
@@ -842,15 +907,15 @@ reload (first, global, dumpfile)
     {
       int something_changed;
       int did_spill;
-      struct insn_chain *chain;
 
       HOST_WIDE_INT starting_frame_size;
 
-      /* Round size of stack frame to BIGGEST_ALIGNMENT.  This must be done
+      /* Round size of stack frame to stack_alignment_needed.  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);
+      if (cfun->stack_alignment_needed)
+        assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed);
 
       starting_frame_size = get_frame_size ();
 
@@ -928,7 +993,7 @@ reload (first, global, dumpfile)
 
       calculate_needs_all_insns (global);
 
-      CLEAR_REG_SET (spilled_pseudos);
+      CLEAR_REG_SET (&spilled_pseudos);
       did_spill = 0;
 
       something_changed = 0;
@@ -945,7 +1010,7 @@ reload (first, global, dumpfile)
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
          if (TEST_HARD_REG_BIT (to_spill, i))
            {
-             spill_hard_reg (i, dumpfile, 1);
+             spill_hard_reg (i, 1);
              did_spill = 1;
 
              /* Regardless of the state of spills, if we previously had
@@ -961,23 +1026,20 @@ reload (first, global, dumpfile)
            }
       }
 
-      CLEAR_HARD_REG_SET (used_spill_regs);
-      /* Try to satisfy the needs for each insn.  */
-      for (chain = insns_need_reload; chain != 0;
-          chain = chain->next_need_reload)
-       find_reload_regs (chain, dumpfile);
-
+      select_reload_regs ();
       if (failure)
        goto failed;
 
       if (insns_need_reload != 0 || did_spill)
-       something_changed |= finish_spills (global, dumpfile);
+       something_changed |= finish_spills (global);
 
       if (! something_changed)
        break;
 
       if (caller_save_needed)
        delete_caller_save_insns ();
+
+      obstack_free (&reload_obstack, reload_firstobj);
     }
 
   /* If global-alloc was run, notify it of any register eliminations we have
@@ -1023,7 +1085,7 @@ reload (first, global, dumpfile)
   if (insns_need_reload != 0 || something_needs_elimination
       || something_needs_operands_changed)
     {
-      int old_frame_size = get_frame_size ();
+      HOST_WIDE_INT old_frame_size = get_frame_size ();
 
       reload_as_needed (global);
 
@@ -1049,6 +1111,7 @@ reload (first, global, dumpfile)
      and we decide not to abort about it.  */
  failed:
 
+  CLEAR_REG_SET (&spilled_pseudos);
   reload_in_progress = 0;
 
   /* Now eliminate all pseudo regs by modifying them into
@@ -1114,10 +1177,15 @@ reload (first, global, dumpfile)
      and regenerate REG_INC notes that may have been moved around.  */
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+    if (INSN_P (insn))
       {
        rtx *pnote;
 
+       if (GET_CODE (insn) == CALL_INSN)
+         replace_pseudos_in_call_usage (& CALL_INSN_FUNCTION_USAGE (insn),
+                                        VOIDmode,
+                                        CALL_INSN_FUNCTION_USAGE (insn));
+
        if ((GET_CODE (PATTERN (insn)) == USE
             && find_reg_note (insn, REG_EQUAL, NULL_RTX))
            || (GET_CODE (PATTERN (insn)) == CLOBBER
@@ -1194,8 +1262,6 @@ reload (first, global, dumpfile)
   free (pseudo_previous_regs);
   free (pseudo_forbidden_regs);
 
-  FREE_REG_SET (spilled_pseudos);
-
   CLEAR_HARD_REG_SET (used_spill_regs);
   for (i = 0; i < n_spills; i++)
     SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
@@ -1213,6 +1279,7 @@ reload (first, global, dumpfile)
    fatal_insn later.  We clear the corresponding regnos in the live
    register sets to avoid this.
    The whole thing is rather sick, I'm afraid.  */
+
 static void
 maybe_fix_stack_asms ()
 {
@@ -1227,7 +1294,7 @@ maybe_fix_stack_asms ()
       HARD_REG_SET clobbered, allowed;
       rtx pat;
 
-      if (GET_RTX_CLASS (GET_CODE (chain->insn)) != 'i'
+      if (! INSN_P (chain->insn)
          || (noperands = asm_noperands (PATTERN (chain->insn))) < 0)
        continue;
       pat = PATTERN (chain->insn);
@@ -1285,9 +1352,6 @@ maybe_fix_stack_asms ()
                case 'F': case 's': case 'i': case 'n': case 'X': case 'I':
                case 'J': case 'K': case 'L': case 'M': case 'N': case 'O':
                case 'P':
-#ifdef EXTRA_CONSTRAINT
-               case 'Q': case 'R': case 'S': case 'T': case 'U':
-#endif
                  break;
 
                case 'p':
@@ -1312,15 +1376,28 @@ maybe_fix_stack_asms ()
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (TEST_HARD_REG_BIT (allowed, i))
          {
-           CLEAR_REGNO_REG_SET (chain->live_before, i);
-           CLEAR_REGNO_REG_SET (chain->live_after, i);
+           CLEAR_REGNO_REG_SET (&chain->live_throughout, i);
+           CLEAR_REGNO_REG_SET (&chain->dead_or_set, i);
          }
     }
 
 #endif
 }
-
 \f
+/* Copy the global variables n_reloads and rld into the corresponding elts
+   of CHAIN.  */
+static void
+copy_reloads (chain)
+     struct insn_chain *chain;
+{
+  chain->n_reloads = n_reloads;
+  chain->rld
+    = (struct reload *) obstack_alloc (&reload_obstack,
+                                      n_reloads * sizeof (struct reload));
+  memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
+  reload_insn_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+}
+
 /* Walk the chain of insns, and determine for each whether it needs reloads
    and/or eliminations.  Build the corresponding insns_need_reload list, and
    set something_needs_elimination as appropriate.  */
@@ -1329,15 +1406,19 @@ calculate_needs_all_insns (global)
      int global;
 {
   struct insn_chain **pprev_reload = &insns_need_reload;
-  struct insn_chain *chain;
+  struct insn_chain *chain, *next = 0;
 
   something_needs_elimination = 0;
 
-  for (chain = reload_insn_chain; chain != 0; chain = chain->next)
+  reload_insn_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+  for (chain = reload_insn_chain; chain != 0; chain = next)
     {
       rtx insn = chain->insn;
 
-      /* Clear out the shortcuts, in case they were set last time through.  */
+      next = chain->next;
+
+      /* Clear out the shortcuts.  */
+      chain->n_reloads = 0;
       chain->need_elim = 0;
       chain->need_reload = 0;
       chain->need_operand_change = 0;
@@ -1347,11 +1428,10 @@ calculate_needs_all_insns (global)
         known offsets at labels.  */
 
       if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == JUMP_INSN
-         || (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-             && REG_NOTES (insn) != 0))
+         || (INSN_P (insn) && REG_NOTES (insn) != 0))
        set_label_offsets (insn, insn, 0);
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        {
          rtx old_body = PATTERN (insn);
          int old_code = INSN_CODE (insn);
@@ -1392,6 +1472,15 @@ calculate_needs_all_insns (global)
                  PUT_CODE (insn, NOTE);
                  NOTE_SOURCE_FILE (insn) = 0;
                  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+                 /* Delete it from the reload chain */
+                 if (chain->prev)
+                   chain->prev->next = next;
+                 else
+                   reload_insn_chain = next;
+                 if (next)
+                   next->prev = chain->prev;
+                 chain->next = unused_insn_chains;
+                 unused_insn_chains = chain;
                  continue;
                }
            }
@@ -1407,7 +1496,7 @@ calculate_needs_all_insns (global)
          /* Discard any register replacements done.  */
          if (did_elimination)
            {
-             obstack_free (&reload_obstack, reload_firstobj);
+             obstack_free (&reload_obstack, reload_insn_firstobj);
              PATTERN (insn) = old_body;
              INSN_CODE (insn) = old_code;
              REG_NOTES (insn) = old_notes;
@@ -1418,611 +1507,338 @@ calculate_needs_all_insns (global)
 
          if (n_reloads != 0)
            {
+             copy_reloads (chain);
              *pprev_reload = chain;
              pprev_reload = &chain->next_need_reload;
-
-             calculate_needs (chain);
            }
        }
     }
   *pprev_reload = 0;
 }
+\f
+/* Comparison function for qsort to decide which of two reloads
+   should be handled first.  *P1 and *P2 are the reload numbers.  */
 
-/* Compute the most additional registers needed by one instruction,
-   given by CHAIN.  Collect information separately for each class of regs.
-
-   To compute the number of reload registers of each class 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, which must be live over the entire input section
-   of reloads, and the maximum of all the RELOAD_FOR_INPUT_ADDRESS and
-   RELOAD_FOR_OPERAND_ADDRESS reloads, which conflict with the inputs.
+static int
+reload_reg_class_lower (r1p, r2p)
+     const PTR r1p;
+     const PTR r2p;
+{
+  register int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
+  register int t;
 
-   The registers needed for output are RELOAD_OTHER and RELOAD_FOR_OUTPUT,
-   which are live for the entire output portion, and the maximum of all the
-   RELOAD_FOR_OUTPUT_ADDRESS reloads for each operand.
+  /* Consider required reloads before optional ones.  */
+  t = rld[r1].optional - rld[r2].optional;
+  if (t != 0)
+    return t;
 
-   The total number of registers needed is the maximum of the
-   inputs and outputs.  */
+  /* Count all solitary classes before non-solitary ones.  */
+  t = ((reg_class_size[(int) rld[r2].class] == 1)
+       - (reg_class_size[(int) rld[r1].class] == 1));
+  if (t != 0)
+    return t;
 
-static void
-calculate_needs (chain)
-     struct insn_chain *chain;
-{
-  int i;
+  /* Aside from solitaires, consider all multi-reg groups first.  */
+  t = rld[r2].nregs - rld[r1].nregs;
+  if (t != 0)
+    return t;
 
-  /* 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;
-
-  bzero ((char *) chain->group_size, sizeof chain->group_size);
-  for (i = 0; i < N_REG_CLASSES; i++)
-    chain->group_mode[i] = VOIDmode;
-  bzero ((char *) &insn_needs, sizeof insn_needs);
-
-  /* Count each reload once in every class
-     containing the reload's own class.  */
+  /* Consider reloads in order of increasing reg-class number.  */
+  t = (int) rld[r1].class - (int) rld[r2].class;
+  if (t != 0)
+    return t;
 
-  for (i = 0; i < n_reloads; i++)
-    {
-      register enum reg_class *p;
-      enum reg_class class = rld[i].class;
-      int size;
-      enum machine_mode mode;
-      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.
-        Don't count optional reloads.
-        Don't count reloads that got combined with others.  */
-      if (rld[i].reg_rtx != 0
-         || rld[i].optional != 0
-         || (rld[i].out == 0 && rld[i].in == 0
-             && ! rld[i].secondary_p))
-       continue;
+  /* If reloads are equally urgent, sort by reload number,
+     so that the results of qsort leave nothing to chance.  */
+  return r1 - r2;
+}
+\f
+/* The cost of spilling each hard reg.  */
+static int spill_cost[FIRST_PSEUDO_REGISTER];
 
-      mode = rld[i].mode;
-      size = rld[i].nregs;
+/* When spilling multiple hard registers, we use SPILL_COST for the first
+   spilled hard reg and SPILL_ADD_COST for subsequent regs.  SPILL_ADD_COST
+   only the first hard reg for a multi-reg pseudo.  */
+static int spill_add_cost[FIRST_PSEUDO_REGISTER];
 
-      /* Decide which time-of-use to count this reload for.  */
-      switch (rld[i].when_needed)
-       {
-       case RELOAD_OTHER:
-         this_needs = &insn_needs.other;
-         break;
-       case RELOAD_FOR_INPUT:
-         this_needs = &insn_needs.input;
-         break;
-       case RELOAD_FOR_OUTPUT:
-         this_needs = &insn_needs.output;
-         break;
-       case RELOAD_FOR_INSN:
-         this_needs = &insn_needs.insn;
-         break;
-       case RELOAD_FOR_OTHER_ADDRESS:
-         this_needs = &insn_needs.other_addr;
-         break;
-       case RELOAD_FOR_INPUT_ADDRESS:
-         this_needs = &insn_needs.in_addr[rld[i].opnum];
-         break;
-       case RELOAD_FOR_INPADDR_ADDRESS:
-         this_needs = &insn_needs.in_addr_addr[rld[i].opnum];
-         break;
-       case RELOAD_FOR_OUTPUT_ADDRESS:
-         this_needs = &insn_needs.out_addr[rld[i].opnum];
-         break;
-       case RELOAD_FOR_OUTADDR_ADDRESS:
-         this_needs = &insn_needs.out_addr_addr[rld[i].opnum];
-         break;
-       case RELOAD_FOR_OPERAND_ADDRESS:
-         this_needs = &insn_needs.op_addr;
-         break;
-       case RELOAD_FOR_OPADDR_ADDR:
-         this_needs = &insn_needs.op_addr_reload;
-         break;
-       default:
-         abort();
-       }
+/* Update the spill cost arrays, considering that pseudo REG is live.  */
 
-      if (size > 1)
-       {
-         enum machine_mode other_mode, allocate_mode;
-
-         /* Count number of groups needed separately from
-            number of individual regs needed.  */
-         this_needs->groups[(int) class]++;
-         p = reg_class_superclasses[(int) class];
-         while (*p != LIM_REG_CLASSES)
-           this_needs->groups[(int) *p++]++;
-
-         /* Record size and mode of a group of this class.  */
-         /* If more than one size group is needed,
-            make all groups the largest needed size.  */
-         if (chain->group_size[(int) class] < size)
-           {
-             other_mode = chain->group_mode[(int) class];
-             allocate_mode = mode;
+static void
+count_pseudo (reg)
+     int reg;
+{
+  int n_refs = REG_N_REFS (reg);
+  int r = reg_renumber[reg];
+  int nregs;
 
-             chain->group_size[(int) class] = size;
-             chain->group_mode[(int) class] = mode;
-           }
-         else
-           {
-             other_mode = mode;
-             allocate_mode = chain->group_mode[(int) class];
-           }
+  if (REGNO_REG_SET_P (&pseudos_counted, reg)
+      || REGNO_REG_SET_P (&spilled_pseudos, reg))
+    return;
 
-         /* Crash if two dissimilar machine modes both need
-            groups of consecutive regs of the same class.  */
+  SET_REGNO_REG_SET (&pseudos_counted, reg);
 
-         if (other_mode != VOIDmode && other_mode != allocate_mode
-             && ! modes_equiv_for_class_p (allocate_mode,
-                                           other_mode, class))
-           fatal_insn ("Two dissimilar machine modes both need groups of consecutive regs of the same class",
-                       chain->insn);
-       }
-      else if (size == 1)
-       {
-         this_needs->regs[(unsigned char)rld[i].nongroup][(int) class] += 1;
-         p = reg_class_superclasses[(int) class];
-         while (*p != LIM_REG_CLASSES)
-           this_needs->regs[(unsigned char)rld[i].nongroup][(int) *p++] += 1;
-       }
-      else
-       abort ();
-    }
+  if (r < 0)
+    abort ();
 
-  /* All reloads have been counted for this insn;
-     now merge the various times of use.
-     This sets insn_needs, etc., to the maximum total number
-     of registers needed at any point in this insn.  */
+  spill_add_cost[r] += n_refs;
 
-  for (i = 0; i < N_REG_CLASSES; i++)
-    {
-      int j, in_max, out_max;
+  nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
+  while (nregs-- > 0)
+    spill_cost[r + nregs] += n_refs;
+}
 
-      /* Compute normal and nongroup needs.  */
-      for (j = 0; j <= 1; j++)
-       {
-         int k;
-         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]
-                            + 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]);
-           }
+/* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the
+   contents of BAD_SPILL_REGS for the insn described by CHAIN.  */
 
-         /* 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.  */
+static void
+order_regs_for_reload (chain)
+     struct insn_chain *chain;
+{
+  int i;
+  HARD_REG_SET used_by_pseudos;
+  HARD_REG_SET used_by_pseudos2;
 
-         in_max = MAX (MAX (insn_needs.op_addr.regs[j][i],
-                            insn_needs.op_addr_reload.regs[j][i]),
-                       in_max);
+  COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set);
 
-         out_max = MAX (out_max, insn_needs.insn.regs[j][i]);
+  memset (spill_cost, 0, sizeof spill_cost);
+  memset (spill_add_cost, 0, sizeof spill_add_cost);
 
-         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]);
+  /* Count number of uses of each hard reg by pseudo regs allocated to it
+     and then order them by decreasing use.  First exclude hard registers
+     that are live in or across this insn.  */
 
-         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]);
+  REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout);
+  REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
+  IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos);
+  IOR_HARD_REG_SET (bad_spill_regs, used_by_pseudos2);
 
-       }
+  /* Now find out which pseudos are allocated to it, and update
+     hard_reg_n_uses.  */
+  CLEAR_REG_SET (&pseudos_counted);
 
-      /* Now compute group needs.  */
-      for (in_max = 0, out_max = 0, j = 0; j < reload_n_operands; j++)
-       {
-         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]);
-       }
+  EXECUTE_IF_SET_IN_REG_SET
+    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
+     {
+       count_pseudo (i);
+     });
+  EXECUTE_IF_SET_IN_REG_SET
+    (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
+     {
+       count_pseudo (i);
+     });
+  CLEAR_REG_SET (&pseudos_counted);
+}
+\f
+/* Vector of reload-numbers showing the order in which the reloads should
+   be processed.  */
+static short reload_order[MAX_RELOADS];
 
-      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]);
+/* This is used to keep track of the spill regs used in one insn.  */
+static HARD_REG_SET used_spill_regs_local;
 
-      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]);
+/* We decided to spill hard register SPILLED, which has a size of
+   SPILLED_NREGS.  Determine how pseudo REG, which is live during the insn,
+   is affected.  We will add it to SPILLED_PSEUDOS if necessary, and we will
+   update SPILL_COST/SPILL_ADD_COST.  */
 
-      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]);
-    }
+static void
+count_spilled_pseudo (spilled, spilled_nregs, reg)
+     int spilled, spilled_nregs, reg;
+{
+  int r = reg_renumber[reg];
+  int nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
 
-  /* Record the needs for later.  */
-  chain->need = insn_needs.other;
-}
-\f
-/* Find a group of exactly 2 registers.
+  if (REGNO_REG_SET_P (&spilled_pseudos, reg)
+      || spilled + spilled_nregs <= r || r + nregs <= spilled)
+    return;
 
-   First try to fill out the group by spilling a single register which
-   would allow completion of the group.
+  SET_REGNO_REG_SET (&spilled_pseudos, reg);
 
-   Then try to create a new group from a pair of registers, neither of
-   which are explicitly used.
+  spill_add_cost[r] -= REG_N_REFS (reg);
+  while (nregs-- > 0)
+    spill_cost[r + nregs] -= REG_N_REFS (reg);
+}
 
-   Then try to create a group from any pair of registers.  */
+/* Find reload register to use for reload number ORDER.  */
 
-static void
-find_tworeg_group (chain, class, dumpfile)
+static int
+find_reg (chain, order)
      struct insn_chain *chain;
-     int class;
-     FILE *dumpfile;
+     int order;
 {
-  int i;
-  /* First, look for a register that will complete a group.  */
+  int rnum = reload_order[order];
+  struct reload *rl = rld + rnum;
+  int best_cost = INT_MAX;
+  int best_reg = -1;
+  unsigned int i, j;
+  int k;
+  HARD_REG_SET not_usable;
+  HARD_REG_SET used_by_other_reload;
+
+  COPY_HARD_REG_SET (not_usable, bad_spill_regs);
+  IOR_HARD_REG_SET (not_usable, bad_spill_regs_global);
+  IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
+
+  CLEAR_HARD_REG_SET (used_by_other_reload);
+  for (k = 0; k < order; k++)
+    {
+      int other = reload_order[k];
+
+      if (rld[other].regno >= 0 && reloads_conflict (other, rnum))
+       for (j = 0; j < rld[other].nregs; j++)
+         SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j);
+    }
+
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      int j, other;
-
-      j = potential_reload_regs[i];
-      if (j >= 0 && ! TEST_HARD_REG_BIT (bad_spill_regs, j)
-         && ((j > 0 && (other = j - 1, spill_reg_order[other] >= 0)
-              && TEST_HARD_REG_BIT (reg_class_contents[class], j)
-              && TEST_HARD_REG_BIT (reg_class_contents[class], other)
-              && HARD_REGNO_MODE_OK (other, chain->group_mode[class])
-              && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, other)
-              /* We don't want one part of another group.
-                 We could get "two groups" that overlap!  */
-              && ! TEST_HARD_REG_BIT (chain->counted_for_groups, other))
-             || (j < FIRST_PSEUDO_REGISTER - 1
-                 && (other = j + 1, spill_reg_order[other] >= 0)
-                 && TEST_HARD_REG_BIT (reg_class_contents[class], j)
-                 && TEST_HARD_REG_BIT (reg_class_contents[class], other)
-                 && HARD_REGNO_MODE_OK (j, chain->group_mode[class])
-                 && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, other)
-                 && ! TEST_HARD_REG_BIT (chain->counted_for_groups, other))))
+      unsigned int regno = i;
+
+      if (! TEST_HARD_REG_BIT (not_usable, regno)
+         && ! TEST_HARD_REG_BIT (used_by_other_reload, regno)
+         && HARD_REGNO_MODE_OK (regno, rl->mode))
        {
-         register enum reg_class *p;
+         int this_cost = spill_cost[regno];
+         int ok = 1;
+         unsigned int this_nregs = HARD_REGNO_NREGS (regno, rl->mode);
 
-         /* We have found one that will complete a group,
-            so count off one group as provided.  */
-         chain->need.groups[class]--;
-         p = reg_class_superclasses[class];
-         while (*p != LIM_REG_CLASSES)
+         for (j = 1; j < this_nregs; j++)
            {
-             if (chain->group_size [(int) *p] <= chain->group_size [class])
-               chain->need.groups[(int) *p]--;
-             p++;
+             this_cost += spill_add_cost[regno + j];
+             if ((TEST_HARD_REG_BIT (not_usable, regno + j))
+                 || TEST_HARD_REG_BIT (used_by_other_reload, regno + j))
+               ok = 0;
+           }
+         if (! ok)
+           continue;
+         if (rl->in && GET_CODE (rl->in) == REG && REGNO (rl->in) == regno)
+           this_cost--;
+         if (rl->out && GET_CODE (rl->out) == REG && REGNO (rl->out) == regno)
+           this_cost--;
+         if (this_cost < best_cost
+             /* Among registers with equal cost, prefer caller-saved ones, or
+                use REG_ALLOC_ORDER if it is defined.  */
+             || (this_cost == best_cost
+#ifdef REG_ALLOC_ORDER
+                 && (inv_reg_alloc_order[regno]
+                     < inv_reg_alloc_order[best_reg])
+#else
+                 && call_used_regs[regno]
+                 && ! call_used_regs[best_reg]
+#endif
+                 ))
+           {
+             best_reg = regno;
+             best_cost = this_cost;
            }
-
-         /* Indicate both these regs are part of a group.  */
-         SET_HARD_REG_BIT (chain->counted_for_groups, j);
-         SET_HARD_REG_BIT (chain->counted_for_groups, other);
-         break;
        }
     }
-  /* We can't complete a group, so start one.  */
-  if (i == FIRST_PSEUDO_REGISTER)
-    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-      {
-       int j, k;
-       j = potential_reload_regs[i];
-       /* Verify that J+1 is a potential reload reg.  */
-       for (k = 0; k < FIRST_PSEUDO_REGISTER; k++)
-         if (potential_reload_regs[k] == j + 1)
-           break;
-       if (j >= 0 && j + 1 < FIRST_PSEUDO_REGISTER
-           && k < FIRST_PSEUDO_REGISTER
-           && spill_reg_order[j] < 0 && spill_reg_order[j + 1] < 0
-           && TEST_HARD_REG_BIT (reg_class_contents[class], j)
-           && TEST_HARD_REG_BIT (reg_class_contents[class], j + 1)
-           && HARD_REGNO_MODE_OK (j, chain->group_mode[class])
-           && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, j + 1)
-           && ! TEST_HARD_REG_BIT (bad_spill_regs, j + 1))
-         break;
-      }
+  if (best_reg == -1)
+    return 0;
+
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Using reg %d for reload %d\n", best_reg, rnum);
+
+  rl->nregs = HARD_REGNO_NREGS (best_reg, rl->mode);
+  rl->regno = best_reg;
+
+  EXECUTE_IF_SET_IN_REG_SET
+    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
+     {
+       count_spilled_pseudo (best_reg, rl->nregs, j);
+     });
 
-  /* I should be the index in potential_reload_regs
-     of the new reload reg we have found.  */
+  EXECUTE_IF_SET_IN_REG_SET
+    (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
+     {
+       count_spilled_pseudo (best_reg, rl->nregs, j);
+     });
 
-  new_spill_reg (chain, i, class, 0, dumpfile);
+  for (i = 0; i < rl->nregs; i++)
+    {
+      if (spill_cost[best_reg + i] != 0
+         || spill_add_cost[best_reg + i] != 0)
+       abort ();
+      SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i);
+    }
+  return 1;
 }
 
-/* Find a group of more than 2 registers.
-   Look for a sufficient sequence of unspilled registers, and spill them all
-   at once.  */
+/* Find more reload regs to satisfy the remaining need of an insn, which
+   is given by CHAIN.
+   Do it by ascending class number, since otherwise a reg
+   might be spilled for a big class and might fail to count
+   for a smaller class even though it belongs to that class.  */
 
 static void
-find_group (chain, class, dumpfile)
+find_reload_regs (chain)
      struct insn_chain *chain;
-     int class;
-     FILE *dumpfile;
 {
   int i;
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  /* In order to be certain of getting the registers we need,
+     we must sort the reloads into order of increasing register class.
+     Then our grabbing of reload registers will parallel the process
+     that provided the reload registers.  */
+  for (i = 0; i < chain->n_reloads; i++)
     {
-      int j = potential_reload_regs[i];
-
-      if (j >= 0
-         && j + chain->group_size[class] <= FIRST_PSEUDO_REGISTER
-         && HARD_REGNO_MODE_OK (j, chain->group_mode[class]))
+      /* Show whether this reload already has a hard reg.  */
+      if (chain->rld[i].reg_rtx)
        {
-         int k;
-         /* Check each reg in the sequence.  */
-         for (k = 0; k < chain->group_size[class]; k++)
-           if (! (spill_reg_order[j + k] < 0
-                  && ! TEST_HARD_REG_BIT (bad_spill_regs, j + k)
-                  && TEST_HARD_REG_BIT (reg_class_contents[class], j + k)))
-             break;
-         /* We got a full sequence, so spill them all.  */
-         if (k == chain->group_size[class])
-           {
-             register enum reg_class *p;
-             for (k = 0; k < chain->group_size[class]; k++)
-               {
-                 int idx;
-                 SET_HARD_REG_BIT (chain->counted_for_groups, j + k);
-                 for (idx = 0; idx < FIRST_PSEUDO_REGISTER; idx++)
-                   if (potential_reload_regs[idx] == j + k)
-                     break;
-                 new_spill_reg (chain, idx, class, 0, dumpfile);
-               }
-
-             /* We have found one that will complete a group,
-                so count off one group as provided.  */
-             chain->need.groups[class]--;
-             p = reg_class_superclasses[class];
-             while (*p != LIM_REG_CLASSES)
-               {
-                 if (chain->group_size [(int) *p]
-                     <= chain->group_size [class])
-                   chain->need.groups[(int) *p]--;
-                 p++;
-               }
-             return;
-           }
+         int regno = REGNO (chain->rld[i].reg_rtx);
+         chain->rld[i].regno = regno;
+         chain->rld[i].nregs
+           = HARD_REGNO_NREGS (regno, GET_MODE (chain->rld[i].reg_rtx));
        }
+      else
+       chain->rld[i].regno = -1;
+      reload_order[i] = i;
     }
-  /* There are no groups left.  */
-  spill_failure (chain->insn);
-  failure = 1;
-}
 
-/* If pseudo REG conflicts with one of our reload registers, mark it as
-   spilled.  */
-static void
-maybe_mark_pseudo_spilled (reg)
-     int reg;
-{
-  int i;
-  int r = reg_renumber[reg];
-  int nregs;
-
-  if (r < 0)
-    abort ();
-  nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
-  for (i = 0; i < n_spills; i++)
-    if (r <= spill_regs[i] && r + nregs > spill_regs[i])
-      {
-       SET_REGNO_REG_SET (spilled_pseudos, reg);
-       return;
-      }
-}
-
-/* Find more reload regs to satisfy the remaining need of an insn, which
-   is given by CHAIN.
-   Do it by ascending class number, since otherwise a reg
-   might be spilled for a big class and might fail to count
-   for a smaller class even though it belongs to that class.
+  n_reloads = chain->n_reloads;
+  memcpy (rld, chain->rld, n_reloads * sizeof (struct reload));
 
-   Count spilled regs in `spills', and add entries to
-   `spill_regs' and `spill_reg_order'.
+  CLEAR_HARD_REG_SET (used_spill_regs_local);
 
-   ??? Note there is a problem here.
-   When there is a need for a group in a high-numbered class,
-   and also need for non-group regs that come from a lower class,
-   the non-group regs are chosen first.  If there aren't many regs,
-   they might leave no room for a group.
-
-   This was happening on the 386.  To fix it, we added the code
-   that calls possible_group_p, so that the lower class won't
-   break up the last possible group.
-
-   Really fixing the problem would require changes above
-   in counting the regs already spilled, and in choose_reload_regs.
-   It might be hard to avoid introducing bugs there.  */
-
-static void
-find_reload_regs (chain, dumpfile)
-     struct insn_chain *chain;
-     FILE *dumpfile;
-{
-  int i, class;
-  short *group_needs = chain->need.groups;
-  short *simple_needs = chain->need.regs[0];
-  short *nongroup_needs = chain->need.regs[1];
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
 
-  if (dumpfile)
-    fprintf (dumpfile, "Spilling for insn %d.\n", INSN_UID (chain->insn));
+  qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower);
 
-  /* Compute the order of preference for hard registers to spill.
-     Store them by decreasing preference in potential_reload_regs.  */
+  /* Compute the order of preference for hard registers to spill.  */
 
   order_regs_for_reload (chain);
 
-  /* So far, no hard regs have been spilled.  */
-  n_spills = 0;
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    spill_reg_order[i] = -1;
-
-  CLEAR_HARD_REG_SET (chain->used_spill_regs);
-  CLEAR_HARD_REG_SET (chain->counted_for_groups);
-  CLEAR_HARD_REG_SET (chain->counted_for_nongroups);
-
-  for (class = 0; class < N_REG_CLASSES; class++)
+  for (i = 0; i < n_reloads; i++)
     {
-      /* First get the groups of registers.
-        If we got single registers first, we might fragment
-        possible groups.  */
-      while (group_needs[class] > 0)
-       {
-         /* 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 (chain, class);
+      int r = reload_order[i];
 
-         if (group_needs[class] <= 0)
-           break;
-
-         /* Groups of size 2, the only groups used on most machines,
-            are treated specially.  */
-         if (chain->group_size[class] == 2)
-           find_tworeg_group (chain, class, dumpfile);
-         else
-           find_group (chain, class, dumpfile);
-         if (failure)
-           return;
-       }
-
-      /* Now similarly satisfy all need for single registers.  */
-
-      while (simple_needs[class] > 0 || nongroup_needs[class] > 0)
-       {
-         /* 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.  */
-         if (simple_needs[class] <= 0 && nongroup_needs[class] > 0)
-           for (i = 0; i < n_spills; i++)
-             {
-               int regno = spill_regs[i];
-               if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
-                   && !TEST_HARD_REG_BIT (chain->counted_for_groups, regno)
-                   && !TEST_HARD_REG_BIT (chain->counted_for_nongroups, regno)
-                   && nongroup_needs[class] > 0)
-                 {
-                   register enum reg_class *p;
-
-                   SET_HARD_REG_BIT (chain->counted_for_nongroups, regno);
-                   nongroup_needs[class]--;
-                   p = reg_class_superclasses[class];
-                   while (*p != LIM_REG_CLASSES)
-                     nongroup_needs[(int) *p++]--;
-                 }
-             }
-
-         if (simple_needs[class] <= 0 && nongroup_needs[class] <= 0)
-           break;
-
-         /* Consider the potential reload regs that aren't
-            yet in use as reload regs, in order of preference.
-            Find the most preferred one that's in this class.  */
-
-         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-           {
-             int regno = potential_reload_regs[i];
-             if (regno >= 0
-                 && TEST_HARD_REG_BIT (reg_class_contents[class], regno)
-                 /* If this reg will not be available for groups,
-                    pick one that does not foreclose possible groups.
-                    This is a kludge, and not very general,
-                    but it should be sufficient to make the 386 work,
-                    and the problem should not occur on machines with
-                    more registers.  */
-                 && (nongroup_needs[class] == 0
-                     || possible_group_p (chain, regno)))
-               break;
-           }
-
-         /* If we couldn't get a register, try to get one even if we
-            might foreclose possible groups.  This may cause problems
-            later, but that's better than aborting now, since it is
-            possible that we will, in fact, be able to form the needed
-            group even with this allocation.  */
-
-         if (i >= FIRST_PSEUDO_REGISTER
-             && asm_noperands (chain->insn) < 0)
-           for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-             if (potential_reload_regs[i] >= 0
-                 && TEST_HARD_REG_BIT (reg_class_contents[class],
-                                       potential_reload_regs[i]))
-               break;
-
-         /* I should be the index in potential_reload_regs
-            of the new reload reg we have found.  */
-
-         new_spill_reg (chain, i, class, 1, dumpfile);
-         if (failure)
+      /* Ignore reloads that got marked inoperative.  */
+      if ((rld[r].out != 0 || rld[r].in != 0 || rld[r].secondary_p)
+         && ! rld[r].optional
+         && rld[r].regno == -1)
+       if (! find_reg (chain, i))
+         {
+           spill_failure (chain->insn, rld[r].class);
+           failure = 1;
            return;
-       }
+         }
     }
 
-  /* We know which hard regs to use, now mark the pseudos that live in them
-     as needing to be kicked out.  */
-  EXECUTE_IF_SET_IN_REG_SET
-    (chain->live_before, FIRST_PSEUDO_REGISTER, i,
-     {
-       maybe_mark_pseudo_spilled (i);
-     });
-  EXECUTE_IF_SET_IN_REG_SET
-    (chain->live_after, FIRST_PSEUDO_REGISTER, i,
-     {
-       maybe_mark_pseudo_spilled (i);
-     });
+  COPY_HARD_REG_SET (chain->used_spill_regs, used_spill_regs_local);
+  IOR_HARD_REG_SET (used_spill_regs, used_spill_regs_local);
 
-  IOR_HARD_REG_SET (used_spill_regs, chain->used_spill_regs);
+  memcpy (chain->rld, rld, n_reloads * sizeof (struct reload));
 }
 
-void
-dump_needs (chain, dumpfile)
-     struct insn_chain *chain;
-     FILE *dumpfile;
+static void
+select_reload_regs ()
 {
-  static const char * const reg_class_names[] = REG_CLASS_NAMES;
-  int i;
-  struct needs *n = &chain->need;
-
-  for (i = 0; i < N_REG_CLASSES; i++)
-    {
-      if (n->regs[i][0] > 0)
-       fprintf (dumpfile,
-                ";; Need %d reg%s of class %s.\n",
-                n->regs[i][0], n->regs[i][0] == 1 ? "" : "s",
-                reg_class_names[i]);
-      if (n->regs[i][1] > 0)
-       fprintf (dumpfile,
-                ";; Need %d nongroup reg%s of class %s.\n",
-                n->regs[i][1], n->regs[i][1] == 1 ? "" : "s",
-                reg_class_names[i]);
-      if (n->groups[i] > 0)
-       fprintf (dumpfile,
-                ";; Need %d group%s (%smode) of class %s.\n",
-                n->groups[i], n->groups[i] == 1 ? "" : "s",
-                GET_MODE_NAME(chain->group_mode[i]),
-                reg_class_names[i]);
-    }
+  struct insn_chain *chain;
+
+  /* Try to satisfy the needs for each insn.  */
+  for (chain = insns_need_reload; chain != 0;
+       chain = chain->next_need_reload)
+    find_reload_regs (chain);
 }
 \f
 /* Delete all insns that were inserted by emit_caller_save_insns during
@@ -2064,250 +1880,24 @@ delete_caller_save_insns ()
     }
 }
 \f
-/* Nonzero if, after spilling reg REGNO for non-groups,
-   it will still be possible to find a group if we still need one.  */
-
-static int
-possible_group_p (chain, regno)
-     struct insn_chain *chain;
-     int regno;
-{
-  int i;
-  int class = (int) NO_REGS;
-
-  for (i = 0; i < (int) N_REG_CLASSES; i++)
-    if (chain->need.groups[i] > 0)
-      {
-       class = i;
-       break;
-      }
-
-  if (class == (int) NO_REGS)
-    return 1;
-
-  /* Consider each pair of consecutive registers.  */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER - 1; i++)
-    {
-      /* Ignore pairs that include reg REGNO.  */
-      if (i == regno || i + 1 == regno)
-       continue;
-
-      /* Ignore pairs that are outside the class that needs the group.
-        ??? Here we fail to handle the case where two different classes
-        independently need groups.  But this never happens with our
-        current machine descriptions.  */
-      if (! (TEST_HARD_REG_BIT (reg_class_contents[class], i)
-            && TEST_HARD_REG_BIT (reg_class_contents[class], i + 1)))
-       continue;
-
-      /* A pair of consecutive regs we can still spill does the trick.  */
-      if (spill_reg_order[i] < 0 && spill_reg_order[i + 1] < 0
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i)
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i + 1))
-       return 1;
-
-      /* A pair of one already spilled and one we can spill does it
-        provided the one already spilled is not otherwise reserved.  */
-      if (spill_reg_order[i] < 0
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i)
-         && spill_reg_order[i + 1] >= 0
-         && ! TEST_HARD_REG_BIT (chain->counted_for_groups, i + 1)
-         && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, i + 1))
-       return 1;
-      if (spill_reg_order[i + 1] < 0
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i + 1)
-         && spill_reg_order[i] >= 0
-         && ! TEST_HARD_REG_BIT (chain->counted_for_groups, i)
-         && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, i))
-       return 1;
-    }
-
-  return 0;
-}
-
-/* Count any groups of CLASS that can be formed from the registers recently
-   spilled.  */
-
-static void
-count_possible_groups (chain, class)
-     struct insn_chain *chain;
-     int class;
-{
-  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.  */
-
-  if (chain->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++)
-    {
-      int regno = spill_regs[i];
-
-      if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
-         && ! TEST_HARD_REG_BIT (chain->counted_for_groups, regno)
-         && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups, regno))
-       SET_HARD_REG_BIT (new, regno);
-    }
-
-  /* Find each consecutive group of them.  */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER && chain->need.groups[class] > 0; i++)
-    if (TEST_HARD_REG_BIT (new, i)
-       && i + chain->group_size[class] <= FIRST_PSEUDO_REGISTER
-       && HARD_REGNO_MODE_OK (i, chain->group_mode[class]))
-      {
-       for (j = 1; j < chain->group_size[class]; j++)
-         if (! TEST_HARD_REG_BIT (new, i + j))
-           break;
-
-       if (j == chain->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;
-
-           chain->need.groups[class]--;
-           p = reg_class_superclasses[class];
-           while (*p != LIM_REG_CLASSES)
-             {
-               if (chain->group_size [(int) *p] <= chain->group_size [class])
-                 chain->need.groups[(int) *p]--;
-               p++;
-             }
-
-           /* Don't count these registers again.  */
-           for (j = 0; j < chain->group_size[class]; j++)
-             SET_HARD_REG_BIT (chain->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
-   another mode that needs to be reloaded for the same register class CLASS.
-   If any reg in CLASS allows ALLOCATE_MODE but not OTHER_MODE, fail.
-   ALLOCATE_MODE will never be smaller than OTHER_MODE.
-
-   This code used to also fail if any reg in CLASS allows OTHER_MODE but not
-   ALLOCATE_MODE.  This test is unnecessary, because we will never try to put
-   something of mode ALLOCATE_MODE into an OTHER_MODE register.  Testing this
-   causes unnecessary failures on machines requiring alignment of register
-   groups when the two modes are different sizes, because the larger mode has
-   more strict alignment rules than the smaller mode.  */
-
-static int
-modes_equiv_for_class_p (allocate_mode, other_mode, class)
-     enum machine_mode allocate_mode, other_mode;
-     enum reg_class class;
-{
-  register int regno;
-  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-    {
-      if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
-         && HARD_REGNO_MODE_OK (regno, allocate_mode)
-         && ! HARD_REGNO_MODE_OK (regno, other_mode))
-       return 0;
-    }
-  return 1;
-}
-\f
 /* Handle the failure to find a register to spill.
    INSN should be one of the insns which needed this particular spill reg.  */
 
 static void
-spill_failure (insn)
+spill_failure (insn, class)
      rtx insn;
+     enum reg_class class;
 {
+  static const char *const reg_class_names[] = REG_CLASS_NAMES;
   if (asm_noperands (PATTERN (insn)) >= 0)
-    error_for_asm (insn, "`asm' needs too many reloads");
+    error_for_asm (insn, "Can't find a register in class `%s' while reloading `asm'.",
+                  reg_class_names[class]);
   else
-    fatal_insn ("Unable to find a register to spill.", insn);
-}
-
-/* Add a new register to the tables of available spill-registers.
-   CHAIN is the insn for which the register will be used; we decrease the
-   needs of that insn.
-   I is the index of this register in potential_reload_regs.
-   CLASS is the regclass whose need is being satisfied.
-   NONGROUP is 0 if this register is part of a group.
-   DUMPFILE is the same as the one that `reload' got.  */
-
-static void
-new_spill_reg (chain, i, class, nongroup, dumpfile)
-     struct insn_chain *chain;
-     int i;
-     int class;
-     int nongroup;
-     FILE *dumpfile;
-{
-  register enum reg_class *p;
-  int regno = potential_reload_regs[i];
-
-  if (i >= FIRST_PSEUDO_REGISTER)
-    {
-      spill_failure (chain->insn);
-      failure = 1;
-      return;
-    }
-
-  if (TEST_HARD_REG_BIT (bad_spill_regs, regno))
-    {
-      static const char * const reg_class_names[] = REG_CLASS_NAMES;
-
-      if (asm_noperands (PATTERN (chain->insn)) < 0)
-       {
-         /* The error message is still correct - we know only that it wasn't
-            an asm statement that caused the problem, but one of the global
-            registers declared by the users might have screwed us.  */
-         error ("fixed or forbidden register %d (%s) was spilled for class %s.",
-                regno, reg_names[regno], reg_class_names[class]);
-         error ("This may be due to a compiler bug or to impossible asm");
-         error ("statements or clauses.");
-         fatal_insn ("This is the instruction:", chain->insn);
-       }
-      error_for_asm (chain->insn, "Invalid `asm' statement:");
-      error_for_asm (chain->insn,
-                    "fixed or forbidden register %d (%s) was spilled for class %s.",
-                    regno, reg_names[regno], reg_class_names[class]);
-      failure = 1;
-      return;
-    }
-
-  /* Make reg REGNO an additional reload reg.  */
-
-  potential_reload_regs[i] = -1;
-  spill_regs[n_spills] = regno;
-  spill_reg_order[regno] = n_spills;
-  if (dumpfile)
-    fprintf (dumpfile, "Spilling reg %d.\n", regno);
-  SET_HARD_REG_BIT (chain->used_spill_regs, regno);
-
-  /* Clear off the needs we just satisfied.  */
-
-  chain->need.regs[0][class]--;
-  p = reg_class_superclasses[class];
-  while (*p != LIM_REG_CLASSES)
-    chain->need.regs[0][(int) *p++]--;
-
-  if (nongroup && chain->need.regs[1][class] > 0)
     {
-      SET_HARD_REG_BIT (chain->counted_for_nongroups, regno);
-      chain->need.regs[1][class]--;
-      p = reg_class_superclasses[class];
-      while (*p != LIM_REG_CLASSES)
-       chain->need.regs[1][(int) *p++]--;
+      error ("Unable to find a register to spill in class `%s'.",
+            reg_class_names[class]);
+      fatal_insn ("This is the insn:", insn);
     }
-
-  n_spills++;
 }
 \f
 /* Delete an unneeded INSN and any previous insns who sole purpose is loading
@@ -2371,8 +1961,8 @@ alter_reg (i, from_reg)
       && reg_equiv_memory_loc[i] == 0)
     {
       register rtx x;
-      int inherent_size = PSEUDO_REGNO_BYTES (i);
-      int total_size = MAX (inherent_size, reg_max_ref_width[i]);
+      unsigned int inherent_size = PSEUDO_REGNO_BYTES (i);
+      unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
       int adjust = 0;
 
       /* Each pseudo reg has an inherent size which comes from its own mode,
@@ -2396,13 +1986,18 @@ alter_reg (i, from_reg)
            adjust = inherent_size - total_size;
 
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
+
+         /* Nothing can alias this slot except this pseudo.  */
+         MEM_ALIAS_SET (x) = new_alias_set ();
        }
+
       /* Reuse a stack slot if possible.  */
       else if (spill_stack_slot[from_reg] != 0
               && spill_stack_slot_width[from_reg] >= total_size
               && (GET_MODE_SIZE (GET_MODE (spill_stack_slot[from_reg]))
                   >= inherent_size))
        x = spill_stack_slot[from_reg];
+
       /* Allocate a bigger slot.  */
       else
        {
@@ -2410,6 +2005,7 @@ alter_reg (i, from_reg)
             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]))
@@ -2418,10 +2014,18 @@ alter_reg (i, from_reg)
              if (spill_stack_slot_width[from_reg] > total_size)
                total_size = spill_stack_slot_width[from_reg];
            }
+
          /* Make a slot with that size.  */
          x = assign_stack_local (mode, total_size,
                                  inherent_size == total_size ? 0 : -1);
          stack_slot = x;
+
+         /* All pseudos mapped to this slot can alias each other.  */
+         if (spill_stack_slot[from_reg])
+           MEM_ALIAS_SET (x) = MEM_ALIAS_SET (spill_stack_slot[from_reg]);
+         else
+           MEM_ALIAS_SET (x) = new_alias_set ();
+
          if (BYTES_BIG_ENDIAN)
            {
              /* Cancel the  big-endian correction done in assign_stack_local.
@@ -2435,6 +2039,7 @@ alter_reg (i, from_reg)
                                                         MODE_INT, 1),
                                          plus_constant (XEXP (x, 0), adjust));
            }
+
          spill_stack_slot[from_reg] = stack_slot;
          spill_stack_slot_width[from_reg] = total_size;
        }
@@ -2448,16 +2053,11 @@ alter_reg (i, from_reg)
         wrong mode, make a new stack slot.  */
       if (adjust != 0 || GET_MODE (x) != GET_MODE (regno_reg_rtx[i]))
        {
-         x = gen_rtx_MEM (GET_MODE (regno_reg_rtx[i]),
-                          plus_constant (XEXP (x, 0), adjust));
-
-         /* If this was shared among registers, must ensure we never
-            set it readonly since that can cause scheduling
-            problems.  Note we would only have in this adjustment
-            case in any event, since the code above doesn't set it.  */
+         rtx new = gen_rtx_MEM (GET_MODE (regno_reg_rtx[i]),
+                                plus_constant (XEXP (x, 0), adjust));
 
-         if (from_reg == -1)
-           RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
+         MEM_COPY_ATTRIBUTES (new, x);
+         x = new;
        }
 
       /* Save the stack slot for later.   */
@@ -2473,6 +2073,7 @@ mark_home_live (regno)
      int regno;
 {
   register int i, lim;
+
   i = reg_renumber[regno];
   if (i < 0)
     return;
@@ -2564,11 +2165,12 @@ set_label_offsets (x, insn, initial_p)
          set_label_offsets (XEXP (tem, 0), insn, 1);
       return;
 
+    case PARALLEL:
     case ADDR_VEC:
     case ADDR_DIFF_VEC:
-      /* Each of the labels in the address vector must be at their initial
-        offsets.  We want the first field for ADDR_VEC and the second
-        field for ADDR_DIFF_VEC.  */
+      /* Each of the labels in the parallel or address vector must be
+        at their initial offsets.  We want the first field for PARALLEL
+        and ADDR_VEC and the second field for ADDR_DIFF_VEC.  */
 
       for (i = 0; i < (unsigned) XVECLEN (x, code == ADDR_DIFF_VEC); i++)
        set_label_offsets (XVECEXP (x, code == ADDR_DIFF_VEC, i),
@@ -2908,7 +2510,7 @@ eliminate_regs (x, mem_mode, insn)
       return x;
 
     case SUBREG:
-      /* Similar to above processing, but preserve SUBREG_WORD.
+      /* Similar to above processing, but preserve SUBREG_BYTE.
         Convert (subreg (mem)) to (mem) if not paradoxical.
         Also, if we have a non-paradoxical (subreg (pseudo)) and the
         pseudo didn't get a hard reg, we must replace this with the
@@ -2925,7 +2527,7 @@ eliminate_regs (x, mem_mode, insn)
       else
        new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
 
-      if (new != XEXP (x, 0))
+      if (new != SUBREG_REG (x))
        {
          int x_size = GET_MODE_SIZE (GET_MODE (x));
          int new_size = GET_MODE_SIZE (GET_MODE (new));
@@ -2946,20 +2548,15 @@ eliminate_regs (x, mem_mode, insn)
                  || (x_size == new_size))
              )
            {
-             int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+             int offset = SUBREG_BYTE (x);
              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)));
-
              PUT_MODE (new, mode);
              XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
              return new;
            }
          else
-           return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_WORD (x));
+           return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x));
        }
 
       return x;
@@ -2978,15 +2575,19 @@ eliminate_regs (x, mem_mode, insn)
       if (new != XEXP (x, 0))
        {
          new = gen_rtx_MEM (GET_MODE (x), new);
-         new->volatil = x->volatil;
-         new->unchanging = x->unchanging;
-         new->in_struct = x->in_struct;
+         MEM_COPY_ATTRIBUTES (new, x);
          return new;
        }
       else
        return x;
 
     case USE:
+      /* Handle insn_list USE that a call to a pure function may generate.  */
+      new = eliminate_regs (XEXP (x, 0), 0, insn);
+      if (new != XEXP (x, 0))
+       return gen_rtx_USE (GET_MODE (x), new);
+      return x;
+
     case CLOBBER:
     case ASM_OPERANDS:
     case SET:
@@ -3007,9 +2608,9 @@ eliminate_regs (x, mem_mode, insn)
          if (new != XEXP (x, i) && ! copied)
            {
              rtx new_x = rtx_alloc (code);
-             bcopy ((char *) x, (char *) new_x,
-                    (sizeof (*new_x) - sizeof (new_x->fld)
-                     + sizeof (new_x->fld[0]) * GET_RTX_LENGTH (code)));
+             memcpy (new_x, x,
+                     (sizeof (*new_x) - sizeof (new_x->fld)
+                      + sizeof (new_x->fld[0]) * GET_RTX_LENGTH (code)));
              x = new_x;
              copied = 1;
            }
@@ -3028,10 +2629,10 @@ eliminate_regs (x, mem_mode, insn)
                  if (! copied)
                    {
                      rtx new_x = rtx_alloc (code);
-                     bcopy ((char *) x, (char *) new_x,
-                            (sizeof (*new_x) - sizeof (new_x->fld)
-                             + (sizeof (new_x->fld[0])
-                                * GET_RTX_LENGTH (code))));
+                     memcpy (new_x, x,
+                             (sizeof (*new_x) - sizeof (new_x->fld)
+                              + (sizeof (new_x->fld[0])
+                                 * GET_RTX_LENGTH (code))));
                      x = new_x;
                      copied = 1;
                    }
@@ -3107,6 +2708,8 @@ elimination_effects (x, mem_mode)
     case POST_INC:
     case PRE_DEC:
     case POST_DEC:
+    case POST_MODIFY:
+    case PRE_MODIFY:
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
        if (ep->to_rtx == XEXP (x, 0))
          {
@@ -3119,10 +2722,19 @@ elimination_effects (x, mem_mode)
 #endif
            if (code == PRE_DEC || code == POST_DEC)
              ep->offset += size;
-           else
+           else if (code == PRE_INC || code == POST_INC)
              ep->offset -= size;
+           else if ((code == PRE_MODIFY || code == POST_MODIFY)
+                    && GET_CODE (XEXP (x, 1)) == PLUS
+                    && XEXP (x, 0) == XEXP (XEXP (x, 1), 0)
+                    && CONSTANT_P (XEXP (XEXP (x, 1), 1)))
+             ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1));
          }
 
+      /* These two aren't unary operators.  */
+      if (code == POST_MODIFY || code == PRE_MODIFY)
+       break;
+
       /* Fall through to generic unary operation case.  */
     case STRICT_LOW_PART:
     case NEG:          case NOT:
@@ -3233,6 +2845,7 @@ elimination_effects (x, mem_mode)
 /* Descend through rtx X and verify that no references to eliminable registers
    remain.  If any do remain, mark the involved register as not
    eliminable.  */
+
 static void
 check_eliminable_occurrences (x)
      rtx x;
@@ -3243,7 +2856,7 @@ check_eliminable_occurrences (x)
 
   if (x == 0)
     return;
-  
+
   code = GET_CODE (x);
 
   if (code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
@@ -3255,7 +2868,7 @@ check_eliminable_occurrences (x)
          ep->can_eliminate = 0;
       return;
     }
-  
+
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
     {
@@ -3310,9 +2923,6 @@ eliminate_regs_in_insn (insn, replace)
       abort ();
     }
 
-  if (! replace)
-    push_obstacks (&reload_obstack, &reload_obstack);
-
   if (old_set != 0 && GET_CODE (SET_DEST (old_set)) == REG
       && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER)
     {
@@ -3394,47 +3004,75 @@ eliminate_regs_in_insn (insn, replace)
               process it since it won't be used unless something changes.  */
            if (replace)
              {
-               delete_dead_insn (insn);
+               delete_dead_insn (insn);
                return 1;
              }
            val = 1;
            goto done;
          }
+    }
 
-      /* Check for (set (reg) (plus (reg from) (offset))) where the offset
-        in the insn is the negative of the offset in FROM.  Substitute
-        (set (reg) (reg to)) for the insn and change its code.
+  /* We allow one special case which happens to work on all machines we
+     currently support: a single set with the source being a PLUS of an
+     eliminable register and a constant.  */
+  if (old_set
+      && GET_CODE (SET_DEST (old_set)) == REG
+      && 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
+      && REGNO (XEXP (SET_SRC (old_set), 0)) < FIRST_PSEUDO_REGISTER)
+    {
+      rtx reg = XEXP (SET_SRC (old_set), 0);
+      int offset = INTVAL (XEXP (SET_SRC (old_set), 1));
 
-        We have to do this here, rather than in eliminate_regs, so that we can
-        change the insn code.  */
+      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+       if (ep->from_rtx == reg && ep->can_eliminate)
+         {
+           offset += ep->offset;
 
-      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_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_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_set),
-                                               ep->to_rtx);
-                 INSN_CODE (insn) = -1;
-                 val = 1;
-                 goto done;
-               }
+           if (offset == 0)
+             {
+               int num_clobbers;
+               /* We assume here that if we need a PARALLEL with
+                  CLOBBERs for this assignment, we can do with the
+                  MATCH_SCRATCHes that add_clobbers allocates.
+                  There's not much we can do if that doesn't work.  */
+               PATTERN (insn) = gen_rtx_SET (VOIDmode,
+                                             SET_DEST (old_set),
+                                             ep->to_rtx);
+               num_clobbers = 0;
+               INSN_CODE (insn) = recog (PATTERN (insn), insn, &num_clobbers);
+               if (num_clobbers)
+                 {
+                   rtvec vec = rtvec_alloc (num_clobbers + 1);
 
-             break;
-           }
+                   vec->elem[0] = PATTERN (insn);
+                   PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec);
+                   add_clobbers (PATTERN (insn), INSN_CODE (insn));
+                 }
+               if (INSN_CODE (insn) < 0)
+                 abort ();
+             }
+           else
+             {
+               new_body = old_body;
+               if (! replace)
+                 {
+                   new_body = copy_insn (old_body);
+                   if (REG_NOTES (insn))
+                     REG_NOTES (insn) = copy_insn_1 (REG_NOTES (insn));
+                 }
+               PATTERN (insn) = new_body;
+               old_set = single_set (insn);
+
+               XEXP (SET_SRC (old_set), 0) = ep->to_rtx;
+               XEXP (SET_SRC (old_set), 1) = GEN_INT (offset);
+             }
+           val = 1;
+           /* This can't have an effect on elimination offsets, so skip right
+              to the end.  */
+           goto done;
+         }
     }
 
   /* Determine the effects of this insn on elimination offsets.  */
@@ -3487,7 +3125,7 @@ eliminate_regs_in_insn (insn, replace)
 
   for (i = 0; i < recog_data.n_dups; i++)
     *recog_data.dup_loc[i]
-       = *recog_data.operand_loc[(int)recog_data.dup_num[i]];
+      = *recog_data.operand_loc[(int) recog_data.dup_num[i]];
 
   /* If any eliminable remain, they aren't eliminable anymore.  */
   check_eliminable_occurrences (old_body);
@@ -3497,7 +3135,7 @@ eliminate_regs_in_insn (insn, replace)
   for (i = 0; i < recog_data.n_operands; i++)
     *recog_data.operand_loc[i] = substed_operand[i];
   for (i = 0; i < recog_data.n_dups; i++)
-    *recog_data.dup_loc[i] = substed_operand[(int)recog_data.dup_num[i]];
+    *recog_data.dup_loc[i] = substed_operand[(int) recog_data.dup_num[i]];
 
   /* 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
@@ -3506,7 +3144,7 @@ eliminate_regs_in_insn (insn, replace)
      If re-recognition fails, the old insn code number will still be used,
      and some register operands may have changed into PLUS expressions.
      These will be handled by find_reloads by loading them into a register
-     again.*/
+     again.  */
 
   if (val)
     {
@@ -3561,7 +3199,7 @@ eliminate_regs_in_insn (insn, replace)
       for (i = 0; i < recog_data.n_operands; i++)
        *recog_data.operand_loc[i] = orig_operand[i];
       for (i = 0; i < recog_data.n_dups; i++)
-       *recog_data.dup_loc[i] = orig_operand[(int)recog_data.dup_num[i]];
+       *recog_data.dup_loc[i] = orig_operand[(int) recog_data.dup_num[i]];
     }
 
   /* Update all elimination pairs to reflect the status after the current
@@ -3597,9 +3235,6 @@ eliminate_regs_in_insn (insn, replace)
   if (val && REG_NOTES (insn) != 0)
     REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn));
 
-  if (! replace)
-    pop_obstacks ();
-
   return val;
 }
 
@@ -3671,6 +3306,7 @@ mark_not_eliminable (dest, x, data)
    last call to set_initial_elim_offsets.  This is used to catch cases
    where something illegal happened during reload_as_needed that could
    cause incorrect code to be generated if we did not check for it.  */
+
 static void
 verify_initial_elim_offsets ()
 {
@@ -3693,6 +3329,7 @@ verify_initial_elim_offsets ()
 }
 
 /* Reset all offsets on eliminable registers to their initial values.  */
+
 static void
 set_initial_elim_offsets ()
 {
@@ -3723,7 +3360,7 @@ static void
 set_initial_label_offsets ()
 {
   rtx x;
-  bzero ((char *) &offsets_known_at[get_first_label_num ()], num_labels);
+  memset ((char *) &offsets_known_at[get_first_label_num ()], 0, num_labels);
 
   for (x = forced_labels; x; x = XEXP (x, 1))
     if (XEXP (x, 0))
@@ -3732,6 +3369,7 @@ set_initial_label_offsets ()
 
 /* Set all elimination offsets to the known values for the code label given
    by INSN.  */
+
 static void
 set_offsets_for_label (insn)
      rtx insn;
@@ -3835,6 +3473,7 @@ update_eliminables (pset)
 }
 
 /* Initialize the table of registers to eliminate.  */
+
 static void
 init_elim_table ()
 {
@@ -3845,7 +3484,7 @@ init_elim_table ()
 
   if (!reg_eliminate)
     reg_eliminate = (struct elim_table *)
-      xcalloc(sizeof(struct elim_table), NUM_ELIMINABLE_REGS);
+      xcalloc (sizeof (struct elim_table), NUM_ELIMINABLE_REGS);
 
   /* Does this function require a frame pointer?  */
 
@@ -3893,7 +3532,6 @@ init_elim_table ()
 }
 \f
 /* Kick all pseudos out of hard register REGNO.
-   If DUMPFILE is nonzero, log actions taken on that file.
 
    If CANT_ELIMINATE is nonzero, it means that we are doing this spill
    because we found we can't eliminate some register.  In the case, no pseudos
@@ -3904,9 +3542,8 @@ init_elim_table ()
    Return nonzero if any pseudos needed to be kicked out.  */
 
 static void
-spill_hard_reg (regno, dumpfile, cant_eliminate)
-     register int regno;
-     FILE *dumpfile ATTRIBUTE_UNUSED;
+spill_hard_reg (regno, cant_eliminate)
+     unsigned int regno;
      int cant_eliminate;
 {
   register int i;
@@ -3922,16 +3559,17 @@ spill_hard_reg (regno, dumpfile, cant_eliminate)
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     if (reg_renumber[i] >= 0
-       && reg_renumber[i] <= regno
-       && (reg_renumber[i]
-           + HARD_REGNO_NREGS (reg_renumber[i],
+       && (unsigned int) reg_renumber[i] <= regno
+       && ((unsigned int) reg_renumber[i]
+           + HARD_REGNO_NREGS ((unsigned int) reg_renumber[i],
                                PSEUDO_REGNO_MODE (i))
            > regno))
-      SET_REGNO_REG_SET (spilled_pseudos, i);
+      SET_REGNO_REG_SET (&spilled_pseudos, i);
 }
 
 /* I'm getting weird preprocessor errors if I use IOR_HARD_REG_SET
    from within EXECUTE_IF_SET_IN_REG_SET.  Hence this awkwardness.  */
+
 static void
 ior_hard_reg_set (set1, set2)
      HARD_REG_SET *set1, *set2;
@@ -3945,9 +3583,8 @@ ior_hard_reg_set (set1, set2)
    spill_regs array for use by choose_reload_regs.  */
 
 static int
-finish_spills (global, dumpfile)
+finish_spills (global)
      int global;
-     FILE *dumpfile;
 {
   struct insn_chain *chain;
   int something_changed = 0;
@@ -3978,38 +3615,39 @@ finish_spills (global, dumpfile)
     else
       spill_reg_order[i] = -1;
 
-  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (REGNO_REG_SET_P (spilled_pseudos, i))
-      {
-       /* Record the current hard register the pseudo is allocated to in
-          pseudo_previous_regs so we avoid reallocating it to the same
-          hard reg in a later pass.  */
-       if (reg_renumber[i] < 0)
-         abort ();
-       SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
-       /* Mark it as no longer having a hard register home.  */
-       reg_renumber[i] = -1;
-       /* We will need to scan everything again.  */
-       something_changed = 1;
-      }
+  EXECUTE_IF_SET_IN_REG_SET
+    (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i,
+     {
+       /* Record the current hard register the pseudo is allocated to in
+         pseudo_previous_regs so we avoid reallocating it to the same
+         hard reg in a later pass.  */
+       if (reg_renumber[i] < 0)
+        abort ();
+
+       SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]);
+       /* Mark it as no longer having a hard register home.  */
+       reg_renumber[i] = -1;
+       /* We will need to scan everything again.  */
+       something_changed = 1;
+     });
 
   /* Retry global register allocation if possible.  */
   if (global)
     {
-      bzero ((char *) pseudo_forbidden_regs, max_regno * sizeof (HARD_REG_SET));
+      memset ((char *) pseudo_forbidden_regs, 0, max_regno * sizeof (HARD_REG_SET));
       /* For every insn that needs reloads, set the registers used as spill
         regs in pseudo_forbidden_regs for every pseudo live across the
         insn.  */
       for (chain = insns_need_reload; chain; chain = chain->next_need_reload)
        {
          EXECUTE_IF_SET_IN_REG_SET
-           (chain->live_before, FIRST_PSEUDO_REGISTER, i,
+           (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
             {
               ior_hard_reg_set (pseudo_forbidden_regs + i,
                                 &chain->used_spill_regs);
             });
          EXECUTE_IF_SET_IN_REG_SET
-           (chain->live_after, FIRST_PSEUDO_REGISTER, i,
+           (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
             {
               ior_hard_reg_set (pseudo_forbidden_regs + i,
                                 &chain->used_spill_regs);
@@ -4030,7 +3668,7 @@ finish_spills (global, dumpfile)
            IOR_HARD_REG_SET (forbidden, pseudo_previous_regs[i]);
            retry_global_alloc (i, forbidden);
            if (reg_renumber[i] >= 0)
-             CLEAR_REGNO_REG_SET (spilled_pseudos, i);
+             CLEAR_REGNO_REG_SET (&spilled_pseudos, i);
          }
     }
 
@@ -4042,22 +3680,22 @@ finish_spills (global, dumpfile)
       HARD_REG_SET used_by_pseudos;
       HARD_REG_SET used_by_pseudos2;
 
-      AND_COMPL_REG_SET (chain->live_before, spilled_pseudos);
-      AND_COMPL_REG_SET (chain->live_after, spilled_pseudos);
+      AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos);
+      AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos);
 
       /* Mark any unallocated hard regs as available for spills.  That
         makes inheritance work somewhat better.  */
       if (chain->need_reload)
        {
-         REG_SET_TO_HARD_REG_SET (used_by_pseudos, chain->live_before);
-         REG_SET_TO_HARD_REG_SET (used_by_pseudos2, chain->live_after);
+         REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout);
+         REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set);
          IOR_HARD_REG_SET (used_by_pseudos, used_by_pseudos2);
 
          /* Save the old value for the sanity test below.  */
          COPY_HARD_REG_SET (used_by_pseudos2, chain->used_spill_regs);
 
-         compute_use_by_pseudos (&used_by_pseudos, chain->live_before);
-         compute_use_by_pseudos (&used_by_pseudos, chain->live_after);
+         compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout);
+         compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set);
          COMPL_HARD_REG_SET (chain->used_spill_regs, used_by_pseudos);
          AND_HARD_REG_SET (chain->used_spill_regs, used_spill_regs);
 
@@ -4077,12 +3715,12 @@ finish_spills (global, dumpfile)
 
       alter_reg (i, reg_old_renumber[i]);
       reg_old_renumber[i] = regno;
-      if (dumpfile)
+      if (rtl_dump_file)
        {
          if (regno == -1)
-           fprintf (dumpfile, " Register %d now on stack.\n\n", i);
+           fprintf (rtl_dump_file, " Register %d now on stack.\n\n", i);
          else
-           fprintf (dumpfile, " Register %d now in %d.\n\n",
+           fprintf (rtl_dump_file, " Register %d now in %d.\n\n",
                     i, reg_renumber[i]);
        }
     }
@@ -4142,179 +3780,38 @@ scan_paradoxical_subregs (x)
       else if (fmt[i] == 'E')
        {
          register int j;
-         for (j = XVECLEN (x, i) - 1; j >=0; j--)
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            scan_paradoxical_subregs (XVECEXP (x, i, j));
        }
     }
 }
 \f
-static int
-hard_reg_use_compare (p1p, p2p)
-     const PTR p1p;
-     const PTR p2p;
-{
-  const struct hard_reg_n_uses *p1 = (const struct hard_reg_n_uses *)p1p;
-  const struct hard_reg_n_uses *p2 = (const struct hard_reg_n_uses *)p2p;
-  int bad1 = TEST_HARD_REG_BIT (bad_spill_regs, p1->regno);
-  int bad2 = TEST_HARD_REG_BIT (bad_spill_regs, p2->regno);
-  if (bad1 && bad2)
-    return p1->regno - p2->regno;
-  if (bad1)
-    return 1;
-  if (bad2)
-    return -1;
-  if (p1->uses > p2->uses)
-    return 1;
-  if (p1->uses < p2->uses)
-    return -1;
-  /* If regs are equally good, sort by regno,
-     so that the results of qsort leave nothing to chance.  */
-  return p1->regno - p2->regno;
-}
+/* 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.
 
-/* Used for communication between order_regs_for_reload and count_pseudo.
-   Used to avoid counting one pseudo twice.  */
-static regset pseudos_counted;
+   reg_last_reload_reg and reg_reloaded_contents keep track of
+   which registers are already available in reload registers.
+   We update these for the reloads that we perform,
+   as the insns are scanned.  */
 
-/* Update the costs in N_USES, considering that pseudo REG is live.  */
 static void
-count_pseudo (n_uses, reg)
-     struct hard_reg_n_uses *n_uses;
-     int reg;
+reload_as_needed (live_known)
+     int live_known;
 {
-  int r = reg_renumber[reg];
-  int nregs;
-
-  if (REGNO_REG_SET_P (pseudos_counted, reg))
-    return;
-  SET_REGNO_REG_SET (pseudos_counted, reg);
+  struct insn_chain *chain;
+#if defined (AUTO_INC_DEC)
+  register int i;
+#endif
+  rtx x;
 
-  if (r < 0)
-    abort ();
+  memset ((char *) spill_reg_rtx, 0, sizeof spill_reg_rtx);
+  memset ((char *) spill_reg_store, 0, sizeof spill_reg_store);
+  reg_last_reload_reg = (rtx *) xcalloc (max_regno, sizeof (rtx));
+  reg_has_output_reload = (char *) xmalloc (max_regno);
+  CLEAR_HARD_REG_SET (reg_reloaded_valid);
 
-  nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
-  while (nregs-- > 0)
-    n_uses[r++].uses += REG_N_REFS (reg);
-}
-/* Choose the order to consider regs for use as reload registers
-   based on how much trouble would be caused by spilling one.
-   Store them in order of decreasing preference in potential_reload_regs.  */
-
-static void
-order_regs_for_reload (chain)
-     struct insn_chain *chain;
-{
-  register int i;
-  register int o = 0;
-  struct hard_reg_n_uses hard_reg_n_uses[FIRST_PSEUDO_REGISTER];
-
-  pseudos_counted = ALLOCA_REG_SET ();
-
-  COPY_HARD_REG_SET (bad_spill_regs, bad_spill_regs_global);
-
-  /* Count number of uses of each hard reg by pseudo regs allocated to it
-     and then order them by decreasing use.  */
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      hard_reg_n_uses[i].regno = i;
-      hard_reg_n_uses[i].uses = 0;
-
-      /* Test the various reasons why we can't use a register for
-        spilling in this insn.  */
-      if (fixed_regs[i]
-         || REGNO_REG_SET_P (chain->live_before, i)
-         || REGNO_REG_SET_P (chain->live_after, i))
-       SET_HARD_REG_BIT (bad_spill_regs, i);
-    }
-
-  /* Now compute hard_reg_n_uses.  */
-  CLEAR_REG_SET (pseudos_counted);
-
-  EXECUTE_IF_SET_IN_REG_SET
-    (chain->live_before, FIRST_PSEUDO_REGISTER, i,
-     {
-       count_pseudo (hard_reg_n_uses, i);
-     });
-  EXECUTE_IF_SET_IN_REG_SET
-    (chain->live_after, FIRST_PSEUDO_REGISTER, i,
-     {
-       count_pseudo (hard_reg_n_uses, i);
-     });
-
-  FREE_REG_SET (pseudos_counted);
-
-  /* Prefer registers not so far used, for use in temporary loading.
-     Among them, if REG_ALLOC_ORDER is defined, use that order.
-     Otherwise, prefer registers not preserved by calls.  */
-
-#ifdef REG_ALLOC_ORDER
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      int regno = reg_alloc_order[i];
-
-      if (hard_reg_n_uses[regno].uses == 0
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, regno))
-       potential_reload_regs[o++] = regno;
-    }
-#else
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      if (hard_reg_n_uses[i].uses == 0 && call_used_regs[i]
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i))
-       potential_reload_regs[o++] = i;
-    }
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      if (hard_reg_n_uses[i].uses == 0 && ! call_used_regs[i]
-         && ! TEST_HARD_REG_BIT (bad_spill_regs, i))
-       potential_reload_regs[o++] = i;
-    }
-#endif
-
-  qsort (hard_reg_n_uses, FIRST_PSEUDO_REGISTER,
-        sizeof hard_reg_n_uses[0], hard_reg_use_compare);
-
-  /* Now add the regs that are already used,
-     preferring those used less often.  The fixed and otherwise forbidden
-     registers will be at the end of this list.  */
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (hard_reg_n_uses[i].uses != 0
-       && ! TEST_HARD_REG_BIT (bad_spill_regs, hard_reg_n_uses[i].regno))
-      potential_reload_regs[o++] = hard_reg_n_uses[i].regno;
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (TEST_HARD_REG_BIT (bad_spill_regs, hard_reg_n_uses[i].regno))
-      potential_reload_regs[o++] = hard_reg_n_uses[i].regno;
-}
-\f
-/* 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.
-
-   reg_last_reload_reg and reg_reloaded_contents keep track of
-   which registers are already available in reload registers.
-   We update these for the reloads that we perform,
-   as the insns are scanned.  */
-
-static void
-reload_as_needed (live_known)
-     int live_known;
-{
-  struct insn_chain *chain;
-#if defined (AUTO_INC_DEC) || defined (INSN_CLOBBERS_REGNO_P)
-  register int i;
-#endif
-  rtx x;
-
-  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 ((char *) reg_last_reload_reg, max_regno * sizeof (rtx));
-  reg_has_output_reload = (char *) alloca (max_regno);
-  CLEAR_HARD_REG_SET (reg_reloaded_valid);
-
-  set_initial_elim_offsets ();
+  set_initial_elim_offsets ();
 
   for (chain = reload_insn_chain; chain; chain = chain->next)
     {
@@ -4327,7 +3824,7 @@ reload_as_needed (live_known)
       if (GET_CODE (insn) == CODE_LABEL)
        set_offsets_for_label (insn);
 
-      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      else if (INSN_P (insn))
        {
          rtx oldpat = PATTERN (insn);
 
@@ -4370,7 +3867,7 @@ reload_as_needed (live_known)
             rtx's for those pseudo regs.  */
          else
            {
-             bzero (reg_has_output_reload, max_regno);
+             memset (reg_has_output_reload, 0, max_regno);
              CLEAR_HARD_REG_SET (reg_is_output_reload);
 
              find_reloads (insn, 1, spill_indirect_levels, live_known,
@@ -4407,7 +3904,7 @@ reload_as_needed (live_known)
                 into the insn's body (or perhaps into the bodies of other
                 load and store insn that we just made for reloading
                 and that we moved the structure into).  */
-             subst_reloads ();
+             subst_reloads (insn);
 
              /* If this was an ASM, make sure that all the reload insns
                 we have generated are valid.  If not, give an error
@@ -4415,7 +3912,7 @@ reload_as_needed (live_known)
 
              if (asm_noperands (PATTERN (insn)) >= 0)
                for (p = NEXT_INSN (prev); p != next; p = NEXT_INSN (p))
-                 if (p != insn && GET_RTX_CLASS (GET_CODE (p)) == 'i'
+                 if (p != insn && INSN_P (p)
                      && (recog_memoized (p) < 0
                          || (extract_insn (p), ! constrain_operands (1))))
                    {
@@ -4476,7 +3973,7 @@ reload_as_needed (live_known)
                             use PATTERN (p) as argument to reg_set_p .  */
                          if (reg_set_p (reload_reg, PATTERN (p)))
                            break;
-                         n = count_occurrences (PATTERN (p), reload_reg);
+                         n = count_occurrences (PATTERN (p), reload_reg, 0);
                          if (! n)
                            continue;
                          if (n == 1)
@@ -4520,7 +4017,7 @@ reload_as_needed (live_known)
                          reg_has_output_reload[REGNO (XEXP (in_reg, 0))] = 1;
                        }
                      else
-                       forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX, 
+                       forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX,
                                              NULL);
                    }
                  else if ((code == PRE_INC || code == PRE_DEC)
@@ -4563,21 +4060,11 @@ reload_as_needed (live_known)
         if it is a call-used reg.  */
       else if (GET_CODE (insn) == CALL_INSN)
        AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
-
-      /* In case registers overlap, allow certain insns to invalidate
-        particular hard registers.  */
-
-#ifdef INSN_CLOBBERS_REGNO_P
-      for (i = 0 ; i < FIRST_PSEUDO_REGISTER; i++)
-       if (TEST_HARD_REG_BIT (reg_reloaded_valid, i)
-           && INSN_CLOBBERS_REGNO_P (insn, i))
-         CLEAR_HARD_REG_BIT (reg_reloaded_valid, i);
-#endif
-
-#ifdef USE_C_ALLOCA
-      alloca (0);
-#endif
     }
+
+  /* Clean up.  */
+  free (reg_last_reload_reg);
+  free (reg_has_output_reload);
 }
 
 /* Discard all record of any value reloaded from X,
@@ -4593,14 +4080,18 @@ forget_old_reloads_1 (x, ignored, data)
      rtx ignored ATTRIBUTE_UNUSED;
      void *data ATTRIBUTE_UNUSED;
 {
-  register int regno;
-  int nr;
+  unsigned int regno;
+  unsigned int nr;
   int offset = 0;
 
-  /* note_stores does give us subregs of hard regs.  */
+  /* note_stores does give us subregs of hard regs,
+     subreg_regno_offset will abort if it is not a hard reg.  */
   while (GET_CODE (x) == SUBREG)
     {
-      offset += SUBREG_WORD (x);
+      offset += subreg_regno_offset (REGNO (SUBREG_REG (x)),
+                                    GET_MODE (SUBREG_REG (x)),
+                                    SUBREG_BYTE (x),
+                                    GET_MODE (x));
       x = SUBREG_REG (x);
     }
 
@@ -4613,7 +4104,8 @@ forget_old_reloads_1 (x, ignored, data)
     nr = 1;
   else
     {
-      int i;
+      unsigned int i;
+
       nr = HARD_REGNO_NREGS (regno, GET_MODE (x));
       /* Storing into a spilled-reg invalidates its contents.
         This can happen if a block-local pseudo is allocated to that reg
@@ -4624,7 +4116,10 @@ forget_old_reloads_1 (x, ignored, data)
           reload reg in the current instruction.  */
        if (n_reloads == 0
            || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
-         CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+         {
+           CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
+           spill_reg_store[regno + i] = 0;
+         }
     }
 
   /* Since value of X has changed,
@@ -4637,46 +4132,11 @@ forget_old_reloads_1 (x, ignored, data)
       reg_last_reload_reg[regno + nr] = 0;
 }
 \f
-/* Comparison function for qsort to decide which of two reloads
-   should be handled first.  *P1 and *P2 are the reload numbers.  */
-
-static int
-reload_reg_class_lower (r1p, r2p)
-     const PTR r1p;
-     const PTR r2p;
-{
-  register int r1 = *(const short *)r1p, r2 = *(const short *)r2p;
-  register int t;
-
-  /* Consider required reloads before optional ones.  */
-  t = rld[r1].optional - rld[r2].optional;
-  if (t != 0)
-    return t;
-
-  /* Count all solitary classes before non-solitary ones.  */
-  t = ((reg_class_size[(int) rld[r2].class] == 1)
-       - (reg_class_size[(int) rld[r1].class] == 1));
-  if (t != 0)
-    return t;
-
-  /* Aside from solitaires, consider all multi-reg groups first.  */
-  t = rld[r2].nregs - rld[r1].nregs;
-  if (t != 0)
-    return t;
-
-  /* Consider reloads in order of increasing reg-class number.  */
-  t = (int) rld[r1].class - (int) rld[r2].class;
-  if (t != 0)
-    return t;
-
-  /* If reloads are equally urgent, sort by reload number,
-     so that the results of qsort leave nothing to chance.  */
-  return r1 - r2;
-}
-\f
 /* The following HARD_REG_SETs indicate when each hard register is
    used for a reload of various parts of the current insn.  */
 
+/* If reg is unavailable for all reloads.  */
+static HARD_REG_SET reload_reg_unavailable;
 /* If reg is in use as a reload reg for a RELOAD_OTHER reload.  */
 static HARD_REG_SET reload_reg_used;
 /* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I.  */
@@ -4717,13 +4177,13 @@ static HARD_REG_SET reg_used_in_insn;
 
 static void
 mark_reload_reg_in_use (regno, opnum, type, mode)
-     int regno;
+     unsigned int regno;
      int opnum;
      enum reload_type type;
      enum machine_mode mode;
 {
-  int nregs = HARD_REGNO_NREGS (regno, mode);
-  int i;
+  unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
+  unsigned int i;
 
   for (i = regno; i < nregs + regno; i++)
     {
@@ -4782,13 +4242,13 @@ mark_reload_reg_in_use (regno, opnum, type, mode)
 
 static void
 clear_reload_reg_in_use (regno, opnum, type, mode)
-     int regno;
+     unsigned int regno;
      int opnum;
      enum reload_type type;
      enum machine_mode mode;
 {
-  int nregs = HARD_REGNO_NREGS (regno, mode);
-  int start_regno, end_regno;
+  unsigned int nregs = HARD_REGNO_NREGS (regno, mode);
+  unsigned int start_regno, end_regno, r;
   int i;
   /* A complication is that for some reload types, inheritance might
      allow multiple reloads of the same types to share a reload register.
@@ -4868,8 +4328,8 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
              && (check_any || rld[i].opnum == opnum)
              && rld[i].reg_rtx)
            {
-             int conflict_start = true_regnum (rld[i].reg_rtx);
-             int conflict_end
+             unsigned int conflict_start = true_regnum (rld[i].reg_rtx);
+             unsigned int conflict_end
                = (conflict_start
                   + HARD_REGNO_NREGS (conflict_start, rld[i].mode));
 
@@ -4884,8 +4344,9 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
            }
        }
     }
-  for (i = start_regno; i < end_regno; i++)
-    CLEAR_HARD_REG_BIT (*used_in_set, i);
+
+  for (r = start_regno; r < end_regno; r++)
+    CLEAR_HARD_REG_BIT (*used_in_set, r);
 }
 
 /* 1 if reg REGNO is free as a reload reg for a reload of the sort
@@ -4893,14 +4354,15 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
 
 static int
 reload_reg_free_p (regno, opnum, type)
-     int regno;
+     unsigned int regno;
      int opnum;
      enum reload_type type;
 {
   int i;
 
   /* In use for a RELOAD_OTHER means it's not available for anything.  */
-  if (TEST_HARD_REG_BIT (reload_reg_used, regno))
+  if (TEST_HARD_REG_BIT (reload_reg_used, regno)
+      || TEST_HARD_REG_BIT (reload_reg_unavailable, regno))
     return 0;
 
   switch (type)
@@ -5052,7 +4514,7 @@ reload_reg_free_p (regno, opnum, type)
 
 static int
 reload_reg_reaches_end_p (regno, opnum, type)
-     int regno;
+     unsigned int regno;
      int opnum;
      enum reload_type type;
 {
@@ -5112,8 +4574,9 @@ reload_reg_reaches_end_p (regno, opnum, type)
       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));
+      return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+             && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && !TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INPUT:
       /* Similar to input address, except we start at the next operand for
@@ -5138,7 +4601,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
-      return 1;
+      return (!TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_OPADDR_ADDR:
       for (i = 0; i < reload_n_operands; i++)
@@ -5147,8 +4610,9 @@ reload_reg_reaches_end_p (regno, opnum, type)
            || 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));
+      return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+             && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && !TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INSN:
       /* These conflict with other outputs with RELOAD_OTHER.  So
@@ -5233,7 +4697,7 @@ reloads_conflict (r1, r2)
       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));
+                 && r2_opnum <= r1_opnum));
 
     case RELOAD_FOR_INSN:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_OUTPUT
@@ -5251,10 +4715,6 @@ reloads_conflict (r1, r2)
     }
 }
 \f
-/* Vector of reload-numbers showing the order in which the reloads should
-   be processed.  */
-short reload_order[MAX_RELOADS];
-
 /* Indexed by reload number, 1 if incoming value
    inherited from previous insns.  */
 char reload_inherited[MAX_RELOADS];
@@ -5271,29 +4731,14 @@ rtx reload_override_in[MAX_RELOADS];
    or -1 if we did not need a register for this reload.  */
 int reload_spill_index[MAX_RELOADS];
 
-/* Return 1 if the value in reload reg REGNO, as used by a reload
-   needed for the part of the insn specified by OPNUM and TYPE,
-   may be used to load VALUE into it.
-
-   Other read-only reloads with the same value do not conflict
-   unless OUT is non-zero and these other reloads have to live while
-   output reloads live.
-   If OUT is CONST0_RTX, this is a special case: it means that the
-   test should not be for using register REGNO as reload register, but
-   for copying from register REGNO into the reload register.
-
-   RELOADNUM is the number of the reload we want to load this value for;
-   a reload does not conflict with itself.
-
-   When IGNORE_ADDRESS_RELOADS is set, we can not have conflicts with
-   reloads that load an address for the very reload we are considering.
+/* Subroutine of free_for_value_p, used to check a single register.
+   START_REGNO is the starting regno of the full reload register
+   (possibly comprising multiple hard registers) that we are considering.  */
 
-   The caller has to make sure that there is no conflict with the return
-   register.  */
 static int
-reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
-                            ignore_address_reloads)
-     int regno;
+reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
+                            reloadnum, ignore_address_reloads)
+     int start_regno, regno;
      int opnum;
      enum reload_type type;
      rtx value, out;
@@ -5308,6 +4753,9 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
   int i;
   int copy = 0;
 
+  if (TEST_HARD_REG_BIT (reload_reg_unavailable, regno))
+    return 0;
+
   if (out == const0_rtx)
     {
       copy = 1;
@@ -5332,7 +4780,7 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
   switch (type)
     {
     case RELOAD_FOR_OTHER_ADDRESS:
-      /* RELOAD_FOR_OTHER_ADDRESS conflits with RELOAD_OTHER reloads.  */
+      /* RELOAD_FOR_OTHER_ADDRESS conflicts with RELOAD_OTHER reloads.  */
       time1 = copy ? 0 : 1;
       break;
     case RELOAD_OTHER:
@@ -5383,7 +4831,14 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
              <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
          && i != reloadnum)
        {
-         if (! rld[i].in || ! rtx_equal_p (rld[i].in, value)
+         rtx other_input = rld[i].in;
+
+         /* If the other reload loads the same input value, that
+            will not cause a conflict only if it's loading it into
+            the same register.  */
+         if (true_regnum (reg) != start_regno)
+           other_input = NULL_RTX;
+         if (! other_input || ! rtx_equal_p (other_input, value)
              || rld[i].out || out)
            {
              int time2;
@@ -5464,13 +4919,13 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
                case RELOAD_OTHER:
                  /* If there is no conflict in the input part, handle this
                     like an output reload.  */
-                 if (! rld[i].in || rtx_equal_p (rld[i].in, value))
+                 if (! rld[i].in || rtx_equal_p (other_input, value))
                    {
                      time2 = MAX_RECOG_OPERANDS * 4 + 4;
                      /* Earlyclobbered outputs must conflict with inputs.  */
                      if (earlyclobber_operand_p (rld[i].out))
                        time2 = MAX_RECOG_OPERANDS * 4 + 3;
-                         
+
                      break;
                    }
                  time2 = 1;
@@ -5486,7 +4941,7 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
                }
              if ((time1 >= time2
                   && (! rld[i].in || rld[i].out
-                      || ! rtx_equal_p (rld[i].in, value)))
+                      || ! rtx_equal_p (other_input, value)))
                  || (out && rld[reloadnum].out_reg
                      && time2 >= MAX_RECOG_OPERANDS * 4 + 3))
                return 0;
@@ -5501,6 +4956,64 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
   return 1;
 }
 
+/* Return 1 if the value in reload reg REGNO, as used by a reload
+   needed for the part of the insn specified by OPNUM and TYPE,
+   may be used to load VALUE into it.
+
+   MODE is the mode in which the register is used, this is needed to
+   determine how many hard regs to test.
+
+   Other read-only reloads with the same value do not conflict
+   unless OUT is non-zero and these other reloads have to live while
+   output reloads live.
+   If OUT is CONST0_RTX, this is a special case: it means that the
+   test should not be for using register REGNO as reload register, but
+   for copying from register REGNO into the reload register.
+
+   RELOADNUM is the number of the reload we want to load this value for;
+   a reload does not conflict with itself.
+
+   When IGNORE_ADDRESS_RELOADS is set, we can not have conflicts with
+   reloads that load an address for the very reload we are considering.
+
+   The caller has to make sure that there is no conflict with the return
+   register.  */
+
+static int
+free_for_value_p (regno, mode, opnum, type, value, out, reloadnum,
+                 ignore_address_reloads)
+     int regno;
+     enum machine_mode mode;
+     int opnum;
+     enum reload_type type;
+     rtx value, out;
+     int reloadnum;
+     int ignore_address_reloads;
+{
+  int nregs = HARD_REGNO_NREGS (regno, mode);
+  while (nregs-- > 0)
+    if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type,
+                                      value, out, reloadnum,
+                                      ignore_address_reloads))
+      return 0;
+  return 1;
+}
+
+/* Determine whether the reload reg X overlaps any rtx'es used for
+   overriding inheritance.  Return nonzero if so.  */
+
+static int
+conflicts_with_override (x)
+     rtx x;
+{
+  int i;
+  for (i = 0; i < n_reloads; i++)
+    if (reload_override_in[i]
+       && reg_overlap_mentioned_p (x, reload_override_in[i]))
+      return 1;
+  return 0;
+}
+\f
 /* Give an error message saying we failed to find a reload for INSN,
    and clear out reload R.  */
 static void
@@ -5579,17 +5092,15 @@ set_reload_reg (i, r)
 
    Set rld[R].reg_rtx to the register allocated.
 
-   If NOERROR is nonzero, we return 1 if successful,
-   or 0 if we couldn't find a spill reg and we didn't change anything.  */
+   We return 1 if successful, or 0 if we couldn't find a spill reg and
+   we didn't change anything.  */
 
 static int
-allocate_reload_reg (chain, r, last_reload, noerror)
-     struct insn_chain *chain;
+allocate_reload_reg (chain, r, last_reload)
+     struct insn_chain *chain ATTRIBUTE_UNUSED;
      int r;
      int last_reload;
-     int noerror;
 {
-  rtx insn = chain->insn;
   int i, pass, count;
 
   /* If we put this reload ahead, thinking it is a group,
@@ -5624,17 +5135,9 @@ allocate_reload_reg (chain, r, 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.  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;
+        of leapfrogging each other.  */
+
+      i = last_spill_reg;
 
       for (count = 0; count < n_spills; count++)
        {
@@ -5652,11 +5155,9 @@ allocate_reload_reg (chain, r, last_reload, noerror)
                   /* We check reload_reg_used to make sure we
                      don't clobber the return register.  */
                   && ! TEST_HARD_REG_BIT (reload_reg_used, regnum)
-                  && reload_reg_free_for_value_p (regnum,
-                                                  rld[r].opnum,
-                                                  rld[r].when_needed,
-                                                  rld[r].in,
-                                                  rld[r].out, r, 1)))
+                  && free_for_value_p (regnum, rld[r].mode, rld[r].opnum,
+                                       rld[r].when_needed, rld[r].in,
+                                       rld[r].out, r, 1)))
              && TEST_HARD_REG_BIT (reg_class_contents[class], regnum)
              && HARD_REGNO_MODE_OK (regnum, rld[r].mode)
              /* Look first for regs to share, then for unshared.  But
@@ -5683,22 +5184,17 @@ allocate_reload_reg (chain, r, last_reload, noerror)
                  break;
                }
              /* Otherwise check that as many consecutive regs as we need
-                are available here.
-                Also, don't use for a group registers that are
-                needed for nongroups.  */
-             if (! TEST_HARD_REG_BIT (chain->counted_for_nongroups, regnum))
-               while (nr > 1)
-                 {
-                   int regno = regnum + nr - 1;
-                   if (!(TEST_HARD_REG_BIT (reg_class_contents[class], regno)
-                         && spill_reg_order[regno] >= 0
-                         && reload_reg_free_p (regno, rld[r].opnum,
-                                               rld[r].when_needed)
-                         && ! TEST_HARD_REG_BIT (chain->counted_for_nongroups,
-                                                 regno)))
-                     break;
-                   nr--;
-                 }
+                are available here.  */
+             while (nr > 1)
+               {
+                 int regno = regnum + nr - 1;
+                 if (!(TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+                       && spill_reg_order[regno] >= 0
+                       && reload_reg_free_p (regno, rld[r].opnum,
+                                             rld[r].when_needed)))
+                   break;
+                 nr--;
+               }
              if (nr == 1)
                break;
            }
@@ -5710,29 +5206,19 @@ allocate_reload_reg (chain, r, last_reload, noerror)
     }
 
   /* We should have found a spill register by now.  */
-  if (count == n_spills)
-    {
-      if (noerror)
-       return 0;
-      goto failure;
-    }
-
-  if (set_reload_reg (i, r))
-    return 1;
-
-  /* The reg is not OK.  */
-  if (noerror)
+  if (count >= n_spills)
     return 0;
 
- failure:
-  failed_reload (insn, r);
+  /* I is the index in SPILL_REG_RTX of the reload register we are to
+     allocate.  Get an rtx for it and find its register number.  */
 
-  return 1;
+  return set_reload_reg (i, r);
 }
 \f
 /* Initialize all the tables needed to allocate reload registers.
    CHAIN is the insn currently being processed; SAVE_RELOAD_REG_RTX
    is the array we use to restore the reg_rtx field for every reload.  */
+
 static void
 choose_reload_regs_init (chain, save_reload_reg_rtx)
      struct insn_chain *chain;
@@ -5743,9 +5229,9 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
   for (i = 0; i < n_reloads; i++)
     rld[i].reg_rtx = save_reload_reg_rtx[i];
 
-  bzero (reload_inherited, MAX_RELOADS);
-  bzero ((char *) reload_inheritance_insn, MAX_RELOADS * sizeof (rtx));
-  bzero ((char *) reload_override_in, MAX_RELOADS * sizeof (rtx));
+  memset (reload_inherited, 0, MAX_RELOADS);
+  memset ((char *) reload_inheritance_insn, 0, MAX_RELOADS * sizeof (rtx));
+  memset ((char *) reload_override_in, 0, MAX_RELOADS * sizeof (rtx));
 
   CLEAR_HARD_REG_SET (reload_reg_used);
   CLEAR_HARD_REG_SET (reload_reg_used_at_all);
@@ -5757,13 +5243,14 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
   CLEAR_HARD_REG_SET (reg_used_in_insn);
   {
     HARD_REG_SET tmp;
-    REG_SET_TO_HARD_REG_SET (tmp, chain->live_before);
+    REG_SET_TO_HARD_REG_SET (tmp, &chain->live_throughout);
     IOR_HARD_REG_SET (reg_used_in_insn, tmp);
-    REG_SET_TO_HARD_REG_SET (tmp, chain->live_after);
+    REG_SET_TO_HARD_REG_SET (tmp, &chain->dead_or_set);
     IOR_HARD_REG_SET (reg_used_in_insn, tmp);
-    compute_use_by_pseudos (&reg_used_in_insn, chain->live_before);
-    compute_use_by_pseudos (&reg_used_in_insn, chain->live_after);
+    compute_use_by_pseudos (&reg_used_in_insn, &chain->live_throughout);
+    compute_use_by_pseudos (&reg_used_in_insn, &chain->dead_or_set);
   }
+
   for (i = 0; i < reload_n_operands; i++)
     {
       CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
@@ -5774,7 +5261,7 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
       CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
     }
 
-  IOR_COMPL_HARD_REG_SET (reload_reg_used, chain->used_spill_regs);
+  COMPL_HARD_REG_SET (reload_reg_unavailable, chain->used_spill_regs);
 
   CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
 
@@ -5799,10 +5286,9 @@ choose_reload_regs (chain)
 {
   rtx insn = chain->insn;
   register int i, j;
-  int max_group_size = 1;
+  unsigned int max_group_size = 1;
   enum reg_class group_class = NO_REGS;
-  int inheritance;
-  int pass;
+  int pass, win, inheritance;
 
   rtx save_reload_reg_rtx[MAX_RELOADS];
 
@@ -5823,7 +5309,8 @@ choose_reload_regs (chain)
       if (rld[j].nregs > 1)
        {
          max_group_size = MAX (rld[j].nregs, max_group_size);
-         group_class = reg_class_superunion[(int)rld[j].class][(int)group_class];
+         group_class
+           = reg_class_superunion[(int) rld[j].class][(int)group_class];
        }
 
       save_reload_reg_rtx[j] = rld[j].reg_rtx;
@@ -5837,7 +5324,7 @@ choose_reload_regs (chain)
      Using inheritance when not optimizing leads to paradoxes
      with fp on the 68k: fp numbers (not NaNs) fail to be equal to themselves
      because one side of the comparison might be inherited.  */
-
+  win = 0;
   for (inheritance = optimize > 0; inheritance >= 0; inheritance--)
     {
       choose_reload_regs_init (chain, save_reload_reg_rtx);
@@ -5845,11 +5332,11 @@ choose_reload_regs (chain)
       /* Process the reloads in order of preference just found.
         Beyond this point, subregs can be found in reload_reg_rtx.
 
-        This used to look for an existing reloaded home for all
-        of the reloads, and only then perform any new reloads.
-        But that could lose if the reloads were done out of reg-class order
-        because a later reload with a looser constraint might have an old
-        home in a register needed by an earlier reload with a tighter constraint.
+        This used to look for an existing reloaded home for all of the
+        reloads, and only then perform any new reloads.  But that could lose
+        if the reloads were done out of reg-class order because a later
+        reload with a looser constraint might have an old home in a register
+        needed by an earlier reload with a tighter constraint.
 
         To solve this, we make two passes over the reloads, in the order
         described above.  In the first pass we try to inherit a reload
@@ -5895,7 +5382,7 @@ choose_reload_regs (chain)
                   || rld[reload_order[i]].secondary_p)
                  && ! rld[reload_order[i]].optional
                  && rld[reload_order[i]].reg_rtx == 0)
-               allocate_reload_reg (chain, reload_order[i], 0, inheritance);
+               allocate_reload_reg (chain, reload_order[i], 0);
 #endif
 
          /* First see if this pseudo is already available as reloaded
@@ -5914,7 +5401,7 @@ choose_reload_regs (chain)
 
          if (inheritance)
            {
-             int word = 0;
+             int byte = 0;
              register int regno = -1;
              enum machine_mode mode = VOIDmode;
 
@@ -5933,10 +5420,10 @@ choose_reload_regs (chain)
              else if (GET_CODE (rld[r].in_reg) == SUBREG
                       && GET_CODE (SUBREG_REG (rld[r].in_reg)) == REG)
                {
-                 word = SUBREG_WORD (rld[r].in_reg);
+                 byte = SUBREG_BYTE (rld[r].in_reg);
                  regno = REGNO (SUBREG_REG (rld[r].in_reg));
                  if (regno < FIRST_PSEUDO_REGISTER)
-                   regno += word;
+                   regno = subreg_regno (rld[r].in_reg);
                  mode = GET_MODE (rld[r].in_reg);
                }
 #ifdef AUTO_INC_DEC
@@ -5957,18 +5444,38 @@ choose_reload_regs (chain)
                 that can invalidate an inherited reload of part of a pseudoreg.  */
              else if (GET_CODE (rld[r].in) == SUBREG
                       && GET_CODE (SUBREG_REG (rld[r].in)) == REG)
-               regno = REGNO (SUBREG_REG (rld[r].in)) + SUBREG_WORD (rld[r].in);
+               regno = subreg_regno (rld[r].in);
 #endif
 
              if (regno >= 0 && reg_last_reload_reg[regno] != 0)
                {
                  enum reg_class class = rld[r].class, last_class;
                  rtx last_reg = reg_last_reload_reg[regno];
+                 enum machine_mode need_mode;
 
-                 i = REGNO (last_reg) + word;
+                 i = REGNO (last_reg);
+                 i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
                  last_class = REGNO_REG_CLASS (i);
-                 if ((GET_MODE_SIZE (GET_MODE (last_reg))
-                      >= GET_MODE_SIZE (mode) + word * UNITS_PER_WORD)
+
+                 if (byte == 0)
+                   need_mode = mode;
+                 else
+                   need_mode
+                     = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte,
+                                               GET_MODE_CLASS (mode));
+
+                 if (
+#ifdef CLASS_CANNOT_CHANGE_MODE
+                     (TEST_HARD_REG_BIT
+                      (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], i)
+                      ? ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (last_reg),
+                                                      need_mode)
+                      : (GET_MODE_SIZE (GET_MODE (last_reg))
+                         >= GET_MODE_SIZE (need_mode)))
+#else
+                     (GET_MODE_SIZE (GET_MODE (last_reg))
+                      >= GET_MODE_SIZE (need_mode))
+#endif
                      && reg_reloaded_contents[i] == regno
                      && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
                      && HARD_REGNO_MODE_OK (i, rld[r].mode)
@@ -5977,7 +5484,7 @@ choose_reload_regs (chain)
                             register, we might use it for reload_override_in,
                             if copying it to the desired class is cheap
                             enough.  */
-                         || ((REGISTER_MOVE_COST (last_class, class)
+                         || ((REGISTER_MOVE_COST (mode, last_class, class)
                               < MEMORY_MOVE_COST (mode, class, 1))
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
                              && (SECONDARY_INPUT_RELOAD_CLASS (class, mode,
@@ -5993,15 +5500,13 @@ choose_reload_regs (chain)
                      && (rld[r].nregs == max_group_size
                          || ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
                                                  i))
-                     && reload_reg_free_for_value_p (i, rld[r].opnum,
-                                                     rld[r].when_needed,
-                                                     rld[r].in,
-                                                     const0_rtx, r, 1))
+                     && free_for_value_p (i, rld[r].mode, rld[r].opnum,
+                                          rld[r].when_needed, rld[r].in,
+                                          const0_rtx, r, 1))
                    {
                      /* If a group is needed, verify that all the subsequent
                         registers still have their values intact.  */
-                     int nr
-                       = HARD_REGNO_NREGS (i, rld[r].mode);
+                     int nr = HARD_REGNO_NREGS (i, rld[r].mode);
                      int k;
 
                      for (k = 1; k < nr; k++)
@@ -6030,15 +5535,17 @@ choose_reload_regs (chain)
                              break;
 
                          if (i1 != n_earlyclobbers
-                             || ! (reload_reg_free_for_value_p
-                                   (i, rld[r].opnum, rld[r].when_needed,
-                                    rld[r].in, rld[r].out, r, 1))
+                             || ! (free_for_value_p (i, rld[r].mode,
+                                                     rld[r].opnum,
+                                                     rld[r].when_needed, rld[r].in,
+                                                     rld[r].out, r, 1))
                              /* Don't use it if we'd clobber a pseudo reg.  */
                              || (TEST_HARD_REG_BIT (reg_used_in_insn, i)
                                  && rld[r].out
                                  && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
                              /* Don't clobber the frame pointer.  */
-                             || (i == HARD_FRAME_POINTER_REGNUM && rld[r].out)
+                             || (i == HARD_FRAME_POINTER_REGNUM
+                                 && rld[r].out)
                              /* Don't really use the inherited spill reg
                                 if we need it wider than we've got it.  */
                              || (GET_MODE_SIZE (rld[r].mode)
@@ -6052,9 +5559,12 @@ choose_reload_regs (chain)
                              || (rld[r].out && rld[r].reg_rtx
                                  && rtx_equal_p (rld[r].out, rld[r].reg_rtx)))
                            {
-                             reload_override_in[r] = last_reg;
-                             reload_inheritance_insn[r]
-                               = reg_reloaded_insn[i];
+                             if (! rld[r].optional)
+                               {
+                                 reload_override_in[r] = last_reg;
+                                 reload_inheritance_insn[r]
+                                   = reg_reloaded_insn[i];
+                               }
                            }
                          else
                            {
@@ -6108,7 +5618,7 @@ choose_reload_regs (chain)
            {
              register rtx equiv
                = find_equiv_reg (search_equiv, insn, rld[r].class,
-                                 -1, NULL_PTR, 0, rld[r].mode);
+                                 -1, NULL, 0, rld[r].mode);
              int regno = 0;
 
              if (equiv != 0)
@@ -6121,7 +5631,7 @@ choose_reload_regs (chain)
                         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);
+                     regno = subreg_regno (equiv);
                      equiv = gen_rtx_REG (rld[r].mode, regno);
                    }
                  else
@@ -6132,10 +5642,9 @@ choose_reload_regs (chain)
                 and of the desired class.  */
              if (equiv != 0
                  && ((TEST_HARD_REG_BIT (reload_reg_used_at_all, regno)
-                      && ! reload_reg_free_for_value_p (regno, rld[r].opnum,
-                                                        rld[r].when_needed,
-                                                        rld[r].in,
-                                                        rld[r].out, r, 1))
+                      && ! free_for_value_p (regno, rld[r].mode,
+                                             rld[r].opnum, rld[r].when_needed,
+                                             rld[r].in, rld[r].out, r, 1))
                      || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
                                              regno)))
                equiv = 0;
@@ -6153,7 +5662,8 @@ choose_reload_regs (chain)
                  if (reg_overlap_mentioned_for_reload_p (equiv,
                                                          reload_earlyclobbers[i]))
                    {
-                     reload_override_in[r] = equiv;
+                     if (! rld[r].optional)
+                       reload_override_in[r] = equiv;
                      equiv = 0;
                      break;
                    }
@@ -6164,24 +5674,44 @@ choose_reload_regs (chain)
                 In particular, we then can't use EQUIV for a
                 RELOAD_FOR_OUTPUT_ADDRESS reload.  */
 
-             if (equiv != 0 && regno_clobbered_p (regno, insn))
+             if (equiv != 0)
                {
-                 switch (rld[r].when_needed)
-                   {
-                   case RELOAD_FOR_OTHER_ADDRESS:
-                   case RELOAD_FOR_INPADDR_ADDRESS:
-                   case RELOAD_FOR_INPUT_ADDRESS:
-                   case RELOAD_FOR_OPADDR_ADDR:
-                     break;
-                   case RELOAD_OTHER:
-                   case RELOAD_FOR_INPUT:
-                   case RELOAD_FOR_OPERAND_ADDRESS:
-                     reload_override_in[r] = equiv;
-                     /* Fall through. */
-                   default:
-                     equiv = 0;
-                     break;
-                   }
+                 if (regno_clobbered_p (regno, insn, rld[r].mode, 0))
+                   switch (rld[r].when_needed)
+                     {
+                     case RELOAD_FOR_OTHER_ADDRESS:
+                     case RELOAD_FOR_INPADDR_ADDRESS:
+                     case RELOAD_FOR_INPUT_ADDRESS:
+                     case RELOAD_FOR_OPADDR_ADDR:
+                       break;
+                     case RELOAD_OTHER:
+                     case RELOAD_FOR_INPUT:
+                     case RELOAD_FOR_OPERAND_ADDRESS:
+                       if (! rld[r].optional)
+                         reload_override_in[r] = equiv;
+                       /* Fall through.  */
+                     default:
+                       equiv = 0;
+                       break;
+                     }
+                 else if (regno_clobbered_p (regno, insn, rld[r].mode, 1))
+                   switch (rld[r].when_needed)
+                     {
+                     case RELOAD_FOR_OTHER_ADDRESS:
+                     case RELOAD_FOR_INPADDR_ADDRESS:
+                     case RELOAD_FOR_INPUT_ADDRESS:
+                     case RELOAD_FOR_OPADDR_ADDR:
+                     case RELOAD_FOR_OPERAND_ADDRESS:
+                     case RELOAD_FOR_INPUT:
+                       break;
+                     case RELOAD_OTHER:
+                       if (! rld[r].optional)
+                         reload_override_in[r] = equiv;
+                       /* Fall through.  */
+                     default:
+                       equiv = 0;
+                       break;
+                     }
                }
 
              /* If we found an equivalent reg, say no code need be generated
@@ -6221,8 +5751,9 @@ choose_reload_regs (chain)
          if (rld[r].reg_rtx != 0 || rld[r].optional != 0)
            continue;
 
-#if 0 /* No longer needed for correct operation.  Might or might not
-        give better code on the average.  Want to experiment?  */
+#if 0
+         /* No longer needed for correct operation.  Might or might
+            not give better code on the average.  Want to experiment?  */
 
          /* See if there is a later reload that has a class different from our
             class that intersects our class or that requires less register
@@ -6252,7 +5783,7 @@ choose_reload_regs (chain)
          if (i == n_reloads)
            continue;
 
-         allocate_reload_reg (chain, r, j == n_reloads - 1, inheritance);
+         allocate_reload_reg (chain, r, j == n_reloads - 1);
 #endif
        }
 
@@ -6271,28 +5802,55 @@ choose_reload_regs (chain)
          if (rld[r].reg_rtx != 0 || rld[r].optional)
            continue;
 
-         if (! allocate_reload_reg (chain, r, j == n_reloads - 1, inheritance))
+         if (! allocate_reload_reg (chain, r, j == n_reloads - 1))
            break;
        }
 
       /* If that loop got all the way, we have won.  */
       if (j == n_reloads)
-       break;
+       {
+         win = 1;
+         break;
+       }
 
       /* Loop around and try without any inheritance.  */
     }
 
-  /* If we thought we could inherit a reload, because it seemed that
-     nothing else wanted the same reload register earlier in the insn,
-     verify that assumption, now that all reloads have been assigned.
-     Likewise for reloads where reload_override_in has been set.  */
-
-  /* If doing expensive optimizations, do one preliminary pass that doesn't
-     cancel any inheritance, but removes reloads that have been needed only
-     for reloads that we know can be inherited.  */
-  for (pass = flag_expensive_optimizations; pass >= 0; pass--)
+  if (! win)
     {
-      for (j = 0; j < n_reloads; j++)
+      /* First undo everything done by the failed attempt
+        to allocate with inheritance.  */
+      choose_reload_regs_init (chain, save_reload_reg_rtx);
+
+      /* Some sanity tests to verify that the reloads found in the first
+        pass are identical to the ones we have now.  */
+      if (chain->n_reloads != n_reloads)
+       abort ();
+
+      for (i = 0; i < n_reloads; i++)
+       {
+         if (chain->rld[i].regno < 0 || chain->rld[i].reg_rtx != 0)
+           continue;
+         if (chain->rld[i].when_needed != rld[i].when_needed)
+           abort ();
+         for (j = 0; j < n_spills; j++)
+           if (spill_regs[j] == chain->rld[i].regno)
+             if (! set_reload_reg (j, i))
+               failed_reload (chain->insn, i);
+       }
+    }
+
+  /* If we thought we could inherit a reload, because it seemed that
+     nothing else wanted the same reload register earlier in the insn,
+     verify that assumption, now that all reloads have been assigned.
+     Likewise for reloads where reload_override_in has been set.  */
+
+  /* If doing expensive optimizations, do one preliminary pass that doesn't
+     cancel any inheritance, but removes reloads that have been needed only
+     for reloads that we know can be inherited.  */
+  for (pass = flag_expensive_optimizations; pass >= 0; pass--)
+    {
+      for (j = 0; j < n_reloads; j++)
        {
          register int r = reload_order[j];
          rtx check_reg;
@@ -6304,13 +5862,11 @@ choose_reload_regs (chain)
            check_reg = reload_override_in[r];
          else
            continue;
-         if (! reload_reg_free_for_value_p (true_regnum (check_reg),
-                                            rld[r].opnum,
-                                            rld[r].when_needed,
-                                            rld[r].in,
-                                            (reload_inherited[r]
-                                             ? rld[r].out : const0_rtx),
-                                            r, 1))
+         if (! free_for_value_p (true_regnum (check_reg), rld[r].mode,
+                                 rld[r].opnum, rld[r].when_needed, rld[r].in,
+                                 (reload_inherited[r]
+                                  ? rld[r].out : const0_rtx),
+                                 r, 1))
            {
              if (pass)
                continue;
@@ -6357,6 +5913,7 @@ choose_reload_regs (chain)
          clear_reload_reg_in_use (regno, rld[j].opnum,
                                   rld[j].when_needed, rld[j].mode);
        rld[j].reg_rtx = 0;
+       reload_spill_index[j] = -1;
       }
 
   /* Record which pseudos and which spill regs have output reloads.  */
@@ -6398,6 +5955,7 @@ choose_reload_regs (chain)
 
 /* Deallocate the reload register for reload R.  This is called from
    remove_address_replacements.  */
+
 void
 deallocate_reload_reg (r)
      int r;
@@ -6523,872 +6081,906 @@ merge_assigned_reloads (insn)
        }
     }
 }
-
 \f
-/* Output insns to reload values in and out of the chosen reload regs.  */
+/* These arrays are filled by emit_reload_insns and its subroutines.  */
+static rtx input_reload_insns[MAX_RECOG_OPERANDS];
+static rtx other_input_address_reload_insns = 0;
+static rtx other_input_reload_insns = 0;
+static rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx output_reload_insns[MAX_RECOG_OPERANDS];
+static rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
+static rtx operand_reload_insns = 0;
+static rtx other_operand_reload_insns = 0;
+static rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
+
+/* Values to be put in spill_reg_store are put here first.  */
+static rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
+static HARD_REG_SET reg_reloaded_died;
+
+/* Generate insns to perform reload RL, which is for the insn in CHAIN and
+   has the number J.  OLD contains the value to be used as input.  */
 
 static void
-emit_reload_insns (chain)
+emit_input_reload_insns (chain, rl, old, j)
      struct insn_chain *chain;
+     struct reload *rl;
+     rtx old;
+     int j;
 {
   rtx insn = chain->insn;
-
-  register int j;
-  rtx input_reload_insns[MAX_RECOG_OPERANDS];
-  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 = PREV_INSN (insn);
-  int special;
-  /* Values to be put in spill_reg_store are put here first.  */
-  rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
-  HARD_REG_SET reg_reloaded_died;
-
-  CLEAR_HARD_REG_SET (reg_reloaded_died);
-
-  for (j = 0; j < reload_n_operands; j++)
-    input_reload_insns[j] = input_address_reload_insns[j]
-      = 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,
-     since reloads of base and index registers precede reloads of operands
-     and the operands may need the base and index registers reloaded.  */
-
-  for (j = 0; j < n_reloads; j++)
-    {
-      register rtx old;
-      rtx oldequiv_reg = 0;
-      rtx this_reload_insn = 0;
-      int expect_occurrences = 1;
-
-      if (rld[j].reg_rtx
-         && REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
-       new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
-
-      old = (rld[j].in && GET_CODE (rld[j].in) == MEM
-            ? rld[j].in_reg : rld[j].in);
-
-      if (old != 0
-         /* AUTO_INC reloads need to be handled even if inherited.  We got an
-            AUTO_INC reload if reload_out is set but reload_out_reg isn't.  */
-         && (! reload_inherited[j] || (rld[j].out && ! rld[j].out_reg))
-         && ! rtx_equal_p (rld[j].reg_rtx, old)
-         && rld[j].reg_rtx != 0)
-       {
-         register rtx reloadreg = rld[j].reg_rtx;
-         rtx oldequiv = 0;
-         enum machine_mode mode;
-         rtx *where;
-
-         /* Determine the mode to reload in.
-            This is very tricky because we have three to choose from.
-            There is the mode the insn operand wants (rld[J].inmode).
-            There is the mode of the reload register RELOADREG.
-            There is the intrinsic mode of the operand, which we could find
-            by stripping some SUBREGs.
-            It turns out that RELOADREG's mode is irrelevant:
-            we can change that arbitrarily.
-
-            Consider (SUBREG:SI foo:QI) as an operand that must be SImode;
-            then the reload reg may not support QImode moves, so use SImode.
-            If foo is in memory due to spilling a pseudo reg, this is safe,
-            because the QImode value is in the least significant part of a
-            slot big enough for a SImode.  If foo is some other sort of
-            memory reference, then it is impossible to reload this case,
-            so previous passes had better make sure this never happens.
-
-            Then consider a one-word union which has SImode and one of its
-            members is a float, being fetched as (SUBREG:SF union:SI).
-            We must fetch that as SFmode because we could be loading into
-            a float-only register.  In this case OLD's mode is correct.
-
-            Consider an immediate integer: it has VOIDmode.  Here we need
-            to get a mode from something else.
-
-            In some cases, there is a fourth mode, the operand's
-            containing mode.  If the insn specifies a containing mode for
-            this operand, it overrides all others.
-
-            I am not sure whether the algorithm here is always right,
-            but it does the right things in those cases.  */
-
-         mode = GET_MODE (old);
-         if (mode == VOIDmode)
-           mode = rld[j].inmode;
+  register rtx reloadreg = rl->reg_rtx;
+  rtx oldequiv_reg = 0;
+  rtx oldequiv = 0;
+  int special = 0;
+  enum machine_mode mode;
+  rtx *where;
+
+  /* Determine the mode to reload in.
+     This is very tricky because we have three to choose from.
+     There is the mode the insn operand wants (rl->inmode).
+     There is the mode of the reload register RELOADREG.
+     There is the intrinsic mode of the operand, which we could find
+     by stripping some SUBREGs.
+     It turns out that RELOADREG's mode is irrelevant:
+     we can change that arbitrarily.
+
+     Consider (SUBREG:SI foo:QI) as an operand that must be SImode;
+     then the reload reg may not support QImode moves, so use SImode.
+     If foo is in memory due to spilling a pseudo reg, this is safe,
+     because the QImode value is in the least significant part of a
+     slot big enough for a SImode.  If foo is some other sort of
+     memory reference, then it is impossible to reload this case,
+     so previous passes had better make sure this never happens.
+
+     Then consider a one-word union which has SImode and one of its
+     members is a float, being fetched as (SUBREG:SF union:SI).
+     We must fetch that as SFmode because we could be loading into
+     a float-only register.  In this case OLD's mode is correct.
+
+     Consider an immediate integer: it has VOIDmode.  Here we need
+     to get a mode from something else.
+
+     In some cases, there is a fourth mode, the operand's
+     containing mode.  If the insn specifies a containing mode for
+     this operand, it overrides all others.
+
+     I am not sure whether the algorithm here is always right,
+     but it does the right things in those cases.  */
+
+  mode = GET_MODE (old);
+  if (mode == VOIDmode)
+    mode = rl->inmode;
 
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
-         /* If we need a secondary register for this operation, see if
-            the value is already in a register in that class.  Don't
-            do this if the secondary register will be used as a scratch
-            register.  */
-
-         if (rld[j].secondary_in_reload >= 0
-             && rld[j].secondary_in_icode == CODE_FOR_nothing
-             && optimize)
-           oldequiv
-             = find_equiv_reg (old, insn,
-                               rld[rld[j].secondary_in_reload].class,
-                               -1, NULL_PTR, 0, mode);
+  /* If we need a secondary register for this operation, see if
+     the value is already in a register in that class.  Don't
+     do this if the secondary register will be used as a scratch
+     register.  */
+
+  if (rl->secondary_in_reload >= 0
+      && rl->secondary_in_icode == CODE_FOR_nothing
+      && optimize)
+    oldequiv
+      = find_equiv_reg (old, insn,
+                       rld[rl->secondary_in_reload].class,
+                       -1, NULL, 0, mode);
 #endif
 
-         /* If reloading from memory, see if there is a register
-            that already holds the same value.  If so, reload from there.
-            We can pass 0 as the reload_reg_p argument because
-            any other reload has either already been emitted,
-            in which case find_equiv_reg will see the reload-insn,
-            or has yet to be emitted, in which case it doesn't matter
-            because we will use this equiv reg right away.  */
-
-         if (oldequiv == 0 && optimize
-             && (GET_CODE (old) == MEM
-                 || (GET_CODE (old) == REG
-                     && REGNO (old) >= FIRST_PSEUDO_REGISTER
-                     && reg_renumber[REGNO (old)] < 0)))
-           oldequiv = find_equiv_reg (old, insn, ALL_REGS,
-                                      -1, NULL_PTR, 0, mode);
-
-         if (oldequiv)
-           {
-             int regno = true_regnum (oldequiv);
-
-             /* Don't use OLDEQUIV if any other reload changes it at an
-                earlier stage of this insn or at this stage.  */
-             if (! reload_reg_free_for_value_p (regno, rld[j].opnum,
-                                                rld[j].when_needed,
-                                                rld[j].in, const0_rtx, j,
-                                                0))
-               oldequiv = 0;
-
-             /* If it is no cheaper to copy from OLDEQUIV into the
-                reload register than it would be to move from memory,
-                don't use it. Likewise, if we need a secondary register
-                or memory.   */
-
-             if (oldequiv != 0
-                 && ((REGNO_REG_CLASS (regno) != rld[j].class
-                      && (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
-                                              rld[j].class)
-                          >= MEMORY_MOVE_COST (mode, rld[j].class, 1)))
+  /* If reloading from memory, see if there is a register
+     that already holds the same value.  If so, reload from there.
+     We can pass 0 as the reload_reg_p argument because
+     any other reload has either already been emitted,
+     in which case find_equiv_reg will see the reload-insn,
+     or has yet to be emitted, in which case it doesn't matter
+     because we will use this equiv reg right away.  */
+
+  if (oldequiv == 0 && optimize
+      && (GET_CODE (old) == MEM
+         || (GET_CODE (old) == REG
+             && REGNO (old) >= FIRST_PSEUDO_REGISTER
+             && reg_renumber[REGNO (old)] < 0)))
+    oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
+
+  if (oldequiv)
+    {
+      unsigned int regno = true_regnum (oldequiv);
+
+      /* Don't use OLDEQUIV if any other reload changes it at an
+        earlier stage of this insn or at this stage.  */
+      if (! free_for_value_p (regno, rl->mode, rl->opnum, rl->when_needed,
+                             rl->in, const0_rtx, j, 0))
+       oldequiv = 0;
+
+      /* If it is no cheaper to copy from OLDEQUIV into the
+        reload register than it would be to move from memory,
+        don't use it. Likewise, if we need a secondary register
+        or memory.   */
+
+      if (oldequiv != 0
+         && ((REGNO_REG_CLASS (regno) != rl->class
+              && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
+                                      rl->class)
+                  >= MEMORY_MOVE_COST (mode, rl->class, 1)))
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
-                     || (SECONDARY_INPUT_RELOAD_CLASS (rld[j].class,
-                                                       mode, oldequiv)
-                         != NO_REGS)
+             || (SECONDARY_INPUT_RELOAD_CLASS (rl->class,
+                                               mode, oldequiv)
+                 != NO_REGS)
 #endif
 #ifdef SECONDARY_MEMORY_NEEDED
-                     || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
-                                                 rld[j].class,
-                                                 mode)
+             || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
+                                         rl->class,
+                                         mode)
 #endif
-                     ))
-               oldequiv = 0;
-           }
+             ))
+       oldequiv = 0;
+    }
+
+  /* delete_output_reload is only invoked properly if old contains
+     the original pseudo register.  Since this is replaced with a
+     hard reg when RELOAD_OVERRIDE_IN is set, see if we can
+     find the pseudo in RELOAD_IN_REG.  */
+  if (oldequiv == 0
+      && reload_override_in[j]
+      && GET_CODE (rl->in_reg) == REG)
+    {
+      oldequiv = old;
+      old = rl->in_reg;
+    }
+  if (oldequiv == 0)
+    oldequiv = old;
+  else if (GET_CODE (oldequiv) == REG)
+    oldequiv_reg = oldequiv;
+  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_store[REGNO (oldequiv)]
+      && GET_CODE (old) == REG
+      && (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
+         || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
+                         rl->out_reg)))
+    delete_output_reload (insn, j, REGNO (oldequiv));
+
+  /* Encapsulate both RELOADREG and OLDEQUIV into that mode,
+     then load RELOADREG from OLDEQUIV.  Note that we cannot use
+     gen_lowpart_common since it can do the wrong thing when
+     RELOADREG has a multi-word mode.  Note that RELOADREG
+     must always be a REG here.  */
+
+  if (GET_MODE (reloadreg) != mode)
+    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+  while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
+    oldequiv = SUBREG_REG (oldequiv);
+  if (GET_MODE (oldequiv) != VOIDmode
+      && mode != GET_MODE (oldequiv))
+    oldequiv = gen_lowpart_SUBREG (mode, oldequiv);
+
+  /* Switch to the right place to emit the reload insns.  */
+  switch (rl->when_needed)
+    {
+    case RELOAD_OTHER:
+      where = &other_input_reload_insns;
+      break;
+    case RELOAD_FOR_INPUT:
+      where = &input_reload_insns[rl->opnum];
+      break;
+    case RELOAD_FOR_INPUT_ADDRESS:
+      where = &input_address_reload_insns[rl->opnum];
+      break;
+    case RELOAD_FOR_INPADDR_ADDRESS:
+      where = &inpaddr_address_reload_insns[rl->opnum];
+      break;
+    case RELOAD_FOR_OUTPUT_ADDRESS:
+      where = &output_address_reload_insns[rl->opnum];
+      break;
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      where = &outaddr_address_reload_insns[rl->opnum];
+      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;
+    default:
+      abort ();
+    }
 
-         /* delete_output_reload is only invoked properly if old contains
-            the original pseudo register.  Since this is replaced with a
-            hard reg when RELOAD_OVERRIDE_IN is set, see if we can
-            find the pseudo in RELOAD_IN_REG.  */
-         if (oldequiv == 0
-             && reload_override_in[j]
-             && GET_CODE (rld[j].in_reg) == REG)
-           {
-             oldequiv = old;
-             old = rld[j].in_reg;
-           }
-         if (oldequiv == 0)
-           oldequiv = old;
-         else if (GET_CODE (oldequiv) == REG)
-           oldequiv_reg = oldequiv;
-         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_store[REGNO (oldequiv)]
-             && GET_CODE (old) == REG
-             && (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)])
-                 || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
-                                 rld[j].out_reg)))
-           delete_output_reload (insn, j, REGNO (oldequiv));
-
-         /* Encapsulate both RELOADREG and OLDEQUIV into that mode,
-            then load RELOADREG from OLDEQUIV.  Note that we cannot use
-            gen_lowpart_common since it can do the wrong thing when
-            RELOADREG has a multi-word mode.  Note that RELOADREG
-            must always be a REG here.  */
-
-         if (GET_MODE (reloadreg) != mode)
-           reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
-         while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
-           oldequiv = SUBREG_REG (oldequiv);
-         if (GET_MODE (oldequiv) != VOIDmode
-             && mode != GET_MODE (oldequiv))
-           oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
-
-         /* Switch to the right place to emit the reload insns.  */
-         switch (rld[j].when_needed)
-           {
-           case RELOAD_OTHER:
-             where = &other_input_reload_insns;
-             break;
-           case RELOAD_FOR_INPUT:
-             where = &input_reload_insns[rld[j].opnum];
-             break;
-           case RELOAD_FOR_INPUT_ADDRESS:
-             where = &input_address_reload_insns[rld[j].opnum];
-             break;
-           case RELOAD_FOR_INPADDR_ADDRESS:
-             where = &inpaddr_address_reload_insns[rld[j].opnum];
-             break;
-           case RELOAD_FOR_OUTPUT_ADDRESS:
-             where = &output_address_reload_insns[rld[j].opnum];
-             break;
-           case RELOAD_FOR_OUTADDR_ADDRESS:
-             where = &outaddr_address_reload_insns[rld[j].opnum];
-             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;
-           default:
-             abort ();
-           }
+  push_to_sequence (*where);
+
+  /* Auto-increment addresses must be reloaded in a special way.  */
+  if (rl->out && ! rl->out_reg)
+    {
+      /* We are not going to bother supporting the case where a
+        incremented register can't be copied directly from
+        OLDEQUIV since this seems highly unlikely.  */
+      if (rl->secondary_in_reload >= 0)
+       abort ();
+
+      if (reload_inherited[j])
+       oldequiv = reloadreg;
 
-         push_to_sequence (*where);
-         special = 0;
+      old = XEXP (rl->in_reg, 0);
 
-         /* Auto-increment addresses must be reloaded in a special way.  */
-         if (rld[j].out && ! rld[j].out_reg)
+      if (optimize && GET_CODE (oldequiv) == REG
+         && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
+         && spill_reg_store[REGNO (oldequiv)]
+         && GET_CODE (old) == REG
+         && (dead_or_set_p (insn,
+                            spill_reg_stored_to[REGNO (oldequiv)])
+             || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
+                             old)))
+       delete_output_reload (insn, j, REGNO (oldequiv));
+
+      /* Prevent normal processing of this reload.  */
+      special = 1;
+      /* Output a special code sequence for this case.  */
+      new_spill_reg_store[REGNO (reloadreg)]
+       = inc_for_reload (reloadreg, oldequiv, rl->out,
+                         rl->inc);
+    }
+
+  /* If we are reloading a pseudo-register that was set by the previous
+     insn, see if we can get rid of that pseudo-register entirely
+     by redirecting the previous insn into our reload register.  */
+
+  else if (optimize && GET_CODE (old) == REG
+          && REGNO (old) >= FIRST_PSEUDO_REGISTER
+          && dead_or_set_p (insn, old)
+          /* This is unsafe if some other reload
+             uses the same reg first.  */
+          && ! conflicts_with_override (reloadreg)
+          && free_for_value_p (REGNO (reloadreg), rl->mode, rl->opnum,
+                               rl->when_needed, old, rl->out, j, 0))
+    {
+      rtx temp = PREV_INSN (insn);
+      while (temp && GET_CODE (temp) == NOTE)
+       temp = PREV_INSN (temp);
+      if (temp
+         && GET_CODE (temp) == INSN
+         && GET_CODE (PATTERN (temp)) == SET
+         && SET_DEST (PATTERN (temp)) == old
+         /* Make sure we can access insn_operand_constraint.  */
+         && asm_noperands (PATTERN (temp)) < 0
+         /* This is unsafe if prev insn rejects our reload reg.  */
+         && constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
+                                      reloadreg)
+         /* This is unsafe if operand occurs more than once in current
+            insn.  Perhaps some occurrences aren't reloaded.  */
+         && count_occurrences (PATTERN (insn), old, 0) == 1
+         /* Don't risk splitting a matching pair of operands.  */
+         && ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
+       {
+         /* Store into the reload register instead of the pseudo.  */
+         SET_DEST (PATTERN (temp)) = reloadreg;
+
+         /* If the previous insn is an output reload, the source is
+            a reload register, and its spill_reg_store entry will
+            contain the previous destination.  This is now
+            invalid.  */
+         if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
+             && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
            {
-             /* We are not going to bother supporting the case where a
-                incremented register can't be copied directly from
-                OLDEQUIV since this seems highly unlikely.  */
-             if (rld[j].secondary_in_reload >= 0)
-               abort ();
-
-             if (reload_inherited[j])
-               oldequiv = reloadreg;
-
-             old = XEXP (rld[j].in_reg, 0);
-
-             if (optimize && GET_CODE (oldequiv) == REG
-                 && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
-                 && spill_reg_store[REGNO (oldequiv)]
-                 && GET_CODE (old) == REG
-                 && (dead_or_set_p (insn,
-                                    spill_reg_stored_to[REGNO (oldequiv)])
-                     || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)],
-                                     old)))
-               delete_output_reload (insn, j, REGNO (oldequiv));
-
-             /* Prevent normal processing of this reload.  */
-             special = 1;
-             /* Output a special code sequence for this case.  */
-             new_spill_reg_store[REGNO (reloadreg)]
-               = inc_for_reload (reloadreg, oldequiv, rld[j].out,
-                                 rld[j].inc);
+             spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
+             spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
            }
 
-         /* If we are reloading a pseudo-register that was set by the previous
-            insn, see if we can get rid of that pseudo-register entirely
-            by redirecting the previous insn into our reload register.  */
-
-         else if (optimize && GET_CODE (old) == REG
-                  && REGNO (old) >= FIRST_PSEUDO_REGISTER
-                  && dead_or_set_p (insn, old)
-                  /* This is unsafe if some other reload
-                     uses the same reg first.  */
-                  && reload_reg_free_for_value_p (REGNO (reloadreg),
-                                                  rld[j].opnum,
-                                                  rld[j].when_needed,
-                                                  old, rld[j].out,
-                                                  j, 0))
+         /* If these are the only uses of the pseudo reg,
+            pretend for GDB it lives in the reload reg we used.  */
+         if (REG_N_DEATHS (REGNO (old)) == 1
+             && REG_N_SETS (REGNO (old)) == 1)
            {
-             rtx temp = PREV_INSN (insn);
-             while (temp && GET_CODE (temp) == NOTE)
-               temp = PREV_INSN (temp);
-             if (temp
-                 && GET_CODE (temp) == INSN
-                 && GET_CODE (PATTERN (temp)) == SET
-                 && SET_DEST (PATTERN (temp)) == old
-                 /* Make sure we can access insn_operand_constraint.  */
-                 && asm_noperands (PATTERN (temp)) < 0
-                 /* This is unsafe if prev insn rejects our reload reg.  */
-                 && constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
-                                              reloadreg)
-                 /* This is unsafe if operand occurs more than once in current
-                    insn.  Perhaps some occurrences aren't reloaded.  */
-                 && count_occurrences (PATTERN (insn), old) == 1
-                 /* Don't risk splitting a matching pair of operands.  */
-                 && ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
-               {
-                 /* Store into the reload register instead of the pseudo.  */
-                 SET_DEST (PATTERN (temp)) = reloadreg;
-
-                 /* If the previous insn is an output reload, the source is
-                    a reload register, and its spill_reg_store entry will
-                    contain the previous destination.  This is now
-                    invalid.  */
-                 if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
-                     && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
-                   {
-                     spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
-                     spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
-                   }
-
-                 /* If these are the only uses of the pseudo reg,
-                    pretend for GDB it lives in the reload reg we used.  */
-                 if (REG_N_DEATHS (REGNO (old)) == 1
-                     && REG_N_SETS (REGNO (old)) == 1)
-                   {
-                     reg_renumber[REGNO (old)] = REGNO (rld[j].reg_rtx);
-                     alter_reg (REGNO (old), -1);
-                   }
-                 special = 1;
-               }
+             reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
+             alter_reg (REGNO (old), -1);
            }
+         special = 1;
+       }
+    }
 
-         /* We can't do that, so output an insn to load RELOADREG.  */
+  /* We can't do that, so output an insn to load RELOADREG.  */
 
-         if (! special)
-           {
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
-             rtx second_reload_reg = 0;
-             enum insn_code icode;
-
-             /* If we have a secondary reload, pick up the secondary register
-                and icode, if any.  If OLDEQUIV and OLD are different or
-                if this is an in-out reload, recompute whether or not we
-                still need a secondary register and what the icode should
-                be.  If we still need a secondary register and the class or
-                icode is different, go back to reloading from OLD if using
-                OLDEQUIV means that we got the wrong type of register.  We
-                cannot have different class or icode due to an in-out reload
-                because we don't make such reloads when both the input and
-                output need secondary reload registers.  */
-
-             if (rld[j].secondary_in_reload >= 0)
-               {
-                 int secondary_reload = rld[j].secondary_in_reload;
-                 rtx real_oldequiv = oldequiv;
-                 rtx real_old = old;
-                 rtx tmp;
-
-                 /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
-                    and similarly for OLD.
-                    See comments in get_secondary_reload in reload.c.  */
-                 /* If it is a pseudo that cannot be replaced with its
-                    equivalent MEM, we must fall back to reload_in, which
-                    will have all the necessary substitutions registered.
-                    Likewise for a pseudo that can't be replaced with its
-                    equivalent constant.
-
-                    Take extra care for subregs of such pseudos.  Note that
-                    we cannot use reg_equiv_mem in this case because it is
-                    not in the right mode.  */
-
-                 tmp = oldequiv;
-                 if (GET_CODE (tmp) == SUBREG)
-                   tmp = SUBREG_REG (tmp);
-                 if (GET_CODE (tmp) == REG
-                     && REGNO (tmp) >= FIRST_PSEUDO_REGISTER
-                     && (reg_equiv_memory_loc[REGNO (tmp)] != 0
-                         || reg_equiv_constant[REGNO (tmp)] != 0))
-                   {
-                     if (! reg_equiv_mem[REGNO (tmp)]
-                         || num_not_at_initial_offset
-                         || GET_CODE (oldequiv) == SUBREG)
-                       real_oldequiv = rld[j].in;
-                     else
-                       real_oldequiv = reg_equiv_mem[REGNO (tmp)];
-                   }
-
-                 tmp = old;
-                 if (GET_CODE (tmp) == SUBREG)
-                   tmp = SUBREG_REG (tmp);
-                 if (GET_CODE (tmp) == REG
-                     && REGNO (tmp) >= FIRST_PSEUDO_REGISTER
-                     && (reg_equiv_memory_loc[REGNO (tmp)] != 0
-                         || reg_equiv_constant[REGNO (tmp)] != 0))
-                   {
-                     if (! reg_equiv_mem[REGNO (tmp)]
-                         || num_not_at_initial_offset
-                         || GET_CODE (old) == SUBREG)
-                       real_old = rld[j].in;
-                     else
-                       real_old = reg_equiv_mem[REGNO (tmp)];
-                   }
-
-                 second_reload_reg = rld[secondary_reload].reg_rtx;
-                 icode = rld[j].secondary_in_icode;
+  /* If we have a secondary reload, pick up the secondary register
+     and icode, if any.  If OLDEQUIV and OLD are different or
+     if this is an in-out reload, recompute whether or not we
+     still need a secondary register and what the icode should
+     be.  If we still need a secondary register and the class or
+     icode is different, go back to reloading from OLD if using
+     OLDEQUIV means that we got the wrong type of register.  We
+     cannot have different class or icode due to an in-out reload
+     because we don't make such reloads when both the input and
+     output need secondary reload registers.  */
+
+  if (! special && rl->secondary_in_reload >= 0)
+    {
+      rtx second_reload_reg = 0;
+      int secondary_reload = rl->secondary_in_reload;
+      rtx real_oldequiv = oldequiv;
+      rtx real_old = old;
+      rtx tmp;
+      enum insn_code icode;
+
+      /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
+        and similarly for OLD.
+        See comments in get_secondary_reload in reload.c.  */
+      /* If it is a pseudo that cannot be replaced with its
+        equivalent MEM, we must fall back to reload_in, which
+        will have all the necessary substitutions registered.
+        Likewise for a pseudo that can't be replaced with its
+        equivalent constant.
+
+        Take extra care for subregs of such pseudos.  Note that
+        we cannot use reg_equiv_mem in this case because it is
+        not in the right mode.  */
+
+      tmp = oldequiv;
+      if (GET_CODE (tmp) == SUBREG)
+       tmp = SUBREG_REG (tmp);
+      if (GET_CODE (tmp) == REG
+         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER
+         && (reg_equiv_memory_loc[REGNO (tmp)] != 0
+             || reg_equiv_constant[REGNO (tmp)] != 0))
+       {
+         if (! reg_equiv_mem[REGNO (tmp)]
+             || num_not_at_initial_offset
+             || GET_CODE (oldequiv) == SUBREG)
+           real_oldequiv = rl->in;
+         else
+           real_oldequiv = reg_equiv_mem[REGNO (tmp)];
+       }
 
-                 if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
-                     || (rld[j].in != 0 && rld[j].out != 0))
-                   {
-                     enum reg_class new_class
-                       = SECONDARY_INPUT_RELOAD_CLASS (rld[j].class,
-                                                       mode, real_oldequiv);
+      tmp = old;
+      if (GET_CODE (tmp) == SUBREG)
+       tmp = SUBREG_REG (tmp);
+      if (GET_CODE (tmp) == REG
+         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER
+         && (reg_equiv_memory_loc[REGNO (tmp)] != 0
+             || reg_equiv_constant[REGNO (tmp)] != 0))
+       {
+         if (! reg_equiv_mem[REGNO (tmp)]
+             || num_not_at_initial_offset
+             || GET_CODE (old) == SUBREG)
+           real_old = rl->in;
+         else
+           real_old = reg_equiv_mem[REGNO (tmp)];
+       }
 
-                     if (new_class == NO_REGS)
-                       second_reload_reg = 0;
-                     else
-                       {
-                         enum insn_code new_icode;
-                         enum machine_mode new_mode;
+      second_reload_reg = rld[secondary_reload].reg_rtx;
+      icode = rl->secondary_in_icode;
 
-                         if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
-                                                  REGNO (second_reload_reg)))
-                           oldequiv = old, real_oldequiv = real_old;
-                         else
-                           {
-                             new_icode = reload_in_optab[(int) mode];
-                             if (new_icode != CODE_FOR_nothing
-                                 && ((insn_data[(int) new_icode].operand[0].predicate
-                                      && ! ((*insn_data[(int) new_icode].operand[0].predicate)
-                                            (reloadreg, mode)))
-                                     || (insn_data[(int) new_icode].operand[1].predicate
-                                         && ! ((*insn_data[(int) new_icode].operand[1].predicate)
-                                               (real_oldequiv, mode)))))
-                               new_icode = CODE_FOR_nothing;
-
-                             if (new_icode == CODE_FOR_nothing)
-                               new_mode = mode;
-                             else
-                               new_mode = insn_data[(int) new_icode].operand[2].mode;
+      if ((old != oldequiv && ! rtx_equal_p (old, oldequiv))
+         || (rl->in != 0 && rl->out != 0))
+       {
+         enum reg_class new_class
+           = SECONDARY_INPUT_RELOAD_CLASS (rl->class,
+                                           mode, real_oldequiv);
 
-                             if (GET_MODE (second_reload_reg) != new_mode)
-                               {
-                                 if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
-                                                          new_mode))
-                                   oldequiv = old, real_oldequiv = real_old;
-                                 else
-                                   second_reload_reg
-                                     = gen_rtx_REG (new_mode,
-                                                    REGNO (second_reload_reg));
-                               }
-                           }
-                       }
-                   }
+         if (new_class == NO_REGS)
+           second_reload_reg = 0;
+         else
+           {
+             enum insn_code new_icode;
+             enum machine_mode new_mode;
 
-                 /* If we still need a secondary reload register, check
-                    to see if it is being used as a scratch or intermediate
-                    register and generate code appropriately.  If we need
-                    a scratch register, use REAL_OLDEQUIV since the form of
-                    the insn may depend on the actual address if it is
-                    a MEM.  */
+             if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
+                                      REGNO (second_reload_reg)))
+               oldequiv = old, real_oldequiv = real_old;
+             else
+               {
+                 new_icode = reload_in_optab[(int) mode];
+                 if (new_icode != CODE_FOR_nothing
+                     && ((insn_data[(int) new_icode].operand[0].predicate
+                          && ! ((*insn_data[(int) new_icode].operand[0].predicate)
+                                (reloadreg, mode)))
+                         || (insn_data[(int) new_icode].operand[1].predicate
+                             && ! ((*insn_data[(int) new_icode].operand[1].predicate)
+                                   (real_oldequiv, mode)))))
+                   new_icode = CODE_FOR_nothing;
+
+                 if (new_icode == CODE_FOR_nothing)
+                   new_mode = mode;
+                 else
+                   new_mode = insn_data[(int) new_icode].operand[2].mode;
 
-                 if (second_reload_reg)
+                 if (GET_MODE (second_reload_reg) != new_mode)
                    {
-                     if (icode != CODE_FOR_nothing)
-                       {
-                         emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
-                                                     second_reload_reg));
-                         special = 1;
-                       }
+                     if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
+                                              new_mode))
+                       oldequiv = old, real_oldequiv = real_old;
                      else
-                       {
-                         /* See if we need a scratch register to load the
-                            intermediate register (a tertiary reload).  */
-                         enum insn_code tertiary_icode
-                           = rld[secondary_reload].secondary_in_icode;
-
-                         if (tertiary_icode != CODE_FOR_nothing)
-                           {
-                             rtx third_reload_reg
-                               = rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
-
-                             emit_insn ((GEN_FCN (tertiary_icode)
-                                         (second_reload_reg, real_oldequiv,
-                                          third_reload_reg)));
-                           }
-                         else
-                           gen_reload (second_reload_reg, real_oldequiv,
-                                       rld[j].opnum,
-                                       rld[j].when_needed);
-
-                         oldequiv = second_reload_reg;
-                       }
+                       second_reload_reg
+                         = gen_rtx_REG (new_mode,
+                                        REGNO (second_reload_reg));
                    }
                }
-#endif
-
-             if (! special && ! rtx_equal_p (reloadreg, oldequiv))
-               {
-                 rtx real_oldequiv = oldequiv;
-
-                 if ((GET_CODE (oldequiv) == REG
-                      && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
-                      && (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
-                          || reg_equiv_constant[REGNO (oldequiv)] != 0))
-                     || (GET_CODE (oldequiv) == SUBREG
-                         && GET_CODE (SUBREG_REG (oldequiv)) == REG
-                         && (REGNO (SUBREG_REG (oldequiv))
-                             >= FIRST_PSEUDO_REGISTER)
-                         && ((reg_equiv_memory_loc
-                              [REGNO (SUBREG_REG (oldequiv))] != 0)
-                             || (reg_equiv_constant
-                                 [REGNO (SUBREG_REG (oldequiv))] != 0))))
-                   real_oldequiv = rld[j].in;
-                 gen_reload (reloadreg, real_oldequiv, rld[j].opnum,
-                             rld[j].when_needed);
-               }
-
            }
-
-         this_reload_insn = get_last_insn ();
-         /* End this sequence.  */
-         *where = get_insns ();
-         end_sequence ();
-
-         /* Update reload_override_in so that delete_address_reloads_1
-            can see the actual register usage.  */
-         if (oldequiv_reg)
-           reload_override_in[j] = oldequiv;
-       }
-
-      /* When inheriting a wider reload, we have a MEM in rld[j].in,
-        e.g. inheriting a SImode output reload for
-        (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10)))  */
-      if (optimize && reload_inherited[j] && rld[j].in
-         && GET_CODE (rld[j].in) == MEM
-         && GET_CODE (rld[j].in_reg) == MEM
-         && reload_spill_index[j] >= 0
-         && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
-       {
-         expect_occurrences
-           = count_occurrences (PATTERN (insn), rld[j].in) == 1 ? 0 : -1;
-         rld[j].in
-           = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
        }
 
-      /* If we are reloading 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
-         && (reload_inherited[j] || reload_override_in[j])
-         && rld[j].reg_rtx
-         && GET_CODE (rld[j].reg_rtx) == REG
-         && spill_reg_store[REGNO (rld[j].reg_rtx)] != 0
-#if 0
-         /* There doesn't seem to be any reason to restrict this to pseudos
-            and doing so loses in the case where we are copying from a
-            register of the wrong class.  */
-         && (REGNO (spill_reg_stored_to[REGNO (rld[j].reg_rtx)])
-             >= FIRST_PSEUDO_REGISTER)
-#endif
-         /* The insn might have already some references to stackslots
-            replaced by MEMs, while reload_out_reg still names the
-            original pseudo.  */
-         && (dead_or_set_p (insn,
-                            spill_reg_stored_to[REGNO (rld[j].reg_rtx)])
-             || rtx_equal_p (spill_reg_stored_to[REGNO (rld[j].reg_rtx)],
-                             rld[j].out_reg)))
-       delete_output_reload (insn, j, REGNO (rld[j].reg_rtx));
-
-      /* Input-reloading is done.  Now do output-reloading,
-        storing the value from the reload-register after the main insn
-        if rld[j].out is nonzero.
-
-        ??? At some point we need to support handling output reloads of
-        JUMP_INSNs or insns that set cc0.  */
+      /* If we still need a secondary reload register, check
+        to see if it is being used as a scratch or intermediate
+        register and generate code appropriately.  If we need
+        a scratch register, use REAL_OLDEQUIV since the form of
+        the insn may depend on the actual address if it is
+        a MEM.  */
 
-      /* If this is an output reload that stores something that is
-        not loaded in this same reload, see if we can eliminate a previous
-        store.  */
-      {
-       rtx pseudo = rld[j].out_reg;
-
-       if (pseudo
-           && GET_CODE (pseudo) == REG
-           && ! rtx_equal_p (rld[j].in_reg, pseudo)
-           && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
-           && reg_last_reload_reg[REGNO (pseudo)])
-         {
-           int pseudo_no = REGNO (pseudo);
-           int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
-
-           /* We don't need to test full validity of last_regno for
-              inherit here; we only want to know if the store actually
-              matches the pseudo.  */
-           if (reg_reloaded_contents[last_regno] == pseudo_no
-               && spill_reg_store[last_regno]
-               && rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
-             delete_output_reload (insn, j, last_regno);
-         }
-      }
-
-      old = rld[j].out_reg;
-      if (old != 0
-         && rld[j].reg_rtx != old
-         && rld[j].reg_rtx != 0)
+      if (second_reload_reg)
        {
-         register rtx reloadreg = rld[j].reg_rtx;
-#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-         register rtx second_reloadreg = 0;
-#endif
-         rtx note, p;
-         enum machine_mode mode;
-         int special = 0;
-
-         /* An output operand that dies right away does need a reload,
-            but need not be copied from it.  Show the new location in the
-            REG_UNUSED note.  */
-         if ((GET_CODE (old) == REG || GET_CODE (old) == SCRATCH)
-             && (note = find_reg_note (insn, REG_UNUSED, old)) != 0)
+         if (icode != CODE_FOR_nothing)
            {
-             XEXP (note, 0) = rld[j].reg_rtx;
-             continue;
+             emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
+                                         second_reload_reg));
+             special = 1;
            }
-         /* 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))))
+         else
            {
-             XEXP (note, 0) = gen_lowpart_common (GET_MODE (old),
-                                                  rld[j].reg_rtx);
-             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.  */
-           continue;
+             /* See if we need a scratch register to load the
+                intermediate register (a tertiary reload).  */
+             enum insn_code tertiary_icode
+               = rld[secondary_reload].secondary_in_icode;
 
-#if 0
-         /* Strip off of OLD any size-increasing SUBREGs such as
-            (SUBREG:SI foo:QI 0).  */
+             if (tertiary_icode != CODE_FOR_nothing)
+               {
+                 rtx third_reload_reg
+                   = rld[rld[secondary_reload].secondary_in_reload].reg_rtx;
+
+                 emit_insn ((GEN_FCN (tertiary_icode)
+                             (second_reload_reg, real_oldequiv,
+                              third_reload_reg)));
+               }
+             else
+               gen_reload (second_reload_reg, real_oldequiv,
+                           rl->opnum,
+                           rl->when_needed);
 
-         while (GET_CODE (old) == SUBREG && SUBREG_WORD (old) == 0
-                && (GET_MODE_SIZE (GET_MODE (old))
-                    > GET_MODE_SIZE (GET_MODE (SUBREG_REG (old)))))
-           old = SUBREG_REG (old);
+             oldequiv = second_reload_reg;
+           }
+       }
+    }
 #endif
 
-         /* If is a JUMP_INSN, we can't support output reloads yet.  */
-         if (GET_CODE (insn) == JUMP_INSN)
-           abort ();
+  if (! special && ! rtx_equal_p (reloadreg, oldequiv))
+    {
+      rtx real_oldequiv = oldequiv;
+
+      if ((GET_CODE (oldequiv) == REG
+          && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
+          && (reg_equiv_memory_loc[REGNO (oldequiv)] != 0
+              || reg_equiv_constant[REGNO (oldequiv)] != 0))
+         || (GET_CODE (oldequiv) == SUBREG
+             && GET_CODE (SUBREG_REG (oldequiv)) == REG
+             && (REGNO (SUBREG_REG (oldequiv))
+                 >= FIRST_PSEUDO_REGISTER)
+             && ((reg_equiv_memory_loc
+                  [REGNO (SUBREG_REG (oldequiv))] != 0)
+                 || (reg_equiv_constant
+                     [REGNO (SUBREG_REG (oldequiv))] != 0)))
+         || (CONSTANT_P (oldequiv)
+             && PREFERRED_RELOAD_CLASS (oldequiv,
+                       REGNO_REG_CLASS (REGNO (reloadreg))) == NO_REGS))
+       real_oldequiv = rl->in;
+      gen_reload (reloadreg, real_oldequiv, rl->opnum,
+                 rl->when_needed);
+    }
+
+  if (flag_non_call_exceptions)
+    copy_eh_notes (insn, get_insns ());
+
+  /* End this sequence.  */
+  *where = get_insns ();
+  end_sequence ();
+                                
+  /* Update reload_override_in so that delete_address_reloads_1
+     can see the actual register usage.  */
+  if (oldequiv_reg)
+    reload_override_in[j] = oldequiv;
+}
 
-         if (rld[j].when_needed == RELOAD_OTHER)
-           start_sequence ();
-         else
-           push_to_sequence (output_reload_insns[rld[j].opnum]);
+/* Generate insns to for the output reload RL, which is for the insn described
+   by CHAIN and has the number J.  */
+static void
+emit_output_reload_insns (chain, rl, j)
+     struct insn_chain *chain;
+     struct reload *rl;
+     int j;
+{
+  rtx reloadreg = rl->reg_rtx;
+  rtx insn = chain->insn;
+  int special = 0;
+  rtx old = rl->out;
+  enum machine_mode mode = GET_MODE (old);
+  rtx p;
 
-         old = rld[j].out;
+  if (rl->when_needed == RELOAD_OTHER)
+    start_sequence ();
+  else
+    push_to_sequence (output_reload_insns[rl->opnum]);
 
-         /* Determine the mode to reload in.
-            See comments above (for input reloading).  */
+  /* Determine the mode to reload in.
+     See comments above (for input reloading).  */
 
-         mode = GET_MODE (old);
-         if (mode == VOIDmode)
-           {
-             /* VOIDmode should never happen for an output.  */
-             if (asm_noperands (PATTERN (insn)) < 0)
-               /* It's the compiler's fault.  */
-               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;
-             old = gen_rtx_REG (mode, REGNO (reloadreg));
-           }
+  if (mode == VOIDmode)
+    {
+      /* VOIDmode should never happen for an output.  */
+      if (asm_noperands (PATTERN (insn)) < 0)
+       /* It's the compiler's fault.  */
+       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;
+      old = gen_rtx_REG (mode, REGNO (reloadreg));
+    }
 
-         if (GET_MODE (reloadreg) != mode)
-           reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+  if (GET_MODE (reloadreg) != mode)
+    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
-         /* If we need two reload regs, set RELOADREG to the intermediate
-            one, since it will be stored into OLD.  We might need a secondary
-            register only for an input reload, so check again here.  */
+  /* If we need two reload regs, set RELOADREG to the intermediate
+     one, since it will be stored into OLD.  We might need a secondary
+     register only for an input reload, so check again here.  */
 
-         if (rld[j].secondary_out_reload >= 0)
-           {
-             rtx real_old = old;
+  if (rl->secondary_out_reload >= 0)
+    {
+      rtx real_old = old;
 
-             if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
-                 && reg_equiv_mem[REGNO (old)] != 0)
-               real_old = reg_equiv_mem[REGNO (old)];
+      if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
+         && reg_equiv_mem[REGNO (old)] != 0)
+       real_old = reg_equiv_mem[REGNO (old)];
 
-             if((SECONDARY_OUTPUT_RELOAD_CLASS (rld[j].class,
-                                                mode, real_old)
-                 != NO_REGS))
-               {
-                 second_reloadreg = reloadreg;
-                 reloadreg = rld[rld[j].secondary_out_reload].reg_rtx;
+      if ((SECONDARY_OUTPUT_RELOAD_CLASS (rl->class,
+                                         mode, real_old)
+          != NO_REGS))
+       {
+         rtx second_reloadreg = reloadreg;
+         reloadreg = rld[rl->secondary_out_reload].reg_rtx;
 
-                 /* See if RELOADREG is to be used as a scratch register
-                    or as an intermediate register.  */
-                 if (rld[j].secondary_out_icode != CODE_FOR_nothing)
-                   {
-                     emit_insn ((GEN_FCN (rld[j].secondary_out_icode)
-                                 (real_old, second_reloadreg, reloadreg)));
-                     special = 1;
-                   }
-                 else
-                   {
-                     /* See if we need both a scratch and intermediate reload
-                        register.  */
+         /* See if RELOADREG is to be used as a scratch register
+            or as an intermediate register.  */
+         if (rl->secondary_out_icode != CODE_FOR_nothing)
+           {
+             emit_insn ((GEN_FCN (rl->secondary_out_icode)
+                         (real_old, second_reloadreg, reloadreg)));
+             special = 1;
+           }
+         else
+           {
+             /* See if we need both a scratch and intermediate reload
+                register.  */
 
-                     int secondary_reload = rld[j].secondary_out_reload;
-                     enum insn_code tertiary_icode
-                       = rld[secondary_reload].secondary_out_icode;
+             int secondary_reload = rl->secondary_out_reload;
+             enum insn_code tertiary_icode
+               = rld[secondary_reload].secondary_out_icode;
 
-                     if (GET_MODE (reloadreg) != mode)
-                       reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+             if (GET_MODE (reloadreg) != mode)
+               reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
 
-                     if (tertiary_icode != CODE_FOR_nothing)
-                       {
-                         rtx third_reloadreg
-                           = rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
-                         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,
-                                     rld[j].opnum, rld[j].when_needed);
-                         emit_insn ((GEN_FCN (tertiary_icode)
-                                     (real_old, reloadreg, third_reloadreg)));
-                         special = 1;
-                       }
+             if (tertiary_icode != CODE_FOR_nothing)
+               {
+                 rtx third_reloadreg
+                   = rld[rld[secondary_reload].secondary_out_reload].reg_rtx;
+                 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,
+                             rl->opnum, rl->when_needed);
+                 emit_insn ((GEN_FCN (tertiary_icode)
+                             (real_old, reloadreg, third_reloadreg)));
+                 special = 1;
+               }
 
-                     else
-                       /* Copy between the reload regs here and then to
-                          OUT later.  */
+             else
+               /* Copy between the reload regs here and then to
+                  OUT later.  */
 
-                       gen_reload (reloadreg, second_reloadreg,
-                                   rld[j].opnum, rld[j].when_needed);
-                   }
-               }
+               gen_reload (reloadreg, second_reloadreg,
+                           rl->opnum, rl->when_needed);
            }
+       }
+    }
 #endif
 
-         /* Output the last reload insn.  */
-         if (! special)
-           {
-             rtx set;
-
-             /* Don't output the last reload if OLD is not the dest of
-                INSN and is in the src and is clobbered by INSN. */
-             if (! flag_expensive_optimizations
-                 || GET_CODE (old) != REG
-                 || !(set = single_set (insn))
-                 || rtx_equal_p (old, SET_DEST (set))
-                 || !reg_mentioned_p (old, SET_SRC (set))
-                 || !regno_clobbered_p (REGNO (old), insn))
-               gen_reload (old, reloadreg, rld[j].opnum,
-                           rld[j].when_needed);
-           }
+  /* Output the last reload insn.  */
+  if (! special)
+    {
+      rtx set;
 
-         /* Look at all insns we emitted, just to be safe.  */
-         for (p = get_insns (); p; p = NEXT_INSN (p))
-           if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
-             {
-               rtx pat = PATTERN (p);
+      /* Don't output the last reload if OLD is not the dest of
+        INSN and is in the src and is clobbered by INSN.  */
+      if (! flag_expensive_optimizations
+         || GET_CODE (old) != REG
+         || !(set = single_set (insn))
+         || rtx_equal_p (old, SET_DEST (set))
+         || !reg_mentioned_p (old, SET_SRC (set))
+         || !regno_clobbered_p (REGNO (old), insn, rl->mode, 0))
+       gen_reload (old, reloadreg, rl->opnum,
+                   rl->when_needed);
+    }
+
+  /* Look at all insns we emitted, just to be safe.  */
+  for (p = get_insns (); p; p = NEXT_INSN (p))
+    if (INSN_P (p))
+      {
+       rtx pat = PATTERN (p);
 
-               /* If this output reload doesn't come from a spill reg,
-                  clear any memory of reloaded copies of the pseudo reg.
-                  If this output reload comes from a spill reg,
-                  reg_has_output_reload will make this do nothing.  */
-               note_stores (pat, forget_old_reloads_1, NULL);
+       /* If this output reload doesn't come from a spill reg,
+          clear any memory of reloaded copies of the pseudo reg.
+          If this output reload comes from a spill reg,
+          reg_has_output_reload will make this do nothing.  */
+       note_stores (pat, forget_old_reloads_1, NULL);
 
-               if (reg_mentioned_p (rld[j].reg_rtx, pat))
-                 {
-                   rtx set = single_set (insn);
-                   if (reload_spill_index[j] < 0
-                       && set
-                       && SET_SRC (set) == rld[j].reg_rtx)
-                     {
-                       int src = REGNO (SET_SRC (set));
+       if (reg_mentioned_p (rl->reg_rtx, pat))
+         {
+           rtx set = single_set (insn);
+           if (reload_spill_index[j] < 0
+               && set
+               && SET_SRC (set) == rl->reg_rtx)
+             {
+               int src = REGNO (SET_SRC (set));
 
-                       reload_spill_index[j] = src;
-                       SET_HARD_REG_BIT (reg_is_output_reload, src);
-                       if (find_regno_note (insn, REG_DEAD, src))
-                         SET_HARD_REG_BIT (reg_reloaded_died, src);
-                     }
-                   if (REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
+               reload_spill_index[j] = src;
+               SET_HARD_REG_BIT (reg_is_output_reload, src);
+               if (find_regno_note (insn, REG_DEAD, src))
+                 SET_HARD_REG_BIT (reg_reloaded_died, src);
+             }
+           if (REGNO (rl->reg_rtx) < FIRST_PSEUDO_REGISTER)
+             {
+               int s = rl->secondary_out_reload;
+               set = single_set (p);
+               /* If this reload copies only to the secondary reload
+                  register, the secondary reload does the actual
+                  store.  */
+               if (s >= 0 && set == NULL_RTX)
+                 /* We can't tell what function the secondary reload
+                    has and where the actual store to the pseudo is
+                    made; leave new_spill_reg_store alone.  */
+                 ;
+               else if (s >= 0
+                        && SET_SRC (set) == rl->reg_rtx
+                        && SET_DEST (set) == rld[s].reg_rtx)
+                 {
+                   /* Usually the next instruction will be the
+                      secondary reload insn;  if we can confirm
+                      that it is, setting new_spill_reg_store to
+                      that insn will allow an extra optimization.  */
+                   rtx s_reg = rld[s].reg_rtx;
+                   rtx next = NEXT_INSN (p);
+                   rld[s].out = rl->out;
+                   rld[s].out_reg = rl->out_reg;
+                   set = single_set (next);
+                   if (set && SET_SRC (set) == s_reg
+                       && ! new_spill_reg_store[REGNO (s_reg)])
                      {
-                       int s = rld[j].secondary_out_reload;
-                       set = single_set (p);
-                       /* If this reload copies only to the secondary reload
-                          register, the secondary reload does the actual
-                          store.  */
-                       if (s >= 0 && set == NULL_RTX)
-                         ; /* We can't tell what function the secondary reload
-                              has and where the actual store to the pseudo is
-                              made; leave new_spill_reg_store alone.  */
-                       else if (s >= 0
-                                && SET_SRC (set) == rld[j].reg_rtx
-                                && SET_DEST (set) == rld[s].reg_rtx)
-                         {
-                           /* Usually the next instruction will be the
-                              secondary reload insn;  if we can confirm
-                              that it is, setting new_spill_reg_store to
-                              that insn will allow an extra optimization.  */
-                           rtx s_reg = rld[s].reg_rtx;
-                           rtx next = NEXT_INSN (p);
-                           rld[s].out = rld[j].out;
-                           rld[s].out_reg = rld[j].out_reg;
-                           set = single_set (next);
-                           if (set && SET_SRC (set) == s_reg
-                               && ! new_spill_reg_store[REGNO (s_reg)])
-                             {
-                               SET_HARD_REG_BIT (reg_is_output_reload,
-                                                 REGNO (s_reg));
-                               new_spill_reg_store[REGNO (s_reg)] = next;
-                             }
-                         }
-                       else
-                         new_spill_reg_store[REGNO (rld[j].reg_rtx)] = p;
+                       SET_HARD_REG_BIT (reg_is_output_reload,
+                                         REGNO (s_reg));
+                       new_spill_reg_store[REGNO (s_reg)] = next;
                      }
                  }
+               else
+                 new_spill_reg_store[REGNO (rl->reg_rtx)] = p;
              }
+         }
+      }
 
-         if (rld[j].when_needed == RELOAD_OTHER)
-           {
-             emit_insns (other_output_reload_insns[rld[j].opnum]);
-             other_output_reload_insns[rld[j].opnum] = get_insns ();
-           }
-         else
-           output_reload_insns[rld[j].opnum] = get_insns ();
-
-         end_sequence ();
-       }
+  if (rl->when_needed == RELOAD_OTHER)
+    {
+      emit_insns (other_output_reload_insns[rl->opnum]);
+      other_output_reload_insns[rl->opnum] = get_insns ();
     }
+  else
+    output_reload_insns[rl->opnum] = get_insns ();
 
-  /* Now write all the insns we made for reloads in the order expected by
+  if (flag_non_call_exceptions)
+    copy_eh_notes (insn, get_insns ());
+
+  end_sequence ();
+}
+
+/* Do input reloading for reload RL, which is for the insn described by CHAIN
+   and has the number J.  */
+static void
+do_input_reload (chain, rl, j)
+     struct insn_chain *chain;
+     struct reload *rl;
+     int j;
+{
+  int expect_occurrences = 1;
+  rtx insn = chain->insn;
+  rtx old = (rl->in && GET_CODE (rl->in) == MEM
+            ? rl->in_reg : rl->in);
+
+  if (old != 0
+      /* AUTO_INC reloads need to be handled even if inherited.  We got an
+        AUTO_INC reload if reload_out is set but reload_out_reg isn't.  */
+      && (! reload_inherited[j] || (rl->out && ! rl->out_reg))
+      && ! rtx_equal_p (rl->reg_rtx, old)
+      && rl->reg_rtx != 0)
+    emit_input_reload_insns (chain, rld + j, old, j);
+
+  /* When inheriting a wider reload, we have a MEM in rl->in,
+     e.g. inheriting a SImode output reload for
+     (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10)))  */
+  if (optimize && reload_inherited[j] && rl->in
+      && GET_CODE (rl->in) == MEM
+      && GET_CODE (rl->in_reg) == MEM
+      && reload_spill_index[j] >= 0
+      && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
+    {
+      expect_occurrences
+       = count_occurrences (PATTERN (insn), rl->in, 0) == 1 ? 0 : -1;
+      rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
+    }
+
+  /* If we are reloading 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
+      && (reload_inherited[j] || reload_override_in[j])
+      && rl->reg_rtx
+      && GET_CODE (rl->reg_rtx) == REG
+      && spill_reg_store[REGNO (rl->reg_rtx)] != 0
+#if 0
+      /* There doesn't seem to be any reason to restrict this to pseudos
+        and doing so loses in the case where we are copying from a
+        register of the wrong class.  */
+      && (REGNO (spill_reg_stored_to[REGNO (rl->reg_rtx)])
+         >= FIRST_PSEUDO_REGISTER)
+#endif
+      /* The insn might have already some references to stackslots
+        replaced by MEMs, while reload_out_reg still names the
+        original pseudo.  */
+      && (dead_or_set_p (insn,
+                        spill_reg_stored_to[REGNO (rl->reg_rtx)])
+         || rtx_equal_p (spill_reg_stored_to[REGNO (rl->reg_rtx)],
+                         rl->out_reg)))
+    delete_output_reload (insn, j, REGNO (rl->reg_rtx));
+}
+
+/* Do output reloading for reload RL, which is for the insn described by
+   CHAIN and has the number J.
+   ??? At some point we need to support handling output reloads of
+   JUMP_INSNs or insns that set cc0.  */
+static void
+do_output_reload (chain, rl, j)
+     struct insn_chain *chain;
+     struct reload *rl;
+     int j;
+{
+  rtx note, old;
+  rtx insn = chain->insn;
+  /* If this is an output reload that stores something that is
+     not loaded in this same reload, see if we can eliminate a previous
+     store.  */
+  rtx pseudo = rl->out_reg;
+
+  if (pseudo
+      && GET_CODE (pseudo) == REG
+      && ! rtx_equal_p (rl->in_reg, pseudo)
+      && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
+      && reg_last_reload_reg[REGNO (pseudo)])
+    {
+      int pseudo_no = REGNO (pseudo);
+      int last_regno = REGNO (reg_last_reload_reg[pseudo_no]);
+
+      /* We don't need to test full validity of last_regno for
+        inherit here; we only want to know if the store actually
+        matches the pseudo.  */
+      if (TEST_HARD_REG_BIT (reg_reloaded_valid, last_regno)
+         && reg_reloaded_contents[last_regno] == pseudo_no
+         && spill_reg_store[last_regno]
+         && rtx_equal_p (pseudo, spill_reg_stored_to[last_regno]))
+       delete_output_reload (insn, j, last_regno);
+    }
+
+  old = rl->out_reg;
+  if (old == 0
+      || rl->reg_rtx == old
+      || rl->reg_rtx == 0)
+    return;
+
+  /* An output operand that dies right away does need a reload,
+     but need not be copied from it.  Show the new location in the
+     REG_UNUSED note.  */
+  if ((GET_CODE (old) == REG || GET_CODE (old) == SCRATCH)
+      && (note = find_reg_note (insn, REG_UNUSED, old)) != 0)
+    {
+      XEXP (note, 0) = rl->reg_rtx;
+      return;
+    }
+  /* 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),
+                                          rl->reg_rtx);
+      return;
+    }
+  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.  */
+    return;
+
+  /* If is a JUMP_INSN, we can't support output reloads yet.  */
+  if (GET_CODE (insn) == JUMP_INSN)
+    abort ();
+
+  emit_output_reload_insns (chain, rld + j, j);
+}
+
+/* Output insns to reload values in and out of the chosen reload regs.  */
+
+static void
+emit_reload_insns (chain)
+     struct insn_chain *chain;
+{
+  rtx insn = chain->insn;
+
+  register int j;
+  rtx following_insn = NEXT_INSN (insn);
+  rtx before_insn = PREV_INSN (insn);
+
+  CLEAR_HARD_REG_SET (reg_reloaded_died);
+
+  for (j = 0; j < reload_n_operands; j++)
+    input_reload_insns[j] = input_address_reload_insns[j]
+      = 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;
+  other_input_address_reload_insns = 0;
+  other_input_reload_insns = 0;
+  operand_reload_insns = 0;
+  other_operand_reload_insns = 0;
+
+  /* Dump reloads into the dump file.  */
+  if (rtl_dump_file)
+    {
+      fprintf (rtl_dump_file, "\nReloads for insn # %d\n", INSN_UID (insn));
+      debug_reload_to_stream (rtl_dump_file);
+    }
+
+  /* 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,
+     since reloads of base and index registers precede reloads of operands
+     and the operands may need the base and index registers reloaded.  */
+
+  for (j = 0; j < n_reloads; j++)
+    {
+      if (rld[j].reg_rtx
+         && REGNO (rld[j].reg_rtx) < FIRST_PSEUDO_REGISTER)
+       new_spill_reg_store[REGNO (rld[j].reg_rtx)] = 0;
+
+      do_input_reload (chain, rld + j, j);
+      do_output_reload (chain, rld + j, j);
+    }
+
+  /* Now write all the insns we made for reloads in the order expected by
      the allocation functions.  Prior to the insn being reloaded, we write
      the following reloads:
 
@@ -7488,8 +7080,7 @@ emit_reload_insns (chain)
 
       if (i >= 0 && rld[r].reg_rtx != 0)
        {
-         int nr
-           = HARD_REGNO_NREGS (i, GET_MODE (rld[r].reg_rtx));
+         int nr = HARD_REGNO_NREGS (i, GET_MODE (rld[r].reg_rtx));
          int k;
          int part_reaches_end = 0;
          int all_reaches_end = 1;
@@ -7715,7 +7306,7 @@ emit_reload_insns (chain)
            }
          else
            {
-             int num_regs = HARD_REGNO_NREGS (nregno,GET_MODE (rld[r].out));
+             int num_regs = HARD_REGNO_NREGS (nregno, GET_MODE (rld[r].out));
 
              while (num_regs-- > 0)
                reg_last_reload_reg[nregno + num_regs] = 0;
@@ -8006,9 +7597,9 @@ delete_output_reload (insn, j, last_reload_reg)
            return;
        }
     }
-  n_occurrences = count_occurrences (PATTERN (insn), reg);
+  n_occurrences = count_occurrences (PATTERN (insn), reg, 0);
   if (substed)
-    n_occurrences += count_occurrences (PATTERN (insn), substed);
+    n_occurrences += count_occurrences (PATTERN (insn), substed, 0);
   if (n_occurrences > n_inherited)
     return;
 
@@ -8148,7 +7739,7 @@ delete_address_reloads (dead_insn, current_insn)
       || ! rtx_equal_p (dst, XEXP (SET_SRC (set), 0))
       || ! rtx_equal_p (dst, XEXP (SET_SRC (set2), 0))
       || (INTVAL (XEXP (SET_SRC (set), 1))
-         != - INTVAL (XEXP (SET_SRC (set2), 1))))
+         != -INTVAL (XEXP (SET_SRC (set2), 1))))
     return;
   delete_insn (prev);
   delete_insn (next);
@@ -8165,14 +7756,14 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
 
   if (code != REG)
     {
-      const char *fmt= GET_RTX_FORMAT (code);
+      const char *fmt = GET_RTX_FORMAT (code);
       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
        {
          if (fmt[i] == 'e')
            delete_address_reloads_1 (dead_insn, XEXP (x, i), current_insn);
          else if (fmt[i] == 'E')
            {
-             for (j = XVECLEN (x, i) - 1; j >=0; j--)
+             for (j = XVECLEN (x, i) - 1; j >= 0; j--)
                delete_address_reloads_1 (dead_insn, XVECEXP (x, i, j),
                                          current_insn);
            }
@@ -8215,7 +7806,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
        {
          if (GET_CODE (i2) == CODE_LABEL)
            break;
-         if (GET_RTX_CLASS (GET_CODE (i2)) != 'i')
+         if (! INSN_P (i2))
            continue;
          if (reg_referenced_p (dst, PATTERN (i2)))
            {
@@ -8302,7 +7893,7 @@ inc_for_reload (reloadreg, in, value, inc_amount)
     reg_last_reload_reg[REGNO (incloc)] = 0;
 
   if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC)
-    inc_amount = - inc_amount;
+    inc_amount = -inc_amount;
 
   inc = GEN_INT (inc_amount);
 
@@ -8415,298 +8006,117 @@ constraint_accepts_reg_p (string, reg)
       }
 }
 \f
-/* Return the number of places FIND appears within X, but don't count
-   an occurrence if some SET_DEST is FIND.  */
-
-int
-count_occurrences (x, find)
-     register rtx x, find;
+/* INSN is a no-op; delete it.
+   If this sets the return value of the function, we must keep a USE around,
+   in case this is in a different basic block than the final USE.  Otherwise,
+   we could loose important register lifeness information on
+   SMALL_REGISTER_CLASSES machines, where return registers might be used as
+   spills:  subsequent passes assume that spill registers are dead at the end
+   of a basic block.
+   VALUE must be the return value in such a case, NULL otherwise.  */
+static void
+reload_cse_delete_noop_set (insn, value)
+     rtx insn, value;
 {
-  register int i, j;
-  register enum rtx_code code;
-  register const char *format_ptr;
-  int count;
-
-  if (x == find)
-    return 1;
-  if (x == 0)
-    return 0;
-
-  code = GET_CODE (x);
-
-  switch (code)
+  if (value)
     {
-    case REG:
-    case QUEUED:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case SYMBOL_REF:
-    case CODE_LABEL:
-    case PC:
-    case CC0:
-      return 0;
-
-    case MEM:
-      if (GET_CODE (find) == MEM && rtx_equal_p (x, find))
-       return 1;
-      break;
-    case SET:
-      if (SET_DEST (x) == find)
-       return count_occurrences (SET_SRC (x), find);
-      break;
-
-    default:
-      break;
+      PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
+      INSN_CODE (insn) = -1;
+      REG_NOTES (insn) = NULL_RTX;
     }
-
-  format_ptr = GET_RTX_FORMAT (code);
-  count = 0;
-
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+  else
     {
-      switch (*format_ptr++)
-       {
-       case 'e':
-         count += count_occurrences (XEXP (x, i), find);
-         break;
-
-       case 'E':
-         if (XVEC (x, i) != NULL)
-           {
-             for (j = 0; j < XVECLEN (x, i); j++)
-               count += count_occurrences (XVECEXP (x, i, j), find);
-           }
-         break;
-       }
+      PUT_CODE (insn, NOTE);
+      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+      NOTE_SOURCE_FILE (insn) = 0;
     }
-  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.  */
+/* See whether a single set SET is a noop.  */
+static int
+reload_cse_noop_set_p (set)
+     rtx set;
+{
+  return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
+}
 
+/* Try to simplify INSN.  */
 static void
-reload_cse_invalidate_regno (regno, mode, clobber)
-     int regno;
-     enum machine_mode mode;
-     int clobber;
+reload_cse_simplify (insn)
+     rtx insn;
 {
-  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;
+  rtx body = PATTERN (insn);
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  if (GET_CODE (body) == SET)
     {
-      rtx x;
+      int count = 0;
+
+      /* Simplify even if we may think it is a no-op.
+         We may think a memory load of a value smaller than WORD_SIZE
+         is redundant because we haven't taken into account possible
+         implicit extension.  reload_cse_simplify_set() will bring
+         this out, so it's safer to simplify before we delete.  */
+      count += reload_cse_simplify_set (body, insn);
 
-      for (x = reg_values[i]; x; x = XEXP (x, 1))
+      if (!count && reload_cse_noop_set_p (body))
        {
-         if (XEXP (x, 0) != 0
-             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
-           {
-             /* 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;
-           }
+         rtx value = SET_DEST (body);
+         if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
+           value = 0;
+         reload_cse_delete_noop_set (insn, value);
+         return;
        }
-    }
-
-  /* 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++)
+      if (count > 0)
+       apply_change_group ();
+      else
+       reload_cse_simplify_operands (insn);
+    }
+  else if (GET_CODE (body) == PARALLEL)
     {
-      rtx x;
+      int i;
+      int count = 0;
+      rtx value = NULL_RTX;
 
-      for (x = reg_values[i]; x; x = XEXP (x, 1))
+      /* 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 (XEXP (x, 0) != 0)
+         rtx part = XVECEXP (body, 0, i);
+         if (GET_CODE (part) == SET)
            {
-             PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
-             REGNO (invalidate_regno_rtx) = i;
-             if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
-                                    NULL_PTR))
+             if (! reload_cse_noop_set_p (part))
+               break;
+             if (REG_FUNCTION_VALUE_P (SET_DEST (part)))
                {
-                 reload_cse_invalidate_regno (i, VOIDmode, 1);
-                 break;
+                 if (value)
+                   break;
+                 value = SET_DEST (part);
                }
            }
+         else if (GET_CODE (part) != CLOBBER)
+           break;
        }
-    }
-}
-
-/* The memory at address MEM_BASE is being changed.
-   Return whether this change will invalidate VAL.  */
-
-static int
-reload_cse_mem_conflict_p (mem_base, val)
-     rtx mem_base;
-     rtx val;
-{
-  enum rtx_code code;
-  const 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:
-      if (GET_MODE (mem_base) == BLKmode
-         || GET_MODE (val) == BLKmode)
-       return 1;
-      if (anti_dependence (val, mem_base))
-       return 1;
-      /* The address may contain nested MEMs.  */
-      break;
-
-    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, XEXP (val, i)))
-           return 1;
-       }
-      else if (fmt[i] == 'E')
+      if (i < 0)
        {
-         int j;
-
-         for (j = 0; j < XVECLEN (val, i); j++)
-           if (reload_cse_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
-             return 1;
+         reload_cse_delete_noop_set (insn, value);
+         /* We're done with this insn.  */
+         return;
        }
-    }
-
-  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;
-
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      rtx x;
+      /* It's not a no-op, but we can try to simplify it.  */
+      for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+       if (GET_CODE (XVECEXP (body, 0, i)) == SET)
+         count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
 
-      for (x = reg_values[i]; x; x = XEXP (x, 1))
-       {
-         if (XEXP (x, 0) != 0
-             && reload_cse_mem_conflict_p (mem_rtx, 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;
-           }
-       }
+      if (count > 0)
+       apply_change_group ();
+      else
+       reload_cse_simplify_operands (insn);
     }
 }
 
-/* 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, data)
-     rtx dest;
-     rtx ignore ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
-{
-  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
@@ -8728,223 +8138,22 @@ static void
 reload_cse_regs_1 (first)
      rtx first;
 {
-  char *firstobj;
-  rtx callmem;
-  register int i;
   rtx insn;
 
+  cselib_init ();
   init_alias_analysis ();
 
-  reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
-  bzero ((char *)reg_values, FIRST_PSEUDO_REGISTER * sizeof (rtx));
-
-  /* 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);
-       }
-
-
-      /* Forget all the register values at a volatile asm.  */
-      if (GET_CODE (insn) == INSN
-         && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
-         && MEM_VOLATILE_P (PATTERN (insn)))
-       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-         reg_values[i] = 0;
-
-      body = PATTERN (insn);
-      if (GET_CODE (body) == SET)
-       {
-         int count = 0;
-         if (reload_cse_noop_set_p (body, insn))
-           {
-             /* If this sets the return value of the function, we must keep
-                a USE around, in case this is in a different basic block
-                than the final USE.  Otherwise, we could loose important
-                register lifeness information on SMALL_REGISTER_CLASSES
-                machines, where return registers might be used as spills:
-                subsequent passes assume that spill registers are dead at
-                the end of a basic block.  */
-             if (REG_FUNCTION_VALUE_P (SET_DEST (body)))
-               {
-                 pop_obstacks ();
-                 PATTERN (insn) = gen_rtx_USE (VOIDmode, SET_DEST (body));
-                 INSN_CODE (insn) = -1;
-                 REG_NOTES (insn) = NULL_RTX;
-                 push_obstacks (&reload_obstack, &reload_obstack);
-               }
-             else
-               {
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
-               }
-
-             /* We're done with this insn.  */
-             continue;
-           }
-
-         /* It's not a no-op, but we can try to simplify it.  */
-         count += reload_cse_simplify_set (body, insn);
-
-         if (count > 0)
-           apply_change_group ();
-         else
-           reload_cse_simplify_operands (insn);
-
-         reload_cse_record_set (body, body);
-       }
-      else if (GET_CODE (body) == PARALLEL)
-       {
-         int count = 0;
-         rtx value = NULL_RTX;
-
-         /* If every action in a PARALLEL is a noop, we can delete
-            the entire PARALLEL.  */
-         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
-           {
-             rtx part = XVECEXP (body, 0, i);
-             if (GET_CODE (part) == SET)
-               {
-                 if (! reload_cse_noop_set_p (part, insn))
-                   break;
-                 if (REG_FUNCTION_VALUE_P (SET_DEST (part)))
-                   {
-                     if (value)
-                       break;
-                     value = SET_DEST (part);
-                   }
-               }
-             else if (GET_CODE (part) != CLOBBER)
-               break;
-           }
-         if (i < 0)
-           {
-             if (value)
-               {
-                 pop_obstacks ();
-                 PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
-                 INSN_CODE (insn) = -1;
-                 REG_NOTES (insn) = NULL_RTX;
-                 push_obstacks (&reload_obstack, &reload_obstack);
-               }
-             else
-               {
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
-               }
-
-             /* We're done with this insn.  */
-             continue;
-           }
-
-         /* It's not a no-op, but we can try to simplify it.  */
-         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
-           if (GET_CODE (XVECEXP (body, 0, i)) == SET)
-             count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
-
-         if (count > 0)
-           apply_change_group ();
-         else
-           reload_cse_simplify_operands (insn);
-
-         /* 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, NULL);
-           }
-       }
-      else
-       note_stores (body, reload_cse_invalidate_rtx, NULL);
-
-#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, NULL);
-      }
-#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;
+      if (INSN_P (insn))
+       reload_cse_simplify (insn);
 
-         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,
-                                        NULL);
-       }
+      cselib_process_insn (insn);
     }
 
   /* Clean up.  */
   end_alias_analysis ();
-
-  /* Free all the temporary structures we created, and go back to the
-     regular obstacks.  */
-  obstack_free (&reload_obstack, firstobj);
-  pop_obstacks ();
+  cselib_finish ();
 }
 
 /* Call cse / combine like post-reload optimization phases.
@@ -8956,129 +8165,8 @@ reload_cse_regs (first)
   reload_cse_regs_1 (first);
   reload_combine ();
   reload_cse_move2add (first);
-  if (flag_expensive_optimizations)
-    reload_cse_regs_1 (first);
-}
-
-/* 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)
-       && (! flag_float_store || GET_CODE (XEXP (x, 0)) != MEM
-           || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
-       && (GET_CODE (val) != CONST_INT
-           || mode == GET_MODE (x)
-           || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
-               /* On a big endian machine if the value spans more than
-                  one register then this register holds the high part of
-                  it and we can't use it.
-
-                  ??? We should also compare with the high part of the
-                  value.  */
-               && !(WORDS_BIG_ENDIAN
-                    && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
-               && 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 ATTRIBUTE_UNUSED;
-{
-  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))
-           {
-             rtx tmp;
-
-             if (XEXP (x, 0) == 0)
-               continue;
-
-             if (dest_mode == GET_MODE (x))
-               tmp = XEXP (x, 0);
-             else if (GET_MODE_BITSIZE (dest_mode)
-                      < GET_MODE_BITSIZE (GET_MODE (x)))
-               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
-             else
-               continue;
-
-             if (tmp
-                 && reload_cse_regno_equal_p (dreg, tmp, 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;
-    }
-
-  return ret;
+  if (flag_expensive_optimizations)
+    reload_cse_regs_1 (first);
 }
 
 /* Try to simplify a single SET instruction.  SET is the set pattern.
@@ -9092,11 +8180,16 @@ reload_cse_simplify_set (set, insn)
      rtx set;
      rtx insn;
 {
+  int did_change = 0;
   int dreg;
   rtx src;
-  enum machine_mode dest_mode;
   enum reg_class dclass;
-  register int i;
+  int old_cost;
+  cselib_val *val;
+  struct elt_loc_list *l;
+#ifdef LOAD_EXTEND_OP
+  enum rtx_code extend_op = NIL;
+#endif
 
   dreg = true_regnum (SET_DEST (set));
   if (dreg < 0)
@@ -9108,40 +8201,108 @@ reload_cse_simplify_set (set, insn)
 
   dclass = REGNO_REG_CLASS (dreg);
 
-  /* If memory loads are cheaper than register copies, don't change them.  */
+#ifdef LOAD_EXTEND_OP
+  /* When replacing a memory with a register, we need to honor assumptions
+     that combine made wrt the contents of sign bits.  We'll do this by
+     generating an extend instruction instead of a reg->reg copy.  Thus 
+     the destination must be a register that we can widen.  */
   if (GET_CODE (src) == MEM
-      && MEMORY_MOVE_COST (GET_MODE (src), dclass, 1) < 2)
+      && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
+      && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
+      && GET_CODE (SET_DEST (set)) != REG)
     return 0;
+#endif
 
-  /* If the constant is cheaper than a register, don't change it.  */
-  if (CONSTANT_P (src)
-      && rtx_cost (src, SET) < 2)
-    return 0;
+  /* If memory loads are cheaper than register copies, don't change them.  */
+  if (GET_CODE (src) == MEM)
+    old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
+  else if (CONSTANT_P (src))
+    old_cost = rtx_cost (src, SET);
+  else if (GET_CODE (src) == REG)
+    old_cost = REGISTER_MOVE_COST (GET_MODE (src),
+                                  REGNO_REG_CLASS (REGNO (src)), dclass);
+  else
+    /* ???   */
+    old_cost = rtx_cost (src, SET);
 
-  dest_mode = GET_MODE (SET_DEST (set));
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  if (! val)
+    return 0;
+  for (l = val->locs; l; l = l->next)
     {
-      if (i != dreg
-         && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
-         && reload_cse_regno_equal_p (i, src, dest_mode))
+      rtx this_rtx = l->loc;
+      int this_cost;
+
+      if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
        {
-         int validated;
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             HOST_WIDE_INT this_val;
 
-         /* Pop back to the real obstacks while changing the insn.  */
-         pop_obstacks ();
+             /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
+                constants, such as SYMBOL_REF, cannot be extended.  */
+             if (GET_CODE (this_rtx) != CONST_INT)
+               continue;
 
-         validated = validate_change (insn, &SET_SRC (set),
-                                      gen_rtx_REG (dest_mode, i), 1);
+             this_val = INTVAL (this_rtx);
+             switch (extend_op)
+               {
+               case ZERO_EXTEND:
+                 this_val &= GET_MODE_MASK (GET_MODE (src));
+                 break;
+               case SIGN_EXTEND:
+                 /* ??? In theory we're already extended.  */
+                 if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
+                   break;
+               default:
+                 abort ();
+               }
+             this_rtx = GEN_INT (this_val);
+           }
+#endif
+         this_cost = rtx_cost (this_rtx, SET);
+       }
+      else if (GET_CODE (this_rtx) == REG)
+       {
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
+             this_cost = rtx_cost (this_rtx, SET);
+           }
+         else
+#endif
+           this_cost = REGISTER_MOVE_COST (GET_MODE (this_rtx),
+                                           REGNO_REG_CLASS (REGNO (this_rtx)),
+                                           dclass);
+       }
+      else
+       continue;
 
-         /* Go back to the obstack we are using for temporary
-            storage.  */
-         push_obstacks (&reload_obstack, &reload_obstack);
+      /* If equal costs, prefer registers over anything else.  That
+        tends to lead to smaller instructions on some machines.  */
+      if (this_cost < old_cost
+         || (this_cost == old_cost
+             && GET_CODE (this_rtx) == REG
+             && GET_CODE (SET_SRC (set)) != REG))
+       {
+#ifdef LOAD_EXTEND_OP
+         if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
+             && extend_op != NIL)
+           {
+             rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
+             ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
+             validate_change (insn, &SET_DEST (set), wide_dest, 1);
+           }
+#endif
 
-         if (validated)
-           return 1;
+         validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
+         old_cost = this_cost, did_change = 1;
        }
     }
-  return 0;
+
+  return did_change;
 }
 
 /* Try to replace operands in INSN with equivalent values that are already
@@ -9159,7 +8320,10 @@ static int
 reload_cse_simplify_operands (insn)
      rtx insn;
 {
-  int i,j;
+  int i, j;
+
+  /* For each operand, all registers that are equivalent to it.  */
+  HARD_REG_SET equiv_regs[MAX_RECOG_OPERANDS];
 
   const char *constraints[MAX_RECOG_OPERANDS];
 
@@ -9188,8 +8352,33 @@ reload_cse_simplify_operands (insn)
   alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
   alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
   alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
-  bzero ((char *)alternative_reject, recog_data.n_alternatives * sizeof (int));
-  bzero ((char *)alternative_nregs, recog_data.n_alternatives * sizeof (int));
+  memset ((char *)alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
+  memset ((char *)alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
+
+  /* For each operand, find out which regs are equivalent.  */
+  for (i = 0; i < recog_data.n_operands; i++)
+    {
+      cselib_val *v;
+      struct elt_loc_list *l;
+
+      CLEAR_HARD_REG_SET (equiv_regs[i]);
+
+      /* cselib blows up on CODE_LABELs.  Trying to fix that doesn't seem
+        right, so avoid the problem here.  Likewise if we have a constant
+         and the insn pattern doesn't tell us the mode we need.  */
+      if (GET_CODE (recog_data.operand[i]) == CODE_LABEL
+         || (CONSTANT_P (recog_data.operand[i])
+             && recog_data.operand_mode[i] == VOIDmode))
+       continue;
+
+      v = cselib_lookup (recog_data.operand[i], recog_data.operand_mode[i], 0);
+      if (! v)
+       continue;
+
+      for (l = v->locs; l; l = l->next)
+       if (GET_CODE (l->loc) == REG)
+         SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc));
+    }
 
   for (i = 0; i < recog_data.n_operands; i++)
     {
@@ -9230,7 +8419,7 @@ reload_cse_simplify_operands (insn)
        {
          int class = (int) NO_REGS;
 
-         if (! reload_cse_regno_equal_p (regno, recog_data.operand[i], mode))
+         if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
            continue;
 
          REGNO (reg) = regno;
@@ -9257,9 +8446,6 @@ reload_cse_simplify_operands (insn)
                case 's':  case 'i':  case 'n':
                case 'I':  case 'J':  case 'K':  case 'L':
                case 'M':  case 'N':  case 'O':  case 'P':
-#ifdef EXTRA_CONSTRAINT
-               case 'Q':  case 'R':  case 'S':  case 'T':  case 'U':
-#endif
                case 'p': case 'X':
                  /* These don't say anything we care about.  */
                  break;
@@ -9277,7 +8463,7 @@ reload_cse_simplify_operands (insn)
                  /* See if REGNO fits this alternative, and set it up as the
                     replacement register if we don't have one for this
                     alternative yet and the operand being replaced is not
-                    a cheap CONST_INT. */
+                    a cheap CONST_INT.  */
                  if (op_alt_regno[i][j] == -1
                      && reg_fits_class_p (reg, class, 0, mode)
                      && (GET_CODE (recog_data.operand[i]) != CONST_INT
@@ -9336,9 +8522,6 @@ reload_cse_simplify_operands (insn)
      alternative.  */
   j = alternative_order[0];
 
-  /* Pop back to the real obstacks while changing the insn.  */
-  pop_obstacks ();
-
   for (i = 0; i < recog_data.n_operands; i++)
     {
       enum machine_mode mode = recog_data.operand_mode[i];
@@ -9361,178 +8544,8 @@ reload_cse_simplify_operands (insn)
                       gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
     }
 
-  /* Go back to the obstack we are using for temporary
-     storage.  */
-  push_obstacks (&reload_obstack, &reload_obstack);
-
   return apply_change_group ();
 }
-
-/* 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, data)
-     rtx dest;
-     rtx ignore ATTRIBUTE_UNUSED;
-     void *data ATTRIBUTE_UNUSED;
-{
-  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, x;
-  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);
-
-  /* Some machines don't define AUTO_INC_DEC, but they still use push
-     instructions.  We need to catch that case here in order to
-     invalidate the stack pointer correctly.  Note that invalidating
-     the stack pointer is different from invalidating DEST.  */
-  x = dest;
-  while (GET_CODE (x) == SUBREG
-        || GET_CODE (x) == ZERO_EXTRACT
-        || GET_CODE (x) == SIGN_EXTRACT
-        || GET_CODE (x) == STRICT_LOW_PART)
-    x = XEXP (x, 0);
-  if (push_operand (x, GET_MODE (x)))
-    {
-      reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX, NULL);
-      reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
-      return;
-    }
-
-  /* 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, NULL);
-      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, NULL);
-      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, NULL);
-         if (reload_cse_check_clobbered)
-           {
-             reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
-             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 if (GET_MODE_BITSIZE (dest_mode)
-                       > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
-               continue;
-             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 ();
-    }
-}
 \f
 /* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
    addressing now.
@@ -9579,8 +8592,9 @@ static void
 reload_combine ()
 {
   rtx insn, set;
-  int first_index_reg = 1, last_index_reg = 0;
+  int first_index_reg = -1, last_index_reg;
   int i;
+  unsigned int r;
   int last_label_ruid;
   int min_labelno, n_labels;
   HARD_REG_SET ever_live_at_start, *label_live;
@@ -9593,17 +8607,17 @@ reload_combine ()
 
   /* To avoid wasting too much time later searching for an index register,
      determine the minimum and maximum index register numbers.  */
-  for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-    {
-      if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i))
-       {
-         if (! last_index_reg)
-           last_index_reg = i;
-         first_index_reg = i;
-       }
-    }
+  for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+    if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
+      {
+       if (first_index_reg == -1)
+         first_index_reg = r;
+
+       last_index_reg = r;
+      }
+
   /* If no index register is available, we can quit now.  */
-  if (first_index_reg > last_index_reg)
+  if (first_index_reg == -1)
     return;
 
   /* Set up LABEL_LIVE and EVER_LIVE_AT_START.  The register lifetime
@@ -9614,6 +8628,7 @@ reload_combine ()
   n_labels = max_label_num () - min_labelno;
   label_live = (HARD_REG_SET *) xmalloc (n_labels * sizeof (HARD_REG_SET));
   CLEAR_HARD_REG_SET (ever_live_at_start);
+
   for (i = n_basic_blocks - 1; i >= 0; i--)
     {
       insn = BLOCK_HEAD (i);
@@ -9621,8 +8636,10 @@ reload_combine ()
        {
          HARD_REG_SET live;
 
-         REG_SET_TO_HARD_REG_SET (live, BASIC_BLOCK (i)->global_live_at_start);
-         compute_use_by_pseudos (&live, BASIC_BLOCK (i)->global_live_at_start);
+         REG_SET_TO_HARD_REG_SET (live,
+                                  BASIC_BLOCK (i)->global_live_at_start);
+         compute_use_by_pseudos (&live,
+                                 BASIC_BLOCK (i)->global_live_at_start);
          COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
          IOR_HARD_REG_SET (ever_live_at_start, live);
        }
@@ -9630,13 +8647,13 @@ reload_combine ()
 
   /* Initialize last_label_ruid, reload_combine_ruid and reg_state.  */
   last_label_ruid = reload_combine_ruid = 0;
-  for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
+  for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
     {
-      reg_state[i].store_ruid = reload_combine_ruid;
-      if (fixed_regs[i])
-       reg_state[i].use_index = -1;
+      reg_state[r].store_ruid = reload_combine_ruid;
+      if (fixed_regs[r])
+       reg_state[r].use_index = -1;
       else
-       reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
+       reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
     }
 
   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
@@ -9648,13 +8665,14 @@ reload_combine ()
         is and then later disable any optimization that would cross it.  */
       if (GET_CODE (insn) == CODE_LABEL)
        last_label_ruid = reload_combine_ruid;
-      if (GET_CODE (insn) == BARRIER)
-       {
-         for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-           reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
-       }
-      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      else if (GET_CODE (insn) == BARRIER)
+       for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+         if (! fixed_regs[r])
+             reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
+
+      if (! INSN_P (insn))
        continue;
+
       reload_combine_ruid++;
 
       /* Look for (set (REGX) (CONST_INT))
@@ -9684,7 +8702,7 @@ reload_combine ()
          rtx base = XEXP (plus, 1);
          rtx prev = prev_nonnote_insn (insn);
          rtx prev_set = prev ? single_set (prev) : NULL_RTX;
-         int regno = REGNO (reg);
+         unsigned int regno = REGNO (reg);
          rtx const_reg = NULL_RTX;
          rtx reg_sum = NULL_RTX;
 
@@ -9711,31 +8729,35 @@ reload_combine ()
                 two registers.  */
              for (i = first_index_reg; i <= last_index_reg; i++)
                {
-                 if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)
+                 if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
+                                        i)
                      && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
                      && reg_state[i].store_ruid <= reg_state[regno].use_ruid
                      && HARD_REGNO_NREGS (i, GET_MODE (reg)) == 1)
                    {
                      rtx index_reg = gen_rtx_REG (GET_MODE (reg), i);
+
                      const_reg = index_reg;
                      reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
                      break;
                    }
                }
            }
+
          /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
             (REGY), i.e. BASE, is not clobbered before the last use we'll
             create.  */
-         if (prev_set
+         if (prev_set != 0
              && GET_CODE (SET_SRC (prev_set)) == CONST_INT
              && rtx_equal_p (SET_DEST (prev_set), reg)
              && reg_state[regno].use_index >= 0
-             && reg_state[REGNO (base)].store_ruid <= reg_state[regno].use_ruid
-             && reg_sum)
+             && (reg_state[REGNO (base)].store_ruid
+                 <= reg_state[regno].use_ruid)
+             && reg_sum != 0)
            {
              int i;
 
-             /* Change destination register and - if necessary - the
+             /* Change destination register and, if necessary, the
                 constant value in PREV, the constant loading instruction.  */
              validate_change (prev, &SET_DEST (prev_set), const_reg, 1);
              if (reg_state[regno].offset != const0_rtx)
@@ -9744,6 +8766,7 @@ reload_combine ()
                                 GEN_INT (INTVAL (SET_SRC (prev_set))
                                          + INTVAL (reg_state[regno].offset)),
                                 1);
+
              /* Now for every use of REG that we have recorded, replace REG
                 with REG_SUM.  */
              for (i = reg_state[regno].use_index;
@@ -9762,67 +8785,79 @@ reload_combine ()
                  NOTE_SOURCE_FILE (insn) = 0;
 
                  if (reg_state[regno].offset != const0_rtx)
-                   {
-                     /* Previous REG_EQUIV / REG_EQUAL notes for PREV
-                        are now invalid.  */
-                     for (np = &REG_NOTES (prev); *np; )
-                       {
-                         if (REG_NOTE_KIND (*np) == REG_EQUAL
-                             || REG_NOTE_KIND (*np) == REG_EQUIV)
-                           *np = XEXP (*np, 1);
-                         else
-                           np = &XEXP (*np, 1);
-                       }
-                   }
+                   /* Previous REG_EQUIV / REG_EQUAL notes for PREV
+                      are now invalid.  */
+                   for (np = &REG_NOTES (prev); *np;)
+                     {
+                       if (REG_NOTE_KIND (*np) == REG_EQUAL
+                           || REG_NOTE_KIND (*np) == REG_EQUIV)
+                         *np = XEXP (*np, 1);
+                       else
+                         np = &XEXP (*np, 1);
+                     }
+
                  reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
-                 reg_state[REGNO (const_reg)].store_ruid = reload_combine_ruid;
+                 reg_state[REGNO (const_reg)].store_ruid
+                   = reload_combine_ruid;
                  continue;
                }
            }
        }
+
       note_stores (PATTERN (insn), reload_combine_note_store, NULL);
+
       if (GET_CODE (insn) == CALL_INSN)
        {
          rtx link;
 
-         for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-           {
-             if (call_used_regs[i])
-               {
-                 reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
-                 reg_state[i].store_ruid = reload_combine_ruid;
-               }
-           }
+         for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
+           if (call_used_regs[r])
+             {
+               reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
+               reg_state[r].store_ruid = reload_combine_ruid;
+             }
+
          for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
               link = XEXP (link, 1))
            {
-             rtx use = XEXP (link, 0);
-             int regno = REGNO (XEXP (use, 0));
-             if (GET_CODE (use) == CLOBBER)
-               {
-                 reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
-                 reg_state[regno].store_ruid = reload_combine_ruid;
-               }
-             else
-               reg_state[regno].use_index = -1;
-           }
+             rtx usage_rtx = XEXP (XEXP (link, 0), 0);
+             if (GET_CODE (usage_rtx) == REG)
+               {
+                 int i;
+                 unsigned int start_reg = REGNO (usage_rtx);
+                 unsigned int num_regs =
+                       HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
+                 unsigned int end_reg  = start_reg + num_regs - 1;
+                 for (i = start_reg; i <= end_reg; i++)
+                   if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+                     {
+                       reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
+                       reg_state[i].store_ruid = reload_combine_ruid;
+                     }
+                   else
+                     reg_state[i].use_index = -1;
+                }
+            }
+
        }
-      if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) != RETURN)
+      else if (GET_CODE (insn) == JUMP_INSN
+              && GET_CODE (PATTERN (insn)) != RETURN)
        {
          /* Non-spill registers might be used at the call destination in
             some unknown fashion, so we have to mark the unknown use.  */
          HARD_REG_SET *live;
+
          if ((condjump_p (insn) || condjump_in_parallel_p (insn))
              && JUMP_LABEL (insn))
            live = &LABEL_LIVE (JUMP_LABEL (insn));
          else
            live = &ever_live_at_start;
+
          for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
-           {
-             if (TEST_HARD_REG_BIT (*live, i))
-               reg_state[i].use_index = -1;
-           }
+           if (TEST_HARD_REG_BIT (*live, i))
+             reg_state[i].use_index = -1;
        }
+
       reload_combine_note_use (&PATTERN (insn), insn);
       for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
        {
@@ -9836,12 +8871,14 @@ reload_combine ()
            }
        }
     }
+
   free (label_live);
 }
 
 /* Check if DST is a register or a subreg of a register; if it is,
    update reg_state[regno].store_ruid and reg_state[regno].use_index
    accordingly.  Called via note_stores from reload_combine.  */
+
 static void
 reload_combine_note_store (dst, set, data)
      rtx dst, set;
@@ -9849,11 +8886,14 @@ reload_combine_note_store (dst, set, data)
 {
   int regno = 0;
   int i;
-  unsigned size = GET_MODE_SIZE (GET_MODE (dst));
+  enum machine_mode mode = GET_MODE (dst);
 
   if (GET_CODE (dst) == SUBREG)
     {
-      regno = SUBREG_WORD (dst);
+      regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+                                  GET_MODE (SUBREG_REG (dst)),
+                                  SUBREG_BYTE (dst),
+                                  GET_MODE (dst));
       dst = SUBREG_REG (dst);
     }
   if (GET_CODE (dst) != REG)
@@ -9869,7 +8909,7 @@ reload_combine_note_store (dst, set, data)
       || GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
       || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
     {
-      for (i = (size - 1) / UNITS_PER_WORD + regno; i >= regno; i--)
+      for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
        {
          reg_state[i].use_index = -1;
          reg_state[i].store_ruid = reload_combine_ruid;
@@ -9877,7 +8917,7 @@ reload_combine_note_store (dst, set, data)
     }
   else
     {
-      for (i = (size - 1) / UNITS_PER_WORD + regno; i >= regno; i--)
+      for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
        {
          reg_state[i].store_ruid = reload_combine_ruid;
          reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
@@ -9909,6 +8949,21 @@ reload_combine_note_use (xp, insn)
        }
       break;
 
+    case USE:
+      /* If this is the USE of a return value, we can't change it.  */
+      if (GET_CODE (XEXP (x, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (x, 0)))
+       {
+       /* Mark the return register as used in an unknown fashion.  */
+         rtx reg = XEXP (x, 0);
+         int regno = REGNO (reg);
+         int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+
+         while (--nregs >= 0)
+           reg_state[regno + nregs].use_index = -1;
+         return;
+       }
+      break;
+
     case CLOBBER:
       if (GET_CODE (SET_DEST (x)) == REG)
        return;
@@ -9916,7 +8971,8 @@ reload_combine_note_use (xp, insn)
 
     case PLUS:
       /* We are interested in (plus (reg) (const_int)) .  */
-      if (GET_CODE (XEXP (x, 0)) != REG || GET_CODE (XEXP (x, 1)) != CONST_INT)
+      if (GET_CODE (XEXP (x, 0)) != REG
+         || GET_CODE (XEXP (x, 1)) != CONST_INT)
        break;
       offset = XEXP (x, 1);
       x = XEXP (x, 0);
@@ -9925,12 +8981,23 @@ reload_combine_note_use (xp, insn)
       {
        int regno = REGNO (x);
        int use_index;
+       int nregs;
 
        /* Some spurious USEs of pseudo registers might remain.
           Just ignore them.  */
        if (regno >= FIRST_PSEUDO_REGISTER)
          return;
 
+       nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+
+       /* We can't substitute into multi-hard-reg uses.  */
+       if (nregs > 1)
+         {
+           while (--nregs >= 0)
+             reg_state[regno + nregs].use_index = -1;
+           return;
+         }
+
        /* If this register is already used in some unknown fashion, we
           can't do anything.
           If we decrement the index from zero to -1, we can't store more
@@ -9980,34 +9047,39 @@ reload_combine_note_use (xp, insn)
     }
 }
 \f
-/* See if we can reduce the cost of a constant by replacing a move with
-   an add.  */
+/* See if we can reduce the cost of a constant by replacing a move
+   with an add.  We track situations in which a register is set to a
+   constant or to a register plus a constant.  */
 /* We cannot do our optimization across labels.  Invalidating all the
    information about register contents we have would be costly, so we
-   use last_label_luid (local variable of reload_cse_move2add) to note
-   where the label is and then later disable any optimization that would
-   cross it.
+   use move2add_last_label_luid to note where the label is and then
+   later disable any optimization that would cross it.
    reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
-   reg_set_luid[n] is larger than last_label_luid[n] .  */
+   reg_set_luid[n] is greater than last_label_luid[n] .  */
 static int reg_set_luid[FIRST_PSEUDO_REGISTER];
-/* reg_offset[n] has to be CONST_INT for it and reg_base_reg[n] /
-   reg_mode[n] to be valid.
-   If reg_offset[n] is a CONST_INT and reg_base_reg[n] is negative, register n
-   has been set to reg_offset[n] in mode reg_mode[n] .
-   If reg_offset[n] is a CONST_INT and reg_base_reg[n] is non-negative,
-   register n has been set to the sum of reg_offset[n] and register
-   reg_base_reg[n], calculated in mode reg_mode[n] .  */
-static rtx reg_offset[FIRST_PSEUDO_REGISTER];
+
+/* If reg_base_reg[n] is negative, register n has been set to
+   reg_offset[n] in mode reg_mode[n] .
+   If reg_base_reg[n] is non-negative, register n has been set to the
+   sum of reg_offset[n] and the value of register reg_base_reg[n]
+   before reg_set_luid[n], calculated in mode reg_mode[n] . */
+static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
 static int reg_base_reg[FIRST_PSEUDO_REGISTER];
 static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
+
 /* move2add_luid is linearily increased while scanning the instructions
    from first to last.  It is used to set reg_set_luid in
    reload_cse_move2add and move2add_note_store.  */
 static int move2add_luid;
 
+/* move2add_last_label_luid is set whenever a label is found.  Labels
+   invalidate all previously collected reg_offset data.  */
+static int move2add_last_label_luid;
+
 /* Generate a CONST_INT and force it in the range of MODE.  */
-static rtx
-gen_mode_int (mode, value)
+
+static HOST_WIDE_INT
+sext_for_mode (mode, value)
      enum machine_mode mode;
      HOST_WIDE_INT value;
 {
@@ -10020,29 +9092,43 @@ gen_mode_int (mode, value)
       && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
     cval |= (HOST_WIDE_INT) -1 << width;
 
-  return GEN_INT (cval);
+  return cval;
 }
 
+/* ??? We don't know how zero / sign extension is handled, hence we
+   can't go from a narrower to a wider mode.  */
+#define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
+  (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
+   || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
+       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
+                                GET_MODE_BITSIZE (INMODE))))
+
 static void
 reload_cse_move2add (first)
      rtx first;
 {
   int i;
   rtx insn;
-  int last_label_luid;
 
-  for (i = FIRST_PSEUDO_REGISTER-1; i >= 0; i--)
+  for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
     reg_set_luid[i] = 0;
 
-  last_label_luid = 0;
-  move2add_luid = 1;
+  move2add_last_label_luid = 0;
+  move2add_luid = 2;
   for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
     {
       rtx pat, note;
 
       if (GET_CODE (insn) == CODE_LABEL)
-       last_label_luid = move2add_luid;
-      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       {
+         move2add_last_label_luid = move2add_luid;
+         /* We're going to increment move2add_luid twice after a
+            label, so that we can use move2add_last_label_luid + 1 as
+            the luid for constants.  */
+         move2add_luid++;
+         continue;
+       }
+      if (! INSN_P (insn))
        continue;
       pat = PATTERN (insn);
       /* For simplicity, we only perform this optimization on
@@ -10056,12 +9142,8 @@ reload_cse_move2add (first)
 
          /* Check if we have valid information on the contents of this
             register in the mode of REG.  */
-         /* ??? We don't know how zero / sign extension is handled, hence
-            we can't go from a narrower to a wider mode.  */
-         if (reg_set_luid[regno] > last_label_luid
-             && (GET_MODE_SIZE (GET_MODE (reg))
-                 <= GET_MODE_SIZE (reg_mode[regno]))
-             && GET_CODE (reg_offset[regno]) == CONST_INT)
+         if (reg_set_luid[regno] > move2add_last_label_luid
+             && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
            {
              /* Try to transform (set (REGX) (CONST_INT A))
                                  ...
@@ -10074,9 +9156,9 @@ reload_cse_move2add (first)
              if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
                {
                  int success = 0;
-                 rtx new_src
-                   = gen_mode_int (GET_MODE (reg),
-                                   INTVAL (src) - INTVAL (reg_offset[regno]));
+                 rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+                                                       INTVAL (src)
+                                                       - reg_offset[regno]));
                  /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
                     use (set (reg) (reg)) instead.
                     We don't delete this insn, nor do we convert it into a
@@ -10091,7 +9173,7 @@ reload_cse_move2add (first)
                                               gen_add2_insn (reg, new_src), 0);
                  reg_set_luid[regno] = move2add_luid;
                  reg_mode[regno] = GET_MODE (reg);
-                 reg_offset[regno] = src;
+                 reg_offset[regno] = INTVAL (src);
                  continue;
                }
 
@@ -10106,25 +9188,29 @@ reload_cse_move2add (first)
                                  ...
                                  (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
              else if (GET_CODE (src) == REG
-                      && reg_base_reg[regno] == REGNO (src)
-                      && reg_set_luid[regno] > reg_set_luid[REGNO (src)])
+                      && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
+                      && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
+                      && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
+                                                reg_mode[REGNO (src)]))
                {
                  rtx next = next_nonnote_insn (insn);
                  rtx set = NULL_RTX;
                  if (next)
                    set = single_set (next);
-                 if (next
-                     && set
+                 if (set
                      && SET_DEST (set) == reg
                      && GET_CODE (SET_SRC (set)) == PLUS
                      && XEXP (SET_SRC (set), 0) == reg
                      && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
                    {
                      rtx src3 = XEXP (SET_SRC (set), 1);
-                     rtx new_src
-                       = gen_mode_int (GET_MODE (reg),
-                                       INTVAL (src3)
-                                       - INTVAL (reg_offset[regno]));
+                     HOST_WIDE_INT added_offset = INTVAL (src3);
+                     HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
+                     HOST_WIDE_INT regno_offset = reg_offset[regno];
+                     rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+                                                           added_offset
+                                                           + base_offset
+                                                           - regno_offset));
                      int success = 0;
 
                      if (new_src == const0_rtx)
@@ -10132,7 +9218,7 @@ reload_cse_move2add (first)
                        success
                          = validate_change (next, &SET_SRC (set), reg, 0);
                      else if ((rtx_cost (new_src, PLUS)
-                               < 2 + rtx_cost (src3, SET))
+                               < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
                               && have_add2_insn (GET_MODE (reg)))
                        success
                          = validate_change (next, &PATTERN (next),
@@ -10147,9 +9233,10 @@ reload_cse_move2add (first)
                          NOTE_SOURCE_FILE (insn) = 0;
                        }
                      insn = next;
-                     reg_set_luid[regno] = move2add_luid;
                      reg_mode[regno] = GET_MODE (reg);
-                     reg_offset[regno] = src3;
+                     reg_offset[regno] = sext_for_mode (GET_MODE (reg),
+                                                        added_offset
+                                                        + base_offset);
                      continue;
                    }
                }
@@ -10161,14 +9248,10 @@ reload_cse_move2add (first)
          if (REG_NOTE_KIND (note) == REG_INC
              && GET_CODE (XEXP (note, 0)) == REG)
            {
-             /* Indicate that this register has been recently written to,
-                but the exact contents are not available.  */
+             /* Reset the information about this register.  */
              int regno = REGNO (XEXP (note, 0));
              if (regno < FIRST_PSEUDO_REGISTER)
-               {
-                 reg_set_luid[regno] = move2add_luid;
-                 reg_offset[regno] = note;
-               }
+               reg_set_luid[regno] = 0;
            }
        }
       note_stores (PATTERN (insn), move2add_note_store, NULL);
@@ -10176,13 +9259,11 @@ reload_cse_move2add (first)
         unknown values.  */
       if (GET_CODE (insn) == CALL_INSN)
        {
-         for (i = FIRST_PSEUDO_REGISTER-1; i >= 0; i--)
+         for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
            {
              if (call_used_regs[i])
-               {
-                 reg_set_luid[i] = move2add_luid;
-                 reg_offset[i] = insn; /* Invalidate contents.  */
-               }
+               /* Reset the information about this register.  */
+               reg_set_luid[i] = 0;
            }
        }
     }
@@ -10191,20 +9272,35 @@ reload_cse_move2add (first)
 /* SET is a SET or CLOBBER that sets DST.
    Update reg_set_luid, reg_offset and reg_base_reg accordingly.
    Called from reload_cse_move2add via note_stores.  */
+
 static void
 move2add_note_store (dst, set, data)
      rtx dst, set;
      void *data ATTRIBUTE_UNUSED;
 {
-  int regno = 0;
-  int i;
-
+  unsigned int regno = 0;
+  unsigned int i;
   enum machine_mode mode = GET_MODE (dst);
+
   if (GET_CODE (dst) == SUBREG)
     {
-      regno = SUBREG_WORD (dst);
+      regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+                                  GET_MODE (SUBREG_REG (dst)),
+                                  SUBREG_BYTE (dst),
+                                  GET_MODE (dst));
       dst = SUBREG_REG (dst);
     }
+
+  /* Some targets do argument pushes without adding REG_INC notes.  */
+
+  if (GET_CODE (dst) == MEM)
+    {
+      dst = XEXP (dst, 0);
+      if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_DEC
+         || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
+       reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
+      return;
+    }
   if (GET_CODE (dst) != REG)
     return;
 
@@ -10216,51 +9312,106 @@ move2add_note_store (dst, set, data)
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
     {
       rtx src = SET_SRC (set);
+      rtx base_reg;
+      HOST_WIDE_INT offset;
+      int base_regno;
+      /* This may be different from mode, if SET_DEST (set) is a
+        SUBREG.  */
+      enum machine_mode dst_mode = GET_MODE (dst);
 
-      reg_mode[regno] = mode;
       switch (GET_CODE (src))
        {
        case PLUS:
-         {
-           rtx src0 = XEXP (src, 0);
-           if (GET_CODE (src0) == REG)
-             {
-               if (REGNO (src0) != regno
-                   || reg_offset[regno] != const0_rtx)
-                 {
-                   reg_base_reg[regno] = REGNO (src0);
-                   reg_set_luid[regno] = move2add_luid;
-                 }
-               reg_offset[regno] = XEXP (src, 1);
-               break;
-             }
-           reg_set_luid[regno] = move2add_luid;
-           reg_offset[regno] = set;    /* Invalidate contents.  */
-           break;
-         }
+         if (GET_CODE (XEXP (src, 0)) == REG)
+           {
+             base_reg = XEXP (src, 0);
+
+             if (GET_CODE (XEXP (src, 1)) == CONST_INT)
+               offset = INTVAL (XEXP (src, 1));
+             else if (GET_CODE (XEXP (src, 1)) == REG
+                      && (reg_set_luid[REGNO (XEXP (src, 1))]
+                          > move2add_last_label_luid)
+                      && (MODES_OK_FOR_MOVE2ADD
+                          (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
+               {
+                 if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
+                   offset = reg_offset[REGNO (XEXP (src, 1))];
+                 /* Maybe the first register is known to be a
+                    constant.  */
+                 else if (reg_set_luid[REGNO (base_reg)]
+                          > move2add_last_label_luid
+                          && (MODES_OK_FOR_MOVE2ADD
+                              (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
+                          && reg_base_reg[REGNO (base_reg)] < 0)
+                   {
+                     offset = reg_offset[REGNO (base_reg)];
+                     base_reg = XEXP (src, 1);
+                   }
+                 else
+                   goto invalidate;
+               }
+             else
+               goto invalidate;
+
+             break;
+           }
+
+         goto invalidate;
 
        case REG:
-         reg_base_reg[regno] = REGNO (SET_SRC (set));
-         reg_offset[regno] = const0_rtx;
-         reg_set_luid[regno] = move2add_luid;
+         base_reg = src;
+         offset = 0;
          break;
 
-       default:
+       case CONST_INT:
+         /* Start tracking the register as a constant.  */
          reg_base_reg[regno] = -1;
-         reg_offset[regno] = SET_SRC (set);
-         reg_set_luid[regno] = move2add_luid;
-         break;
+         reg_offset[regno] = INTVAL (SET_SRC (set));
+         /* We assign the same luid to all registers set to constants.  */
+         reg_set_luid[regno] = move2add_last_label_luid + 1;
+         reg_mode[regno] = mode;
+         return;
+         
+       default:
+       invalidate:
+         /* Invalidate the contents of the register.  */
+         reg_set_luid[regno] = 0;
+         return;
+       }
+
+      base_regno = REGNO (base_reg);
+      /* If information about the base register is not valid, set it
+        up as a new base register, pretending its value is known
+        starting from the current insn.  */
+      if (reg_set_luid[base_regno] <= move2add_last_label_luid)
+       {
+         reg_base_reg[base_regno] = base_regno;
+         reg_offset[base_regno] = 0;
+         reg_set_luid[base_regno] = move2add_luid;
+         reg_mode[base_regno] = mode;
        }
+      else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
+                                       reg_mode[base_regno]))
+       goto invalidate;
+
+      reg_mode[regno] = mode;
+
+      /* Copy base information from our base register.  */
+      reg_set_luid[regno] = reg_set_luid[base_regno];
+      reg_base_reg[regno] = reg_base_reg[base_regno];
+
+      /* Compute the sum of the offsets or constants.  */
+      reg_offset[regno] = sext_for_mode (dst_mode,
+                                        offset
+                                        + reg_offset[base_regno]);
     }
   else
     {
-      for (i = regno + HARD_REGNO_NREGS (regno, mode) - 1; i >= regno; i--)
-       {
-         /* Indicate that this register has been recently written to,
-            but the exact contents are not available.  */
-         reg_set_luid[i] = move2add_luid;
-         reg_offset[i] = dst;
-       }
+      unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+      for (i = regno; i < endregno; i++)
+       /* Reset the information about this register.  */
+       reg_set_luid[i] = 0;
     }
 }
 
@@ -10293,3 +9444,23 @@ add_auto_inc_notes (insn, x)
     }
 }
 #endif
+
+/* Copy EH notes from an insn to its reloads.  */
+static void
+copy_eh_notes (insn, x)
+     rtx insn;
+     rtx x;
+{
+  rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+  if (eh_note)
+    {
+      for (; x != 0; x = NEXT_INSN (x))
+       {
+         if (may_trap_p (PATTERN (x)))
+           REG_NOTES (x) 
+             = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
+                                  REG_NOTES (x));
+       }
+    }
+}
+