OSDN Git Service

Don't assume a SUBREG can not conflict with a MEM
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 5343e2d..61b8d01 100644 (file)
@@ -1,5 +1,5 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
-   Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -79,7 +79,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 \f
 /* During reload_as_needed, element N contains a REG rtx for the hard reg
-   into which 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
@@ -170,6 +170,13 @@ static HARD_REG_SET bad_spill_regs;
    elements that are actually valid; new ones are added at the end.  */
 static short spill_regs[FIRST_PSEUDO_REGISTER];
 
+/* This reg set indicates those registers that have been used a spill
+   registers.  This information is used in reorg.c, to help figure out
+   what registers are live at any point.  It is assumed that all spill_regs
+   are dead at every CODE_LABEL.  */
+
+HARD_REG_SET used_spill_regs;
+
 /* Index of last register assigned as a spill register.  We allocate in
    a round-robin fashion.  */
 
@@ -246,6 +253,18 @@ int reload_first_uid;
 
 int caller_save_needed;
 
+/* The register class to use for a base register when reloading an
+   address.  This is normally BASE_REG_CLASS, but it may be different
+   when using SMALL_REGISTER_CLASSES and passing parameters in
+   registers.  */
+enum reg_class reload_address_base_reg_class;
+
+/* The register class to use for an index register when reloading an
+   address.  This is normally INDEX_REG_CLASS, but it may be different
+   when using SMALL_REGISTER_CLASSES and passing parameters in
+   registers.  */
+enum reg_class reload_address_index_reg_class;
+
 /* Set to 1 while reload_as_needed is operating.
    Required by some machines to handle any generated moves differently.  */
 
@@ -270,6 +289,9 @@ char *reload_firstobj;
 
 /* List of labels that must never be deleted.  */
 extern rtx forced_labels;
+
+/* Allocation number table from global register allocation.  */
+extern int *reg_allocno;
 \f
 /* This structure is used to record information about register eliminations.
    Each array entry describes one possible way of eliminating a register
@@ -278,22 +300,22 @@ extern rtx forced_labels;
 
 static struct elim_table
 {
-  int from;                    /* Register number to be eliminated. */
-  int to;                      /* Register number used as replacement. */
-  int initial_offset;          /* Initial difference between values. */
-  int can_eliminate;           /* Non-zero if this elimination can be done. */
+  int from;                    /* Register number to be eliminated.  */
+  int to;                      /* Register number used as replacement.  */
+  int initial_offset;          /* Initial difference between values.  */
+  int can_eliminate;           /* Non-zero if this elimination can be done.  */
   int can_eliminate_previous;  /* Value of CAN_ELIMINATE in previous scan over
-                                  insns made by reload. */
-  int offset;                  /* Current offset between the two regs. */
-  int max_offset;              /* Maximum offset between the two regs. */
-  int previous_offset;         /* Offset at end of previous insn. */
-  int ref_outside_mem;         /* "to" has been referenced outside a MEM. */
+                                  insns made by reload.  */
+  int offset;                  /* Current offset between the two regs.  */
+  int max_offset;              /* Maximum offset between the two regs.  */
+  int previous_offset;         /* Offset at end of previous insn.  */
+  int ref_outside_mem;         /* "to" has been referenced outside a MEM.  */
   rtx from_rtx;                        /* REG rtx for the register to be eliminated.
                                   We cannot simply compare the number since
                                   we might then spuriously replace a hard
                                   register corresponding to a pseudo
-                                  assigned to the reg to be eliminated. */
-  rtx to_rtx;                  /* REG rtx for the replacement. */
+                                  assigned to the reg to be eliminated.  */
+  rtx to_rtx;                  /* REG rtx for the replacement.  */
 } reg_eliminate[] =
 
 /* If a set of eliminable registers was specified, define the table from it.
@@ -349,13 +371,12 @@ 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 int compare_spill_regs          PROTO((short *, short *));
+static int hard_reg_use_compare                PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void order_regs_for_reload      PROTO((int));
+static int compare_spill_regs          PROTO((const GENERIC_PTR, const GENERIC_PTR));
 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 int reload_reg_class_lower      PROTO((const GENERIC_PTR, const GENERIC_PTR));
 static void mark_reload_reg_in_use     PROTO((int, int, enum reload_type,
                                               enum machine_mode));
 static void clear_reload_reg_in_use    PROTO((int, int, enum reload_type,
@@ -372,6 +393,17 @@ 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));
+static void reload_cse_invalidate_regno        PROTO((int, enum machine_mode, int));
+static int reload_cse_mem_conflict_p   PROTO((rtx, rtx, enum machine_mode,
+                                              rtx));
+static void reload_cse_invalidate_mem  PROTO((rtx));
+static void reload_cse_invalidate_rtx  PROTO((rtx, rtx));
+static void reload_cse_regs            PROTO((rtx));
+static int reload_cse_regno_equal_p    PROTO((int, rtx, enum machine_mode));
+static int reload_cse_noop_set_p       PROTO((rtx, rtx));
+static void reload_cse_simplify_set    PROTO((rtx, rtx));
+static void reload_cse_check_clobber   PROTO((rtx, rtx));
+static void reload_cse_record_set      PROTO((rtx, rtx));
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -419,9 +451,69 @@ init_reload ()
        }
     }
 
-  /* Initialize obstack for our rtl allocation. */
+  /* Initialize obstack for our rtl allocation.  */
   gcc_obstack_init (&reload_obstack);
   reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+  /* Decide which register class should be used when reloading
+     addresses.  If we are using SMALL_REGISTER_CLASSES, and any
+     parameters are passed in registers, then we do not want to use
+     those registers when reloading an address.  Otherwise, if a
+     function argument needs a reload, we may wind up clobbering
+     another argument to the function which was already computed.  If
+     we find a subset class which simply avoids those registers, we
+     use it instead.  ??? It would be better to only use the
+     restricted class when we actually are loading function arguments,
+     but that is hard to determine.  */
+  reload_address_base_reg_class = BASE_REG_CLASS;
+  reload_address_index_reg_class = INDEX_REG_CLASS;
+#ifdef SMALL_REGISTER_CLASSES
+  if (SMALL_REGISTER_CLASSES)
+    {
+      int regno;
+      HARD_REG_SET base, index;
+      enum reg_class *p;
+
+      COPY_HARD_REG_SET (base, reg_class_contents[BASE_REG_CLASS]);
+      COPY_HARD_REG_SET (index, reg_class_contents[INDEX_REG_CLASS]);
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       {
+         if (FUNCTION_ARG_REGNO_P (regno))
+           {
+             CLEAR_HARD_REG_BIT (base, regno);
+             CLEAR_HARD_REG_BIT (index, regno);
+           }
+       }
+      
+      GO_IF_HARD_REG_EQUAL (base, reg_class_contents[BASE_REG_CLASS],
+                           baseok);
+      for (p = reg_class_subclasses[BASE_REG_CLASS];
+          *p != LIM_REG_CLASSES;
+          p++)
+       {
+         GO_IF_HARD_REG_EQUAL (base, reg_class_contents[*p], usebase);
+         continue;
+       usebase:
+         reload_address_base_reg_class = *p;
+         break;
+       }
+    baseok:;
+
+      GO_IF_HARD_REG_EQUAL (index, reg_class_contents[INDEX_REG_CLASS],
+                           indexok);
+      for (p = reg_class_subclasses[INDEX_REG_CLASS];
+          *p != LIM_REG_CLASSES;
+          p++)
+       {
+         GO_IF_HARD_REG_EQUAL (index, reg_class_contents[*p], useindex);
+         continue;
+       useindex:
+         reload_address_index_reg_class = *p;
+         break;
+       }
+    indexok:;
+    }
+#endif /* SMALL_REGISTER_CLASSES */
 }
 
 /* Main entry point for the reload pass.
@@ -497,10 +589,18 @@ reload (first, global, dumpfile)
      as homes for pseudo registers.
      This is done here rather than (eg) in global_alloc
      because this point is reached even if not optimizing.  */
-
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
     mark_home_live (i);
 
+  /* A function that receives a nonlocal goto must save all call-saved
+     registers.  */
+  if (current_function_has_nonlocal_label)
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      {
+       if (! call_used_regs[i] && ! fixed_regs[i])
+         regs_ever_live[i] = 1;
+      }
+
   for (i = 0; i < scratch_list_length; i++)
     if (scratch_list[i])
       mark_scratch_live (scratch_list[i]);
@@ -535,18 +635,27 @@ reload (first, global, dumpfile)
   bzero (cannot_omit_stores, max_regno);
 
 #ifdef SMALL_REGISTER_CLASSES
-  CLEAR_HARD_REG_SET (forbidden_regs);
+  if (SMALL_REGISTER_CLASSES)
+    CLEAR_HARD_REG_SET (forbidden_regs);
 #endif
 
   /* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
      Also find all paradoxical subregs and find largest such for each pseudo.
      On machines with small register classes, record hard registers that
-     are used for user variables.  These can never be used for spills.  */
+     are used for user variables.  These can never be used for spills. 
+     Also look for a "constant" NOTE_INSN_SETJMP.  This means that all
+     caller-saved registers must be marked live.  */
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       rtx set = single_set (insn);
 
