OSDN Git Service

* reload1.c (reg_set_luid): Fix a comment typo.
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 7828bf5..edfd5d5 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, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "machmode.h"
 #include "hard-reg-set.h"
@@ -41,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "real.h"
 #include "toplev.h"
 #include "except.h"
+#include "tree.h"
 
 /* This file contains the reload pass of the compiler, which is
    run after register allocation has been done.  It checks that
@@ -138,7 +141,7 @@ static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER];
    when reg_reloaded_valid is set for this register.  */
 static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
 
-/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
+/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
 static HARD_REG_SET reg_reloaded_valid;
 /* Indicate if the register was dead at the end of the reload.
    This is only valid if reg_reloaded_contents is set and valid.  */
@@ -225,7 +228,7 @@ static char spill_indirect_levels;
 
 /* Nonzero if indirect addressing is supported when the innermost MEM is
    of the form (MEM (SYMBOL_REF sym)).  It is assumed that the level to
-   which these are valid is the same as spill_indirect_levels, above.   */
+   which these are valid is the same as spill_indirect_levels, above.  */
 char indirect_symref_ok;
 
 /* Nonzero if an address (plus (reg frame_pointer) (reg ...)) is valid.  */
@@ -279,9 +282,6 @@ char *reload_firstobj;
    Used to quickly free all memory after processing one insn.  */
 static char *reload_insn_firstobj;
 
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
 /* List of insn_chain instructions, one for every insn that reload needs to
    examine.  */
 struct insn_chain *reload_insn_chain;
@@ -305,7 +305,7 @@ struct elim_table
   int from;                    /* Register number to be eliminated.  */
   int to;                      /* Register number used as replacement.  */
   int initial_offset;          /* Initial difference between values.  */
-  int can_eliminate;           /* Non-zero if this elimination can be done.  */
+  int can_eliminate;           /* Nonzero if this elimination can be done.  */
   int can_eliminate_previous;  /* Value of CAN_ELIMINATE in previous scan over
                                   insns made by reload.  */
   int offset;                  /* Current offset between the two regs.  */
@@ -323,10 +323,10 @@ 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.  */
-static struct elim_table_1
+static const struct elim_table_1
 {
-  int from;
-  int to;
+  const int from;
+  const int to;
 } reg_eliminate_1[] =
 
 /* If a set of eliminable registers was specified, define the table from it.
@@ -342,7 +342,7 @@ static struct elim_table_1
 #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
+   to their initial offset.  If nonzero, we use a new copy of each
    replacement result in any insns encountered.  */
 int num_not_at_initial_offset;
 
@@ -354,11 +354,14 @@ static int num_eliminable_invariants;
 
 /* For each label, we record the offset of each elimination.  If we reach
    a label by more than one path and an offset differs, we cannot do the
-   elimination.  This information is indexed by the number of the label.
-   The first table is an array of flags that records whether we have yet
-   encountered a label and the second table is an array of arrays, one
-   entry in the latter array for each elimination.  */
-
+   elimination.  This information is indexed by the difference of the
+   number of the label and the first label number.  We can't offset the
+   pointer itself as this can cause problems on machines with segmented
+   memory.  The first table is an array of flags that records whether we
+   have yet encountered a label and the second table is an array of arrays,
+   one entry in the latter array for each elimination.  */
+
+static int first_label_num;
 static char *offsets_known_at;
 static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 
@@ -366,9 +369,9 @@ 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 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));
@@ -439,11 +442,10 @@ static void delete_output_reload  PARAMS ((rtx, int, int));
 static void delete_address_reloads     PARAMS ((rtx, rtx));
 static void delete_address_reloads_1   PARAMS ((rtx, rtx, rtx));
 static rtx inc_for_reload              PARAMS ((rtx, rtx, rtx, int));
-static int constraint_accepts_reg_p    PARAMS ((const char *, rtx));
 static void reload_cse_regs_1          PARAMS ((rtx));
 static int reload_cse_noop_set_p       PARAMS ((rtx));
 static int reload_cse_simplify_set     PARAMS ((rtx, rtx));
-static int reload_cse_simplify_operands        PARAMS ((rtx));
+static int reload_cse_simplify_operands        PARAMS ((rtx, rtx));
 static void reload_combine             PARAMS ((void));
 static void reload_combine_note_use    PARAMS ((rtx *, rtx));
 static void reload_combine_note_store  PARAMS ((rtx, rtx, void *));
@@ -453,13 +455,10 @@ static void move2add_note_store           PARAMS ((rtx, rtx, void *));
 static void add_auto_inc_notes         PARAMS ((rtx, rtx));
 #endif
 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));
-static void fixup_abnormal_edges       PARAMS ((void));
+static void reload_cse_simplify                PARAMS ((rtx, rtx));
+void fixup_abnormal_edges              PARAMS ((void));
 extern void dump_needs                 PARAMS ((struct insn_chain *));
 \f
 /* Initialize the reload pass once per compilation.  */
