OSDN Git Service

* config/xtensa/xtensa.c (xtensa_init_machine_status): Fix
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 3a3dab0..1ce3199 100644 (file)
@@ -1,23 +1,23 @@
 /* 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 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -28,11 +28,10 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "obstack.h"
 #include "insn-config.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "flags.h"
 #include "function.h"
 #include "expr.h"
+#include "optabs.h"
 #include "regs.h"
 #include "basic-block.h"
 #include "reload.h"
@@ -41,10 +40,8 @@ Boston, MA 02111-1307, USA.  */
 #include "cselib.h"
 #include "real.h"
 #include "toplev.h"
-
-#if !defined PREFERRED_STACK_BOUNDARY && defined STACK_BOUNDARY
-#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
-#endif
+#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
@@ -229,7 +226,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.  */
@@ -327,10 +324,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.
@@ -370,6 +367,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 maybe_fix_stack_asms       PARAMS ((void));
 static void copy_reloads               PARAMS ((struct insn_chain *));
 static void calculate_needs_all_insns  PARAMS ((int));
@@ -381,7 +381,7 @@ static void delete_caller_save_insns        PARAMS ((void));
 static void spill_failure              PARAMS ((rtx, enum reg_class));
 static void count_spilled_pseudo       PARAMS ((int, int, int));
 static void delete_dead_insn           PARAMS ((rtx));
-static void alter_reg                          PARAMS ((int, int));
+static void alter_reg                  PARAMS ((int, int));
 static void set_label_offsets          PARAMS ((rtx, rtx, int));
 static void check_eliminable_occurrences       PARAMS ((rtx));
 static void elimination_effects                PARAMS ((rtx, enum machine_mode));
@@ -411,7 +411,8 @@ static void clear_reload_reg_in_use PARAMS ((unsigned int, int,
                                                 enum machine_mode));
 static int reload_reg_free_p           PARAMS ((unsigned int, int,
                                                 enum reload_type));
-static int reload_reg_free_for_value_p PARAMS ((int, int, enum reload_type,
+static int reload_reg_free_for_value_p PARAMS ((int, int, int,
+                                                enum reload_type,
                                                 rtx, rtx, int, int));
 static int free_for_value_p            PARAMS ((int, enum machine_mode, int,
                                                 enum reload_type, rtx, rtx,
@@ -439,7 +440,6 @@ 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));
@@ -452,12 +452,13 @@ static void move2add_note_store           PARAMS ((rtx, rtx, void *));
 #ifdef AUTO_INC_DEC
 static void add_auto_inc_notes         PARAMS ((rtx, rtx));
 #endif
-static rtx gen_mode_int                        PARAMS ((enum machine_mode,
+static void copy_eh_notes              PARAMS ((rtx, rtx));
+static HOST_WIDE_INT sext_for_mode     PARAMS ((enum machine_mode,
                                                 HOST_WIDE_INT));
 static void failed_reload              PARAMS ((rtx, int));
 static int set_reload_reg              PARAMS ((int, int));
-static void reload_cse_delete_noop_set PARAMS ((rtx, rtx));
 static void reload_cse_simplify                PARAMS ((rtx));
+void fixup_abnormal_edges              PARAMS ((void));
 extern void dump_needs                 PARAMS ((struct insn_chain *));
 \f
 /* Initialize the reload pass once per compilation.  */
@@ -465,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,
@@ -577,6 +578,70 @@ compute_use_by_pseudos (to, from)
         }
      });
 }
+
+/* Replace all pseudos found in LOC with their corresponding
+   equivalences.  */
+
+static void
+replace_pseudos_in_call_usage (loc, mem_mode, usage)
+     rtx *loc;
+     enum machine_mode mem_mode;
+     rtx usage;
+{
+  rtx x = *loc;
+  enum rtx_code code;
+  const char *fmt;
+  int i, j;
+
+  if (! x)
+    return;
+
+  code = GET_CODE (x);
+  if (code == REG)
+    {
+      unsigned int regno = REGNO (x);
+
+      if (regno < FIRST_PSEUDO_REGISTER)
+       return;
+
+      x = eliminate_regs (x, mem_mode, usage);
+      if (x != *loc)
+       {
+         *loc = x;
+         replace_pseudos_in_call_usage (loc, mem_mode, usage);
+         return;
+       }
+
+      if (reg_equiv_constant[regno])
+       *loc = reg_equiv_constant[regno];
+      else if (reg_equiv_mem[regno])
+       *loc = reg_equiv_mem[regno];
+      else if (reg_equiv_address[regno])
+       *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address[regno]);
+      else if (GET_CODE (regno_reg_rtx[regno]) != REG
+              || REGNO (regno_reg_rtx[regno]) != regno)
+       *loc = regno_reg_rtx[regno];
+      else
+       abort ();
+
+      return;
+    }
+  else if (code == MEM)
+    {
+      replace_pseudos_in_call_usage (& XEXP (x, 0), GET_MODE (x), usage);
+      return;
+    }
+
+  /* Process each of our operands recursively.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+    if (*fmt == 'e')
+      replace_pseudos_in_call_usage (&XEXP (x, i), mem_mode, usage);
+    else if (*fmt == 'E')
+      for (j = 0; j < XVECLEN (x, i); j++)
+       replace_pseudos_in_call_usage (& XVECEXP (x, i, j), mem_mode, usage);
+}
+
 \f
 /* Global variables used by reload and its subroutines.  */
 
@@ -606,13 +671,14 @@ reload (first, global)
      rtx first;
      int global;
 {
-  register int i;
-  register rtx insn;
-  register struct elim_table *ep;
+  int i;
+  rtx insn;
+  struct elim_table *ep;
+  basic_block bb;
 
   /* The two pointers used to track the true location of the memory used
      for label offsets.  */
-  char *real_known_ptr = NULL_PTR;
+  char *real_known_ptr = NULL;
   int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
 
   /* Make sure even insns with volatile mem refs are recognizable.  */
@@ -624,7 +690,7 @@ reload (first, global)
 
   /* Make sure that the last insn in the chain
      is not something that needs reloading.  */
-  emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  emit_note (NULL, NOTE_INSN_DELETED);
 
   /* Enable find_equiv_reg to distinguish insns made by reload.  */
   reload_first_uid = get_max_uid ();
@@ -667,7 +733,6 @@ reload (first, global)
      be substituted eventually by altering the REG-rtx's.  */
 
   reg_equiv_constant = (rtx *) xcalloc (max_regno, sizeof (rtx));
-  reg_equiv_memory_loc = (rtx *) xcalloc (max_regno, sizeof (rtx));
   reg_equiv_mem = (rtx *) xcalloc (max_regno, sizeof (rtx));
   reg_equiv_init = (rtx *) xcalloc (max_regno, sizeof (rtx));
   reg_equiv_address = (rtx *) xcalloc (max_regno, sizeof (rtx));
@@ -685,7 +750,7 @@ reload (first, global)
      Also find all paradoxical subregs and find largest such for each pseudo.
      On machines with small register classes, record hard registers that
      are used for user variables.  These can never be used for spills.
-     Also look for a "constant" NOTE_INSN_SETJMP.  This means that all
+     Also look for a "constant" REG_SETJMP.  This means that all
      caller-saved registers must be marked live.  */
 
   num_eliminable_invariants = 0;
@@ -693,8 +758,15 @@ reload (first, global)
     {
       rtx set = single_set (insn);
 
-      if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+      /* We may introduce USEs that we want to remove at the end, so
+        we'll mark them with QImode.  Make sure there are no
+        previously-marked insns left by say regmove.  */
+      if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE
+         && GET_MODE (insn) != VOIDmode)
+       PUT_MODE (insn, VOIDmode);
+
+      if (GET_CODE (insn) == CALL_INSN
+         && find_reg_note (insn, REG_SETJMP, NULL))
        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
          if (! call_used_regs[i])
            regs_ever_live[i] = 1;
@@ -706,7 +778,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
              )
            {
@@ -714,14 +790,17 @@ 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))
                    {
-                     /* If the operand is a PLUS, the MEM may be shared,
-                        so make sure we have an unshared copy here.  */
-                     if (GET_CODE (XEXP (x, 0)) == PLUS)
-                       x = copy_rtx (x);
-
-                     reg_equiv_memory_loc[i] = x;
+                     /* Always unshare the equivalence, so we can
+                        substitute into this insn without touching the
+                        equivalence.  */
+                     reg_equiv_memory_loc[i] = copy_rtx (x);
                    }
                  else if (function_invariant_p (x))
                    {
@@ -846,7 +925,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);
 
