OSDN Git Service

Added fixup for __STDC__ == 0 and __STDC__ == 1
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index e4ca0e7..c7ea46f 100644 (file)
@@ -1,5 +1,5 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,6 +18,7 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
+#include <stdio.h>
 #include "config.h"
 #include "rtl.h"
 #include "obstack.h"
@@ -32,7 +33,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "recog.h"
 #include "basic-block.h"
 #include "output.h"
-#include <stdio.h>
 
 /* This file contains the reload pass of the compiler, which is
    run after register allocation has been done.  It checks that
@@ -66,9 +66,18 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    reload needs, spilling, assigning reload registers to use for
    fixing up each insn, and generating the new insns to copy values
    into the reload registers.  */
+
+
+#ifndef REGISTER_MOVE_COST
+#define REGISTER_MOVE_COST(x, y) 2
+#endif
+
+#ifndef MEMORY_MOVE_COST
+#define MEMORY_MOVE_COST(x) 4
+#endif
 \f
 /* During reload_as_needed, element N contains a REG rtx for the hard reg
-   into which pseudo reg N has been reloaded (perhaps for a previous insn). */
+   into which reg N has been reloaded (perhaps for a previous insn). */
 static rtx *reg_last_reload_reg;
 
 /* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
@@ -89,7 +98,7 @@ rtx *reg_equiv_constant;
    prior to any register elimination (such as frame pointer to stack
    pointer).  Depending on whether or not it is a valid address, this value
    is transferred to either reg_equiv_address or reg_equiv_mem.  */
-static rtx *reg_equiv_memory_loc;
+rtx *reg_equiv_memory_loc;
 
 /* Element N is the address of stack slot to which pseudo reg N is equivalent.
    This is used when the address is not valid as a memory address
@@ -147,8 +156,8 @@ HARD_REG_SET forbidden_regs;
 
 /* This reg set indicates registers that are not good for spill registers.
    They will not be used to complete groups of spill registers.  This includes
-   all fixed registers, registers that may be eliminated, and registers
-   explicitly used in the rtl.
+   all fixed registers, registers that may be eliminated, and, if
+   SMALL_REGISTER_CLASSES is not defined, registers explicitly used in the rtl.
 
    (spill_reg_order prevents these registers from being used to start a
    group.)  */
@@ -181,6 +190,12 @@ static HARD_REG_SET counted_for_groups;
    as part of a group, even if it seems to be otherwise ok.  */
 static HARD_REG_SET counted_for_nongroups;
 
+/* Indexed by pseudo reg number N,
+   says may not delete stores into the real (memory) home of pseudo N.
+   This is set if we already substituted a memory equivalent in some uses,
+   which happens when we have to eliminate the fp from it.  */
+static char *cannot_omit_stores;
+
 /* Nonzero if indirect addressing is supported on the machine; this means
    that spilling (REG n) does not require reloading it into a register in
    order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))).  The
@@ -236,7 +251,7 @@ int reload_in_progress = 0;
 enum insn_code reload_in_optab[NUM_MACHINE_MODES];
 enum insn_code reload_out_optab[NUM_MACHINE_MODES];
 
-/* This obstack is used for allocation of rtl during register elmination.
+/* This obstack is used for allocation of rtl during register elimination.
    The allocated storage can be freed once find_reloads has processed the
    insn.  */
 
@@ -246,9 +261,6 @@ char *reload_firstobj;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
-extern int xmalloc ();
-extern void free ();
-
 /* List of labels that must never be deleted.  */
 extern rtx forced_labels;
 \f
@@ -310,33 +322,50 @@ static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 /* Number of labels in the current function.  */
 
 static int num_labels;
+
+struct hard_reg_n_uses { int regno; int uses; };
 \f
-void mark_home_live ();
-static void count_possible_groups ();
-static int possible_group_p ();
-static void scan_paradoxical_subregs ();
-static void reload_as_needed ();
-static int modes_equiv_for_class_p ();
-static void alter_reg ();
-static void delete_dead_insn ();
-static int new_spill_reg();
-static void set_label_offsets ();
-static int eliminate_regs_in_insn ();
-static void mark_not_eliminable ();
-static int spill_hard_reg ();
-static void choose_reload_regs ();
-static void emit_reload_insns ();
-static void delete_output_reload ();
-static void forget_old_reloads_1 ();
-static void order_regs_for_reload ();
-static rtx inc_for_reload ();
-static int constraint_accepts_reg_p ();
-static int count_occurrences ();
-
-extern void remove_death ();
-extern rtx adj_offsettable_operand ();
-extern rtx form_sum ();
+static int possible_group_p            PROTO((int, int *));
+static void count_possible_groups      PROTO((int *, enum machine_mode *,
+                                              int *));
+static int modes_equiv_for_class_p     PROTO((enum machine_mode,
+                                              enum machine_mode,
+                                              enum reg_class));
+static void spill_failure              PROTO((rtx));
+static int new_spill_reg               PROTO((int, int, int *, int *, int,
+                                              FILE *));
+static void delete_dead_insn           PROTO((rtx));
+static void alter_reg                          PROTO((int, int));
+static void mark_scratch_live          PROTO((rtx));
+static void set_label_offsets          PROTO((rtx, rtx, int));
+static int eliminate_regs_in_insn      PROTO((rtx, int));
+static void mark_not_eliminable                PROTO((rtx, rtx));
+static int spill_hard_reg              PROTO((int, int, FILE *, int));
+static void scan_paradoxical_subregs   PROTO((rtx));
+static int hard_reg_use_compare                PROTO((struct hard_reg_n_uses *,
+                                              struct hard_reg_n_uses *));
+static void order_regs_for_reload      PROTO((void));
+static void reload_as_needed           PROTO((rtx, int));
+static void forget_old_reloads_1       PROTO((rtx, rtx));
+static int reload_reg_class_lower      PROTO((short *, short *));
+static void mark_reload_reg_in_use     PROTO((int, int, enum reload_type,
+                                              enum machine_mode));
+static void clear_reload_reg_in_use    PROTO((int, int, enum reload_type,
+                                              enum machine_mode));
+static int reload_reg_free_p           PROTO((int, int, enum reload_type));
+static int reload_reg_free_before_p    PROTO((int, int, enum reload_type));
+static int reload_reg_reaches_end_p    PROTO((int, int, enum reload_type));
+static int allocate_reload_reg         PROTO((int, rtx, int, int));
+static void choose_reload_regs         PROTO((rtx, rtx));
+static void merge_assigned_reloads     PROTO((rtx));
+static void emit_reload_insns          PROTO((rtx));
+static void delete_output_reload       PROTO((rtx, int, rtx));
+static void inc_for_reload             PROTO((rtx, rtx, int));
+static int constraint_accepts_reg_p    PROTO((char *, rtx));
+static int count_occurrences           PROTO((rtx, rtx));
 \f
+/* Initialize the reload pass once per compilation.  */
+
 void
 init_reload ()
 {
@@ -350,7 +379,7 @@ init_reload ()
     = gen_rtx (MEM, Pmode,
               gen_rtx (PLUS, Pmode,
                        gen_rtx (REG, Pmode, LAST_VIRTUAL_REGISTER + 1),
-                       gen_rtx (CONST_INT, VOIDmode, 4)));
+                       GEN_INT (4)));
   spill_indirect_levels = 0;
 
   while (memory_address_p (QImode, tem))
@@ -366,105 +395,27 @@ init_reload ()
 
   /* See if reg+reg is a valid (and offsettable) address.  */
 
-  tem = gen_rtx (PLUS, Pmode,
-                gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM),
-                gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM));
-  /* This way, we make sure that reg+reg is an offsettable address.  */
-  tem = plus_constant (tem, 4);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      tem = gen_rtx (PLUS, Pmode,
+                    gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM),
+                    gen_rtx (REG, Pmode, i));
+      /* This way, we make sure that reg+reg is an offsettable address.  */
+      tem = plus_constant (tem, 4);
 
-  double_reg_address_ok = memory_address_p (QImode, tem);
+      if (memory_address_p (QImode, tem))
+       {
+         double_reg_address_ok = 1;
+         break;
+       }
+    }
 
   /* Initialize obstack for our rtl allocation. */
   gcc_obstack_init (&reload_obstack);
   reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
-
-#ifdef HAVE_SECONDARY_RELOADS
-
-  /* Initialize the optabs for doing special input and output reloads.  */
-
-  for (i = 0; i < NUM_MACHINE_MODES; i++)
-    reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
-
-#ifdef HAVE_reload_inqi
-  if (HAVE_reload_inqi)
-    reload_in_optab[(int) QImode] = CODE_FOR_reload_inqi;
-#endif
-#ifdef HAVE_reload_inhi
-  if (HAVE_reload_inhi)
-    reload_in_optab[(int) HImode] = CODE_FOR_reload_inhi;
-#endif
-#ifdef HAVE_reload_insi
-  if (HAVE_reload_insi)
-    reload_in_optab[(int) SImode] = CODE_FOR_reload_insi;
-#endif
-#ifdef HAVE_reload_indi
-  if (HAVE_reload_indi)
-    reload_in_optab[(int) DImode] = CODE_FOR_reload_indi;
-#endif
-#ifdef HAVE_reload_inti
-  if (HAVE_reload_inti)
-    reload_in_optab[(int) TImode] = CODE_FOR_reload_inti;
-#endif
-#ifdef HAVE_reload_insf
-  if (HAVE_reload_insf)
-    reload_in_optab[(int) SFmode] = CODE_FOR_reload_insf;
-#endif
-#ifdef HAVE_reload_indf
-  if (HAVE_reload_indf)
-    reload_in_optab[(int) DFmode] = CODE_FOR_reload_indf;
-#endif
-#ifdef HAVE_reload_inxf
-  if (HAVE_reload_inxf)
-    reload_in_optab[(int) XFmode] = CODE_FOR_reload_inxf;
-#endif
-#ifdef HAVE_reload_intf
-  if (HAVE_reload_intf)
-    reload_in_optab[(int) TFmode] = CODE_FOR_reload_intf;
-#endif
-
-#ifdef HAVE_reload_outqi
-  if (HAVE_reload_outqi)
-    reload_out_optab[(int) QImode] = CODE_FOR_reload_outqi;
-#endif
-#ifdef HAVE_reload_outhi
-  if (HAVE_reload_outhi)
-    reload_out_optab[(int) HImode] = CODE_FOR_reload_outhi;
-#endif
-#ifdef HAVE_reload_outsi
-  if (HAVE_reload_outsi)
-    reload_out_optab[(int) SImode] = CODE_FOR_reload_outsi;
-#endif
-#ifdef HAVE_reload_outdi
-  if (HAVE_reload_outdi)
-    reload_out_optab[(int) DImode] = CODE_FOR_reload_outdi;
-#endif
-#ifdef HAVE_reload_outti
-  if (HAVE_reload_outti)
-    reload_out_optab[(int) TImode] = CODE_FOR_reload_outti;
-#endif
-#ifdef HAVE_reload_outsf
-  if (HAVE_reload_outsf)
-    reload_out_optab[(int) SFmode] = CODE_FOR_reload_outsf;
-#endif
-#ifdef HAVE_reload_outdf
-  if (HAVE_reload_outdf)
-    reload_out_optab[(int) DFmode] = CODE_FOR_reload_outdf;
-#endif
-#ifdef HAVE_reload_outxf
-  if (HAVE_reload_outxf)
-    reload_out_optab[(int) XFmode] = CODE_FOR_reload_outxf;
-#endif
-#ifdef HAVE_reload_outtf
-  if (HAVE_reload_outtf)
-    reload_out_optab[(int) TFmode] = CODE_FOR_reload_outtf;
-#endif
-
-#endif /* HAVE_SECONDARY_RELOADS */
-
 }
 
-/* Main entry point for the reload pass, and only entry point
-   in this file.
+/* Main entry point for the reload pass.
 
    FIRST is the first insn of the function being compiled.
 
@@ -477,16 +428,19 @@ init_reload ()
    DUMPFILE is the global-reg debugging dump file stream, or 0.
    If it is nonzero, messages are written to it to describe
    which registers are seized as reload regs, which pseudo regs
-   are spilled from them, and where the pseudo regs are reallocated to.  */
+   are spilled from them, and where the pseudo regs are reallocated to.
 
-void
+   Return value is nonzero if reload failed
+   and we must not do any more for this function.  */
+
+int
 reload (first, global, dumpfile)
      rtx first;
      int global;
      FILE *dumpfile;
 {
   register int class;
-  register int i;
+  register int i, j;
   register rtx insn;
   register struct elim_table *ep;
 
@@ -497,6 +451,9 @@ reload (first, global, dumpfile)
   enum reg_class caller_save_spill_class = NO_REGS;
   int caller_save_group_size = 1;
 
+  /* Nonzero means we couldn't get enough spill regs.  */
+  int failure = 0;
+
   /* The basic block number currently being processed for INSN.  */
   int this_block;
 
@@ -509,6 +466,11 @@ reload (first, global, dumpfile)
   for (i = 0; i < N_REG_CLASSES; i++)
     basic_block_needs[i] = 0;
 
+#ifdef SECONDARY_MEMORY_NEEDED
+  /* Initialize the secondary memory table.  */
+  clear_secondary_mem ();
+#endif
+
   /* Remember which hard regs appear explicitly
      before we merge into `regs_ever_live' the ones in which
      pseudo regs have been allocated.  */
@@ -530,9 +492,13 @@ reload (first, global, dumpfile)
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     mark_home_live (i);
 
+  for (i = 0; i < scratch_list_length; i++)
+    if (scratch_list[i])
+      mark_scratch_live (scratch_list[i]);
+
   /* Make sure that the last insn in the chain
      is not something that needs reloading.  */
-  emit_note (0, NOTE_INSN_DELETED);
+  emit_note (NULL_PTR, NOTE_INSN_DELETED);
 
   /* Find all the pseudo registers that didn't get hard regs
      but do have known equivalent constants or memory slots.
@@ -556,6 +522,8 @@ reload (first, global, dumpfile)
   bzero (reg_equiv_address, max_regno * sizeof (rtx));
   reg_max_ref_width = (int *) alloca (max_regno * sizeof (int));
   bzero (reg_max_ref_width, max_regno * sizeof (int));
+  cannot_omit_stores = (char *) alloca (max_regno);
+  bzero (cannot_omit_stores, max_regno);
 
   /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
      Also find all paradoxical subregs
@@ -567,7 +535,7 @@ reload (first, global, dumpfile)
 
       if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
        {
-         rtx note = find_reg_note (insn, REG_EQUIV, 0);
+         rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
          if (note
 #ifdef LEGITIMATE_PIC_OPERAND_P
              && (! CONSTANT_P (XEXP (note, 0)) || ! flag_pic
@@ -702,7 +670,7 @@ reload (first, global, dumpfile)
     if (reg_renumber[i] == -1 && reg_n_refs[i] != 0)
       break;
 
-  if (i == max_regno && num_eliminable = 0 && ! caller_save_needed)
+  if (i == max_regno && num_eliminable == 0 && ! caller_save_needed)
     return;
 #endif
 
@@ -741,10 +709,13 @@ reload (first, global, dumpfile)
        bzero (basic_block_needs[i], n_basic_blocks);
       }
 
+  /* From now on, we need to emit any moves without making new pseudos.  */
+  reload_in_progress = 1;
+
   /* This loop scans the entire function each go-round
      and repeats until one repetition spills no additional hard regs.  */
 
-  /* This flag is set when a psuedo reg is spilled,
+  /* This flag is set when a pseudo reg is spilled,
      to require another pass.  Note that getting an additional reload
      reg does not necessarily imply any pseudo reg was spilled;
      sometimes we find a reload reg that no pseudo reg was allocated in.  */
@@ -777,12 +748,21 @@ reload (first, global, dumpfile)
         they must be the same size and equally restrictive for that class,
         otherwise we can't handle the complexity.  */
       enum machine_mode group_mode[N_REG_CLASSES];
+      /* Record the insn where each maximum need is first found.  */
+      rtx max_needs_insn[N_REG_CLASSES];
+      rtx max_groups_insn[N_REG_CLASSES];
+      rtx max_nongroups_insn[N_REG_CLASSES];
       rtx x;
+      int starting_frame_size = get_frame_size ();
+      static char *reg_class_names[] = REG_CLASS_NAMES;
 
       something_changed = 0;
       bzero (max_needs, sizeof max_needs);
       bzero (max_groups, sizeof max_groups);
       bzero (max_nongroups, sizeof max_nongroups);
+      bzero (max_needs_insn, sizeof max_needs_insn);
+      bzero (max_groups_insn, sizeof max_groups_insn);
+      bzero (max_nongroups_insn, sizeof max_nongroups_insn);
       bzero (group_size, sizeof group_size);
       for (i = 0; i < N_REG_CLASSES; i++)
        group_mode[i] = VOIDmode;
@@ -825,7 +805,7 @@ reload (first, global, dumpfile)
 
       for (x = forced_labels; x; x = XEXP (x, 1))
        if (XEXP (x, 0))
-         set_label_offsets (XEXP (x, 0), 0, 1);
+         set_label_offsets (XEXP (x, 0), NULL_RTX, 1);
 
       /* For each pseudo register that has an equivalent location defined,
         try to eliminate any eliminable registers (such as the frame pointer)
@@ -839,7 +819,8 @@ reload (first, global, dumpfile)
         and constant, it is probably not addressable because the constant is
         out of range, in that case record the address; we will generate
         hairy code to compute the address in a register each time it is
-        needed.
+        needed.  Similarly if it is a hard register, but one that is not
+        valid as an address register.
 
         If the location is not addressable, but does not have one of the
         above forms, assign a stack slot.  We have to do this to avoid the
@@ -853,12 +834,14 @@ reload (first, global, dumpfile)
       for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
        if (reg_renumber[i] < 0 && reg_equiv_memory_loc[i])
          {
-           rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, 0);
+           rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX);
 
            if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]),
                                         XEXP (x, 0)))
              reg_equiv_mem[i] = x, reg_equiv_address[i] = 0;
            else if (CONSTANT_P (XEXP (x, 0))
+                    || (GET_CODE (XEXP (x, 0)) == REG
+                        && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
                     || (GET_CODE (XEXP (x, 0)) == PLUS
                         && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
                         && (REGNO (XEXP (XEXP (x, 0), 0))
@@ -880,7 +863,7 @@ reload (first, global, dumpfile)
              }
          }
 
-      /* If we allocated another psuedo to the stack, redo elimination
+      /* If we allocated another pseudo to the stack, redo elimination
         bookkeeping.  */
       if (something_changed)
        continue;
@@ -922,27 +905,65 @@ reload (first, global, dumpfile)
              int old_code = INSN_CODE (insn);
              rtx old_notes = REG_NOTES (insn);
              int did_elimination = 0;
-
-             /* Initially, count RELOAD_OTHER reloads.
-                Later, merge in the other kinds.  */
+             int max_total_input_groups = 0, max_total_output_groups = 0;
+
+             /* To compute the number of reload registers of each class 
+                needed for an insn, we must similate what choose_reload_regs
+                can do.  We do this by splitting an insn into an "input" and
+                an "output" part.  RELOAD_OTHER reloads are used in both. 
+                The input part uses those reloads, RELOAD_FOR_INPUT reloads,
+                which must be live over the entire input section of reloads,
+                and the maximum of all the RELOAD_FOR_INPUT_ADDRESS and
+                RELOAD_FOR_OPERAND_ADDRESS reloads, which conflict with the
+                inputs.
+
+                The registers needed for output are RELOAD_OTHER and
+                RELOAD_FOR_OUTPUT, which are live for the entire output
+                portion, and the maximum of all the RELOAD_FOR_OUTPUT_ADDRESS
+                reloads for each operand.
+
+                The total number of registers needed is the maximum of the
+                inputs and outputs.  */
+
+             /* These just count RELOAD_OTHER.  */
              int insn_needs[N_REG_CLASSES];
              int insn_groups[N_REG_CLASSES];
              int insn_total_groups = 0;
 
-             /* Count RELOAD_FOR_INPUT_RELOAD_ADDRESS reloads.  */
+             /* Count RELOAD_FOR_INPUT reloads.  */
              int insn_needs_for_inputs[N_REG_CLASSES];
              int insn_groups_for_inputs[N_REG_CLASSES];
              int insn_total_groups_for_inputs = 0;
 
-             /* Count RELOAD_FOR_OUTPUT_RELOAD_ADDRESS reloads.  */
+             /* Count RELOAD_FOR_OUTPUT reloads.  */
              int insn_needs_for_outputs[N_REG_CLASSES];
              int insn_groups_for_outputs[N_REG_CLASSES];
              int insn_total_groups_for_outputs = 0;
 
+             /* Count RELOAD_FOR_INSN reloads.  */
+             int insn_needs_for_insn[N_REG_CLASSES];
+             int insn_groups_for_insn[N_REG_CLASSES];
+             int insn_total_groups_for_insn = 0;
+
+             /* Count RELOAD_FOR_OTHER_ADDRESS reloads.  */
+             int insn_needs_for_other_addr[N_REG_CLASSES];
+             int insn_groups_for_other_addr[N_REG_CLASSES];
+             int insn_total_groups_for_other_addr = 0;
+
+             /* Count RELOAD_FOR_INPUT_ADDRESS reloads.  */
+             int insn_needs_for_in_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
+             int insn_groups_for_in_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
+             int insn_total_groups_for_in_addr[MAX_RECOG_OPERANDS];
+
+             /* Count RELOAD_FOR_OUTPUT_ADDRESS reloads.  */
+             int insn_needs_for_out_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
+             int insn_groups_for_out_addr[MAX_RECOG_OPERANDS][N_REG_CLASSES];
+             int insn_total_groups_for_out_addr[MAX_RECOG_OPERANDS];
+
              /* Count RELOAD_FOR_OPERAND_ADDRESS reloads.  */
-             int insn_needs_for_operands[N_REG_CLASSES];
-             int insn_groups_for_operands[N_REG_CLASSES];
-             int insn_total_groups_for_operands = 0;
+             int insn_needs_for_op_addr[N_REG_CLASSES];
+             int insn_groups_for_op_addr[N_REG_CLASSES];
+             int insn_total_groups_for_op_addr = 0;
 
 #if 0  /* This wouldn't work nowadays, since optimize_bit_field
          looks for non-strict memory addresses.  */
@@ -1011,6 +1032,7 @@ reload (first, global, dumpfile)
 
              PUT_MODE (insn, (did_elimination ? QImode
                               : n_reloads ? HImode
+                              : GET_MODE (insn) == DImode ? DImode
                               : VOIDmode));
 
              /* Discard any register replacements done.  */
@@ -1039,15 +1061,33 @@ reload (first, global, dumpfile)
                  insn_needs[i] = 0, insn_groups[i] = 0;
                  insn_needs_for_inputs[i] = 0, insn_groups_for_inputs[i] = 0;
                  insn_needs_for_outputs[i] = 0, insn_groups_for_outputs[i] = 0;
-                 insn_needs_for_operands[i] = 0, insn_groups_for_operands[i] = 0;
+                 insn_needs_for_insn[i] = 0, insn_groups_for_insn[i] = 0;
+                 insn_needs_for_op_addr[i] = 0, insn_groups_for_op_addr[i] = 0;
+                 insn_needs_for_other_addr[i] = 0;
+                 insn_groups_for_other_addr[i] = 0;
                }
 
