OSDN Git Service

Merge from gcc-2.8
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index a7b4238..c8573dc 100644 (file)
@@ -19,8 +19,8 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 
-#include <stdio.h>
 #include "config.h"
+#include <stdio.h>
 #include "rtl.h"
 #include "obstack.h"
 #include "insn-config.h"
@@ -159,7 +159,7 @@ HARD_REG_SET forbidden_regs;
 /* This reg set indicates registers that are not good for spill registers.
    They will not be used to complete groups of spill registers.  This includes
    all fixed registers, registers that may be eliminated, and, if
-   SMALL_REGISTER_CLASSES is not defined, registers explicitly used in the rtl.
+   SMALL_REGISTER_CLASSES is zero, registers explicitly used in the rtl.
 
    (spill_reg_order prevents these registers from being used to start a
    group.)  */
@@ -394,16 +394,17 @@ 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 int reload_cse_mem_conflict_p   PROTO((rtx, 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));
-static void reload_cse_simplify_set    PROTO((rtx, rtx));
+static int reload_cse_noop_set_p       PROTO((rtx, rtx));
+static int reload_cse_simplify_set     PROTO((rtx, rtx));
+static int reload_cse_simplify_operands        PROTO((rtx));
 static void reload_cse_check_clobber   PROTO((rtx, rtx));
 static void reload_cse_record_set      PROTO((rtx, rtx));
+static void reload_cse_delete_death_notes      PROTO((rtx));
+static void reload_cse_no_longer_dead  PROTO((int, enum machine_mode));
 \f
 /* Initialize the reload pass once per compilation.  */
 
@@ -467,7 +468,6 @@ init_reload ()
      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;
@@ -513,7 +513,6 @@ init_reload ()
        }
     indexok:;
     }
-#endif /* SMALL_REGISTER_CLASSES */
 }
 
 /* Main entry point for the reload pass.
@@ -545,6 +544,11 @@ reload (first, global, dumpfile)
   register rtx insn;
   register struct elim_table *ep;
 
+  /* The two pointers used to track the true location of the memory used
+     for label offsets.  */
+  char *real_known_ptr = NULL_PTR;
+  int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
+
   int something_changed;
   int something_needs_reloads;
   int something_needs_elimination;
@@ -589,10 +593,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]);
@@ -626,10 +638,8 @@ reload (first, global, dumpfile)
   cannot_omit_stores = (char *) alloca (max_regno);
   bzero (cannot_omit_stores, max_regno);
 
-#ifdef SMALL_REGISTER_CLASSES
   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.
@@ -663,7 +673,14 @@ reload (first, global, dumpfile)
              if (i > LAST_VIRTUAL_REGISTER)
                {
                  if (GET_CODE (x) == MEM)
-                   reg_equiv_memory_loc[i] = x;
+                   {
+                     /* If the operand is a PLUS, the MEM may be shared,
+                        so make sure we have an unshared copy here.  */
+                     if (GET_CODE (XEXP (x, 0)) == PLUS)
+                       x = copy_rtx (x);
+
+                     reg_equiv_memory_loc[i] = x;
+                   }
                  else if (CONSTANT_P (x))
                    {
                      if (LEGITIMATE_CONSTANT_P (x))
@@ -743,13 +760,17 @@ reload (first, global, dumpfile)
   num_labels = max_label_num () - get_first_label_num ();
 
   /* Allocate the tables used to store offset information at labels.  */
-  offsets_known_at = (char *) alloca (num_labels);
-  offsets_at
+  /* We used to use alloca here, but the size of what it would try to
+     allocate would occasionally cause it to exceed the stack limit and
+     cause a core dump.  */
+  real_known_ptr = xmalloc (num_labels);
+  real_at_ptr
     = (int (*)[NUM_ELIMINABLE_REGS])
-      alloca (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
+    xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
 
-  offsets_known_at -= get_first_label_num ();
-  offsets_at -= get_first_label_num ();
+  offsets_known_at = real_known_ptr - get_first_label_num ();
+  offsets_at
+    = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
 
   /* Alter each pseudo-reg rtx to contain its hard reg number.
      Assign stack slots to the pseudos that lack hard regs or equivalents.
@@ -777,11 +798,15 @@ reload (first, global, dumpfile)
      in that case some pseudos might be in the wrong kind of hard reg.  */
 
   for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (reg_renumber[i] == -1 && reg_n_refs[i] != 0)
+    if (reg_renumber[i] == -1 && REG_N_REFS (i) != 0)
       break;
 
   if (i == max_regno && num_eliminable == 0 && ! caller_save_needed)
-    return;
+    {
+      free (real_known_ptr);
+      free (real_at_ptr);
+      return;
+    }
 #endif
 
   /* Compute the order of preference for hard registers to spill.
@@ -801,9 +826,7 @@ 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.  */
 
-#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.  */
@@ -1073,7 +1096,6 @@ reload (first, global, dumpfile)
              if (num_eliminable)
                did_elimination = eliminate_regs_in_insn (insn, 0);
 
-#ifdef SMALL_REGISTER_CLASSES
              /* Set avoid_return_reg if this is an insn
                 that might use the value of a function call.  */
              if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
@@ -1086,8 +1108,7 @@ reload (first, global, dumpfile)
                  else
                    after_call = 0;
                }
-             else if (SMALL_REGISTER_CLASSES
-                      && after_call != 0
+             else if (SMALL_REGISTER_CLASSES && after_call != 0
                       && !(GET_CODE (PATTERN (insn)) == SET
                            && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
                {
@@ -1095,7 +1116,6 @@ reload (first, global, dumpfile)
                    avoid_return_reg = after_call;
                  after_call = 0;
                }
-#endif /* SMALL_REGISTER_CLASSES */
 
              /* Analyze the instruction.  */
              find_reloads (insn, 0, spill_indirect_levels, global,
@@ -1174,7 +1194,6 @@ reload (first, global, dumpfile)
                      new_basic_block_needs = 1;
                    }
 
-
                  mode = reload_inmode[i];
                  if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
                    mode = reload_outmode[i];
@@ -1307,10 +1326,9 @@ reload (first, global, dumpfile)
                           k < reload_n_operands; k++)
                        {
                          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]);
+                                  (insn_needs.in_addr[k].regs[j][i]
+                                   + insn_needs.in_addr_addr[k].regs[j][i]));
                          out_max
                            = MAX (out_max, insn_needs.out_addr[k].regs[j][i]);
                          out_max
@@ -1442,7 +1460,6 @@ reload (first, global, dumpfile)
                    }
                }
 