@@ -997,9 +1076,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
                {
@@ -1036,8 +1122,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
@@ -1060,16 +1146,6 @@ reload (first, global)
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     {
       rtx addr = 0;
-      int in_struct = 0;
-      int is_scalar = 0;
-      int is_readonly = 0;
-
-      if (reg_equiv_memory_loc[i])
-       {
-         in_struct = MEM_IN_STRUCT_P (reg_equiv_memory_loc[i]);
-         is_scalar = MEM_SCALAR_P (reg_equiv_memory_loc[i]);
-         is_readonly = RTX_UNCHANGING_P (reg_equiv_memory_loc[i]);
-       }
 
       if (reg_equiv_mem[i])
        addr = XEXP (reg_equiv_mem[i], 0);
@@ -1082,15 +1158,18 @@ reload (first, global)
          if (reg_renumber[i] < 0)
            {
              rtx reg = regno_reg_rtx[i];
+
+             REG_USERVAR_P (reg) = 0;
              PUT_CODE (reg, MEM);
              XEXP (reg, 0) = addr;
-             REG_USERVAR_P (reg) = 0;
-             RTX_UNCHANGING_P (reg) = is_readonly;
-             MEM_IN_STRUCT_P (reg) = in_struct;
-             MEM_SCALAR_P (reg) = is_scalar;
-             /* We have no alias information about this newly created
-                MEM.  */
-             MEM_ALIAS_SET (reg) = 0;
+             if (reg_equiv_memory_loc[i])
+               MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc[i]);
+             else
+               {
+                 RTX_UNCHANGING_P (reg) = MEM_IN_STRUCT_P (reg)
+                   = MEM_SCALAR_P (reg) = 0;
+                 MEM_ATTRS (reg) = 0;
+               }
            }
          else if (reg_equiv_mem[i])
            XEXP (reg_equiv_mem[i], 0) = addr;
@@ -1114,15 +1193,20 @@ reload (first, global)
       {
        rtx *pnote;
 
+       if (GET_CODE (insn) == CALL_INSN)
+         replace_pseudos_in_call_usage (& CALL_INSN_FUNCTION_USAGE (insn),
+                                        VOIDmode,
+                                        CALL_INSN_FUNCTION_USAGE (insn));
+
        if ((GET_CODE (PATTERN (insn)) == USE
-            && find_reg_note (insn, REG_EQUAL, NULL_RTX))
+            /* We mark with QImode USEs introduced by reload itself.  */
+            && (GET_MODE (insn) == QImode
+                || find_reg_note (insn, REG_EQUAL, NULL_RTX)))
            || (GET_CODE (PATTERN (insn)) == CLOBBER
                && (GET_CODE (XEXP (PATTERN (insn), 0)) != REG
                    || ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0)))))
          {
-           PUT_CODE (insn, NOTE);
-           NOTE_SOURCE_FILE (insn) = 0;
-           NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+           delete_insn (insn);
            continue;
          }
 
@@ -1197,6 +1281,12 @@ reload (first, global)
   /* Free all the insn_chain structures at once.  */
   obstack_free (&reload_obstack, reload_startobj);
   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;
 }
@@ -1283,7 +1373,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':
@@ -1397,9 +1488,7 @@ calculate_needs_all_insns (global)
                  && GET_CODE (SET_SRC (set)) == REG
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
                {
-                 PUT_CODE (insn, NOTE);
-                 NOTE_SOURCE_FILE (insn) = 0;
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+                 delete_insn (insn);
                  /* Delete it from the reload chain */
                  if (chain->prev)
                    chain->prev->next = next;
@@ -1452,8 +1541,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;
@@ -1495,7 +1584,7 @@ static void
 count_pseudo (reg)
      int reg;
 {
-  int n_refs = REG_N_REFS (reg);
+  int freq = REG_FREQ (reg);
   int r = reg_renumber[reg];
   int nregs;
 
@@ -1508,11 +1597,11 @@ count_pseudo (reg)
   if (r < 0)
     abort ();
 
-  spill_add_cost[r] += n_refs;
+  spill_add_cost[r] += freq;
 
   nregs = HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (reg));
   while (nregs-- > 0)
-    spill_cost[r + nregs] += n_refs;
+    spill_cost[r + nregs] += freq;
 }
 
 /* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the
@@ -1582,9 +1671,9 @@ count_spilled_pseudo (spilled, spilled_nregs, reg)
 
   SET_REGNO_REG_SET (&spilled_pseudos, reg);
 
-  spill_add_cost[r] -= REG_N_REFS (reg);
+  spill_add_cost[r] -= REG_FREQ (reg);
   while (nregs-- > 0)
-    spill_cost[r + nregs] -= REG_N_REFS (reg);
+    spill_cost[r + nregs] -= REG_FREQ (reg);
 }
 
 /* Find reload register to use for reload number ORDER.  */
@@ -1783,17 +1872,9 @@ delete_caller_save_insns ()
          struct insn_chain *next = c->next;
          rtx insn = c->insn;
 
-         if (insn == BLOCK_HEAD (c->block))
-           BLOCK_HEAD (c->block) = NEXT_INSN (insn);
-         if (insn == BLOCK_END (c->block))
-           BLOCK_END (c->block) = PREV_INSN (insn);
          if (c == reload_insn_chain)
            reload_insn_chain = next;
-
-         if (NEXT_INSN (insn) != 0)
-           PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
-         if (PREV_INSN (insn) != 0)
-           NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+         delete_insn (insn);
 
          if (next)
            next->prev = c->prev;
@@ -1818,13 +1899,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
@@ -1862,7 +1943,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
@@ -1888,7 +1969,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;
@@ -1916,7 +1997,7 @@ alter_reg (i, from_reg)
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
 
          /* Nothing can alias this slot except this pseudo.  */
-         MEM_ALIAS_SET (x) = new_alias_set ();
+         set_mem_alias_set (x, new_alias_set ());
        }
 
       /* Reuse a stack slot if possible.  */
@@ -1950,9 +2031,9 @@ alter_reg (i, from_reg)
 
          /* All pseudos mapped to this slot can alias each other.  */
          if (spill_stack_slot[from_reg])
-           MEM_ALIAS_SET (x) = MEM_ALIAS_SET (spill_stack_slot[from_reg]);
+           set_mem_alias_set (x, MEM_ALIAS_SET (spill_stack_slot[from_reg]));
          else
-           MEM_ALIAS_SET (x) = new_alias_set ();
+           set_mem_alias_set (x, new_alias_set ());
 
          if (BYTES_BIG_ENDIAN)
            {
@@ -1962,10 +2043,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;
@@ -1979,16 +2061,28 @@ 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);
+
+      /* If we have a decl for the original register, set it for the
+        memory.  If this is a shared MEM, make a copy.  */
+      if (REGNO_DECL (i))
        {
-         rtx new = gen_rtx_MEM (GET_MODE (regno_reg_rtx[i]),
-                                plus_constant (XEXP (x, 0), adjust));
+         rtx decl = DECL_RTL_IF_SET (REGNO_DECL (i));
 
-         MEM_COPY_ATTRIBUTES (new, x);
-         x = new;
+         /* 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);
+
+             set_mem_expr (x, REGNO_DECL (i));
+           }
        }
 
-      /* Save the stack slot for later.   */
+      /* Save the stack slot for later.  */
       reg_equiv_memory_loc[i] = x;
     }
 }
@@ -2000,7 +2094,7 @@ void
 mark_home_live (regno)
      int regno;
 {
-  register int i, lim;
+  int i, lim;
 
   i = reg_renumber[regno];
   if (i < 0)
@@ -2207,6 +2301,7 @@ eliminate_regs (x, mem_mode, insn)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -2240,8 +2335,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);
@@ -2263,7 +2358,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)))
@@ -2307,7 +2402,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,
@@ -2415,7 +2510,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;
 