+             for (i = 0; i < reload_n_operands; i++)
+               {
+                 insn_total_groups_for_in_addr[i] = 0;
+                 insn_total_groups_for_out_addr[i] = 0;
+
+                 for (j = 0; j < N_REG_CLASSES; j++)
+                   {
+                     insn_needs_for_in_addr[i][j] = 0;
+                     insn_needs_for_out_addr[i][j] = 0;
+                     insn_groups_for_in_addr[i][j] = 0;
+                     insn_groups_for_out_addr[i][j] = 0;
+                   }
+               }
+                   
              /* Count each reload once in every class
                 containing the reload's own class.  */
 
              for (i = 0; i < n_reloads; i++)
                {
                  register enum reg_class *p;
+                 enum reg_class class = reload_reg_class[i];
                  int size;
                  enum machine_mode mode;
                  int *this_groups;
@@ -1064,48 +1104,82 @@ reload (first, global, dumpfile)
                          && ! reload_secondary_p[i]))
                    continue;
 
+                 /* Show that a reload register of this class is needed
+                    in this basic block.  We do not use insn_needs and
+                    insn_groups because they are overly conservative for
+                    this purpose.  */
+                 if (global && ! basic_block_needs[(int) class][this_block])
+                   {
+                     basic_block_needs[(int) class][this_block] = 1;
+                     new_basic_block_needs = 1;
+                   }
+
                  /* Decide which time-of-use to count this reload for.  */
                  switch (reload_when_needed[i])
                    {
                    case RELOAD_OTHER:
-                   case RELOAD_FOR_OUTPUT:
-                   case RELOAD_FOR_INPUT:
                      this_needs = insn_needs;
                      this_groups = insn_groups;
                      this_total_groups = &insn_total_groups;
                      break;
 
-                   case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
+                   case RELOAD_FOR_INPUT:
                      this_needs = insn_needs_for_inputs;
                      this_groups = insn_groups_for_inputs;
                      this_total_groups = &insn_total_groups_for_inputs;
                      break;
 
-                   case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
+                   case RELOAD_FOR_OUTPUT:
                      this_needs = insn_needs_for_outputs;
                      this_groups = insn_groups_for_outputs;
                      this_total_groups = &insn_total_groups_for_outputs;
                      break;
 
+                   case RELOAD_FOR_INSN:
+                     this_needs = insn_needs_for_insn;
+                     this_groups = insn_groups_for_outputs;
+                     this_total_groups = &insn_total_groups_for_insn;
+                     break;
+
+                   case RELOAD_FOR_OTHER_ADDRESS:
+                     this_needs = insn_needs_for_other_addr;
+                     this_groups = insn_groups_for_other_addr;
+                     this_total_groups = &insn_total_groups_for_other_addr;
+                     break;
+
+                   case RELOAD_FOR_INPUT_ADDRESS:
+                     this_needs = insn_needs_for_in_addr[reload_opnum[i]];
+                     this_groups = insn_groups_for_in_addr[reload_opnum[i]];
+                     this_total_groups
+                       = &insn_total_groups_for_in_addr[reload_opnum[i]];
+                     break;
+
+                   case RELOAD_FOR_OUTPUT_ADDRESS:
+                     this_needs = insn_needs_for_out_addr[reload_opnum[i]];
+                     this_groups = insn_groups_for_out_addr[reload_opnum[i]];
+                     this_total_groups
+                       = &insn_total_groups_for_out_addr[reload_opnum[i]];
+                     break;
+
                    case RELOAD_FOR_OPERAND_ADDRESS:
-                     this_needs = insn_needs_for_operands;
-                     this_groups = insn_groups_for_operands;
-                     this_total_groups = &insn_total_groups_for_operands;
+                     this_needs = insn_needs_for_op_addr;
+                     this_groups = insn_groups_for_op_addr;
+                     this_total_groups = &insn_total_groups_for_op_addr;
                      break;
                    }
 
                  mode = reload_inmode[i];
                  if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
                    mode = reload_outmode[i];
-                 size = CLASS_MAX_NREGS (reload_reg_class[i], mode);
+                 size = CLASS_MAX_NREGS (class, mode);
                  if (size > 1)
                    {
                      enum machine_mode other_mode, allocate_mode;
 
                      /* Count number of groups needed separately from
                         number of individual regs needed.  */
-                     this_groups[(int) reload_reg_class[i]]++;
-                     p = reg_class_superclasses[(int) reload_reg_class[i]];
+                     this_groups[(int) class]++;
+                     p = reg_class_superclasses[(int) class];
                      while (*p != LIM_REG_CLASSES)
                        this_groups[(int) *p++]++;
                      (*this_total_groups)++;
@@ -1113,18 +1187,18 @@ reload (first, global, dumpfile)
                      /* Record size and mode of a group of this class.  */
                      /* If more than one size group is needed,
                         make all groups the largest needed size.  */
-                     if (group_size[(int) reload_reg_class[i]] < size)
+                     if (group_size[(int) class] < size)
                        {
-                         other_mode = group_mode[(int) reload_reg_class[i]];
+                         other_mode = group_mode[(int) class];
                          allocate_mode = mode;
 
-                         group_size[(int) reload_reg_class[i]] = size;
-                         group_mode[(int) reload_reg_class[i]] = mode;
+                         group_size[(int) class] = size;
+                         group_mode[(int) class] = mode;
                        }
                      else
                        {
                          other_mode = mode;
-                         allocate_mode = group_mode[(int) reload_reg_class[i]];
+                         allocate_mode = group_mode[(int) class];
                        }
 
                      /* Crash if two dissimilar machine modes both need
@@ -1134,13 +1208,13 @@ reload (first, global, dumpfile)
                          && other_mode != allocate_mode
                          && ! modes_equiv_for_class_p (allocate_mode,
                                                        other_mode,
-                                                       reload_reg_class[i]))
+                                                       class))
                        abort ();
                    }
                  else if (size == 1)
                    {
-                     this_needs[(int) reload_reg_class[i]] += 1;
-                     p = reg_class_superclasses[(int) reload_reg_class[i]];
+                     this_needs[(int) class] += 1;
+                     p = reg_class_superclasses[(int) class];
                      while (*p != LIM_REG_CLASSES)
                        this_needs[(int) *p++] += 1;
                    }
@@ -1155,24 +1229,82 @@ reload (first, global, dumpfile)
 
              for (i = 0; i < N_REG_CLASSES; i++)
                {
-                 int this_max;
-                 this_max = insn_needs_for_inputs[i];
-                 if (insn_needs_for_outputs[i] > this_max)
-                   this_max = insn_needs_for_outputs[i];
-                 if (insn_needs_for_operands[i] > this_max)
-                   this_max = insn_needs_for_operands[i];
-                 insn_needs[i] += this_max;
-                 this_max = insn_groups_for_inputs[i];
-                 if (insn_groups_for_outputs[i] > this_max)
-                   this_max = insn_groups_for_outputs[i];
-                 if (insn_groups_for_operands[i] > this_max)
-                   this_max = insn_groups_for_operands[i];
-                 insn_groups[i] += this_max;
+                 int in_max, out_max;
+
+                 for (in_max = 0, out_max = 0, j = 0;
+                      j < reload_n_operands; j++)
+                   {
+                     in_max = MAX (in_max, insn_needs_for_in_addr[j][i]);
+                     out_max = MAX (out_max, insn_needs_for_out_addr[j][i]);
+                   }
+
+                 /* RELOAD_FOR_INSN reloads conflict with inputs, outputs,
+                    and operand addresses but not things used to reload them.
+                    Similarly, RELOAD_FOR_OPERAND_ADDRESS reloads don't
+                    conflict with things needed to reload inputs or
+                    outputs. */
+
+                 in_max = MAX (in_max, insn_needs_for_op_addr[i]);
+                 out_max = MAX (out_max, insn_needs_for_insn[i]);
+
+                 insn_needs_for_inputs[i]
+                   = MAX (insn_needs_for_inputs[i]
+                          + insn_needs_for_op_addr[i]
+                          + insn_needs_for_insn[i],
+                          in_max + insn_needs_for_inputs[i]);
+
+                 insn_needs_for_outputs[i] += out_max;
+                 insn_needs[i] += MAX (MAX (insn_needs_for_inputs[i],
+                                            insn_needs_for_outputs[i]),
+                                       insn_needs_for_other_addr[i]);
+
+                 for (in_max = 0, out_max = 0, j = 0;
+                      j < reload_n_operands; j++)
+                   {
+                     in_max = MAX (in_max, insn_groups_for_in_addr[j][i]);
+                     out_max = MAX (out_max, insn_groups_for_out_addr[j][i]);
+                   }
+
+                 in_max = MAX (in_max, insn_groups_for_op_addr[i]);
+                 out_max = MAX (out_max, insn_groups_for_insn[i]);
+
+                 insn_groups_for_inputs[i]
+                   = MAX (insn_groups_for_inputs[i]
+                          + insn_groups_for_op_addr[i]
+                          + insn_groups_for_insn[i],
+                          in_max + insn_groups_for_inputs[i]);
+
+                 insn_groups_for_outputs[i] += out_max;
+                 insn_groups[i] += MAX (MAX (insn_groups_for_inputs[i],
+                                             insn_groups_for_outputs[i]),
+                                        insn_groups_for_other_addr[i]);
+               }
+
+             for (i = 0; i < reload_n_operands; i++)
+               {
+                 max_total_input_groups
+                   = MAX (max_total_input_groups,
+                          insn_total_groups_for_in_addr[i]);
+                 max_total_output_groups
+                   = MAX (max_total_output_groups,
+                          insn_total_groups_for_out_addr[i]);
                }
 
-             insn_total_groups += MAX (insn_total_groups_for_inputs,
-                                       MAX (insn_total_groups_for_outputs,
-                                            insn_total_groups_for_operands));
+             max_total_input_groups = MAX (max_total_input_groups,
+                                           insn_total_groups_for_op_addr);
+             max_total_output_groups = MAX (max_total_output_groups,
+                                            insn_total_groups_for_insn);
+
+             insn_total_groups_for_inputs
+               = MAX (max_total_input_groups + insn_total_groups_for_op_addr
+                      + insn_total_groups_for_insn,
+                      max_total_input_groups + insn_total_groups_for_inputs);
+
+             insn_total_groups_for_outputs += max_total_output_groups;
+
+             insn_total_groups += MAX (MAX (insn_total_groups_for_outputs,
+                                            insn_total_groups_for_inputs),
+                                       insn_total_groups_for_other_addr);
 
              /* If this is a CALL_INSN and caller-saves will need
                 a spill register, act as if the spill register is
@@ -1188,7 +1320,7 @@ reload (first, global, dumpfile)
                 of that class should be quite rare.
 
                 If a group is needed, the size and mode of the group will
-                have been set up at the begining of this loop.  */
+                have been set up at the beginning of this loop.  */
 
              if (GET_CODE (insn) == CALL_INSN
                  && caller_save_spill_class != NO_REGS)
@@ -1209,17 +1341,20 @@ reload (first, global, dumpfile)
 
                  if (caller_save_group_size > 1)
                    insn_total_groups = MAX (insn_total_groups, 1);
-               }
 
-             /* Update the basic block needs.  */
 
-             for (i = 0; i < N_REG_CLASSES; i++)
-               if (global && (insn_needs[i] || insn_groups[i])
-                   && ! basic_block_needs[i][this_block])
-                 {
-                   new_basic_block_needs = 1;
-                   basic_block_needs[i][this_block] = 1;
-                 }
+                /* Show that this basic block will need a register of
+                   this class.  */
+
+                if (global
+                    && ! (basic_block_needs[(int) caller_save_spill_class]
+                          [this_block]))
+                  {
+                    basic_block_needs[(int) caller_save_spill_class]
+                      [this_block] = 1;
+                    new_basic_block_needs = 1;
+                  }
+               }
 
 #ifdef SMALL_REGISTER_CLASSES
              /* If this insn stores the value of a function call,
@@ -1235,20 +1370,53 @@ reload (first, global, dumpfile)
                  int nregs
                    = HARD_REGNO_NREGS (regno, GET_MODE (avoid_return_reg));
                  int r;
-                 int inc_groups = 0;
+                 int basic_needs[N_REG_CLASSES], basic_groups[N_REG_CLASSES];
+
+                 /* First compute the "basic needs", which counts a
+                    need only in the smallest class in which it
+                    is required.  */
+
+                 bcopy (insn_needs, basic_needs, sizeof basic_needs);
+                 bcopy (insn_groups, basic_groups, sizeof basic_groups);
+
+                 for (i = 0; i < N_REG_CLASSES; i++)
+                   {
+                     enum reg_class *p;
+
+                     if (basic_needs[i] >= 0)
+                       for (p = reg_class_superclasses[i];
+                            *p != LIM_REG_CLASSES; p++)
+                         basic_needs[(int) *p] -= basic_needs[i];
+
+                     if (basic_groups[i] >= 0)
+                       for (p = reg_class_superclasses[i];
+                            *p != LIM_REG_CLASSES; p++)
+                         basic_groups[(int) *p] -= basic_groups[i];
+                   }
+
+                 /* Now count extra regs if there might be a conflict with
+                    the return value register.
+
+                    ??? This is not quite correct because we don't properly
+                    handle the case of groups, but if we end up doing
+                    something wrong, it either will end up not mattering or
+                    we will abort elsewhere.  */
+                  
                  for (r = regno; r < regno + nregs; r++)
                    if (spill_reg_order[r] >= 0)
                      for (i = 0; i < N_REG_CLASSES; i++)
                        if (TEST_HARD_REG_BIT (reg_class_contents[i], r))
                          {
-                           if (insn_needs[i] > 0)
-                             insn_needs[i]++;
-                           if (insn_groups[i] > 0
-                               && nregs > 1)
-                             inc_groups = 1;
+                           if (basic_needs[i] > 0 || basic_groups[i] > 0)
+                             {
+                               enum reg_class *p;
+
+                               insn_needs[i]++;
+                               p = reg_class_superclasses[i];
+                               while (*p != LIM_REG_CLASSES)
+                                 insn_needs[(int) *p++]++;
+                             }
                          }
-                 if (inc_groups)
-                   insn_groups[i]++;
                }
 #endif /* SMALL_REGISTER_CLASSES */
 
@@ -1257,17 +1425,52 @@ reload (first, global, dumpfile)
              for (i = 0; i < N_REG_CLASSES; i++)
                {
                  if (max_needs[i] < insn_needs[i])
-                   max_needs[i] = insn_needs[i];
+                   {
+                     max_needs[i] = insn_needs[i];
+                     max_needs_insn[i] = insn;
+                   }
                  if (max_groups[i] < insn_groups[i])
-                   max_groups[i] = insn_groups[i];
+                   {
+                     max_groups[i] = insn_groups[i];
+                     max_groups_insn[i] = insn;
+                   }
                  if (insn_total_groups > 0)
                    if (max_nongroups[i] < insn_needs[i])
-                     max_nongroups[i] = insn_needs[i];
+                     {
+                       max_nongroups[i] = insn_needs[i];
+                       max_nongroups_insn[i] = insn;
+                     }
                }
            }
          /* Note that there is a continue statement above.  */
        }
 
+      /* If we allocated any new memory locations, make another pass
+        since it might have changed elimination offsets.  */
+      if (starting_frame_size != get_frame_size ())
+       something_changed = 1;
+
+      if (dumpfile)
+       for (i = 0; i < N_REG_CLASSES; i++)
+         {
+           if (max_needs[i] > 0)
+             fprintf (dumpfile,
+                        ";; Need %d reg%s of class %s (for insn %d).\n",
+                      max_needs[i], max_needs[i] == 1 ? "" : "s",
+                      reg_class_names[i], INSN_UID (max_needs_insn[i]));
+           if (max_nongroups[i] > 0)
+             fprintf (dumpfile,
+                      ";; Need %d nongroup reg%s of class %s (for insn %d).\n",
+                      max_nongroups[i], max_nongroups[i] == 1 ? "" : "s",
+                      reg_class_names[i], INSN_UID (max_nongroups_insn[i]));
+           if (max_groups[i] > 0)
+             fprintf (dumpfile,
+                      ";; Need %d group%s (%smode) of class %s (for insn %d).\n",
+                      max_groups[i], max_groups[i] == 1 ? "" : "s",
+                      mode_name[(int) group_mode[i]],
+                      reg_class_names[i], INSN_UID (max_groups_insn[i]));
+         }
+                        
       /* If we have caller-saves, set up the save areas and see if caller-save
         will need a spill register.  */
 
@@ -1286,86 +1489,19 @@ reload (first, global, dumpfile)
          something_changed = 1;
        }
 
