OSDN Git Service

Add new test - do not warn about (non-)redundant friend declaration.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 6affa68..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.  */
@@ -235,7 +237,7 @@ 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_head spilled_pseudos;
@@ -319,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;
@@ -339,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
@@ -366,92 +368,100 @@ static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 
 static int num_labels;
 \f
-static void maybe_fix_stack_asms       PROTO((void));
-static void copy_reloads               PROTO((struct insn_chain *));
-static void calculate_needs_all_insns  PROTO((int));
-static int find_reg                    PROTO((struct insn_chain *, int,
-                                              FILE *));
-static void find_reload_regs           PROTO((struct insn_chain *, FILE *));
-static void select_reload_regs         PROTO((FILE *));
-static void delete_caller_save_insns   PROTO((void));
-
-static void spill_failure              PROTO((rtx, enum reg_class));
-static void count_spilled_pseudo       PROTO((int, int, 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 void count_pseudo               PROTO((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));
-static void failed_reload              PROTO((rtx, int));
-static int set_reload_reg              PROTO((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_input_reload_insns    PROTO((struct insn_chain *,
-                                              struct reload *, rtx, int));
-static void emit_output_reload_insns   PROTO((struct insn_chain *,
-                                              struct reload *, int));
-static void do_input_reload            PROTO((struct insn_chain *,
-                                              struct reload *, int));
-static void do_output_reload           PROTO((struct insn_chain *,
-                                              struct reload *, int));
-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.  */
 
@@ -539,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
@@ -567,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.  */
 
@@ -588,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;
@@ -608,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.  */
@@ -620,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 ();
@@ -631,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.  */
@@ -649,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.
@@ -669,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
@@ -768,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));
     }
 
@@ -819,13 +888,13 @@ reload (first, global, dumpfile)
   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.
@@ -841,11 +910,12 @@ reload (first, global, dumpfile)
 
       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 ();
 
@@ -940,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
@@ -956,12 +1026,12 @@ reload (first, global, dumpfile)
            }
       }
 
-      select_reload_regs (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;
@@ -1015,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);
 
@@ -1107,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
@@ -1204,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 ()
 {
@@ -1218,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);
@@ -1276,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':
@@ -1333,15 +1406,17 @@ 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;
 
   reload_insn_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
-  for (chain = reload_insn_chain; chain != 0; chain = chain->next)
+  for (chain = reload_insn_chain; chain != 0; chain = next)
     {
       rtx insn = chain->insn;
 
+      next = chain->next;
+
       /* Clear out the shortcuts.  */
       chain->n_reloads = 0;
       chain->need_elim = 0;
@@ -1353,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);
@@ -1398,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;
                }
            }