-#ifdef SMALL_REGISTER_CLASSES
              /* If this insn stores the value of a function call,
                 and that value is in a register that has been spilled,
                 and if the insn needs a reload in a class
@@ -1511,7 +1528,6 @@ reload (first, global, dumpfile)
                              }
                          }
                }
-#endif /* SMALL_REGISTER_CLASSES */
 
              /* For each class, collect maximum need of any insn.  */
 
@@ -1807,7 +1823,6 @@ 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 (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER)
                    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -1832,7 +1847,6 @@ reload (first, global, dumpfile)
                            && ! regs_explicitly_used[j + 1])
                          break;
                      }
-#endif
                  /* Now try any group at all
                     whose registers are not in bad_spill_regs.  */
                  if (i == FIRST_PSEUDO_REGISTER)
@@ -2071,9 +2085,8 @@ reload (first, global, dumpfile)
 
   if (! frame_pointer_needed)
     for (i = 0; i < n_basic_blocks; i++)
-      basic_block_live_at_start[i][HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
-       &= ~ ((REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
-                                     % REGSET_ELT_BITS));
+      CLEAR_REGNO_REG_SET (basic_block_live_at_start[i],
+                          HARD_FRAME_POINTER_REGNUM);
 
   /* Come here (with failure set nonzero) if we can't get enough spill regs
      and we decide not to abort about it.  */
@@ -2117,10 +2130,6 @@ 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
@@ -2142,10 +2151,29 @@ reload (first, global, dumpfile)
       }
 #endif
 
+  /* If we are doing stack checking, give a warning if this function's
+     frame size is larger than we expect.  */
+  if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+    {
+      HOST_WIDE_INT size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE;
+
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (regs_ever_live[i] && ! fixed_regs[i] && call_used_regs[i])
+         size += UNITS_PER_WORD;
+
+      if (size > STACK_CHECK_MAX_FRAME_SIZE)
+       warning ("frame size too large for reliable stack checking");
+    }
+       
   /* Indicate that we no longer have known memory locations or constants.  */
   reg_equiv_constant = 0;
   reg_equiv_memory_loc = 0;
 
+  if (real_known_ptr)
+    free (real_known_ptr);
+  if (real_at_ptr)
+    free (real_at_ptr);
+
   if (scratch_list)
     free (scratch_list);
   scratch_list = 0;
@@ -2353,9 +2381,12 @@ new_spill_reg (i, class, max_needs, max_nongroups, global, dumpfile)
     abort ();  /* Caller failed to find any register.  */
 
   if (fixed_regs[regno] || TEST_HARD_REG_BIT (forbidden_regs, regno))
-    fatal ("fixed or forbidden register was spilled.\n\
+    {
+      static char *reg_class_names[] = REG_CLASS_NAMES;
+      fatal ("fixed or forbidden register %d (%s) was spilled for class %s.\n\
 This may be due to a compiler bug or to impossible asm\n\
-statements or clauses.");
+statements or clauses.", regno, reg_names[regno], reg_class_names[class]);
+    }
 
   /* Make reg REGNO an additional reload reg.  */
 
@@ -2463,7 +2494,7 @@ alter_reg (i, from_reg)
      allocate a stack slot for it.  */
 
   if (reg_renumber[i] < 0
-      && reg_n_refs[i] > 0
+      && REG_N_REFS (i) > 0
       && reg_equiv_constant[i] == 0
       && reg_equiv_memory_loc[i] == 0)
     {
@@ -2730,6 +2761,9 @@ set_label_offsets (x, insn, initial_p)
          else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN)
            break;
          return;
+
+       default:
+         break;
        }
 
       /* If we reach here, all eliminations must be at their initial
@@ -2737,6 +2771,10 @@ set_label_offsets (x, insn, initial_p)
       for (p = reg_eliminate; p < &reg_eliminate[NUM_ELIMINABLE_REGS]; p++)
        if (p->offset != p->initial_offset)
          p->can_eliminate = 0;
+      break;
+      
+    default:
+      break;
     }
 }
 \f
@@ -2803,6 +2841,15 @@ eliminate_regs (x, mem_mode, insn, storing)
     case RETURN:
       return x;
 
+    case ADDRESSOF:
+      /* This is only for the benefit of the debugging backends, which call
+        eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+        removed after CSE.  */
+      new = eliminate_regs (XEXP (x, 0), 0, insn, 0);
+      if (GET_CODE (new) == MEM)
+       return XEXP (new, 0);
+      return x;
+
     case REG:
       regno = REGNO (x);
 