-      /* Now deduct from the needs for the registers already
-        available (already spilled).  */
-
-      CLEAR_HARD_REG_SET (counted_for_groups);
-      CLEAR_HARD_REG_SET (counted_for_nongroups);
-
-      /* First find all regs alone in their class
-        and count them (if desired) for non-groups.
-        We would be screwed if a group took the only reg in a class
-        for which a non-group reload is needed.
-        (Note there is still a bug; if a class has 2 regs,
-        both could be stolen by groups and we would lose the same way.
-        With luck, no machine will need a nongroup in a 2-reg class.)  */
-
-      for (i = 0; i < n_spills; i++)
-       {
-         register enum reg_class *p;
-         class = (int) REGNO_REG_CLASS (spill_regs[i]);
-
-         if (reg_class_size[class] == 1 && max_nongroups[class] > 0)
-           {
-             max_needs[class]--;
-             p = reg_class_superclasses[class];
-             while (*p != LIM_REG_CLASSES)
-               max_needs[(int) *p++]--;
-
-             SET_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]);
-             max_nongroups[class]--;
-             p = reg_class_superclasses[class];
-             while (*p != LIM_REG_CLASSES)
-               {
-                 if (max_nongroups[(int) *p] > 0)
-                   SET_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]);
-                 max_nongroups[(int) *p++]--;
-               }
-           }
-       }
-
-      /* Now find all consecutive groups of spilled registers
-        and mark each group off against the need for such groups.
-        But don't count them against ordinary need, yet.  */
-
-      count_possible_groups (group_size, group_mode, max_groups);
-
-      /* Now count all spill regs against the individual need,
-        This includes those counted above for groups,
-        but not those previously counted for nongroups.
-
-        Those that weren't counted_for_groups can also count against
-        the not-in-group need.  */
-
-      for (i = 0; i < n_spills; i++)
-       {
-         register enum reg_class *p;
-         class = (int) REGNO_REG_CLASS (spill_regs[i]);
-
-         /* Those counted at the beginning shouldn't be counted twice.  */
-         if (! TEST_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]))
-           {
-             max_needs[class]--;
-             p = reg_class_superclasses[class];
-             while (*p != LIM_REG_CLASSES)
-               max_needs[(int) *p++]--;
+      /* See if anything that happened changes which eliminations are valid.
+        For example, on the Sparc, whether or not the frame pointer can
+        be eliminated can depend on what registers have been used.  We need
+        not check some conditions again (such as flag_omit_frame_pointer)
+        since they can't have changed.  */
 
-             if (! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[i]))
-               {
-                 if (max_nongroups[class] > 0)
-                   SET_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]);
-                 max_nongroups[class]--;
-                 p = reg_class_superclasses[class];
-                 while (*p != LIM_REG_CLASSES)
-                   {
-                     if (max_nongroups[(int) *p] > 0)
-                       SET_HARD_REG_BIT (counted_for_nongroups,
-                                         spill_regs[i]);
-                     max_nongroups[(int) *p++]--;
-                   }
-               }
-           }
-       }
+      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+       if ((ep->from == FRAME_POINTER_REGNUM && FRAME_POINTER_REQUIRED)
+#ifdef ELIMINABLE_REGS
+           || ! CAN_ELIMINATE (ep->from, ep->to)
+#endif
+           )
+         ep->can_eliminate = 0;
 
       /* Look for the case where we have discovered that we can't replace
         register A with register B and that means that we will now be
@@ -1430,16 +1566,44 @@ reload (first, global, dumpfile)
       if (i == N_REG_CLASSES && !new_basic_block_needs && ! something_changed)
        break;
 
-      /* Not all needs are met; must spill more hard regs.  */
+      /* Not all needs are met; must spill some hard regs.  */
+
+      /* Put all registers spilled so far back in potential_reload_regs, but
+        put them at the front, since we've already spilled most of the
+        psuedos in them (we might have left some pseudos unspilled if they
+        were in a block that didn't need any spill registers of a conflicting
+        class.  We used to try to mark off the need for those registers,
+        but doing so properly is very complex and reallocating them is the
+        simpler approach.  First, "pack" potential_reload_regs by pushing 
+        any nonnegative entries towards the end.  That will leave room 
+        for the registers we already spilled.
+
+        Also, undo the marking of the spill registers from the last time
+        around in FORBIDDEN_REGS since we will be probably be allocating
+        them again below.
+
+        ??? It is theoretically possible that we might end up not using one
+        of our previously-spilled registers in this allocation, even though
+        they are at the head of the list.  It's not clear what to do about
+        this, but it was no better before, when we marked off the needs met
+        by the previously-spilled registers.  With the current code, globals
+        can be allocated into these registers, but locals cannot.  */
+
+      if (n_spills)
+       {
+         for (i = j = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
+           if (potential_reload_regs[i] != -1)
+             potential_reload_regs[j--] = potential_reload_regs[i];
 
-      /* If any element of basic_block_needs changed from 0 to 1,
-        re-spill all the regs already spilled.  This may spill
-        additional pseudos that didn't spill before.  */
+         for (i = 0; i < n_spills; i++)
+           {
+             potential_reload_regs[i] = spill_regs[i];
+             spill_reg_order[spill_regs[i]] = -1;
+             CLEAR_HARD_REG_BIT (forbidden_regs, spill_regs[i]);
+           }
 
-      if (new_basic_block_needs)
-       for (i = 0; i < n_spills; i++)
-         something_changed
-           |= spill_hard_reg (spill_regs[i], global, dumpfile, 0);
+         n_spills = 0;
+       }
 
       /* Now find more reload regs to satisfy the remaining need
         Do it by ascending class number, since otherwise a reg
@@ -1463,6 +1627,9 @@ reload (first, global, dumpfile)
         in counting the regs already spilled, and in choose_reload_regs.
         It might be hard to avoid introducing bugs there.  */
 
+      CLEAR_HARD_REG_SET (counted_for_groups);
+      CLEAR_HARD_REG_SET (counted_for_nongroups);
+
       for (class = 0; class < N_REG_CLASSES; class++)
        {
          /* First get the groups of registers.
@@ -1475,6 +1642,9 @@ reload (first, global, dumpfile)
                 to spill another group.  */
              count_possible_groups (group_size, group_mode, max_groups);
 
+             if (max_groups[class] <= 0)
+               break;
+
              /* Groups of size 2 (the only groups used on most machines)
                 are treated specially.  */
              if (group_size[class] == 2)
@@ -1482,8 +1652,9 @@ reload (first, global, dumpfile)
                  /* First, look for a register that will complete a group.  */
                  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                    {
-                     int j = potential_reload_regs[i];
                      int other;
+
+                     j = potential_reload_regs[i];
                      if (j >= 0 && ! TEST_HARD_REG_BIT (bad_spill_regs, j)
                          &&
                          ((j > 0 && (other = j - 1, spill_reg_order[other] >= 0)
@@ -1525,23 +1696,38 @@ reload (first, global, dumpfile)
                  if (i == FIRST_PSEUDO_REGISTER)
                    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                      {
-                       int j = potential_reload_regs[i];
+                       int k;
+                       j = potential_reload_regs[i];
+                       /* Verify that J+1 is a potential reload reg.  */
+                       for (k = 0; k < FIRST_PSEUDO_REGISTER; k++)
+                         if (potential_reload_regs[k] == j + 1)
+                           break;
                        if (j >= 0 && j + 1 < FIRST_PSEUDO_REGISTER
+                           && k < FIRST_PSEUDO_REGISTER
                            && spill_reg_order[j] < 0 && spill_reg_order[j + 1] < 0
                            && TEST_HARD_REG_BIT (reg_class_contents[class], j)
                            && TEST_HARD_REG_BIT (reg_class_contents[class], j + 1)
                            && HARD_REGNO_MODE_OK (j, group_mode[class])
                            && ! TEST_HARD_REG_BIT (counted_for_nongroups,
-                                                   j + 1))
+                                                   j + 1)
+                           && ! TEST_HARD_REG_BIT (bad_spill_regs, j + 1))
                          break;
                      }
 
                  /* I should be the index in potential_reload_regs
                     of the new reload reg we have found.  */
 
-                 something_changed
-                   |= new_spill_reg (i, class, max_needs, 0,
-                                     global, dumpfile);
+                 if (i >= FIRST_PSEUDO_REGISTER)
+                   {
+                     /* There are no groups left to spill.  */
+                     spill_failure (max_groups_insn[class]);
+                     failure = 1;
+                     goto failed;
+                   }
+                 else
+                   something_changed
+                     |= new_spill_reg (i, class, max_needs, NULL_PTR,
+                                       global, dumpfile);
                }
              else
                {
@@ -1550,9 +1736,11 @@ reload (first, global, dumpfile)
                     and spill them all at once.  */
                  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                    {
-                     int j = potential_reload_regs[i];
                      int k;
-                     if (j >= 0 && j + 1 < FIRST_PSEUDO_REGISTER
+
+                     j = potential_reload_regs[i];
+                     if (j >= 0
+                         && j + group_size[class] <= FIRST_PSEUDO_REGISTER
                          && HARD_REGNO_MODE_OK (j, group_mode[class]))
                        {
                          /* Check each reg in the sequence.  */
@@ -1573,7 +1761,8 @@ reload (first, global, dumpfile)
                                    if (potential_reload_regs[idx] == j + k)
                                      break;
                                  something_changed
-                                   |= new_spill_reg (idx, class, max_needs, 0,
+                                   |= new_spill_reg (idx, class,
+                                                     max_needs, NULL_PTR,
                                                      global, dumpfile);
                                }
 
@@ -1588,6 +1777,15 @@ reload (first, global, dumpfile)
                            }
                        }
                    }
+                 /* We couldn't find any registers for this reload.
+                    Avoid going into an infinite loop.  */
+                 if (i >= FIRST_PSEUDO_REGISTER)
+                   {
+                     /* There are no groups left.  */
+                     spill_failure (max_groups_insn[class]);
+                     failure = 1;
+                     goto failed;
+                   }
                }
            }
 
@@ -1595,6 +1793,35 @@ reload (first, global, dumpfile)
 
          while (max_needs[class] > 0 || max_nongroups[class] > 0)
            {
+#ifdef SMALL_REGISTER_CLASSES
+             /* This should be right for all machines, but only the 386
+                is known to need it, so this conditional plays safe.
+                ??? For 2.5, try making this unconditional.  */
+             /* If we spilled enough regs, but they weren't counted
+                against the non-group need, see if we can count them now.
+                If so, we can avoid some actual spilling.  */
+             if (max_needs[class] <= 0 && max_nongroups[class] > 0)
+               for (i = 0; i < n_spills; i++)
+                 if (TEST_HARD_REG_BIT (reg_class_contents[class],
+                                        spill_regs[i])
+                     && !TEST_HARD_REG_BIT (counted_for_groups,
+                                            spill_regs[i])
+                     && !TEST_HARD_REG_BIT (counted_for_nongroups,
+                                            spill_regs[i])
+                     && max_nongroups[class] > 0)
+                   {
+                     register enum reg_class *p;
+
+                     SET_HARD_REG_BIT (counted_for_nongroups, spill_regs[i]);
+                     max_nongroups[class]--;
+                     p = reg_class_superclasses[class];
+                     while (*p != LIM_REG_CLASSES)
+                       max_nongroups[(int) *p++]--;
+                   }
+             if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
+               break;
+#endif
+
              /* Consider the potential reload regs that aren't
                 yet in use as reload regs, in order of preference.
                 Find the most preferred one that's in this class.  */
@@ -1613,12 +1840,38 @@ reload (first, global, dumpfile)
                        || possible_group_p (potential_reload_regs[i], max_groups)))
                  break;
 
+             /* If we couldn't get a register, try to get one even if we
+                might foreclose possible groups.  This may cause problems
+                later, but that's better than aborting now, since it is
+                possible that we will, in fact, be able to form the needed
+                group even with this allocation.  */
+
+             if (i >= FIRST_PSEUDO_REGISTER
+                 && (asm_noperands (max_needs[class] > 0
+                                    ? max_needs_insn[class]
+                                    : max_nongroups_insn[class])
+                     < 0))
+               for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+                 if (potential_reload_regs[i] >= 0
+                     && TEST_HARD_REG_BIT (reg_class_contents[class],
+                                           potential_reload_regs[i]))
+                   break;
+
              /* I should be the index in potential_reload_regs
                 of the new reload reg we have found.  */
 
-             something_changed
-               |= new_spill_reg (i, class, max_needs, max_nongroups,
-                                 global, dumpfile);
+             if (i >= FIRST_PSEUDO_REGISTER)
+               {
+                 /* There are no possible registers left to spill.  */
+                 spill_failure (max_needs[class] > 0 ? max_needs_insn[class]
+                                : max_nongroups_insn[class]);
+                 failure = 1;
+                 goto failed;
+               }
+             else
+               something_changed
+                 |= new_spill_reg (i, class, max_needs, max_nongroups,
+                                   global, dumpfile);
            }
        }
     }
@@ -1630,9 +1883,6 @@ reload (first, global, dumpfile)
       if (ep->can_eliminate)
        mark_elimination (ep->from, ep->to);
 
-  /* From now on, we need to emit any moves without making new pseudos.  */
-  reload_in_progress = 1;
-
   /* Insert code to save and restore call-clobbered hard regs
      around calls.  Tell if what mode to use so that we will process
      those insns in reload_as_needed if we have to.  */
@@ -1672,6 +1922,21 @@ reload (first, global, dumpfile)
       || caller_save_spill_class != NO_REGS)
     reload_as_needed (first, global);
 
+  /* If we were able to eliminate the frame pointer, show that it is no
+     longer live at the start of any basic block.  If it ls live by
+     virtue of being in a pseudo, that pseudo will be marked live
+     and hence the frame pointer will be known to be live via that
+     pseudo.  */
+
+  if (! frame_pointer_needed)
+    for (i = 0; i < n_basic_blocks; i++)
+      basic_block_live_at_start[i][FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
+       &= ~ ((REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS));
+
+  /* Come here (with failure set nonzero) if we can't get enough spill regs
+     and we decide not to abort about it.  */
+ failed:
+
   reload_in_progress = 0;
 
   /* Now eliminate all pseudo regs by modifying them into
@@ -1687,8 +1952,12 @@ reload (first, global, dumpfile)
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     {
       rtx addr = 0;
+      int in_struct = 0;
       if (reg_equiv_mem[i])
-       addr = XEXP (reg_equiv_mem[i], 0);
+       {
+         addr = XEXP (reg_equiv_mem[i], 0);
+         in_struct = MEM_IN_STRUCT_P (reg_equiv_mem[i]);
+       }
       if (reg_equiv_address[i])
        addr = reg_equiv_address[i];
       if (addr)
@@ -1698,6 +1967,7 @@ reload (first, global, dumpfile)
              rtx reg = regno_reg_rtx[i];
              XEXP (reg, 0) = addr;
              REG_USERVAR_P (reg) = 0;
+             MEM_IN_STRUCT_P (reg) = in_struct;
              PUT_CODE (reg, MEM);
            }
          else if (reg_equiv_mem[i])
@@ -1729,6 +1999,13 @@ reload (first, global, dumpfile)
   /* Indicate that we no longer have known memory locations or constants.  */
   reg_equiv_constant = 0;
   reg_equiv_memory_loc = 0;
+
+  free (scratch_list);
+  scratch_list = 0;
+  free (scratch_block);
+  scratch_block = 0;
+
+  return failure;
 }
 \f
 /* Nonzero if, after spilling reg REGNO for non-groups,
@@ -1797,8 +2074,9 @@ possible_group_p (regno, max_groups)
 
 static void
 count_possible_groups (group_size, group_mode, max_groups)
-     int *group_size, *max_groups;
+     int *group_size;
      enum machine_mode *group_mode;
+     int *max_groups;
 {
   int i;
   /* Now find all consecutive groups of spilled registers
@@ -1808,27 +2086,30 @@ count_possible_groups (group_size, group_mode, max_groups)
   for (i = 0; i < N_REG_CLASSES; i++)
     if (group_size[i] > 1)
       {
-       char regmask[FIRST_PSEUDO_REGISTER];
+       HARD_REG_SET new;
        int j;
 
-       bzero (regmask, sizeof regmask);
+       CLEAR_HARD_REG_SET (new);
+
        /* Make a mask of all the regs that are spill regs in class I.  */
        for (j = 0; j < n_spills; j++)
          if (TEST_HARD_REG_BIT (reg_class_contents[i], spill_regs[j])
              && ! TEST_HARD_REG_BIT (counted_for_groups, spill_regs[j])
              && ! TEST_HARD_REG_BIT (counted_for_nongroups,
                                      spill_regs[j]))
-           regmask[spill_regs[j]] = 1;
+           SET_HARD_REG_BIT (new, spill_regs[j]);
+
        /* Find each consecutive group of them.  */
        for (j = 0; j < FIRST_PSEUDO_REGISTER && max_groups[i] > 0; j++)
-         if (regmask[j] && j + group_size[i] <= FIRST_PSEUDO_REGISTER
+         if (TEST_HARD_REG_BIT (new, j)
+             && j + group_size[i] <= FIRST_PSEUDO_REGISTER
              /* Next line in case group-mode for this class
                 demands an even-odd pair.  */
              && HARD_REGNO_MODE_OK (j, group_mode[i]))
            {
              int k;
              for (k = 1; k < group_size[i]; k++)
-               if (! regmask[j + k])
+               if (! TEST_HARD_REG_BIT (new, j + k))
                  break;
              if (k == group_size[i])
                {
@@ -1843,7 +2124,10 @@ count_possible_groups (group_size, group_mode, max_groups)
                  for (k = 0; k < group_size[i]; k++)
                    SET_HARD_REG_BIT (counted_for_groups, j + k);
                }
-             j += k;
+             /* Skip to the last reg in this group.  When j is incremented
+                above, it will then point to the first reg of the next
+                possible group.  */
+             j += k - 1;
            }
       }
 
@@ -1877,6 +2161,19 @@ modes_equiv_for_class_p (allocate_mode, other_mode, class)
   return 1;
 }
 
+/* Handle the failure to find a register to spill.
+   INSN should be one of the insns which needed this particular spill reg.  */
+
+static void
+spill_failure (insn)
+     rtx insn;
+{
+  if (asm_noperands (PATTERN (insn)) >= 0)
+    error_for_asm (insn, "`asm' needs too many reloads");
+  else
+    abort ();
+}
+
 /* Add a new register to the tables of available spill-registers
     (as well as spilling all pseudos allocated to the register).
    I is the index of this register in potential_reload_regs.
@@ -2110,6 +2407,20 @@ mark_home_live (regno)
   while (i < lim)
     regs_ever_live[i++] = 1;
 }
+
+/* Mark the registers used in SCRATCH as being live.  */
+
+static void
+mark_scratch_live (scratch)
+     rtx scratch;
+{
+  register int i;
+  int regno = REGNO (scratch);
+  int lim = regno + HARD_REGNO_NREGS (regno, GET_MODE (scratch));
+
+  for (i = regno; i < lim; i++)
+    regs_ever_live[i] = 1;
+}
 \f
 /* This function handles the tracking of elimination offsets around branches.
 
@@ -2135,6 +2446,9 @@ set_label_offsets (x, insn, initial_p)
   switch (code)
     {
     case LABEL_REF:
+      if (LABEL_REF_NONLOCAL_P (x))
+       return;
+
       x = XEXP (x, 0);
 
       /* ... fall through ... */
@@ -2157,7 +2471,7 @@ set_label_offsets (x, insn, initial_p)
        }
 
       /* Otherwise, if this is the definition of a label and it is
-        preceeded by a BARRIER, set our offsets to the known offset of
+        preceded by a BARRIER, set our offsets to the known offset of
         that label.  */
 
       else if (x == insn
@@ -2169,7 +2483,9 @@ set_label_offsets (x, insn, initial_p)
            {
              reg_eliminate[i].offset = reg_eliminate[i].previous_offset
                = offsets_at[CODE_LABEL_NUMBER (x)][i];
-             if (reg_eliminate[i].offset != reg_eliminate[i].initial_offset)
+             if (reg_eliminate[i].can_eliminate
+                 && (reg_eliminate[i].offset
+                     != reg_eliminate[i].initial_offset))
                num_not_at_initial_offset++;
            }
        }
@@ -2346,9 +2662,13 @@ eliminate_regs (x, mem_mode, insn)
             elimination) and ignore the fact that this is actually a
             reference to the pseudo.  Ensure we make a copy of the
             address in case it is shared.  */
-         new = eliminate_regs (reg_equiv_memory_loc[regno], mem_mode, 0);
+         new = eliminate_regs (reg_equiv_memory_loc[regno],
+                               mem_mode, NULL_RTX);
          if (new != reg_equiv_memory_loc[regno])
-           return copy_rtx (new);
+           {
+             cannot_omit_stores[regno] = 1;
+             return copy_rtx (new);
+           }
        }
       return x;
 
@@ -2374,7 +2694,7 @@ eliminate_regs (x, mem_mode, insn)
                   We special-case the commonest situation in
                   eliminate_regs_in_insn, so just replace a PLUS with a
                   PLUS here, unless inside a MEM.  */
-               if (mem_mode && GET_CODE (XEXP (x, 1)) == CONST_INT
+               if (mem_mode != 0 && GET_CODE (XEXP (x, 1)) == CONST_INT
                    && INTVAL (XEXP (x, 1)) == - ep->previous_offset)
                  return ep->to_rtx;
                else
@@ -2402,8 +2722,8 @@ eliminate_regs (x, mem_mode, insn)
         reload.  This is the desired action.  */
 
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, 0);
-       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, 0);
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, NULL_RTX);
+       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, NULL_RTX);
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          {
@@ -2440,7 +2760,7 @@ eliminate_regs (x, mem_mode, insn)
       /* If we have something in XEXP (x, 0), the usual case, eliminate it.  */
       if (XEXP (x, 0))
        {
-         new = eliminate_regs (XEXP (x, 0), mem_mode, 0);
+         new = eliminate_regs (XEXP (x, 0), mem_mode, NULL_RTX);
          if (new != XEXP (x, 0))
            x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1));
        }
@@ -2453,7 +2773,7 @@ eliminate_regs (x, mem_mode, insn)
         strictly needed, but it simplifies the code.  */
       if (XEXP (x, 1))
        {
-         new = eliminate_regs (XEXP (x, 1), mem_mode, 0);
+         new = eliminate_regs (XEXP (x, 1), mem_mode, NULL_RTX);
          if (new != XEXP (x, 1))
            return gen_rtx (INSN_LIST, GET_MODE (x), XEXP (x, 0), new);
        }
@@ -2472,8 +2792,9 @@ eliminate_regs (x, mem_mode, insn)
     case GE:       case GT:       case GEU:    case GTU:
     case LE:       case LT:       case LEU:    case LTU:
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, 0);
-       rtx new1 = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, 0) : 0;
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, NULL_RTX);
+       rtx new1
+         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, NULL_RTX) : 0;
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          return gen_rtx (code, GET_MODE (x), new0, new1);
@@ -2487,10 +2808,17 @@ eliminate_regs (x, mem_mode, insn)
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
        if (ep->to_rtx == XEXP (x, 0))
          {
+           int size = GET_MODE_SIZE (mem_mode);
+
+           /* If more bytes than MEM_MODE are pushed, account for them.  */
+#ifdef PUSH_ROUNDING
+           if (ep->to_rtx == stack_pointer_rtx)
+             size = PUSH_ROUNDING (size);
+#endif
            if (code == PRE_DEC || code == POST_DEC)
-             ep->offset += GET_MODE_SIZE (mem_mode);
+             ep->offset += size;
            else
-             ep->offset -= GET_MODE_SIZE (mem_mode);
+             ep->offset -= size;
          }
 
       /* Fall through to generic unary operation case.  */