+      if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+         if (! call_used_regs[i])
+           regs_ever_live[i] = 1;
+
       if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
        {
          rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
@@ -657,11 +766,6 @@ reload (first, global, dumpfile)
   for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
     alter_reg (i, -1);
 
-  /* Round size of stack frame to BIGGEST_ALIGNMENT.  This must be done here
-     because the stack size may be a part of the offset computation for
-     register elimination.   */
-  assign_stack_local (BLKmode, 0, 0);
-
   /* If we have some registers we think can be eliminated, scan all insns to
      see if there is an insn that sets one of these registers to something
      other than itself plus a constant.  If so, the register cannot be
@@ -691,7 +795,7 @@ reload (first, global, dumpfile)
   /* Compute the order of preference for hard registers to spill.
      Store them by decreasing preference in potential_reload_regs.  */
 
-  order_regs_for_reload ();
+  order_regs_for_reload (global);
 
   /* So far, no hard regs have been spilled.  */
   n_spills = 0;
@@ -705,9 +809,10 @@ reload (first, global, dumpfile)
      rtl as a spill register.  But on some, we have to.  Those will have
      taken care to keep the life of hard regs as short as possible.  */
 
-#ifndef SMALL_REGISTER_CLASSES
-  COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
+#ifdef SMALL_REGISTER_CLASSES
+  if (! SMALL_REGISTER_CLASSES)
 #endif
+    COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
 
   /* Spill any hard regs that we know we can't eliminate.  */
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -770,7 +875,7 @@ reload (first, global, dumpfile)
       rtx max_groups_insn[N_REG_CLASSES];
       rtx max_nongroups_insn[N_REG_CLASSES];
       rtx x;
-      int starting_frame_size = get_frame_size ();
+      HOST_WIDE_INT starting_frame_size;
       int previous_frame_pointer_needed = frame_pointer_needed;
       static char *reg_class_names[] = REG_CLASS_NAMES;
 
@@ -792,6 +897,14 @@ reload (first, global, dumpfile)
         changes from 0 to 1 in this pass.  */
       new_basic_block_needs = 0;
 
+      /* Round size of stack frame to BIGGEST_ALIGNMENT.  This must be done
+        here because the stack size may be a part of the offset computation
+        for register elimination, and there might have been new stack slots
+        created in the last iteration of this loop.   */
+      assign_stack_local (BLKmode, 0, 0);
+
+      starting_frame_size = get_frame_size ();
+
       /* Reset all offsets on eliminable registers to their initial values.  */
 #ifdef ELIMINABLE_REGS
       for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -852,7 +965,7 @@ 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, NULL_RTX);
+           rtx x = eliminate_regs (reg_equiv_memory_loc[i], 0, NULL_RTX, 0);
 
            if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]),
                                         XEXP (x, 0)))
@@ -959,7 +1072,9 @@ reload (first, global, dumpfile)
                struct needs op_addr;
                struct needs op_addr_reload;
                struct needs in_addr[MAX_RECOG_OPERANDS];
+               struct needs in_addr_addr[MAX_RECOG_OPERANDS];
                struct needs out_addr[MAX_RECOG_OPERANDS];
+               struct needs out_addr_addr[MAX_RECOG_OPERANDS];
              } insn_needs;
 
              /* If needed, eliminate any eliminable registers.  */
@@ -969,7 +1084,7 @@ reload (first, global, dumpfile)
 #ifdef SMALL_REGISTER_CLASSES
              /* Set avoid_return_reg if this is an insn
                 that might use the value of a function call.  */
-             if (GET_CODE (insn) == CALL_INSN)
+             if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
                {
                  if (GET_CODE (PATTERN (insn)) == SET)
                    after_call = SET_DEST (PATTERN (insn));
@@ -979,7 +1094,8 @@ reload (first, global, dumpfile)
                  else
                    after_call = 0;
                }
-             else if (after_call != 0
+             else if (SMALL_REGISTER_CLASSES
+                      && after_call != 0
                       && !(GET_CODE (PATTERN (insn)) == SET
                            && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
                {
@@ -1118,9 +1234,15 @@ reload (first, global, dumpfile)
                    case RELOAD_FOR_INPUT_ADDRESS:
                      this_needs = &insn_needs.in_addr[reload_opnum[i]];
                      break;
+                   case RELOAD_FOR_INPADDR_ADDRESS:
+                     this_needs = &insn_needs.in_addr_addr[reload_opnum[i]];
+                     break;
                    case RELOAD_FOR_OUTPUT_ADDRESS:
                      this_needs = &insn_needs.out_addr[reload_opnum[i]];
                      break;
+                   case RELOAD_FOR_OUTADDR_ADDRESS:
+                     this_needs = &insn_needs.out_addr_addr[reload_opnum[i]];
+                     break;
                    case RELOAD_FOR_OPERAND_ADDRESS:
                      this_needs = &insn_needs.op_addr;
                      break;
@@ -1194,15 +1316,21 @@ reload (first, global, dumpfile)
                        {
                          in_max
                            = MAX (in_max, insn_needs.in_addr[k].regs[j][i]);
+                         in_max
+                           = MAX (in_max,
+                                  insn_needs.in_addr_addr[k].regs[j][i]);
                          out_max
                            = MAX (out_max, insn_needs.out_addr[k].regs[j][i]);
+                         out_max
+                           = MAX (out_max,
+                                  insn_needs.out_addr_addr[k].regs[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. */
+                        outputs.  */
 
                      in_max = MAX (MAX (insn_needs.op_addr.regs[j][i],
                                         insn_needs.op_addr_reload.regs[j][i]),
@@ -1229,8 +1357,12 @@ reload (first, global, dumpfile)
                       j < reload_n_operands; j++)
                    {
                      in_max = MAX (in_max, insn_needs.in_addr[j].groups[i]);
+                     in_max = MAX (in_max,
+                                    insn_needs.in_addr_addr[j].groups[i]);
                      out_max
                        = MAX (out_max, insn_needs.out_addr[j].groups[i]);
+                     out_max
+                       = MAX (out_max, insn_needs.out_addr_addr[j].groups[i]);
                    }
 
                  in_max = MAX (MAX (insn_needs.op_addr.groups[i],
@@ -1327,7 +1459,7 @@ reload (first, global, dumpfile)
                 This makes sure we have a register available that does
                 not overlap the return value.  */
 
-             if (avoid_return_reg)
+             if (SMALL_REGISTER_CLASSES && avoid_return_reg)
                {
                  int regno = REGNO (avoid_return_reg);
                  int nregs
@@ -1360,7 +1492,7 @@ reload (first, global, dumpfile)
                    }
 
                  /* Now count extra regs if there might be a conflict with
-                    the return value register. */
+                    the return value register.  */
 
                  for (r = regno; r < regno + nregs; r++)
                    if (spill_reg_order[r] >= 0)
@@ -1442,19 +1574,26 @@ reload (first, global, dumpfile)
       /* If we have caller-saves, set up the save areas and see if caller-save
         will need a spill register.  */
 
-      if (caller_save_needed
-         && ! setup_save_areas (&something_changed)
-         && caller_save_spill_class  == NO_REGS)
+      if (caller_save_needed)
        {
-         /* The class we will need depends on whether the machine
-            supports the sum of two registers for an address; see
-            find_address_reloads for details.  */
-
-         caller_save_spill_class
-           = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
-         caller_save_group_size
-           = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
-         something_changed = 1;
+         /* Set the offsets for setup_save_areas.  */
+         for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+              ep++)
+           ep->previous_offset = ep->max_offset;
+
+         if ( ! setup_save_areas (&something_changed)
+             && caller_save_spill_class  == NO_REGS)
+           {
+             /* The class we will need depends on whether the machine
+                supports the sum of two registers for an address; see
+             find_address_reloads for details.  */
+
+             caller_save_spill_class
+               = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
+             caller_save_group_size
+               = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
+             something_changed = 1;
+           }
        }
 
       /* See if anything that happened changes which eliminations are valid.
@@ -1678,7 +1817,7 @@ reload (first, global, dumpfile)
                  /* We can't complete a group, so start one.  */
 #ifdef SMALL_REGISTER_CLASSES
                  /* Look for a pair neither of which is explicitly used.  */
-                 if (i == FIRST_PSEUDO_REGISTER)
+                 if (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER)
                    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                      {
                        int k;
@@ -1808,10 +1947,6 @@ 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.  */
@@ -1835,7 +1970,6 @@ reload (first, global, dumpfile)
                    }
              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.
@@ -1991,6 +2125,10 @@ reload (first, global, dumpfile)
        }
     }
 
+  /* Do a very simple CSE pass over just the hard registers.  */
+  if (optimize > 0)
+    reload_cse_regs (first);
+
 #ifdef PRESERVE_DEATH_INFO_REGNO_P
   /* Make a pass over all the insns and remove death notes for things that
      are no longer registers or no longer die in the insn (e.g., an input
@@ -2023,6 +2161,10 @@ reload (first, global, dumpfile)
     free (scratch_block);
   scratch_block = 0;
 
+  CLEAR_HARD_REG_SET (used_spill_regs);
+  for (i = 0; i < n_spills; i++)
+    SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
+
   return failure;
 }
 \f
@@ -2349,7 +2491,8 @@ alter_reg (i, from_reg)
       if (from_reg == -1)
        {
          /* No known place to spill from => no slot to reuse.  */
-         x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
+         x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
+                                 inherent_size == total_size ? 0 : -1);
          if (BYTES_BIG_ENDIAN)
            /* Cancel the  big-endian correction done in assign_stack_local.
               Get the address of the beginning of the slot.
@@ -2381,7 +2524,8 @@ alter_reg (i, from_reg)
                total_size = spill_stack_slot_width[from_reg];
            }
          /* Make a slot with that size.  */
-         x = assign_stack_local (mode, total_size, -1);
+         x = assign_stack_local (mode, total_size,
+                                 inherent_size == total_size ? 0 : -1);
          stack_slot = x;
          if (BYTES_BIG_ENDIAN)
            {
@@ -2478,7 +2622,7 @@ set_label_offsets (x, insn, initial_p)
 
       x = XEXP (x, 0);
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case CODE_LABEL:
       /* If we know nothing about this label, set the desired offsets.  Note
@@ -2533,7 +2677,7 @@ set_label_offsets (x, insn, initial_p)
     case JUMP_INSN:
       set_label_offsets (PATTERN (insn), insn, initial_p);
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case INSN:
     case CALL_INSN:
@@ -2638,10 +2782,11 @@ static struct rtvec_def *old_asm_operands_vec, *new_asm_operands_vec;
    the proper thing.  */
 
 rtx
-eliminate_regs (x, mem_mode, insn)
+eliminate_regs (x, mem_mode, insn, storing)
      rtx x;
      enum machine_mode mem_mode;
      rtx insn;
+     int storing;
 {
   enum rtx_code code = GET_CODE (x);
   struct elim_table *ep;
@@ -2698,7 +2843,7 @@ eliminate_regs (x, mem_mode, insn)
             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, insn);
+                               mem_mode, insn, 0);
          if (new != reg_equiv_memory_loc[regno])
            {
              cannot_omit_stores[regno] = 1;
@@ -2760,8 +2905,8 @@ eliminate_regs (x, mem_mode, insn)
         reload.  This is the desired action.  */
 
       {
-       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn);
-       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn);
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
+       rtx new1 = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0);
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          {
@@ -2818,7 +2963,7 @@ eliminate_regs (x, mem_mode, insn)
                               ep->previous_offset * INTVAL (XEXP (x, 1)));
            }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case CALL:
     case COMPARE:
@@ -2832,9 +2977,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, insn);
+       rtx new0 = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
        rtx new1
-         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
+         = XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn, 0) : 0;
 
        if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
          return gen_rtx (code, GET_MODE (x), new0, new1);
@@ -2845,12 +2990,12 @@ 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, insn);
+         new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
          if (new != XEXP (x, 0))
            x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1));
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case INSN_LIST:
       /* Now do eliminations in the rest of the chain.  If this was
@@ -2858,7 +3003,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, insn);
+         new = eliminate_regs (XEXP (x, 1), mem_mode, insn, 0);
          if (new != XEXP (x, 1))
            return gen_rtx (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
        }
@@ -2885,7 +3030,6 @@ eliminate_regs (x, mem_mode, insn)
          }
 
       /* Fall through to generic unary operation case.  */