@@ -3240,6 +3287,12 @@ eliminate_regs (x, mem_mode, insn, storing)
            && GET_CODE (insn) != INSN_LIST)
          emit_insn_after (gen_rtx (CLOBBER, VOIDmode, SET_DEST (x)), insn);
 
+       /* If SET_DEST was a partial-word subreg, NEW0 may have been widened
+          to spill the entire register (see SUBREG case above).  If the 
+          widths of SET_DEST and NEW0 no longer match, adjust NEW1.  */
+       if (GET_MODE (SET_DEST (x)) != GET_MODE (new0))
+         new1 = gen_rtx (SUBREG, GET_MODE (new0), new1, 0);
+
        if (new0 != SET_DEST (x) || new1 != SET_SRC (x))
          return gen_rtx (SET, VOIDmode, new0, new1);
       }
@@ -3247,6 +3300,12 @@ eliminate_regs (x, mem_mode, insn, storing)
       return x;
 
     case MEM:
+      /* This is only for the benefit of the debugging backends, which call
+        eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+        removed after CSE.  */
+      if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
+       return eliminate_regs (XEXP (XEXP (x, 0), 0), 0, insn, 0);
+
       /* 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.  */
@@ -3261,6 +3320,9 @@ eliminate_regs (x, mem_mode, insn, storing)
        }
       else
        return x;
+      
+    default:
+      break;
     }
 
   /* Process each of our operands recursively.  If any have changed, make a
@@ -3651,14 +3713,14 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
 
        if (! cant_eliminate
            && basic_block_needs[0]
-           && reg_basic_block[i] >= 0
-           && basic_block_needs[(int) class][reg_basic_block[i]] == 0)
+           && REG_BASIC_BLOCK (i) >= 0
+           && basic_block_needs[(int) class][REG_BASIC_BLOCK (i)] == 0)
          {
            enum reg_class *p;
 
            for (p = reg_class_superclasses[(int) class];
                 *p != LIM_REG_CLASSES; p++)
-             if (basic_block_needs[(int) *p][reg_basic_block[i]] > 0)
+             if (basic_block_needs[(int) *p][REG_BASIC_BLOCK (i)] > 0)
                break;
 
            if (*p == LIM_REG_CLASSES)
@@ -3724,12 +3786,9 @@ scan_paradoxical_subregs (x)
   switch (code)
     {
     case REG:
-#ifdef SMALL_REGISTER_CLASSES
-      if (SMALL_REGISTER_CLASSES
-         && REGNO (x) < FIRST_PSEUDO_REGISTER
+      if (SMALL_REGISTER_CLASSES && REGNO (x) < FIRST_PSEUDO_REGISTER
          && REG_USERVAR_P (x))
        SET_HARD_REG_BIT (forbidden_regs, REGNO (x));
-#endif
       return;
 
     case CONST_INT:
@@ -3749,6 +3808,9 @@ scan_paradoxical_subregs (x)
        reg_max_ref_width[REGNO (SUBREG_REG (x))]
          = GET_MODE_SIZE (GET_MODE (x));
       return;
+      
+    default:
+      break;
     }
 
   fmt = GET_RTX_FORMAT (code);
@@ -3819,12 +3881,12 @@ order_regs_for_reload (global)
                 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) + 1) / 2;
 
-             hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+             hard_reg_n_uses[regno++].uses += REG_N_REFS (i);
            }
        }
-      large += reg_n_refs[i];
+      large += REG_N_REFS (i);
     }
 
   /* Now fixed registers (which cannot safely be used for reloading)
@@ -3841,14 +3903,12 @@ order_regs_for_reload (global)
       else if (regs_explicitly_used[i])
        {
          hard_reg_n_uses[i].uses += large + 1;
-         /* ??? 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.  */
-#ifdef SMALL_REGISTER_CLASSES
          if (! SMALL_REGISTER_CLASSES)
-#endif
+           /* ??? 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);
        }
     }
@@ -4000,7 +4060,6 @@ reload_as_needed (first, live_known)
          rtx avoid_return_reg = 0;
          rtx oldpat = PATTERN (insn);
 
-#ifdef SMALL_REGISTER_CLASSES
          /* Set avoid_return_reg if this is an insn
             that might use the value of a function call.  */
          if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
@@ -4013,8 +4072,7 @@ reload_as_needed (first, live_known)
              else
                after_call = 0;
            }