@@ -467,13 +466,13 @@ extern void dump_needs                    PARAMS ((struct insn_chain *));
 void
 init_reload ()
 {
-  register int i;
+  int i;
 
   /* Often (MEM (REG n)) is still valid even if (REG n) is put on the stack.
      Set spill_indirect_levels to the number of levels such addressing is
      permitted, zero if it is not permitted at all.  */
 
-  register rtx tem
+  rtx tem
     = gen_rtx_MEM (Pmode,
                   gen_rtx_PLUS (Pmode,
                                 gen_rtx_REG (Pmode,
@@ -672,14 +671,10 @@ reload (first, global)
      rtx first;
      int global;
 {
-  register int i;
-  register rtx insn;
-  register struct elim_table *ep;
-
-  /* The two pointers used to track the true location of the memory used
-     for label offsets.  */
-  char *real_known_ptr = NULL;
-  int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
+  int i;
+  rtx insn;
+  struct elim_table *ep;
+  basic_block bb;
 
   /* Make sure even insns with volatile mem refs are recognizable.  */
   init_recog ();
@@ -778,7 +773,11 @@ reload (first, global)
 #ifdef LEGITIMATE_PIC_OPERAND_P
              && (! function_invariant_p (XEXP (note, 0))
                  || ! flag_pic
-                 || LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0)))
+                 /* A function invariant is often CONSTANT_P but may
+                    include a register.  We promise to only pass
+                    CONSTANT_P objects to LEGITIMATE_PIC_OPERAND_P.  */
+                 || (CONSTANT_P (XEXP (note, 0))
+                     && LEGITIMATE_PIC_OPERAND_P (XEXP (note, 0))))
 #endif
              )
            {
@@ -786,11 +785,16 @@ reload (first, global)
              i = REGNO (SET_DEST (set));
              if (i > LAST_VIRTUAL_REGISTER)
                {
-                 if (GET_CODE (x) == MEM)
+                 /* It can happen that a REG_EQUIV note contains a MEM
+                    that is not a legitimate memory operand.  As later
+                    stages of reload assume that all addresses found
+                    in the reg_equiv_* arrays were originally legitimate,
+                    we ignore such REG_EQUIV notes.  */
+                 if (memory_operand (x, VOIDmode))
                    {
                      /* Always unshare the equivalence, so we can
                         substitute into this insn without touching the
-                        equivalence. */
+                        equivalence.  */
                      reg_equiv_memory_loc[i] = copy_rtx (x);
                    }
                  else if (function_invariant_p (x))
@@ -811,8 +815,12 @@ reload (first, global)
                      else if (LEGITIMATE_CONSTANT_P (x))
                        reg_equiv_constant[i] = x;
                      else
-                       reg_equiv_memory_loc[i]
-                         = force_const_mem (GET_MODE (SET_DEST (set)), x);
+                       {
+                         reg_equiv_memory_loc[i]
+                           = force_const_mem (GET_MODE (SET_DEST (set)), x);
+                         if (!reg_equiv_memory_loc[i])
+                           continue;
+                       }
                    }
                  else
                    continue;
@@ -846,21 +854,18 @@ reload (first, global)
 
   init_elim_table ();
 
-  num_labels = max_label_num () - get_first_label_num ();
+  first_label_num = get_first_label_num ();
+  num_labels = max_label_num () - first_label_num;
 
   /* Allocate the tables used to store offset information at labels.  */
   /* We used to use alloca here, but the size of what it would try to
      allocate would occasionally cause it to exceed the stack limit and
      cause a core dump.  */
-  real_known_ptr = xmalloc (num_labels);
-  real_at_ptr
+  offsets_known_at = xmalloc (num_labels);
+  offsets_at
     = (int (*)[NUM_ELIMINABLE_REGS])
     xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
 
-  offsets_known_at = real_known_ptr - get_first_label_num ();
-  offsets_at
-    = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
-
   /* Alter each pseudo-reg rtx to contain its hard reg number.
      Assign stack slots to the pseudos that lack hard regs or equivalents.
      Do not touch virtual registers.  */
@@ -916,7 +921,7 @@ reload (first, global)
       /* Round size of stack frame to stack_alignment_needed.  This must be done
         here because the stack size may be a part of the offset computation
         for register elimination, and there might have been new stack slots
-        created in the last iteration of this loop.   */
+        created in the last iteration of this loop.  */
       if (cfun->stack_alignment_needed)
         assign_stack_local (BLKmode, 0, cfun->stack_alignment_needed);
 
@@ -1017,7 +1022,7 @@ reload (first, global)
              did_spill = 1;
 
              /* Regardless of the state of spills, if we previously had
-                a register that we thought we could eliminate, but no can
+                a register that we thought we could eliminate, but now can
                 not eliminate, we must run another pass.
 
                 Consider pseudos which have an entry in reg_equiv_* which
@@ -1067,9 +1072,16 @@ reload (first, global)
          for (list = reg_equiv_init[i]; list; list = XEXP (list, 1))
            {
              rtx equiv_insn = XEXP (list, 0);
-             if (GET_CODE (equiv_insn) == NOTE)
-               continue;
-             if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
+
+             /* If we already deleted the insn or if it may trap, we can't
+                delete it.  The latter case shouldn't happen, but can
+                if an insn has a variable address, gets a REG_EH_REGION
+                note added to it, and then gets converted into an load
+                from a constant address.  */
+             if (GET_CODE (equiv_insn) == NOTE
+                 || can_throw_internal (equiv_insn))
+               ;
+             else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn)))
                delete_dead_insn (equiv_insn);
              else
                {
@@ -1106,8 +1118,8 @@ reload (first, global)
      pseudo.  */
 
   if (! frame_pointer_needed)
-    for (i = 0; i < n_basic_blocks; i++)
-      CLEAR_REGNO_REG_SET (BASIC_BLOCK (i)->global_live_at_start,
+    FOR_EACH_BB (bb)
+      CLEAR_REGNO_REG_SET (bb->global_live_at_start,
                           HARD_FRAME_POINTER_REGNUM);
 
   /* Come here (with failure set nonzero) if we can't get enough spill regs
@@ -1143,9 +1155,9 @@ reload (first, global)
            {
              rtx reg = regno_reg_rtx[i];
 
+             REG_USERVAR_P (reg) = 0;
              PUT_CODE (reg, MEM);
              XEXP (reg, 0) = addr;
-             REG_USERVAR_P (reg) = 0;
              if (reg_equiv_memory_loc[i])
                MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]);
              else
@@ -1167,10 +1179,12 @@ reload (first, global)
 
   /* Make a pass over all the insns and delete all USEs which we inserted
      only to tag a REG_EQUAL note on them.  Remove all REG_DEAD and REG_UNUSED
-     notes.  Delete all CLOBBER insns that don't refer to the return value
-     and simplify (subreg (reg)) operands.  Also remove all REG_RETVAL and
-     REG_LIBCALL notes since they are no longer useful or accurate.  Strip
-     and regenerate REG_INC notes that may have been moved around.  */
+     notes.  Delete all CLOBBER insns, except those that refer to the return
+     value and the special mem:BLK CLOBBERs added to prevent the scheduler
+     from misarranging variable-array code, and simplify (subreg (reg))
+     operands.  Also remove all REG_RETVAL and REG_LIBCALL notes since they
+     are no longer useful or accurate.  Strip and regenerate REG_INC notes
+     that may have been moved around.  */
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
@@ -1187,6 +1201,11 @@ reload (first, global)
             && (GET_MODE (insn) == QImode
                 || find_reg_note (insn, REG_EQUAL, NULL_RTX)))
            || (GET_CODE (PATTERN (insn)) == CLOBBER
+               && (GET_CODE (XEXP (PATTERN (insn), 0)) != MEM
+                   || GET_MODE (XEXP (PATTERN (insn), 0)) != BLKmode
+                   || (GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) != SCRATCH
+                       && XEXP (XEXP (PATTERN (insn), 0), 0) 
+                               != stack_pointer_rtx))
                && (GET_CODE (XEXP (PATTERN (insn), 0)) != REG
                    || ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
          {
@@ -1245,10 +1264,10 @@ reload (first, global)
     free (reg_equiv_memory_loc);
   reg_equiv_memory_loc = 0;
 
-  if (real_known_ptr)
-    free (real_known_ptr);
-  if (real_at_ptr)
-    free (real_at_ptr);
+  if (offsets_known_at)
+    free (offsets_known_at);
+  if (offsets_at)
+    free (offsets_at);
 
   free (reg_equiv_mem);
   free (reg_equiv_init);
@@ -1267,6 +1286,11 @@ reload (first, global)
   unused_insn_chains = 0;
   fixup_abnormal_edges ();
 
+  /* Replacing pseudos with their memory equivalents might have
+     created shared rtx.  Subsequent passes would get confused
+     by this, so unshare everything here.  */
+  unshare_all_rtl_again (first);
+
   return failure;
 }
 
@@ -1324,7 +1348,7 @@ maybe_fix_stack_asms ()
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              if (c == '\0' || c == ',' || c == '#')
                {
@@ -1332,6 +1356,7 @@ maybe_fix_stack_asms ()
                     class, and reset the class.  */
                  IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
                  cls = NO_REGS;
+                 p++;
                  if (c == '#')
                    do {
                      c = *p++;
@@ -1352,7 +1377,8 @@ maybe_fix_stack_asms ()
                  break;
 
                case 'p':
-                 cls = (int) reg_class_subunion[cls][(int) BASE_REG_CLASS];
+                 cls = (int) reg_class_subunion[cls]
+                   [(int) MODE_BASE_REG_CLASS (VOIDmode)];
                  break;
 
                case 'g':
@@ -1361,9 +1387,14 @@ maybe_fix_stack_asms ()
                  break;
 
                default:
-                 cls = (int) reg_class_subunion[cls][(int) REG_CLASS_FROM_LETTER (c)];
-
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+                   cls = (int) reg_class_subunion[cls]
+                     [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+                 else
+                   cls = (int) reg_class_subunion[cls]
+                     [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
                }
+             p += CONSTRAINT_LEN (c, p);
            }
        }
       /* Those of the registers which are clobbered, but allowed by the
@@ -1467,7 +1498,7 @@ calculate_needs_all_insns (global)
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
                {
                  delete_insn (insn);
-                 /* Delete it from the reload chain */
+                 /* Delete it from the reload chain */
                  if (chain->prev)
                    chain->prev->next = next;
                  else
@@ -1519,8 +1550,8 @@ reload_reg_class_lower (r1p, r2p)
      const PTR r1p;
      const PTR r2p;
 {
-  register int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
-  register int t;
+  int r1 = *(const short *) r1p, r2 = *(const short *) r2p;
+  int t;
 
   /* Consider required reloads before optional ones.  */
   t = rld[r1].optional - rld[r2].optional;
@@ -1877,13 +1908,13 @@ spill_failure (insn, class)
 {
   static const char *const reg_class_names[] = REG_CLASS_NAMES;
   if (asm_noperands (PATTERN (insn)) >= 0)
-    error_for_asm (insn, "Can't find a register in class `%s' while reloading `asm'.",
+    error_for_asm (insn, "can't find a register in class `%s' while reloading `asm'",
                   reg_class_names[class]);
   else
     {
-      error ("Unable to find a register to spill in class `%s'.",
+      error ("unable to find a register to spill in class `%s'",
             reg_class_names[class]);
-      fatal_insn ("This is the insn:", insn);
+      fatal_insn ("this is the insn:", insn);
     }
 }
 \f
@@ -1921,7 +1952,7 @@ delete_dead_insn (insn)
 
 static void
 alter_reg (i, from_reg)
-     register int i;
+     int i;
      int from_reg;
 {
   /* When outputting an inline function, this can happen
@@ -1947,7 +1978,7 @@ alter_reg (i, from_reg)
       && reg_equiv_constant[i] == 0
       && reg_equiv_memory_loc[i] == 0)
     {
-      register rtx x;
+      rtx x;
       unsigned int inherent_size = PSEUDO_REGNO_BYTES (i);
       unsigned int total_size = MAX (inherent_size, reg_max_ref_width[i]);
       int adjust = 0;
@@ -2021,10 +2052,11 @@ alter_reg (i, from_reg)
                 below.  */
              adjust = GET_MODE_SIZE (mode) - total_size;
              if (adjust)
-               stack_slot = gen_rtx_MEM (mode_for_size (total_size
+               stack_slot
+                 = adjust_address_nv (x, mode_for_size (total_size
                                                         * BITS_PER_UNIT,
                                                         MODE_INT, 1),
-                                         plus_constant (XEXP (x, 0), adjust));
+                                      adjust);
            }
 
          spill_stack_slot[from_reg] = stack_slot;
@@ -2038,10 +2070,29 @@ alter_reg (i, from_reg)
 
       /* If we have any adjustment to make, or if the stack slot is the
         wrong mode, make a new stack slot.  */
-      if (adjust != 0 || GET_MODE (x) != GET_MODE (regno_reg_rtx[i]))
-       x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust);
+      x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust);
+
+      /* If we have a decl for the original register, set it for the
+        memory.  If this is a shared MEM, make a copy.  */
+      if (REG_EXPR (regno_reg_rtx[i])
+         && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd')
+       {
+         rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
+
+         /* We can do this only for the DECLs home pseudo, not for
+            any copies of it, since otherwise when the stack slot
+            is reused, nonoverlapping_memrefs_p might think they
+            cannot overlap.  */
+         if (decl && GET_CODE (decl) == REG && REGNO (decl) == (unsigned) i)
+           {
+             if (from_reg != -1 && spill_stack_slot[from_reg] == x)
+               x = copy_rtx (x);
 
-      /* Save the stack slot for later.   */
+             set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
+           }
+       }
+
+      /* Save the stack slot for later.  */
       reg_equiv_memory_loc[i] = x;
     }
 }
@@ -2053,7 +2104,7 @@ void
 mark_home_live (regno)
      int regno;
 {
-  register int i, lim;
+  int i, lim;
 
   i = reg_renumber[regno];
   if (i < 0)
@@ -2069,7 +2120,7 @@ mark_home_live (regno)
 
    INSN is the insn that it came from, if any.
 
-   INITIAL_P is non-zero if we are to set the offset to be the initial
+   INITIAL_P is nonzero if we are to set the offset to be the initial
    offset and zero if we are setting the offset of the label to be the
    current offset.  */
 
@@ -2102,13 +2153,13 @@ set_label_offsets (x, insn, initial_p)
         we guessed wrong, we will suppress an elimination that might have
         been possible had we been able to guess correctly.  */
 
-      if (! offsets_known_at[CODE_LABEL_NUMBER (x)])
+      if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num])
        {
          for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-           offsets_at[CODE_LABEL_NUMBER (x)][i]
+           offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              = (initial_p ? reg_eliminate[i].initial_offset
                 : reg_eliminate[i].offset);
-         offsets_known_at[CODE_LABEL_NUMBER (x)] = 1;
+         offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1;
        }
 
       /* Otherwise, if this is the definition of a label and it is
@@ -2125,7 +2176,7 @@ set_label_offsets (x, insn, initial_p)
           where the offsets disagree.  */
 
        for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-         if (offsets_at[CODE_LABEL_NUMBER (x)][i]
+         if (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              != (initial_p ? reg_eliminate[i].initial_offset
                  : reg_eliminate[i].offset))
            reg_eliminate[i].can_eliminate = 0;
@@ -2224,7 +2275,7 @@ set_label_offsets (x, insn, initial_p)
    to record the fact that a register is referenced outside a MEM.
 
    If INSN is an insn, it is the insn containing X.  If we replace a REG
-   in a SET_DEST with an equivalent MEM and INSN is non-zero, write a
+   in a SET_DEST with an equivalent MEM and INSN is nonzero, write a
    CLOBBER of the pseudo after INSN so find_equiv_regs will know that
    the REG is being modified.
 
@@ -2260,6 +2311,7 @@ eliminate_regs (x, mem_mode, insn)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -2293,8 +2345,8 @@ eliminate_regs (x, mem_mode, insn)
              return plus_constant (ep->to_rtx, ep->previous_offset);
 
        }
-      else if (reg_renumber[regno] < 0 && reg_equiv_constant
-              && reg_equiv_constant[regno]
+      else if (reg_renumber && reg_renumber[regno] < 0
+              && reg_equiv_constant && reg_equiv_constant[regno]
               && ! CONSTANT_P (reg_equiv_constant[regno]))
        return eliminate_regs (copy_rtx (reg_equiv_constant[regno]),
                               mem_mode, insn);
@@ -2316,7 +2368,7 @@ eliminate_regs (x, mem_mode, insn)
        whole instead of this little section as well as the backend issues.  */
     case PLUS:
       /* If this is the sum of an eliminable register and a constant, rework
-        the sum.   */
+        the sum.  */
       if (GET_CODE (XEXP (x, 0)) == REG
          && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
          && CONSTANT_P (XEXP (x, 1)))
@@ -2360,7 +2412,7 @@ eliminate_regs (x, mem_mode, insn)
        rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
        rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn);
 
-       if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
+       if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)))
          {
            /* If one side is a PLUS and the other side is a pseudo that
               didn't get a hard register but has a reg_equiv_constant,
@@ -2468,7 +2520,8 @@ eliminate_regs (x, mem_mode, insn)
        {
          new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
          if (new != XEXP (x, 1))
-           return gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
+           return
+             gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
        }
       return x;
 
@@ -2485,6 +2538,10 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
       if (new != XEXP (x, 0))
        return gen_rtx_fmt_e (code, GET_MODE (x), new);
@@ -2529,14 +2586,7 @@ eliminate_regs (x, mem_mode, insn)
                   )
                  || x_size == new_size)
              )
-           {
-             int offset = SUBREG_BYTE (x);
-             enum machine_mode mode = GET_MODE (x);
-
-             PUT_MODE (new, mode);
-             XEXP (new, 0) = plus_constant (XEXP (new, 0), offset);
-             return new;
-           }
+           return adjust_address_nv (new, GET_MODE (x), SUBREG_BYTE (x));
          else
            return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x));
        }
@@ -2644,6 +2694,7 @@ elimination_effects (x, mem_mode)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -2677,7 +2728,7 @@ elimination_effects (x, mem_mode)
        }
       else if (reg_renumber[regno] < 0 && reg_equiv_constant
               && reg_equiv_constant[regno]
-              && ! CONSTANT_P (reg_equiv_constant[regno]))
+              && ! function_invariant_p (reg_equiv_constant[regno]))
        elimination_effects (reg_equiv_constant[regno], mem_mode);
       return;
 
@@ -2722,6 +2773,10 @@ elimination_effects (x, mem_mode)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       elimination_effects (XEXP (x, 0), mem_mode);
       return;
 
@@ -2884,7 +2939,7 @@ eliminate_regs_in_insn (insn, replace)
   rtx old_set = single_set (insn);
   rtx new_body;
   int val = 0;
-  int i, any_changes;
+  int i;
   rtx substed_operand[MAX_RECOG_OPERANDS];
   rtx orig_operand[MAX_RECOG_OPERANDS];
   struct elim_table *ep;
@@ -2916,38 +2971,32 @@ eliminate_regs_in_insn (insn, replace)
            if (ep->from == FRAME_POINTER_REGNUM
                && ep->to == HARD_FRAME_POINTER_REGNUM)
              {
-               rtx src = SET_SRC (old_set);
-               int offset = 0, ok = 0;
-               rtx prev_insn, prev_set;
-
-               if (src == ep->to_rtx)
-                 offset = 0, ok = 1;
-               else if (GET_CODE (src) == PLUS
-                        && GET_CODE (XEXP (src, 0)) == CONST_INT
-                        && XEXP (src, 1) == ep->to_rtx)
-                 offset = INTVAL (XEXP (src, 0)), ok = 1;
-               else if (GET_CODE (src) == PLUS
-                        && GET_CODE (XEXP (src, 1)) == CONST_INT
-                        && XEXP (src, 0) == ep->to_rtx)
-                 offset = INTVAL (XEXP (src, 1)), ok = 1;
-               else if ((prev_insn = prev_nonnote_insn (insn)) != 0
-                        && (prev_set = single_set (prev_insn)) != 0
-                        && rtx_equal_p (SET_DEST (prev_set), src))
+               rtx base = SET_SRC (old_set);
+               rtx base_insn = insn;
+               int offset = 0;
+
+               while (base != ep->to_rtx)
                  {
-                   src = SET_SRC (prev_set);
-                   if (src == ep->to_rtx)
-                     offset = 0, ok = 1;
-                   else if (GET_CODE (src) == PLUS
-                            && GET_CODE (XEXP (src, 0)) == CONST_INT
-                            && XEXP (src, 1) == ep->to_rtx)
-                     offset = INTVAL (XEXP (src, 0)), ok = 1;
-                   else if (GET_CODE (src) == PLUS
-                            && GET_CODE (XEXP (src, 1)) == CONST_INT
-                            && XEXP (src, 0) == ep->to_rtx)
-                     offset = INTVAL (XEXP (src, 1)), ok = 1;
+                   rtx prev_insn, prev_set;
+
+                   if (GET_CODE (base) == PLUS
+                       && GET_CODE (XEXP (base, 1)) == CONST_INT)
+                     {
+                       offset += INTVAL (XEXP (base, 1));
+                       base = XEXP (base, 0);
+                     }
+                   else if ((prev_insn = prev_nonnote_insn (base_insn)) != 0
+                            && (prev_set = single_set (prev_insn)) != 0
+                            && rtx_equal_p (SET_DEST (prev_set), base))
+                     {
+                       base = SET_SRC (prev_set);
+                       base_insn = prev_insn;
+                     }
+                   else
+                     break;
                  }
 
-               if (ok)
+               if (base == ep->to_rtx)
                  {
                    rtx src
                      = plus_constant (ep->to_rtx, offset - ep->offset);
@@ -3065,7 +3114,6 @@ eliminate_regs_in_insn (insn, replace)
   /* Eliminate all eliminable registers occurring in operands that
      can be handled by reload.  */
   extract_insn (insn);
-  any_changes = 0;
   for (i = 0; i < recog_data.n_operands; i++)
     {
       orig_operand[i] = recog_data.operand[i];
@@ -3091,7 +3139,7 @@ eliminate_regs_in_insn (insn, replace)
          substed_operand[i] = eliminate_regs (recog_data.operand[i], 0,
                                               replace ? insn : NULL_RTX);
          if (substed_operand[i] != orig_operand[i])
-           val = any_changes = 1;
+           val = 1;
          /* Terminate the search in check_eliminable_occurrences at
             this point.  */
          *recog_data.operand_loc[i] = 0;
@@ -3190,7 +3238,7 @@ eliminate_regs_in_insn (insn, replace)
      insn.  The changes we make were determined by the earlier call to
      elimination_effects.
 
-     We also detect cases where register elimination cannot be done,
+     We also detect cases where register elimination cannot be done,
      namely, if a register would be both changed and referenced outside a MEM
      in the resulting insn since such an insn is often undefined and, even if
      not, we cannot know what meaning will be given to it.  Note that it is
@@ -3262,7 +3310,7 @@ mark_not_eliminable (dest, x, data)
      rtx x;
      void *data ATTRIBUTE_UNUSED;
 {
-  register unsigned int i;
+  unsigned int i;
 
   /* A SUBREG of a hard register here is just changing its mode.  We should
      not see a SUBREG of an eliminable hard register, but check just in
@@ -3344,7 +3392,7 @@ static void
 set_initial_label_offsets ()
 {
   rtx x;
-  memset ((char *) &offsets_known_at[get_first_label_num ()], 0, num_labels);
+  memset (offsets_known_at, 0, num_labels);
 
   for (x = forced_labels; x; x = XEXP (x, 1))
     if (XEXP (x, 0))
@@ -3365,14 +3413,15 @@ set_offsets_for_label (insn)
   num_not_at_initial_offset = 0;
   for (i = 0, ep = reg_eliminate; i < NUM_ELIMINABLE_REGS; ep++, i++)
     {
-      ep->offset = ep->previous_offset = offsets_at[label_nr][i];
+      ep->offset = ep->previous_offset
+                = offsets_at[label_nr - first_label_num][i];
       if (ep->can_eliminate && ep->offset != ep->initial_offset)
        num_not_at_initial_offset++;
     }
 }
 
 /* See if anything that happened changes which eliminations are valid.
-   For example, on the Sparc, whether or not the frame pointer can
+   For example, on the SPARC, whether or not the frame pointer can
    be eliminated can depend on what registers have been used.  We need
    not check some conditions again (such as flag_omit_frame_pointer)
    since they can't have changed.  */
@@ -3381,9 +3430,7 @@ static void
 update_eliminables (pset)
      HARD_REG_SET *pset;
 {
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
   int previous_frame_pointer_needed = frame_pointer_needed;
-#endif
   struct elim_table *ep;
 
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -3404,7 +3451,7 @@ update_eliminables (pset)
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
     {
       struct elim_table *op;
-      register int new_to = -1;
+      int new_to = -1;
 
       if (! ep->can_eliminate && ep->can_eliminate_previous)
        {
@@ -3448,12 +3495,10 @@ update_eliminables (pset)
        }
     }
 
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
   /* If we didn't need a frame pointer last time, but we do now, spill
      the hard frame pointer.  */
   if (frame_pointer_needed && ! previous_frame_pointer_needed)
     SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM);
-#endif
 }
 
 /* Initialize the table of registers to eliminate.  */
@@ -3463,7 +3508,7 @@ init_elim_table ()
 {
   struct elim_table *ep;
 #ifdef ELIMINABLE_REGS
-  struct elim_table_1 *ep1;
+  const struct elim_table_1 *ep1;
 #endif
 
   if (!reg_eliminate)
@@ -3530,7 +3575,7 @@ spill_hard_reg (regno, cant_eliminate)
      unsigned int regno;
      int cant_eliminate;
 {
-  register int i;
+  int i;
 
   if (cant_eliminate)
     {
@@ -3718,11 +3763,11 @@ finish_spills (global)
 
 static void
 scan_paradoxical_subregs (x)
-     register rtx x;
+     rtx x;
 {
-  register int i;
-  register const char *fmt;
-  register enum rtx_code code = GET_CODE (x);
+  int i;
+  const char *fmt;
+  enum rtx_code code = GET_CODE (x);
 
   switch (code)
     {
@@ -3739,6 +3784,7 @@ scan_paradoxical_subregs (x)
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR: /* shouldn't happen, but just in case.  */
     case CC0:
     case PC:
     case USE:
@@ -3763,7 +3809,7 @@ scan_paradoxical_subregs (x)
        scan_paradoxical_subregs (XEXP (x, i));
       else if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            scan_paradoxical_subregs (XVECEXP (x, i, j));
        }
@@ -3785,7 +3831,7 @@ reload_as_needed (live_known)
 {
   struct insn_chain *chain;
 #if defined (AUTO_INC_DEC)
-  register int i;
+  int i;
 #endif
   rtx x;
 
@@ -3799,7 +3845,7 @@ reload_as_needed (live_known)
 
   for (chain = reload_insn_chain; chain; chain = chain->next)
     {
-      rtx prev;
+      rtx prev = 0;
       rtx insn = chain->insn;
       rtx old_next = NEXT_INSN (insn);
 
@@ -3810,7 +3856,7 @@ reload_as_needed (live_known)
 
       else if (INSN_P (insn))
        {
-         rtx oldpat = PATTERN (insn);
+         rtx oldpat = copy_rtx (PATTERN (insn));
 
          /* If this is a USE and CLOBBER of a MEM, ensure that any
             references to eliminable registers have been removed.  */
@@ -3894,6 +3940,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 && INSN_P (p)
+                     && GET_CODE (PATTERN (p)) != USE
                      && (recog_memoized (p) < 0
                          || (extract_insn (p), ! constrain_operands (1))))
                    {
@@ -3941,7 +3988,7 @@ reload_as_needed (live_known)
                                            REGNO (rld[i].reg_rtx))
                      /* Make sure it is the inc/dec pseudo, and not
                         some other (e.g. output operand) pseudo.  */
-                     && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                     && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                          == REGNO (XEXP (in_reg, 0))))
 
                    {
@@ -4008,7 +4055,7 @@ reload_as_needed (live_known)
                                                 REGNO (rld[i].reg_rtx))
                           /* Make sure it is the inc/dec pseudo, and not
                              some other (e.g. output operand) pseudo.  */
-                          && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                          && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                               == REGNO (XEXP (in_reg, 0))))
                    {
                      SET_HARD_REG_BIT (reg_is_output_reload,
@@ -4042,7 +4089,7 @@ reload_as_needed (live_known)
       /* Don't assume a reload reg is still good after a call insn
         if it is a call-used reg.  */
       else if (GET_CODE (insn) == CALL_INSN)
-       AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
+       AND_COMPL_HARD_REG_SET (reg_reloaded_valid, call_used_reg_set);
     }
 
   /* Clean up.  */
@@ -4065,23 +4112,21 @@ forget_old_reloads_1 (x, ignored, data)
 {
   unsigned int regno;
   unsigned int nr;
-  int offset = 0;
 
   /* 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_regno_offset (REGNO (SUBREG_REG (x)),
-                                    GET_MODE (SUBREG_REG (x)),
-                                    SUBREG_BYTE (x),
-                                    GET_MODE (x));
+      /* We ignore the subreg offset when calculating the regno,
+        because we are using the entire underlying hard register
+        below.  */
       x = SUBREG_REG (x);
     }
 
   if (GET_CODE (x) != REG)
     return;
 
-  regno = REGNO (x) + offset;
+  regno = REGNO (x);
 
   if (regno >= FIRST_PSEUDO_REGISTER)
     nr = 1;
@@ -4294,10 +4339,10 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
       abort ();
     }
   /* We resolve conflicts with remaining reloads of the same type by
-     excluding the intervals of of reload registers by them from the
+     excluding the intervals of reload registers by them from the
      interval of freed reload registers.  Since we only keep track of
      one set of interval bounds, we might have to exclude somewhat
-     more then what would be necessary if we used a HARD_REG_SET here.
+     more than what would be necessary if we used a HARD_REG_SET here.
      But this should only happen very infrequently, so there should
      be no reason to worry about it.  */
 
@@ -4417,11 +4462,13 @@ reload_reg_free_p (regno, opnum, type)
 
     case RELOAD_FOR_OUTPUT_ADDRESS:
       /* Can't use a register if it is used for an output address for this
-        operand or used as an output in this or a later operand.  */
+        operand or used as an output in this or a later operand.  Note
+        that multiple output operands are emitted in reverse order, so
+        the conflicting ones are those with lower indices.  */
       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
        return 0;
 
-      for (i = opnum; i < reload_n_operands; i++)
+      for (i = 0; i <= opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4430,11 +4477,13 @@ reload_reg_free_p (regno, opnum, type)
     case RELOAD_FOR_OUTADDR_ADDRESS:
       /* Can't use a register if it is used for an output address
         for this operand or used as an output in this or a
-        later operand.  */
+        later operand.  Note that multiple output operands are
+        emitted in reverse order, so the conflicting ones are
+        those with lower indices.  */
       if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
        return 0;
 
-      for (i = opnum; i < reload_n_operands; i++)
+      for (i = 0; i <= opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4457,7 +4506,9 @@ reload_reg_free_p (regno, opnum, type)
 
     case RELOAD_FOR_OUTPUT:
       /* This cannot share a register with RELOAD_FOR_INSN reloads, other
-        outputs, or an operand address for this or an earlier output.  */
+        outputs, or an operand address for this or an earlier output.
+        Note that multiple output operands are emitted in reverse order,
+        so the conflicting ones are those with higher indices.  */
       if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
        return 0;
 
@@ -4465,7 +4516,7 @@ reload_reg_free_p (regno, opnum, type)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
-      for (i = 0; i <= opnum; i++)
+      for (i = opnum; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
@@ -4601,7 +4652,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
       /* These conflict with other outputs with RELOAD_OTHER.  So
         we need only check for output addresses.  */
 
-      opnum = -1;
+      opnum = reload_n_operands;
 
       /* ... fall through ...  */
 
@@ -4609,8 +4660,10 @@ reload_reg_reaches_end_p (regno, opnum, type)
     case RELOAD_FOR_OUTPUT_ADDRESS:
     case RELOAD_FOR_OUTADDR_ADDRESS:
       /* We already know these can't conflict with a later output.  So the
-        only thing to check are later output addresses.  */
-      for (i = opnum + 1; i < reload_n_operands; i++)
+        only thing to check are later output addresses.
+        Note that multiple output operands are emitted in reverse order,
+        so the conflicting ones are those with lower indices.  */
+      for (i = 0; i < opnum; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
@@ -4662,11 +4715,11 @@ reloads_conflict (r1, r2)
 
     case RELOAD_FOR_OUTPUT_ADDRESS:
       return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum)
-             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum <= r1_opnum));
 
     case RELOAD_FOR_OUTADDR_ADDRESS:
       return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum)
-             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum <= r1_opnum));
 
     case RELOAD_FOR_OPERAND_ADDRESS:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
@@ -4680,7 +4733,7 @@ reloads_conflict (r1, r2)
       return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT
              || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS
                   || r2_type == RELOAD_FOR_OUTADDR_ADDRESS)
-                 && r2_opnum <= r1_opnum));
+                 && r2_opnum >= r1_opnum));
 
     case RELOAD_FOR_INSN:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_OUTPUT