@@ -2438,7 +2534,7 @@ eliminate_regs (x, mem_mode, insn)
       return x;
 
     case SUBREG:
-      /* Similar to above processing, but preserve SUBREG_WORD.
+      /* Similar to above processing, but preserve SUBREG_BYTE.
         Convert (subreg (mem)) to (mem) if not paradoxical.
         Also, if we have a non-paradoxical (subreg (pseudo)) and the
         pseudo didn't get a hard reg, we must replace this with the
@@ -2455,7 +2551,7 @@ eliminate_regs (x, mem_mode, insn)
       else
        new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
 
-      if (new != XEXP (x, 0))
+      if (new != SUBREG_REG (x))
        {
          int x_size = GET_MODE_SIZE (GET_MODE (x));
          int new_size = GET_MODE_SIZE (GET_MODE (new));
@@ -2470,26 +2566,15 @@ eliminate_regs (x, mem_mode, insn)
                      (reg:m2 R) later, expecting all bits to be preserved.
                      So if the number of words is the same, preserve the
                      subreg so that push_reloads can see it.  */
-                  && ! ((x_size-1)/UNITS_PER_WORD == (new_size-1)/UNITS_PER_WORD)
+                  && ! ((x_size - 1) / UNITS_PER_WORD
+                        == (new_size -1 ) / UNITS_PER_WORD)
 #endif
                   )
-                 || (x_size == new_size))
+                 || x_size == new_size)
              )
-           {
-             int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
-             enum machine_mode mode = GET_MODE (x);
-
-             if (BYTES_BIG_ENDIAN)
-               offset += (MIN (UNITS_PER_WORD,
-                               GET_MODE_SIZE (GET_MODE (new)))
-                          - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-
-             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_WORD (x));
+           return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x));
        }
 
       return x;
@@ -2504,17 +2589,18 @@ eliminate_regs (x, mem_mode, insn)
       /* Our only special processing is to pass the mode of the MEM to our
         recursive call and copy the flags.  While we are here, handle this
         case more efficiently.  */
-      new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn);
-      if (new != XEXP (x, 0))
-       {
-         new = gen_rtx_MEM (GET_MODE (x), new);
-         MEM_COPY_ATTRIBUTES (new, x);
-         return new;
-       }
-      else
-       return x;
+      return
+       replace_equiv_address_nv (x,
+                                 eliminate_regs (XEXP (x, 0),
+                                                 GET_MODE (x), insn));
 
     case USE:
+      /* Handle insn_list USE that a call to a pure function may generate.  */
+      new = eliminate_regs (XEXP (x, 0), 0, insn);
+      if (new != XEXP (x, 0))
+       return gen_rtx_USE (GET_MODE (x), new);
+      return x;
+
     case CLOBBER:
     case ASM_OPERANDS:
     case SET:
@@ -2594,6 +2680,7 @@ elimination_effects (x, mem_mode)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST:
     case SYMBOL_REF:
     case CODE_LABEL:
@@ -2627,7 +2714,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;
 
@@ -2866,55 +2953,56 @@ 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)
                  {
-                   if (replace)
+                   rtx src
+                     = plus_constant (ep->to_rtx, offset - ep->offset);
+
+                   new_body = old_body;
+                   if (! replace)
+                     {
+                       new_body = copy_insn (old_body);
+                       if (REG_NOTES (insn))
+                         REG_NOTES (insn) = copy_insn_1 (REG_NOTES (insn));
+                     }
+                   PATTERN (insn) = new_body;
+                   old_set = single_set (insn);
+
+                   /* First see if this insn remains valid when we
+                      make the change.  If not, keep the INSN_CODE
+                      the same and let reload fit it up.  */
+                   validate_change (insn, &SET_SRC (old_set), src, 1);
+                   validate_change (insn, &SET_DEST (old_set),
+                                    ep->to_rtx, 1);
+                   if (! apply_change_group ())
                      {
-                       rtx src
-                         = plus_constant (ep->to_rtx, offset - ep->offset);
-
-                       /* First see if this insn remains valid when we
-                          make the change.  If not, keep the INSN_CODE
-                          the same and let reload fit it up.  */
-                       validate_change (insn, &SET_SRC (old_set), src, 1);
-                       validate_change (insn, &SET_DEST (old_set),
-                                        ep->to_rtx, 1);
-                       if (! apply_change_group ())
-                         {
-                           SET_SRC (old_set) = src;
-                           SET_DEST (old_set) = ep->to_rtx;
-                         }
+                       SET_SRC (old_set) = src;
+                       SET_DEST (old_set) = ep->to_rtx;
                      }
 
                    val = 1;
@@ -2943,6 +3031,7 @@ eliminate_regs_in_insn (insn, replace)
      currently support: a single set with the source being a PLUS of an
      eliminable register and a constant.  */
   if (old_set
+      && GET_CODE (SET_DEST (old_set)) == REG
       && GET_CODE (SET_SRC (old_set)) == PLUS
       && GET_CODE (XEXP (SET_SRC (old_set), 0)) == REG
       && GET_CODE (XEXP (SET_SRC (old_set), 1)) == CONST_INT
@@ -3204,7 +3293,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
@@ -3346,7 +3435,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)
        {
@@ -3405,7 +3494,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)
@@ -3472,7 +3561,7 @@ spill_hard_reg (regno, cant_eliminate)
      unsigned int regno;
      int cant_eliminate;
 {
-  register int i;
+  int i;
 
   if (cant_eliminate)
     {
@@ -3660,11 +3749,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)
     {
@@ -3681,6 +3770,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:
@@ -3705,7 +3795,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));
        }
@@ -3727,7 +3817,7 @@ reload_as_needed (live_known)
 {
   struct insn_chain *chain;
 #if defined (AUTO_INC_DEC)
-  register int i;
+  int i;
 #endif
   rtx x;
 
@@ -3800,9 +3890,6 @@ reload_as_needed (live_known)
                            spill_reg_order);
            }
 
-         if (num_eliminable && chain->need_elim)
-           update_eliminable_offsets ();
-
          if (n_reloads > 0)
            {
              rtx next = NEXT_INSN (insn);
@@ -3830,7 +3917,7 @@ reload_as_needed (live_known)
                 into the insn's body (or perhaps into the bodies of other
                 load and store insn that we just made for reloading
                 and that we moved the structure into).  */
-             subst_reloads ();
+             subst_reloads (insn);
 
              /* If this was an ASM, make sure that all the reload insns
                 we have generated are valid.  If not, give an error
@@ -3844,11 +3931,13 @@ reload_as_needed (live_known)
                    {
                      error_for_asm (insn,
                                     "`asm' operand requires impossible reload");
-                     PUT_CODE (p, NOTE);
-                     NOTE_SOURCE_FILE (p) = 0;
-                     NOTE_LINE_NUMBER (p) = NOTE_INSN_DELETED;
+                     delete_insn (p);
                    }
            }
+
+         if (num_eliminable && chain->need_elim)
+           update_eliminable_offsets ();
+
          /* Any previously reloaded spilled pseudo reg, stored in this insn,
             is no longer validly lying around to save a future reload.
             Note that this does not detect pseudos that were reloaded
@@ -3985,7 +4074,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.  */
@@ -4008,19 +4097,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.  */
+  /* note_stores does give us subregs of hard regs,
+     subreg_regno_offset will abort if it is not a hard reg.  */
   while (GET_CODE (x) == SUBREG)
     {
-      offset += SUBREG_WORD (x);
+      /* 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;
@@ -4236,7 +4327,7 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
      excluding the intervals of 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.  */
 
@@ -4356,11 +4447,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;
 
@@ -4369,11 +4462,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;
 
@@ -4396,7 +4491,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;
 
@@ -4404,7 +4501,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;
@@ -4540,7 +4637,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 ...  */
 
@@ -4548,8 +4645,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;
@@ -4601,11 +4700,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
@@ -4619,7 +4718,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
@@ -4653,12 +4752,14 @@ rtx reload_override_in[MAX_RELOADS];
    or -1 if we did not need a register for this reload.  */
 int reload_spill_index[MAX_RELOADS];
 
-/* Subroutine of free_for_value_p, used to check a single register.  */
+/* Subroutine of free_for_value_p, used to check a single register.
+   START_REGNO is the starting regno of the full reload register
+   (possibly comprising multiple hard registers) that we are considering.  */
 
 static int
-reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
-                            ignore_address_reloads)
-     int regno;
+reload_reg_free_for_value_p (start_regno, regno, opnum, type, value, out,
+                            reloadnum, ignore_address_reloads)
+     int start_regno, regno;
      int opnum;
      enum reload_type type;
      rtx value, out;