@@ -2504,7 +2832,7 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
-      new = eliminate_regs (XEXP (x, 0), mem_mode, 0);
+      new = eliminate_regs (XEXP (x, 0), mem_mode, NULL_RTX);
       if (new != XEXP (x, 0))
        return gen_rtx (code, GET_MODE (x), new);
       return x;
@@ -2523,7 +2851,7 @@ eliminate_regs (x, mem_mode, insn)
          && reg_equiv_memory_loc[REGNO (SUBREG_REG (x))] != 0)
        {
          new = eliminate_regs (reg_equiv_memory_loc[REGNO (SUBREG_REG (x))],
-                               mem_mode, 0);
+                               mem_mode, NULL_RTX);
 
          /* If we didn't change anything, we must retain the pseudo.  */
          if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))])
@@ -2534,13 +2862,23 @@ eliminate_regs (x, mem_mode, insn)
            new = copy_rtx (new);
        }
       else
-       new = eliminate_regs (SUBREG_REG (x), mem_mode, 0);
+       new = eliminate_regs (SUBREG_REG (x), mem_mode, NULL_RTX);
 
       if (new != XEXP (x, 0))
        {
          if (GET_CODE (new) == MEM
              && (GET_MODE_SIZE (GET_MODE (x))
-                 <= GET_MODE_SIZE (GET_MODE (new))))
+                 <= GET_MODE_SIZE (GET_MODE (new)))
+#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+             /* On these machines we will be reloading what is
+                inside the SUBREG if it originally was a pseudo and
+                the inner and outer modes are both a word or
+                smaller.  So leave the SUBREG then.  */
+             && ! (GET_CODE (SUBREG_REG (x)) == REG
+                   && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+                   && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD)
+#endif
+             )
            {
              int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
              enum machine_mode mode = GET_MODE (x);
@@ -2563,12 +2901,15 @@ eliminate_regs (x, mem_mode, insn)
 
     case CLOBBER:
       /* If clobbering a register that is the replacement register for an
-        elimination we still think can be peformed, note that it cannot
+        elimination we still think can be performed, note that it cannot
         be performed.  Otherwise, we need not be concerned about it.  */
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
        if (ep->to_rtx == XEXP (x, 0))
          ep->can_eliminate = 0;
 
+      new = eliminate_regs (XEXP (x, 0), mem_mode, NULL_RTX);
+      if (new != XEXP (x, 0))
+       return gen_rtx (code, GET_MODE (x), new);
       return x;
 
     case ASM_OPERANDS:
@@ -2584,7 +2925,7 @@ eliminate_regs (x, mem_mode, insn)
            temp_vec = (rtx *) alloca (XVECLEN (x, 3) * sizeof (rtx));
            for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
              temp_vec[i] = eliminate_regs (ASM_OPERANDS_INPUT (x, i),
-                                           mem_mode, 0);
+                                           mem_mode, NULL_RTX);
 
            for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
              if (temp_vec[i] != ASM_OPERANDS_INPUT (x, i))
@@ -2630,7 +2971,7 @@ eliminate_regs (x, mem_mode, insn)
            if (ep->to_rtx == SET_DEST (x)
                && SET_DEST (x) != frame_pointer_rtx)
              {
-               /* If it is being incrememented, adjust the offset.  Otherwise,
+               /* If it is being incremented, adjust the offset.  Otherwise,
                   this elimination can't be done.  */
                rtx src = SET_SRC (x);
 
@@ -2654,8 +2995,8 @@ eliminate_regs (x, mem_mode, insn)
 
       /* Now avoid the loop below in this common case.  */
       {
-       rtx new0 = eliminate_regs (SET_DEST (x), 0, 0);
-       rtx new1 = eliminate_regs (SET_SRC (x), 0, 0);
+       rtx new0 = eliminate_regs (SET_DEST (x), 0, NULL_RTX);
+       rtx new1 = eliminate_regs (SET_SRC (x), 0, NULL_RTX);
 
        /* If SET_DEST changed from a REG to a MEM and INSN is non-zero,
           write a CLOBBER insn.  */
@@ -2673,7 +3014,7 @@ 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), 0);
+      new = eliminate_regs (XEXP (x, 0), GET_MODE (x), NULL_RTX);
       if (new != XEXP (x, 0))
        {
          new = gen_rtx (MEM, GET_MODE (x), new);
@@ -2693,7 +3034,7 @@ eliminate_regs (x, mem_mode, insn)
     {
       if (*fmt == 'e')
        {
-         new = eliminate_regs (XEXP (x, i), mem_mode, 0);
+         new = eliminate_regs (XEXP (x, i), mem_mode, NULL_RTX);
          if (new != XEXP (x, i) && ! copied)
            {
              rtx new_x = rtx_alloc (code);
@@ -2793,14 +3134,22 @@ eliminate_regs_in_insn (insn, replace)
        for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
             ep++)
          if (ep->from_rtx == XEXP (SET_SRC (old_body), 0)
-             && ep->can_eliminate
-             && ep->offset == - INTVAL (XEXP (SET_SRC (old_body), 1)))
+             && ep->can_eliminate)
            {
-             PATTERN (insn) = gen_rtx (SET, VOIDmode,
-                                       SET_DEST (old_body), ep->to_rtx);
-             INSN_CODE (insn) = -1;
-             val = 1;
-             goto done;
+             /* We must stop at the first elimination that will be used.
+                If this one would replace the PLUS with a REG, do it
+                now.  Otherwise, quit the loop and let eliminate_regs
+                do its normal replacement.  */
+             if (ep->offset == - INTVAL (XEXP (SET_SRC (old_body), 1)))
+               {
+                 PATTERN (insn) = gen_rtx (SET, VOIDmode,
+                                           SET_DEST (old_body), ep->to_rtx);
+                 INSN_CODE (insn) = -1;
+                 val = 1;
+                 goto done;
+               }
+
+             break;
            }
     }
 
@@ -2815,15 +3164,39 @@ eliminate_regs_in_insn (insn, replace)
      but now can do this as a load-address.  This saves an insn in this
      common case. */
 
-  new_body = eliminate_regs (old_body, 0, replace ? insn : 0);
+  new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX);
   if (new_body != old_body)
     {
-      if (GET_CODE (old_body) != SET || GET_CODE (SET_SRC (old_body)) != PLUS
-         || ! validate_change (insn, &PATTERN (insn), new_body, 0))
+      /* If we aren't replacing things permanently and we changed something,
+        make another copy to ensure that all the RTL is new.  Otherwise
+        things can go wrong if find_reload swaps commutative operands
+        and one is inside RTL that has been copied while the other is not. */
+
+      /* Don't copy an asm_operands because (1) there's no need and (2)
+        copy_rtx can't do it properly when there are multiple outputs.  */
+      if (! replace && asm_noperands (old_body) < 0)
+       new_body = copy_rtx (new_body);
+
+      /* If we had a move insn but now we don't, rerecognize it.  */
+      if ((GET_CODE (old_body) == SET && GET_CODE (SET_SRC (old_body)) == REG
+          && (GET_CODE (new_body) != SET
+              || GET_CODE (SET_SRC (new_body)) != REG))
+         /* If this was an add insn before, rerecognize.  */
+         ||
+         (GET_CODE (old_body) == SET
+          && GET_CODE (SET_SRC (old_body)) == PLUS))
+       {
+         if (! validate_change (insn, &PATTERN (insn), new_body, 0))
+           /* If recognition fails, store the new body anyway.
+              It's normal to have recognition failures here
+              due to bizarre memory addresses; reloading will fix them.  */
+           PATTERN (insn) = new_body;
+       }
+      else
        PATTERN (insn) = new_body;
 
       if (replace && REG_NOTES (insn))
-       REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, 0);
+       REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, NULL_RTX);
       val = 1;
     }
 
@@ -2933,6 +3306,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
      FILE *dumpfile;
      int cant_eliminate;
 {
+  enum reg_class class = REGNO_REG_CLASS (regno);
   int something_changed = 0;
   register int i;
 
@@ -2949,8 +3323,6 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
                                PSEUDO_REGNO_MODE (i))
            > regno))
       {
-       enum reg_class class = REGNO_REG_CLASS (regno);
-
        /* If this register belongs solely to a basic block which needed no
           spilling of any class that this register is contained in,
           leave it be, unless we are spilling this register because
@@ -2989,6 +3361,29 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
                       i, reg_renumber[i]);
          }
       }
+  for (i = 0; i < scratch_list_length; i++)
+    {
+      if (scratch_list[i] && REGNO (scratch_list[i]) == regno)
+       {
+         if (! cant_eliminate && basic_block_needs[0]
+             && ! basic_block_needs[(int) class][scratch_block[i]])
+           {
+             enum reg_class *p;
+
+             for (p = reg_class_superclasses[(int) class];
+                  *p != LIM_REG_CLASSES; p++)
+               if (basic_block_needs[(int) *p][scratch_block[i]] > 0)
+                 break;
+
+             if (*p == LIM_REG_CLASSES)
+               continue;
+           }
+         PUT_CODE (scratch_list[i], SCRATCH);
+         scratch_list[i] = 0;
+         something_changed = 1;
+         continue;
+       }
+    }
 
   return something_changed;
 }
@@ -3039,8 +3434,6 @@ scan_paradoxical_subregs (x)
     }
 }
 \f
-struct hard_reg_n_uses { int regno; int uses; };
-
 static int
 hard_reg_use_compare (p1, p2)
      struct hard_reg_n_uses *p1, *p2;
@@ -3105,12 +3498,14 @@ order_regs_for_reload ()
       else if (regs_explicitly_used[i])
        {
          hard_reg_n_uses[i].uses += large + 1;
+#ifndef SMALL_REGISTER_CLASSES
          /* ??? We are doing this here because of the potential that
             bad code may be generated if a register explicitly used in
             an insn was used as a spill register for that insn.  But
             not using these are spill registers may lose on some machine.
             We'll have to see how this works out.  */
          SET_HARD_REG_BIT (bad_spill_regs, i);
+#endif
        }
     }
   hard_reg_n_uses[FRAME_POINTER_REGNUM].uses += 2 * large + 2;
@@ -3168,7 +3563,7 @@ order_regs_for_reload ()
    and perhaps store insns after insns that modify the reloaded pseudo reg.
 
    reg_last_reload_reg and reg_reloaded_contents keep track of
-   which pseudo-registers are already available in reload registers.
+   which registers are already available in reload registers.
    We update these for the reloads that we perform,
    as the insns are scanned.  */
 
@@ -3198,7 +3593,7 @@ reload_as_needed (first, live_known)
   for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
     {
       INITIAL_ELIMINATION_OFFSET (reg_eliminate[i].from, reg_eliminate[i].to,
-                                 reg_eliminate[i].initial_offset)
+                                 reg_eliminate[i].initial_offset);
       reg_eliminate[i].previous_offset
        = reg_eliminate[i].offset = reg_eliminate[i].initial_offset;
     }
@@ -3215,7 +3610,7 @@ reload_as_needed (first, live_known)
       register rtx next = NEXT_INSN (insn);
 
       /* Notice when we move to a new basic block.  */
-      if (live_known && basic_block_needs && this_block + 1 < n_basic_blocks
+      if (live_known && this_block + 1 < n_basic_blocks
          && insn == basic_block_head[this_block+1])
        ++this_block;
 
@@ -3228,7 +3623,9 @@ reload_as_needed (first, live_known)
            {
              reg_eliminate[i].offset = reg_eliminate[i].previous_offset
                = offsets_at[CODE_LABEL_NUMBER (insn)][i];
-             if (reg_eliminate[i].offset != reg_eliminate[i].initial_offset)
+             if (reg_eliminate[i].can_eliminate
+                 && (reg_eliminate[i].offset
+                     != reg_eliminate[i].initial_offset))
                num_not_at_initial_offset++;
            }
        }
@@ -3260,6 +3657,16 @@ reload_as_needed (first, live_known)
            }
 #endif /* SMALL_REGISTER_CLASSES */
 
+         /* If this is a USE and CLOBBER of a MEM, ensure that any
+            references to eliminable registers have been removed.  */
+
+         if ((GET_CODE (PATTERN (insn)) == USE
+              || GET_CODE (PATTERN (insn)) == CLOBBER)
+             && GET_CODE (XEXP (PATTERN (insn), 0)) == MEM)
+           XEXP (XEXP (PATTERN (insn), 0), 0)
+             = eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0),
+                               GET_MODE (XEXP (PATTERN (insn), 0)), NULL_RTX);
+
          /* If we need to do register elimination processing, do so.
             This might delete the insn, in which case we are done.  */
          if (num_eliminable && GET_MODE (insn) == QImode)
@@ -3289,25 +3696,24 @@ reload_as_needed (first, live_known)
 
          if (n_reloads > 0)
            {
+             rtx prev = PREV_INSN (insn), next = NEXT_INSN (insn);
+             rtx p;
              int class;
 
              /* If this block has not had spilling done for a
-                particular class, deactivate any optional reloads
-                of that class lest they try to use a spill-reg which isn't
-                available here.  If we have any non-optionals that need a
-                spill reg, abort.  */
+                particular clas and we have any non-optionals that need a
+                spill reg in that class, abort.  */
 
              for (class = 0; class < N_REG_CLASSES; class++)
                if (basic_block_needs[class] != 0
                    && basic_block_needs[class][this_block] == 0)
                  for (i = 0; i < n_reloads; i++)
-                   if (class == (int) reload_reg_class[i])
-                     {
-                       if (reload_optional[i])
-                         reload_in[i] = reload_out[i] = reload_reg_rtx[i] = 0;
-                       else if (reload_reg_rtx[i] == 0)
-                         abort ();
-                     }
+                   if (class == (int) reload_reg_class[i]
+                       && reload_reg_rtx[i] == 0
+                       && ! reload_optional[i]
+                       && (reload_in[i] != 0 || reload_out[i] != 0
+                           || reload_secondary_p[i] != 0))
+                     abort ();
 
              /* Now compute which reload regs to reload them into.  Perhaps
                 reusing reload regs from previous insns, or else output
@@ -3315,6 +3721,13 @@ reload_as_needed (first, live_known)
                 Record the choices of reload reg in reload_reg_rtx.  */
              choose_reload_regs (insn, avoid_return_reg);
 
+#ifdef SMALL_REGISTER_CLASSES
+             /* Merge any reloads that we didn't combine for fear of 
+                increasing the number of spill registers needed but now
+                discover can be safely merged.  */
+             merge_assigned_reloads (insn);
+#endif
+
              /* Generate the insns to reload operands into or out of
                 their reload regs.  */
              emit_reload_insns (insn);
@@ -3324,6 +3737,24 @@ reload_as_needed (first, live_known)
                 load and store insn that we just made for reloading
                 and that we moved the structure into).  */
              subst_reloads ();
+
+             /* If this was an ASM, make sure that all the reload insns
+                we have generated are valid.  If not, give an error
+                and delete them.  */
+
+             if (asm_noperands (PATTERN (insn)) >= 0)
+               for (p = NEXT_INSN (prev); p != next; p = NEXT_INSN (p))
+                 if (p != insn && GET_RTX_CLASS (GET_CODE (p)) == 'i'
+                     && (recog_memoized (p) < 0
+                         || (insn_extract (p),
+                             ! constrain_operands (INSN_CODE (p), 1))))
+                   {
+                     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;
+                   }
            }
          /* Any previously reloaded spilled pseudo reg, stored in this insn,
             is no longer validly lying around to save a future reload.
@@ -3353,8 +3784,8 @@ reload_as_needed (first, live_known)
                  if (reload_out[i] == XEXP (x, 0))
                    break;
 
-               if (i != n_reloads)
-                 forget_old_reloads_1 (XEXP (x, 0));
+               if (i == n_reloads)
+                 forget_old_reloads_1 (XEXP (x, 0), NULL_RTX);
              }
 #endif
        }
@@ -3368,7 +3799,7 @@ reload_as_needed (first, live_known)
 
       /* Don't assume a reload reg is still good after a call insn
         if it is a call-used reg.  */
-      if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == CALL_INSN)
+      else if (GET_CODE (insn) == CALL_INSN)
        for (i = 0; i < n_spills; i++)
          if (call_used_regs[spill_regs[i]])
            {
@@ -3404,16 +3835,25 @@ reload_as_needed (first, live_known)
    or it may be a pseudo reg that was reloaded from.  */
 
 static void
-forget_old_reloads_1 (x)
+forget_old_reloads_1 (x, ignored)
      rtx x;
+     rtx ignored;
 {
   register int regno;
   int nr;
+  int offset = 0;
+
+  /* note_stores does give us subregs of hard regs.  */
+  while (GET_CODE (x) == SUBREG)
+    {
+      offset += SUBREG_WORD (x);
+      x = SUBREG_REG (x);
+    }
 
   if (GET_CODE (x) != REG)
     return;
 
-  regno = REGNO (x);
+  regno = REGNO (x) + offset;
 
   if (regno >= FIRST_PSEUDO_REGISTER)
     nr = 1;
@@ -3494,27 +3934,37 @@ reload_reg_class_lower (p1, p2)
 
 /* If reg is in use as a reload reg for a RELOAD_OTHER reload.  */
 static HARD_REG_SET reload_reg_used;
-/* If reg is in use for a RELOAD_FOR_INPUT_RELOAD_ADDRESS reload.  */
-static HARD_REG_SET reload_reg_used_in_input_addr;
-/* If reg is in use for a RELOAD_FOR_OUTPUT_RELOAD_ADDRESS reload.  */
-static HARD_REG_SET reload_reg_used_in_output_addr;
+/* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_INPUT reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_output[MAX_RECOG_OPERANDS];
 /* If reg is in use for a RELOAD_FOR_OPERAND_ADDRESS reload.  */
 static HARD_REG_SET reload_reg_used_in_op_addr;
-/* If reg is in use for a RELOAD_FOR_INPUT reload.  */
-static HARD_REG_SET reload_reg_used_in_input;
-/* If reg is in use for a RELOAD_FOR_OUTPUT reload.  */
-static HARD_REG_SET reload_reg_used_in_output;
+/* If reg is in use for a RELOAD_FOR_INSN reload.  */
+static HARD_REG_SET reload_reg_used_in_insn;
+/* If reg is in use for a RELOAD_FOR_OTHER_ADDRESS reload.  */
+static HARD_REG_SET reload_reg_used_in_other_addr;
 
 /* If reg is in use as a reload reg for any sort of reload.  */
 static HARD_REG_SET reload_reg_used_at_all;
 
-/* Mark reg REGNO as in use for a reload of the sort spec'd by WHEN_NEEDED.
-   MODE is used to indicate how many consecutive regs are actually used.  */
+/* If reg is use as an inherited reload.  We just mark the first register
+   in the group.  */
+static HARD_REG_SET reload_reg_used_for_inherit;
+
+/* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and
+   TYPE. MODE is used to indicate how many consecutive regs are
+   actually used.  */
 
 static void
-mark_reload_reg_in_use (regno, when_needed, mode)
+mark_reload_reg_in_use (regno, opnum, type, mode)
      int regno;
-     enum reload_when_needed when_needed;
+     int opnum;
+     enum reload_type type;
      enum machine_mode mode;
 {
   int nregs = HARD_REGNO_NREGS (regno, mode);
@@ -3522,30 +3972,38 @@ mark_reload_reg_in_use (regno, when_needed, mode)
 
   for (i = regno; i < nregs + regno; i++)
     {
-      switch (when_needed)
+      switch (type)
        {
        case RELOAD_OTHER:
          SET_HARD_REG_BIT (reload_reg_used, i);
          break;
 
-       case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
-         SET_HARD_REG_BIT (reload_reg_used_in_input_addr, i);
+       case RELOAD_FOR_INPUT_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
          break;
 
-       case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
-         SET_HARD_REG_BIT (reload_reg_used_in_output_addr, i);
+       case RELOAD_FOR_OUTPUT_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
          break;
 
        case RELOAD_FOR_OPERAND_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
          break;
 
+       case RELOAD_FOR_OTHER_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
+         break;
+
        case RELOAD_FOR_INPUT:
-         SET_HARD_REG_BIT (reload_reg_used_in_input, i);
+         SET_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
          break;
 
        case RELOAD_FOR_OUTPUT:
-         SET_HARD_REG_BIT (reload_reg_used_in_output, i);
+         SET_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
+         break;
+
+       case RELOAD_FOR_INSN:
+         SET_HARD_REG_BIT (reload_reg_used_in_insn, i);
          break;
        }
 
@@ -3553,18 +4011,77 @@ mark_reload_reg_in_use (regno, when_needed, mode)
     }
 }
 
+/* Similarly, but show REGNO is no longer in use for a reload.  */
+
+static void
+clear_reload_reg_in_use (regno, opnum, type, mode)
+     int regno;
+     int opnum;
+     enum reload_type type;
+     enum machine_mode mode;
+{
+  int nregs = HARD_REGNO_NREGS (regno, mode);
+  int i;
+
+  for (i = regno; i < nregs + regno; i++)
+    {
+      switch (type)
+       {
+       case RELOAD_OTHER:
+         CLEAR_HARD_REG_BIT (reload_reg_used, i);
+         break;
+
+       case RELOAD_FOR_INPUT_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
+         break;
+
+       case RELOAD_FOR_OUTPUT_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
+         break;
+
+       case RELOAD_FOR_OPERAND_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
+         break;
+
+       case RELOAD_FOR_OTHER_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_other_addr, i);
+         break;
+
+       case RELOAD_FOR_INPUT:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_input[opnum], i);
+         break;
+
+       case RELOAD_FOR_OUTPUT:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_output[opnum], i);
+         break;
+
+       case RELOAD_FOR_INSN:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_insn, i);
+         break;
+       }
+    }
+}
+
 /* 1 if reg REGNO is free as a reload reg for a reload of the sort
-   specified by WHEN_NEEDED.  */
+   specified by OPNUM and TYPE.  */
 
 static int