-    case USE:
     case STRICT_LOW_PART:
     case NEG:          case NOT:
     case SIGN_EXTEND:  case ZERO_EXTEND:
@@ -2895,7 +3039,7 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
       if (new != XEXP (x, 0))
        return gen_rtx (code, GET_MODE (x), new);
       return x;
@@ -2914,7 +3058,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, insn);
+                               mem_mode, insn, 0);
 
          /* If we didn't change anything, we must retain the pseudo.  */
          if (new == reg_equiv_memory_loc[REGNO (SUBREG_REG (x))])
@@ -2934,27 +3078,37 @@ eliminate_regs (x, mem_mode, insn)
            }
        }
       else
-       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn);
+       new = eliminate_regs (SUBREG_REG (x), mem_mode, insn, 0);
 
       if (new != XEXP (x, 0))
        {
-         if (GET_CODE (new) == MEM
-             && (GET_MODE_SIZE (GET_MODE (x))
-                 <= GET_MODE_SIZE (GET_MODE (new)))
+         int x_size = GET_MODE_SIZE (GET_MODE (x));
+         int new_size = GET_MODE_SIZE (GET_MODE (new));
+
+         /* When asked to spill a partial word subreg, we need to go
+            ahead and spill the whole thing against the possibility
+            that we reload the whole reg and find garbage at the top.  */
+         if (storing
+             && GET_CODE (new) == MEM
+             && x_size < new_size
+             && ((x_size + UNITS_PER_WORD-1) / UNITS_PER_WORD
+                 == (new_size + UNITS_PER_WORD-1) / UNITS_PER_WORD))
+           return new;
+         else if (GET_CODE (new) == MEM
+                  && x_size <= new_size
 #ifdef LOAD_EXTEND_OP
-             /* 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
-                   && (GET_MODE_SIZE (GET_MODE (x))
-                       > GET_MODE_SIZE (GET_MODE (new)))
-                   && INTEGRAL_MODE_P (GET_MODE (new))
-                   && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
+                  /* 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
+                        && x_size <= UNITS_PER_WORD
+                        && new_size <= UNITS_PER_WORD
+                        && x_size > new_size
+                        && INTEGRAL_MODE_P (GET_MODE (new))
+                        && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
 #endif
-             )
+                  )
            {
              int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
              enum machine_mode mode = GET_MODE (x);
@@ -2974,6 +3128,19 @@ eliminate_regs (x, mem_mode, insn)
 
       return x;
 
+    case USE:
+      /* If using a register that is the source of an eliminate we still
+        think can be performed, note it cannot be performed since we don't
+        know how this register is used.  */
+      for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+       if (ep->from_rtx == XEXP (x, 0))
+         ep->can_eliminate = 0;
+
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
+      if (new != XEXP (x, 0))
+       return gen_rtx (code, GET_MODE (x), new);
+      return x;
+
     case CLOBBER:
       /* If clobbering a register that is the replacement register for an
         elimination we still think can be performed, note that it cannot
@@ -2982,7 +3149,7 @@ eliminate_regs (x, mem_mode, insn)
        if (ep->to_rtx == XEXP (x, 0))
          ep->can_eliminate = 0;
 
-      new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+      new = eliminate_regs (XEXP (x, 0), mem_mode, insn, 0);
       if (new != XEXP (x, 0))
        return gen_rtx (code, GET_MODE (x), new);
       return x;
@@ -3000,7 +3167,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, insn);
+                                           mem_mode, insn, 0);
 
            for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
              if (temp_vec[i] != ASM_OPERANDS_INPUT (x, i))
@@ -3071,8 +3238,8 @@ eliminate_regs (x, mem_mode, insn)
 
       /* Now avoid the loop below in this common case.  */
       {
-       rtx new0 = eliminate_regs (SET_DEST (x), 0, insn);
-       rtx new1 = eliminate_regs (SET_SRC (x), 0, insn);
+       rtx new0 = eliminate_regs (SET_DEST (x), 0, insn, 1);
+       rtx new1 = eliminate_regs (SET_SRC (x), 0, insn, 0);
 
        /* If SET_DEST changed from a REG to a MEM and INSN is an insn,
           write a CLOBBER insn.  */
@@ -3091,7 +3258,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), insn);
+      new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn, 0);
       if (new != XEXP (x, 0))
        {
          new = gen_rtx (MEM, GET_MODE (x), new);
@@ -3111,7 +3278,7 @@ eliminate_regs (x, mem_mode, insn)
     {
       if (*fmt == 'e')
        {
-         new = eliminate_regs (XEXP (x, i), mem_mode, insn);
+         new = eliminate_regs (XEXP (x, i), mem_mode, insn, 0);
          if (new != XEXP (x, i) && ! copied)
            {
              rtx new_x = rtx_alloc (code);
@@ -3128,11 +3295,11 @@ eliminate_regs (x, mem_mode, insn)
          int copied_vec = 0;
          for (j = 0; j < XVECLEN (x, i); j++)
            {
-             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
+             new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn, 0);
              if (new != XVECEXP (x, i, j) && ! copied_vec)
                {
-                 rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
-                                            &XVECEXP (x, i, 0));
+                 rtvec new_v = gen_rtvec_vv (XVECLEN (x, i),
+                                             XVEC (x, i)->elem);
                  if (! copied)
                    {
                      rtx new_x = rtx_alloc (code);
@@ -3199,12 +3366,29 @@ eliminate_regs_in_insn (insn, replace)
              {
                rtx src = SET_SRC (old_set);
                int offset, ok = 0;
+               rtx prev_insn, prev_set;
 
                if (src == ep->to_rtx)
                  offset = 0, ok = 1;
                else if (GET_CODE (src) == PLUS
                         && GET_CODE (XEXP (src, 0)) == CONST_INT)
                  offset = INTVAL (XEXP (src, 0)), ok = 1;
+               else if ((prev_insn = prev_nonnote_insn (insn)) != 0
+                        && (prev_set = single_set (prev_insn)) != 0
+                        && rtx_equal_p (SET_DEST (prev_set), src))
+                 {
+                   src = SET_SRC (prev_set);
+                   if (src == ep->to_rtx)
+                     offset = 0, ok = 1;
+                   else if (GET_CODE (src) == PLUS
+                            && GET_CODE (XEXP (src, 0)) == CONST_INT
+                            && XEXP (src, 1) == ep->to_rtx)
+                     offset = INTVAL (XEXP (src, 0)), ok = 1;
+                   else if (GET_CODE (src) == PLUS
+                            && GET_CODE (XEXP (src, 1)) == CONST_INT
+                            && XEXP (src, 0) == ep->to_rtx)
+                     offset = INTVAL (XEXP (src, 1)), ok = 1;
+                 }
 
                if (ok)
                  {
@@ -3236,7 +3420,7 @@ eliminate_regs_in_insn (insn, replace)
               will delete it in reload_as_needed once we know that this
               elimination is, in fact, being done.
 
-              If REPLACE isn't set, we can't delete this insn, but neededn't
+              If REPLACE isn't set, we can't delete this insn, but needn't
               process it since it won't be used unless something changes.  */
            if (replace)
              delete_dead_insn (insn);
@@ -3287,15 +3471,15 @@ eliminate_regs_in_insn (insn, replace)
      If we are replacing a body that was a (set X (plus Y Z)), try to
      re-recognize the insn.  We do this in case we had a simple addition
      but now can do this as a load-address.  This saves an insn in this
-     common case. */
+     common case.  */
 
-  new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX);
+  new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX, 0);
   if (new_body != old_body)
     {
       /* 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. */
+        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.  */
@@ -3378,7 +3562,7 @@ eliminate_regs_in_insn (insn, replace)
      of spill registers to be needed in the final reload pass than in
      the pre-passes.  */
   if (val && REG_NOTES (insn) != 0)
-    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn));
+    REG_NOTES (insn) = eliminate_regs (REG_NOTES (insn), 0, REG_NOTES (insn), 0);
 
   if (! replace)
     pop_obstacks ();
@@ -3494,7 +3678,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
        /* We will need to scan everything again.  */
        something_changed = 1;
        if (global)
-           retry_global_alloc (i, forbidden_regs);
+         retry_global_alloc (i, forbidden_regs);
 
        alter_reg (i, regno);
        if (dumpfile)
@@ -3549,7 +3733,9 @@ scan_paradoxical_subregs (x)
     {
     case REG:
 #ifdef SMALL_REGISTER_CLASSES
-      if (REGNO (x) < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x))
+      if (SMALL_REGISTER_CLASSES
+         && REGNO (x) < FIRST_PSEUDO_REGISTER
+         && REG_USERVAR_P (x))
        SET_HARD_REG_BIT (forbidden_regs, REGNO (x));
 #endif
       return;
@@ -3588,9 +3774,12 @@ scan_paradoxical_subregs (x)
 }
 \f
 static int
-hard_reg_use_compare (p1, p2)
-     struct hard_reg_n_uses *p1, *p2;
+hard_reg_use_compare (p1p, p2p)
+  const GENERIC_PTR p1p;
+  const GENERIC_PTR p2p;
 {
+  struct hard_reg_n_uses *p1 = (struct hard_reg_n_uses *)p1p,
+                        *p2 = (struct hard_reg_n_uses *)p2p;
   int tem = p1->uses - p2->uses;
   if (tem != 0) return tem;
   /* If regs are equally good, sort by regno,
@@ -3603,7 +3792,8 @@ hard_reg_use_compare (p1, p2)
    Store them in order of decreasing preference in potential_reload_regs.  */
 
 static void
-order_regs_for_reload ()
+order_regs_for_reload (global)
+     int global;
 {
   register int i;
   register int o = 0;
@@ -3632,7 +3822,15 @@ order_regs_for_reload ()
        {
          int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
          while (regno < lim)
-           hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+           {
+             /* If allocated by local-alloc, show more uses since
+                we're not going to be able to reallocate it, but
+                we might if allocated by global alloc.  */
+             if (global && reg_allocno[i] < 0)
+               hard_reg_n_uses[regno].uses += (reg_n_refs[i] + 1) / 2;
+
+             hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+           }
        }
       large += reg_n_refs[i];
     }
@@ -3651,14 +3849,15 @@ 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);
+#ifdef SMALL_REGISTER_CLASSES
+         if (! SMALL_REGISTER_CLASSES)
 #endif
+           SET_HARD_REG_BIT (bad_spill_regs, i);
        }
     }
   hard_reg_n_uses[HARD_FRAME_POINTER_REGNUM].uses += 2 * large + 2;
@@ -3714,10 +3913,12 @@ order_regs_for_reload ()
 /* Used in reload_as_needed to sort the spilled regs.  */
 
 static int
-compare_spill_regs (r1, r2)
-     short *r1, *r2;
+compare_spill_regs (r1p, r2p)
+     const GENERIC_PTR r1p;
+     const GENERIC_PTR r2p;
 {
-  return *r1 - *r2;
+  short r1 = *(short *)r1p, r2 = *(short *)r2p;
+  return r1 - r2;
 }
 
 /* Reload pseudo-registers into hard regs around each insn as needed.
@@ -3810,7 +4011,7 @@ reload_as_needed (first, live_known)
 #ifdef SMALL_REGISTER_CLASSES
          /* Set avoid_return_reg if this is an insn
             that might use the value of a function call.  */
-         if (GET_CODE (insn) == CALL_INSN)
+         if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
            {
              if (GET_CODE (PATTERN (insn)) == SET)
                after_call = SET_DEST (PATTERN (insn));
@@ -3820,7 +4021,8 @@ reload_as_needed (first, live_known)
              else
                after_call = 0;
            }
-         else if (after_call != 0
+         else if (SMALL_REGISTER_CLASSES
+                  && after_call != 0
                   && !(GET_CODE (PATTERN (insn)) == SET
                        && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
            {
@@ -3838,7 +4040,8 @@ reload_as_needed (first, live_known)
              && 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);
+                               GET_MODE (XEXP (PATTERN (insn), 0)),
+                               NULL_RTX, 0);
 
          /* If we need to do register elimination processing, do so.
             This might delete the insn, in which case we are done.  */
@@ -3898,7 +4101,8 @@ reload_as_needed (first, live_known)
              /* 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);
+             if (SMALL_REGISTER_CLASSES)
+               merge_assigned_reloads (insn);
 #endif
 
              /* Generate the insns to reload operands into or out of
@@ -4070,10 +4274,11 @@ static int reload_nregs[MAX_RELOADS];
    should be handled first.  *P1 and *P2 are the reload numbers.  */
 
 static int
-reload_reg_class_lower (p1, p2)
-     short *p1, *p2;
+reload_reg_class_lower (r1p, r2p)
+     const GENERIC_PTR r1p;
+     const GENERIC_PTR r2p;
 {
-  register int r1 = *p1, r2 = *p2;
+  register int r1 = *(short *)r1p, r2 = *(short *)r2p;
   register int t;
 
   /* Consider required reloads before optional ones.  */
@@ -4109,8 +4314,12 @@ reload_reg_class_lower (p1, p2)
 static HARD_REG_SET reload_reg_used;
 /* 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_INPADDR_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_inpaddr_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_OUTADDR_ADDRESS reload for operand I.  */
+static HARD_REG_SET reload_reg_used_in_outaddr_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.  */
@@ -4157,10 +4366,18 @@ mark_reload_reg_in_use (regno, opnum, type, mode)
          SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_INPADDR_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OUTPUT_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_OUTADDR_ADDRESS:
+         SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OPERAND_ADDRESS:
          SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
          break;
@@ -4214,10 +4431,18 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
          CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
          break;
 
+       case RELOAD_FOR_INPADDR_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_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_OUTADDR_ADDRESS:
+         CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+         break;
+
        case RELOAD_FOR_OPERAND_ADDRESS:
          CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
          break;
@@ -4256,27 +4481,24 @@ reload_reg_free_p (regno, opnum, type)
 {
   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))
+  /* In use for a RELOAD_OTHER means it's not available for anything.  */
+  if (TEST_HARD_REG_BIT (reload_reg_used, regno))
     return 0;
 
   switch (type)
     {
     case RELOAD_OTHER:
-      /* In use for anything except RELOAD_FOR_OTHER_ADDRESS means
-        we can't use it for RELOAD_OTHER.  */
-      if (TEST_HARD_REG_BIT (reload_reg_used, regno)
+      /* In use for anything means we can't use it for RELOAD_OTHER.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
          || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
          || 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_inpaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
@@ -4298,7 +4520,8 @@ reload_reg_free_p (regno, opnum, type)
 
       /* 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))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
          return 0;
 
       return 1;
@@ -4306,7 +4529,21 @@ reload_reg_free_p (regno, opnum, type)
     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))
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_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_INPADDR_ADDRESS:
+      /* Can't use a register if it is used for an input address
+         address for this operand or used as an input in an earlier
+         one.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
        return 0;
 
       for (i = 0; i < opnum; i++)
@@ -4327,6 +4564,19 @@ reload_reg_free_p (regno, opnum, type)
 
       return 1;
 
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      /* Can't use a register if it is used for an output address
+         address for this operand or used as an output in this or a
+         later operand.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_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:
       for (i = 0; i < reload_n_operands; i++)
        if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
@@ -4353,7 +4603,8 @@ reload_reg_free_p (regno, opnum, type)
          return 0;
 
       for (i = 0; i <= opnum; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
 
       return 1;
@@ -4407,12 +4658,14 @@ reload_reg_free_before_p (regno, opnum, type)
         the first place, since we know that it was allocated.  */
 
     case RELOAD_FOR_OUTPUT_ADDRESS:
+    case RELOAD_FOR_OUTADDR_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_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4421,6 +4674,7 @@ reload_reg_free_before_p (regno, opnum, type)
 
       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_inpaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
@@ -4433,16 +4687,19 @@ reload_reg_free_before_p (regno, opnum, type)
         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))
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno)
+         || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_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_outaddr_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_inpaddr_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;
@@ -4450,13 +4707,20 @@ reload_reg_free_before_p (regno, opnum, type)
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
 
     case RELOAD_FOR_OPERAND_ADDRESS:
+      /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads.  */
+      if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
+       return 0;
+
+      /* ... fall through ...  */
+
     case RELOAD_FOR_OPADDR_ADDR:
     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))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
          return 0;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4467,16 +4731,19 @@ reload_reg_free_before_p (regno, opnum, type)
         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))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
          return 0;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
 
     case RELOAD_FOR_INPUT_ADDRESS:
+    case RELOAD_FOR_INPADDR_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))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
          return 0;
 
       return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4518,8 +4785,10 @@ reload_reg_reaches_end_p (regno, opnum, type)
 
       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_outaddr_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_inpaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
@@ -4528,6 +4797,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
              && ! TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INPUT_ADDRESS:
+    case RELOAD_FOR_INPADDR_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
@@ -4538,11 +4808,13 @@ reload_reg_reaches_end_p (regno, opnum, type)
          return 0;
 
       for (i = opnum + 1; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_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_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4560,16 +4832,18 @@ reload_reg_reaches_end_p (regno, opnum, type)
 
       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_inpaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
          return 0;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case RELOAD_FOR_OPERAND_ADDRESS:
       /* 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_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4578,6 +4852,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
     case RELOAD_FOR_OPADDR_ADDR:
       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_outaddr_addr[i], regno)
            || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
          return 0;
 
@@ -4590,14 +4865,16 @@ reload_reg_reaches_end_p (regno, opnum, type)
 
       opnum = -1;
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case RELOAD_FOR_OUTPUT:
     case RELOAD_FOR_OUTPUT_ADDRESS:
+    case RELOAD_FOR_OUTADDR_ADDRESS:
       /* We already know these can't conflict with a later output.  So the
         only thing to check are later output addresses.  */
       for (i = opnum + 1; i < reload_n_operands; i++)
-       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+       if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+           || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
          return 0;
 
       return 1;
@@ -4620,9 +4897,8 @@ reloads_conflict (r1, r2)
   int r1_opnum = reload_opnum[r1];
   int r2_opnum = reload_opnum[r2];
 
-  /* RELOAD_OTHER conflicts with everything except RELOAD_FOR_OTHER_ADDRESS. */
-  
-  if (r2_type == RELOAD_OTHER && r1_type != RELOAD_FOR_OTHER_ADDRESS)
+  /* RELOAD_OTHER conflicts with everything.  */
+  if (r2_type == RELOAD_OTHER)
     return 1;
 
   /* Otherwise, check conflicts differently for each type.  */
@@ -4634,16 +4910,26 @@ reloads_conflict (r1, r2)
              || r2_type == RELOAD_FOR_OPERAND_ADDRESS
              || r2_type == RELOAD_FOR_OPADDR_ADDR
              || r2_type == RELOAD_FOR_INPUT
-             || (r2_type == RELOAD_FOR_INPUT_ADDRESS && r2_opnum > r1_opnum));
+             || ((r2_type == RELOAD_FOR_INPUT_ADDRESS
+                  || r2_type == RELOAD_FOR_INPADDR_ADDRESS)
+                 && r2_opnum > r1_opnum));
 
     case RELOAD_FOR_INPUT_ADDRESS:
       return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum)
              || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
 