@@ -4748,10 +4849,17 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
       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)
        {
-         if (! rld[i].in || ! rtx_equal_p (rld[i].in, value)
+         rtx other_input = rld[i].in;
+
+         /* If the other reload loads the same input value, that
+            will not cause a conflict only if it's loading it into
+            the same register.  */
+         if (true_regnum (reg) != start_regno)
+           other_input = NULL_RTX;
+         if (! other_input || ! rtx_equal_p (other_input, value)
              || rld[i].out || out)
            {
              int time2;
@@ -4832,7 +4940,7 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
                case RELOAD_OTHER:
                  /* If there is no conflict in the input part, handle this
                     like an output reload.  */
-                 if (! rld[i].in || rtx_equal_p (rld[i].in, value))
+                 if (! rld[i].in || rtx_equal_p (other_input, value))
                    {
                      time2 = MAX_RECOG_OPERANDS * 4 + 4;
                      /* Earlyclobbered outputs must conflict with inputs.  */
@@ -4854,7 +4962,7 @@ reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum,
                }
              if ((time1 >= time2
                   && (! rld[i].in || rld[i].out
-                      || ! rtx_equal_p (rld[i].in, value)))
+                      || ! rtx_equal_p (other_input, value)))
                  || (out && rld[reloadnum].out_reg
                      && time2 >= MAX_RECOG_OPERANDS * 4 + 3))
                return 0;
@@ -4905,8 +5013,9 @@ free_for_value_p (regno, mode, opnum, type, value, out, reloadnum,
 {
   int nregs = HARD_REGNO_NREGS (regno, mode);
   while (nregs-- > 0)
-    if (! reload_reg_free_for_value_p (regno + nregs, opnum, type, value, out,
-                                      reloadnum, ignore_address_reloads))
+    if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type,
+                                      value, out, reloadnum,
+                                      ignore_address_reloads))
       return 0;
   return 1;
 }
@@ -4935,7 +5044,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.  */
@@ -5197,7 +5306,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;
@@ -5222,7 +5331,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;
@@ -5261,7 +5370,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.  */
@@ -5313,8 +5422,8 @@ choose_reload_regs (chain)
 
          if (inheritance)
            {
-             int word = 0;
-             register int regno = -1;
+             int byte = 0;
+             int regno = -1;
              enum machine_mode mode = VOIDmode;
 
              if (rld[r].in == 0)
@@ -5332,10 +5441,10 @@ choose_reload_regs (chain)
              else if (GET_CODE (rld[r].in_reg) == SUBREG
                       && GET_CODE (SUBREG_REG (rld[r].in_reg)) == REG)
                {
-                 word = SUBREG_WORD (rld[r].in_reg);
+                 byte = SUBREG_BYTE (rld[r].in_reg);
                  regno = REGNO (SUBREG_REG (rld[r].in_reg));
                  if (regno < FIRST_PSEUDO_REGISTER)
-                   regno += word;
+                   regno = subreg_regno (rld[r].in_reg);
                  mode = GET_MODE (rld[r].in_reg);
                }
 #ifdef AUTO_INC_DEC
@@ -5356,7 +5465,7 @@ choose_reload_regs (chain)
                 that can invalidate an inherited reload of part of a pseudoreg.  */
              else if (GET_CODE (rld[r].in) == SUBREG
                       && GET_CODE (SUBREG_REG (rld[r].in)) == REG)
-               regno = REGNO (SUBREG_REG (rld[r].in)) + SUBREG_WORD (rld[r].in);
+               regno = subreg_regno (rld[r].in);
 #endif
 
              if (regno >= 0 && reg_last_reload_reg[regno] != 0)
@@ -5365,15 +5474,15 @@ choose_reload_regs (chain)
                  rtx last_reg = reg_last_reload_reg[regno];
                  enum machine_mode need_mode;
 
-                 i = REGNO (last_reg) + word;
+                 i = REGNO (last_reg);
+                 i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
                  last_class = REGNO_REG_CLASS (i);
 
-                 if (word == 0)
+                 if (byte == 0)
                    need_mode = mode;
                  else
                    need_mode
-                     = smallest_mode_for_size (GET_MODE_SIZE (mode)
-                                               + word * UNITS_PER_WORD,
+                     = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte,
                                                GET_MODE_CLASS (mode));
 
                  if (
@@ -5429,10 +5538,16 @@ choose_reload_regs (chain)
                      if (k == nr)
                        {
                          int i1;
+                         int bad_for_class;
 
                          last_reg = (GET_MODE (last_reg) == mode
                                      ? last_reg : gen_rtx_REG (mode, i));
 
+                         bad_for_class = 0;
+                         for (k = 0; k < nr; k++)
+                           bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
+                                                                 i+k);
+
                          /* We found a register that contains the
                             value we need.  If this register is the
                             same as an `earlyclobber' operand of the
@@ -5457,13 +5572,13 @@ 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.  */
                              || (GET_MODE_SIZE (rld[r].mode)
                                  > GET_MODE_SIZE (mode))
-                             || ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].class],
-                                                     i)
+                             || bad_for_class
 
                              /* If find_reloads chose reload_out as reload
                                 register, stay with it - that leaves the
@@ -5528,9 +5643,9 @@ choose_reload_regs (chain)
 
          if (search_equiv)
            {
-             register rtx equiv
+             rtx equiv
                = find_equiv_reg (search_equiv, insn, rld[r].class,
-                                 -1, NULL_PTR, 0, rld[r].mode);
+                                 -1, NULL, 0, rld[r].mode);
              int regno = 0;
 
              if (equiv != 0)
@@ -5543,7 +5658,7 @@ choose_reload_regs (chain)
                         Make a new REG since this might be used in an
                         address and not all machines support SUBREGs
                         there.  */
-                     regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv);
+                     regno = subreg_regno (equiv);
                      equiv = gen_rtx_REG (rld[r].mode, regno);
                    }
                  else
@@ -5587,7 +5702,7 @@ choose_reload_regs (chain)
                 RELOAD_FOR_OUTPUT_ADDRESS reload.  */
 
              if (equiv != 0)
-               {
+               {
                  if (regno_clobbered_p (regno, insn, rld[r].mode, 0))
                    switch (rld[r].when_needed)
                      {
@@ -5628,7 +5743,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;
@@ -5703,7 +5820,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)
@@ -5764,7 +5881,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;
@@ -5794,7 +5911,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
@@ -5831,7 +5948,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];
 
@@ -5841,7 +5958,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)
@@ -5983,12 +6100,12 @@ merge_assigned_reloads (insn)
          if (rld[i].when_needed == RELOAD_OTHER)
            for (j = 0; j < n_reloads; j++)
              if (rld[j].in != 0
-                 && rld[i].when_needed != RELOAD_OTHER
+                 && rld[j].when_needed != RELOAD_OTHER
                  && reg_overlap_mentioned_for_reload_p (rld[j].in,
                                                         rld[i].in))
                rld[j].when_needed
-                 = ((rld[i].when_needed == RELOAD_FOR_INPUT_ADDRESS
-                     || rld[i].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
+                 = ((rld[j].when_needed == RELOAD_FOR_INPUT_ADDRESS
+                     || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
                     ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
        }
     }
@@ -6022,7 +6139,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;
@@ -6077,7 +6194,7 @@ emit_input_reload_insns (chain, rl, old, j)
     oldequiv
       = find_equiv_reg (old, insn,
                        rld[rl->secondary_in_reload].class,
-                       -1, NULL_PTR, 0, mode);
+                       -1, NULL, 0, mode);
 #endif
 
   /* If reloading from memory, see if there is a register
@@ -6093,8 +6210,7 @@ emit_input_reload_insns (chain, rl, old, j)
          || (GET_CODE (old) == REG
              && REGNO (old) >= FIRST_PSEUDO_REGISTER
              && reg_renumber[REGNO (old)] < 0)))
-    oldequiv = find_equiv_reg (old, insn, ALL_REGS,
-                              -1, NULL_PTR, 0, mode);
+    oldequiv = find_equiv_reg (old, insn, ALL_REGS, -1, NULL, 0, mode);
 
   if (oldequiv)
     {
@@ -6109,7 +6225,7 @@ 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
@@ -6173,7 +6289,7 @@ emit_input_reload_insns (chain, rl, old, j)
     oldequiv = SUBREG_REG (oldequiv);
   if (GET_MODE (oldequiv) != VOIDmode
       && mode != GET_MODE (oldequiv))
-    oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
+    oldequiv = gen_lowpart_SUBREG (mode, oldequiv);
 
   /* Switch to the right place to emit the reload insns.  */
   switch (rl->when_needed)
@@ -6265,38 +6381,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;
        }
     }
 
