OSDN Git Service

Add new test - do not warn about (non-)redundant friend declaration.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index c0bf424..dbf99d6 100644 (file)
@@ -1,6 +1,6 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -19,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"
 
@@ -29,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"
@@ -81,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
@@ -321,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;
@@ -341,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
@@ -368,19 +368,21 @@ static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 
 static int num_labels;
 \f
+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,
-                                              FILE *));
-static void find_reload_regs           PARAMS ((struct insn_chain *, FILE *));
-static void select_reload_regs         PARAMS ((FILE *));
+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 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));
@@ -393,8 +395,8 @@ 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, FILE *, int));
-static int finish_spills               PARAMS ((int, FILE *));
+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));
@@ -410,12 +412,17 @@ static void clear_reload_reg_in_use       PARAMS ((unsigned int, int,
                                                 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, 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 *));
@@ -447,13 +454,14 @@ static void move2add_note_store           PARAMS ((rtx, rtx, void *));
 #ifdef AUTO_INC_DEC
 static void add_auto_inc_notes         PARAMS ((rtx, rtx));
 #endif
-static rtx gen_mode_int                        PARAMS ((enum machine_mode,
+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 *, FILE *));
+extern void dump_needs                 PARAMS ((struct insn_chain *));
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -572,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.  */
 
@@ -593,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;
@@ -613,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.  */
@@ -625,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 ();
@@ -636,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.  */
@@ -654,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.
@@ -676,7 +740,7 @@ reload (first, global, dumpfile)
   reg_equiv_address = (rtx *) xcalloc (max_regno, sizeof (rtx));
   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
@@ -773,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));
     }
 
@@ -824,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.
@@ -946,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
@@ -962,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;
@@ -1021,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);
 
@@ -1113,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
@@ -1225,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);
@@ -1283,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':
@@ -1340,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;
@@ -1360,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);
@@ -1405,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;
                }
            }
@@ -1448,7 +1524,7 @@ reload_reg_class_lower (r1p, r2p)
      const PTR r1p;
      const PTR r2p;
 {
-  register int r1 = *(const short *)r1p, r2 = *(const short *)r2p;
+  register int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
   register int t;
 
   /* Consider required reloads before optional ones.  */
@@ -1503,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));
@@ -1586,10 +1662,9 @@ 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;
@@ -1660,8 +1735,8 @@ 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;
@@ -1695,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;
 
@@ -1725,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);
 
@@ -1742,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;
@@ -1757,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
@@ -1913,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
        {
@@ -1927,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]))
@@ -1935,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.
@@ -1952,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;
        }
@@ -1965,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));
+         rtx new = 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.  */
-
-         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.   */
@@ -2082,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),
@@ -2426,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
@@ -2443,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));
@@ -2464,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;
@@ -2496,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:
@@ -2525,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;
            }
@@ -2546,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;
                    }
@@ -2625,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))
          {
@@ -2637,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:
@@ -2762,7 +2856,7 @@ check_eliminable_occurrences (x)
 
   if (x == 0)
     return;
-  
+
   code = GET_CODE (x);
 
   if (code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER)
@@ -2774,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++)
     {
@@ -2829,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)
     {
@@ -2913,7 +3004,7 @@ 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;
@@ -2925,6 +3016,7 @@ eliminate_regs_in_insn (insn, replace)
      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
@@ -2940,13 +3032,24 @@ eliminate_regs_in_insn (insn, replace)
 
            if (offset == 0)
              {
-               /* 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.  */
+               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);
-               INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
+               num_clobbers = 0;
+               INSN_CODE (insn) = recog (PATTERN (insn), insn, &num_clobbers);
+               if (num_clobbers)
+                 {
+                   rtvec vec = rtvec_alloc (num_clobbers + 1);
+
+                   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 ();
              }
@@ -3022,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);
@@ -3032,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
@@ -3041,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)
     {
@@ -3096,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
@@ -3132,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;
 }
 
@@ -3260,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))
@@ -3384,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?  */
 
@@ -3432,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
@@ -3443,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)
+spill_hard_reg (regno, cant_eliminate)
      unsigned int regno;
-     FILE *dumpfile ATTRIBUTE_UNUSED;
      int cant_eliminate;
 {
   register int i;
@@ -3485,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;
@@ -3537,7 +3634,7 @@ finish_spills (global, dumpfile)
   /* 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.  */
@@ -3618,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]);
        }
     }
@@ -3683,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));
        }
     }
@@ -3708,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);
@@ -3727,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);
 
@@ -3770,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,
@@ -3807,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
@@ -3815,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))))
                    {
@@ -3876,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)
@@ -3920,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)
@@ -3987,10 +4084,14 @@ forget_old_reloads_1 (x, ignored, data)
   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);
     }
 