@@ -1441,7 +1524,7 @@ reload_reg_class_lower (r1p, r2p)
      const PTR r1p;
      const PTR r2p;
 {
-  register int r1 = *(short *)r1p, r2 = *(short *)r2p;
+  register int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
   register int t;
 
   /* Consider required reloads before optional ones.  */
@@ -1479,6 +1562,7 @@ static int spill_cost[FIRST_PSEUDO_REGISTER];
 static int spill_add_cost[FIRST_PSEUDO_REGISTER];
 
 /* Update the spill cost arrays, considering that pseudo REG is live.  */
+
 static void
 count_pseudo (reg)
      int reg;
@@ -1495,7 +1579,7 @@ count_pseudo (reg)
 
   if (r < 0)
     abort ();
-  
+
   spill_add_cost[r] += n_refs;
 
   nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
@@ -1505,42 +1589,42 @@ count_pseudo (reg)
 
 /* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the
    contents of BAD_SPILL_REGS for the insn described by CHAIN.  */
+
 static void
 order_regs_for_reload (chain)
      struct insn_chain *chain;
 {
-  register int i, j;
+  int i;
+  HARD_REG_SET used_by_pseudos;
+  HARD_REG_SET used_by_pseudos2;
 
-  COPY_HARD_REG_SET (bad_spill_regs, bad_spill_regs_global);
+  COPY_HARD_REG_SET (bad_spill_regs, fixed_reg_set);
 
   memset (spill_cost, 0, sizeof spill_cost);
   memset (spill_add_cost, 0, sizeof spill_add_cost);
 
   /* Count number of uses of each hard reg by pseudo regs allocated to it
-     and then order them by decreasing use.  */
+     and then order them by decreasing use.  First exclude hard registers
+     that are live in or across this insn.  */
+
+  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);
 
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      /* 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_throughout, i)
-         || REGNO_REG_SET_P (&chain->dead_or_set, i))
-       SET_HARD_REG_BIT (bad_spill_regs, i);
-    }
   /* Now find out which pseudos are allocated to it, and update
      hard_reg_n_uses.  */
   CLEAR_REG_SET (&pseudos_counted);
 
   EXECUTE_IF_SET_IN_REG_SET
-    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j,
+    (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i,
      {
-       count_pseudo (j);
+       count_pseudo (i);
      });
   EXECUTE_IF_SET_IN_REG_SET
-    (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
+    (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i,
      {
-       count_pseudo (j);
+       count_pseudo (i);
      });
   CLEAR_REG_SET (&pseudos_counted);
 }
@@ -1556,6 +1640,7 @@ static HARD_REG_SET used_spill_regs_local;
    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.  */
+
 static void
 count_spilled_pseudo (spilled, spilled_nregs, reg)
      int spilled, spilled_nregs, reg;
@@ -1577,16 +1662,16 @@ count_spilled_pseudo (spilled, spilled_nregs, reg)
 /* Find reload register to use for reload number ORDER.  */
 
 static int
-find_reg (chain, order, dumpfile)
+find_reg (chain, order)
      struct insn_chain *chain;
      int order;
-     FILE *dumpfile;
 {
   int rnum = reload_order[order];
   struct reload *rl = rld + rnum;
   int best_cost = INT_MAX;
   int best_reg = -1;
-  int i, j;
+  unsigned int i, j;
+  int k;
   HARD_REG_SET not_usable;
   HARD_REG_SET used_by_other_reload;
 
@@ -1595,9 +1680,10 @@ find_reg (chain, order, dumpfile)
   IOR_COMPL_HARD_REG_SET (not_usable, reg_class_contents[rl->class]);
 
   CLEAR_HARD_REG_SET (used_by_other_reload);
-  for (i = 0; i < order; i++)
+  for (k = 0; k < order; k++)
     {
-      int other = reload_order[i];
+      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);
@@ -1605,14 +1691,15 @@ find_reg (chain, order, dumpfile)
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      int regno = i;
+      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))
        {
          int this_cost = spill_cost[regno];
          int ok = 1;
-         int this_nregs = HARD_REGNO_NREGS (regno, rl->mode);
+         unsigned int this_nregs = HARD_REGNO_NREGS (regno, rl->mode);
 
          for (j = 1; j < this_nregs; j++)
            {
@@ -1647,8 +1734,10 @@ find_reg (chain, order, dumpfile)
     }
   if (best_reg == -1)
     return 0;
-  if (dumpfile)
-    fprintf (dumpfile, "Using reg %d for reload %d\n", best_reg, rnum);
+
+  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;
 
@@ -1657,6 +1746,7 @@ find_reg (chain, order, dumpfile)
      {
        count_spilled_pseudo (best_reg, rl->nregs, j);
      });
+
   EXECUTE_IF_SET_IN_REG_SET
     (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j,
      {
@@ -1680,9 +1770,8 @@ find_reg (chain, order, dumpfile)
    for a smaller class even though it belongs to that class.  */
 
 static void
-find_reload_regs (chain, dumpfile)
+find_reload_regs (chain)
      struct insn_chain *chain;
-     FILE *dumpfile;
 {
   int i;
 
@@ -1697,7 +1786,8 @@ find_reload_regs (chain, dumpfile)
        {
          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));
+         chain->rld[i].nregs
+           = HARD_REGNO_NREGS (regno, GET_MODE (chain->rld[i].reg_rtx));
        }
       else
        chain->rld[i].regno = -1;
@@ -1709,8 +1799,8 @@ find_reload_regs (chain, dumpfile)
 
   CLEAR_HARD_REG_SET (used_spill_regs_local);
 
-  if (dumpfile)
-    fprintf (dumpfile, "Spilling for insn %d.\n", INSN_UID (chain->insn));
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn));
 
   qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower);
 