-         else if (SMALL_REGISTER_CLASSES
-                  && after_call != 0
+         else if (SMALL_REGISTER_CLASSES && after_call != 0
                   && !(GET_CODE (PATTERN (insn)) == SET
                        && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
            {
@@ -4022,7 +4080,6 @@ reload_as_needed (first, live_known)
                avoid_return_reg = after_call;
              after_call = 0;
            }
-#endif /* SMALL_REGISTER_CLASSES */
 
          /* If this is a USE and CLOBBER of a MEM, ensure that any
             references to eliminable registers have been removed.  */
@@ -4089,13 +4146,11 @@ reload_as_needed (first, live_known)
                 Record the choices of reload reg in reload_reg_rtx.  */
              choose_reload_regs (insn, avoid_return_reg);
 
-#ifdef SMALL_REGISTER_CLASSES
              /* Merge any reloads that we didn't combine for fear of 
                 increasing the number of spill registers needed but now
                 discover can be safely merged.  */
              if (SMALL_REGISTER_CLASSES)
                merge_assigned_reloads (insn);
-#endif
 
              /* Generate the insns to reload operands into or out of
                 their reload regs.  */
@@ -5227,7 +5282,6 @@ choose_reload_regs (insn, avoid_return_reg)
       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 (SMALL_REGISTER_CLASSES && avoid_return_reg)
@@ -5250,7 +5304,6 @@ choose_reload_regs (insn, avoid_return_reg)
       if (!do_avoid)
        avoid_return_reg = 0;
     }
-#endif /* SMALL_REGISTER_CLASSES */
 
 #if 0  /* Not needed, now that we can always retry without inheritance.  */
   /* See if we have more mandatory reloads than spill regs.
@@ -5261,11 +5314,7 @@ choose_reload_regs (insn, avoid_return_reg)
      unless it is equal to reload_in or reload_out, count such reloads.  */
 
   {
-    int tem = 0;
-#ifdef SMALL_REGISTER_CLASSES
-    if (SMALL_REGISTER_CLASSES)
-      tem = (avoid_return_reg != 0);
-#endif
+    int tem = SMALL_REGISTER_CLASSES? (avoid_return_reg != 0): 0;
     for (j = 0; j < n_reloads; j++)
       if (! reload_optional[j]
          && (reload_in[j] != 0 || reload_out[j] != 0 || reload_secondary_p[j])
@@ -5278,7 +5327,6 @@ choose_reload_regs (insn, avoid_return_reg)
   }
 #endif
 
-#ifdef SMALL_REGISTER_CLASSES
   /* Don't use the subroutine call return reg for a reload
      if we are supposed to avoid it.  */
   if (SMALL_REGISTER_CLASSES && avoid_return_reg)
@@ -5292,7 +5340,6 @@ choose_reload_regs (insn, avoid_return_reg)
        if (spill_reg_order[r] >= 0)
          SET_HARD_REG_BIT (reload_reg_used, r);
     }
-#endif /* SMALL_REGISTER_CLASSES */
 
   /* In order to be certain of getting the registers we need,
      we must sort the reloads into order of increasing register class.
@@ -5404,12 +5451,14 @@ choose_reload_regs (insn, avoid_return_reg)
          register int r = reload_order[j];
 
          /* Ignore reloads that got marked inoperative.  */
-         if (reload_out[r] == 0 && reload_in[r] == 0 && ! reload_secondary_p[r])
+         if (reload_out[r] == 0 && reload_in[r] == 0
+             && ! reload_secondary_p[r])
            continue;
 
          /* If find_reloads chose a to use reload_in or reload_out as a reload
-            register, we don't need to chose one.  Otherwise, try even if it found
-            one since we might save an insn if we find the value lying around.  */
+            register, we don't need to chose one.  Otherwise, try even if it
+            found one since we might save an insn if we find the value lying
+            around.  */
          if (reload_in[r] != 0 && reload_reg_rtx[r] != 0
              && (rtx_equal_p (reload_in[r], reload_reg_rtx[r])
                  || rtx_equal_p (reload_out[r], reload_reg_rtx[r])))
@@ -5441,9 +5490,9 @@ choose_reload_regs (insn, avoid_return_reg)
             an object that is already in a register of the desired class.
             This would avoid the need for the secondary reload register.
             But this is complex because we can't easily determine what
-            objects might want to be loaded via this reload.  So let a register
-            be allocated here.  In `emit_reload_insns' we suppress one of the
-            loads in the case described above.  */
+            objects might want to be loaded via this reload.  So let a
+            register be allocated here.  In `emit_reload_insns' we suppress
+            one of the loads in the case described above.  */
 
          if (inheritance)
            {
@@ -5843,7 +5892,7 @@ choose_reload_regs (insn, avoid_return_reg)
     }
 }
 \f
-/* If SMALL_REGISTER_CLASSES are defined, we may not have merged two
+/* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
    reloads of the same item for fear that we might not have enough reload
    registers. However, normally they will get the same reload register
    and hence actually need not be loaded twice.  
@@ -5856,8 +5905,6 @@ choose_reload_regs (insn, avoid_return_reg)
    This will not increase the number of spill registers needed and will
    prevent redundant code.  */
 
-#ifdef SMALL_REGISTER_CLASSES
-
 static void
 merge_assigned_reloads (insn)
      rtx insn;
@@ -5931,7 +5978,7 @@ merge_assigned_reloads (insn)
        }
     }
 }          
-#endif /* SMALL_RELOAD_CLASSES */
+
 \f
 /* Output insns to reload values in and out of the chosen reload regs.  */
 
@@ -6233,8 +6280,8 @@ emit_reload_insns (insn)
                  SET_DEST (PATTERN (temp)) = reloadreg;
                  /* If these are the only uses of the pseudo reg,
                     pretend for GDB it lives in the reload reg we used.  */