@@ -6478,13 +6599,17 @@ 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);
     }
 
+  if (flag_non_call_exceptions)
+    copy_eh_notes (insn, get_insns ());
+
   /* End this sequence.  */
   *where = get_insns ();
   end_sequence ();
@@ -6582,7 +6707,7 @@ emit_output_reload_insns (chain, rl, j)
 
                  /* Copy primary reload reg to secondary reload reg.
                     (Note that these have been swapped above, then
-                    secondary reload reg to OLD using our insn.  */
+                    secondary reload reg to OLD using our insn.)  */
 
                  /* If REAL_OLD is a paradoxical SUBREG, remove it
                     and try to put the opposite SUBREG on
@@ -6703,6 +6828,9 @@ emit_output_reload_insns (chain, rl, j)
   else
     output_reload_insns[rl->opnum] = get_insns ();
 
+  if (flag_non_call_exceptions)
+    copy_eh_notes (insn, get_insns ());
+
   end_sequence ();
 }
 
@@ -6785,6 +6913,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
@@ -6848,9 +6977,7 @@ emit_reload_insns (chain)
 {
   rtx insn = chain->insn;
 
-  register int j;
-  rtx following_insn = NEXT_INSN (insn);
-  rtx before_insn = PREV_INSN (insn);
+  int j;
 
   CLEAR_HARD_REG_SET (reg_reloaded_died);
 
@@ -6926,19 +7053,10 @@ emit_reload_insns (chain)
 
   for (j = 0; j < reload_n_operands; j++)
     {
-      emit_insns_before (outaddr_address_reload_insns[j], following_insn);
-      emit_insns_before (output_address_reload_insns[j], following_insn);
-      emit_insns_before (output_reload_insns[j], following_insn);
-      emit_insns_before (other_output_reload_insns[j], following_insn);
-    }
-
-  /* Keep basic block info up to date.  */
-  if (n_basic_blocks)
-    {
-      if (BLOCK_HEAD (chain->block) == insn)
-       BLOCK_HEAD (chain->block) = NEXT_INSN (before_insn);
-      if (BLOCK_END (chain->block) == insn)
-       BLOCK_END (chain->block) = PREV_INSN (following_insn);
+      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);
     }
 
   /* For all the spill regs newly reloaded in this instruction,
@@ -6950,8 +7068,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
@@ -7026,7 +7144,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)));
@@ -7074,7 +7192,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
@@ -7147,7 +7265,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;
@@ -7192,7 +7310,7 @@ emit_reload_insns (chain)
                     necessarily checked exactly in the code that moves
                     notes, so just check both locations.  */
                  rtx note = find_regno_note (insn, REG_DEAD, src_regno);
-                 if (! note)
+                 if (! note && store_insn)
                    note = find_regno_note (store_insn, REG_DEAD, src_regno);
                  while (nr-- > 0)
                    {
@@ -7442,9 +7560,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
@@ -7463,7 +7580,7 @@ delete_output_reload (insn, j, last_reload_reg)
   int k;
   int n_occurrences;
   int n_inherited = 0;
-  register rtx i1;
+  rtx i1;
   rtx substed;
 
   /* Get the raw pseudo-register referred to.  */
@@ -7506,7 +7623,9 @@ delete_output_reload (insn, j, last_reload_reg)
     }
   n_occurrences = count_occurrences (PATTERN (insn), reg, 0);
   if (substed)
-    n_occurrences += count_occurrences (PATTERN (insn), substed, 0);
+    n_occurrences += count_occurrences (PATTERN (insn),
+                                       eliminate_regs (substed, 0,
+                                                       NULL_RTX), 0);
   if (n_occurrences > n_inherited)
     return;
 
@@ -7536,15 +7655,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
+     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.  */
   if (rld[j].out != rld[j].in
       && REG_N_DEATHS (REGNO (reg)) == 1
       && REG_N_SETS (REGNO (reg)) == 1
@@ -7553,11 +7678,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);
@@ -7575,14 +7699,13 @@ delete_output_reload (insn, j, last_reload_reg)
              /* Some other ref remains; just delete the output reload we
                 know to be dead.  */
              delete_address_reloads (output_reload_insn, insn);
-             PUT_CODE (output_reload_insn, NOTE);
-             NOTE_SOURCE_FILE (output_reload_insn) = 0;
-             NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
+             delete_insn (output_reload_insn);
              return;
            }
        }
 
-      /* 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);
@@ -7590,27 +7713,22 @@ 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.  */
-             PUT_CODE (i2, NOTE);
-             NOTE_SOURCE_FILE (i2) = 0;
-             NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+             delete_insn (i2);
            }
          if (GET_CODE (i2) == CODE_LABEL
              || GET_CODE (i2) == JUMP_INSN)
            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);
-  PUT_CODE (output_reload_insn, NOTE);
-  NOTE_SOURCE_FILE (output_reload_insn) = 0;
-  NOTE_LINE_NUMBER (output_reload_insn) = NOTE_INSN_DELETED;
-
+  else
+    {
+      delete_address_reloads (output_reload_insn, insn);
+      delete_insn (output_reload_insn);
+    }
 }
 
 /* We are going to delete DEAD_INSN.  Recursively delete loads of
@@ -7648,8 +7766,8 @@ delete_address_reloads (dead_insn, current_insn)
       || (INTVAL (XEXP (SET_SRC (set), 1))
          != -INTVAL (XEXP (SET_SRC (set2), 1))))
     return;
-  delete_insn (prev);
-  delete_insn (next);
+  delete_related_insns (prev);
+  delete_related_insns (next);
 }
 
 /* Subfunction of delete_address_reloads: process registers found in X.  */
@@ -7758,10 +7876,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
     }
   delete_address_reloads_1 (prev, SET_SRC (set), current_insn);
   reg_reloaded_contents[REGNO (dst)] = -1;
-  /* Can't use delete_insn here because PREV might be a basic block head.  */
-  PUT_CODE (prev, NOTE);
-  NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (prev) = 0;
+  delete_insn (prev);
 }
 \f
 /* Output reload-insns to reload VALUE into RELOADREG.
@@ -7868,76 +7983,6 @@ 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
-    {
-      PUT_CODE (insn, NOTE);
-      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (insn) = 0;
-    }
-}
 
 /* See whether a single set SET is a noop.  */
 static int
@@ -7957,18 +8002,24 @@ reload_cse_simplify (insn)
   if (GET_CODE (body) == SET)
     {
       int count = 0;
-      if (reload_cse_noop_set_p (body))
+
+      /* Simplify even if we may think it is a no-op.
+         We may think a memory load of a value smaller than WORD_SIZE
+         is redundant because we haven't taken into account possible
+         implicit extension.  reload_cse_simplify_set() will bring
+         this out, so it's safer to simplify before we delete.  */
+      count += reload_cse_simplify_set (body, insn);
+
+      if (!count && reload_cse_noop_set_p (body))
        {
          rtx value = SET_DEST (body);
-         if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
+         if (REG_P (value)
+             && ! REG_FUNCTION_VALUE_P (value))
            value = 0;
-         reload_cse_delete_noop_set (insn, value);
+         delete_insn_and_edges (insn);
          return;
        }
 
-      /* It's not a no-op, but we can try to simplify it.  */
-      count += reload_cse_simplify_set (body, insn);
-
       if (count > 0)
        apply_change_group ();
       else
@@ -8002,7 +8053,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;
        }