+    case RELOAD_FOR_INPADDR_ADDRESS:
+      return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum)
+             || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+
     case RELOAD_FOR_OUTPUT_ADDRESS:
       return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum)
              || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
 
+    case RELOAD_FOR_OUTADDR_ADDRESS:
+      return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum)
+             || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+
     case RELOAD_FOR_OPERAND_ADDRESS:
       return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
              || r2_type == RELOAD_FOR_OPERAND_ADDRESS);
@@ -4654,7 +4940,8 @@ reloads_conflict (r1, r2)
 
     case RELOAD_FOR_OUTPUT:
       return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT
-             || (r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+             || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+                  || r2_type == RELOAD_FOR_OUTADDR_ADDRESS)
                  && r2_opnum >= r1_opnum));
 
     case RELOAD_FOR_INSN:
@@ -4666,7 +4953,7 @@ reloads_conflict (r1, r2)
       return r2_type == RELOAD_FOR_OTHER_ADDRESS;
 
     case RELOAD_OTHER:
-      return r2_type != RELOAD_FOR_OTHER_ADDRESS;
+      return 1;
 
     default:
       abort ();
@@ -4916,7 +5203,9 @@ choose_reload_regs (insn, avoid_return_reg)
   int save_reload_spill_index[MAX_RELOADS];
   HARD_REG_SET save_reload_reg_used;
   HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+  HARD_REG_SET save_reload_reg_used_in_inpaddr_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_outaddr_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;
@@ -4941,13 +5230,15 @@ choose_reload_regs (insn, avoid_return_reg)
       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_inpaddr_addr[i]);
       CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]);
+      CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
     }
 
 #ifdef SMALL_REGISTER_CLASSES
   /* Don't bother with avoiding the return reg
      if we have no mandatory reload that could use it.  */
-  if (avoid_return_reg)
+  if (SMALL_REGISTER_CLASSES && avoid_return_reg)
     {
       int do_avoid = 0;
       int regno = REGNO (avoid_return_reg);
@@ -4980,7 +5271,8 @@ choose_reload_regs (insn, avoid_return_reg)
   {
     int tem = 0;
 #ifdef SMALL_REGISTER_CLASSES
-    int tem = (avoid_return_reg != 0);
+    if (SMALL_REGISTER_CLASSES)
+      tem = (avoid_return_reg != 0);
 #endif
     for (j = 0; j < n_reloads; j++)
       if (! reload_optional[j]
@@ -4997,7 +5289,7 @@ choose_reload_regs (insn, avoid_return_reg)
 #ifdef SMALL_REGISTER_CLASSES
   /* Don't use the subroutine call return reg for a reload
      if we are supposed to avoid it.  */
-  if (avoid_return_reg)
+  if (SMALL_REGISTER_CLASSES && avoid_return_reg)
     {
       int regno = REGNO (avoid_return_reg);
       int nregs
@@ -5079,8 +5371,12 @@ choose_reload_regs (insn, avoid_return_reg)
                         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_inpaddr_addr[i],
+                        reload_reg_used_in_inpaddr_addr[i]);
       COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i],
                         reload_reg_used_in_output_addr[i]);
+      COPY_HARD_REG_SET (save_reload_reg_used_in_outaddr_addr[i],
+                        reload_reg_used_in_outaddr_addr[i]);
     }
 
   /* If -O, try first with inheritance, then turning it off.
@@ -5203,7 +5499,7 @@ choose_reload_regs (insn, avoid_return_reg)
                                                   reload_when_needed[r]))
                    {
                      /* If a group is needed, verify that all the subsequent
-                        registers still have their values intact. */
+                        registers still have their values intact.  */
                      int nr
                        = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
                      int k;
@@ -5325,8 +5621,9 @@ choose_reload_regs (insn, avoid_return_reg)
                      break;
                    }
 
-             /* JRV: If the equiv register we have found is explicitly
-                clobbered in the current insn, mark but don't use, as above. */
+             /* JRV: If the equiv register we have found is
+                explicitly clobbered in the current insn, mark but
+                don't use, as above.  */
 
              if (equiv != 0 && regno_clobbered_p (regno, insn))
                {
@@ -5338,20 +5635,24 @@ choose_reload_regs (insn, avoid_return_reg)
                 to load it, and use it as our reload reg.  */
              if (equiv != 0 && regno != HARD_FRAME_POINTER_REGNUM)
                {
+                 int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
+                 int k;
                  reload_reg_rtx[r] = equiv;
                  reload_inherited[r] = 1;
-                 /* If it is a spill reg,
-                    mark the spill reg as in use for this insn.  */
-                 i = spill_reg_order[regno];
-                 if (i >= 0)
+
+                 /* If any of the hard registers in EQUIV are spill
+                    registers, mark them as in use for this insn.  */
+                 for (k = 0; k < nr; k++)
                    {
-                     int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
-                     int k;
-                     mark_reload_reg_in_use (regno, reload_opnum[r],
-                                             reload_when_needed[r],
-                                             reload_mode[r]);
-                     for (k = 0; k < nr; k++)
-                       SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno + k);
+                     i = spill_reg_order[regno + k];
+                     if (i >= 0)
+                       {
+                         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 + k);
+                       }
                    }
                }
            }
@@ -5407,7 +5708,7 @@ choose_reload_regs (insn, avoid_return_reg)
            continue;
 
          /* Skip reloads that already have a register allocated or are
-            optional. */
+            optional.  */
          if (reload_reg_rtx[r] != 0 || reload_optional[r])
            continue;
 
@@ -5453,8 +5754,12 @@ choose_reload_regs (insn, avoid_return_reg)
                             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_inpaddr_addr[i],
+                            save_reload_reg_used_in_inpaddr_addr[i]);
          COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i],
                             save_reload_reg_used_in_output_addr[i]);
+         COPY_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i],
+                            save_reload_reg_used_in_outaddr_addr[i]);
        }
     }
 
@@ -5628,8 +5933,9 @@ merge_assigned_reloads (insn)
                  && 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;
+                 = ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+                     || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+                    ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
        }
     }
 }          
@@ -5646,10 +5952,13 @@ emit_reload_insns (insn)
   rtx other_input_address_reload_insns = 0;
   rtx other_input_reload_insns = 0;
   rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
   rtx output_reload_insns[MAX_RECOG_OPERANDS];
   rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+  rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
   rtx operand_reload_insns = 0;
   rtx other_operand_reload_insns = 0;
+  rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
   rtx following_insn = NEXT_INSN (insn);
   rtx before_insn = insn;
   int special;
@@ -5658,7 +5967,10 @@ emit_reload_insns (insn)
 
   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;
+      = inpaddr_address_reload_insns[j]
+      = output_reload_insns[j] = output_address_reload_insns[j]
+      = outaddr_address_reload_insns[j]
+      = other_output_reload_insns[j] = 0;
 
   /* 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,
@@ -5669,6 +5981,7 @@ emit_reload_insns (insn)
     {
       register rtx old;
       rtx oldequiv_reg = 0;
+      rtx this_reload_insn = 0;
 
       if (reload_spill_index[j] >= 0)
        new_spill_reg_store[reload_spill_index[j]] = 0;
@@ -5851,9 +6164,15 @@ emit_reload_insns (insn)
            case RELOAD_FOR_INPUT_ADDRESS:
              where = &input_address_reload_insns[reload_opnum[j]];
              break;
+           case RELOAD_FOR_INPADDR_ADDRESS:
+             where = &inpaddr_address_reload_insns[reload_opnum[j]];
+             break;
            case RELOAD_FOR_OUTPUT_ADDRESS:
              where = &output_address_reload_insns[reload_opnum[j]];
              break;
+           case RELOAD_FOR_OUTADDR_ADDRESS:
+             where = &outaddr_address_reload_insns[reload_opnum[j]];
+             break;
            case RELOAD_FOR_OPERAND_ADDRESS:
              where = &operand_reload_insns;
              break;
@@ -6091,6 +6410,7 @@ emit_reload_insns (insn)
 #endif
            }
 
+         this_reload_insn = get_last_insn ();
          /* End this sequence.  */
          *where = get_insns ();
          end_sequence ();
@@ -6288,7 +6608,10 @@ emit_reload_insns (insn)
          if (GET_CODE (insn) == JUMP_INSN)
            abort ();
 
-         push_to_sequence (output_reload_insns[reload_opnum[j]]);
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           start_sequence ();
+         else
+           push_to_sequence (output_reload_insns[reload_opnum[j]]);
 
          /* Determine the mode to reload in.
             See comments above (for input reloading).  */
@@ -6407,7 +6730,7 @@ emit_reload_insns (insn)
                                         reloadreg, REG_NOTES (p));
 
 #ifdef SECONDARY_OUTPUT_RELOAD_CLASS
-         if (! special
+         if (! special && second_reloadreg
              && PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
            for (p = get_last_insn (); p; p = PREV_INSN (p))
              if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
@@ -6432,7 +6755,14 @@ emit_reload_insns (insn)
                  new_spill_reg_store[reload_spill_index[j]] = p;
              }
 
-         output_reload_insns[reload_opnum[j]] = get_insns ();
+         if (reload_when_needed[j] == RELOAD_OTHER)
+           {
+             emit_insns (other_output_reload_insns[reload_opnum[j]]);
+             other_output_reload_insns[reload_opnum[j]] = get_insns ();
+           }
+         else
+           output_reload_insns[reload_opnum[j]] = get_insns ();
+
          end_sequence ();
        }
     }