@@ -4706,7 +4759,7 @@ char reload_inherited[MAX_RELOADS];
    if we know it.  Otherwise, this is 0.  */
 rtx reload_inheritance_insn[MAX_RELOADS];
 
-/* If non-zero, this is a place to get the value of the reload,
+/* If nonzero, this is a place to get the value of the reload,
    rather than using reload_in.  */
 rtx reload_override_in[MAX_RELOADS];
 
@@ -4811,7 +4864,7 @@ reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
       rtx reg = rld[i].reg_rtx;
       if (reg && GET_CODE (reg) == REG
          && ((unsigned) regno - true_regnum (reg)
-             <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
+             <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned) 1)
          && i != reloadnum)
        {
          rtx other_input = rld[i].in;
@@ -4947,7 +5000,7 @@ reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
    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
+   unless OUT is nonzero 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
@@ -5006,7 +5059,7 @@ failed_reload (insn, r)
 {
   if (asm_noperands (PATTERN (insn)) < 0)
     /* It's the compiler's fault.  */
-    fatal_insn ("Could not find a spill register", insn);
+    fatal_insn ("could not find a spill register", insn);
 
   /* It's the user's fault; the operand's mode and constraint
      don't match.  Disable this reload so we don't crash in final.  */
@@ -5070,7 +5123,7 @@ set_reload_reg (i, r)
 }
 
 /* Find a spill register to use as a reload register for reload R.
-   LAST_RELOAD is non-zero if this is the last reload for the insn being
+   LAST_RELOAD is nonzero if this is the last reload for the insn being
    processed.
 
    Set rld[R].reg_rtx to the register allocated.
@@ -5268,7 +5321,7 @@ choose_reload_regs (chain)
      struct insn_chain *chain;
 {
   rtx insn = chain->insn;
-  register int i, j;
+  int i, j;
   unsigned int max_group_size = 1;
   enum reg_class group_class = NO_REGS;
   int pass, win, inheritance;
@@ -5293,7 +5346,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;
@@ -5332,7 +5385,7 @@ choose_reload_regs (chain)
 
       for (j = 0; j < n_reloads; j++)
        {
-         register int r = reload_order[j];
+         int r = reload_order[j];
          rtx search_equiv = NULL_RTX;
 
          /* Ignore reloads that got marked inoperative.  */
@@ -5385,7 +5438,7 @@ choose_reload_regs (chain)
          if (inheritance)
            {
              int byte = 0;
-             register int regno = -1;
+             int regno = -1;
              enum machine_mode mode = VOIDmode;
 
              if (rld[r].in == 0)
@@ -5448,16 +5501,15 @@ choose_reload_regs (chain)
                                                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
+#ifdef CANNOT_CHANGE_MODE_CLASS
+                     (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
+                                                 need_mode)
+                      &&
+#endif
                      (GET_MODE_SIZE (GET_MODE (last_reg))
                       >= GET_MODE_SIZE (need_mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+                     )
 #endif
                      && reg_reloaded_contents[i] == regno
                      && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
@@ -5534,6 +5586,7 @@ choose_reload_regs (chain)
                                  && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
                              /* Don't clobber the frame pointer.  */
                              || (i == HARD_FRAME_POINTER_REGNUM
+                                 && frame_pointer_needed
                                  && rld[r].out)
                              /* Don't really use the inherited spill reg
                                 if we need it wider than we've got it.  */
@@ -5604,7 +5657,7 @@ choose_reload_regs (chain)
 
          if (search_equiv)
            {
-             register rtx equiv
+             rtx equiv
                = find_equiv_reg (search_equiv, insn, rld[r].class,
                                  -1, NULL, 0, rld[r].mode);
              int regno = 0;
@@ -5704,7 +5757,9 @@ choose_reload_regs (chain)
 
              /* If we found an equivalent reg, say no code need be generated
                 to load it, and use it as our reload reg.  */
-             if (equiv != 0 && regno != HARD_FRAME_POINTER_REGNUM)
+             if (equiv != 0
+                 && (regno != HARD_FRAME_POINTER_REGNUM
+                     || !frame_pointer_needed))
                {
                  int nr = HARD_REGNO_NREGS (regno, rld[r].mode);
                  int k;
@@ -5779,7 +5834,7 @@ choose_reload_regs (chain)
         didn't get one yet.  */
       for (j = 0; j < n_reloads; j++)
        {
-         register int r = reload_order[j];
+         int r = reload_order[j];
 
          /* Ignore reloads that got marked inoperative.  */
          if (rld[r].out == 0 && rld[r].in == 0 && ! rld[r].secondary_p)
@@ -5840,7 +5895,7 @@ choose_reload_regs (chain)
     {
       for (j = 0; j < n_reloads; j++)
        {
-         register int r = reload_order[j];
+         int r = reload_order[j];
          rtx check_reg;
          if (reload_inherited[r] && rld[r].reg_rtx)
            check_reg = rld[r].reg_rtx;
@@ -5870,7 +5925,7 @@ choose_reload_regs (chain)
             A special case are auto_inc expressions; even if the input is
             inherited, we still need the address for the output.  We can
             recognize them because they have RELOAD_OUT set to RELOAD_IN.
-            If we suceeded removing some reload and we are doing a preliminary
+            If we succeeded removing some reload and we are doing a preliminary
             pass just to remove such reloads, make another pass, since the
             removal of one reload might allow us to inherit another one.  */
          else if (rld[r].in
@@ -5886,7 +5941,7 @@ choose_reload_regs (chain)
     if (reload_override_in[j])
       rld[j].in = reload_override_in[j];
 
-  /* If this reload won't be done because it has been cancelled or is
+  /* If this reload won't be done because it has been canceled or is
      optional and not inherited, clear reload_reg_rtx so other
      routines (such as subst_reloads) don't get confused.  */
   for (j = 0; j < n_reloads; j++)
@@ -5907,7 +5962,7 @@ choose_reload_regs (chain)
   /* Record which pseudos and which spill regs have output reloads.  */
   for (j = 0; j < n_reloads; j++)
     {
-      register int r = reload_order[j];
+      int r = reload_order[j];
 
       i = reload_spill_index[r];
 
@@ -5917,7 +5972,7 @@ choose_reload_regs (chain)
       if (rld[r].out_reg != 0 && GET_CODE (rld[r].out_reg) == REG
          && rld[r].reg_rtx != 0)
        {
-         register int nregno = REGNO (rld[r].out_reg);
+         int nregno = REGNO (rld[r].out_reg);
          int nr = 1;
 
          if (nregno < FIRST_PSEUDO_REGISTER)
@@ -5960,7 +6015,7 @@ deallocate_reload_reg (r)
   reload_spill_index[r] = -1;
 }
 \f
-/* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
+/* If SMALL_REGISTER_CLASSES is nonzero, we may not have merged two
    reloads of the same item for fear that we might not have enough reload
    registers. However, normally they will get the same reload register
    and hence actually need not be loaded twice.
@@ -6055,17 +6110,39 @@ merge_assigned_reloads (insn)
             if they were for inputs, RELOAD_OTHER for outputs.  Note that
             this test is equivalent to looking for reloads for this operand
             number.  */
+         /* We must take special care when there are two or more reloads to
+            be merged and a RELOAD_FOR_OUTPUT_ADDRESS reload that loads the
+            same value or a part of it; we must not change its type if there
+            is a conflicting input.  */
 
          if (rld[i].when_needed == RELOAD_OTHER)
            for (j = 0; j < n_reloads; j++)
              if (rld[j].in != 0
                  && rld[j].when_needed != RELOAD_OTHER
+                 && rld[j].when_needed != RELOAD_FOR_OTHER_ADDRESS
+                 && (! conflicting_input
+                     || rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
+                     || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
                  && reg_overlap_mentioned_for_reload_p (rld[j].in,
                                                         rld[i].in))
-               rld[j].when_needed
-                 = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
-                     || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
-                    ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
+               {
+                 int k;
+
+                 rld[j].when_needed
+                   = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
+                       || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
+                      ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
+
+                 /* Check to see if we accidentally converted two reloads
+                    that use the same reload register to the same type.
+                    If so, the resulting code won't work, so abort.  */
+                 if (rld[j].reg_rtx)
+                   for (k = 0; k < j; k++)
+                     if (rld[k].in != 0 && rld[k].reg_rtx != 0
+                         && rld[k].when_needed == rld[j].when_needed
+                         && rtx_equal_p (rld[k].reg_rtx, rld[j].reg_rtx))
+                       abort ();
+               }
        }
     }
 }
@@ -6098,7 +6175,7 @@ emit_input_reload_insns (chain, rl, old, j)
      int j;
 {
   rtx insn = chain->insn;
-  register rtx reloadreg = rl->reg_rtx;
+  rtx reloadreg = rl->reg_rtx;
   rtx oldequiv_reg = 0;
   rtx oldequiv = 0;
   int special = 0;
@@ -6184,10 +6261,10 @@ emit_input_reload_insns (chain, rl, old, j)
       /* If it is no cheaper to copy from OLDEQUIV into the
         reload register than it would be to move from memory,
         don't use it. Likewise, if we need a secondary register
-        or memory.   */
+        or memory.  */
 
       if (oldequiv != 0
-         && ((REGNO_REG_CLASS (regno) != rl->class
+         && (((enum reg_class) REGNO_REG_CLASS (regno) != rl->class
               && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
                                       rl->class)
                   >= MEMORY_MOVE_COST (mode, rl->class, 1)))
@@ -6243,7 +6320,7 @@ emit_input_reload_insns (chain, rl, old, j)
      must always be a REG here.  */
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
   while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
     oldequiv = SUBREG_REG (oldequiv);
   if (GET_MODE (oldequiv) != VOIDmode
@@ -6340,38 +6417,43 @@ emit_input_reload_insns (chain, rl, old, j)
          && SET_DEST (PATTERN (temp)) == old
          /* Make sure we can access insn_operand_constraint.  */
          && asm_noperands (PATTERN (temp)) < 0
-         /* This is unsafe if prev insn rejects our reload reg.  */
-         && constraint_accepts_reg_p (insn_data[recog_memoized (temp)].operand[0].constraint,
-                                      reloadreg)
          /* This is unsafe if operand occurs more than once in current
             insn.  Perhaps some occurrences aren't reloaded.  */
-         && count_occurrences (PATTERN (insn), old, 0) == 1
-         /* Don't risk splitting a matching pair of operands.  */
-         && ! reg_mentioned_p (old, SET_SRC (PATTERN (temp))))
+         && count_occurrences (PATTERN (insn), old, 0) == 1)
        {
+         rtx old = SET_DEST (PATTERN (temp));
          /* Store into the reload register instead of the pseudo.  */
          SET_DEST (PATTERN (temp)) = reloadreg;
 
-         /* If the previous insn is an output reload, the source is
-            a reload register, and its spill_reg_store entry will
-            contain the previous destination.  This is now
-            invalid.  */
-         if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
-             && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
+         /* Verify that resulting insn is valid.  */
+         extract_insn (temp);
+         if (constrain_operands (1))
            {
-             spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
-             spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
-           }
+             /* If the previous insn is an output reload, the source is
+                a reload register, and its spill_reg_store entry will
+                contain the previous destination.  This is now
+                invalid.  */
+             if (GET_CODE (SET_SRC (PATTERN (temp))) == REG
+                 && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER)
+               {
+                 spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0;
+                 spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0;
+               }
 
-         /* If these are the only uses of the pseudo reg,
-            pretend for GDB it lives in the reload reg we used.  */
-         if (REG_N_DEATHS (REGNO (old)) == 1
-             && REG_N_SETS (REGNO (old)) == 1)
+             /* If these are the only uses of the pseudo reg,
+                pretend for GDB it lives in the reload reg we used.  */
+             if (REG_N_DEATHS (REGNO (old)) == 1
+                 && REG_N_SETS (REGNO (old)) == 1)
+               {
+                 reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
+                 alter_reg (REGNO (old), -1);
+               }
+             special = 1;
+           }
+         else
            {
-             reg_renumber[REGNO (old)] = REGNO (rl->reg_rtx);
-             alter_reg (REGNO (old), -1);
+             SET_DEST (PATTERN (temp)) = old;
            }
-         special = 1;
        }
     }
 
@@ -6487,8 +6569,8 @@ emit_input_reload_insns (chain, rl, old, j)
                        oldequiv = old, real_oldequiv = real_old;
                      else
                        second_reload_reg
-                         = gen_rtx_REG (new_mode,
-                                        REGNO (second_reload_reg));
+                         = reload_adjust_reg_for_mode (second_reload_reg,
+                                                       new_mode);
                    }
                }
            }
@@ -6553,8 +6635,9 @@ emit_input_reload_insns (chain, rl, old, j)
                  || (reg_equiv_constant
                      [REGNO (SUBREG_REG (oldequiv))] != 0)))
          || (CONSTANT_P (oldequiv)
-             && PREFERRED_RELOAD_CLASS (oldequiv,
-                       REGNO_REG_CLASS (REGNO (reloadreg))) == NO_REGS))
+             && (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);
@@ -6566,7 +6649,7 @@ emit_input_reload_insns (chain, rl, old, j)
   /* 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)
@@ -6609,7 +6692,7 @@ emit_output_reload_insns (chain, rl, j)
     }
 
   if (GET_MODE (reloadreg) != mode)
-    reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+    reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
 
@@ -6650,7 +6733,7 @@ emit_output_reload_insns (chain, rl, j)
                = rld[secondary_reload].secondary_out_icode;
 
              if (GET_MODE (reloadreg) != mode)
-               reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
+               reloadreg = reload_adjust_reg_for_mode (reloadreg, mode);
 
              if (tertiary_icode != CODE_FOR_nothing)
                {
@@ -6775,7 +6858,7 @@ emit_output_reload_insns (chain, rl, j)
 
   if (rl->when_needed == RELOAD_OTHER)
     {
-      emit_insns (other_output_reload_insns[rl->opnum]);
+      emit_insn (other_output_reload_insns[rl->opnum]);
       other_output_reload_insns[rl->opnum] = get_insns ();
     }
   else
@@ -6795,7 +6878,6 @@ do_input_reload (chain, rl, j)
      struct reload *rl;
      int j;
 {
-  int expect_occurrences = 1;
   rtx insn = chain->insn;
   rtx old = (rl->in && GET_CODE (rl->in) == MEM
             ? rl->in_reg : rl->in);
@@ -6816,11 +6898,7 @@ do_input_reload (chain, rl, j)
       && GET_CODE (rl->in_reg) == MEM
       && reload_spill_index[j] >= 0
       && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
-    {
-      expect_occurrences
-       = count_occurrences (PATTERN (insn), rl->in, 0) == 1 ? 0 : -1;
-      rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
-    }
+    rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
 
   /* If we are reloading a register that was recently stored in with an
      output-reload, see if we can prove there was
@@ -6866,6 +6944,7 @@ do_output_reload (chain, rl, j)
   rtx pseudo = rl->out_reg;
 
   if (pseudo
+      && optimize
       && GET_CODE (pseudo) == REG
       && ! rtx_equal_p (rl->in_reg, pseudo)
       && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER
@@ -6929,7 +7008,7 @@ emit_reload_insns (chain)
 {
   rtx insn = chain->insn;
 
-  register int j;
+  int j;
 
   CLEAR_HARD_REG_SET (reg_reloaded_died);
 
@@ -6990,25 +7069,25 @@ emit_reload_insns (chain)
      reloads for the operand.  The RELOAD_OTHER output reloads are
      output in descending order by reload number.  */
 
-  emit_insns_before (other_input_address_reload_insns, insn);
-  emit_insns_before (other_input_reload_insns, insn);
+  emit_insn_before (other_input_address_reload_insns, insn);
+  emit_insn_before (other_input_reload_insns, insn);
 
   for (j = 0; j < reload_n_operands; j++)
     {
-      emit_insns_before (inpaddr_address_reload_insns[j], insn);
-      emit_insns_before (input_address_reload_insns[j], insn);
-      emit_insns_before (input_reload_insns[j], insn);
+      emit_insn_before (inpaddr_address_reload_insns[j], insn);
+      emit_insn_before (input_address_reload_insns[j], insn);
+      emit_insn_before (input_reload_insns[j], insn);
     }
 
-  emit_insns_before (other_operand_reload_insns, insn);
-  emit_insns_before (operand_reload_insns, insn);
+  emit_insn_before (other_operand_reload_insns, insn);
+  emit_insn_before (operand_reload_insns, insn);
 
   for (j = 0; j < reload_n_operands; j++)
     {
-      rtx x = emit_insns_after (outaddr_address_reload_insns[j], insn);
-      x = emit_insns_after (output_address_reload_insns[j], x);
-      x = emit_insns_after (output_reload_insns[j], x);
-      emit_insns_after (other_output_reload_insns[j], x);
+      rtx x = emit_insn_after (outaddr_address_reload_insns[j], insn);
+      x = emit_insn_after (output_address_reload_insns[j], x);
+      x = emit_insn_after (output_reload_insns[j], x);
+      emit_insn_after (other_output_reload_insns[j], x);
     }
 
   /* For all the spill regs newly reloaded in this instruction,
@@ -7020,8 +7099,8 @@ emit_reload_insns (chain)
 
   for (j = 0; j < n_reloads; j++)
     {
-      register int r = reload_order[j];
-      register int i = reload_spill_index[r];
+      int r = reload_order[j];
+      int i = reload_spill_index[r];
 
       /* If this is a non-inherited input reload from a pseudo, we must
         clear any memory of a previous store to the same pseudo.  Only do
@@ -7096,7 +7175,7 @@ emit_reload_insns (chain)
                             : rld[r].out_reg
                             ? rld[r].out_reg
 /* AUTO_INC */              : XEXP (rld[r].in_reg, 0));
-                 register int nregno = REGNO (out);
+                 int nregno = REGNO (out);
                  int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
                             : HARD_REGNO_NREGS (nregno,
                                                 GET_MODE (rld[r].reg_rtx)));