-reload_reg_free_p (regno, when_needed)
+reload_reg_free_p (regno, opnum, type)
      int regno;
-     enum reload_when_needed when_needed;
+     int opnum;
+     enum reload_type type;
 {
-  /* In use for a RELOAD_OTHER means it's not available for anything.  */
-  if (TEST_HARD_REG_BIT (reload_reg_used, regno))
+  int i;
+
+  /* In use for a RELOAD_OTHER means it's not available for anything except
+     RELOAD_FOR_OTHER_ADDRESS.  Recall that RELOAD_FOR_OTHER_ADDRESS is known
+     to be used only for inputs.  */
+
+  if (type != RELOAD_FOR_OTHER_ADDRESS
+      && TEST_HARD_REG_BIT (reload_reg_used, regno))
     return 0;
-  switch (when_needed)
+
+  switch (type)
     {
     case RELOAD_OTHER:
       /* In use for anything means not available for a RELOAD_OTHER.  */
@@ -3572,29 +4089,87 @@ reload_reg_free_p (regno, when_needed)
 
       /* The other kinds of use can sometimes share a register.  */
     case RELOAD_FOR_INPUT:
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_input, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_input_addr, regno));
-    case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_input_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_input, regno));
-    case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_output_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_output, regno));
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
+       return 0;
+
+      /* If it is used for some other input, can't use it.  */
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      /* If it is used in a later operand's address, can't use it.  */
+      for (i = opnum + 1; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+         return 0;
+
+      return 1;
+
+    case RELOAD_FOR_INPUT_ADDRESS:
+      /* Can't use a register if it is used for an input address for this
+        operand or used as an input in an earlier one.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno))
+       return 0;
+
+      for (i = 0; i < opnum; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      return 1;
+
+    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.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
+       return 0;
+
+      for (i = opnum; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      return 1;
+
     case RELOAD_FOR_OPERAND_ADDRESS:
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_input, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_output, regno));
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
+
     case RELOAD_FOR_OUTPUT:
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_output_addr, regno)
-             && ! TEST_HARD_REG_BIT (reload_reg_used_in_output, regno));
+      /* This cannot share a register with RELOAD_FOR_INSN reloads, other
+        outputs, or an operand address for this or an earlier output.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
+       return 0;
+
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      for (i = 0; i <= opnum; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+         return 0;
+
+      return 1;
+
+    case RELOAD_FOR_INSN:
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
+
+    case RELOAD_FOR_OTHER_ADDRESS:
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
     }
   abort ();
 }
 
 /* Return 1 if the value in reload reg REGNO, as used by a reload
-   needed for the part of the insn specified by WHEN_NEEDED,
+   needed for the part of the insn specified by OPNUM and TYPE,
    is not in use for a reload in any prior part of the insn.
 
    We can assume that the reload reg was already tested for availability
@@ -3602,37 +4177,109 @@ reload_reg_free_p (regno, when_needed)
    in case the reg has already been marked in use.  */
 
 static int
-reload_reg_free_before_p (regno, when_needed)
+reload_reg_free_before_p (regno, opnum, type)
      int regno;
-     enum reload_when_needed when_needed;
+     int opnum;
+     enum reload_type type;
 {
-  switch (when_needed)
+  int i;
+
+  switch (type)
     {
-    case RELOAD_OTHER:
-      /* Since a RELOAD_OTHER reload claims the reg for the entire insn,
-        its use starts from the beginning, so nothing can use it earlier.  */
+    case RELOAD_FOR_OTHER_ADDRESS:
+      /* These always come first.  */
       return 1;
 
+    case RELOAD_OTHER:
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+
       /* If this use is for part of the insn,
-        check the reg is not in use for any prior part.  */
-    case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
+        check the reg is not in use for any prior part.  It is tempting
+        to try to do this by falling through from objecs that occur
+        later in the insn to ones that occur earlier, but that will not
+        correctly take into account the fact that here we MUST ignore
+        things that would prevent the register from being allocated in
+        the first place, since we know that it was allocated.  */
+
+    case RELOAD_FOR_OUTPUT_ADDRESS:
+      /* Earlier reloads are for earlier outputs or their addresses,
+        any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any
+        RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with
+        RELOAD_OTHER)..  */
+      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_output[i], regno))
+         return 0;
+
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
        return 0;
+
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
+                                  
     case RELOAD_FOR_OUTPUT:
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_input, regno))
+      /* This can't be used in the output address for this operand and
+        anything that can't be used for it, except that we've already
+        tested for RELOAD_FOR_INSN objects.  */
+
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
        return 0;
+
+      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_output[i], regno))
+         return 0;
+
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
+         return 0;
+
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+
     case RELOAD_FOR_OPERAND_ADDRESS:
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr, regno))
-       return 0;
-    case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
+    case RELOAD_FOR_INSN:
+      /* These can't conflict with inputs, or each other, so all we have to
+        test is input addresses and the addresses of OTHER items.  */
+
+      for (i = 0; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+         return 0;
+
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+
     case RELOAD_FOR_INPUT:
-      return 1;
+      /* The only things earlier are the address for this and
+        earlier inputs, other inputs (which we know we don't conflict
+        with), and addresses of RELOAD_OTHER objects.  */
+
+      for (i = 0; i <= opnum; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+         return 0;
+
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+
+    case RELOAD_FOR_INPUT_ADDRESS:
+      /* Similarly, all we have to check is for use in earlier inputs'
+        addresses.  */
+      for (i = 0; i < opnum; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+         return 0;
+
+      return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
     }
   abort ();
 }
 
 /* Return 1 if the value in reload reg REGNO, as used by a reload
-   needed for the part of the insn specified by WHEN_NEEDED,
+   needed for the part of the insn specified by OPNUM and TYPE,
    is still available in REGNO at the end of the insn.
 
    We can assume that the reload reg was already tested for availability
@@ -3640,11 +4287,14 @@ reload_reg_free_before_p (regno, when_needed)
    in case the reg has already been marked in use.  */
 
 static int
-reload_reg_reaches_end_p (regno, when_needed)
+reload_reg_reaches_end_p (regno, opnum, type)
      int regno;
-     enum reload_when_needed when_needed;
+     int opnum;
+     enum reload_type type;
 {
-  switch (when_needed)
+  int i;
+
+  switch (type)
     {
     case RELOAD_OTHER:
       /* Since a RELOAD_OTHER reload claims the reg for the entire insn,
@@ -3652,19 +4302,89 @@ reload_reg_reaches_end_p (regno, when_needed)
       return 1;
 
       /* If this use is for part of the insn,
-        its value reaches if no subsequent part uses the same register.  */
-    case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
+        its value reaches if no subsequent part uses the same register. 
+        Just like the above function, don't try to do this with lots
+        of fallthroughs.  */
+
+    case RELOAD_FOR_OTHER_ADDRESS:
+      /* Here we check for everything else, since these don't conflict
+        with anything else and everything comes later.  */
+
+      for (i = 0; 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_output[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used, regno));
+
+    case RELOAD_FOR_INPUT_ADDRESS:
+      /* Similar, except that we check only for this and subsequent inputs
+        and the address of only subsequent inputs and we do not need
+        to check for RELOAD_OTHER objects since they are known not to
+        conflict.  */
+
+      for (i = opnum; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      for (i = opnum + 1; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+         return 0;
+
+      for (i = 0; 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_output[i], regno))
+         return 0;
+
+      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+             && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno));
+
     case RELOAD_FOR_INPUT:
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-         || TEST_HARD_REG_BIT (reload_reg_used_in_output, regno))
-       return 0;
+      /* Similar to input address, except we start at the next operand for
+        both input and input address and we do not check for 
+        RELOAD_FOR_OPERAND_ADDRESS and RELOAD_FOR_INSN since these
+        would conflict.  */
+
+      for (i = opnum + 1; i < reload_n_operands; i++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+         return 0;
+
+      /* ... fall through ... */
+
     case RELOAD_FOR_OPERAND_ADDRESS:
-      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr, regno))
-       return 0;
+      /* Check outputs and their addresses.  */
+
+      for (i = 0; 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_output[i], regno))
+         return 0;
+
+      return 1;
+
+    case RELOAD_FOR_INSN:
+      /* These conflict with other outputs with with RELOAD_OTHER.  So
+        we need only check for output addresses.  */
+
+      opnum = -1;
+
+      /* ... fall through ... */
+
     case RELOAD_FOR_OUTPUT:
-    case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
+    case RELOAD_FOR_OUTPUT_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++)
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+         return 0;
+
       return 1;
     }
+
   abort ();
 }
 \f
@@ -3691,7 +4411,7 @@ int reload_spill_index[MAX_RELOADS];
 /* Index of last register assigned as a spill register.  We allocate in
    a round-robin fashio.  */
 
-static last_spill_reg = 0;
+static int last_spill_reg = 0;
 
 /* Find a spill register to use as a reload register for reload R.
    LAST_RELOAD is non-zero if this is the last reload for the insn being
@@ -3755,12 +4475,18 @@ allocate_reload_reg (r, insn, last_reload, noerror)
 
          i = (i + 1) % n_spills;
 
-         if (reload_reg_free_p (spill_regs[i], reload_when_needed[r])
+         if (reload_reg_free_p (spill_regs[i], reload_opnum[r],
+                                reload_when_needed[r])
              && TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
              && HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
-             /* Look first for regs to share, then for unshared.  */
-             && (pass || TEST_HARD_REG_BIT (reload_reg_used_at_all,
-                                            spill_regs[i])))
+             /* Look first for regs to share, then for unshared.  But
+                don't share regs used for inherited reloads; they are
+                the ones we want to preserve.  */
+             && (pass
+                 || (TEST_HARD_REG_BIT (reload_reg_used_at_all,
+                                        spill_regs[i])
+                     && ! TEST_HARD_REG_BIT (reload_reg_used_for_inherit,
+                                             spill_regs[i]))))
            {
              int nr = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
              /* Avoid the problem where spilling a GENERAL_OR_FP_REG
@@ -3786,7 +4512,8 @@ allocate_reload_reg (r, insn, last_reload, noerror)
                    regno = spill_regs[i] + nr - 1;
                    if (!(TEST_HARD_REG_BIT (reg_class_contents[class], regno)
                          && spill_reg_order[regno] >= 0
-                         && reload_reg_free_p (regno, reload_when_needed[r])
+                         && reload_reg_free_p (regno, reload_opnum[r],
+                                               reload_when_needed[r])
                          && ! TEST_HARD_REG_BIT (counted_for_nongroups,
                                                  regno)))
                      break;
@@ -3807,22 +4534,18 @@ allocate_reload_reg (r, insn, last_reload, noerror)
     {
       if (noerror)
        return 0;
-      abort ();
+      goto failure;
     }
 
-  last_spill_reg = i;
-
-  /* Mark as in use for this insn the reload regs we use for this.  */
-  mark_reload_reg_in_use (spill_regs[i], reload_when_needed[r],
-                         reload_mode[r]);
+  /* I is the index in SPILL_REG_RTX of the reload register we are to
+     allocate.  Get an rtx for it and find its register number.  */
 
   new = spill_reg_rtx[i];
 
   if (new == 0 || GET_MODE (new) != reload_mode[r])
-    spill_reg_rtx[i] = new = gen_rtx (REG, reload_mode[r], spill_regs[i]);
-
-  reload_reg_rtx[r] = new;
-  reload_spill_index[r] = i;
+    spill_reg_rtx[i] = new
+      = gen_rtx (REG, reload_mode[r], spill_regs[i]);
+           
   regno = true_regnum (new);
 
   /* Detect when the reload reg can't hold the reload mode.
@@ -3842,14 +4565,26 @@ allocate_reload_reg (r, insn, last_reload, noerror)
             && ! HARD_REGNO_MODE_OK (regno, test_mode)))
        if (! (reload_out[r] != 0
               && ! HARD_REGNO_MODE_OK (regno, GET_MODE (reload_out[r]))))
-         /* The reg is OK.  */
-         return 1;
+         {
+           /* The reg is OK.  */
+           last_spill_reg = i;
+
+           /* Mark as in use for this insn the reload regs we use
+              for this.  */
+           mark_reload_reg_in_use (spill_regs[i], reload_opnum[r],
+                                   reload_when_needed[r], reload_mode[r]);
+
+           reload_reg_rtx[r] = new;
+           reload_spill_index[r] = i;
+           return 1;
+         }
     }
 
   /* The reg is not OK.  */
   if (noerror)
     return 0;
 
+ failure:
   if (asm_noperands (PATTERN (insn)) < 0)
     /* It's the compiler's fault.  */
     abort ();
@@ -3877,7 +4612,6 @@ allocate_reload_reg (r, insn, last_reload, noerror)
 static void
 choose_reload_regs (insn, avoid_return_reg)
      rtx insn;
-     /* This argument is currently ignored.  */
      rtx avoid_return_reg;
 {
   register int i, j;
@@ -3891,11 +4625,13 @@ choose_reload_regs (insn, avoid_return_reg)
   rtx save_reload_override_in[MAX_RELOADS];
   int save_reload_spill_index[MAX_RELOADS];
   HARD_REG_SET save_reload_reg_used;
-  HARD_REG_SET save_reload_reg_used_in_input_addr;
-  HARD_REG_SET save_reload_reg_used_in_output_addr;
+  HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_input[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_output[MAX_RECOG_OPERANDS];
   HARD_REG_SET save_reload_reg_used_in_op_addr;
-  HARD_REG_SET save_reload_reg_used_in_input;
-  HARD_REG_SET save_reload_reg_used_in_output;
+  HARD_REG_SET save_reload_reg_used_in_insn;
+  HARD_REG_SET save_reload_reg_used_in_other_addr;
   HARD_REG_SET save_reload_reg_used_at_all;
 
   bzero (reload_inherited, MAX_RELOADS);
@@ -3904,35 +4640,17 @@ choose_reload_regs (insn, avoid_return_reg)
 
   CLEAR_HARD_REG_SET (reload_reg_used);
   CLEAR_HARD_REG_SET (reload_reg_used_at_all);
-  CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr);
-  CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr);
   CLEAR_HARD_REG_SET (reload_reg_used_in_op_addr);
-  CLEAR_HARD_REG_SET (reload_reg_used_in_output);
-  CLEAR_HARD_REG_SET (reload_reg_used_in_input);
+  CLEAR_HARD_REG_SET (reload_reg_used_in_insn);
+  CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr);
 
-  /* Distinguish output-only and input-only reloads
-     because they can overlap with other things.  */
-  for (j = 0; j < n_reloads; j++)
-    if (reload_when_needed[j] == RELOAD_OTHER
-       && ! reload_needed_for_multiple[j])
-      {
-       if (reload_in[j] == 0)
-         {
-           /* But earlyclobber operands must stay as RELOAD_OTHER.  */
-           for (i = 0; i < n_earlyclobbers; i++)
-             if (rtx_equal_p (reload_out[j], reload_earlyclobbers[i]))
-               break;
-           if (i == n_earlyclobbers)
-             reload_when_needed[j] = RELOAD_FOR_OUTPUT;
-         }
-       if (reload_out[j] == 0)
-         reload_when_needed[j] = RELOAD_FOR_INPUT;
-
-       if (reload_secondary_reload[j] >= 0
-           && ! reload_needed_for_multiple[reload_secondary_reload[j]])
-         reload_when_needed[reload_secondary_reload[j]]
-           = reload_when_needed[j];
-      }
+  for (i = 0; i < reload_n_operands; i++)
+    {
+      CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]);
+    }
 
 #ifdef SMALL_REGISTER_CLASSES
   /* Don't bother with avoiding the return reg
@@ -4015,12 +4733,10 @@ choose_reload_regs (insn, avoid_return_reg)
       reload_spill_index[j] = -1;
 
       reload_mode[j]
-       = (reload_strict_low[j] && reload_out[j]
-          ? GET_MODE (SUBREG_REG (reload_out[j]))
-          : (reload_inmode[j] == VOIDmode
-             || (GET_MODE_SIZE (reload_outmode[j])
-                 > GET_MODE_SIZE (reload_inmode[j])))
-          ? reload_outmode[j] : reload_inmode[j]);
+       = (reload_inmode[j] == VOIDmode
+          || (GET_MODE_SIZE (reload_outmode[j])
+              > GET_MODE_SIZE (reload_inmode[j])))
+         ? reload_outmode[j] : reload_inmode[j];
 
       reload_nregs[j] = CLASS_MAX_NREGS (reload_reg_class[j], reload_mode[j]);
 
@@ -4033,7 +4749,7 @@ choose_reload_regs (insn, avoid_return_reg)
       /* If we have already decided to use a certain register,
         don't use it in another way.  */
       if (reload_reg_rtx[j])
-       mark_reload_reg_in_use (REGNO (reload_reg_rtx[j]),
+       mark_reload_reg_in_use (REGNO (reload_reg_rtx[j]), reload_opnum[j],
                                reload_when_needed[j], reload_mode[j]);
     }
 
@@ -4050,20 +4766,32 @@ choose_reload_regs (insn, avoid_return_reg)
         sizeof reload_spill_index);
   COPY_HARD_REG_SET (save_reload_reg_used, reload_reg_used);
   COPY_HARD_REG_SET (save_reload_reg_used_at_all, reload_reg_used_at_all);
-  COPY_HARD_REG_SET (save_reload_reg_used_in_output,
-                    reload_reg_used_in_output);
-  COPY_HARD_REG_SET (save_reload_reg_used_in_input,
-                    reload_reg_used_in_input);
-  COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr,
-                    reload_reg_used_in_input_addr);
-  COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr,
-                    reload_reg_used_in_output_addr);
   COPY_HARD_REG_SET (save_reload_reg_used_in_op_addr,
                     reload_reg_used_in_op_addr);
+  COPY_HARD_REG_SET (save_reload_reg_used_in_insn,
+                    reload_reg_used_in_insn);
+  COPY_HARD_REG_SET (save_reload_reg_used_in_other_addr,
+                    reload_reg_used_in_other_addr);
 