@@ -4015,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,
@@ -4470,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
@@ -4496,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++)
@@ -4505,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
@@ -4625,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.
+/* 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.  */
 
-   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
-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;
@@ -4740,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;
@@ -4821,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;
@@ -4843,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;
@@ -4858,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
@@ -4999,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
@@ -5050,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;
@@ -5075,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);
@@ -5156,7 +5310,7 @@ choose_reload_regs (chain)
        {
          max_group_size = MAX (rld[j].nregs, max_group_size);
          group_class
-           = reg_class_superunion[(int)rld[j].class][(int)group_class];
+           = reg_class_superunion[(int) rld[j].class][(int)group_class];
        }
 
       save_reload_reg_rtx[j] = rld[j].reg_rtx;
@@ -5247,7 +5401,7 @@ choose_reload_regs (chain)
 
          if (inheritance)
            {
-             int word = 0;
+             int byte = 0;
              register int regno = -1;
              enum machine_mode mode = VOIDmode;
 
@@ -5266,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
@@ -5290,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)
@@ -5310,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,
@@ -5326,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++)
@@ -5363,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)
@@ -5385,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
                            {
@@ -5441,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)
@@ -5454,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
@@ -5465,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;
@@ -5486,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;
                    }
@@ -5497,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
@@ -5554,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
@@ -5664,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;
@@ -5885,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];
@@ -5970,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
@@ -5986,8 +6181,7 @@ 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)
     {
@@ -5995,10 +6189,8 @@ emit_input_reload_insns (chain, rl, old, j)
 
       /* 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
@@ -6008,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
@@ -6068,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)
@@ -6147,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)
@@ -6167,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))))
        {
@@ -6373,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)
@@ -6476,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
@@ -6513,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);
 
@@ -6558,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)
@@ -6596,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
@@ -6630,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
@@ -6759,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
@@ -6874,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;
@@ -7101,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;
@@ -7392,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;
 
@@ -7534,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);
@@ -7551,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);
            }
@@ -7601,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)))
            {
@@ -7688,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);
 
@@ -7801,73 +8006,6 @@ 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;
-{
-  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)
-    {
-    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;
-    }
-
-  format_ptr = GET_RTX_FORMAT (code);
-  count = 0;
-
-  for (i = 0; i < GET_RTX_LENGTH (code); i++)
-    {
-      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;
-       }
-    }
-  return count;
-}
-\f
 /* 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,
@@ -7912,7 +8050,15 @@ reload_cse_simplify (insn)
   if (GET_CODE (body) == SET)
     {
       int count = 0;
-      if (reload_cse_noop_set_p (body))
+
+      /* 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);
+
+      if (!count && reload_cse_noop_set_p (body))
        {
          rtx value = SET_DEST (body);
          if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
@@ -7921,9 +8067,6 @@ reload_cse_simplify (insn)
          return;
        }
 
-      /* 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
@@ -7997,12 +8140,12 @@ reload_cse_regs_1 (first)
 {
   rtx insn;
 
-  cselib_init ();  
+  cselib_init ();
   init_alias_analysis ();
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        reload_cse_simplify (insn);
 
       cselib_process_insn (insn);
@@ -8044,6 +8187,9 @@ reload_cse_simplify_set (set, insn)
   int old_cost;
   cselib_val *val;
   struct elt_loc_list *l;
+#ifdef LOAD_EXTEND_OP
+  enum rtx_code extend_op = NIL;
+#endif
 
   dreg = true_regnum (SET_DEST (set));
   if (dreg < 0)
@@ -8055,38 +8201,105 @@ reload_cse_simplify_set (set, insn)
 
   dclass = REGNO_REG_CLASS (dreg);
 
+#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
+
   /* 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 (REGNO_REG_CLASS (REGNO (src)), dclass);
+    old_cost = REGISTER_MOVE_COST (GET_MODE (src),
+                                  REGNO_REG_CLASS (REGNO (src)), dclass);
   else
     /* ???   */
     old_cost = rtx_cost (src, SET);
 
-  val = cselib_lookup (src, VOIDmode, 0);
+  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;
-      if (CONSTANT_P (l->loc) && ! references_value_p (l->loc, 0))
-       this_cost = rtx_cost (l->loc, SET);
-      else if (GET_CODE (l->loc) == REG)
-       this_cost = REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (l->loc)),
-                                       dclass);
+
+      if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
+       {
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             HOST_WIDE_INT this_val;
+
+             /* ??? 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;
+
+             this_val = INTVAL (this_rtx);
+             switch (extend_op)
+               {
+               case ZERO_EXTEND:
+                 this_val &= GET_MODE_MASK (GET_MODE (src));
+                 break;
+               case SIGN_EXTEND:
+                 /* ??? In theory we're already extended.  */
+                 if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
+                   break;
+               default:
+                 abort ();
+               }
+             this_rtx = GEN_INT (this_val);
+           }
+#endif
+         this_cost = rtx_cost (this_rtx, SET);
+       }
+      else if (GET_CODE (this_rtx) == REG)
+       {
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
+             this_cost = rtx_cost (this_rtx, SET);
+           }
+         else
+#endif
+           this_cost = REGISTER_MOVE_COST (GET_MODE (this_rtx),
+                                           REGNO_REG_CLASS (REGNO (this_rtx)),
+                                           dclass);
+       }
       else
        continue;