@@ -7115,8 +7194,7 @@ emit_reload_insns (chain)
                    for (k = 1; k < nnr; k++)
                      reg_last_reload_reg[nregno + k]
                        = (nr == nnr
-                          ? gen_rtx_REG (reg_raw_mode[REGNO (rld[r].reg_rtx) + k],
-                                         REGNO (rld[r].reg_rtx) + k)
+                          ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
                           : 0);
 
                  /* Now do the inverse operation.  */
@@ -7144,7 +7222,7 @@ emit_reload_insns (chain)
                               && ! reg_has_output_reload[REGNO (rld[r].in_reg)]))
                       && ! reg_set_p (rld[r].reg_rtx, PATTERN (insn)))
                {
-                 register int nregno;
+                 int nregno;
                  int nnr;
 
                  if (GET_CODE (rld[r].in) == REG
@@ -7165,8 +7243,7 @@ emit_reload_insns (chain)
                    for (k = 1; k < nnr; k++)
                      reg_last_reload_reg[nregno + k]
                        = (nr == nnr
-                          ? gen_rtx_REG (reg_raw_mode[REGNO (rld[r].reg_rtx) + k],
-                                         REGNO (rld[r].reg_rtx) + k)
+                          ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
                           : 0);
 
                  /* Unless we inherited this reload, show we haven't
@@ -7217,7 +7294,7 @@ emit_reload_insns (chain)
        {
          rtx out = (GET_CODE (rld[r].out) == REG
                     ? rld[r].out : rld[r].out_reg);
-         register int nregno = REGNO (out);
+         int nregno = REGNO (out);
          if (nregno >= FIRST_PSEUDO_REGISTER)
            {
              rtx src_reg, store_insn = NULL_RTX;
@@ -7470,10 +7547,12 @@ gen_reload (out, in, opnum, type)
 
 #ifdef SECONDARY_MEMORY_NEEDED
   /* If we need a memory location to do the move, do it that way.  */
-  else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
-          && GET_CODE (out) == REG && REGNO (out) < FIRST_PSEUDO_REGISTER
-          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
-                                      REGNO_REG_CLASS (REGNO (out)),
+  else if ((GET_CODE (in) == REG || GET_CODE (in) == SUBREG)
+          && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER
+          && (GET_CODE (out) == REG || GET_CODE (out) == SUBREG)
+          && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER
+          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)),
+                                      REGNO_REG_CLASS (reg_or_subregno (out)),
                                       GET_MODE (out)))
     {
       /* Get the memory to use and rewrite both registers to its mode.  */
@@ -7512,9 +7591,8 @@ gen_reload (out, in, opnum, type)
   return last ? NEXT_INSN (last) : get_insns ();
 }
 \f