-                 if (reg_n_deaths[REGNO (old)] == 1
-                     && reg_n_sets[REGNO (old)] == 1)
+                 if (REG_N_DEATHS (REGNO (old)) == 1
+                     && REG_N_SETS (REGNO (old)) == 1)
                    {
                      reg_renumber[REGNO (old)] = REGNO (reload_reg_rtx[j]);
                      alter_reg (REGNO (old), -1);
@@ -7272,8 +7319,8 @@ delete_output_reload (insn, j, output_reload_insn)
   /* See if the pseudo reg has been completely replaced
      with reload regs.  If so, delete the store insn
      and forget we had a stack slot for the pseudo.  */
-  else if (reg_n_deaths[REGNO (reg)] == 1
-          && reg_basic_block[REGNO (reg)] >= 0
+  else if (REG_N_DEATHS (REGNO (reg)) == 1
+          && REG_BASIC_BLOCK (REGNO (reg)) >= 0
           && find_regno_note (insn, REG_DEAD, REGNO (reg)))
     {
       rtx i2;
@@ -7502,6 +7549,9 @@ count_occurrences (x, find)
       if (SET_DEST (x) == find)
        return count_occurrences (SET_SRC (x), find);
       break;
+      
+    default:
+      break;
     }
 
   format_ptr = GET_RTX_FORMAT (code);
@@ -7543,6 +7593,19 @@ count_occurrences (x, find)
 
 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;
+
+/* This is a set of registers for which we must remove REG_DEAD notes in
+   previous insns, because our modifications made them invalid.  That can
+   happen if we introduced the register into the current insn, or we deleted
+   the current insn which used to set the register.  */
+
+static HARD_REG_SET no_longer_dead_regs;
+
 /* 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
@@ -7586,7 +7649,7 @@ reload_cse_invalidate_regno (regno, mode, clobber)
       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))
+             && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
            {
              /* If this is the only entry on the list, clear
                  reg_values[i].  Otherwise, just clear this entry on
@@ -7600,17 +7663,41 @@ reload_cse_invalidate_regno (regno, mode, clobber)
            }
        }
     }
+
+  /* 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 (x));
+             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.  */
+/* The memory at address MEM_BASE is being changed.
+   Return whether this change will invalidate VAL.  */
 
 static int
-reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
+reload_cse_mem_conflict_p (mem_base, val)
      rtx mem_base;
-     rtx mem_offset;
-     enum machine_mode mem_mode;
      rtx val;
 {
   enum rtx_code code;
@@ -7622,7 +7709,6 @@ reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
     {
       /* Get rid of a few simple cases quickly. */
     case REG:
-    case SUBREG:
     case PC:
     case CC0:
     case SCRATCH:
@@ -7634,37 +7720,13 @@ reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
       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);
-
+      if (GET_MODE (mem_base) == BLKmode
+         || GET_MODE (val) == BLKmode)
        return 1;
-      }
+      if (anti_dependence (val, mem_base))
+       return 1;
+      /* The address may contain nested MEMs.  */
+      break;
 
     default:
       break;
@@ -7676,8 +7738,7 @@ reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
     {
       if (fmt[i] == 'e')
        {
-         if (reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode,
-                                        XEXP (val, i)))
+         if (reload_cse_mem_conflict_p (mem_base, XEXP (val, i)))
            return 1;
        }
       else if (fmt[i] == 'E')
@@ -7685,8 +7746,7 @@ reload_cse_mem_conflict_p (mem_base, mem_offset, mem_mode, val)
          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)))
+           if (reload_cse_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
              return 1;
        }
     }
@@ -7703,15 +7763,6 @@ 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++)
     {
@@ -7720,8 +7771,7 @@ reload_cse_invalidate_mem (mem_rtx)
       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)))
+             && reload_cse_mem_conflict_p (mem_rtx, XEXP (x, 0)))
            {
              /* If this is the only entry on the list, clear
                  reg_values[i].  Otherwise, just clear this entry on
@@ -7758,6 +7808,55 @@ reload_cse_invalidate_rtx (dest, ignore)
     reload_cse_invalidate_mem (dest);
 }
 
+/* Possibly delete death notes on the insns before INSN if modifying INSN
+   extended the lifespan of the registers.  */
+
+static void
+reload_cse_delete_death_notes (insn)
+     rtx insn;
+{
+  int dreg;
+
+  for (dreg = 0; dreg < FIRST_PSEUDO_REGISTER; dreg++)
+    {
+      rtx trial;
+
+      if (! TEST_HARD_REG_BIT (no_longer_dead_regs, dreg))
+       continue;
+
+      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;
+           }
+       }
+    }
+}
+
+/* Record that the current insn uses hard reg REGNO in mode MODE.  This
+   will be used in reload_cse_delete_death_notes to delete prior REG_DEAD
+   notes for this register.  */
+
+static void
+reload_cse_no_longer_dead (regno, mode)
+     int regno;
+     enum machine_mode mode;
+{
+  int nregs = HARD_REGNO_NREGS (regno, mode);
+  while (nregs-- > 0)
+    {
+      SET_HARD_REG_BIT (no_longer_dead_regs, regno);
+      regno++;
+    }
+}
+
+
 /* Do a very simple CSE pass over the hard registers.
 
    This function detects no-op moves where we happened to assign two
@@ -7768,9 +7867,14 @@ reload_cse_invalidate_rtx (dest, ignore)
    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.  */
+   second register.  
 