-  /* Try first with inheritance, then turning it off.  */
+  for (i = 0; i < reload_n_operands; i++)
+    {
+      COPY_HARD_REG_SET (save_reload_reg_used_in_output[i],
+                        reload_reg_used_in_output[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_input[i],
+                        reload_reg_used_in_input[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr[i],
+                        reload_reg_used_in_input_addr[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i],
+                        reload_reg_used_in_output_addr[i]);
+    }
 
-  for (inheritance = 1; inheritance >= 0; inheritance--)
+  /* If -O, try first with inheritance, then turning it off.
+     If not -O, don't do inheritance.
+     Using inheritance when not optimizing leads to paradoxes
+     with fp on the 68k: fp numbers (not NaNs) fail to be equal to themselves
+     because one side of the comparison might be inherited.  */
+
+  for (inheritance = optimize > 0; inheritance >= 0; inheritance--)
     {
       /* Process the reloads in order of preference just found.
         Beyond this point, subregs can be found in reload_reg_rtx.
@@ -4083,6 +4811,8 @@ choose_reload_regs (insn, avoid_return_reg)
         Then make a second pass over the reloads to allocate any reloads
         that haven't been given registers yet.  */
 
+      CLEAR_HARD_REG_SET (reload_reg_used_for_inherit);
+
       for (j = 0; j < n_reloads; j++)
        {
          register int r = reload_order[j];
@@ -4132,13 +4862,20 @@ choose_reload_regs (insn, avoid_return_reg)
          if (inheritance)
            {
              register int regno = -1;
+             enum machine_mode mode;
 
              if (reload_in[r] == 0)
                ;
              else if (GET_CODE (reload_in[r]) == REG)
-               regno = REGNO (reload_in[r]);
+               {
+                 regno = REGNO (reload_in[r]);
+                 mode = GET_MODE (reload_in[r]);
+               }
              else if (GET_CODE (reload_in_reg[r]) == REG)
-               regno = REGNO (reload_in_reg[r]);
+               {
+                 regno = REGNO (reload_in_reg[r]);
+                 mode = GET_MODE (reload_in_reg[r]);
+               }
 #if 0
              /* This won't work, since REGNO can be a pseudo reg number.
                 Also, it takes much more hair to keep track of all the things
@@ -4153,14 +4890,18 @@ choose_reload_regs (insn, avoid_return_reg)
                  i = spill_reg_order[REGNO (reg_last_reload_reg[regno])];
 
                  if (reg_reloaded_contents[i] == regno
+                     && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
+                         >= GET_MODE_SIZE (mode))
                      && HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
                      && TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
                                            spill_regs[i])
                      && (reload_nregs[r] == max_group_size
                          || ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
                                                  spill_regs[i]))
-                     && reload_reg_free_p (spill_regs[i], reload_when_needed[r])
+                     && reload_reg_free_p (spill_regs[i], reload_opnum[r],
+                                           reload_when_needed[r])
                      && reload_reg_free_before_p (spill_regs[i],
+                                                  reload_opnum[r],
                                                   reload_when_needed[r]))
                    {
                      /* If a group is needed, verify that all the subsequent
@@ -4176,15 +4917,44 @@ choose_reload_regs (insn, avoid_return_reg)
 
                      if (k == nr)
                        {
-                         /* Mark the register as in use for this part of
-                            the insn.  */
-                         mark_reload_reg_in_use (spill_regs[i],
-                                                 reload_when_needed[r],
-                                                 reload_mode[r]);
-                         reload_reg_rtx[r] = reg_last_reload_reg[regno];
-                         reload_inherited[r] = 1;
-                         reload_inheritance_insn[r] = reg_reloaded_insn[i];
-                         reload_spill_index[r] = i;
+                         int i1;
+
+                         /* We found a register that contains the
+                            value we need.  If this register is the
+                            same as an `earlyclobber' operand of the
+                            current insn, just mark it as a place to
+                            reload from since we can't use it as the
+                            reload register itself.  */
+
+                         for (i1 = 0; i1 < n_earlyclobbers; i1++)
+                           if (reg_overlap_mentioned_for_reload_p
+                               (reg_last_reload_reg[regno],
+                                reload_earlyclobbers[i1]))
+                             break;
+
+                         if (i1 != n_earlyclobbers
+                             /* Don't really use the inherited spill reg
+                                if we need it wider than we've got it.  */
+                             || (GET_MODE_SIZE (reload_mode[r])
+                                 > GET_MODE_SIZE (mode)))
+                           reload_override_in[r] = reg_last_reload_reg[regno];
+                         else
+                           {
+                             /* We can use this as a reload reg.  */
+                             /* Mark the register as in use for this part of
+                                the insn.  */
+                             mark_reload_reg_in_use (spill_regs[i],
+                                                     reload_opnum[r],
+                                                     reload_when_needed[r],
+                                                     reload_mode[r]);
+                             reload_reg_rtx[r] = reg_last_reload_reg[regno];
+                             reload_inherited[r] = 1;
+                             reload_inheritance_insn[r]
+                               = reg_reloaded_insn[i];
+                             reload_spill_index[r] = i;
+                             SET_HARD_REG_BIT (reload_reg_used_for_inherit,
+                                               spill_regs[i]);
+                           }
                        }
                    }
                }
@@ -4204,7 +4974,7 @@ choose_reload_regs (insn, avoid_return_reg)
            {
              register rtx equiv
                = find_equiv_reg (reload_in[r], insn, reload_reg_class[r],
-                                 -1, 0, 0, reload_mode[r]);
+                                 -1, NULL_PTR, 0, reload_mode[r]);
              int regno;
 
              if (equiv != 0)
@@ -4225,7 +4995,7 @@ choose_reload_regs (insn, avoid_return_reg)
                 and of the desired class.  */
              if (equiv != 0
                  && ((spill_reg_order[regno] >= 0
-                      && ! reload_reg_free_before_p (regno,
+                      && ! reload_reg_free_before_p (regno, reload_opnum[r],
                                                      reload_when_needed[r]))
                      || ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
                                              regno)))
@@ -4244,7 +5014,8 @@ choose_reload_regs (insn, avoid_return_reg)
 
              if (equiv != 0)
                for (i = 0; i < n_earlyclobbers; i++)
-                 if (reg_overlap_mentioned_p (equiv, reload_earlyclobbers[i]))
+                 if (reg_overlap_mentioned_for_reload_p (equiv,
+                                                         reload_earlyclobbers[i]))
                    {
                      reload_override_in[r] = equiv;
                      equiv = 0;
@@ -4270,8 +5041,12 @@ choose_reload_regs (insn, avoid_return_reg)
                     mark the spill reg as in use for this insn.  */
                  i = spill_reg_order[regno];
                  if (i >= 0)
-                   mark_reload_reg_in_use (regno, reload_when_needed[r],
-                                           reload_mode[r]);
+                   {
+                     mark_reload_reg_in_use (regno, reload_opnum[r],
+                                             reload_when_needed[r],
+                                             reload_mode[r]);
+                     SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno);
+                   }
                }
            }
 
@@ -4296,8 +5071,8 @@ choose_reload_regs (insn, avoid_return_reg)
            {
              int s = reload_order[i];
 
-             if ((reload_in[s] == 0 && reload_out[s] == 0 &&
-                  ! reload_secondary_p[s])
+             if ((reload_in[s] == 0 && reload_out[s] == 0
+                  && ! reload_secondary_p[s])
                  || reload_optional[s])
                continue;
 
@@ -4352,16 +5127,24 @@ choose_reload_regs (insn, avoid_return_reg)
             sizeof reload_spill_index);
       COPY_HARD_REG_SET (reload_reg_used, save_reload_reg_used);
       COPY_HARD_REG_SET (reload_reg_used_at_all, save_reload_reg_used_at_all);
-      COPY_HARD_REG_SET (reload_reg_used_in_input,
-                        save_reload_reg_used_in_input);
-      COPY_HARD_REG_SET (reload_reg_used_in_output,
-                        save_reload_reg_used_in_output);
-      COPY_HARD_REG_SET (reload_reg_used_in_input_addr,
-                        save_reload_reg_used_in_input_addr);
-      COPY_HARD_REG_SET (reload_reg_used_in_output_addr,
-                        save_reload_reg_used_in_output_addr);
       COPY_HARD_REG_SET (reload_reg_used_in_op_addr,
                         save_reload_reg_used_in_op_addr);
+      COPY_HARD_REG_SET (reload_reg_used_in_insn,
+                        save_reload_reg_used_in_insn);
+      COPY_HARD_REG_SET (reload_reg_used_in_other_addr,
+                        save_reload_reg_used_in_other_addr);
+
+      for (i = 0; i < reload_n_operands; i++)
+       {
+         COPY_HARD_REG_SET (reload_reg_used_in_input[i],
+                            save_reload_reg_used_in_input[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_output[i],
+                            save_reload_reg_used_in_output[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_input_addr[i],
+                            save_reload_reg_used_in_input_addr[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i],
+                            save_reload_reg_used_in_output_addr[i]);
+       }
     }
 
   /* If we thought we could inherit a reload, because it seemed that
@@ -4374,6 +5157,7 @@ choose_reload_regs (insn, avoid_return_reg)
 
       if (reload_inherited[r] && reload_reg_rtx[r] != 0
          && ! reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
+                                        reload_opnum[r],
                                         reload_when_needed[r]))
        reload_inherited[r] = 0;
 
@@ -4385,7 +5169,8 @@ choose_reload_regs (insn, avoid_return_reg)
        {
          int regno = true_regnum (reload_override_in[r]);
          if (spill_reg_order[regno] >= 0
-             && ! reload_reg_free_before_p (regno, reload_when_needed[r]))
+             && ! reload_reg_free_before_p (regno, reload_opnum[r],
+                                            reload_when_needed[r]))
            reload_override_in[r] = 0;
        }
     }
@@ -4400,10 +5185,18 @@ choose_reload_regs (insn, avoid_return_reg)
      optional and not inherited, clear reload_reg_rtx so other
      routines (such as subst_reloads) don't get confused.  */
   for (j = 0; j < n_reloads; j++)
-    if ((reload_optional[j] && ! reload_inherited[j])
-       || (reload_in[j] == 0 && reload_out[j] == 0
-           && ! reload_secondary_p[j]))
-      reload_reg_rtx[j] = 0;
+    if (reload_reg_rtx[j] != 0
+       && ((reload_optional[j] && ! reload_inherited[j])
+           || (reload_in[j] == 0 && reload_out[j] == 0
+               && ! reload_secondary_p[j])))
+      {
+       int regno = true_regnum (reload_reg_rtx[j]);
+
+       if (spill_reg_order[regno] >= 0)
+         clear_reload_reg_in_use (regno, reload_opnum[j],
+                                  reload_when_needed[j], reload_mode[j]);
+       reload_reg_rtx[j] = 0;
+      }
 
   /* Record which pseudos and which spill regs have output reloads.  */
   for (j = 0; j < n_reloads; j++)
@@ -4419,22 +5212,118 @@ choose_reload_regs (insn, avoid_return_reg)
          && reload_reg_rtx[r] != 0)
        {
          register int nregno = REGNO (reload_out[r]);
-         int nr = HARD_REGNO_NREGS (nregno, reload_mode[r]);
+         int nr = 1;
+
+         if (nregno < FIRST_PSEUDO_REGISTER)
+           nr = HARD_REGNO_NREGS (nregno, reload_mode[r]);
 
          while (--nr >= 0)
+           reg_has_output_reload[nregno + nr] = 1;
+
+         if (i >= 0)
            {
-             reg_has_output_reload[nregno + nr] = 1;
-             if (i >= 0)
+             nr = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
+             while (--nr >= 0)
                SET_HARD_REG_BIT (reg_is_output_reload, spill_regs[i] + nr);
            }
 
          if (reload_when_needed[r] != RELOAD_OTHER
-             && reload_when_needed[r] != RELOAD_FOR_OUTPUT)
+             && reload_when_needed[r] != RELOAD_FOR_OUTPUT
+             && reload_when_needed[r] != RELOAD_FOR_INSN)
            abort ();
        }
     }
 }
 \f
+/* If SMALL_REGISTER_CLASSES are defined, we may not have merged two
+   reloads of the same item for fear that we might not have enough reload
+   registers. However, normally they will get the same reload register
+   and hence actually need not be loaded twice.  
+
+   Here we check for the most common case of this phenomenon: when we have
+   a number of reloads for the same object, each of which were allocated
+   the same reload_reg_rtx, that reload_reg_rtx is not used for any other
+   reload, and is not modified in the insn itself.  If we find such,
+   merge all the reloads and set the resulting reload to RELOAD_OTHER.
+   This will not increase the number of spill registers needed and will
+   prevent redundant code.  */
+
+#ifdef SMALL_REGISTER_CLASSES
+
+static void
+merge_assigned_reloads (insn)
+     rtx insn;
+{
+  int i, j;
+
+  /* Scan all the reloads looking for ones that only load values and
+     are not already RELOAD_OTHER and ones whose reload_reg_rtx are
+     assigned and not modified by INSN.  */
+
+  for (i = 0; i < n_reloads; i++)
+    {
+      if (reload_in[i] == 0 || reload_when_needed[i] == RELOAD_OTHER
+         || reload_out[i] != 0 || reload_reg_rtx[i] == 0
+         || reg_set_p (reload_reg_rtx[i], insn))
+       continue;
+
+      /* Look at all other reloads.  Ensure that the only use of this
+        reload_reg_rtx is in a reload that just loads the same value
+        as we do.  Note that any secondary reloads must be of the identical
+        class since the values, modes, and result registers are the
+        same, so we need not do anything with any secondary reloads.  */
+
+      for (j = 0; j < n_reloads; j++)
+       {
+         if (i == j || reload_reg_rtx[j] == 0
+             || ! reg_overlap_mentioned_p (reload_reg_rtx[j],
+                                           reload_reg_rtx[i]))
+           continue;
+
+         /* If the reload regs aren't exactly the same (e.g, different modes)
+            or if the values are different, we can't merge anything with this
+            reload register.  */
+
+         if (! rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j])
+             || reload_out[j] != 0 || reload_in[j] == 0
+             || ! rtx_equal_p (reload_in[i], reload_in[j]))
+           break;
+       }
+
+      /* If all is OK, merge the reloads.  Only set this to RELOAD_OTHER if
+        we, in fact, found any matching reloads.  */
+
+      if (j == n_reloads)
+       {
+         for (j = 0; j < n_reloads; j++)
+           if (i != j && reload_reg_rtx[j] != 0
+               && rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j]))
+             {
+               reload_when_needed[i] = RELOAD_OTHER;
+               reload_in[j] = 0;
+               transfer_replacements (i, j);
+             }
+
+         /* If this is now RELOAD_OTHER, look for any reloads that load
+            parts of this operand and set them to RELOAD_FOR_OTHER_ADDRESS
+            if they were for inputs, RELOAD_OTHER for outputs.  Note that
+            this test is equivalent to looking for reloads for this operand
+            number.  */
+
+         if (reload_when_needed[i] == RELOAD_OTHER)
+           for (j = 0; j < n_reloads; j++)
+             if (reload_in[j] != 0
+                 && reload_when_needed[i] != RELOAD_OTHER
+                 && reg_overlap_mentioned_for_reload_p (reload_in[j],
+                                                        reload_in[i]))
+               reload_when_needed[j]
+                 = reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+                   ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER;
+       }
+    }
+}          
+#endif /* SMALL_RELOAD_CLASSES */
+\f
 /* Output insns to reload values in and out of the chosen reload regs.  */
 
 static void
@@ -4442,24 +5331,41 @@ emit_reload_insns (insn)
      rtx insn;
 {
   register int j;
+  rtx input_reload_insns[MAX_RECOG_OPERANDS];
+  rtx other_input_address_reload_insns = 0;
+  rtx other_input_reload_insns = 0;
+  rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx output_reload_insns[MAX_RECOG_OPERANDS];
+  rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx operand_reload_insns = 0;
   rtx following_insn = NEXT_INSN (insn);
   rtx before_insn = insn;
-  rtx first_output_reload_insn = NEXT_INSN (insn);
-  rtx first_other_reload_insn = insn;
-  rtx first_operand_address_reload_insn = insn;
   int special;
   /* Values to be put in spill_reg_store are put here first.  */
   rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
 
-  /* If this is a CALL_INSN preceeded by USE insns, any reload insns
+  for (j = 0; j < reload_n_operands; j++)
+    input_reload_insns[j] = input_address_reload_insns[j]
+      = output_reload_insns[j] = output_address_reload_insns[j] = 0;
+
+  /* If this is a CALL_INSN preceded by USE insns, any reload insns
      must go in front of the first USE insn, not in front of INSN.  */
 
   if (GET_CODE (insn) == CALL_INSN && GET_CODE (PREV_INSN (insn)) == INSN
       && GET_CODE (PATTERN (PREV_INSN (insn))) == USE)
     while (GET_CODE (PREV_INSN (before_insn)) == INSN
           && GET_CODE (PATTERN (PREV_INSN (before_insn))) == USE)
-      first_other_reload_insn = first_operand_address_reload_insn
-       = before_insn = PREV_INSN (before_insn);
+      before_insn = PREV_INSN (before_insn);
+
+  /* If INSN is followed by any CLOBBER insns made by find_reloads,
+     put our reloads after them since they may otherwise be 
+     misinterpreted.  */
+
+  while (GET_CODE (following_insn) == INSN
+        && GET_MODE (following_insn) == DImode
+        && GET_CODE (PATTERN (following_insn)) == CLOBBER
+        && NEXT_INSN (following_insn) != 0)
+    following_insn = NEXT_INSN (following_insn);
 
   /* Now output the instructions to copy the data into and out of the
      reload registers.  Do these in the order that the reloads were reported,
@@ -4470,7 +5376,6 @@ emit_reload_insns (insn)
     {
       register rtx old;
       rtx oldequiv_reg = 0;
-      rtx this_reload_insn = 0;
       rtx store_insn = 0;
 
       old = reload_in[j];
@@ -4481,8 +5386,7 @@ emit_reload_insns (insn)
          register rtx reloadreg = reload_reg_rtx[j];
          rtx oldequiv = 0;
          enum machine_mode mode;
-         rtx where;
-         rtx reload_insn;
+         rtx *where;
 
          /* Determine the mode to reload in.
             This is very tricky because we have three to choose from.
@@ -4519,8 +5423,6 @@ emit_reload_insns (insn)
          mode = GET_MODE (old);
          if (mode == VOIDmode)
            mode = reload_inmode[j];
-         if (reload_strict_low[j])
-           mode = GET_MODE (SUBREG_REG (reload_in[j]));
 
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
          /* If we need a secondary register for this operation, see if
@@ -4529,11 +5431,12 @@ emit_reload_insns (insn)
             register.  */
 
          if (reload_secondary_reload[j] >= 0
-             && reload_secondary_icode[j] == CODE_FOR_nothing)
+             && reload_secondary_icode[j] == CODE_FOR_nothing
+             && optimize)
            oldequiv
              = find_equiv_reg (old, insn,
                                reload_reg_class[reload_secondary_reload[j]],
-                               -1, 0, 0, mode);
+                               -1, NULL_PTR, 0, mode);
 #endif
 
          /* If reloading from memory, see if there is a register
@@ -4544,13 +5447,13 @@ emit_reload_insns (insn)
             or has yet to be emitted, in which case it doesn't matter
             because we will use this equiv reg right away.  */
 
-         if (oldequiv == 0
+         if (oldequiv == 0 && optimize
              && (GET_CODE (old) == MEM
                  || (GET_CODE (old) == REG
                      && REGNO (old) >= FIRST_PSEUDO_REGISTER
                      && reg_renumber[REGNO (old)] < 0)))
-           oldequiv = find_equiv_reg (old, insn, GENERAL_REGS,
-                                      -1, 0, 0, mode);
+           oldequiv = find_equiv_reg (old, insn, ALL_REGS,
+                                      -1, NULL_PTR, 0, mode);
 
          if (oldequiv)
            {
@@ -4560,8 +5463,9 @@ emit_reload_insns (insn)
                 if any other reload needs it at an earlier stage of this insn
                 or at this stage.  */
              if (spill_reg_order[regno] >= 0
-                 && (! reload_reg_free_p (regno, reload_when_needed[j])
-                     || ! reload_reg_free_before_p (regno,
+                 && (! reload_reg_free_p (regno, reload_opnum[j],
+                                          reload_when_needed[j])
+                     || ! reload_reg_free_before_p (regno, reload_opnum[j],
                                                     reload_when_needed[j])))
                oldequiv = 0;
 
@@ -4572,12 +5476,36 @@ emit_reload_insns (insn)
                  int k;
                  for (k = 0; k < n_reloads; k++)
                    if (reload_reg_rtx[k] != 0 && k != j
-                       && reg_overlap_mentioned_p (reload_reg_rtx[k], oldequiv))
+                       && reg_overlap_mentioned_for_reload_p (reload_reg_rtx[k],
+                                                              oldequiv))
                      {
                        oldequiv = 0;
                        break;
                      }
                }
+
+             /* If it is no cheaper to copy from OLDEQUIV into the
+                reload register than it would be to move from memory,
+                don't use it. Likewise, if we need a secondary register
+                or memory.   */
+
+             if (oldequiv != 0
+                 && ((REGNO_REG_CLASS (regno) != reload_reg_class[j]
+                      && (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
+                                              reload_reg_class[j])
+                          >= MEMORY_MOVE_COST (mode)))
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+                     || (SECONDARY_INPUT_RELOAD_CLASS (reload_reg_class[j],
+                                                       mode, oldequiv)
+                         != NO_REGS)
+#endif
+#ifdef SECONDARY_MEMORY_NEEDED
+                     || SECONDARY_MEMORY_NEEDED (reload_reg_class[j],
+                                                 REGNO_REG_CLASS (regno),
+                                                 mode)
+#endif
+                     ))
+               oldequiv = 0;
            }
 
          if (oldequiv == 0)
@@ -4588,7 +5516,10 @@ emit_reload_insns (insn)
            oldequiv_reg = SUBREG_REG (oldequiv);
 
          /* Encapsulate both RELOADREG and OLDEQUIV into that mode,
-            then load RELOADREG from OLDEQUIV.  */
+            then load RELOADREG from OLDEQUIV.  Note that we cannot use
+            gen_lowpart_common since it can do the wrong thing when
+            RELOADREG has a multi-word mode.  Note that RELOADREG
+            must always be a REG here.  */
 
          if (GET_MODE (reloadreg) != mode)
            reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
@@ -4598,23 +5529,32 @@ emit_reload_insns (insn)
              && mode != GET_MODE (oldequiv))
            oldequiv = gen_rtx (SUBREG, mode, oldequiv, 0);
 
-         /* Decide where to put reload insn for this reload.  */
+         /* Switch to the right place to emit the reload insns.  */
          switch (reload_when_needed[j])
            {
-           case RELOAD_FOR_INPUT:
            case RELOAD_OTHER:
-             where = first_operand_address_reload_insn;
+             where = &other_input_reload_insns;
              break;
-           case RELOAD_FOR_INPUT_RELOAD_ADDRESS:
-             where = first_other_reload_insn;
+           case RELOAD_FOR_INPUT:
+             where = &input_reload_insns[reload_opnum[j]];
+             break;
+           case RELOAD_FOR_INPUT_ADDRESS:
+             where = &input_address_reload_insns[reload_opnum[j]];
              break;
-           case RELOAD_FOR_OUTPUT_RELOAD_ADDRESS:
-             where = first_output_reload_insn;
+           case RELOAD_FOR_OUTPUT_ADDRESS:
+             where = &output_address_reload_insns[reload_opnum[j]];
              break;
            case RELOAD_FOR_OPERAND_ADDRESS:
-             where = before_insn;
+             where = &operand_reload_insns;
+             break;
+           case RELOAD_FOR_OTHER_ADDRESS:
+             where = &other_input_address_reload_insns;
+             break;
+           default:
+             abort ();
            }
 