-/* Delete a previously made output-reload
-   whose result we now believe is not needed.
-   First we double-check.
+/* Delete a previously made output-reload whose result we now believe
+   is not needed.  First we double-check.
 
    INSN is the insn now being processed.
    LAST_RELOAD_REG is the hard register number for which we want to delete
@@ -7533,9 +7611,14 @@ delete_output_reload (insn, j, last_reload_reg)
   int k;
   int n_occurrences;
   int n_inherited = 0;
-  register rtx i1;
+  rtx i1;
   rtx substed;
 
+  /* It is possible that this reload has been only used to set another reload
+     we eliminated earlier and thus deleted this instruction too.  */
+  if (INSN_DELETED_P (output_reload_insn))
+    return;
+
   /* Get the raw pseudo-register referred to.  */
 
   while (GET_CODE (reg) == SUBREG)
@@ -7608,15 +7691,21 @@ delete_output_reload (insn, j, last_reload_reg)
        }
     }
 
+  /* We will be deleting the insn.  Remove the spill reg information.  */
+  for (k = HARD_REGNO_NREGS (last_reload_reg, GET_MODE (reg)); k-- > 0; )
+    {
+      spill_reg_store[last_reload_reg + k] = 0;
+      spill_reg_stored_to[last_reload_reg + k] = 0;
+    }
+
   /* The caller has already checked that REG dies or is set in INSN.
-     It has also checked that we are optimizing, and thus some inaccurancies
-     in the debugging information are acceptable.
-     So we could just delete output_reload_insn.
-     But in some cases we can improve the debugging information without
-     sacrificing optimization - maybe even improving the code:
-     See if the pseudo reg has been completely replaced
-     with reload regs.  If so, delete the store insn
-     and forget we had a stack slot for the pseudo.  */
+     It has also checked that we are optimizing, and thus some
+     inaccuracies in the debugging information are acceptable.
+     So we could just delete output_reload_insn.  But in some cases
+     we can improve the debugging information without sacrificing
+     optimization - maybe even improving the code: See if the pseudo
+     reg has been completely replaced with reload regs.  If so, delete
+     the store insn and forget we had a stack slot for the pseudo.  */
   if (rld[j].out != rld[j].in
       && REG_N_DEATHS (REGNO (reg)) == 1
       && REG_N_SETS (REGNO (reg)) == 1
@@ -7625,11 +7714,10 @@ delete_output_reload (insn, j, last_reload_reg)
     {
       rtx i2;
 
-      /* We know that it was used only between here
-        and the beginning of the current basic block.
-        (We also know that the last use before INSN was
-        the output reload we are thinking of deleting, but never mind that.)
-        Search that range; see if any ref remains.  */
+      /* We know that it was used only between here and the beginning of
+        the current basic block.  (We also know that the last use before
+        INSN was the output reload we are thinking of deleting, but never
+        mind that.)  Search that range; see if any ref remains.  */
       for (i2 = PREV_INSN (insn); i2; i2 = PREV_INSN (i2))
        {
          rtx set = single_set (i2);
@@ -7652,7 +7740,8 @@ delete_output_reload (insn, j, last_reload_reg)
            }
        }
 
-      /* Delete the now-dead stores into this pseudo.  */
+      /* Delete the now-dead stores into this pseudo.  Note that this
+        loop also takes care of deleting output_reload_insn.  */
       for (i2 = PREV_INSN (insn); i2; i2 = PREV_INSN (i2))
        {
          rtx set = single_set (i2);
@@ -7660,8 +7749,6 @@ delete_output_reload (insn, j, last_reload_reg)
          if (set != 0 && SET_DEST (set) == reg)
            {
              delete_address_reloads (i2, insn);
-             /* This might be a basic block head,
-                thus don't use delete_insn.  */
              delete_insn (i2);
            }
          if (GET_CODE (i2) == CODE_LABEL
@@ -7669,14 +7756,15 @@ delete_output_reload (insn, j, last_reload_reg)
            break;
        }
 
-      /* For the debugging info,
-        say the pseudo lives in this reload reg.  */
+      /* For the debugging info, say the pseudo lives in this reload reg.  */
       reg_renumber[REGNO (reg)] = REGNO (rld[j].reg_rtx);
       alter_reg (REGNO (reg), -1);
     }
-  delete_address_reloads (output_reload_insn, insn);
-  delete_insn (output_reload_insn);
-
+  else
+    {
+      delete_address_reloads (output_reload_insn, insn);
+      delete_insn (output_reload_insn);
+    }
 }
 
 /* We are going to delete DEAD_INSN.  Recursively delete loads of
@@ -7814,7 +7902,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
                  return;
              /* ??? We can't finish the loop here, because dst might be
                 allocated to a pseudo in this block if no reload in this
-                block needs any of the clsses containing DST - see
+                block needs any of the classes containing DST - see
                 spill_hard_reg.  There is no easy way to tell this, so we
                 have to scan till the end of the basic block.  */
            }