-static void
+   Another optimization is performed that scans the operands of each
+   instruction to see whether the value is already available in a
+   hard register.  It then replaces the operand with the hard register
+   if possible, much like an optional reload would.  */
+
+void
 reload_cse_regs (first)
      rtx first;
 {
@@ -7779,6 +7883,8 @@ reload_cse_regs (first)
   register int i;
   rtx insn;
 
+  init_alias_analysis ();
+
   reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     reg_values[i] = 0;
@@ -7792,6 +7898,10 @@ reload_cse_regs (first)
      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;
@@ -7820,6 +7930,8 @@ reload_cse_regs (first)
       if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
        continue;
 
+      CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
       /* If this is a call instruction, forget anything stored in a
         call clobbered register, or, if this is not a const call, in
         memory.  */
@@ -7836,44 +7948,61 @@ reload_cse_regs (first)
       body = PATTERN (insn);
       if (GET_CODE (body) == SET)
        {
-         if (reload_cse_noop_set_p (body))
+         int count = 0;
+         if (reload_cse_noop_set_p (body, insn))
            {
-             /* If we were preserving death notes, then we would want
-                to remove any existing death note for the register
-                being set.  */
              PUT_CODE (insn, NOTE);
              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (insn) = 0;
+             reload_cse_delete_death_notes (insn);
 
              /* We're done with this insn.  */
              continue;
            }
 
-         reload_cse_simplify_set (body, insn);
+         /* It's not a no-op, but we can try to simplify it.  */
+         CLEAR_HARD_REG_SET (no_longer_dead_regs);
+         count += reload_cse_simplify_set (body, insn);
+
+         if (count > 0 && apply_change_group ())
+           reload_cse_delete_death_notes (insn);
+         else if (reload_cse_simplify_operands (insn))
+           reload_cse_delete_death_notes (insn);
+           
          reload_cse_record_set (body, body);
        }
       else if (GET_CODE (body) == PARALLEL)
        {
-         int delete;
+         int count = 0;
 
          /* 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)))
+           if ((GET_CODE (XVECEXP (body, 0, i)) != SET
+                || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
+               && GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
              break;
          if (i < 0)
            {
-             /* If we were preserving death notes, then we would want
-                to remove any existing death notes for the registers
-                being set.  */
              PUT_CODE (insn, NOTE);
              NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
              NOTE_SOURCE_FILE (insn) = 0;
+             reload_cse_delete_death_notes (insn);
 
              /* We're done with this insn.  */
              continue;
            }
+         
+         /* It's not a no-op, but we can try to simplify it.  */
+         CLEAR_HARD_REG_SET (no_longer_dead_regs);
+         for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+           if (GET_CODE (XVECEXP (body, 0, i)) == SET)
+             count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
+
+         if (count > 0 && apply_change_group ())
+           reload_cse_delete_death_notes (insn);
+         else if (reload_cse_simplify_operands (insn))
+           reload_cse_delete_death_notes (insn);
 
          /* Look through the PARALLEL and record the values being
              set, if possible.  Also handle any CLOBBERs.  */
@@ -7942,6 +8071,14 @@ reload_cse_regno_equal_p (regno, val, mode)
        && (GET_CODE (val) != CONST_INT
            || mode == GET_MODE (x)
            || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+               /* On a big endian machine if the value spans more than
+                  one register then this register holds the high part of
+                  it and we can't use it.
+
+                  ??? We should also compare with the high part of the
+                  value.  */
+               && !(WORDS_BIG_ENDIAN
+                    && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
                && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
                                          GET_MODE_BITSIZE (GET_MODE (x))))))
       return 1;
@@ -7949,15 +8086,18 @@ reload_cse_regno_equal_p (regno, val, mode)
   return 0;
 }
 
-/* See whether a single SET instruction is a nooop.  */
+/* 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)
+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);
@@ -7969,27 +8109,51 @@ reload_cse_noop_set_p (set)
   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)
-       return 1;
+       ret = 1;
 
       /* Check for setting a register to a value which we already know
          is in the register.  */
-      if (reload_cse_regno_equal_p (dreg, src, dest_mode))
-       return 1;
+      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.  */
-      if (sreg >= 0)
+      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))
-             return 1;
+           {
+             rtx tmp;
+
+             if (XEXP (x, 0) == 0)
+               continue;
+
+             if (dest_mode == GET_MODE (x))
+               tmp = XEXP (x, 0);
+             else if (GET_MODE_BITSIZE (dest_mode)
+                      < GET_MODE_BITSIZE (GET_MODE (x)))
+               tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+             else
+               continue;
+
+             if (tmp
+                 && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
+               {
+                 ret = 1;
+                 break;
+               }
+           }
        }
     }
   else if (GET_CODE (dest) == MEM)
@@ -7999,16 +8163,27 @@ reload_cse_noop_set_p (set)
       if (sreg >= 0
          && reload_cse_regno_equal_p (sreg, dest, dest_mode)
          && ! side_effects_p (dest))
-       return 1;
+       ret = 1;
     }
 
-  return 0;
+  /* 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 && dreg >= 0)
+    {
+      if (! find_regno_note (insn, REG_UNUSED, dreg))
+       reload_cse_no_longer_dead (dreg, dest_mode);
+    }
+
+  return ret;
 }
 
 /* Try to simplify a single SET instruction.  SET is the set pattern.
-   INSN is the instruction it came from. */
+   INSN is the instruction it came from.
+   This function only handles 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.  */
 