@@ -1726,7 +1816,7 @@ find_reload_regs (chain, dumpfile)
       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, dumpfile))
+       if (! find_reg (chain, i))
          {
            spill_failure (chain->insn, rld[r].class);
            failure = 1;
@@ -1741,15 +1831,14 @@ find_reload_regs (chain, dumpfile)
 }
 
 static void
-select_reload_regs (dumpfile)
-     FILE *dumpfile;
+select_reload_regs ()
 {
   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, dumpfile);
+    find_reload_regs (chain);
 }
 \f
 /* Delete all insns that were inserted by emit_caller_save_insns during
@@ -1872,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,
@@ -1897,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
        {
@@ -1911,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]))
@@ -1919,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.
@@ -1936,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;
        }
@@ -1949,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.   */
@@ -1974,6 +2073,7 @@ mark_home_live (regno)
      int regno;
 {
   register int i, lim;
+
   i = reg_renumber[regno];
   if (i < 0)
     return;
@@ -2065,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),
@@ -2409,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
@@ -2426,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));
@@ -2447,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;
@@ -2479,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:
@@ -2508,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;
            }
@@ -2529,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;
                    }
@@ -2608,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))
          {
@@ -2620,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:
@@ -2734,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;
@@ -2744,7 +2856,7 @@ check_eliminable_occurrences (x)
 
   if (x == 0)
     return;
-  
+
   code = GET_CODE (x);
 
   if (code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
@@ -2756,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++)
     {
@@ -2811,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)
     {
@@ -2895,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.  */
@@ -2988,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);
@@ -2998,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
@@ -3007,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)
     {
@@ -3062,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
@@ -3098,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;
 }
 
@@ -3172,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 ()
 {
@@ -3194,6 +3329,7 @@ verify_initial_elim_offsets ()
 }
 
 /* Reset all offsets on eliminable registers to their initial values.  */
+
 static void
 set_initial_elim_offsets ()
 {
@@ -3224,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))
@@ -3233,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;
@@ -3336,6 +3473,7 @@ update_eliminables (pset)
 }
 
 /* Initialize the table of registers to eliminate.  */
+
 static void
 init_elim_table ()
 {
@@ -3346,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?  */
 
@@ -3394,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
@@ -3405,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;
@@ -3423,9 +3559,9 @@ 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);
@@ -3433,6 +3569,7 @@ spill_hard_reg (regno, dumpfile, cant_eliminate)
 
 /* 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;
@@ -3446,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;
@@ -3479,25 +3615,26 @@ 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.  */
@@ -3578,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]);
        }
     }
@@ -3643,7 +3780,7 @@ 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));
        }
     }
@@ -3668,8 +3805,8 @@ reload_as_needed (live_known)
 #endif
   rtx x;
 
-  bzero ((char *) spill_reg_rtx, sizeof spill_reg_rtx);
-  bzero ((char *) spill_reg_store, sizeof spill_reg_store);
+  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);
@@ -3687,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);
 
@@ -3730,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,
@@ -3767,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
@@ -3775,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))))
                    {
@@ -3836,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)
@@ -3880,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)
@@ -3943,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);
     }
 
@@ -3963,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
@@ -3974,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,
@@ -3990,6 +4135,8 @@ forget_old_reloads_1 (x, ignored, data)
 /* 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.  */
@@ -4030,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++)
     {
@@ -4095,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.
@@ -4181,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));
 
@@ -4197,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
@@ -4206,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)
@@ -4365,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;
 {
@@ -4425,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
@@ -4451,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++)
@@ -4460,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
@@ -4580,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;
@@ -4617,11 +4753,7 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
   int i;
   int copy = 0;
 