@@ -7856,7 +7944,7 @@ inc_for_reload (reloadreg, in, value, inc_amount)
   rtx real_in = in == value ? XEXP (in, 0) : in;
 
   /* No hard register is equivalent to this register after
-     inc/dec operation.  If REG_LAST_RELOAD_REG were non-zero,
+     inc/dec operation.  If REG_LAST_RELOAD_REG were nonzero,
      we could inc/dec that register as well (maybe even using it for
      the source), but I'm not sure it's worth worrying about.  */
   if (GET_CODE (incloc) == REG)
@@ -7931,85 +8019,23 @@ inc_for_reload (reloadreg, in, value, inc_amount)
   return store;
 }
 \f
-/* Return 1 if we are certain that the constraint-string STRING allows
-   the hard register REG.  Return 0 if we can't be sure of this.  */
-
-static int
-constraint_accepts_reg_p (string, reg)
-     const char *string;
-     rtx reg;
-{
-  int value = 0;
-  int regno = true_regnum (reg);
-  int c;
-
-  /* Initialize for first alternative.  */
-  value = 0;
-  /* Check that each alternative contains `g' or `r'.  */
-  while (1)
-    switch (c = *string++)
-      {
-      case 0:
-       /* If an alternative lacks `g' or `r', we lose.  */
-       return value;
-      case ',':
-       /* If an alternative lacks `g' or `r', we lose.  */
-       if (value == 0)
-         return 0;
-       /* Initialize for next alternative.  */
-       value = 0;
-       break;
-      case 'g':
-      case 'r':
-       /* Any general reg wins for this alternative.  */
-       if (TEST_HARD_REG_BIT (reg_class_contents[(int) GENERAL_REGS], regno))
-         value = 1;
-       break;
-      default:
-       /* Any reg in specified class wins for this alternative.  */
-       {
-         enum reg_class class = REG_CLASS_FROM_LETTER (c);
-
-         if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno))
-           value = 1;
-       }
-      }
-}
-\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,
-   we could loose important register lifeness information on
-   SMALL_REGISTER_CLASSES machines, where return registers might be used as
-   spills:  subsequent passes assume that spill registers are dead at the end
-   of a basic block.
-   VALUE must be the return value in such a case, NULL otherwise.  */
-static void
-reload_cse_delete_noop_set (insn, value)
-     rtx insn, value;
-{
-  if (value)
-    {
-      PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
-      INSN_CODE (insn) = -1;
-      REG_NOTES (insn) = NULL_RTX;
-    }
-  else
-    delete_insn (insn);
-}
 
 /* See whether a single set SET is a noop.  */
 static int
 reload_cse_noop_set_p (set)
      rtx set;
 {
+  if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
+    return 0;
+
   return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
 }
 
 /* Try to simplify INSN.  */
 static void