@@ -8089,6 +8140,9 @@ reload_cse_simplify_set (set, insn)
   int old_cost;
   cselib_val *val;
   struct elt_loc_list *l;
+#ifdef LOAD_EXTEND_OP
+  enum rtx_code extend_op = NIL;
+#endif
 
   dreg = true_regnum (SET_DEST (set));
   if (dreg < 0)
@@ -8100,6 +8154,18 @@ reload_cse_simplify_set (set, insn)
 
   dclass = REGNO_REG_CLASS (dreg);
 
+#ifdef LOAD_EXTEND_OP
+  /* When replacing a memory with a register, we need to honor assumptions
+     that combine made wrt the contents of sign bits.  We'll do this by
+     generating an extend instruction instead of a reg->reg copy.  Thus
+     the destination must be a register that we can widen.  */
+  if (GET_CODE (src) == MEM
+      && GET_MODE_BITSIZE (GET_MODE (src)) < BITS_PER_WORD
+      && (extend_op = LOAD_EXTEND_OP (GET_MODE (src))) != NIL
+      && GET_CODE (SET_DEST (set)) != REG)
+    return 0;
+#endif
+
   /* If memory loads are cheaper than register copies, don't change them.  */
   if (GET_CODE (src) == MEM)
     old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
@@ -8117,23 +8183,76 @@ reload_cse_simplify_set (set, insn)
     return 0;
   for (l = val->locs; l; l = l->next)
     {
+      rtx this_rtx = l->loc;
       int this_cost;
-      if (CONSTANT_P (l->loc) && ! references_value_p (l->loc, 0))
-       this_cost = rtx_cost (l->loc, SET);
-      else if (GET_CODE (l->loc) == REG)
-       this_cost = REGISTER_MOVE_COST (GET_MODE (l->loc),
-                                       REGNO_REG_CLASS (REGNO (l->loc)),
-                                       dclass);
+
+      if (CONSTANT_P (this_rtx) && ! references_value_p (this_rtx, 0))
+       {
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             HOST_WIDE_INT this_val;
+
+             /* ??? I'm lazy and don't wish to handle CONST_DOUBLE.  Other
+                constants, such as SYMBOL_REF, cannot be extended.  */
+             if (GET_CODE (this_rtx) != CONST_INT)
+               continue;
+
+             this_val = INTVAL (this_rtx);
+             switch (extend_op)
+               {
+               case ZERO_EXTEND:
+                 this_val &= GET_MODE_MASK (GET_MODE (src));
+                 break;
+               case SIGN_EXTEND:
+                 /* ??? In theory we're already extended.  */
+                 if (this_val == trunc_int_for_mode (this_val, GET_MODE (src)))
+                   break;
+               default:
+                 abort ();
+               }
+             this_rtx = GEN_INT (this_val);
+           }
+#endif
+         this_cost = rtx_cost (this_rtx, SET);
+       }
+      else if (GET_CODE (this_rtx) == REG)
+       {
+#ifdef LOAD_EXTEND_OP
+         if (extend_op != NIL)
+           {
+             this_rtx = gen_rtx_fmt_e (extend_op, word_mode, this_rtx);
+             this_cost = rtx_cost (this_rtx, SET);
+           }
+         else
+#endif
+           this_cost = REGISTER_MOVE_COST (GET_MODE (this_rtx),
+                                           REGNO_REG_CLASS (REGNO (this_rtx)),
+                                           dclass);
+       }
       else
        continue;
-      /* If equal costs, prefer registers over anything else.  That tends to
-        lead to smaller instructions on some machines.  */
-      if ((this_cost < old_cost
-          || (this_cost == old_cost
-              && GET_CODE (l->loc) == REG
-              && GET_CODE (SET_SRC (set)) != REG))
-         && validate_change (insn, &SET_SRC (set), copy_rtx (l->loc), 1))
-       old_cost = this_cost, did_change = 1;
+
+      /* If equal costs, prefer registers over anything else.  That
+        tends to lead to smaller instructions on some machines.  */
+      if (this_cost < old_cost
+         || (this_cost == old_cost
+             && GET_CODE (this_rtx) == REG
+             && GET_CODE (SET_SRC (set)) != REG))
+       {
+#ifdef LOAD_EXTEND_OP
+         if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
+             && extend_op != NIL)
+           {
+             rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
+             ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
+             validate_change (insn, &SET_DEST (set), wide_dest, 1);
+           }
+#endif
+
+         validate_change (insn, &SET_SRC (set), copy_rtx (this_rtx), 1);
+         old_cost = this_cost, did_change = 1;
+       }
     }
 
   return did_change;
@@ -8186,8 +8305,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++)
@@ -8290,7 +8409,7 @@ 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_LETTER ((unsigned char) c)];
                  break;
 
                case ',': case '\0':
@@ -8426,14 +8545,16 @@ static void
 reload_combine ()
 {
   rtx insn, set;
-  int first_index_reg = -1, last_index_reg;
+  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)
@@ -8463,17 +8584,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);
        }
@@ -8607,16 +8728,16 @@ 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 ())
                {
                  rtx *np;
 
                  /* Delete the reg-reg addition.  */
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
+                 delete_insn (insn);
 
                  if (reg_state[regno].offset != const0_rtx)
                    /* Previous REG_EQUIV / REG_EQUAL notes for PREV
@@ -8657,7 +8778,7 @@ reload_combine ()
              rtx usage_rtx = XEXP (XEXP (link, 0), 0);
              if (GET_CODE (usage_rtx) == REG)
                {
-                 int i;
+                 unsigned int i;
                  unsigned int start_reg = REGNO (usage_rtx);
                  unsigned int num_regs =
                        HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
@@ -8724,7 +8845,10 @@ reload_combine_note_store (dst, set, data)
 
   if (GET_CODE (dst) == SUBREG)
     {
-      regno = SUBREG_WORD (dst);
+      regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+                                  GET_MODE (SUBREG_REG (dst)),
+                                  SUBREG_BYTE (dst),
+                                  GET_MODE (dst));
       dst = SUBREG_REG (dst);
     }
   if (GET_CODE (dst) != REG)
@@ -8797,7 +8921,12 @@ reload_combine_note_use (xp, insn)
 
     case CLOBBER:
       if (GET_CODE (SET_DEST (x)) == REG)
-       return;
+       {
+         /* No spurious CLOBBERs of pseudo registers may remain.  */
+         if (REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER)
+           abort ();
+         return;
+       }
       break;
 
     case PLUS:
@@ -8814,10 +8943,9 @@ reload_combine_note_use (xp, insn)
        int use_index;
        int nregs;
 
-       /* Some spurious USEs of pseudo registers might remain.
-          Just ignore them.  */
+       /* No spurious USEs of pseudo registers may remain.  */
        if (regno >= FIRST_PSEUDO_REGISTER)
-         return;
+         abort ();
 
        nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
 
@@ -8878,25 +9006,23 @@ reload_combine_note_use (xp, insn)
     }
 }
 \f
-/* See if we can reduce the cost of a constant by replacing a move with
-   an add.  */
+/* See if we can reduce the cost of a constant by replacing a move
+   with an add.  We track situations in which a register is set to a
+   constant or to a register plus a constant.  */
 /* We cannot do our optimization across labels.  Invalidating all the
    information about register contents we have would be costly, so we
-   use last_label_luid (local variable of reload_cse_move2add) to note
-   where the label is and then later disable any optimization that would
-   cross it.
+   use move2add_last_label_luid to note where the label is and then
+   later disable any optimization that would cross it.
    reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
-   reg_set_luid[n] is larger than last_label_luid[n] .  */
+   reg_set_luid[n] is greater than last_label_luid[n] .  */
 static int reg_set_luid[FIRST_PSEUDO_REGISTER];
 