-  /* ??? reload_reg_used is abused to hold the registers that are not
-     available as spill registers, including hard registers that are
-     earlyclobbered in asms.  As a temporary measure, reject anything
-     in reload_reg_used.  */
-  if (TEST_HARD_REG_BIT (reload_reg_used, regno))
+  if (TEST_HARD_REG_BIT (reload_reg_unavailable, regno))
     return 0;
 
   if (out == const0_rtx)
@@ -4648,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:
@@ -4699,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;
@@ -4780,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;
@@ -4802,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;
@@ -4817,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
@@ -4900,11 +5097,10 @@ set_reload_reg (i, r)
 
 static int
 allocate_reload_reg (chain, r, last_reload)
-     struct insn_chain *chain;
+     struct insn_chain *chain ATTRIBUTE_UNUSED;
      int r;
      int last_reload;
 {
-  rtx insn = chain->insn;
   int i, pass, count;
 
   /* If we put this reload ahead, thinking it is a group,
@@ -4959,11 +5155,9 @@ allocate_reload_reg (chain, r, last_reload)
                   /* 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
@@ -5010,7 +5204,7 @@ allocate_reload_reg (chain, r, last_reload)
       if (count < n_spills)
        break;
     }
-    
+
   /* We should have found a spill register by now.  */
   if (count >= n_spills)
     return 0;
@@ -5024,6 +5218,7 @@ allocate_reload_reg (chain, r, last_reload)
 /* 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;
@@ -5034,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);
@@ -5055,6 +5250,7 @@ choose_reload_regs_init (chain, save_reload_reg_rtx)
     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]);
@@ -5065,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);
 
@@ -5090,7 +5286,7 @@ 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 pass, win, inheritance;
 
@@ -5113,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;
@@ -5135,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
@@ -5204,7 +5401,7 @@ choose_reload_regs (chain)
 
          if (inheritance)
            {
-             int word = 0;
+             int byte = 0;
              register int regno = -1;
              enum machine_mode mode = VOIDmode;
 
@@ -5223,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
@@ -5247,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)
@@ -5267,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,
@@ -5283,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++)
@@ -5320,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)
@@ -5342,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
                            {
@@ -5398,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)
@@ -5411,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
@@ -5422,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;
@@ -5443,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;
                    }
@@ -5454,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
@@ -5511,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
@@ -5621,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;
@@ -5674,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.  */
@@ -5715,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;
@@ -5840,7 +6081,6 @@ merge_assigned_reloads (insn)
        }
     }
 }
-
 \f
 /* These arrays are filled by emit_reload_insns and its subroutines.  */
 static rtx input_reload_insns[MAX_RECOG_OPERANDS];
@@ -5861,6 +6101,7 @@ 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_input_reload_insns (chain, rl, old, j)
      struct insn_chain *chain;
@@ -5924,7 +6165,7 @@ emit_input_reload_insns (chain, rl, old, j)
     oldequiv
       = find_equiv_reg (old, insn,
                        rld[rl->secondary_in_reload].class,
-                       -1, NULL_PTR, 0, mode);
+                       -1, NULL, 0, mode);
 #endif
 
   /* If reloading from memory, see if there is a register
@@ -5940,19 +6181,16 @@ emit_input_reload_insns (chain, rl, old, j)
          || (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);
+    oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
 
   if (oldequiv)
     {
-      int regno = true_regnum (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 (! reload_reg_free_for_value_p (regno, rl->opnum,
-                                        rl->when_needed,
-                                        rl->in, const0_rtx, j,
-                                        0))
+      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
@@ -5962,7 +6200,7 @@ emit_input_reload_insns (chain, rl, old, j)
 
       if (oldequiv != 0
          && ((REGNO_REG_CLASS (regno) != rl->class
-              && (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
+              && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
                                       rl->class)
                   >= MEMORY_MOVE_COST (mode, rl->class, 1)))
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
@@ -6022,7 +6260,7 @@ emit_input_reload_insns (chain, rl, old, j)
     oldequiv = SUBREG_REG (oldequiv);
   if (GET_MODE (oldequiv) != VOIDmode
       && mode != GET_MODE (oldequiv))
-    oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
+    oldequiv = gen_lowpart_SUBREG (mode, oldequiv);
 
   /* Switch to the right place to emit the reload insns.  */
   switch (rl->when_needed)