-reload_cse_simplify (insn)
+reload_cse_simplify (insn, testreg)
      rtx insn;
+     rtx testreg;
 {
   rtx body = PATTERN (insn);
 
@@ -8027,16 +8053,17 @@ reload_cse_simplify (insn)
       if (!count && reload_cse_noop_set_p (body))
        {
          rtx value = SET_DEST (body);
-         if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
+         if (REG_P (value)
+             && ! REG_FUNCTION_VALUE_P (value))
            value = 0;
-         reload_cse_delete_noop_set (insn, value);
+         delete_insn_and_edges (insn);
          return;
        }
 
       if (count > 0)
        apply_change_group ();
       else
-       reload_cse_simplify_operands (insn);
+       reload_cse_simplify_operands (insn, testreg);
     }
   else if (GET_CODE (body) == PARALLEL)
     {
@@ -8053,7 +8080,8 @@ reload_cse_simplify (insn)
            {
              if (! reload_cse_noop_set_p (part))
                break;
-             if (REG_FUNCTION_VALUE_P (SET_DEST (part)))
+             if (REG_P (SET_DEST (part))
+                 && REG_FUNCTION_VALUE_P (SET_DEST (part)))
                {
                  if (value)
                    break;
@@ -8066,7 +8094,7 @@ reload_cse_simplify (insn)
 
       if (i < 0)
        {
-         reload_cse_delete_noop_set (insn, value);
+         delete_insn_and_edges (insn);
          /* We're done with this insn.  */
          return;
        }
@@ -8079,7 +8107,7 @@ reload_cse_simplify (insn)
       if (count > 0)
        apply_change_group ();
       else
-       reload_cse_simplify_operands (insn);
+       reload_cse_simplify_operands (insn, testreg);
     }
 }
 
@@ -8105,6 +8133,7 @@ reload_cse_regs_1 (first)
      rtx first;
 {
   rtx insn;
+  rtx testreg = gen_rtx_REG (VOIDmode, -1);
 
   cselib_init ();
   init_alias_analysis ();
@@ -8112,7 +8141,7 @@ reload_cse_regs_1 (first)
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       if (INSN_P (insn))
-       reload_cse_simplify (insn);
+       reload_cse_simplify (insn, testreg);
 
       cselib_process_insn (insn);
     }
@@ -8170,7 +8199,7 @@ reload_cse_simplify_set (set, insn)
 #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 
+     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
@@ -8255,7 +8284,13 @@ reload_cse_simplify_set (set, insn)
        {
 #ifdef LOAD_EXTEND_OP
          if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
-             && extend_op != NIL)
+             && extend_op != NIL
+#ifdef CANNOT_CHANGE_MODE_CLASS
+             && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+                                           word_mode,
+                                           REGNO_REG_CLASS (REGNO (SET_DEST (set))))
+#endif
+             )
            {
              rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
              ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
@@ -8283,8 +8318,9 @@ reload_cse_simplify_set (set, insn)
    hard registers.  */
 
 static int
-reload_cse_simplify_operands (insn)
+reload_cse_simplify_operands (insn, testreg)
      rtx insn;
+     rtx testreg;
 {
   int i, j;
 
@@ -8304,7 +8340,6 @@ reload_cse_simplify_operands (insn)
   int *op_alt_regno[MAX_RECOG_OPERANDS];
   /* Array of alternatives, sorted in order of decreasing desirability.  */
   int *alternative_order;
-  rtx reg = gen_rtx_REG (VOIDmode, -1);
 
   extract_insn (insn);
 
@@ -8318,8 +8353,8 @@ reload_cse_simplify_operands (insn)
   alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
   alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
   alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
-  memset ((char *)alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
-  memset ((char *)alternative_nregs, 0, 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++)
@@ -8388,8 +8423,8 @@ reload_cse_simplify_operands (insn)
          if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
            continue;
 
-         REGNO (reg) = regno;
-         PUT_MODE (reg, mode);
+         REGNO (testreg) = regno;
+         PUT_MODE (testreg, mode);
 
          /* We found a register equal to this operand.  Now look for all
             alternatives that can accept this register and have not been
@@ -8398,7 +8433,7 @@ reload_cse_simplify_operands (insn)
          p = constraints[i];
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              switch (c)
                {
@@ -8422,7 +8457,9 @@ reload_cse_simplify_operands (insn)
 
                default:
                  class
-                   = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER ((unsigned char)c)];
+                   = (reg_class_subunion
+                      [(int) class]
+                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
                  break;
 
                case ',': case '\0':
@@ -8431,10 +8468,10 @@ reload_cse_simplify_operands (insn)
                     alternative yet and the operand being replaced is not
                     a cheap CONST_INT.  */
                  if (op_alt_regno[i][j] == -1
-                     && reg_fits_class_p (reg, class, 0, mode)
+                     && reg_fits_class_p (testreg, class, 0, mode)
                      && (GET_CODE (recog_data.operand[i]) != CONST_INT
                          || (rtx_cost (recog_data.operand[i], SET)
-                             > rtx_cost (reg, SET))))
+                             > rtx_cost (testreg, SET))))
                    {
                      alternative_nregs[j]++;
                      op_alt_regno[i][j] = regno;
@@ -8442,6 +8479,7 @@ reload_cse_simplify_operands (insn)
                  j++;
                  break;
                }
+             p += CONSTRAINT_LEN (c, p);
 
              if (c == '\0')
                break;
@@ -8515,7 +8553,7 @@ reload_cse_simplify_operands (insn)
 \f
 /* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
    addressing now.
-   This code might also be useful when reload gave up on reg+reg addresssing
+   This code might also be useful when reload gave up on reg+reg addressing
    because of clashes between the return register and INDEX_REG_CLASS.  */
 
 /* The maximum number of uses of a register we can keep track of to
@@ -8536,7 +8574,7 @@ struct reg_use { rtx insn, *usep; };
    last, of these uses.
    STORE_RUID is always meaningful if we only want to use a value in a
    register in a different place: it denotes the next insn in the insn
-   stream (i.e. the last ecountered) that sets or clobbers the register.  */
+   stream (i.e. the last encountered) that sets or clobbers the register.  */
 static struct
   {
     struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
@@ -8561,12 +8599,13 @@ reload_combine ()
   int first_index_reg = -1;
   int last_index_reg = 0;
   int i;
+  basic_block bb;
   unsigned int r;
   int last_label_ruid;
   int min_labelno, n_labels;
   HARD_REG_SET ever_live_at_start, *label_live;
 
-  /* If reg+reg can be used in offsetable memory adresses, the main chunk of
+  /* If reg+reg can be used in offsetable memory addresses, the main chunk of
      reload has already used it where appropriate, so there is no use in
      trying to generate it now.  */
   if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
@@ -8596,17 +8635,17 @@ reload_combine ()
   label_live = (HARD_REG_SET *) xmalloc (n_labels * sizeof (HARD_REG_SET));
   CLEAR_HARD_REG_SET (ever_live_at_start);
 
-  for (i = n_basic_blocks - 1; i >= 0; i--)
+  FOR_EACH_BB_REVERSE (bb)
     {
-      insn = BLOCK_HEAD (i);
+      insn = bb->head;
       if (GET_CODE (insn) == CODE_LABEL)
        {
          HARD_REG_SET live;
 
          REG_SET_TO_HARD_REG_SET (live,
-                                  BASIC_BLOCK (i)->global_live_at_start);
+                                  bb->global_live_at_start);
          compute_use_by_pseudos (&live,
-                                 BASIC_BLOCK (i)->global_live_at_start);
+                                 bb->global_live_at_start);
          COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
          IOR_HARD_REG_SET (ever_live_at_start, live);
        }