-/* reg_offset[n] has to be CONST_INT for it and reg_base_reg[n] /
-   reg_mode[n] to be valid.
-   If reg_offset[n] is a CONST_INT and reg_base_reg[n] is negative, register n
-   has been set to reg_offset[n] in mode reg_mode[n] .
-   If reg_offset[n] is a CONST_INT and reg_base_reg[n] is non-negative,
-   register n has been set to the sum of reg_offset[n] and register
-   reg_base_reg[n], calculated in mode reg_mode[n] .  */
-static rtx reg_offset[FIRST_PSEUDO_REGISTER];
+/* If reg_base_reg[n] is negative, register n has been set to
+   reg_offset[n] in mode reg_mode[n] .
+   If reg_base_reg[n] is non-negative, register n has been set to the
+   sum of reg_offset[n] and the value of register reg_base_reg[n]
+   before reg_set_luid[n], calculated in mode reg_mode[n] .  */
+static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
 static int reg_base_reg[FIRST_PSEUDO_REGISTER];
 static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
 
@@ -8905,10 +9031,14 @@ static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
    reload_cse_move2add and move2add_note_store.  */
 static int move2add_luid;
 
+/* move2add_last_label_luid is set whenever a label is found.  Labels
+   invalidate all previously collected reg_offset data.  */
+static int move2add_last_label_luid;
+
 /* Generate a CONST_INT and force it in the range of MODE.  */
 
-static rtx
-gen_mode_int (mode, value)
+static HOST_WIDE_INT
+sext_for_mode (mode, value)
      enum machine_mode mode;
      HOST_WIDE_INT value;
 {
@@ -8921,28 +9051,42 @@ gen_mode_int (mode, value)
       && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
     cval |= (HOST_WIDE_INT) -1 << width;
 
-  return GEN_INT (cval);
+  return cval;
 }
 
+/* ??? We don't know how zero / sign extension is handled, hence we
+   can't go from a narrower to a wider mode.  */
+#define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
+  (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
+   || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
+       && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
+                                GET_MODE_BITSIZE (INMODE))))
+
 static void
 reload_cse_move2add (first)
      rtx first;
 {
   int i;
   rtx insn;
-  int last_label_luid;
 
   for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
     reg_set_luid[i] = 0;
 
-  last_label_luid = 0;
-  move2add_luid = 1;
+  move2add_last_label_luid = 0;
+  move2add_luid = 2;
   for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
     {
       rtx pat, note;
 
       if (GET_CODE (insn) == CODE_LABEL)
-       last_label_luid = move2add_luid;
+       {
+         move2add_last_label_luid = move2add_luid;
+         /* We're going to increment move2add_luid twice after a
+            label, so that we can use move2add_last_label_luid + 1 as
+            the luid for constants.  */
+         move2add_luid++;
+         continue;
+       }
       if (! INSN_P (insn))
        continue;
       pat = PATTERN (insn);
@@ -8957,16 +9101,8 @@ reload_cse_move2add (first)
 
          /* Check if we have valid information on the contents of this
             register in the mode of REG.  */
-         /* ??? We don't know how zero / sign extension is handled, hence
-            we can't go from a narrower to a wider mode.  */
-         if (reg_set_luid[regno] > last_label_luid
-             && ((GET_MODE_SIZE (GET_MODE (reg))
-                  == GET_MODE_SIZE (reg_mode[regno]))
-                 || ((GET_MODE_SIZE (GET_MODE (reg))
-                      <= GET_MODE_SIZE (reg_mode[regno]))
-                     && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (reg)),
-                                               GET_MODE_BITSIZE (reg_mode[regno]))))
-             && GET_CODE (reg_offset[regno]) == CONST_INT)
+         if (reg_set_luid[regno] > move2add_last_label_luid
+             && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
            {
              /* Try to transform (set (REGX) (CONST_INT A))
                                  ...
@@ -8979,9 +9115,9 @@ reload_cse_move2add (first)
              if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
                {
                  int success = 0;
-                 rtx new_src
-                   = gen_mode_int (GET_MODE (reg),
-                                   INTVAL (src) - INTVAL (reg_offset[regno]));
+                 rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+                                                       INTVAL (src)
+                                                       - reg_offset[regno]));
                  /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
                     use (set (reg) (reg)) instead.
                     We don't delete this insn, nor do we convert it into a
@@ -8991,12 +9127,12 @@ reload_cse_move2add (first)
                  if (new_src == const0_rtx)
                    success = validate_change (insn, &SET_SRC (pat), reg, 0);
                  else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
-                          && have_add2_insn (GET_MODE (reg)))
+                          && have_add2_insn (reg, new_src))
                    success = validate_change (insn, &PATTERN (insn),
                                               gen_add2_insn (reg, new_src), 0);
                  reg_set_luid[regno] = move2add_luid;
                  reg_mode[regno] = GET_MODE (reg);
-                 reg_offset[regno] = src;
+                 reg_offset[regno] = INTVAL (src);
                  continue;
                }
 
@@ -9011,25 +9147,29 @@ reload_cse_move2add (first)
                                  ...
                                  (set (REGX) (plus (REGX) (CONST_INT B-A)))  */
              else if (GET_CODE (src) == REG
-                      && reg_base_reg[regno] == (int) REGNO (src)
-                      && reg_set_luid[regno] > reg_set_luid[REGNO (src)])
+                      && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
+                      && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
+                      && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
+                                                reg_mode[REGNO (src)]))
                {
                  rtx next = next_nonnote_insn (insn);
                  rtx set = NULL_RTX;
                  if (next)
                    set = single_set (next);
-                 if (next
-                     && set
+                 if (set
                      && SET_DEST (set) == reg
                      && GET_CODE (SET_SRC (set)) == PLUS
                      && XEXP (SET_SRC (set), 0) == reg
                      && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
                    {
                      rtx src3 = XEXP (SET_SRC (set), 1);
-                     rtx new_src
-                       = gen_mode_int (GET_MODE (reg),
-                                       INTVAL (src3)
-                                       - INTVAL (reg_offset[regno]));
+                     HOST_WIDE_INT added_offset = INTVAL (src3);
+                     HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
+                     HOST_WIDE_INT regno_offset = reg_offset[regno];
+                     rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
+                                                           added_offset
+                                                           + base_offset
+                                                           - regno_offset));
                      int success = 0;
 
                      if (new_src == const0_rtx)
@@ -9038,23 +9178,17 @@ reload_cse_move2add (first)
                          = validate_change (next, &SET_SRC (set), reg, 0);
                      else if ((rtx_cost (new_src, PLUS)
                                < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
-                              && have_add2_insn (GET_MODE (reg)))
+                              && have_add2_insn (reg, new_src))
                        success
                          = validate_change (next, &PATTERN (next),
                                             gen_add2_insn (reg, new_src), 0);
                      if (success)
-                       {
-                         /* INSN might be the first insn in a basic block
-                            if the preceding insn is a conditional jump
-                            or a possible-throwing call.  */
-                         PUT_CODE (insn, NOTE);
-                         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                         NOTE_SOURCE_FILE (insn) = 0;
-                       }
+                       delete_insn (insn);
                      insn = next;
-                     reg_set_luid[regno] = move2add_luid;
                      reg_mode[regno] = GET_MODE (reg);
-                     reg_offset[regno] = src3;
+                     reg_offset[regno] = sext_for_mode (GET_MODE (reg),
+                                                        added_offset
+                                                        + base_offset);
                      continue;
                    }
                }
@@ -9066,14 +9200,10 @@ reload_cse_move2add (first)
          if (REG_NOTE_KIND (note) == REG_INC
              && GET_CODE (XEXP (note, 0)) == REG)
            {
-             /* Indicate that this register has been recently written to,
-                but the exact contents are not available.  */
+             /* Reset the information about this register.  */
              int regno = REGNO (XEXP (note, 0));
              if (regno < FIRST_PSEUDO_REGISTER)
-               {
-                 reg_set_luid[regno] = move2add_luid;
-                 reg_offset[regno] = note;
-               }
+               reg_set_luid[regno] = 0;
            }
        }
       note_stores (PATTERN (insn), move2add_note_store, NULL);
@@ -9084,10 +9214,8 @@ reload_cse_move2add (first)
          for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
            {
              if (call_used_regs[i])
-               {
-                 reg_set_luid[i] = move2add_luid;
-                 reg_offset[i] = insn; /* Invalidate contents.  */
-               }
+               /* Reset the information about this register.  */
+               reg_set_luid[i] = 0;
            }
        }
     }