@@ -6101,11 +6339,9 @@ emit_input_reload_insns (chain, rl, old, j)
           && 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),
-                                          rl->opnum,
-                                          rl->when_needed,
-                                          old, rl->out,
-                                          j, 0))
+          && ! 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)
@@ -6121,7 +6357,7 @@ emit_input_reload_insns (chain, rl, old, j)
                                       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
+         && count_occurrences (PATTERN (insn), old, 0) == 1
          /* Don't risk splitting a matching pair of operands.  */
          && ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
        {
@@ -6327,16 +6563,22 @@ emit_input_reload_insns (chain, rl, old, j)
              && ((reg_equiv_memory_loc
                   [REGNO (SUBREG_REG (oldequiv))] != 0)
                  || (reg_equiv_constant
-                     [REGNO (SUBREG_REG (oldequiv))] != 0))))
+                     [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)
@@ -6430,7 +6672,7 @@ emit_output_reload_insns (chain, rl, j)
 
                  /* Copy primary reload reg to secondary reload reg.
                     (Note that these have been swapped above, then
-                    secondary reload reg to OLD using our insn.  */
+                    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
@@ -6467,20 +6709,20 @@ emit_output_reload_insns (chain, rl, j)
       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. */
+        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))
+         || !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 (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+    if (INSN_P (p))
       {
        rtx pat = PATTERN (p);
 
@@ -6512,9 +6754,10 @@ emit_output_reload_insns (chain, rl, j)
                   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.  */
+                 /* 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)
@@ -6550,7 +6793,10 @@ emit_output_reload_insns (chain, rl, j)
   else
     output_reload_insns[rl->opnum] = get_insns ();
 
-  end_sequence (); 
+  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
@@ -6572,9 +6818,7 @@ do_input_reload (chain, rl, j)
       && (! 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);
-    }
+    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
@@ -6586,9 +6830,8 @@ do_input_reload (chain, rl, j)
       && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
     {
       expect_occurrences
-       = count_occurrences (PATTERN (insn), rl->in) == 1 ? 0 : -1;
-      rl->in
-       = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
+       = 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
@@ -6646,7 +6889,8 @@ do_output_reload (chain, rl, j)
       /* 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
+      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);
@@ -6714,6 +6958,13 @@ emit_reload_insns (chain)
   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
@@ -6829,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;
@@ -7056,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;
@@ -7347,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;
 
@@ -7489,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);
@@ -7506,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);
            }
@@ -7556,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)))
            {
@@ -7643,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);
 
@@ -7756,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
@@ -8069,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;
-           }
+      if (INSN_P (insn))
+       reload_cse_simplify (insn);
 
-         /* 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;
-
-         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.
@@ -8301,188 +8169,140 @@ reload_cse_regs (first)
     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.  */
+/* Try to simplify a single SET instruction.  SET is the set pattern.
+   INSN is the instruction it came from.
+   This function only handles one case: if we set a register to a value
+   which is not a register, we try to find that value in some other register
+   and change the set into a register copy.  */
 
 static int
-reload_cse_regno_equal_p (regno, val, mode)
-     int regno;
-     rtx val;
-     enum machine_mode mode;
+reload_cse_simplify_set (set, insn)
+     rtx set;
+     rtx insn;
 {
-  rtx x;
+  int did_change = 0;
+  int dreg;
+  rtx src;
+  enum reg_class dclass;
+  int old_cost;
+  cselib_val *val;
+  struct elt_loc_list *l;
+#ifdef LOAD_EXTEND_OP
+  enum rtx_code extend_op = NIL;
+#endif
 
-  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;
+  dreg = true_regnum (SET_DEST (set));
+  if (dreg < 0)
+    return 0;
 
   src = SET_SRC (set);
-  dest = SET_DEST (set);
-  dest_mode = GET_MODE (dest);
-
-  if (side_effects_p (src))
+  if (side_effects_p (src) || true_regnum (src) >= 0)
     return 0;
 
-  dreg = true_regnum (dest);
-  sreg = true_regnum (src);
+  dclass = REGNO_REG_CLASS (dreg);
 
-  /* 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;
+#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
+      && 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
 
-  ret = 0;
-  if (dreg >= 0)
-    {
-      /* Check for setting a register to itself.  */
-      if (dreg == sreg)
-       ret = 1;
+  /* 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);
 
-      /* 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;
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  if (! val)
+    return 0;
+  for (l = val->locs; l; l = l->next)
+    {
+      rtx this_rtx = l->loc;
+      int this_cost;
 
-      /* 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)
+      if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
        {
-         rtx x;
-
-         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
            {
-             rtx tmp;
+             HOST_WIDE_INT this_val;
 
-             if (XEXP (x, 0) == 0)
+             /* ??? 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;
 
-             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))
+             this_val = INTVAL (this_rtx);
+             switch (extend_op)
                {
-                 ret = 1;
+               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 (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;
-}
-
-/* Try to simplify a single SET instruction.  SET is the set pattern.
-   INSN is the instruction it came from.
-   This function only handles one case: if we set a register to a value
-   which is not a register, we try to find that value in some other register
-   and change the set into a register copy.  */
-
-static int
-reload_cse_simplify_set (set, insn)
-     rtx set;
-     rtx insn;
-{
-  int dreg;
-  rtx src;
-  enum machine_mode dest_mode;
-  enum reg_class dclass;
-  register int i;
-
-  dreg = true_regnum (SET_DEST (set));
-  if (dreg < 0)
-    return 0;
-
-  src = SET_SRC (set);
-  if (side_effects_p (src) || true_regnum (src) >= 0)
-    return 0;
-
-  dclass = REGNO_REG_CLASS (dreg);
-
-  /* If memory loads are cheaper than register copies, don't change them.  */
-  if (GET_CODE (src) == MEM
-      && MEMORY_MOVE_COST (GET_MODE (src), dclass, 1) < 2)
-    return 0;
-
-  /* If the constant is cheaper than a register, don't change it.  */
-  if (CONSTANT_P (src)
-      && rtx_cost (src, SET) < 2)
-    return 0;
-
-  dest_mode = GET_MODE (SET_DEST (set));
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    {
-      if (i != dreg
-         && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
-         && reload_cse_regno_equal_p (i, src, dest_mode))
+      else if (GET_CODE (this_rtx) == REG)
        {
-         int validated;
-
-         /* Pop back to the real obstacks while changing the insn.  */
-         pop_obstacks ();
-
-         validated = validate_change (insn, &SET_SRC (set),
-                                      gen_rtx_REG (dest_mode, i), 1);
+#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
@@ -8500,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];
 
@@ -8529,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++)
     {
@@ -8571,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;
@@ -8598,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;
@@ -8618,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
@@ -8677,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];
@@ -8702,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.
@@ -8920,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;
@@ -8934,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
@@ -8955,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);
@@ -8962,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);
        }
@@ -8971,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))
@@ -8989,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))
@@ -9025,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;
 
@@ -9052,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)
@@ -9085,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;
@@ -9103,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))
        {
@@ -9177,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;
@@ -9190,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)
@@ -9210,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;
@@ -9218,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;
@@ -9250,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;
@@ -9257,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);
@@ -9266,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
@@ -9321,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;
 {
@@ -9361,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
@@ -9397,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))
                                  ...
@@ -9415,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
@@ -9432,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;
                }
 
@@ -9447,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)
@@ -9473,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),
@@ -9488,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;
                    }
                }
@@ -9502,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);
@@ -9517,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;
            }
        }
     }
@@ -9532,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;
 
@@ -9557,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;
     }
 }
 
@@ -9634,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));
+       }
+    }
+}
+