@@ -8740,7 +8779,9 @@ reload_combine ()
                   i < RELOAD_COMBINE_MAX_USES; i++)
                validate_change (reg_state[regno].reg_use[i].insn,
                                 reg_state[regno].reg_use[i].usep,
-                                reg_sum, 1);
+                                /* Each change must have its own
+                                   replacement.  */
+                                copy_rtx (reg_sum), 1);
 
              if (apply_change_group ())
                {
@@ -9024,7 +9065,7 @@ reload_combine_note_use (xp, insn)
    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 greater than last_label_luid[n] .  */
+   reg_set_luid[n] is greater than move2add_last_label_luid.  */
 static int reg_set_luid[FIRST_PSEUDO_REGISTER];
 
 /* If reg_base_reg[n] is negative, register n has been set to
@@ -9036,7 +9077,7 @@ static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
 static int reg_base_reg[FIRST_PSEUDO_REGISTER];
 static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
 
-/* move2add_luid is linearily increased while scanning the instructions
+/* move2add_luid is linearly increased while scanning the instructions
    from first to last.  It is used to set reg_set_luid in
    reload_cse_move2add and move2add_note_store.  */
 static int move2add_luid;
@@ -9045,25 +9086,6 @@ static int move2add_luid;
    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 HOST_WIDE_INT
-sext_for_mode (mode, value)
-     enum machine_mode mode;
-     HOST_WIDE_INT value;
-{
-  HOST_WIDE_INT cval = value & GET_MODE_MASK (mode);
-  int width = GET_MODE_BITSIZE (mode);
-
-  /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative number,
-     sign extend it.  */
-  if (width > 0 && width < HOST_BITS_PER_WIDE_INT
-      && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
-    cval |= (HOST_WIDE_INT) -1 << width;
-
-  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) \
@@ -9120,26 +9142,68 @@ reload_cse_move2add (first)
                 to
                                  (set (REGX) (CONST_INT A))
                                  ...
-                                 (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
+                                 (set (REGX) (plus (REGX) (CONST_INT B-A)))
+                or
+                                 (set (REGX) (CONST_INT A))
+                                 ...
+                                 (set (STRICT_LOW_PART (REGX)) (CONST_INT B))
+             */
 
              if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
                {
-                 int success = 0;
-                 rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
-                                                       INTVAL (src)
-                                                       - reg_offset[regno]));
+                 rtx new_src =
+                   GEN_INT (trunc_int_for_mode (INTVAL (src)
+                                                - reg_offset[regno],
+                                                GET_MODE (reg)));
                  /* (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
                     note, to avoid losing register notes or the return
-                    value flag.  jump2 already knowns how to get rid of
+                    value flag.  jump2 already knows how to get rid of
                     no-op moves.  */
                  if (new_src == const0_rtx)
-                   success = validate_change (insn, &SET_SRC (pat), reg, 0);
+                   validate_change (insn, &SET_SRC (pat), reg, 0);
                  else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
                           && have_add2_insn (reg, new_src))
-                   success = validate_change (insn, &PATTERN (insn),
-                                              gen_add2_insn (reg, new_src), 0);
+                   {
+                     rtx newpat = gen_add2_insn (reg, new_src);
+                     if (INSN_P (newpat) && NEXT_INSN (newpat) == NULL_RTX)
+                       newpat = PATTERN (newpat);
+                     /* If it was the first insn of a sequence or
+                        some other emitted insn, validate_change will
+                        reject it.  */
+                     validate_change (insn, &PATTERN (insn),
+                                      newpat, 0);
+                   }
+                 else
+                   {
+                     enum machine_mode narrow_mode;
+                     for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+                          narrow_mode != GET_MODE (reg);
+                          narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
+                       {
+                         if (have_insn_for (STRICT_LOW_PART, narrow_mode)
+                             && ((reg_offset[regno]
+                                  & ~GET_MODE_MASK (narrow_mode))
+                                 == (INTVAL (src)
+                                     & ~GET_MODE_MASK (narrow_mode))))
+                           {
+                             rtx narrow_reg = gen_rtx_REG (narrow_mode,
+                                                           REGNO (reg));
+                             rtx narrow_src =
+                               GEN_INT (trunc_int_for_mode (INTVAL (src),
+                                                            narrow_mode));
+                             rtx new_set =
+                               gen_rtx_SET (VOIDmode,
+                                            gen_rtx_STRICT_LOW_PART (VOIDmode,
+                                                                     narrow_reg),
+                                            narrow_src);
+                             if (validate_change (insn, &PATTERN (insn),
+                                                  new_set, 0))
+                               break;
+                           }
+                       }
+                   }
                  reg_set_luid[regno] = move2add_luid;
                  reg_mode[regno] = GET_MODE (reg);
                  reg_offset[regno] = INTVAL (src);
@@ -9152,7 +9216,7 @@ reload_cse_move2add (first)
                                  (set (REGX) (REGY))
                                  (set (REGX) (PLUS (REGX) (CONST_INT B)))
                 to
-                                 (REGX) (REGY))
+                                 (set (REGX) (REGY))
                                  (set (REGX) (PLUS (REGX) (CONST_INT A)))
                                  ...
                                  (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
@@ -9176,10 +9240,11 @@ reload_cse_move2add (first)
                      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));
+                     rtx new_src =
+                       GEN_INT (trunc_int_for_mode (added_offset
+                                                    + base_offset
+                                                    - regno_offset,
+                                                    GET_MODE (reg)));
                      int success = 0;
 
                      if (new_src == const0_rtx)
@@ -9189,16 +9254,22 @@ reload_cse_move2add (first)
                      else if ((rtx_cost (new_src, PLUS)
                                < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
                               && have_add2_insn (reg, new_src))
-                       success
-                         = validate_change (next, &PATTERN (next),
-                                            gen_add2_insn (reg, new_src), 0);
+                       {
+                         rtx newpat = gen_add2_insn (reg, new_src);
+                         if (INSN_P (newpat)
+                             && NEXT_INSN (newpat) == NULL_RTX)
+                           newpat = PATTERN (newpat);
+                         success
+                           = validate_change (next, &PATTERN (next),
+                                              newpat, 0);
+                       }
                      if (success)
                        delete_insn (insn);
                      insn = next;
                      reg_mode[regno] = GET_MODE (reg);
-                     reg_offset[regno] = sext_for_mode (GET_MODE (reg),
-                                                        added_offset
-                                                        + base_offset);
+                     reg_offset[regno] =
+                       trunc_int_for_mode (added_offset + base_offset,
+                                           GET_MODE (reg));
                      continue;
                    }
                }
@@ -9268,7 +9339,8 @@ move2add_note_store (dst, set, data)
 
   regno += REGNO (dst);
 
-  if (HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
+  if (SCALAR_INT_MODE_P (mode)
+      && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
       && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
       && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
@@ -9333,7 +9405,7 @@ move2add_note_store (dst, set, data)
          reg_set_luid[regno] = move2add_last_label_luid + 1;
          reg_mode[regno] = mode;
          return;
-         
+
        default:
        invalidate:
          /* Invalidate the contents of the register.  */
@@ -9363,9 +9435,9 @@ move2add_note_store (dst, set, data)
       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]);
+      reg_offset[regno] = trunc_int_for_mode (offset
+                                             + reg_offset[base_regno],
+                                             dst_mode);
     }
   else
     {
@@ -9419,7 +9491,7 @@ copy_eh_notes (insn, x)
       for (; x != 0; x = NEXT_INSN (x))
        {
          if (may_trap_p (PATTERN (x)))
-           REG_NOTES (x) 
+           REG_NOTES (x)
              = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
                                   REG_NOTES (x));
        }
@@ -9430,20 +9502,19 @@ copy_eh_notes (insn, x)
    abnormal calls moving basic block end, but in fact it wants to emit
    them on the edge.  Looks for abnormal call edges, find backward the
    proper call and fix the damage.
+
    Similar handle instructions throwing exceptions internally.  */
-static void
+void
 fixup_abnormal_edges ()
 {
-  int i;
   bool inserted = false;
+  basic_block bb;
 
-  for (i = 0; i < n_basic_blocks; i++)
+  FOR_EACH_BB (bb)
     {
-      basic_block bb = BASIC_BLOCK (i);
       edge e;
 
-      /* Look for cases we are interested in - an calls or instructions causing
+      /* Look for cases we are interested in - calls or instructions causing
          exceptions.  */
       for (e = bb->succ; e; e = e->succ_next)
        {
@@ -9476,13 +9547,35 @@ fixup_abnormal_edges ()
              next = NEXT_INSN (insn);
              if (INSN_P (insn))
                {
-                 insert_insn_on_edge (PATTERN (insn), e);
                  delete_insn (insn);
+
+                 /* Sometimes there's still the return value USE.
+                    If it's placed after a trapping call (i.e. that
+                    call is the last insn anyway), we have no fallthru
+                    edge.  Simply delete this use and don't try to insert
+                    on the non-existent edge.  */
+                 if (GET_CODE (PATTERN (insn)) != USE)
+                   {
+                     /* We're not deleting it, we're moving it.  */
+                     INSN_DELETED_P (insn) = 0;
+                     PREV_INSN (insn) = NULL_RTX;
+                     NEXT_INSN (insn) = NULL_RTX;
+
+                     insert_insn_on_edge (insn, e);
+                   }
                }
              insn = next;
            }
        }
     }
+  /* We've possibly turned single trapping insn into multiple ones.  */
+  if (flag_non_call_exceptions)
+    {
+      sbitmap blocks;
+      blocks = sbitmap_alloc (last_basic_block);
+      sbitmap_ones (blocks);
+      find_many_sub_basic_blocks (blocks);
+    }
   if (inserted)
     commit_edge_insertions ();
 }