@@ -9108,7 +9236,10 @@ move2add_note_store (dst, set, data)
 
   if (GET_CODE (dst) == SUBREG)
     {
-      regno = SUBREG_WORD (dst);
+      regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
+                                  GET_MODE (SUBREG_REG (dst)),
+                                  SUBREG_BYTE (dst),
+                                  GET_MODE (dst));
       dst = SUBREG_REG (dst);
     }
 
@@ -9117,15 +9248,11 @@ move2add_note_store (dst, set, data)
   if (GET_CODE (dst) == MEM)
     {
       dst = XEXP (dst, 0);
-      if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_DEC
+      if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
          || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
-       {
-         regno = REGNO (XEXP (dst, 0));
-         reg_set_luid[regno] = move2add_luid;
-         reg_offset[regno] = dst;
-       }
+       reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
       return;
-    } 
+    }
   if (GET_CODE (dst) != REG)
     return;
 
@@ -9137,56 +9264,106 @@ move2add_note_store (dst, set, data)
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
     {
       rtx src = SET_SRC (set);
+      rtx base_reg;
+      HOST_WIDE_INT offset;
+      int base_regno;
+      /* This may be different from mode, if SET_DEST (set) is a
+        SUBREG.  */
+      enum machine_mode dst_mode = GET_MODE (dst);
 
-      reg_mode[regno] = mode;
       switch (GET_CODE (src))
        {
        case PLUS:
-         {
-           rtx src0 = XEXP (src, 0);
-
-           if (GET_CODE (src0) == REG)
-             {
-               if (REGNO (src0) != regno
-                   || reg_offset[regno] != const0_rtx)
-                 {
-                   reg_base_reg[regno] = REGNO (src0);
-                   reg_set_luid[regno] = move2add_luid;
-                 }
+         if (GET_CODE (XEXP (src, 0)) == REG)
+           {
+             base_reg = XEXP (src, 0);
+
+             if (GET_CODE (XEXP (src, 1)) == CONST_INT)
+               offset = INTVAL (XEXP (src, 1));
+             else if (GET_CODE (XEXP (src, 1)) == REG
+                      && (reg_set_luid[REGNO (XEXP (src, 1))]
+                          > move2add_last_label_luid)
+                      && (MODES_OK_FOR_MOVE2ADD
+                          (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
+               {
+                 if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
+                   offset = reg_offset[REGNO (XEXP (src, 1))];
+                 /* Maybe the first register is known to be a
+                    constant.  */
+                 else if (reg_set_luid[REGNO (base_reg)]
+                          > move2add_last_label_luid
+                          && (MODES_OK_FOR_MOVE2ADD
+                              (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
+                          && reg_base_reg[REGNO (base_reg)] < 0)
+                   {
+                     offset = reg_offset[REGNO (base_reg)];
+                     base_reg = XEXP (src, 1);
+                   }
+                 else
+                   goto invalidate;
+               }
+             else
+               goto invalidate;
 
-               reg_offset[regno] = XEXP (src, 1);
-               break;
-             }
+             break;
+           }
 
-           reg_set_luid[regno] = move2add_luid;
-           reg_offset[regno] = set;    /* Invalidate contents.  */
-           break;
-         }
+         goto invalidate;
 
        case REG:
-         reg_base_reg[regno] = REGNO (SET_SRC (set));
-         reg_offset[regno] = const0_rtx;
-         reg_set_luid[regno] = move2add_luid;
+         base_reg = src;
+         offset = 0;
          break;
 
-       default:
+       case CONST_INT:
+         /* Start tracking the register as a constant.  */
          reg_base_reg[regno] = -1;
-         reg_offset[regno] = SET_SRC (set);
-         reg_set_luid[regno] = move2add_luid;
-         break;
+         reg_offset[regno] = INTVAL (SET_SRC (set));
+         /* We assign the same luid to all registers set to constants.  */
+         reg_set_luid[regno] = move2add_last_label_luid + 1;
+         reg_mode[regno] = mode;
+         return;
+
+       default:
+       invalidate:
+         /* Invalidate the contents of the register.  */
+         reg_set_luid[regno] = 0;
+         return;
        }
+
+      base_regno = REGNO (base_reg);
+      /* If information about the base register is not valid, set it
+        up as a new base register, pretending its value is known
+        starting from the current insn.  */
+      if (reg_set_luid[base_regno] <= move2add_last_label_luid)
+       {
+         reg_base_reg[base_regno] = base_regno;
+         reg_offset[base_regno] = 0;
+         reg_set_luid[base_regno] = move2add_luid;
+         reg_mode[base_regno] = mode;
+       }
+      else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
+                                       reg_mode[base_regno]))
+       goto invalidate;
+
+      reg_mode[regno] = mode;
+
+      /* Copy base information from our base register.  */
+      reg_set_luid[regno] = reg_set_luid[base_regno];
+      reg_base_reg[regno] = reg_base_reg[base_regno];
+
+      /* Compute the sum of the offsets or constants.  */
+      reg_offset[regno] = sext_for_mode (dst_mode,
+                                        offset
+                                        + reg_offset[base_regno]);
     }
   else
     {
       unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
 
       for (i = regno; i < endregno; i++)
-       {
-         /* Indicate that this register has been recently written to,
-            but the exact contents are not available.  */
-         reg_set_luid[i] = move2add_luid;
-         reg_offset[i] = dst;
-       }
+       /* Reset the information about this register.  */
+       reg_set_luid[i] = 0;
     }
 }
 
@@ -9219,3 +9396,93 @@ add_auto_inc_notes (insn, x)
     }
 }
 #endif
+
+/* Copy EH notes from an insn to its reloads.  */
+static void
+copy_eh_notes (insn, x)
+     rtx insn;
+     rtx x;
+{
+  rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+  if (eh_note)
+    {
+      for (; x != 0; x = NEXT_INSN (x))
+       {
+         if (may_trap_p (PATTERN (x)))
+           REG_NOTES (x)
+             = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
+                                  REG_NOTES (x));
+       }
+    }
+}
+
+/* This is used by reload pass, that does emit some instructions after
+   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.  */
+void
+fixup_abnormal_edges ()
+{
+  bool inserted = false;
+  basic_block bb;
+
+  FOR_EACH_BB (bb)
+    {
+      edge e;
+
+      /* Look for cases we are interested in - an calls or instructions causing
+         exceptions.  */
+      for (e = bb->succ; e; e = e->succ_next)
+       {
+         if (e->flags & EDGE_ABNORMAL_CALL)
+           break;
+         if ((e->flags & (EDGE_ABNORMAL | EDGE_EH))
+             == (EDGE_ABNORMAL | EDGE_EH))
+           break;
+       }
+      if (e && GET_CODE (bb->end) != CALL_INSN && !can_throw_internal (bb->end))
+       {
+         rtx insn = bb->end, stop = NEXT_INSN (bb->end);
+         rtx next;
+         for (e = bb->succ; e; e = e->succ_next)
+           if (e->flags & EDGE_FALLTHRU)
+             break;
+         /* Get past the new insns generated. Allow notes, as the insns may
+            be already deleted.  */
+         while ((GET_CODE (insn) == INSN || GET_CODE (insn) == NOTE)
+                && !can_throw_internal (insn)
+                && insn != bb->head)
+           insn = PREV_INSN (insn);
+         if (GET_CODE (insn) != CALL_INSN && !can_throw_internal (insn))
+           abort ();
+         bb->end = insn;
+         inserted = true;
+         insn = NEXT_INSN (insn);
+         while (insn && insn != stop)
+           {
+             next = NEXT_INSN (insn);
+             if (INSN_P (insn))
+               {
+                 rtx seq;
+
+                 delete_insn (insn);
+
+                 /* We're not deleting it, we're moving it.  */
+                 INSN_DELETED_P (insn) = 0;
+
+                 /* Emit a sequence, rather than scarfing the pattern, so
+                    that we don't lose REG_NOTES etc.  */
+                 /* ??? Could copy the test from gen_sequence, but don't
+                    think it's worth the bother.  */
+                 seq = gen_rtx_SEQUENCE (VOIDmode, gen_rtvec (1, insn));
+                 insert_insn_on_edge (seq, e);
+               }
+             insn = next;
+           }
+       }
+    }
+  if (inserted)
+    commit_edge_insertions ();
+}