-static void
+static int
 reload_cse_simplify_set (set, insn)
      rtx set;
      rtx insn;
@@ -8019,22 +8194,18 @@ reload_cse_simplify_set (set, insn)
   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;
+    return 0;
 
   src = SET_SRC (set);
   if (side_effects_p (src) || true_regnum (src) >= 0)
-    return;
+    return 0;
 
   /* 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;
+    return 0;
 
   dest_mode = GET_MODE (SET_DEST (set));
   dclass = REGNO_REG_CLASS (dreg);
@@ -8050,16 +8221,252 @@ reload_cse_simplify_set (set, insn)
          pop_obstacks ();
 
          validated = validate_change (insn, &SET_SRC (set),
-                                      gen_rtx (REG, dest_mode, i), 0);
+                                      gen_rtx (REG, dest_mode, i), 1);
 
          /* Go back to the obstack we are using for temporary
              storage.  */
          push_obstacks (&reload_obstack, &reload_obstack);
 
-         if (validated)
-           return;
+         if (validated && ! find_regno_note (insn, REG_UNUSED, i))
+           {
+             reload_cse_no_longer_dead (i, dest_mode);
+             return 1;
+           }
        }
     }
+  return 0;
+}
+
+/* Try to replace operands in INSN with equivalent values that are already
+   in registers.  This can be viewed as optional reloading.  
+   For each non-register operand in the insn, see if any hard regs are
+   known to be equivalent to that operand.  Record the alternatives which
+   can accept these hard registers.  Among all alternatives, select the
+   ones which are better or equal to the one currently matching, where
+   "better" is in terms of '?' and '!' constraints.  Among the remaining
+   alternatives, select the one which replaces most operands with
+   hard registers.  */
+
+static int
+reload_cse_simplify_operands (insn)
+     rtx insn;
+{
+#ifdef REGISTER_CONSTRAINTS
+  int insn_code_number, n_operands, n_alternatives;
+  int i,j;
+
+  char *constraints[MAX_RECOG_OPERANDS];
+  
+  /* Vector recording how bad an alternative is.  */
+  int *alternative_reject;
+  /* Vector recording how many registers can be introduced by choosing
+     this alternative.  */
+  int *alternative_nregs;
+  /* Array of vectors recording, for each operand and each alternative,
+     which hard register to substitute, or -1 if the operand should be
+     left as it is.  */
+  int *op_alt_regno[MAX_RECOG_OPERANDS];
+  /* Array of alternatives, sorted in order of decreasing desirability.  */
+  int *alternative_order;
+  
+  /* Find out some information about this insn.  */
+  insn_code_number = recog_memoized (insn);
+  /* We don't modify asm instructions.  */
+  if (insn_code_number < 0)
+    return 0;
+
+  n_operands = insn_n_operands[insn_code_number];
+  n_alternatives = insn_n_alternatives[insn_code_number];
+  
+  if (n_alternatives == 0 || n_operands == 0)
+    return;
+  insn_extract (insn);
+
+  /* Figure out which alternative currently matches.  */
+  if (! constrain_operands (insn_code_number, 1))
+    abort ();
+
+  alternative_reject = (int *) alloca (n_alternatives * sizeof (int));
+  alternative_nregs = (int *) alloca (n_alternatives * sizeof (int));
+  alternative_order = (int *) alloca (n_alternatives * sizeof (int));
+  bzero ((char *)alternative_reject, n_alternatives * sizeof (int));
+  bzero ((char *)alternative_nregs, n_alternatives * sizeof (int));
+
+  for (i = 0; i < n_operands; i++)
+    {
+      enum machine_mode mode;
+      int regno;
+      char *p;
+
+      op_alt_regno[i] = (int *) alloca (n_alternatives * sizeof (int));
+      for (j = 0; j < n_alternatives; j++)
+       op_alt_regno[i][j] = -1;
+
+      p = constraints[i] = insn_operand_constraint[insn_code_number][i];
+      mode = insn_operand_mode[insn_code_number][i];
+
+      /* Add the reject values for each alternative given by the constraints
+        for this operand.  */
+      j = 0;
+      while (*p != '\0')
+       {
+         char c = *p++;
+         if (c == ',')
+           j++;
+         else if (c == '?')
+           alternative_reject[j] += 3;
+         else if (c == '!')
+           alternative_reject[j] += 300;
+       }
+
+      /* We won't change operands which are already registers.  We
+        also don't want to modify output operands.  */
+      regno = true_regnum (recog_operand[i]);
+      if (regno >= 0
+         || constraints[i][0] == '='
+         || constraints[i][0] == '+')
+       continue;
+
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       {
+         int class = (int) NO_REGS;
+
+         if (! reload_cse_regno_equal_p (regno, recog_operand[i], mode))
+           continue;
+
+         /* We found a register equal to this operand.  Now look for all
+            alternatives that can accept this register and have not been
+            assigned a register they can use yet.  */
+         j = 0;
+         p = constraints[i];
+         for (;;)
+           {
+             char c = *p++;
+             
+             switch (c)
+               {
+               case '=':  case '+':  case '?':
+               case '#':  case '&':  case '!':
+               case '*':  case '%':  
+               case '0':  case '1':  case '2':  case '3':  case '4':
+               case 'm':  case '<':  case '>':  case 'V':  case 'o':
+               case 'E':  case 'F':  case 'G':  case 'H':
+               case 's':  case 'i':  case 'n':
+               case 'I':  case 'J':  case 'K':  case 'L':
+               case 'M':  case 'N':  case 'O':  case 'P':
+#ifdef EXTRA_CONSTRAINT
+               case 'Q':  case 'R':  case 'S':  case 'T':  case 'U':
+#endif
+               case 'p': case 'X':
+                 /* These don't say anything we care about.  */
+                 break;
+
+               case 'g': case 'r':
+                 class = reg_class_subunion[(int) class][(int) GENERAL_REGS];
+                 break;
+
+               default:
+                 class
+                   = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER (c)];
+                 break;
+
+               case ',': case '\0':
+                 /* See if REGNO fits this alternative, and set it up as the
+                    replacement register if we don't have one for this
+                    alternative yet.  */
+                 if (op_alt_regno[i][j] == -1
+                     && reg_fits_class_p (gen_rtx (REG, mode, regno), class,
+                                          0, mode))
+                   {
+                     alternative_nregs[j]++;
+                     op_alt_regno[i][j] = regno;
+                   }
+                 j++;
+                 break;
+               }
+
+             if (c == '\0')
+               break;
+           }
+       }
+    }
+
+  /* Record all alternatives which are better or equal to the currently
+     matching one in the alternative_order array.  */
+  for (i = j = 0; i < n_alternatives; i++)
+    if (alternative_reject[i] <= alternative_reject[which_alternative])
+      alternative_order[j++] = i;
+  n_alternatives = j;
+
+  /* Sort it.  Given a small number of alternatives, a dumb algorithm
+     won't hurt too much.  */
+  for (i = 0; i < n_alternatives - 1; i++)
+    {
+      int best = i;
+      int best_reject = alternative_reject[alternative_order[i]];
+      int best_nregs = alternative_nregs[alternative_order[i]];
+      int tmp;
+
+      for (j = i + 1; j < n_alternatives; j++)
+       {
+         int this_reject = alternative_reject[alternative_order[j]];
+         int this_nregs = alternative_nregs[alternative_order[j]];
+
+         if (this_reject < best_reject
+             || (this_reject == best_reject && this_nregs < best_nregs))
+           {
+             best = j;
+             best_reject = this_reject;
+             best_nregs = this_nregs;
+           }
+       }
+      
+      tmp = alternative_order[best];
+      alternative_order[best] = alternative_order[i];
+      alternative_order[i] = tmp;
+    }
+  
+  /* Substitute the operands as determined by op_alt_regno for the best
+     alternative.  */
+  j = alternative_order[0];
+  CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
+  /* Pop back to the real obstacks while changing the insn.  */
+  pop_obstacks ();
+
+  for (i = 0; i < n_operands; i++)
+    {
+      enum machine_mode mode = insn_operand_mode[insn_code_number][i];
+      if (op_alt_regno[i][j] == -1)
+       continue;
+
+      reload_cse_no_longer_dead (op_alt_regno[i][j], mode);
+      validate_change (insn, recog_operand_loc[i],
+                      gen_rtx (REG, mode, op_alt_regno[i][j]), 1);
+    }
+
+  for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
+    {
+      int op = recog_dup_num[i];
+      enum machine_mode mode = insn_operand_mode[insn_code_number][op];
+
+      if (op_alt_regno[op][j] == -1)
+       continue;
+
+      reload_cse_no_longer_dead (op_alt_regno[op][j], mode);
+      validate_change (insn, recog_dup_loc[i],
+                      gen_rtx (REG, mode, op_alt_regno[op][j]), 1);
+    }
+
+  /* Go back to the obstack we are using for temporary
+     storage.  */
+  push_obstacks (&reload_obstack, &reload_obstack);
+
+  return apply_change_group ();
+#else
+  return 0;
+#endif
 }
 
 /* These two variables are used to pass information from
@@ -8089,7 +8496,7 @@ reload_cse_record_set (set, body)
      rtx set;
      rtx body;
 {
-  rtx dest, src;
+  rtx dest, src, x;
   int dreg, sreg;
   enum machine_mode dest_mode;
 
@@ -8099,6 +8506,23 @@ reload_cse_record_set (set, body)
   sreg = true_regnum (src);
   dest_mode = GET_MODE (dest);
 
+  /* Some machines don't define AUTO_INC_DEC, but they still use push
+     instructions.  We need to catch that case here in order to
+     invalidate the stack pointer correctly.  Note that invalidating
+     the stack pointer is different from invalidating DEST.  */
+  x = dest;
+  while (GET_CODE (x) == SUBREG
+        || GET_CODE (x) == ZERO_EXTRACT
+        || GET_CODE (x) == SIGN_EXTRACT
+        || GET_CODE (x) == STRICT_LOW_PART)
+    x = XEXP (x, 0);
+  if (push_operand (x, GET_MODE (x)))
+    {
+      reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX);
+      reload_cse_invalidate_rtx (dest, NULL_RTX);
+      return;
+    }
+
   /* 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
@@ -8154,7 +8578,32 @@ reload_cse_record_set (set, body)
       /* This is an assignment to a register.  Update the value we
          have stored for the register.  */
       if (sreg >= 0)
-       reg_values[dreg] = reg_values[sreg];
+       {
+         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 if (GET_MODE_BITSIZE (dest_mode)
+                       > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
+               continue;
+             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);