+         push_to_sequence (*where);
          special = 0;
 
          /* Auto-increment addresses must be reloaded in a special way.  */
@@ -4631,8 +5571,7 @@ emit_reload_insns (insn)
              /* Prevent normal processing of this reload.  */
              special = 1;
              /* Output a special code sequence for this case.  */
-             this_reload_insn
-               = inc_for_reload (reloadreg, oldequiv, reload_inc[j], where);
+             inc_for_reload (reloadreg, oldequiv, reload_inc[j]);
            }
 
          /* If we are reloading a pseudo-register that was set by the previous
@@ -4644,9 +5583,9 @@ emit_reload_insns (insn)
                   && dead_or_set_p (insn, old)
                   /* This is unsafe if some other reload
                      uses the same reg first.  */
-                  && (reload_when_needed[j] == RELOAD_OTHER
-                      || reload_when_needed[j] == RELOAD_FOR_INPUT
-                      || reload_when_needed[j] == RELOAD_FOR_INPUT_RELOAD_ADDRESS))
+                  && reload_reg_free_before_p (REGNO (reloadreg),
+                                               reload_opnum[j],
+                                               reload_when_needed[j]))
            {
              rtx temp = PREV_INSN (insn);
              while (temp && GET_CODE (temp) == NOTE)
@@ -4680,14 +5619,8 @@ emit_reload_insns (insn)
                }
            }
 
-         /* We can't do that, so output an insn to load RELOADREG.
-            Keep them in the following order:
-            all reloads for input reload addresses,
-            all reloads for ordinary input operands,
-            all reloads for addresses of non-reloaded operands,
-            the insn being reloaded,
-            all reloads for addresses of output reloads,
-            the output reloads.  */
+         /* We can't do that, so output an insn to load RELOADREG.  */
+
          if (! special)
            {
 #ifdef SECONDARY_INPUT_RELOAD_CLASS
@@ -4708,6 +5641,22 @@ emit_reload_insns (insn)
              if (reload_secondary_reload[j] >= 0)
                {
                  int secondary_reload = reload_secondary_reload[j];
+                 rtx real_oldequiv = oldequiv;
+                 rtx real_old = old;
+
+                 /* If OLDEQUIV is a pseudo with a MEM, get the real MEM
+                    and similarly for OLD.
+                    See comments in find_secondary_reload in reload.c.  */
+                 if (GET_CODE (oldequiv) == REG
+                     && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER
+                     && reg_equiv_mem[REGNO (oldequiv)] != 0)
+                   real_oldequiv = reg_equiv_mem[REGNO (oldequiv)];
+
+                 if (GET_CODE (old) == REG
+                     && REGNO (old) >= FIRST_PSEUDO_REGISTER
+                     && reg_equiv_mem[REGNO (old)] != 0)
+                   real_old = reg_equiv_mem[REGNO (old)];
+
                  second_reload_reg = reload_reg_rtx[secondary_reload];
                  icode = reload_secondary_icode[j];
 
@@ -4716,7 +5665,7 @@ emit_reload_insns (insn)
                    {
                      enum reg_class new_class
                        = SECONDARY_INPUT_RELOAD_CLASS (reload_reg_class[j],
-                                                       mode, oldequiv);
+                                                       mode, real_oldequiv);
 
                      if (new_class == NO_REGS)
                        second_reload_reg = 0;
@@ -4727,7 +5676,7 @@ emit_reload_insns (insn)
 
                          if (! TEST_HARD_REG_BIT (reg_class_contents[(int) new_class],
                                                   REGNO (second_reload_reg)))
-                           oldequiv = old;
+                           oldequiv = old, real_oldequiv = real_old;
                          else
                            {
                              new_icode = reload_in_optab[(int) mode];
@@ -4737,23 +5686,23 @@ emit_reload_insns (insn)
                                             (reloadreg, mode)))
                                      || (insn_operand_predicate[(int) new_icode][1]
                                          && ! ((*insn_operand_predicate[(int) new_icode][1])
-                                               (oldequiv, mode)))))
+                                               (real_oldequiv, mode)))))
                                new_icode = CODE_FOR_nothing;
 
                              if (new_icode == CODE_FOR_nothing)
                                new_mode = mode;
                              else
-                               new_mode = insn_operand_mode[new_icode][2];
+                               new_mode = insn_operand_mode[(int) new_icode][2];
 
                              if (GET_MODE (second_reload_reg) != new_mode)
                                {
                                  if (!HARD_REGNO_MODE_OK (REGNO (second_reload_reg),
                                                           new_mode))
-                                   oldequiv = old;
+                                   oldequiv = old, real_oldequiv = real_old;
                                  else
                                    second_reload_reg
-                                     = gen_reg_rtx (REG, new_mode,
-                                                    REGNO (second_reload_reg));
+                                     = gen_rtx (REG, new_mode,
+                                                REGNO (second_reload_reg));
                                }
                            }
                        }
@@ -4761,18 +5710,17 @@ emit_reload_insns (insn)
 
                  /* If we still need a secondary reload register, check
                     to see if it is being used as a scratch or intermediate
-                    register and generate code appropriately.  */
+                    register and generate code appropriately.  If we need
+                    a scratch register, use REAL_OLDEQUIV since the form of
+                    the insn may depend on the actual address if it is 
+                    a MEM.  */
 
                  if (second_reload_reg)
                    {
                      if (icode != CODE_FOR_nothing)
                        {
-                         reload_insn = emit_insn_before (GEN_FCN (icode)
-                                                         (reloadreg, oldequiv,
-                                                          second_reload_reg),
-                                                         where);
-                         if (this_reload_insn == 0)
-                           this_reload_insn = reload_insn;
+                         emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv,
+                                                     second_reload_reg));
                          special = 1;
                        }
                      else
@@ -4787,36 +5735,24 @@ emit_reload_insns (insn)
                              rtx third_reload_reg
                                = reload_reg_rtx[reload_secondary_reload[secondary_reload]];
 
-                             reload_insn
-                               = emit_insn_before ((GEN_FCN (tertiary_icode)
-                                                    (second_reload_reg,
-                                                     oldequiv,
-                                                     third_reload_reg)),
-                                                   where);
-                             if (this_reload_insn == 0)
-                               this_reload_insn = reload_insn;
+                             emit_insn ((GEN_FCN (tertiary_icode)
+                                         (second_reload_reg, real_oldequiv,
+                                          third_reload_reg)));
                            }
                          else
-                           {
-                             reload_insn
-                               = gen_input_reload (second_reload_reg,
-                                                   oldequiv, where);
-                             if (this_reload_insn == 0)
-                               this_reload_insn = reload_insn;
-                             oldequiv = second_reload_reg;
-                           }
+                           gen_input_reload (second_reload_reg, oldequiv,
+                                             reload_opnum[j],
+                                             reload_when_needed[j]);
+
+                         oldequiv = second_reload_reg;
                        }
                    }
                }
 #endif
 
              if (! special)
-               {
-                 reload_insn = gen_input_reload (reloadreg,
-                                                 oldequiv, where);
-                 if (this_reload_insn == 0)
-                   this_reload_insn = reload_insn;
-               }
+               gen_input_reload (reloadreg, oldequiv, reload_opnum[j],
+                                 reload_when_needed[j]);
 
 #if defined(SECONDARY_INPUT_RELOAD_CLASS) && defined(PRESERVE_DEATH_INFO_REGNO_P)
              /* We may have to make a REG_DEAD note for the secondary reload
@@ -4827,12 +5763,11 @@ emit_reload_insns (insn)
                {
                  rtx prev;
 
-                 for (prev = where;
-                      prev != PREV_INSN (this_reload_insn);
+                 for (prev = get_last_insn (); prev;
                       prev = PREV_INSN (prev))
                    if (GET_RTX_CLASS (GET_CODE (prev) == 'i')
-                       && reg_overlap_mentioned_p (second_reload_reg,
-                                                   PATTERN (prev)))
+                       && reg_overlap_mentioned_for_reload_p (second_reload_reg,
+                                                              PATTERN (prev)))
                      {
                        REG_NOTES (prev) = gen_rtx (EXPR_LIST, REG_DEAD,
                                                    second_reload_reg,
@@ -4843,23 +5778,9 @@ emit_reload_insns (insn)
 #endif
            }
 
-         /* Update where to put other reload insns.  */
-         if (this_reload_insn)
-           switch (reload_when_needed[j])
-             {
-             case RELOAD_FOR_INPUT:
-             case RELOAD_OTHER:
-               if (first_other_reload_insn == first_operand_address_reload_insn)
-                 first_other_reload_insn = this_reload_insn;
-               break;
-             case RELOAD_FOR_OPERAND_ADDRESS:
-               if (first_operand_address_reload_insn == before_insn)
-                 first_operand_address_reload_insn = this_reload_insn;
-               if (first_other_reload_insn == before_insn)
-                 first_other_reload_insn = this_reload_insn;
-             }
-
-         /* reload_inc[j] was formerly processed here.  */
+         /* End this sequence.  */
+         *where = get_insns ();
+         end_sequence ();
        }
 
       /* Add a note saying the input reload reg
@@ -4960,8 +5881,8 @@ emit_reload_insns (insn)
                    for (prev1 = this_reload_insn;
                         prev1; prev1 = PREV_INSN (prev1))
                      if (GET_RTX_CLASS (GET_CODE (prev1) == 'i')
-                       && reg_overlap_mentioned_p (oldequiv_reg,
-                                                   PATTERN (prev1)))
+                       && reg_overlap_mentioned_for_reload_p (oldequiv_reg,
+                                                              PATTERN (prev1)))
                      {
                        REG_NOTES (prev1) = gen_rtx (EXPR_LIST, REG_DEAD,
                                                     oldequiv_reg,
@@ -4980,10 +5901,7 @@ emit_reload_insns (insn)
         actually no need to store the old value in it.  */
 
       if (optimize && reload_inherited[j] && reload_spill_index[j] >= 0
-         /* This is unsafe if some other reload uses the same reg first.  */
-         && (reload_when_needed[j] == RELOAD_OTHER
-             || reload_when_needed[j] == RELOAD_FOR_INPUT
-             || reload_when_needed[j] == RELOAD_FOR_INPUT_RELOAD_ADDRESS)
+         && reload_in[j] != 0
          && GET_CODE (reload_in[j]) == REG
 #if 0
          /* There doesn't seem to be any reason to restrict this to pseudos
@@ -4992,6 +5910,9 @@ emit_reload_insns (insn)
          && REGNO (reload_in[j]) >= FIRST_PSEUDO_REGISTER
 #endif
          && spill_reg_store[reload_spill_index[j]] != 0
+         /* This is unsafe if some other reload uses the same reg first.  */
+         && reload_reg_free_before_p (spill_regs[reload_spill_index[j]],
+                                      reload_opnum[j], reload_when_needed[j])
          && dead_or_set_p (insn, reload_in[j])
          /* This is unsafe if operand occurs more than once in current
             insn.  Perhaps some occurrences weren't reloaded.  */
@@ -5012,7 +5933,6 @@ emit_reload_insns (insn)
        {
          register rtx reloadreg = reload_reg_rtx[j];
          register rtx second_reloadreg = 0;
-         rtx prev_insn = PREV_INSN (first_output_reload_insn);
          rtx note, p;
          enum machine_mode mode;
          int special = 0;
@@ -5045,26 +5965,22 @@ emit_reload_insns (insn)
          if (GET_CODE (insn) == JUMP_INSN)
            abort ();
 
+         push_to_sequence (output_reload_insns[reload_opnum[j]]);
+
          /* Determine the mode to reload in.
             See comments above (for input reloading).  */
 
          mode = GET_MODE (old);
          if (mode == VOIDmode)
-           abort ();           /* Should never happen for an output.  */
-
-         /* A strict-low-part output operand needs to be reloaded
-            in the mode of the entire value.  */
-         if (reload_strict_low[j])
            {
-             mode = GET_MODE (SUBREG_REG (reload_out[j]));
-             /* Encapsulate OLD into that mode.  */
-             /* If OLD is a subreg, then strip it, since the subreg will
-                be altered by this very reload.  */
-             while (GET_CODE (old) == SUBREG && GET_MODE (old) != mode)
-               old = SUBREG_REG (old);
-             if (GET_MODE (old) != VOIDmode
-                 && mode != GET_MODE (old))
-               old = gen_rtx (SUBREG, mode, old, 0);
+             /* VOIDmode should never happen for an output.  */
+             if (asm_noperands (PATTERN (insn)) < 0)
+               /* It's the compiler's fault.  */
+               abort ();
+             error_for_asm (insn, "output operand is constant in `asm'");
+             /* Prevent crash--use something we know is valid.  */
+             mode = word_mode;
+             old = gen_rtx (REG, mode, REGNO (reloadreg));
            }
 
          if (GET_MODE (reloadreg) != mode)
@@ -5076,81 +5992,144 @@ emit_reload_insns (insn)
             one, since it will be stored into OUT.  We might need a secondary
             register only for an input reload, so check again here.  */
 
-         if (reload_secondary_reload[j] >= 0
-             && (SECONDARY_OUTPUT_RELOAD_CLASS (reload_reg_class[j],
-                                                mode, old)
-                 != NO_REGS))
+         if (reload_secondary_reload[j] >= 0)
            {
-             second_reloadreg = reloadreg;
-             reloadreg = reload_reg_rtx[reload_secondary_reload[j]];
+             rtx real_old = old;
 
-             /* See if RELOADREG is to be used as a scratch register
-                or as an intermediate register.  */
-             if (reload_secondary_icode[j] != CODE_FOR_nothing)
-               {
-                 emit_insn_before ((GEN_FCN (reload_secondary_icode[j])
-                                    (old, second_reloadreg, reloadreg)),
-                                   first_output_reload_insn);
-                 special = 1;
-               }
-             else
-               {
-                 /* See if we need both a scratch and intermediate reload
-                    register.  */
-                 int secondary_reload = reload_secondary_reload[j];
-                 enum insn_code tertiary_icode
-                   = reload_secondary_icode[secondary_reload];
-                 rtx pat;
+             if (GET_CODE (old) == REG && REGNO (old) >= FIRST_PSEUDO_REGISTER
+                 && reg_equiv_mem[REGNO (old)] != 0)
+               real_old = reg_equiv_mem[REGNO (old)];
 
-                 if (GET_MODE (reloadreg) != mode)
-                   reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+             if((SECONDARY_OUTPUT_RELOAD_CLASS (reload_reg_class[j],
+                                                mode, real_old)
+                 != NO_REGS))
+               {
+                 second_reloadreg = reloadreg;
+                 reloadreg = reload_reg_rtx[reload_secondary_reload[j]];
 
-                 if (tertiary_icode != CODE_FOR_nothing)
+                 /* See if RELOADREG is to be used as a scratch register
+                    or as an intermediate register.  */
+                 if (reload_secondary_icode[j] != CODE_FOR_nothing)
                    {
-                     rtx third_reloadreg
-                       = reload_reg_rtx[reload_secondary_reload[secondary_reload]];
-                     pat = (GEN_FCN (tertiary_icode)
-                            (reloadreg, second_reloadreg, third_reloadreg));
+                     emit_insn ((GEN_FCN (reload_secondary_icode[j])
+                                 (real_old, second_reloadreg, reloadreg)));
+                     special = 1;
                    }
                  else
-                   pat = gen_move_insn (reloadreg, second_reloadreg);
+                   {
+                     /* See if we need both a scratch and intermediate reload
+                        register.  */
+                     int secondary_reload = reload_secondary_reload[j];
+                     enum insn_code tertiary_icode
+                       = reload_secondary_icode[secondary_reload];
+                     rtx pat;
+
+                     if (GET_MODE (reloadreg) != mode)
+                       reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+
+                     if (tertiary_icode != CODE_FOR_nothing)
+                       {
+                         rtx third_reloadreg
+                           = reload_reg_rtx[reload_secondary_reload[secondary_reload]];
+                         pat = (GEN_FCN (tertiary_icode)
+                                (reloadreg, second_reloadreg, third_reloadreg));
+                       }
+#ifdef SECONDARY_MEMORY_NEEDED
+                     /* If we need a memory location to do the move, do it that way.  */
+                     else if (GET_CODE (reloadreg) == REG
+                              && REGNO (reloadreg) < FIRST_PSEUDO_REGISTER
+                              && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (reloadreg)),
+                                          REGNO_REG_CLASS (REGNO (second_reloadreg)),
+                                          GET_MODE (second_reloadreg)))
+                       {
+                         /* Get the memory to use and rewrite both registers
+                            to its mode.  */
+                         rtx loc
+                           = get_secondary_mem (reloadreg,
+                                                GET_MODE (second_reloadreg),
+                                                reload_opnum[j],
+                                                reload_when_needed[j]);
+                         rtx tmp_reloadreg;
+                           
+                         if (GET_MODE (loc) != GET_MODE (second_reloadreg))
+                           second_reloadreg = gen_rtx (REG, GET_MODE (loc),
+                                                       REGNO (second_reloadreg));
+                         
+                         if (GET_MODE (loc) != GET_MODE (reloadreg))
+                           tmp_reloadreg = gen_rtx (REG, GET_MODE (loc),
+                                                    REGNO (reloadreg));
+                         else
+                           tmp_reloadreg = reloadreg;
+                         
+                         emit_move_insn (loc, second_reloadreg);
+                         pat = gen_move_insn (tmp_reloadreg, loc);
+                       }
+#endif
+                     else
+                       pat = gen_move_insn (reloadreg, second_reloadreg);
 
-                 emit_insn_before (pat, first_output_reload_insn);
+                     emit_insn (pat);
+                   }
                }
            }
 #endif
 
          /* Output the last reload insn.  */
          if (! special)
-           emit_insn_before (gen_move_insn (old, reloadreg),
-                             first_output_reload_insn);
+           {
+#ifdef SECONDARY_MEMORY_NEEDED
+             /* If we need a memory location to do the move, do it that way.  */
+             if (GET_CODE (old) == REG && REGNO (old) < FIRST_PSEUDO_REGISTER
+                 && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (old)),
+                                             REGNO_REG_CLASS (REGNO (reloadreg)),
+                                             GET_MODE (reloadreg)))
+               {
+                 /* Get the memory to use and rewrite both registers to
+                    its mode.  */
+                 rtx loc = get_secondary_mem (old, GET_MODE (reloadreg),
+                                              reload_opnum[j],
+                                              reload_when_needed[j]);
+
+                 if (GET_MODE (loc) != GET_MODE (reloadreg))
+                   reloadreg = gen_rtx (REG, GET_MODE (loc),
+                                        REGNO (reloadreg));
+
+                 if (GET_MODE (loc) != GET_MODE (old))
+                   old = gen_rtx (REG, GET_MODE (loc), REGNO (old));
+
+                 emit_insn (gen_move_insn (loc, reloadreg));
+                 emit_insn (gen_move_insn (old, loc));
+               }
+             else
+#endif
+               emit_insn (gen_move_insn (old, reloadreg));
+           }
 
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
          /* If final will look at death notes for this reg,
             put one on the last output-reload insn to use it.  Similarly
             for any secondary register.  */
          if (PRESERVE_DEATH_INFO_REGNO_P (REGNO (reloadreg)))
-           for (p = PREV_INSN (first_output_reload_insn);
-                p != prev_insn; p = PREV_INSN (p))
+           for (p = get_last_insn (); p; p = PREV_INSN (p))
              if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
-                 && reg_overlap_mentioned_p (reloadreg, PATTERN (p)))
+                 && reg_overlap_mentioned_for_reload_p (reloadreg,
+                                                        PATTERN (p)))
                REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
                                         reloadreg, REG_NOTES (p));
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
          if (! special
              && PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
-           for (p = PREV_INSN (first_output_reload_insn);
-                p != prev_insn; p = PREV_INSN (p))
+           for (p = get_last_insn (); p; p = PREV_INSN (p))
              if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
-                 && reg_overlap_mentioned_p (second_reloadreg, PATTERN (p)))
+                 && reg_overlap_mentioned_for_reload_p (second_reloadreg,
+                                                        PATTERN (p)))
                REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
                                         second_reloadreg, REG_NOTES (p));
 #endif
 #endif
          /* Look at all insns we emitted, just to be safe.  */