@@ -6445,8 +6775,9 @@ emit_reload_insns (insn)
 
      RELOAD_OTHER reloads.
 
-     For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
-     the RELOAD_FOR_INPUT reload for the operand.
+     For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed
+     by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the
+     RELOAD_FOR_INPUT reload for the operand.
 
      RELOAD_FOR_OPADDR_ADDRS reloads.
 
@@ -6454,14 +6785,18 @@ emit_reload_insns (insn)
 
      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.  */
+     For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed
+     by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the
+     RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output
+     reloads for the operand.  The RELOAD_OTHER output reloads are
+     output in descending order by reload number.  */
 
   emit_insns_before (other_input_address_reload_insns, before_insn);
   emit_insns_before (other_input_reload_insns, before_insn);
 
   for (j = 0; j < reload_n_operands; j++)
     {
+      emit_insns_before (inpaddr_address_reload_insns[j], before_insn);
       emit_insns_before (input_address_reload_insns[j], before_insn);
       emit_insns_before (input_reload_insns[j], before_insn);
     }
@@ -6471,8 +6806,10 @@ emit_reload_insns (insn)
 
   for (j = 0; j < reload_n_operands; j++)
     {
+      emit_insns_before (outaddr_address_reload_insns[j], following_insn);
       emit_insns_before (output_address_reload_insns[j], following_insn);
       emit_insns_before (output_reload_insns[j], following_insn);
+      emit_insns_before (other_output_reload_insns[j], following_insn);
     }
 
   /* Move death notes from INSN
@@ -6533,107 +6870,139 @@ 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.
-
-        Also ignore reloads that don't reach the end of the insn,
-        since we will eventually see the one that does.  */
+        that we opted to ignore.  */
 
-      if (i >= 0 && reload_reg_rtx[r] != 0
-         && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
-                                      reload_when_needed[r]))
+      if (i >= 0 && reload_reg_rtx[r] != 0)
        {
-         /* First, clear out memory of what used to be in this spill reg.
-            If consecutive registers are used, clear them all.  */
          int nr
            = HARD_REGNO_NREGS (spill_regs[i], GET_MODE (reload_reg_rtx[r]));
          int k;
+         int part_reaches_end = 0;
+         int all_reaches_end = 1;
 
+         /* For a multi register reload, we need to check if all or part
+            of the value lives to the end.  */
          for (k = 0; k < nr; k++)
            {
-             reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
-             reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+             if (reload_reg_reaches_end_p (spill_regs[i] + k, reload_opnum[r],
+                                           reload_when_needed[r]))
+               part_reaches_end = 1;
+             else
+               all_reaches_end = 0;
            }
 
-         /* Maybe the spill reg contains a copy of reload_out.  */
-         if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+         /* Ignore reloads that don't reach the end of the insn in
+            entirety.  */
+         if (all_reaches_end)
            {
-             register int nregno = REGNO (reload_out[r]);
-             int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
-                        : HARD_REGNO_NREGS (nregno,
-                                            GET_MODE (reload_reg_rtx[r])));
+             /* First, clear out memory of what used to be in this spill reg.
+                If consecutive registers are used, clear them all.  */
 
-             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,
-                                           reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
-                                           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 >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
-                      : nregno + k);
-                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+                 reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+                 reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
                }
-           }
-
-         /* 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
-                       && ! 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]);
 
-             nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
-                    : HARD_REGNO_NREGS (nregno,
-                                        GET_MODE (reload_reg_rtx[r])));
+             /* Maybe the spill reg contains a copy of reload_out.  */
+             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,
+                                     reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+                                     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 >= FIRST_PSEUDO_REGISTER || nr != nnr
+                          ? nregno
+                          : nregno + k);
+                     reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+                   }
+               }
 
-             reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+             /* 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
+                           && ! 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 (nregno < FIRST_PSEUDO_REGISTER)
-               for (k = 1; k < nnr; k++)
-                 reg_last_reload_reg[nregno + k]
-                   = (nr == nnr ? gen_rtx (REG,
-                                           reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
-                                           REGNO (reload_reg_rtx[r]) + k)
-                      : 0);
+                 if (GET_CODE (reload_in[r]) == REG)
+                   nregno = REGNO (reload_in[r]);
+                 else
+                   nregno = REGNO (reload_in_reg[r]);
 
-             /* Unless we inherited this reload, show we haven't
-                recently done a store.  */
-             if (! reload_inherited[r])
-               spill_reg_store[i] = 0;
+                 nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+                        : HARD_REGNO_NREGS (nregno,
+                                            GET_MODE (reload_reg_rtx[r])));
+                 
+                 reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+                 if (nregno < FIRST_PSEUDO_REGISTER)
+                   for (k = 1; k < nnr; k++)
+                     reg_last_reload_reg[nregno + k]
+                       = (nr == nnr
+                          ? gen_rtx (REG,
+                                     reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+                                     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;
+                   }
+               }
+           }
 
+         /* However, if part of the reload reaches the end, then we must
+            invalidate the old info for the part that survives to the end.  */
+         else if (part_reaches_end)
+           {
              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;
-               }
+               if (reload_reg_reaches_end_p (spill_regs[i] + k,
+                                             reload_opnum[r],
+                                             reload_when_needed[r]))
+                 {
+                   reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
+                   reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+                 }
            }
        }
 
@@ -6718,8 +7087,10 @@ gen_reload (out, in, opnum, type)
 
   if (GET_CODE (in) == PLUS
       && (GET_CODE (XEXP (in, 0)) == REG
+         || GET_CODE (XEXP (in, 0)) == SUBREG
          || GET_CODE (XEXP (in, 0)) == MEM)
       && (GET_CODE (XEXP (in, 1)) == REG
+         || GET_CODE (XEXP (in, 1)) == SUBREG
          || CONSTANT_P (XEXP (in, 1))
          || GET_CODE (XEXP (in, 1)) == MEM))
     {
@@ -6747,7 +7118,7 @@ gen_reload (out, in, opnum, type)
         if the add instruction is two-address and the second operand
         of the add is the same as the reload reg, which is frequently
         the case.  If the insn would be A = B + A, rearrange it so
-        it will be A = A + B as constrain_operands expects. */
+        it will be A = A + B as constrain_operands expects.  */
 
       if (GET_CODE (XEXP (in, 1)) == REG
          && REGNO (out) == REGNO (XEXP (in, 1)))
@@ -6780,12 +7151,12 @@ gen_reload (out, in, opnum, type)
         DEFINE_PEEPHOLE should be specified that recognizes the sequence
         we emit below.  */
 
-      if (CONSTANT_P (op1) || GET_CODE (op1) == MEM
+      if (CONSTANT_P (op1) || GET_CODE (op1) == MEM || GET_CODE (op1) == SUBREG
          || (GET_CODE (op1) == REG
              && REGNO (op1) >= FIRST_PSEUDO_REGISTER))
        tem = op0, op0 = op1, op1 = tem;
 
-      emit_insn (gen_move_insn (out, op0));
+      gen_reload (out, op0, opnum, type);
 
       /* If OP0 and OP1 are the same, we can use OUT for OP1.
         This fixes a problem on the 32K where the stack pointer cannot
@@ -6797,7 +7168,7 @@ gen_reload (out, in, opnum, type)
       insn = emit_insn (gen_add2_insn (out, op1));
 
       /* If that failed, copy the address register to the reload register.
-        Then add the constant to the reload register. */
+        Then add the constant to the reload register.  */
 
       code = recog_memoized (insn);
 
@@ -6813,7 +7184,7 @@ gen_reload (out, in, opnum, type)
 
       delete_insns_since (last);
 
-      emit_insn (gen_move_insn (out, op1));
+      gen_reload (out, op1, opnum, type);
       emit_insn (gen_add2_insn (out, op0));
     }
 
@@ -6834,8 +7205,8 @@ gen_reload (out, in, opnum, type)
       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 (out, loc));
+      gen_reload (loc, in, opnum, type);
+      gen_reload (out, loc, opnum, type);
     }
 #endif
 
@@ -6944,7 +7315,13 @@ delete_output_reload (insn, j, output_reload_insn)
          rtx set = single_set (i2);
 
          if (set != 0 && SET_DEST (set) == reg)
-           delete_insn (i2);
+           {
+             /* This might be a basic block head,
+                thus don't use delete_insn.  */
+             PUT_CODE (i2, NOTE);
+             NOTE_SOURCE_FILE (i2) = 0;
+             NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+           }
          if (GET_CODE (i2) == CODE_LABEL
              || GET_CODE (i2) == JUMP_INSN)
            break;
@@ -7157,3 +7534,772 @@ count_occurrences (x, find)
     }
   return count;
 }