-      /* 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 (l->loc) == REG
-              && GET_CODE (SET_SRC (set)) != REG))
-         && validate_change (insn, &SET_SRC (set), copy_rtx (l->loc), 1))
-       old_cost = this_cost, did_change = 1;
+
+      /* 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
+
+         validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
+         old_cost = this_cost, did_change = 1;
+       }
     }
 
   return did_change;
@@ -8107,7 +8320,7 @@ 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];
@@ -8135,12 +8348,12 @@ reload_cse_simplify_operands (insn)
   /* Figure out which alternative currently matches.  */
   if (! constrain_operands (1))
     fatal_insn_not_found (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++)
@@ -8151,8 +8364,11 @@ reload_cse_simplify_operands (insn)
       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.  */
-      if (GET_CODE (recog_data.operand[i]) == CODE_LABEL)
+        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);
@@ -8230,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;
@@ -8250,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
@@ -8379,7 +8592,7 @@ 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;
@@ -8397,14 +8610,14 @@ reload_combine ()
   for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
     if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
       {
-       if (! first_index_reg)
+       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
@@ -8457,7 +8670,7 @@ reload_combine ()
          if (! fixed_regs[r])
              reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      if (! INSN_P (insn))
        continue;
 
       reload_combine_ruid++;
@@ -8574,7 +8787,7 @@ reload_combine ()
                  if (reg_state[regno].offset != const0_rtx)
                    /* Previous REG_EQUIV / REG_EQUAL notes for PREV
                       are now invalid.  */
-                   for (np = &REG_NOTES (prev); *np; )
+                   for (np = &REG_NOTES (prev); *np;)
                      {
                        if (REG_NOTE_KIND (*np) == REG_EQUAL
                            || REG_NOTE_KIND (*np) == REG_EQUIV)
@@ -8591,7 +8804,7 @@ reload_combine ()
            }
        }
 
-  note_stores (PATTERN (insn), reload_combine_note_store, NULL);
+      note_stores (PATTERN (insn), reload_combine_note_store, NULL);
 
       if (GET_CODE (insn) == CALL_INSN)
        {
@@ -8606,20 +8819,27 @@ reload_combine ()
 
          for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
               link = XEXP (link, 1))
-           if (GET_CODE (XEXP (XEXP (link, 0), 0)) == REG)
-             {
-               unsigned int regno = REGNO (XEXP (XEXP (link, 0), 0));
+           {
+             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 (XEXP (link, 0)) == 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;
-             }
        }
-
       else if (GET_CODE (insn) == JUMP_INSN
               && GET_CODE (PATTERN (insn)) != RETURN)
        {
@@ -8670,7 +8890,10 @@ reload_combine_note_store (dst, set, data)
 
   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)
@@ -8748,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);
@@ -8823,25 +9047,23 @@ 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];
 
@@ -8850,10 +9072,14 @@ static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
    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;
 {
@@ -8866,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
@@ -8902,16 +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_MODE_SIZE (GET_MODE (reg))
-                      <= GET_MODE_SIZE (reg_mode[regno]))
-                     && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (reg)),
-                                               GET_MODE_BITSIZE (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))
                                  ...
@@ -8924,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
@@ -8941,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;
                }
 
@@ -8956,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] == (int) 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)
@@ -8982,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),
@@ -8997,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;
                    }
                }
@@ -9011,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);
@@ -9026,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;
            }
        }
     }
@@ -9053,10 +9284,23 @@ move2add_note_store (dst, set, data)
 
   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;
 
@@ -9068,56 +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;
-                 }
+         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;
 
-               reg_offset[regno] = XEXP (src, 1);
-               break;
-             }
+             break;
+           }
 
-           reg_set_luid[regno] = move2add_luid;
-           reg_offset[regno] = set;    /* Invalidate contents.  */
-           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
     {
       unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
 
       for (i = regno; i < endregno; 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;
-       }
+       /* Reset the information about this register.  */
+       reg_set_luid[i] = 0;
     }
 }
 
@@ -9150,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));
+       }
+    }
+}
+