-         for (p = NEXT_INSN (prev_insn); p != first_output_reload_insn;
-              p = NEXT_INSN (p))
+         for (p = get_insns (); p; p = NEXT_INSN (p))
            if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
              {
                /* If this output reload doesn't come from a spill reg,
@@ -5163,13 +6142,50 @@ emit_reload_insns (insn)
                  store_insn = p;
              }
 
-         first_output_reload_insn = NEXT_INSN (prev_insn);
+         output_reload_insns[reload_opnum[j]] = get_insns ();
+         end_sequence ();
+
        }
 
       if (reload_spill_index[j] >= 0)
        new_spill_reg_store[reload_spill_index[j]] = store_insn;
     }
 
+  /* Now write all the insns we made for reloads in the order expected by
+     the allocation functions.  Prior to the insn being reloaded, we write
+     the following reloads:
+
+     RELOAD_FOR_OTHER_ADDRESS reloads for input addresses.
+
+     RELOAD_OTHER reloads.
+
+     For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
+     the RELOAD_FOR_INPUT reload for the operand.
+
+     RELOAD_FOR_OPERAND_ADDRESS reloads.
+
+     After the insn being reloaded, we write the following:
+
+     For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
+     the RELOAD_FOR_OUTPUT reload for that operand.  */
+
+  emit_insns_before (other_input_address_reload_insns, before_insn);
+  emit_insns_before (other_input_reload_insns, before_insn);
+
+  for (j = 0; j < reload_n_operands; j++)
+    {
+      emit_insns_before (input_address_reload_insns[j], before_insn);
+      emit_insns_before (input_reload_insns[j], before_insn);
+    }
+
+  emit_insns_before (operand_reload_insns, before_insn);
+
+  for (j = 0; j < reload_n_operands; j++)
+    {
+      emit_insns_before (output_address_reload_insns[j], following_insn);
+      emit_insns_before (output_reload_insns[j], following_insn);
+    }
+
   /* Move death notes from INSN
      to output-operand-address and output reload insns.  */
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -5196,8 +6212,10 @@ emit_reload_insns (insn)
              if (REG_NOTE_KIND (reg_notes) == REG_DEAD
                  && GET_CODE (XEXP (reg_notes, 0)) == REG
                  && ((GET_CODE (dest) != REG
-                      && reg_overlap_mentioned_p (XEXP (reg_notes, 0), dest))
-                     || reg_overlap_mentioned_p (XEXP (reg_notes, 0), source)))
+                      && reg_overlap_mentioned_for_reload_p (XEXP (reg_notes, 0),
+                                                             dest))
+                     || reg_overlap_mentioned_for_reload_p (XEXP (reg_notes, 0),
+                                                            source)))
                {
                  *prev_reg_note = next_reg_notes;
                  XEXP (reg_notes, 1) = REG_NOTES (insn1);
@@ -5226,9 +6244,14 @@ emit_reload_insns (insn)
 
       /* I is nonneg if this reload used one of the spill regs.
         If reload_reg_rtx[r] is 0, this is an optional reload
-        that we opted to ignore.  */
+        that we opted to ignore.
 
-      if (i >= 0 && reload_reg_rtx[r] != 0)
+        Also ignore reloads that don't reach the end of the insn,
+        since we will eventually see the one that does.  */
+
+      if (i >= 0 && reload_reg_rtx[r] != 0
+         && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
+                                      reload_when_needed[r]))
        {
          /* First, clear out memory of what used to be in this spill reg.
             If consecutive registers are used, clear them all.  */
@@ -5246,55 +6269,79 @@ emit_reload_insns (insn)
          if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
            {
              register int nregno = REGNO (reload_out[r]);
+             int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+                        : HARD_REGNO_NREGS (nregno,
+                                            GET_MODE (reload_reg_rtx[r])));
 
              spill_reg_store[i] = new_spill_reg_store[i];
              reg_last_reload_reg[nregno] = reload_reg_rtx[r];
 
+             /* If NREGNO is a hard register, it may occupy more than
+                one register.  If it does, say what is in the 
+                rest of the registers assuming that both registers
+                agree on how many words the object takes.  If not,
+                invalidate the subsequent registers.  */
+
+             if (nregno < FIRST_PSEUDO_REGISTER)
+               for (k = 1; k < nnr; k++)
+                 reg_last_reload_reg[nregno + k]
+                   = (nr == nnr ? gen_rtx (REG, word_mode,
+                                           REGNO (reload_reg_rtx[r]) + k)
+                      : 0);
+
+             /* Now do the inverse operation.  */
              for (k = 0; k < nr; k++)
                {
                  reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
-                   = nregno;
+                   = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
+                      : nregno + k);
                  reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
                }
            }
 
-         /* Maybe the spill reg contains a copy of reload_in.  */
+         /* Maybe the spill reg contains a copy of reload_in.  Only do
+            something if there will not be an output reload for
+            the register being reloaded.  */
          else if (reload_out[r] == 0
                   && reload_in[r] != 0
-                  && (GET_CODE (reload_in[r]) == REG
-                      || GET_CODE (reload_in_reg[r]) == REG))
+                  && ((GET_CODE (reload_in[r]) == REG
+                       && ! reg_has_output_reload[REGNO (reload_in[r])]
+                      || (GET_CODE (reload_in_reg[r]) == REG
+                          && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
            {
              register int nregno;
+             int nnr;
+
              if (GET_CODE (reload_in[r]) == REG)
                nregno = REGNO (reload_in[r]);
              else
                nregno = REGNO (reload_in_reg[r]);
 
-             /* If there are two separate reloads (one in and one out)
-                for the same (hard or pseudo) reg,
-                leave reg_last_reload_reg set
-                based on the output reload.
-                Otherwise, set it from this input reload.  */
-             if (!reg_has_output_reload[nregno]
-                 /* But don't do so if another input reload
-                    will clobber this one's value.  */
-                 && reload_reg_reaches_end_p (spill_regs[i],
-                                              reload_when_needed[r]))
-               {
-                 reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+             nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+                    : HARD_REGNO_NREGS (nregno,
+                                        GET_MODE (reload_reg_rtx[r])));
 
-                 /* Unless we inherited this reload, show we haven't
-                    recently done a store.  */
-                 if (! reload_inherited[r])
-                   spill_reg_store[i] = 0;
+             reg_last_reload_reg[nregno] = reload_reg_rtx[r];
 
-                 for (k = 0; k < nr; k++)
-                   {
-                     reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
-                       = nregno;
-                     reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
-                       = insn;
-                   }
+             if (nregno < FIRST_PSEUDO_REGISTER)
+               for (k = 1; k < nnr; k++)
+                 reg_last_reload_reg[nregno + k]
+                   = (nr == nnr ? gen_rtx (REG, word_mode,
+                                           REGNO (reload_reg_rtx[r]) + k)
+                      : 0);
+
+             /* Unless we inherited this reload, show we haven't
+                recently done a store.  */
+             if (! reload_inherited[r])
+               spill_reg_store[i] = 0;
+
+             for (k = 0; k < nr; k++)
+               {
+                 reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
+                   = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
+                      : nregno + k);
+                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
+                   = insn;
                }
            }
        }
@@ -5315,25 +6362,29 @@ emit_reload_insns (insn)
     }
 }
 \f
-/* Emit code before BEFORE_INSN to perform an input reload of IN to RELOADREG.
+/* Emit code to perform an input reload of IN to RELOADREG.  IN is from
+   operand OPNUM with reload type TYPE. 
+
    Returns first insn emitted.  */
 
 rtx
-gen_input_reload (reloadreg, in, before_insn)
+gen_input_reload (reloadreg, in, opnum, type)
      rtx reloadreg;
      rtx in;
-     rtx before_insn;
+     int opnum;
+     enum reload_type type;
 {
-  register rtx prev_insn = PREV_INSN (before_insn);
+  rtx last = get_last_insn ();
 
   /* How to do this reload can get quite tricky.  Normally, we are being
      asked to reload a simple operand, such as a MEM, a constant, or a pseudo
      register that didn't get a hard register.  In that case we can just
      call emit_move_insn.
 
-     We can also be asked to reload a PLUS that adds either two registers or
-     a register and a constant or MEM.  This can occur during frame pointer
-     elimination.  That case if handled by trying to emit a single insn
+     We can also be asked to reload a PLUS that adds either two registers, or
+     a register and a constant or MEM, or a MEM and a constant.  This can
+     occur during frame pointer elimination and while reloading addresses.
+     This case is handled by trying to emit a single insn
      to perform the add.  If it is not valid, we use a two insn sequence.
 
      Finally, we could be called to handle an 'o' constraint by putting
@@ -5352,28 +6403,33 @@ gen_input_reload (reloadreg, in, before_insn)
      ??? At some point, this whole thing needs to be rethought.  */
 
   if (GET_CODE (in) == PLUS
-      && GET_CODE (XEXP (in, 0)) == REG
-      && (GET_CODE (XEXP (in, 1)) == REG
-         || CONSTANT_P (XEXP (in, 1))
-         || GET_CODE (XEXP (in, 1)) == MEM))
+      && ((GET_CODE (XEXP (in, 0)) == REG
+          && (GET_CODE (XEXP (in, 1)) == REG
+              || CONSTANT_P (XEXP (in, 1))
+              || GET_CODE (XEXP (in, 1)) == MEM))
+         || (GET_CODE (XEXP (in, 0)) == MEM
+             && CONSTANT_P (XEXP (in, 1)))))
     {
       /* We need to compute the sum of what is either a register and a
-        constant, a register and memory, or a hard register and a pseudo
-        register and put it into the reload register.  The best possible way
-        of doing this is if the machine has a three-operand ADD insn that
-        accepts the required operands.
+        constant, a register and memory, a hard register and a pseudo
+        register, or memory and a constant and put it into the reload
+        register.  The best possible way of doing this is if the machine
+        has a three-operand ADD insn that accepts the required operands.
 
         The simplest approach is to try to generate such an insn and see if it
         is recognized and matches its constraints.  If so, it can be used.
 
         It might be better not to actually emit the insn unless it is valid,
-        but we need to pass the insn as an operand to `recog' and it is
-        simpler to emit and then delete the insn if not valid than to
-        dummy things up.  */
+        but we need to pass the insn as an operand to `recog' and
+        `insn_extract' and it is simpler to emit and then delete the insn if
+        not valid than to dummy things up.  */
 
-      rtx move_operand, other_operand, insn;
+      rtx op0, op1, tem, insn;
       int code;
 
+      op0 = find_replacement (&XEXP (in, 0));
+      op1 = find_replacement (&XEXP (in, 1));
+
       /* Since constraint checking is strict, commutativity won't be
         checked, so we need to do that here to avoid spurious failure
         if the add instruction is two-address and the second operand
@@ -5383,10 +6439,12 @@ gen_input_reload (reloadreg, in, before_insn)
 
       if (GET_CODE (XEXP (in, 1)) == REG
          && REGNO (reloadreg) == REGNO (XEXP (in, 1)))
-       in = gen_rtx (PLUS, GET_MODE (in), XEXP (in, 1), XEXP (in, 0));
+       tem = op0, op0 = op1, op1 = tem;
+
+      if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
+       in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
 
-      insn = emit_insn_before (gen_rtx (SET, VOIDmode, reloadreg, in),
-                                  before_insn);
+      insn = emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
       code = recog_memoized (insn);
 
       if (code >= 0)
@@ -5399,51 +6457,75 @@ gen_input_reload (reloadreg, in, before_insn)
            return insn;
        }
 
-      if (PREV_INSN (insn))
-       NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
-      if (NEXT_INSN (insn))
-       PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+      delete_insns_since (last);
 
       /* If that failed, we must use a conservative two-insn sequence.
         use move to copy constant, MEM, or pseudo register to the reload
-        register since "move" will be able to handle arbitrary operand, unlike
-        add which can't, in general.  Then add the registers.
+        register since "move" will be able to handle an arbitrary operand,
+        unlike add which can't, in general.  Then add the registers.
 
         If there is another way to do this for a specific machine, a
         DEFINE_PEEPHOLE should be specified that recognizes the sequence
         we emit below.  */
 
-      if (CONSTANT_P (XEXP (in, 1))
-         || (GET_CODE (XEXP (in, 1)) == REG
-             && REGNO (XEXP (in, 1)) >= FIRST_PSEUDO_REGISTER))
-       move_operand = XEXP (in, 1), other_operand = XEXP (in, 0);
-      else
-       move_operand = XEXP (in, 0), other_operand = XEXP (in, 1);
+      if (CONSTANT_P (op1) || GET_CODE (op1) == MEM
+         || (GET_CODE (op1) == REG
+             && REGNO (op1) >= FIRST_PSEUDO_REGISTER))
+       tem = op0, op0 = op1, op1 = tem;
+
+      emit_insn (gen_move_insn (reloadreg, op0));
+
+      /* If OP0 and OP1 are the same, we can use RELOADREG for OP1.
+        This fixes a problem on the 32K where the stack pointer cannot
+        be used as an operand of an add insn.  */
+
+      if (rtx_equal_p (op0, op1))
+       op1 = reloadreg;
+
+      emit_insn (gen_add2_insn (reloadreg, op1));
+    }
+
+#ifdef SECONDARY_MEMORY_NEEDED
+  /* If we need a memory location to do the move, do it that way.  */
+  else if (GET_CODE (in) == REG && REGNO (in) < FIRST_PSEUDO_REGISTER
+          && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
+                                      REGNO_REG_CLASS (REGNO (reloadreg)),
+                                      GET_MODE (reloadreg)))
+    {
+      /* Get the memory to use and rewrite both registers to its mode.  */
+      rtx loc = get_secondary_mem (in, GET_MODE (reloadreg), opnum, type);
 
-      emit_insn_before (gen_move_insn (reloadreg, move_operand), before_insn);
-      emit_insn_before (gen_add2_insn (reloadreg, other_operand), before_insn);
+      if (GET_MODE (loc) != GET_MODE (reloadreg))
+       reloadreg = gen_rtx (REG, GET_MODE (loc), REGNO (reloadreg));
+
+      if (GET_MODE (loc) != GET_MODE (in))
+       in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
+
+      emit_insn (gen_move_insn (loc, in));
+      emit_insn (gen_move_insn (reloadreg, loc));
     }
+#endif
 
   /* If IN is a simple operand, use gen_move_insn.  */
   else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
-    emit_insn_before (gen_move_insn (reloadreg, in), before_insn);
+    emit_insn (gen_move_insn (reloadreg, in));
 
 #ifdef HAVE_reload_load_address
   else if (HAVE_reload_load_address)
-    emit_insn_before (gen_reload_load_address (reloadreg, in), before_insn);
+    emit_insn (gen_reload_load_address (reloadreg, in));
 #endif
 
   /* Otherwise, just write (set REGLOADREG IN) and hope for the best.  */
   else
-    emit_insn_before (gen_rtx (SET, VOIDmode, reloadreg, in), before_insn);
+    emit_insn (gen_rtx (SET, VOIDmode, reloadreg, in));
 
   /* Return the first insn emitted.
-     We can not just return PREV_INSN (before_insn), because there may have
+     We can not just return get_last_insn, because there may have
      been multiple instructions emitted.  Also note that gen_move_insn may
      emit more than one insn itself, so we can not assume that there is one
      insn emitted per emit_insn_before call.  */
 
-  return NEXT_INSN (prev_insn);
+  return last ? NEXT_INSN (last) : get_insns ();
 }
 \f
 /* Delete a previously made output-reload
@@ -5483,6 +6565,9 @@ delete_output_reload (insn, j, output_reload_insn)
        return;
     }
 
+  if (cannot_omit_stores[REGNO (reg)])
+    return;
+
   /* If this insn will store in the pseudo again,
      the previous store can be removed.  */
   if (reload_out[j] == reload_in[j])
@@ -5538,31 +6623,29 @@ delete_output_reload (insn, j, output_reload_insn)
       alter_reg (REGNO (reg), -1);
     }
 }
-
 \f
 /* Output reload-insns to reload VALUE into RELOADREG.
-   VALUE is a autoincrement or autodecrement RTX whose operand
+   VALUE is an autoincrement or autodecrement RTX whose operand
    is a register or memory location;
    so reloading involves incrementing that location.
 
    INC_AMOUNT is the number to increment or decrement by (always positive).
-   This cannot be deduced from VALUE.
+   This cannot be deduced from VALUE.  */
 
-   INSN is the insn before which the new insns should be emitted.
-
-   The return value is the first of the insns emitted.  */
-
-static rtx
-inc_for_reload (reloadreg, value, inc_amount, insn)
+static void
+inc_for_reload (reloadreg, value, inc_amount)
      rtx reloadreg;
      rtx value;
      int inc_amount;
-     rtx insn;
 {
   /* REG or MEM to be copied and incremented.  */
   rtx incloc = XEXP (value, 0);
   /* Nonzero if increment after copying.  */
   int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC);
+  rtx last;
+  rtx inc;
+  rtx add_insn;
+  int code;
 
   /* No hard register is equivalent to this register after
      inc/dec operation.  If REG_LAST_RELOAD_REG were non-zero,
@@ -5574,78 +6657,67 @@ inc_for_reload (reloadreg, value, inc_amount, insn)
   if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC)
     inc_amount = - inc_amount;
 
-  /* First handle preincrement, which is simpler.  */
-  if (! post)
+  inc = GEN_INT (inc_amount);
+
+  /* If this is post-increment, first copy the location to the reload reg.  */
+  if (post)
+    emit_insn (gen_move_insn (reloadreg, incloc));
+
+  /* See if we can directly increment INCLOC.  Use a method similar to that
+     in gen_input_reload.  */
+
+  last = get_last_insn ();
+  add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,
+                                gen_rtx (PLUS, GET_MODE (incloc),
+                                         incloc, inc)));
+                                                         
+  code = recog_memoized (add_insn);
+  if (code >= 0)
     {
-      /* If incrementing a register, assume we can
-        output an insn to increment it directly.  */
-      if (GET_CODE (incloc) == REG &&
-         (REGNO (incloc) < FIRST_PSEUDO_REGISTER
-          || reg_renumber[REGNO (incloc)] >= 0))
-       {
-         rtx first_new
-           = emit_insn_before (gen_add2_insn (incloc,
-                                              gen_rtx (CONST_INT, VOIDmode,
-                                                       inc_amount)),
-                               insn);
-         emit_insn_before (gen_move_insn (reloadreg, incloc), insn);
-         return first_new;
-       }
-      else
-       /* Else we must not assume we can increment the location directly
-          (even though on many target machines we can);
-          copy it to the reload register, increment there, then save back.  */
+      insn_extract (add_insn);
+      if (constrain_operands (code, 1))
        {
-         rtx first_new
-           = emit_insn_before (gen_move_insn (reloadreg, incloc), insn);
-         emit_insn_before (gen_add2_insn (reloadreg,
-                                          gen_rtx (CONST_INT, VOIDmode,
-                                                   inc_amount)),
-                           insn);
-         emit_insn_before (gen_move_insn (incloc, reloadreg), insn);
-         return first_new;
+         /* If this is a pre-increment and we have incremented the value
+            where it lives, copy the incremented value to RELOADREG to
+            be used as an address.  */
+
+         if (! post)
+           emit_insn (gen_move_insn (reloadreg, incloc));
+
+         return;
        }
     }
-  /* Postincrement.
-     Because this might be a jump insn or a compare, and because RELOADREG
-     may not be available after the insn in an input reload,
-     we must do the incrementation before the insn being reloaded for.  */
+
+  delete_insns_since (last);
+
+  /* If couldn't do the increment directly, must increment in RELOADREG.
+     The way we do this depends on whether this is pre- or post-increment.
+     For pre-increment, copy INCLOC to the reload register, increment it
+     there, then save back.  */
+
+  if (! post)
+    {
+      emit_insn (gen_move_insn (reloadreg, incloc));
+      emit_insn (gen_add2_insn (reloadreg, inc));
+      emit_insn (gen_move_insn (incloc, reloadreg));
+    }
   else
     {
-      /* Copy the value, then increment it.  */
-      rtx first_new
-       = emit_insn_before (gen_move_insn (reloadreg, incloc), insn);
-
-      /* If incrementing a register, assume we can
-        output an insn to increment it directly.  */
-      if (GET_CODE (incloc) == REG &&
-         (REGNO (incloc) < FIRST_PSEUDO_REGISTER
-          || reg_renumber[REGNO (incloc)] >= 0))
-       {
-         emit_insn_before (gen_add2_insn (incloc,
-                                          gen_rtx (CONST_INT, VOIDmode,
-                                                   inc_amount)),
-                           insn);
-       }
-      else
-       /* Else we must not assume we can increment INCLOC
-          (even though on many target machines we can);
-          increment the copy in the reload register,
-          save that back, then decrement the reload register
-          so it has the original value.  */
-       {
-         emit_insn_before (gen_add2_insn (reloadreg,
-                                          gen_rtx (CONST_INT, VOIDmode,
-                                                   inc_amount)),
-                           insn);
-         emit_insn_before (gen_move_insn (incloc, reloadreg), insn);
-         emit_insn_before (gen_sub2_insn (reloadreg,
-                                          gen_rtx (CONST_INT, VOIDmode,
-                                                   inc_amount)),
-                           insn);
-       }
-      return first_new;
+      /* Postincrement.
+        Because this might be a jump insn or a compare, and because RELOADREG
+        may not be available after the insn in an input reload, we must do
+        the incrementation before the insn being reloaded for.
+
+        We have already copied INCLOC to RELOADREG.  Increment the copy in
+        RELOADREG, save that back, then decrement RELOADREG so it has
+        the original value.  */
+
+      emit_insn (gen_add2_insn (reloadreg, inc));
+      emit_insn (gen_move_insn (incloc, reloadreg));
+      emit_insn (gen_add2_insn (reloadreg, GEN_INT (-inc_amount)));
     }
+
+  return;
 }
 \f
 /* Return 1 if we are certain that the constraint-string STRING allows
@@ -5685,9 +6757,9 @@ constraint_accepts_reg_p (string, reg)
       default:
        /* Any reg in specified class wins for this alternative.  */
        {
-         int class = REG_CLASS_FROM_LETTER (c);
+         enum reg_class class = REG_CLASS_FROM_LETTER (c);
 
-         if (TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+         if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno))
            value = 1;
        }
       }