+\f
+/* This array holds values which are equivalent to a hard register
+   during reload_cse_regs.  Each array element is an EXPR_LIST of
+   values.  Each time a hard register is set, we set the corresponding
+   array element to the value.  Each time a hard register is copied
+   into memory, we add the memory location to the corresponding array
+   element.  We don't store values or memory addresses with side
+   effects in this array.
+
+   If the value is a CONST_INT, then the mode of the containing
+   EXPR_LIST is the mode in which that CONST_INT was referenced.
+
+   We sometimes clobber a specific entry in a list.  In that case, we
+   just set XEXP (list-entry, 0) to 0.  */
+
+static rtx *reg_values;
+
+/* This is a preallocated REG rtx which we use as a temporary in
+   reload_cse_invalidate_regno, so that we don't need to allocate a
+   new one each time through a loop in that function.  */
+
+static rtx invalidate_regno_rtx;
+
+/* Invalidate any entries in reg_values which depend on REGNO,
+   including those for REGNO itself.  This is called if REGNO is
+   changing.  If CLOBBER is true, then always forget anything we
+   currently know about REGNO.  MODE is the mode of the assignment to
+   REGNO, which is used to determine how many hard registers are being
+   changed.  If MODE is VOIDmode, then only REGNO is being changed;
+   this is used when invalidating call clobbered registers across a
+   call.  */
+
+static void
+reload_cse_invalidate_regno (regno, mode, clobber)
+     int regno;
+     enum machine_mode mode;
+     int clobber;
+{
+  int endregno;
+  register int i;
+
+  /* Our callers don't always go through true_regnum; we may see a
+     pseudo-register here from a CLOBBER or the like.  We probably
+     won't ever see a pseudo-register that has a real register number,
+     for we check anyhow for safety.  */
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    regno = reg_renumber[regno];
+  if (regno < 0)
+    return;
+
+  if (mode == VOIDmode)
+    endregno = regno + 1;
+  else
+    endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+  if (clobber)
+    for (i = regno; i < endregno; i++)
+      reg_values[i] = 0;
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0
+             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_RTX))
+           {
+             /* If this is the only entry on the list, clear
+                 reg_values[i].  Otherwise, just clear this entry on
+                 the list.  */
+             if (XEXP (x, 1) == 0 && x == reg_values[i])
+               {
+                 reg_values[i] = 0;
+                 break;
+               }
+             XEXP (x, 0) = 0;
+           }
+       }
+    }
+
+  /* We must look at earlier registers, in case REGNO is part of a
+     multi word value but is not the first register.  If an earlier
+     register has a value in a mode which overlaps REGNO, then we must
+     invalidate that earlier register.  Note that we do not need to
+     check REGNO or later registers (we must not check REGNO itself,
+     because we would incorrectly conclude that there was a conflict).  */
+
+  for (i = 0; i < regno; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0)
+           {
+             PUT_MODE (invalidate_regno_rtx, GET_MODE (XEXP (x, 0)));
+             REGNO (invalidate_regno_rtx) = i;
+             if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+                                    NULL_PTR))
+               {
+                 reload_cse_invalidate_regno (i, VOIDmode, 1);
+                 break;
+               }
+           }
+       }
+    }
+}
+
+/* The memory at address (plus MEM_BASE MEM_OFFSET), where MEM_OFFSET
+   is a CONST_INT, is being changed.  MEM_MODE is the mode of the
+   memory reference.  Return whether this change will invalidate VAL.  */
+
+static int
+reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
+     rtx mem_base;
+     rtx mem_offset;
+     enum machine_mode mem_mode;
+     rtx val;
+{
+  enum rtx_code code;
+  char *fmt;
+  int i;
+
+  code = GET_CODE (val);
+  switch (code)
+    {
+      /* Get rid of a few simple cases quickly. */
+    case REG:
+    case PC:
+    case CC0:
+    case SCRATCH:
+    case CONST:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 0;
+
+    case MEM:
+      {
+       rtx val_base, val_offset;
+
+       if (mem_mode == BLKmode || GET_MODE (val) == BLKmode)
+         return 1;
+
+       val_offset = const0_rtx;
+       val_base = eliminate_constant_term (XEXP (val, 0), &val_offset);
+
+       /* If MEM_BASE and VAL_BASE are the same, but the offsets do
+          not overlap, then we do not have a conflict on this MEM.
+          For complete safety, we still need to check that VAL_BASE
+          itself does not contain an overlapping MEM.
+
+          We can't simplify the check to just OFFSET + SIZE <=
+          OTHER_OFFSET, because SIZE might cause OFFSET to wrap from
+          positive to negative.  If we used unsigned arithmetic, we
+          would have the same problem wrapping around zero.  */
+
+       if (rtx_equal_p (mem_base, val_base)
+           && ((INTVAL (mem_offset) < INTVAL (val_offset)
+                && (INTVAL (mem_offset) + GET_MODE_SIZE (mem_mode)
+                    <= INTVAL (val_offset)))
+               || (INTVAL (val_offset) < INTVAL (mem_offset)
+                   && (INTVAL (val_offset) + GET_MODE_SIZE (GET_MODE (val))
+                       <= INTVAL (mem_offset)))))
+         return reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                           val_base);
+
+       return 1;
+      }
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+       {
+         if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                        XEXP (val, i)))
+           return 1;
+       }
+      else if (fmt[i] == 'E')
+       {
+         int j;
+
+         for (j = 0; j < XVECLEN (val, i); j++)
+           if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                          XVECEXP (val, i, j)))
+             return 1;
+       }
+    }
+
+  return 0;
+}
+
+/* Invalidate any entries in reg_values which are changed because of a
+   store to MEM_RTX.  If this is called because of a non-const call
+   instruction, MEM_RTX is (mem:BLK const0_rtx).  */
+
+static void
+reload_cse_invalidate_mem (mem_rtx)
+     rtx mem_rtx;
+{
+  register int i;
+  rtx mem_base, mem_offset;
+  enum machine_mode mem_mode;
+
+  /* We detect certain cases where memory addresses can not conflict:
+     if they use the same register, and the offsets do not overlap.  */
+
+  mem_offset = const0_rtx;
+  mem_base = eliminate_constant_term (XEXP (mem_rtx, 0), &mem_offset);
+  mem_mode = GET_MODE (mem_rtx);
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rtx x;
+
+      for (x = reg_values[i]; x; x = XEXP (x, 1))
+       {
+         if (XEXP (x, 0) != 0
+             && reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
+                                           XEXP (x, 0)))
+           {
+             /* If this is the only entry on the list, clear
+                 reg_values[i].  Otherwise, just clear this entry on
+                 the list.  */
+             if (XEXP (x, 1) == 0 && x == reg_values[i])
+               {
+                 reg_values[i] = 0;
+                 break;
+               }
+             XEXP (x, 0) = 0;
+           }
+       }
+    }
+}
+
+/* Invalidate DEST, which is being assigned to or clobbered.  The
+   second parameter exists so that this function can be passed to
+   note_stores; it is ignored.  */
+
+static void
+reload_cse_invalidate_rtx (dest, ignore)
+     rtx dest;
+     rtx ignore;
+{
+  while (GET_CODE (dest) == STRICT_LOW_PART
+        || GET_CODE (dest) == SIGN_EXTRACT
+        || GET_CODE (dest) == ZERO_EXTRACT
+        || GET_CODE (dest) == SUBREG)
+    dest = XEXP (dest, 0);
+
+  if (GET_CODE (dest) == REG)
+    reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1);
+  else if (GET_CODE (dest) == MEM)
+    reload_cse_invalidate_mem (dest);
+}
+
+/* Do a very simple CSE pass over the hard registers.
+
+   This function detects no-op moves where we happened to assign two
+   different pseudo-registers to the same hard register, and then
+   copied one to the other.  Reload will generate a useless
+   instruction copying a register to itself.
+
+   This function also detects cases where we load a value from memory
+   into two different registers, and (if memory is more expensive than
+   registers) changes it to simply copy the first register into the
+   second register.  */
+
+static void
+reload_cse_regs (first)
+     rtx first;
+{
+  char *firstobj;
+  rtx callmem;
+  register int i;
+  rtx insn;
+
+  reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    reg_values[i] = 0;
+
+  /* Create our EXPR_LIST structures on reload_obstack, so that we can
+     free them when we are done.  */
+  push_obstacks (&reload_obstack, &reload_obstack);
+  firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+  /* We pass this to reload_cse_invalidate_mem to invalidate all of
+     memory for a non-const call instruction.  */
+  callmem = gen_rtx (MEM, BLKmode, const0_rtx);
+
+  /* This is used in reload_cse_invalidate_regno to avoid consing a
+     new REG in a loop in that function.  */
+  invalidate_regno_rtx = gen_rtx (REG, VOIDmode, 0);
+
+  for (insn = first; insn; insn = NEXT_INSN (insn))
+    {
+      rtx body;
+
+      if (GET_CODE (insn) == CODE_LABEL)
+       {
+         /* Forget all the register values at a code label.  We don't
+             try to do anything clever around jumps.  */
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           reg_values[i] = 0;
+
+         continue;
+       }
+
+#ifdef NON_SAVING_SETJMP 
+      if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+       {
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           reg_values[i] = 0;
+
+         continue;
+       }
+#endif
+
+      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       continue;
+
+      /* If this is a call instruction, forget anything stored in a
+        call clobbered register, or, if this is not a const call, in
+        memory.  */
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+           if (call_used_regs[i])
+             reload_cse_invalidate_regno (i, VOIDmode, 1);
+
+         if (! CONST_CALL_P (insn))
+           reload_cse_invalidate_mem (callmem);
+       }
+
+      body = PATTERN (insn);
+      if (GET_CODE (body) == SET)
+       {
+         if (reload_cse_noop_set_p (body, insn))
+           {
+             PUT_CODE (insn, NOTE);
+             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (insn) = 0;
+
+             /* We're done with this insn.  */
+             continue;
+           }
+
+         reload_cse_simplify_set (body, insn);
+         reload_cse_record_set (body, body);
+       }
+      else if (GET_CODE (body) == PARALLEL)
+       {
+         int delete;
+
+         /* If every action in a PARALLEL is a noop, we can delete
+             the entire PARALLEL.  */
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           if (GET_CODE (XVECEXP (body, 0, i)) != SET
+               || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
+             break;
+         if (i < 0)
+           {
+             PUT_CODE (insn, NOTE);
+             NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+             NOTE_SOURCE_FILE (insn) = 0;
+
+             /* We're done with this insn.  */
+             continue;
+           }
+
+         /* Look through the PARALLEL and record the values being
+             set, if possible.  Also handle any CLOBBERs.  */
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           {
+             rtx x = XVECEXP (body, 0, i);
+
+             if (GET_CODE (x) == SET)
+               reload_cse_record_set (x, body);
+             else
+               note_stores (x, reload_cse_invalidate_rtx);
+           }
+       }
+      else
+       note_stores (body, reload_cse_invalidate_rtx);
+
+#ifdef AUTO_INC_DEC
+      /* Clobber any registers which appear in REG_INC notes.  We
+         could keep track of the changes to their values, but it is
+         unlikely to help.  */
+      {
+       rtx x;
+
+       for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+         if (REG_NOTE_KIND (x) == REG_INC)
+           reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX);
+      }
+#endif
+
+      /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
+         after we have processed the insn.  */
+      if (GET_CODE (insn) == CALL_INSN)
+       {
+         rtx x;
+
+         for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+           if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+             reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX);
+       }
+    }
+
+  /* Free all the temporary structures we created, and go back to the
+     regular obstacks.  */
+  obstack_free (&reload_obstack, firstobj);
+  pop_obstacks ();
+}
+
+/* Return whether the values known for REGNO are equal to VAL.  MODE
+   is the mode of the object that VAL is being copied to; this matters
+   if VAL is a CONST_INT.  */
+
+static int
+reload_cse_regno_equal_p (regno, val, mode)
+     int regno;
+     rtx val;
+     enum machine_mode mode;
+{
+  rtx x;
+
+  if (val == 0)
+    return 0;
+
+  for (x = reg_values[regno]; x; x = XEXP (x, 1))
+    if (XEXP (x, 0) != 0
+       && rtx_equal_p (XEXP (x, 0), val)
+       && (GET_CODE (val) != CONST_INT
+           || mode == GET_MODE (x)
+           || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+               && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                         GET_MODE_BITSIZE (GET_MODE (x))))))
+      return 1;
+
+  return 0;
+}
+
+/* See whether a single set is a noop.  SET is the set instruction we
+   are should check, and INSN is the instruction from which it came.  */
+
+static int
+reload_cse_noop_set_p (set, insn)
+     rtx set;
+     rtx insn;
+{
+  rtx src, dest;
+  enum machine_mode dest_mode;
+  int dreg, sreg;
+  int ret;
+
+  src = SET_SRC (set);
+  dest = SET_DEST (set);
+  dest_mode = GET_MODE (dest);
+
+  if (side_effects_p (src))
+    return 0;
+
+  dreg = true_regnum (dest);
+  sreg = true_regnum (src);
+
+  /* Check for setting a register to itself.  In this case, we don't
+     have to worry about REG_DEAD notes.  */
+  if (dreg >= 0 && dreg == sreg)
+    return 1;
+
+  ret = 0;
+  if (dreg >= 0)
+    {
+      /* Check for setting a register to itself.  */
+      if (dreg == sreg)
+       ret = 1;
+
+      /* Check for setting a register to a value which we already know
+         is in the register.  */
+      else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+       ret = 1;
+
+      /* Check for setting a register DREG to another register SREG
+         where SREG is equal to a value which is already in DREG.  */
+      else if (sreg >= 0)
+       {
+         rtx x;
+
+         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+           {
+             if (XEXP (x, 0) != 0
+                 && reload_cse_regno_equal_p (dreg, XEXP (x, 0), dest_mode))
+               {
+                 ret = 1;
+                 break;
+               }
+           }
+       }
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      /* Check for storing a register to memory when we know that the
+         register is equivalent to the memory location. */
+      if (sreg >= 0
+         && reload_cse_regno_equal_p (sreg, dest, dest_mode)
+         && ! side_effects_p (dest))
+       ret = 1;
+    }
+
+  /* If we can delete this SET, then we need to look for an earlier
+     REG_DEAD note on DREG, and remove it if it exists.  */
+  if (ret)
+    {
+      if (! find_regno_note (insn, REG_UNUSED, dreg))
+       {
+         rtx trial;
+
+         for (trial = prev_nonnote_insn (insn);
+              (trial
+               && GET_CODE (trial) != CODE_LABEL
+               && GET_CODE (trial) != BARRIER);
+              trial = prev_nonnote_insn (trial))
+           {
+             if (find_regno_note (trial, REG_DEAD, dreg))
+               {
+                 remove_death (dreg, trial);
+                 break;
+               }
+           }
+       }
+    }
+
+  return ret;
+}
+
+/* Try to simplify a single SET instruction.  SET is the set pattern.
+   INSN is the instruction it came from. */
+
+static void
+reload_cse_simplify_set (set, insn)
+     rtx set;
+     rtx insn;
+{
+  int dreg;
+  rtx src;
+  enum machine_mode dest_mode;
+  enum reg_class dclass;
+  register int i;
+
+  /* We only handle one case: if we set a register to a value which is
+     not a register, we try to find that value in some other register
+     and change the set into a register copy.  */
+
+  dreg = true_regnum (SET_DEST (set));
+  if (dreg < 0)
+    return;
+
+  src = SET_SRC (set);
+  if (side_effects_p (src) || true_regnum (src) >= 0)
+    return;
+
+  /* If memory loads are cheaper than register copies, don't change
+     them.  */
+  if (GET_CODE (src) == MEM && MEMORY_MOVE_COST (GET_MODE (src)) < 2)
+    return;
+
+  dest_mode = GET_MODE (SET_DEST (set));
+  dclass = REGNO_REG_CLASS (dreg);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      if (i != dreg
+         && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
+         && reload_cse_regno_equal_p (i, src, dest_mode))
+       {
+         int validated;
+
+         /* Pop back to the real obstacks while changing the insn.  */
+         pop_obstacks ();
+
+         validated = validate_change (insn, &SET_SRC (set),
+                                      gen_rtx (REG, dest_mode, i), 0);
+
+         /* Go back to the obstack we are using for temporary
+             storage.  */
+         push_obstacks (&reload_obstack, &reload_obstack);
+
+         if (validated)
+           {
+             /* We need to look for an earlier REG_DEAD note on I,
+                and remove it if it exists.  */
+             if (! find_regno_note (insn, REG_UNUSED, i))
+               {
+                 rtx trial;
+
+                 for (trial = prev_nonnote_insn (insn);
+                      (trial
+                       && GET_CODE (trial) != CODE_LABEL
+                       && GET_CODE (trial) != BARRIER);
+                      trial = prev_nonnote_insn (trial))
+                   {
+                     if (find_regno_note (trial, REG_DEAD, i))
+                       {
+                         remove_death (i, trial);
+                         break;
+                       }
+                   }
+               }
+
+             return;
+           }
+       }
+    }
+}
+
+/* These two variables are used to pass information from
+   reload_cse_record_set to reload_cse_check_clobber.  */
+
+static int reload_cse_check_clobbered;
+static rtx reload_cse_check_src;
+
+/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set
+   RELOAD_CSE_CHECK_CLOBBERED.  This is called via note_stores.  The
+   second argument, which is passed by note_stores, is ignored.  */
+
+static void
+reload_cse_check_clobber (dest, ignore)
+     rtx dest;
+     rtx ignore;
+{
+  if (reg_overlap_mentioned_p (dest, reload_cse_check_src))
+    reload_cse_check_clobbered = 1;
+}
+
+/* Record the result of a SET instruction.  SET is the set pattern.
+   BODY is the pattern of the insn that it came from.  */
+
+static void
+reload_cse_record_set (set, body)
+     rtx set;
+     rtx body;
+{
+  rtx dest, src;
+  int dreg, sreg;
+  enum machine_mode dest_mode;
+
+  dest = SET_DEST (set);
+  src = SET_SRC (set);
+  dreg = true_regnum (dest);
+  sreg = true_regnum (src);
+  dest_mode = GET_MODE (dest);
+
+  /* We can only handle an assignment to a register, or a store of a
+     register to a memory location.  For other cases, we just clobber
+     the destination.  We also have to just clobber if there are side
+     effects in SRC or DEST.  */
+  if ((dreg < 0 && GET_CODE (dest) != MEM)
+      || side_effects_p (src)
+      || side_effects_p (dest))
+    {
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+
+#ifdef HAVE_cc0
+  /* We don't try to handle values involving CC, because it's a pain
+     to keep track of when they have to be invalidated.  */
+  if (reg_mentioned_p (cc0_rtx, src)
+      || reg_mentioned_p (cc0_rtx, dest))
+    {
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+#endif
+
+  /* If BODY is a PARALLEL, then we need to see whether the source of
+     SET is clobbered by some other instruction in the PARALLEL.  */
+  if (GET_CODE (body) == PARALLEL)
+    {
+      int i;
+
+      for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+       {
+         rtx x;
+
+         x = XVECEXP (body, 0, i);
+         if (x == set)
+           continue;
+
+         reload_cse_check_clobbered = 0;
+         reload_cse_check_src = src;
+         note_stores (x, reload_cse_check_clobber);
+         if (reload_cse_check_clobbered)
+           {
+             reload_cse_invalidate_rtx (dest, NULL_RTX);
+             return;
+           }
+       }
+    }
+
+  if (dreg >= 0)
+    {
+      int i;
+
+      /* This is an assignment to a register.  Update the value we
+         have stored for the register.  */
+      if (sreg >= 0)
+       {
+         rtx x;
+
+         /* This is a copy from one register to another.  Any values
+            which were valid for SREG are now valid for DREG.  If the
+            mode changes, we use gen_lowpart_common to extract only
+            the part of the value that is copied.  */
+         reg_values[dreg] = 0;
+         for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+           {
+             rtx tmp;
+
+             if (XEXP (x, 0) == 0)
+               continue;
+             if (dest_mode == GET_MODE (XEXP (x, 0)))
+               tmp = XEXP (x, 0);
+             else
+               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+             if (tmp)
+               reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, tmp,
+                                           reg_values[dreg]);
+           }         
+       }
+      else
+       reg_values[dreg] = gen_rtx (EXPR_LIST, dest_mode, src, NULL_RTX);
+
+      /* We've changed DREG, so invalidate any values held by other
+         registers that depend upon it.  */
+      reload_cse_invalidate_regno (dreg, dest_mode, 0);
+
+      /* If this assignment changes more than one hard register,
+         forget anything we know about the others.  */
+      for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++)
+       reg_values[dreg + i] = 0;
+    }
+  else if (GET_CODE (dest) == MEM)
+    {
+      /* Invalidate conflicting memory locations.  */
+      reload_cse_invalidate_mem (dest);
+
+      /* If we're storing a register to memory, add DEST to the list
+         in REG_VALUES.  */
+      if (sreg >= 0 && ! side_effects_p (dest))
+       reg_values[sreg] = gen_rtx (EXPR_LIST, dest_mode, dest,
+                                   reg_values[sreg]);
+    }
+  else
+    {
+      /* We should have bailed out earlier.  */
+      abort ();
+    }
+}