OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index a0f15b3..bd0a225 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -75,27 +75,21 @@ Boston, MA 02111-1307, USA.  */
    combine anyway.  */
 
 #include "config.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-/* Must precede rtl.h for FFS.  */
-#include <stdio.h>
-
-#include "rtl.h"
+#include "system.h"
+#include "rtl.h" /* stdio.h must precede rtl.h for FFS.  */
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "expr.h"
 #include "basic-block.h"
 #include "insn-config.h"
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+#include "expr.h"
 #include "insn-flags.h"
 #include "insn-codes.h"
 #include "insn-attr.h"
 #include "recog.h"
 #include "real.h"
+#include "toplev.h"
 
 /* It is not safe to use ordinary gen_lowpart in combine.
    Use gen_lowpart_for_combine instead.  See comments there.  */
@@ -399,6 +393,7 @@ static void init_reg_last_arrays    PROTO((void));
 static void setup_incoming_promotions   PROTO((void));
 static void set_nonzero_bits_and_sign_copies  PROTO((rtx, rtx));
 static int can_combine_p       PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
+static int sets_function_arg_p PROTO((rtx));
 static int combinable_i3pat    PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
 static rtx try_combine         PROTO((rtx, rtx, rtx));
 static void undo_all           PROTO((void));
@@ -431,7 +426,7 @@ static int merge_outer_ops  PROTO((enum rtx_code *, HOST_WIDE_INT *,
                                       enum machine_mode, int *));
 static rtx simplify_shift_const        PROTO((rtx, enum rtx_code, enum machine_mode,
                                       rtx, int));
-static int recog_for_combine   PROTO((rtx *, rtx, rtx *, int *));
+static int recog_for_combine   PROTO((rtx *, rtx, rtx *));
 static rtx gen_lowpart_for_combine  PROTO((enum machine_mode, rtx));
 static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
                                  ...));
@@ -445,7 +440,7 @@ static void update_table_tick       PROTO((rtx));
 static void record_value_for_reg  PROTO((rtx, rtx, rtx));
 static void record_dead_and_set_regs_1  PROTO((rtx, rtx));
 static void record_dead_and_set_regs  PROTO((rtx));
-static int get_last_value_validate  PROTO((rtx *, int, int));
+static int get_last_value_validate  PROTO((rtx *, rtx, int, int));
 static rtx get_last_value      PROTO((rtx));
 static int use_crosses_set_p   PROTO((rtx, int));
 static void reg_dead_at_p_1    PROTO((rtx, rtx));
@@ -465,7 +460,10 @@ combine_instructions (f, nregs)
      rtx f;
      int nregs;
 {
-  register rtx insn, next, prev;
+  register rtx insn, next;
+#ifdef HAVE_cc0
+  register rtx prev;
+#endif
   register int i;
   register rtx links, nextlinks;
 
@@ -676,6 +674,9 @@ combine_instructions (f, nregs)
   total_successes += combine_successes;
 
   nonzero_sign_valid = 0;
+
+  /* Make recognizer allow volatile MEMs again.  */
+  init_recog ();
 }
 
 /* Wipe the reg_last_xxx arrays in preparation for another pass.  */
@@ -711,10 +712,13 @@ setup_incoming_promotions ()
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     if (FUNCTION_ARG_REGNO_P (regno)
        && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
-      record_value_for_reg (reg, first,
-                           gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
-                                    GET_MODE (reg),
-                                    gen_rtx (CLOBBER, mode, const0_rtx)));
+      {
+       record_value_for_reg
+         (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
+                                      : SIGN_EXTEND),
+                                     GET_MODE (reg),
+                                     gen_rtx_CLOBBER (mode, const0_rtx)));
+      }
 #endif
 }
 \f
@@ -740,8 +744,7 @@ set_nonzero_bits_and_sign_copies (x, set)
       && REGNO (x) >= FIRST_PSEUDO_REGISTER
       /* If this register is undefined at the start of the file, we can't
         say what its contents were.  */
-      && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
-           & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
+      && ! REGNO_REG_SET_P (basic_block_live_at_start[0], REGNO (x))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
       if (set == 0 || GET_CODE (set) == CLOBBER)
@@ -816,12 +819,16 @@ static int
 can_combine_p (insn, i3, pred, succ, pdest, psrc)
      rtx insn;
      rtx i3;
-     rtx pred, succ;
+     rtx pred ATTRIBUTE_UNUSED;
+     rtx succ;
      rtx *pdest, *psrc;
 {
   int i;
   rtx set = 0, src, dest;
-  rtx p, link;
+  rtx p;
+#ifdef AUTO_INC_DEC
+  rtx link;
+#endif
   int all_adjacent = (succ ? (next_active_insn (insn) == succ
                              && next_active_insn (succ) == i3)
                      : next_active_insn (insn) == i3);
@@ -852,6 +859,43 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
 
          switch (GET_CODE (elt))
            {
+           /* This is important to combine floating point insns
+              for the SH4 port.  */
+           case USE:
+             /* Combining an isolated USE doesn't make sense.
+                We depend here on combinable_i3_pat to reject them.  */
+             /* The code below this loop only verifies that the inputs of
+                the SET in INSN do not change.  We call reg_set_between_p
+                to verify that the REG in the USE does not change betweeen
+                I3 and INSN.
+                If the USE in INSN was for a pseudo register, the matching
+                insn pattern will likely match any register; combining this
+                with any other USE would only be safe if we knew that the
+                used registers have identical values, or if there was
+                something to tell them apart, e.g. different modes.  For
+                now, we forgo such compilcated tests and simply disallow
+                combining of USES of pseudo registers with any other USE.  */
+             if (GET_CODE (XEXP (elt, 0)) == REG
+                 && GET_CODE (PATTERN (i3)) == PARALLEL)
+               {
+                 rtx i3pat = PATTERN (i3);
+                 int i = XVECLEN (i3pat, 0) - 1;
+                 int regno = REGNO (XEXP (elt, 0));
+                 do
+                   {
+                     rtx i3elt = XVECEXP (i3pat, 0, i);
+                     if (GET_CODE (i3elt) == USE
+                         && GET_CODE (XEXP (i3elt, 0)) == REG
+                         && (REGNO (XEXP (i3elt, 0)) == regno
+                             ? reg_set_between_p (XEXP (elt, 0),
+                                                  PREV_INSN (insn), i3)
+                             : regno >= FIRST_PSEUDO_REGISTER))
+                       return 0;
+                   }
+                 while (--i >= 0);
+               }
+             break;
+
              /* We can ignore CLOBBERs.  */
            case CLOBBER:
              break;
@@ -910,8 +954,14 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
       /* Don't substitute into an incremented register.  */
       || FIND_REG_INC_NOTE (i3, dest)
       || (succ && FIND_REG_INC_NOTE (succ, dest))
+#if 0
       /* Don't combine the end of a libcall into anything.  */
+      /* ??? This gives worse code, and appears to be unnecessary, since no
+        pass after flow uses REG_LIBCALL/REG_RETVAL notes.  Local-alloc does
+        use REG_RETVAL notes for noconflict blocks, but other code here
+        makes sure that those insns don't disappear.  */
       || find_reg_note (insn, REG_RETVAL, NULL_RTX)
+#endif
       /* Make sure that DEST is not used after SUCC but before I3.  */
       || (succ && ! all_adjacent
          && reg_used_between_p (dest, succ, i3))
@@ -952,7 +1002,12 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
         insns.  Eliminate this problem by not combining with such an insn.
 
         Also, on some machines we don't want to extend the life of a hard
-        register.  */
+        register.
+
+        This is the same test done in can_combine except that we don't test
+        if SRC is a CALL operation to permit a hard register with
+        SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
+        into account.  */
 
       if (GET_CODE (src) == REG
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
@@ -966,13 +1021,10 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
                 inputs.  */
              || (REGNO (src) < FIRST_PSEUDO_REGISTER
                  && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
-#ifdef SMALL_REGISTER_CLASSES
                      || (SMALL_REGISTER_CLASSES
                          && ((! all_adjacent && ! REG_USERVAR_P (src))
                              || (FUNCTION_VALUE_REGNO_P (REGNO (src))
-                                 && ! REG_USERVAR_P (src))))
-#endif
-                     ))))
+                                 && ! REG_USERVAR_P (src))))))))
        return 0;
     }
   else if (GET_CODE (dest) != CC0)
@@ -990,14 +1042,26 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
        return 0;
 
   /* If INSN contains anything volatile, or is an `asm' (whether volatile
-     or not), reject, unless nothing volatile comes between it and I3,
-     with the exception of SUCC.  */
+     or not), reject, unless nothing volatile comes between it and I3 */
 
   if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
-    for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
-      if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
-         && p != succ && volatile_refs_p (PATTERN (p)))
-       return 0;
+    {
+      /* Make sure succ doesn't contain a volatile reference.  */
+      if (succ != 0 && volatile_refs_p (PATTERN (succ)))
+        return 0;
+  
+      for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
+        if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
+         && p != succ && volatile_refs_p (PATTERN (p)))
+       return 0;
+    }
+
+  /* If INSN is an asm, and DEST is a hard register, reject, since it has
+     to be an explicit register variable, and was chosen for a reason.  */
+
+  if (GET_CODE (src) == ASM_OPERANDS
+      && GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER)
+    return 0;
 
   /* If there are any volatile insns between INSN and I3, reject, because
      they might affect machine state.  */
@@ -1047,6 +1111,46 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
   return 1;
 }
 \f
+/* Check if PAT is an insn - or a part of it - used to set up an
+   argument for a function in a hard register.  */
+
+static int
+sets_function_arg_p (pat)
+     rtx pat;
+{
+  int i;
+  rtx inner_dest;
+
+  switch (GET_CODE (pat))
+    {
+    case INSN:
+      return sets_function_arg_p (PATTERN (pat));
+
+    case PARALLEL:
+      for (i = XVECLEN (pat, 0); --i >= 0;)
+       if (sets_function_arg_p (XVECEXP (pat, 0, i)))
+         return 1;
+
+      break;
+
+    case SET:
+      inner_dest = SET_DEST (pat);
+      while (GET_CODE (inner_dest) == STRICT_LOW_PART
+            || GET_CODE (inner_dest) == SUBREG
+            || GET_CODE (inner_dest) == ZERO_EXTRACT)
+       inner_dest = XEXP (inner_dest, 0);
+
+      return (GET_CODE (inner_dest) == REG
+             && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+             && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
+
+    default:
+      break;
+    }
+
+  return 0;
+}
+
 /* LOC is the location within I3 that contains its pattern or the component
    of a PARALLEL of the pattern.  We validate that it is valid for combining.
 
@@ -1075,7 +1179,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
    If I1_NOT_IN_SRC is non-zero, it means that finding I1 in the source
    of a SET must prevent combination from occurring.
 
-   On machines where SMALL_REGISTER_CLASSES is defined, we don't combine
+   On machines where SMALL_REGISTER_CLASSES is non-zero, we don't combine
    if the destination of a SET is a hard register that isn't a user
    variable.
 
@@ -1104,7 +1208,11 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
       rtx set = expand_field_assignment (x);
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
-      rtx inner_dest = dest, inner_src = src;
+      rtx inner_dest = dest;
+#if 0
+      rtx inner_src = src;
+#endif
 
       SUBST (*loc, set);
 
@@ -1142,22 +1250,28 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
       if ((inner_dest != dest
           && (reg_overlap_mentioned_p (i2dest, inner_dest)
               || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
+
          /* This is the same test done in can_combine_p except that we
             allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
-            CALL operation.
-            Moreover, we can't test all_adjacent; we don't have to, since
-            this instruction will stay in place, thus we are not considering
-            to increase the lifetime of INNER_DEST.  */
+            CALL operation. Moreover, we can't test all_adjacent; we don't
+            have to, since this instruction will stay in place, thus we are
+            not considering increasing the lifetime of INNER_DEST.
+
+            Also, if this insn sets a function argument, combining it with
+            something that might need a spill could clobber a previous
+            function argument; the all_adjacent test in can_combine_p also
+            checks this; here, we do a more specific test for this case.  */
+            
          || (GET_CODE (inner_dest) == REG
              && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
              && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
                                        GET_MODE (inner_dest))
-#ifdef SMALL_REGISTER_CLASSES
-                || (SMALL_REGISTER_CLASSES
-                    && GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest)
-                    && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))
-#endif
-                 ))
+                || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
+                    && ! REG_USERVAR_P (inner_dest)
+                    && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
+                        || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
+                            && i3 != 0
+                            && sets_function_arg_p (prev_nonnote_insn (i3)))))))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
        return 0;
 
@@ -1242,8 +1356,6 @@ try_combine (i3, i2, i1)
   int i3_subst_into_i2 = 0;
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
-  /* Number of clobbers of SCRATCH we had to add.  */
-  int i3_scratches = 0, i2_scratches = 0, other_scratches = 0;
 
   int maxreg;
   rtx temp;
@@ -1259,7 +1371,12 @@ try_combine (i3, i2, i1)
   if (GET_RTX_CLASS (GET_CODE (i3)) != 'i'
       || GET_RTX_CLASS (GET_CODE (i2)) != 'i'
       || (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i')
-      || find_reg_note (i3, REG_LIBCALL, NULL_RTX))
+#if 0
+      /* ??? This gives worse code, and appears to be unnecessary, since no
+        pass after flow uses REG_LIBCALL/REG_RETVAL notes.  */
+      || find_reg_note (i3, REG_LIBCALL, NULL_RTX)
+#endif
+)
     return 0;
 
   combine_attempts++;
@@ -1297,12 +1414,10 @@ try_combine (i3, i2, i1)
   if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
       && GET_CODE (SET_SRC (PATTERN (i3))) == REG
       && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
-#ifdef SMALL_REGISTER_CLASSES
       && (! SMALL_REGISTER_CLASSES
-         || GET_CODE (SET_DEST (PATTERN (i3))) != REG
-         || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
-         || REG_USERVAR_P (SET_DEST (PATTERN (i3))))
-#endif
+         || (GET_CODE (SET_DEST (PATTERN (i3))) != REG
+             || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
+             || REG_USERVAR_P (SET_DEST (PATTERN (i3)))))
       && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
       && GET_CODE (PATTERN (i2)) == PARALLEL
       && ! side_effects_p (SET_DEST (PATTERN (i3)))
@@ -1397,8 +1512,9 @@ try_combine (i3, i2, i1)
             as I2 will not cause a problem.  */
 
          subst_prev_insn = i1
-           = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
-                      XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
+           = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
+                           XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
+                           NULL_RTX);
 
          SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
          SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
@@ -1495,7 +1611,7 @@ try_combine (i3, i2, i1)
      I2DEST.  */
 
   i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
-          ? gen_rtx (SET, VOIDmode, i2dest, i2src)
+          ? gen_rtx_SET (VOIDmode, i2dest, i2src)
           : PATTERN (i2));
 
   if (added_sets_2)
@@ -1559,8 +1675,10 @@ try_combine (i3, i2, i1)
       && XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
       && rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
     {
+#ifdef EXTRA_CC_MODES
       rtx *cc_use;
       enum machine_mode compare_mode;
+#endif
 
       newpat = PATTERN (i3);
       SUBST (XEXP (SET_SRC (newpat), 0), i2src);
@@ -1581,10 +1699,10 @@ try_combine (i3, i2, i1)
              != GET_MODE (SET_DEST (newpat))))
        {
          int regno = REGNO (SET_DEST (newpat));
-         rtx new_dest = gen_rtx (REG, compare_mode, regno);
+         rtx new_dest = gen_rtx_REG (compare_mode, regno);
 
          if (regno < FIRST_PSEUDO_REGISTER
-             || (reg_n_sets[regno] == 1 && ! added_sets_2
+             || (REG_N_SETS (regno) == 1 && ! added_sets_2
                  && ! REG_USERVAR_P (SET_DEST (newpat))))
            {
              if (regno >= FIRST_PSEUDO_REGISTER)
@@ -1675,7 +1793,7 @@ try_combine (i3, i2, i1)
        {
          rtvec old = XVEC (newpat, 0);
          total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
-         newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
+         newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
          bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
                 sizeof (old->elem[0]) * old->num_elem);
        }
@@ -1683,14 +1801,14 @@ try_combine (i3, i2, i1)
        {
          rtx old = newpat;
          total_sets = 1 + added_sets_1 + added_sets_2;
-         newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
+         newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
          XVECEXP (newpat, 0, 0) = old;
        }
 
      if (added_sets_1)
        XVECEXP (newpat, 0, --total_sets)
         = (GET_CODE (PATTERN (i1)) == PARALLEL
-           ? gen_rtx (SET, VOIDmode, i1dest, i1src) : PATTERN (i1));
+           ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1));
 
      if (added_sets_2)
        {
@@ -1714,8 +1832,7 @@ try_combine (i3, i2, i1)
   mark_used_regs_combine (newpat);
 
   /* Is the result of combination a valid instruction?  */
-  insn_code_number
-    = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+  insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
   /* If the result isn't valid, see if it is a PARALLEL of two SETs where
      the second SET's destination is a register that is unused.  In that case,
@@ -1736,8 +1853,7 @@ try_combine (i3, i2, i1)
       && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 0);
-      insn_code_number
-       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
@@ -1750,8 +1866,7 @@ try_combine (i3, i2, i1)
           && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 1);
-      insn_code_number
-       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   /* If we were combining three insns and the result is a simple SET
@@ -1787,17 +1902,17 @@ try_combine (i3, i2, i1)
              && GET_MODE (SET_DEST (newpat)) != VOIDmode
              && GET_CODE (i2dest) == REG
              && (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-                 || (reg_n_sets[REGNO (i2dest)] == 1 && ! added_sets_2
+                 || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
                      && ! REG_USERVAR_P (i2dest))))
-           ni2dest = gen_rtx (REG, GET_MODE (SET_DEST (newpat)),
+           ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
                               REGNO (i2dest));
 
-         m_split = split_insns (gen_rtx (PARALLEL, VOIDmode,
-                                         gen_rtvec (2, newpat,
-                                                    gen_rtx (CLOBBER,
-                                                             VOIDmode,
-                                                             ni2dest))),
-                                i3);
+         m_split = split_insns
+           (gen_rtx_PARALLEL (VOIDmode,
+                              gen_rtvec (2, newpat,
+                                         gen_rtx_CLOBBER (VOIDmode,
+                                                          ni2dest))),
+            i3);
        }
 
       if (m_split && GET_CODE (m_split) == SEQUENCE
@@ -1820,8 +1935,7 @@ try_combine (i3, i2, i1)
          if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
            SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
 
-         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
-                                             &i2_scratches);
+         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* If I2 or I3 has multiple SETs, we won't know how to track
             register status, so don't use these insns.  If I2's destination
@@ -1830,8 +1944,8 @@ try_combine (i3, i2, i1)
          if (i2_code_number >= 0 && i2set && i3set
              && (next_real_insn (i2) == i3
                  || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
-           insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
-                                                 &i3_scratches); 
+           insn_code_number = recog_for_combine (&newi3pat, i3,
+                                                 &new_i3_notes);
          if (insn_code_number >= 0)
            newpat = newi3pat;
 
@@ -1856,7 +1970,7 @@ try_combine (i3, i2, i1)
              if (GET_CODE (new_i3_dest) == REG
                  && GET_CODE (new_i2_dest) == REG
                  && REGNO (new_i3_dest) == REGNO (new_i2_dest))
-               reg_n_sets[REGNO (new_i2_dest)]++;
+               REG_N_SETS (REGNO (new_i2_dest))++;
            }
        }
 
@@ -1872,7 +1986,7 @@ try_combine (i3, i2, i1)
          && (GET_MODE (*split) == GET_MODE (i2dest)
              || GET_MODE (*split) == VOIDmode
              || REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-             || (reg_n_sets[REGNO (i2dest)] == 1 && ! added_sets_2
+             || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
                  && ! REG_USERVAR_P (i2dest)))
          && (next_real_insn (i2) == i3
              || ! use_crosses_set_p (*split, INSN_CUID (i2)))
@@ -1888,7 +2002,7 @@ try_combine (i3, i2, i1)
             validated that we can do this.  */
          if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
            {
-             newdest = gen_rtx (REG, split_mode, REGNO (i2dest));
+             newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
 
              if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
                SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
@@ -1918,14 +2032,12 @@ try_combine (i3, i2, i1)
 
          newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
          SUBST (*split, newdest);
-         i2_code_number
-           = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* If the split point was a MULT and we didn't have one before,
             don't use one now.  */
          if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
-           insn_code_number
-             = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+           insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
        }
     }
 
@@ -1979,12 +2091,10 @@ try_combine (i3, i2, i1)
       newpat = XVECEXP (newpat, 0, 1);
       SUBST (SET_SRC (newpat),
             gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
-      i2_code_number
-       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-       insn_code_number
-         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
       if (insn_code_number >= 0)
        {
@@ -2001,7 +2111,7 @@ try_combine (i3, i2, i1)
             that destination.  */
 
          PATTERN (i3) = newpat;
-         distribute_links (gen_rtx (INSN_LIST, VOIDmode, i3, NULL_RTX));
+         distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
 
          /* I3 now uses what used to be its destination and which is
             now I2's destination.  That means we need a LOG_LINK from
@@ -2055,15 +2165,26 @@ try_combine (i3, i2, i1)
           && ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
                                  XVECEXP (newpat, 0, 1)))
     {
-      newi2pat = XVECEXP (newpat, 0, 1);
-      newpat = XVECEXP (newpat, 0, 0);
+      /* Normally, it doesn't matter which of the two is done first,
+        but it does if one references cc0.  In that case, it has to
+        be first.  */
+#ifdef HAVE_cc0
+      if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0)))
+       {
+         newi2pat = XVECEXP (newpat, 0, 0);
+         newpat = XVECEXP (newpat, 0, 1);
+       }
+      else
+#endif
+       {
+         newi2pat = XVECEXP (newpat, 0, 1);
+         newpat = XVECEXP (newpat, 0, 0);
+       }
 
-      i2_code_number
-       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-       insn_code_number
-         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
+       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
   /* If it still isn't recognized, fail and change things back the way they
@@ -2085,9 +2206,8 @@ try_combine (i3, i2, i1)
 
       CLEAR_HARD_REG_SET (newpat_used_regs);
 
-      other_code_number
-       = recog_for_combine (&other_pat, undobuf.other_insn,
-                            &new_other_notes, &other_scratches);
+      other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
+                                            &new_other_notes);
 
       if (other_code_number < 0 && ! check_asm_operands (other_pat))
        {
@@ -2108,7 +2228,7 @@ try_combine (i3, i2, i1)
              && ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
            {
              if (GET_CODE (XEXP (note, 0)) == REG)
-               reg_n_deaths[REGNO (XEXP (note, 0))]--;
+               REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
 
              remove_note (undobuf.other_insn, note);
            }
@@ -2116,7 +2236,7 @@ try_combine (i3, i2, i1)
 
       for (note = new_other_notes; note; note = XEXP (note, 1))
        if (GET_CODE (XEXP (note, 0)) == REG)
-         reg_n_deaths[REGNO (XEXP (note, 0))]++;
+         REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
 
       distribute_notes (new_other_notes, undobuf.other_insn,
                        undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -2130,10 +2250,15 @@ try_combine (i3, i2, i1)
     rtx i3links, i2links, i1links = 0;
     rtx midnotes = 0;
     register int regno;
-    /* Compute which registers we expect to eliminate.  */
-    rtx elim_i2 = (newi2pat || i2dest_in_i2src || i2dest_in_i1src
+    /* Compute which registers we expect to eliminate.  newi2pat may be setting
+       either i3dest or i2dest, so we must check it.  Also, i1dest may be the
+       same as i3dest, in which case newi2pat may be setting i1dest.  */
+    rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
+                  || i2dest_in_i2src || i2dest_in_i1src
                   ? 0 : i2dest);
-    rtx elim_i1 = i1 == 0 || i1dest_in_i1src ? 0 : i1dest;
+    rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
+                  || (newi2pat && reg_set_p (i1dest, newi2pat))
+                  ? 0 : i1dest);
 
     /* Get the old REG_NOTES and LOG_LINKS from all our insns and
        clear them.  */
@@ -2267,7 +2392,7 @@ try_combine (i3, i2, i1)
       {
        for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
          if (GET_CODE (XEXP (temp, 0)) == REG)
-           reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+           REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
        
        distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
       }
@@ -2276,41 +2401,44 @@ try_combine (i3, i2, i1)
       {
        for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
          if (GET_CODE (XEXP (temp, 0)) == REG)
-           reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+           REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
        
        distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
       }
 
     /* If I3DEST was used in I3SRC, it really died in I3.  We may need to
-       put a REG_DEAD note for it somewhere.  Similarly for I2 and I1.
+       put a REG_DEAD note for it somewhere.  If NEWI2PAT exists and sets
+       I3DEST, the death must be somewhere before I2, not I3.  If we passed I3
+       in that case, it might delete I2.  Similarly for I2 and I1.
        Show an additional death due to the REG_DEAD note we make here.  If
        we discard it in distribute_notes, we will decrement it again.  */
 
     if (i3dest_killed)
       {
        if (GET_CODE (i3dest_killed) == REG)
-         reg_n_deaths[REGNO (i3dest_killed)]++;
+         REG_N_DEATHS (REGNO (i3dest_killed))++;
 
-       distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed,
-                                  NULL_RTX),
-                         NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
-                         NULL_RTX, NULL_RTX);
+       if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
+                                              NULL_RTX),
+                           NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
+       else
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
+                                              NULL_RTX),
+                           NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+                           elim_i2, elim_i1);
       }
 
-    /* For I2 and I1, we have to be careful.  If NEWI2PAT exists and sets
-       I2DEST or I1DEST, the death must be somewhere before I2, not I3.  If
-       we passed I3 in that case, it might delete I2.  */
-
     if (i2dest_in_i2src)
       {
        if (GET_CODE (i2dest) == REG)
-         reg_n_deaths[REGNO (i2dest)]++;
+         REG_N_DEATHS (REGNO (i2dest))++;
 
        if (newi2pat && reg_set_p (i2dest, newi2pat))
-         distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
                            NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
        else
-         distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
                            NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
                            NULL_RTX, NULL_RTX);
       }
@@ -2318,13 +2446,13 @@ try_combine (i3, i2, i1)
     if (i1dest_in_i1src)
       {
        if (GET_CODE (i1dest) == REG)
-         reg_n_deaths[REGNO (i1dest)]++;
+         REG_N_DEATHS (REGNO (i1dest))++;
 
        if (newi2pat && reg_set_p (i1dest, newi2pat))
-         distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
                            NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
        else
-         distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
+         distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
                            NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
                            NULL_RTX, NULL_RTX);
       }
@@ -2360,11 +2488,10 @@ try_combine (i3, i2, i1)
            && ! i2dest_in_i2src)
          {
            regno = REGNO (i2dest);
-           reg_n_sets[regno]--;
-           if (reg_n_sets[regno] == 0
-               && ! (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
-                     & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
-             reg_n_refs[regno] = 0;
+           REG_N_SETS (regno)--;
+           if (REG_N_SETS (regno) == 0
+               && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+             REG_N_REFS (regno) = 0;
          }
       }
 
@@ -2383,11 +2510,10 @@ try_combine (i3, i2, i1)
        regno = REGNO (i1dest);
        if (! added_sets_1 && ! i1dest_in_i1src)
          {
-           reg_n_sets[regno]--;
-           if (reg_n_sets[regno] == 0
-               && ! (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
-                     & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
-             reg_n_refs[regno] = 0;
+           REG_N_SETS (regno)--;
+           if (REG_N_SETS (regno) == 0
+               && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+             REG_N_REFS (regno) = 0;
          }
       }
 
@@ -2398,12 +2524,6 @@ try_combine (i3, i2, i1)
     if (newi2pat)
       note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
 
-    /* If we added any (clobber (scratch)), add them to the max for a
-       block.  This is a very pessimistic calculation, since we might
-       have had them already and this might not be the worst block, but
-       it's not worth doing any better.  */
-    max_scratch += i3_scratches + i2_scratches + other_scratches;
-
     /* If I3 is now an unconditional jump, ensure that it has a 
        BARRIER following it since it may have initially been a
        conditional jump.  It may also be the last nonnote insn.  */
@@ -2510,7 +2630,7 @@ find_split_point (loc, insn)
          && ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
        {
          rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
-         rtx seq = split_insns (gen_rtx (SET, VOIDmode, reg, XEXP (x, 0)),
+         rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
                                 subst_insn);
 
          /* This should have produced two insns, each of which sets our
@@ -2615,7 +2735,7 @@ find_split_point (loc, insn)
          if (BITS_BIG_ENDIAN)
            pos = GET_MODE_BITSIZE (mode) - len - pos;
 
-         if (src == mask)
+         if ((unsigned HOST_WIDE_INT) src == mask)
            SUBST (SET_SRC (x),
                   gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
          else
@@ -2674,7 +2794,7 @@ find_split_point (loc, insn)
             is known to be on, this can be converted into a NEG of a shift. */
          if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
              && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
-             && 1 <= (len = exact_log2
+             && 1 <= (pos = exact_log2
                       (nonzero_bits (XEXP (SET_SRC (x), 0),
                                      GET_MODE (XEXP (SET_SRC (x), 0))))))
            {
@@ -2684,7 +2804,7 @@ find_split_point (loc, insn)
                     gen_rtx_combine (NEG, mode,
                                      gen_rtx_combine (LSHIFTRT, mode,
                                                       XEXP (SET_SRC (x), 0),
-                                                      GEN_INT (len))));
+                                                      GEN_INT (pos))));
 
              split = find_split_point (&SET_SRC (x), insn);
              if (split && split != &SET_SRC (x))
@@ -2694,6 +2814,14 @@ find_split_point (loc, insn)
 
        case SIGN_EXTEND:
          inner = XEXP (SET_SRC (x), 0);
+
+         /* We can't optimize if either mode is a partial integer
+            mode as we don't know how many bits are significant
+            in those modes.  */
+         if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
+             || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+           break;
+
          pos = 0;
          len = GET_MODE_BITSIZE (GET_MODE (inner));
          unsignedp = 0;
@@ -2713,6 +2841,9 @@ find_split_point (loc, insn)
              unsignedp = (code == ZERO_EXTRACT);
            }
          break;
+
+       default:
+         break;
        }
 
       if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner)))
@@ -2809,6 +2940,9 @@ find_split_point (loc, insn)
          SUBST (XEXP (x, 1), tem);
        }
       break;
+
+    default:
+      break;
     }
 
   /* Otherwise, select our actions depending on our rtx class.  */
@@ -2898,7 +3032,7 @@ subst (x, from, to, in_dest, unique_copy)
      So force this insn not to match in this (rare) case.  */
   if (! in_dest && code == REG && GET_CODE (from) == REG
       && REGNO (x) == REGNO (from))
-    return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+    return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
   /* If this is an object, we are done unless it is a MEM or LO_SUM, both
      of which may contain things that can be combined.  */
@@ -2914,103 +3048,154 @@ subst (x, from, to, in_dest, unique_copy)
   if (COMBINE_RTX_EQUAL_P (x, to))
     return to;
 
-  len = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
+  /* Parallel asm_operands need special attention because all of the
+     inputs are shared across the arms.  Furthermore, unsharing the
+     rtl results in recognition failures.  Failure to handle this case
+     specially can result in circular rtl.
 
-  /* We don't need to process a SET_DEST that is a register, CC0, or PC, so
-     set up to skip this common case.  All other cases where we want to
-     suppress replacing something inside a SET_SRC are handled via the
-     IN_DEST operand.  */
-  if (code == SET
-      && (GET_CODE (SET_DEST (x)) == REG
-        || GET_CODE (SET_DEST (x)) == CC0
-        || GET_CODE (SET_DEST (x)) == PC))
-    fmt = "ie";
-
-  /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
-     constant.  */
-  if (fmt[0] == 'e')
-    op0_mode = GET_MODE (XEXP (x, 0));
+     Solve this by doing a normal pass across the first entry of the
+     parallel, and only processing the SET_DESTs of the subsequent
+     entries.  Ug.  */
 
-  for (i = 0; i < len; i++)
+  if (code == PARALLEL
+      && GET_CODE (XVECEXP (x, 0, 0)) == SET
+      && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
     {
-      if (fmt[i] == 'E')
+      new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+
+      /* If this substitution failed, this whole thing fails.  */
+      if (GET_CODE (new) == CLOBBER
+         && XEXP (new, 0) == const0_rtx)
+       return new;
+
+      SUBST (XVECEXP (x, 0, 0), new);
+
+      for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
        {
-         register int j;
-         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+         rtx dest = SET_DEST (XVECEXP (x, 0, i));
+         
+         if (GET_CODE (dest) != REG
+             && GET_CODE (dest) != CC0
+             && GET_CODE (dest) != PC)
            {
-             if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
-               {
-                 new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
-                 n_occurrences++;
-               }
-             else
-               {
-                 new = subst (XVECEXP (x, i, j), from, to, 0, unique_copy);
+             new = subst (dest, from, to, 0, unique_copy);
 
-                 /* If this substitution failed, this whole thing fails.  */
-                 if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
-                   return new;
-               }
+             /* If this substitution failed, this whole thing fails.  */
+             if (GET_CODE (new) == CLOBBER
+                 && XEXP (new, 0) == const0_rtx)
+               return new;
 
-             SUBST (XVECEXP (x, i, j), new);
+             SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
            }
        }
-      else if (fmt[i] == 'e')
+    }
+  else
+    {
+      len = GET_RTX_LENGTH (code);
+      fmt = GET_RTX_FORMAT (code);
+
+      /* We don't need to process a SET_DEST that is a register, CC0,
+        or PC, so set up to skip this common case.  All other cases
+        where we want to suppress replacing something inside a
+        SET_SRC are handled via the IN_DEST operand.  */
+      if (code == SET
+         && (GET_CODE (SET_DEST (x)) == REG
+             || GET_CODE (SET_DEST (x)) == CC0
+             || GET_CODE (SET_DEST (x)) == PC))
+       fmt = "ie";
+
+      /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+        constant.  */
+      if (fmt[0] == 'e')
+       op0_mode = GET_MODE (XEXP (x, 0));
+
+      for (i = 0; i < len; i++)
        {
-         if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+         if (fmt[i] == 'E')
            {
-             /* In general, don't install a subreg involving two modes not
-                tieable.  It can worsen register allocation, and can even
-                make invalid reload insns, since the reg inside may need to
-                be copied from in the outside mode, and that may be invalid
-                if it is an fp reg copied in integer mode.
-
-                We allow two exceptions to this: It is valid if it is inside
-                another SUBREG and the mode of that SUBREG and the mode of
-                the inside of TO is tieable and it is valid if X is a SET
-                that copies FROM to CC0.  */
-             if (GET_CODE (to) == SUBREG
-                 && ! MODES_TIEABLE_P (GET_MODE (to),
-                                       GET_MODE (SUBREG_REG (to)))
-                 && ! (code == SUBREG
-                       && MODES_TIEABLE_P (GET_MODE (x),
-                                           GET_MODE (SUBREG_REG (to))))
+             register int j;
+             for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+               {
+                 if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
+                   {
+                     new = (unique_copy && n_occurrences
+                            ? copy_rtx (to) : to);
+                     n_occurrences++;
+                   }
+                 else
+                   {
+                     new = subst (XVECEXP (x, i, j), from, to, 0,
+                                  unique_copy);
+
+                     /* If this substitution failed, this whole thing
+                        fails.  */
+                     if (GET_CODE (new) == CLOBBER
+                         && XEXP (new, 0) == const0_rtx)
+                       return new;
+                   }
+
+                 SUBST (XVECEXP (x, i, j), new);
+               }
+           }
+         else if (fmt[i] == 'e')
+           {
+             if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+               {
+                 /* In general, don't install a subreg involving two
+                    modes not tieable.  It can worsen register
+                    allocation, and can even make invalid reload
+                    insns, since the reg inside may need to be copied
+                    from in the outside mode, and that may be invalid
+                    if it is an fp reg copied in integer mode.
+
+                    We allow two exceptions to this: It is valid if
+                    it is inside another SUBREG and the mode of that
+                    SUBREG and the mode of the inside of TO is
+                    tieable and it is valid if X is a SET that copies
+                    FROM to CC0.  */
+
+                 if (GET_CODE (to) == SUBREG
+                     && ! MODES_TIEABLE_P (GET_MODE (to),
+                                           GET_MODE (SUBREG_REG (to)))
+                     && ! (code == SUBREG
+                           && MODES_TIEABLE_P (GET_MODE (x),
+                                               GET_MODE (SUBREG_REG (to))))
 #ifdef HAVE_cc0
-                 && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
+                     && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
 #endif
-                 )
-               return gen_rtx (CLOBBER, VOIDmode, const0_rtx);
+                     )
+                   return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
 
-             new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
-             n_occurrences++;
+                 new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+                 n_occurrences++;
+               }
+             else
+               /* If we are in a SET_DEST, suppress most cases unless we
+                  have gone inside a MEM, in which case we want to
+                  simplify the address.  We assume here that things that
+                  are actually part of the destination have their inner
+                  parts in the first expression.  This is true for SUBREG, 
+                  STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
+                  things aside from REG and MEM that should appear in a
+                  SET_DEST.  */
+               new = subst (XEXP (x, i), from, to,
+                            (((in_dest
+                               && (code == SUBREG || code == STRICT_LOW_PART
+                                   || code == ZERO_EXTRACT))
+                              || code == SET)
+                             && i == 0), unique_copy);
+
+             /* If we found that we will have to reject this combination,
+                indicate that by returning the CLOBBER ourselves, rather than
+                an expression containing it.  This will speed things up as
+                well as prevent accidents where two CLOBBERs are considered
+                to be equal, thus producing an incorrect simplification.  */
+
+             if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
+               return new;
+
+             SUBST (XEXP (x, i), new);
            }
-         else
-           /* If we are in a SET_DEST, suppress most cases unless we
-              have gone inside a MEM, in which case we want to
-              simplify the address.  We assume here that things that
-              are actually part of the destination have their inner
-              parts in the first expression.  This is true for SUBREG, 
-              STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
-              things aside from REG and MEM that should appear in a
-              SET_DEST.  */
-           new = subst (XEXP (x, i), from, to,
-                        (((in_dest
-                           && (code == SUBREG || code == STRICT_LOW_PART
-                               || code == ZERO_EXTRACT))
-                          || code == SET)
-                         && i == 0), unique_copy);
-
-         /* If we found that we will have to reject this combination,
-            indicate that by returning the CLOBBER ourselves, rather than
-            an expression containing it.  This will speed things up as
-            well as prevent accidents where two CLOBBERs are considered
-            to be equal, thus producing an incorrect simplification.  */
-
-         if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
-           return new;
-
-         SUBST (XEXP (x, i), new);
        }
     }
 
@@ -3182,9 +3367,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
                           gen_binary (reverse_condition (cond_code), 
                                       mode, cond, cop1));
          else
-           return gen_rtx (IF_THEN_ELSE, mode,
-                           gen_binary (cond_code, VOIDmode, cond, cop1),
-                           true, false);
+           return gen_rtx_IF_THEN_ELSE (mode,
+                                        gen_binary (cond_code, VOIDmode,
+                                                    cond, cop1),
+                                        true, false);
 
          code = GET_CODE (x);
          op0_mode = VOIDmode;
@@ -3300,7 +3486,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
             if that would change the meaning of the address.  */
          if (MEM_VOLATILE_P (SUBREG_REG (x))
              || mode_dependent_address_p (XEXP (inner, 0)))
-           return gen_rtx (CLOBBER, mode, const0_rtx);
+           return gen_rtx_CLOBBER (mode, const0_rtx);
 
          if (BYTES_BIG_ENDIAN)
            {
@@ -3312,10 +3498,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
            }
          /* Note if the plus_constant doesn't make a valid address
             then this combination won't be accepted.  */
-         x = gen_rtx (MEM, mode,
-                      plus_constant (XEXP (inner, 0),
-                                     (SUBREG_WORD (x) * UNITS_PER_WORD
-                                      + endian_offset)));
+         x = gen_rtx_MEM (mode,
+                          plus_constant (XEXP (inner, 0),
+                                         (SUBREG_WORD (x) * UNITS_PER_WORD
+                                          + endian_offset)));
          MEM_VOLATILE_P (x) = MEM_VOLATILE_P (inner);
          RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (inner);
          MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (inner);
@@ -3357,10 +3543,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
        {
          if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x),
                                  mode))
-           return gen_rtx (REG, mode,
-                           REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+           return gen_rtx_REG (mode,
+                               REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
          else
-           return gen_rtx (CLOBBER, mode, const0_rtx);
+           return gen_rtx_CLOBBER (mode, const0_rtx);
        }
 
       /* For a constant, try to pick up the part we want.  Handle a full
@@ -3370,7 +3556,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
 
       if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
          && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-         && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD
+         && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
          && GET_MODE_CLASS (mode) == MODE_INT)
        {
          temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
@@ -3382,8 +3568,16 @@ simplify_rtx (x, op0_mode, last, in_dest)
       /* If we want a subreg of a constant, at offset 0,
         take the low bits.  On a little-endian machine, that's
         always valid.  On a big-endian machine, it's valid
-        only if the constant's mode fits in one word.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
+        only if the constant's mode fits in one word.   Note that we
+        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      if (CONSTANT_P (SUBREG_REG (x))
+         && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+             || ! WORDS_BIG_ENDIAN)
+             ? SUBREG_WORD (x) == 0
+             : (SUBREG_WORD (x)
+                == ((GET_MODE_SIZE (op0_mode)
+                     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+                    / UNITS_PER_WORD)))
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
          && (! WORDS_BIG_ENDIAN
              || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
@@ -3426,8 +3620,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
         but this doesn't seem common enough to bother with.  */
       if (GET_CODE (XEXP (x, 0)) == ASHIFT
          && XEXP (XEXP (x, 0), 0) == const1_rtx)
-       return gen_rtx (ROTATE, mode, gen_unary (NOT, mode, mode, const1_rtx),
-                       XEXP (XEXP (x, 0), 1));
+       return gen_rtx_ROTATE (mode, gen_unary (NOT, mode, mode, const1_rtx),
+                              XEXP (XEXP (x, 0), 1));
                                            
       if (GET_CODE (XEXP (x, 0)) == SUBREG
          && subreg_lowpart_p (XEXP (x, 0))
@@ -3438,9 +3632,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
        {
          enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
 
-         x = gen_rtx (ROTATE, inner_mode,
-                      gen_unary (NOT, inner_mode, inner_mode, const1_rtx),
-                      XEXP (SUBREG_REG (XEXP (x, 0)), 1));
+         x = gen_rtx_ROTATE (inner_mode,
+                             gen_unary (NOT, inner_mode, inner_mode,
+                                        const1_rtx),
+                             XEXP (SUBREG_REG (XEXP (x, 0)), 1));
          return gen_lowpart_for_combine (mode, x);
        }
                                            
@@ -3577,7 +3772,15 @@ simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case TRUNCATE:
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+      /* We can't handle truncation to a partial integer mode here
+        because we don't know the real bitsize of the partial
+        integer mode.  */
+      if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+       break;
+
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                   GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
        SUBST (XEXP (x, 0),
               force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
                              GET_MODE_MASK (mode), NULL_RTX, 0));
@@ -3606,10 +3809,12 @@ simplify_rtx (x, op0_mode, last, in_dest)
        return SUBREG_REG (XEXP (x, 0));
 
       /* If we know that the value is already truncated, we can
-         replace the TRUNCATE with a SUBREG.  */
-      if (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-             &~ GET_MODE_MASK (mode)) == 0)
+         replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION is
+        nonzero for the corresponding modes.  */
+      if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
+         && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+            >= GET_MODE_BITSIZE (mode) + 1)
        return gen_lowpart_for_combine (mode, XEXP (x, 0));
 
       /* A truncate of a comparison can be replaced with a subreg if
@@ -3950,7 +4155,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
          if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
              && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-                 == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+                 == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE(mode)-1))
              && op1 == const0_rtx
              && mode == GET_MODE (op0)
              && (i = exact_log2 (nonzero_bits (op0, mode))) >= 0)
@@ -3996,11 +4201,16 @@ simplify_rtx (x, op0_mode, last, in_dest)
     case XOR:
       return simplify_logical (x, last);
 
-    case ABS:
+    case ABS:      
       /* (abs (neg <foo>)) -> (abs <foo>) */
       if (GET_CODE (XEXP (x, 0)) == NEG)
        SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
 
+      /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
+         do nothing.  */
+      if (GET_MODE (XEXP (x, 0)) == VOIDmode)
+       break;
+
       /* If operand is something known to be positive, ignore the ABS.  */
       if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
          || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
@@ -4052,6 +4262,9 @@ simplify_rtx (x, op0_mode, last, in_dest)
 #endif
 
       break;
+
+    default:
+      break;
     }
 
   return x;
@@ -4199,6 +4412,8 @@ simplify_if_then_else (x)
       case LT:
       case LE:
        return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true));
+    default:
+      break;
       }
 
   /* Look for MIN or MAX.  */
@@ -4222,6 +4437,8 @@ simplify_if_then_else (x)
       case LEU:
       case LTU:
        return gen_binary (UMIN, mode, true, false);
+      default:
+       break;
       }
   
   /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
@@ -4427,10 +4644,10 @@ simplify_set (x)
       if (compare_mode != GET_MODE (dest))
        {
          int regno = REGNO (dest);
-         rtx new_dest = gen_rtx (REG, compare_mode, regno);
+         rtx new_dest = gen_rtx_REG (compare_mode, regno);
 
          if (regno < FIRST_PSEUDO_REGISTER
-             || (reg_n_sets[regno] == 1 && ! REG_USERVAR_P (dest)))
+             || (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest)))
            {
              if (regno >= FIRST_PSEUDO_REGISTER)
                SUBST (regno_reg_rtx[regno], new_dest);
@@ -4466,9 +4683,8 @@ simplify_set (x)
              && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
            {
              rtx pat = PATTERN (other_insn), note = 0;
-             int scratches;
 
-             if ((recog_for_combine (&pat, other_insn, &note, &scratches) < 0
+             if ((recog_for_combine (&pat, other_insn, &note) < 0
                   && ! check_asm_operands (pat)))
                {
                  PUT_CODE (*cc_use, old_code);
@@ -4526,7 +4742,7 @@ simplify_set (x)
      we only care about the low bits of the result.
 
      However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
-     perform a narrower operation that requested since the high-order bits will
+     perform a narrower operation than requested since the high-order bits will
      be undefined.  On machine where it is defined, this transformation is safe
      as long as M1 and M2 have the same number of words.  */
  
@@ -4814,9 +5030,9 @@ simplify_logical (x, last)
          && GET_CODE (XEXP (op1, 1)) == CONST_INT
          && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
              == GET_MODE_BITSIZE (mode)))
-       return gen_rtx (ROTATE, mode, XEXP (op0, 0),
-                       (GET_CODE (op0) == ASHIFT
-                        ? XEXP (op0, 1) : XEXP (op1, 1)));
+       return gen_rtx_ROTATE (mode, XEXP (op0, 0),
+                              (GET_CODE (op0) == ASHIFT
+                               ? XEXP (op0, 1) : XEXP (op1, 1)));
 
       /* If OP0 is (ashiftrt (plus ...) C), it might actually be
         a (sign_extend (plus ...)).  If so, OP1 is a CONST_INT, and the PLUS
@@ -4905,13 +5121,16 @@ simplify_logical (x, last)
         when STORE_FLAG_VALUE is the sign bit.  */
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-             == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+             == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
          && op1 == const_true_rtx
          && GET_RTX_CLASS (GET_CODE (op0)) == '<'
          && reversible_comparison_p (op0))
        return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
                                mode, XEXP (op0, 0), XEXP (op0, 1));
       break;
+
+    default:
+      abort ();
     }
 
   return x;
@@ -4995,7 +5214,7 @@ expand_compound_operation (x)
         with a (use (mem ...)) construct that only combine understands
         and is used only for this purpose.  */
       if (len + pos > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
-       SUBST (XEXP (x, 0), gen_rtx (USE, GET_MODE (x), XEXP (x, 0)));
+       SUBST (XEXP (x, 0), gen_rtx_USE (GET_MODE (x), XEXP (x, 0)));
 
       if (BITS_BIG_ENDIAN)
        pos = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - len - pos;
@@ -5025,7 +5244,7 @@ expand_compound_operation (x)
          && subreg_lowpart_p (XEXP (x, 0))
          && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
-             & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))) == 0)
+             & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
        return SUBREG_REG (XEXP (x, 0));
 
       /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
@@ -5071,7 +5290,7 @@ expand_compound_operation (x)
                            >> 1))
                      == 0))))
        {
-         rtx temp = gen_rtx (SIGN_EXTEND, GET_MODE (x), XEXP (x, 0));
+         rtx temp = gen_rtx_SIGN_EXTEND (GET_MODE (x), XEXP (x, 0));
 
          if (rtx_cost (temp, SET) < rtx_cost (x, SET))
            return expand_compound_operation (temp);
@@ -5161,7 +5380,7 @@ expand_field_assignment (x)
             surround INNER  with a USE to indicate this.  */
          if (GET_CODE (pos) == CONST_INT
              && INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
-           inner = gen_rtx (USE, GET_MODE (SET_DEST (x)), inner);
+           inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner);
 
          if (BITS_BIG_ENDIAN)
            {
@@ -5190,9 +5409,9 @@ expand_field_assignment (x)
                   == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
                        + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
        {
-         x = gen_rtx (SET, VOIDmode, SUBREG_REG (SET_DEST (x)),
-                      gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))),
-                                               SET_SRC (x)));
+         x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)),
+                          gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))),
+                                                   SET_SRC (x)));
          continue;
        }
       else
@@ -5203,6 +5422,24 @@ expand_field_assignment (x)
 
       compute_mode = GET_MODE (inner);
 
+      /* Don't attempt bitwise arithmetic on non-integral modes.  */
+      if (! INTEGRAL_MODE_P (compute_mode))
+       {
+         enum machine_mode imode;
+
+         /* Something is probably seriously wrong if this matches.  */
+         if (! FLOAT_MODE_P (compute_mode))
+           break;
+
+         /* Try to find an integral mode to pun with.  */
+         imode = mode_for_size (GET_MODE_BITSIZE (compute_mode), MODE_INT, 0);
+         if (imode == BLKmode)
+           break;
+
+         compute_mode = imode;
+         inner = gen_lowpart_for_combine (imode, inner);
+       }
+
       /* Compute a mask of LEN bits, if we can do this on the host machine.  */
       if (len < HOST_BITS_PER_WIDE_INT)
        mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
@@ -5212,22 +5449,22 @@ expand_field_assignment (x)
       /* Now compute the equivalent expression.  Make a copy of INNER
         for the SET_DEST in case it is a MEM into which we will substitute;
         we don't want shared RTL in that case.  */
-      x = gen_rtx (SET, VOIDmode, copy_rtx (inner),
-                  gen_binary (IOR, compute_mode,
-                              gen_binary (AND, compute_mode,
-                                          gen_unary (NOT, compute_mode,
-                                                     compute_mode,
-                                                     gen_binary (ASHIFT,
-                                                                 compute_mode,
-                                                                 mask, pos)),
-                                          inner),
-                              gen_binary (ASHIFT, compute_mode,
-                                          gen_binary (AND, compute_mode,
-                                                      gen_lowpart_for_combine
-                                                      (compute_mode,
-                                                       SET_SRC (x)),
-                                                      mask),
-                                          pos)));
+      x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
+                      gen_binary (IOR, compute_mode,
+                                  gen_binary (AND, compute_mode,
+                                              gen_unary (NOT, compute_mode,
+                                                         compute_mode,
+                                                         gen_binary (ASHIFT,
+                                                                     compute_mode,
+                                                                     mask, pos)),
+                                              inner),
+                                  gen_binary (ASHIFT, compute_mode,
+                                              gen_binary (AND, compute_mode,
+                                                          gen_lowpart_for_combine
+                                                          (compute_mode,
+                                                           SET_SRC (x)),
+                                                          mask),
+                                              pos)));
     }
 
   return x;
@@ -5357,7 +5594,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
          else
            offset = pos / BITS_PER_UNIT;
 
-         new = gen_rtx (MEM, tmode, plus_constant (XEXP (inner, 0), offset));
+         new = gen_rtx_MEM (tmode, plus_constant (XEXP (inner, 0), offset));
          RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner);
          MEM_VOLATILE_P (new) = MEM_VOLATILE_P (inner);
          MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (inner);
@@ -5367,14 +5604,14 @@ make_extraction (mode, inner, pos, pos_rtx, len,
          /* We can't call gen_lowpart_for_combine here since we always want
             a SUBREG and it would sometimes return a new hard register.  */
          if (tmode != inner_mode)
-           new = gen_rtx (SUBREG, tmode, inner,
-                          (WORDS_BIG_ENDIAN
-                           && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
-                           ? (((GET_MODE_SIZE (inner_mode)
-                                - GET_MODE_SIZE (tmode))
-                               / UNITS_PER_WORD)
-                              - pos / BITS_PER_WORD)
-                           : pos / BITS_PER_WORD));
+           new = gen_rtx_SUBREG (tmode, inner,
+                                 (WORDS_BIG_ENDIAN
+                                  && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
+                                  ? (((GET_MODE_SIZE (inner_mode)
+                                       - GET_MODE_SIZE (tmode))
+                                      / UNITS_PER_WORD)
+                                     - pos / BITS_PER_WORD)
+                                  : pos / BITS_PER_WORD));
          else
            new = inner;
        }
@@ -5391,7 +5628,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       if (in_dest)
        return (GET_CODE (new) == MEM ? new
                : (GET_CODE (new) != SUBREG
-                  ? gen_rtx (CLOBBER, tmode, const0_rtx)
+                  ? gen_rtx_CLOBBER (tmode, const0_rtx)
                   : gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new)));
 
       /* Otherwise, sign- or zero-extend unless we already are in the
@@ -5424,27 +5661,45 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 #ifdef HAVE_insv
   if (in_dest)
     {
-      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
-      pos_mode = insn_operand_mode[(int) CODE_FOR_insv][2];
-      extraction_mode = insn_operand_mode[(int) CODE_FOR_insv][3];
+      wanted_inner_reg_mode
+       = (insn_operand_mode[(int) CODE_FOR_insv][0] == VOIDmode
+          ? word_mode
+          : insn_operand_mode[(int) CODE_FOR_insv][0]);
+      pos_mode = (insn_operand_mode[(int) CODE_FOR_insv][2] == VOIDmode
+                 ? word_mode : insn_operand_mode[(int) CODE_FOR_insv][2]);
+      extraction_mode = (insn_operand_mode[(int) CODE_FOR_insv][3] == VOIDmode
+                        ? word_mode
+                        : insn_operand_mode[(int) CODE_FOR_insv][3]);
     }
 #endif
 
 #ifdef HAVE_extzv
   if (! in_dest && unsignedp)
     {
-      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
-      pos_mode = insn_operand_mode[(int) CODE_FOR_extzv][3];
-      extraction_mode = insn_operand_mode[(int) CODE_FOR_extzv][0];
+      wanted_inner_reg_mode
+       = (insn_operand_mode[(int) CODE_FOR_extzv][1] == VOIDmode
+          ? word_mode
+          : insn_operand_mode[(int) CODE_FOR_extzv][1]);
+      pos_mode = (insn_operand_mode[(int) CODE_FOR_extzv][3] == VOIDmode
+                 ? word_mode : insn_operand_mode[(int) CODE_FOR_extzv][3]);
+      extraction_mode = (insn_operand_mode[(int) CODE_FOR_extzv][0] == VOIDmode
+                        ? word_mode
+                        : insn_operand_mode[(int) CODE_FOR_extzv][0]);
     }
 #endif
 
 #ifdef HAVE_extv
   if (! in_dest && ! unsignedp)
     {
-      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
-      pos_mode = insn_operand_mode[(int) CODE_FOR_extv][3];
-      extraction_mode = insn_operand_mode[(int) CODE_FOR_extv][0];
+      wanted_inner_reg_mode
+       = (insn_operand_mode[(int) CODE_FOR_extv][1] == VOIDmode
+          ? word_mode
+          : insn_operand_mode[(int) CODE_FOR_extv][1]);
+      pos_mode = (insn_operand_mode[(int) CODE_FOR_extv][3] == VOIDmode
+                 ? word_mode : insn_operand_mode[(int) CODE_FOR_extv][3]);
+      extraction_mode = (insn_operand_mode[(int) CODE_FOR_extv][0] == VOIDmode
+                        ? word_mode
+                        : insn_operand_mode[(int) CODE_FOR_extv][0]);
     }
 #endif
 
@@ -5531,8 +5786,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
       if (offset != 0 || inner_mode != wanted_inner_mode)
        {
-         rtx newmem = gen_rtx (MEM, wanted_inner_mode,
-                               plus_constant (XEXP (inner, 0), offset));
+         rtx newmem = gen_rtx_MEM (wanted_inner_mode,
+                                   plus_constant (XEXP (inner, 0), offset));
          RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner);
          MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (inner);
          MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (inner);
@@ -5619,12 +5874,15 @@ extract_left_shift (x, count)
       /* If we can safely shift this constant and we find the inner shift,
         make a new operation.  */
       if (GET_CODE (XEXP (x,1)) == CONST_INT
-         && (INTVAL (XEXP (x, 1)) & (((HOST_WIDE_INT) 1 << count)) - 1) == 0
+         && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
          && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
        return gen_binary (code, mode, tem, 
                           GEN_INT (INTVAL (XEXP (x, 1)) >> count));
 
       break;
+      
+    default:
+      break;
     }
 
   return 0;
@@ -5728,10 +5986,10 @@ make_compound_operation (x, in_code)
        {
          /* Apply the distributive law, and then try to make extractions.  */
          new = gen_rtx_combine (GET_CODE (XEXP (x, 0)), mode,
-                                gen_rtx (AND, mode, XEXP (XEXP (x, 0), 0),
-                                         XEXP (x, 1)),
-                                gen_rtx (AND, mode, XEXP (XEXP (x, 0), 1),
-                                         XEXP (x, 1)));
+                                gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
+                                             XEXP (x, 1)),
+                                gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
+                                             XEXP (x, 1)));
          new = make_compound_operation (new, in_code);
        }
 
@@ -5866,6 +6124,27 @@ make_compound_operation (x, in_code)
 
          return newer;
        }
+
+      /* If this is a paradoxical subreg, and the new code is a sign or
+        zero extension, omit the subreg and widen the extension.  If it
+        is a regular subreg, we can still get rid of the subreg by not
+        widening so much, or in fact removing the extension entirely.  */
+      if ((GET_CODE (tem) == SIGN_EXTEND
+          || GET_CODE (tem) == ZERO_EXTEND)
+         && subreg_lowpart_p (x))
+       {
+         if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem))
+             || (GET_MODE_SIZE (mode) >
+                 GET_MODE_SIZE (GET_MODE (XEXP (tem, 0)))))
+           tem = gen_rtx_combine (GET_CODE (tem), mode, XEXP (tem, 0));
+         else
+           tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
+         return tem;
+       }
+      break;
+      
+    default:
+      break;
     }
 
   if (new)
@@ -5944,9 +6223,13 @@ force_to_mode (x, mode, mask, reg, just_select)
   unsigned HOST_WIDE_INT fuller_mask, nonzero;
   rtx op0, op1, temp;
 
-  /* If this is a CALL, don't do anything.  Some of the code below
-     will do the wrong thing since the mode of a CALL is VOIDmode.  */
-  if (code == CALL)
+  /* If this is a CALL or ASM_OPERANDS, don't do anything.  Some of the
+     code below will do the wrong thing since the mode of such an
+     expression is VOIDmode. 
+
+     Also do nothing if X is a CLOBBER; this can happen if X was
+     the return value from a call to gen_lowpart_for_combine.  */
+  if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
     return x;
 
   /* We want to perform the operation is its present mode unless we know
@@ -6071,7 +6354,7 @@ force_to_mode (x, mode, mask, reg, just_select)
             need it.  */
 
          if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
-             && INTVAL (XEXP (x, 1)) == mask)
+             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == mask)
            x = XEXP (x, 0);
 
          /* If it remains an AND, try making another AND with the bits
@@ -6122,12 +6405,32 @@ force_to_mode (x, mode, mask, reg, just_select)
          smask |= (HOST_WIDE_INT) -1 << width;
 
        if (GET_CODE (XEXP (x, 1)) == CONST_INT
-           && exact_log2 (- smask) >= 0
-           && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
-           && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
-         return force_to_mode (plus_constant (XEXP (x, 0),
-                                              INTVAL (XEXP (x, 1)) & mask),
-                               mode, mask, reg, next_select);
+           && exact_log2 (- smask) >= 0)
+         {
+#ifdef STACK_BIAS
+           if (STACK_BIAS
+               && (XEXP (x, 0) == stack_pointer_rtx
+                   || XEXP (x, 0) == frame_pointer_rtx))
+             {
+                int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+                unsigned HOST_WIDE_INT sp_mask = GET_MODE_MASK (mode);
+          
+               sp_mask &= ~ (sp_alignment - 1);
+               if ((sp_mask & ~ mask) == 0
+                   && ((INTVAL (XEXP (x, 1)) - STACK_BIAS) & ~ mask) != 0)
+                 return force_to_mode (plus_constant (XEXP (x, 0),
+                                                      ((INTVAL (XEXP (x, 1)) -
+                                                        STACK_BIAS) & mask)
+                                                      + STACK_BIAS),
+                                       mode, mask, reg, next_select);
+              }
+#endif
+           if ((nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
+               && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
+             return force_to_mode (plus_constant (XEXP (x, 0),
+                                                  INTVAL (XEXP (x, 1)) & mask),
+                                   mode, mask, reg, next_select);
+         }
       }
 
       /* ... fall through ...  */
@@ -6272,7 +6575,7 @@ force_to_mode (x, mode, mask, reg, just_select)
       /* If we are just looking for the sign bit, we don't need this shift at
         all, even if it has a variable count.  */
       if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-         && (mask == ((HOST_WIDE_INT) 1
+         && (mask == ((unsigned HOST_WIDE_INT) 1
                       << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
        return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 
@@ -6434,6 +6737,9 @@ force_to_mode (x, mode, mask, reg, just_select)
                                      force_to_mode (XEXP (x, 2), mode,
                                                     mask, reg,next_select)));
       break;
+      
+    default:
+      break;
     }
 
   /* Ensure we return a value of the proper mode.  */
@@ -6485,6 +6791,14 @@ if_then_else_cond (x, ptrue, pfalse)
       if ((cond0 != 0 || cond1 != 0)
          && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
        {
+         /* If if_then_else_cond returned zero, then true/false are the
+            same rtl.  We must copy one of them to prevent invalid rtl
+            sharing.  */
+         if (cond0 == 0)
+           true0 = copy_rtx (true0);
+         else if (cond1 == 0)
+           true1 = copy_rtx (true1);
+
          *ptrue = gen_binary (code, mode, true0, true1);
          *pfalse = gen_binary (code, mode, false0, false1);
          return cond0 ? cond0 : cond1;
@@ -6648,6 +6962,8 @@ known_cond (x, cond, reg, val)
       case LT:  case LE:
        return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)),
                          XEXP (x, 0));
+      default:
+       break;
       }
 
   /* The only other cases we handle are MIN, MAX, and comparisons if the
@@ -6684,6 +7000,8 @@ known_cond (x, cond, reg, val)
                  return unsignedp ? XEXP (x, 1) : x;
                case LEU:  case LTU:
                  return unsignedp ? XEXP (x, 0) : x;
+               default:
+                 break;
                }
            }
        }
@@ -6711,8 +7029,6 @@ rtx_equal_for_field_assignment_p (x, y)
      rtx x;
      rtx y;
 {
-  rtx last_x, last_y;
-
   if (x == y || rtx_equal_p (x, y))
     return 1;
 
@@ -6734,19 +7050,12 @@ rtx_equal_for_field_assignment_p (x, y)
                      gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
     return 1;
 
-  last_x = get_last_value (x);
-  last_y = get_last_value (y);
-
-  return ((last_x != 0
-          && GET_CODE (last_x) != CLOBBER
-          && rtx_equal_for_field_assignment_p (last_x, y))
-         || (last_y != 0
-             && GET_CODE (last_y) != CLOBBER
-             && rtx_equal_for_field_assignment_p (x, last_y))
-         || (last_x != 0 && last_y != 0
-             && GET_CODE (last_x) != CLOBBER
-             && GET_CODE (last_y) != CLOBBER
-             && rtx_equal_for_field_assignment_p (last_x, last_y)));
+  /* We used to see if get_last_value of X and Y were the same but that's
+     not correct.  In one direction, we'll cause the assignment to have
+     the wrong destination and in the case, we'll import a register into this
+     insn that might have already have been dead.   So fail if none of the
+     above cases are true.  */
+  return 0;
 }
 \f
 /* See if X, a SET operation, can be rewritten as a bit-field assignment.
@@ -6780,7 +7089,7 @@ make_field_assignment (x)
       assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
       if (assign != 0)
-       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+       return gen_rtx_SET (VOIDmode, assign, const0_rtx);
       return x;
     }
 
@@ -6796,7 +7105,7 @@ make_field_assignment (x)
                                XEXP (SUBREG_REG (XEXP (src, 0)), 1),
                                1, 1, 1, 0);
       if (assign != 0)
-       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+       return gen_rtx_SET (VOIDmode, assign, const0_rtx);
       return x;
     }
 
@@ -6809,7 +7118,7 @@ make_field_assignment (x)
       assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
       if (assign != 0)
-       return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+       return gen_rtx_SET (VOIDmode, assign, const1_rtx);
       return x;
     }
 
@@ -6840,8 +7149,8 @@ make_field_assignment (x)
 
   pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len);
   if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
-      || (GET_MODE_BITSIZE (GET_MODE (other)) <= HOST_BITS_PER_WIDE_INT
-         && (c1 & nonzero_bits (other, GET_MODE (other))) != 0))
+      || GET_MODE_BITSIZE (GET_MODE (dest)) > HOST_BITS_PER_WIDE_INT
+      || (c1 & nonzero_bits (other, GET_MODE (dest))) != 0)
     return x;
 
   assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
@@ -7093,7 +7402,7 @@ simplify_and_const_int (x, mode, varop, constop)
   else
     {
       if (GET_CODE (XEXP (x, 1)) != CONST_INT
-         || INTVAL (XEXP (x, 1)) != constop)
+         || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
        SUBST (XEXP (x, 1), GEN_INT (constop));
 
       SUBST (XEXP (x, 0), varop);
@@ -7105,7 +7414,7 @@ simplify_and_const_int (x, mode, varop, constop)
 /* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
    We don't let nonzero_bits recur into num_sign_bit_copies, because that
    is less useful.  We can't allow both, because that results in exponential
-   run time recusion.  There is a nullstone testcase that triggered
+   run time recursion.  There is a nullstone testcase that triggered
    this.  This macro avoids accidental uses of num_sign_bit_copies.  */
 #define num_sign_bit_copies()
 
@@ -7185,10 +7494,15 @@ nonzero_bits (x, mode)
         In particular, in the Irix6 n64 ABI, the stack has 128 bit
         alignment but the argument pointer has only 64 bit alignment.  */
 
-      if (x == stack_pointer_rtx || x == frame_pointer_rtx
-         || x == hard_frame_pointer_rtx
-         || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
-             && REGNO (x) <= LAST_VIRTUAL_REGISTER))
+      if ((x == frame_pointer_rtx
+          || x == stack_pointer_rtx
+          || x == hard_frame_pointer_rtx
+          || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+              && REGNO (x) <= LAST_VIRTUAL_REGISTER))
+#ifdef STACK_BIAS
+         && !STACK_BIAS
+#endif       
+             )
        {
          int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
 
@@ -7211,7 +7525,7 @@ nonzero_bits (x, mode)
 
       if (reg_last_set_value[REGNO (x)] != 0
          && reg_last_set_mode[REGNO (x)] == mode
-         && (reg_n_sets[REGNO (x)] == 1
+         && (REG_N_SETS (REGNO (x)) == 1
              || reg_last_set_label[REGNO (x)] == label_tick)
          && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
        return reg_last_set_nonzero_bits[REGNO (x)];
@@ -7323,9 +7637,9 @@ nonzero_bits (x, mode)
       if (GET_MODE (XEXP (x, 0)) != VOIDmode)
        {
          inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-         if (inner_nz &
-             (((HOST_WIDE_INT) 1
-               << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
+         if (inner_nz
+             (((HOST_WIDE_INT) 1
+                 << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
            inner_nz |= (GET_MODE_MASK (mode)
                          & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
        }
@@ -7369,6 +7683,22 @@ nonzero_bits (x, mode)
        switch (code)
          {
          case PLUS:
+#ifdef STACK_BIAS
+           if (STACK_BIAS
+               && (XEXP (x, 0) == stack_pointer_rtx
+                   || XEXP (x, 0) == frame_pointer_rtx)
+               && GET_CODE (XEXP (x, 1)) == CONST_INT)
+             {
+               int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+
+               nz0 = (GET_MODE_MASK (mode) & ~ (sp_alignment - 1));
+               nz1 = INTVAL (XEXP (x, 1)) - STACK_BIAS;
+               width0 = floor_log2 (nz0) + 1;
+               width1 = floor_log2 (nz1) + 1;
+               low0 = floor_log2 (nz0 & -nz0);
+               low1 = floor_log2 (nz1 & -nz1);
+             }
+#endif   
            result_width = MAX (width0, width1) + 1;
            result_low = MIN (low0, low1);
            break;
@@ -7395,6 +7725,8 @@ nonzero_bits (x, mode)
            result_width = MIN (width0, width1);
            result_low = MIN (low0, low1);
            break;
+         default:
+           abort ();
          }
 
        if (result_width < mode_width)
@@ -7429,15 +7761,23 @@ nonzero_bits (x, mode)
        {
          nonzero &= nonzero_bits (SUBREG_REG (x), mode);
 
-#ifndef WORD_REGISTER_OPERATIONS
-         /* On many CISC machines, accessing an object in a wider mode
-            causes the high-order bits to become undefined.  So they are
-            not known to be zero.  */
-         if (GET_MODE_SIZE (GET_MODE (x))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-           nonzero |= (GET_MODE_MASK (GET_MODE (x))
-                       & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
+         /* If this is a typical RISC machine, we only have to worry
+            about the way loads are extended.  */
+         if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+             ? (nonzero
+                & (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))
+             : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
 #endif
+           {
+             /* On many CISC machines, accessing an object in a wider mode
+                causes the high-order bits to become undefined.  So they are
+                not known to be zero.  */
+             if (GET_MODE_SIZE (GET_MODE (x))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+               nonzero |= (GET_MODE_MASK (GET_MODE (x))
+                           & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+           }
        }
       break;
 
@@ -7497,6 +7837,9 @@ nonzero_bits (x, mode)
       nonzero &= (nonzero_bits (XEXP (x, 1), mode)
                  | nonzero_bits (XEXP (x, 2), mode));
       break;
+      
+    default:
+      break;
     }
 
   return nonzero;
@@ -7538,13 +7881,25 @@ num_sign_bit_copies (x, mode)
     return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
                    - (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
      
+  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
+    {
 #ifndef WORD_REGISTER_OPERATIONS
   /* If this machine does not do all register operations on the entire
      register and MODE is wider than the mode of X, we can say nothing
      at all about the high-order bits.  */
-  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
-    return 1;
+      return 1;
+#else
+      /* Likewise on machines that do, if the mode of the object is smaller
+        than a word and loads of that size don't sign extend, we can say
+        nothing about the high order bits.  */
+      if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+#ifdef LOAD_EXTEND_OP
+         && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
+#endif
+         )
+       return 1;
 #endif
+    }
 
   switch (code)
     {
@@ -7560,7 +7915,7 @@ num_sign_bit_copies (x, mode)
 
       if (reg_last_set_value[REGNO (x)] != 0
          && reg_last_set_mode[REGNO (x)] == mode
-         && (reg_n_sets[REGNO (x)] == 1
+         && (REG_N_SETS (REGNO (x)) == 1
              || reg_last_set_label[REGNO (x)] == label_tick)
          && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
        return reg_last_set_sign_bit_copies[REGNO (x)];
@@ -7784,6 +8139,10 @@ num_sign_bit_copies (x, mode)
     case GEU: case GTU: case LEU: case LTU:
       if (STORE_FLAG_VALUE == -1)
        return bitwidth;
+      break;
+      
+    default:
+      break;
     }
 
   /* If we haven't been able to figure it out by one of the above rules,
@@ -7895,6 +8254,8 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
        case NEG:
          op0 = NIL;
          break;
+       default:
+         break;
        }
     }
 
@@ -7916,7 +8277,7 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
          op0 = SET;
        else /* op1 == XOR */
          /* (a ^ b) | b == a | b */
-         ;
+         {;}
        break;
 
       case XOR:
@@ -7936,6 +8297,8 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
          /* (a ^ b) & b) == (~a) & b */
          *pcomp_p = 1;
        break;
+      default:
+       break;
       }
 
   /* Check for NO-OP cases.  */
@@ -7945,7 +8308,8 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
     op0 = NIL;
   else if (const0 == 0 && op0 == AND)
     op0 = SET;
-  else if (const0 == GET_MODE_MASK (mode) && op0 == AND)
+  else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
+          && op0 == AND)
     op0 = NIL;
 
   /* If this would be an entire word for the target, but is not for
@@ -8004,7 +8368,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
       if (x)
        return x;
 
-      return gen_rtx (code, mode, varop, GEN_INT (count));
+      return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (count));
     }
 
   /* Unless one of the branches of the `if' in this loop does a `continue',
@@ -8122,11 +8486,11 @@ simplify_shift_const (x, code, result_mode, varop, count)
                                         MODE_INT, 1)) != BLKmode)
            {
              if (BYTES_BIG_ENDIAN)
-               new = gen_rtx (MEM, tmode, XEXP (varop, 0));
+               new = gen_rtx_MEM (tmode, XEXP (varop, 0));
              else
-               new = gen_rtx (MEM, tmode,
-                              plus_constant (XEXP (varop, 0),
-                                             count / BITS_PER_UNIT));
+               new = gen_rtx_MEM (tmode,
+                                  plus_constant (XEXP (varop, 0),
+                                                 count / BITS_PER_UNIT));
              RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (varop);
              MEM_VOLATILE_P (new) = MEM_VOLATILE_P (varop);
              MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (varop);
@@ -8569,6 +8933,32 @@ simplify_shift_const (x, code, result_mode, varop, count)
              continue;
            }
          break;
+
+       case TRUNCATE:
+         /* Change (lshiftrt (truncate (lshiftrt))) to (truncate (lshiftrt))
+            if the truncate does not affect the value.  */
+         if (code == LSHIFTRT
+             && GET_CODE (XEXP (varop, 0)) == LSHIFTRT
+             && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
+             && (INTVAL (XEXP (XEXP (varop, 0), 1))
+                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0)))
+                     - GET_MODE_BITSIZE (GET_MODE (varop)))))
+           {
+             rtx varop_inner = XEXP (varop, 0);
+
+             varop_inner = gen_rtx_combine (LSHIFTRT,
+                                            GET_MODE (varop_inner),
+                                            XEXP (varop_inner, 0),
+                                            GEN_INT (count + INTVAL (XEXP (varop_inner, 1))));
+             varop = gen_rtx_combine (TRUNCATE, GET_MODE (varop),
+                                      varop_inner);
+             count = 0;
+             continue;
+           }
+         break;
+         
+       default:
+         break;
        }
 
       break;
@@ -8693,18 +9083,14 @@ simplify_shift_const (x, code, result_mode, varop, count)
    PNOTES is a pointer to a location where any REG_UNUSED notes added for
    the CLOBBERs are placed.
 
-   PADDED_SCRATCHES is set to the number of (clobber (scratch)) patterns
-   we had to add.
-
    The value is the final insn code from the pattern ultimately matched,
    or -1.  */
 
 static int
-recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
+recog_for_combine (pnewpat, insn, pnotes)
      rtx *pnewpat;
      rtx insn;
      rtx *pnotes;
-     int *padded_scratches;
 {
   register rtx pat = *pnewpat;
   int insn_code_number;
@@ -8712,8 +9098,6 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
   int i;
   rtx notes = 0;
 
-  *padded_scratches = 0;
-
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
      thing, force rejection.  */
@@ -8756,10 +9140,10 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
      them.  Then check to make sure that all of them are dead.  */
   if (num_clobbers_to_add)
     {
-      rtx newpat = gen_rtx (PARALLEL, VOIDmode,
-                           gen_rtvec (GET_CODE (pat) == PARALLEL
-                                      ? XVECLEN (pat, 0) + num_clobbers_to_add
-                                      : num_clobbers_to_add + 1));
+      rtx newpat = gen_rtx_PARALLEL (VOIDmode,
+                                    gen_rtvec (GET_CODE (pat) == PARALLEL
+                                               ? XVECLEN (pat, 0) + num_clobbers_to_add
+                                               : num_clobbers_to_add + 1));
 
       if (GET_CODE (pat) == PARALLEL)
        for (i = 0; i < XVECLEN (pat, 0); i++)
@@ -8775,10 +9159,8 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
          if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
              && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
            return -1;
-         else if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == SCRATCH)
-           (*padded_scratches)++;
-         notes = gen_rtx (EXPR_LIST, REG_UNUSED,
-                          XEXP (XVECEXP (newpat, 0, i), 0), notes);
+         notes = gen_rtx_EXPR_LIST (REG_UNUSED,
+                                    XEXP (XVECEXP (newpat, 0, i), 0), notes);
        }
       pat = newpat;
     }
@@ -8818,7 +9200,7 @@ gen_lowpart_for_combine (mode, x)
             && (GET_CODE (x) == CONST_INT
                 || GET_CODE (x) == CONST_DOUBLE))
            || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
-    return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+    return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
      won't know what to do.  So we will strip off the SUBREG here and
@@ -8837,7 +9219,7 @@ gen_lowpart_for_combine (mode, x)
       && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
       && (GET_MODE_SIZE (GET_MODE (result))
          != GET_MODE_SIZE (GET_MODE (SUBREG_REG (result)))))
-    reg_changes_size[REGNO (SUBREG_REG (result))] = 1;
+    REG_CHANGES_SIZE (REGNO (SUBREG_REG (result))) = 1;
 
   if (result)
     return result;
@@ -8850,13 +9232,13 @@ gen_lowpart_for_combine (mode, x)
       /* Refuse to work on a volatile memory ref or one with a mode-dependent
         address.  */
       if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
-       return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+       return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
 
       /* If we want to refer to something bigger than the original memref,
         generate a perverse subreg instead.  That will force a reload
         of the original memref X.  */
       if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
-       return gen_rtx (SUBREG, mode, x, 0);
+       return gen_rtx_SUBREG (mode, x, 0);
 
       if (WORDS_BIG_ENDIAN)
        offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
@@ -8868,7 +9250,7 @@ gen_lowpart_for_combine (mode, x)
          offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
                     - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
        }
-      new = gen_rtx (MEM, mode, plus_constant (XEXP (x, 0), offset));
+      new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
       RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
       MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
       MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
@@ -8891,7 +9273,7 @@ gen_lowpart_for_combine (mode, x)
        word = ((GET_MODE_SIZE (GET_MODE (x))
                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
                / UNITS_PER_WORD);
-      return gen_rtx (SUBREG, mode, x, word);
+      return gen_rtx_SUBREG (mode, x, word);
     }
 }
 \f
@@ -8906,21 +9288,21 @@ gen_lowpart_for_combine (mode, x)
 static rtx
 gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum rtx_code code;
   enum machine_mode mode;
 #endif
   va_list p;
   int n_args;
   rtx args[3];
-  int i, j;
+  int j;
   char *fmt;
   rtx rt;
   struct undo *undo;
 
   VA_START (p, mode);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum rtx_code);
   mode = va_arg (p, enum machine_mode);
 #endif
@@ -9020,6 +9402,13 @@ gen_binary (code, mode, op0, op1)
              && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
     return gen_rtx_combine (code, mode, op1, op0);
 
+  /* If we are turning off bits already known off in OP0, we need not do
+     an AND.  */
+  else if (code == AND && GET_CODE (op1) == CONST_INT
+          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+          && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
+    return op0;
+
   return gen_rtx_combine (code, mode, op0, op1);
 }
 
@@ -9152,10 +9541,10 @@ simplify_comparison (code, pop0, pop1)
                  > GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
              && (GET_MODE (SUBREG_REG (inner_op0))
                  == GET_MODE (SUBREG_REG (inner_op1)))
-             && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+             && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (inner_op0)))
                  <= HOST_BITS_PER_WIDE_INT)
              && (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
-                                            GET_MODE (SUBREG_REG (op0)))))
+                                            GET_MODE (SUBREG_REG (inner_op0)))))
              && (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
                                             GET_MODE (SUBREG_REG (inner_op1))))))
            {
@@ -9173,7 +9562,7 @@ simplify_comparison (code, pop0, pop1)
            for (tmode = GET_CLASS_NARROWEST_MODE
                 (GET_MODE_CLASS (GET_MODE (op0)));
                 tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode))
-             if (c0 == GET_MODE_MASK (tmode))
+             if ((unsigned HOST_WIDE_INT) c0 == GET_MODE_MASK (tmode))
                {
                  op0 = gen_lowpart_for_combine (tmode, inner_op0);
                  op1 = gen_lowpart_for_combine (tmode, inner_op1);
@@ -9248,7 +9637,7 @@ simplify_comparison (code, pop0, pop1)
              || code == LT || code == LTU)
          && mode_width <= HOST_BITS_PER_WIDE_INT
          && exact_log2 (const_op) >= 0
-         && nonzero_bits (op0, mode) == const_op)
+         && nonzero_bits (op0, mode) == (unsigned HOST_WIDE_INT) const_op)
        {
          code = (code == EQ || code == GE || code == GEU ? NE : EQ);
          op1 = const0_rtx, const_op = 0;
@@ -9401,6 +9790,9 @@ simplify_comparison (code, pop0, pop1)
              code = LT;
            }
          break;
+
+       default:
+         break;
        }
 
       /* Compute some predicates to simplify code below.  */
@@ -9437,12 +9829,16 @@ simplify_comparison (code, pop0, pop1)
              && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
            {
              if (BITS_BIG_ENDIAN)
+               {
 #ifdef HAVE_extzv
-               i = (GET_MODE_BITSIZE
-                    (insn_operand_mode[(int) CODE_FOR_extzv][1]) - 1 - i);
+                 mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+                 if (mode == VOIDmode)
+                   mode = word_mode;
+                 i = (GET_MODE_BITSIZE (mode) - 1 - i);
 #else
-               i = BITS_PER_WORD - 1 - i;
+                 i = BITS_PER_WORD - 1 - i;
 #endif
+               }
 
              op0 = XEXP (op0, 2);
              op1 = GEN_INT (i);
@@ -9570,7 +9966,7 @@ simplify_comparison (code, pop0, pop1)
              && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
                  <= HOST_BITS_PER_WIDE_INT)
              && ((unsigned HOST_WIDE_INT) const_op
-                 < (((HOST_WIDE_INT) 1
+                 < (((unsigned HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1)))))
            {
              op0 = XEXP (op0, 0);
@@ -9594,7 +9990,7 @@ simplify_comparison (code, pop0, pop1)
              && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
              && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
              && (- INTVAL (XEXP (SUBREG_REG (op0), 1))
-                 < GET_MODE_MASK (mode) / 2)
+                 < (HOST_WIDE_INT)(GET_MODE_MASK (mode) / 2))
              && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
              && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
                                      GET_MODE (SUBREG_REG (op0)))
@@ -9798,7 +10194,7 @@ simplify_comparison (code, pop0, pop1)
              && GET_CODE (XEXP (op0, 1)) == CONST_INT
              && mode_width <= HOST_BITS_PER_WIDE_INT
              && ((INTVAL (XEXP (op0, 1)) & GET_MODE_MASK (mode))
-                 == (HOST_WIDE_INT) 1 << (mode_width - 1)))
+                 == (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)))
            {
              op0 = XEXP (op0, 0);
              code = (code == EQ ? GE : LT);
@@ -9820,6 +10216,48 @@ simplify_comparison (code, pop0, pop1)
              op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
              continue;
            }
+
+         /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits
+            in both M1 and M2 and the SUBREG is either paradoxical or
+            represents the low part, permute the SUBREG and the AND and
+            try again.  */
+         if (GET_CODE (XEXP (op0, 0)) == SUBREG
+             && ((mode_width
+                  >= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#ifdef WORD_REGISTER_OPERATIONS
+                 || subreg_lowpart_p (XEXP (op0, 0))
+#endif
+                 )
+#ifndef WORD_REGISTER_OPERATIONS
+             /* It is unsafe to commute the AND into the SUBREG if the SUBREG
+                is paradoxical and WORD_REGISTER_OPERATIONS is not defined.
+                As originally written the upper bits have a defined value
+                due to the AND operation.  However, if we commute the AND
+                inside the SUBREG then they no longer have defined values
+                and the meaning of the code has been changed.  */
+             && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
+                 <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#endif
+             && GET_CODE (XEXP (op0, 1)) == CONST_INT
+             && mode_width <= HOST_BITS_PER_WIDE_INT
+             && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+                 <= HOST_BITS_PER_WIDE_INT)
+             && (INTVAL (XEXP (op0, 1)) & ~ mask) == 0
+             && 0 == (~ GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+                      & INTVAL (XEXP (op0, 1)))
+             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1)) != mask
+             && ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op0, 1))
+                 != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
+                      
+           {
+             op0
+               = gen_lowpart_for_combine
+                 (mode,
+                  gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))),
+                              SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1)));
+             continue;
+           }
+
          break;
 
        case ASHIFT:
@@ -9933,13 +10371,16 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
          break;
+         
+       default:
+         break;
        }
 
       break;
     }
 
   /* Now make any compound operations involved in this comparison.  Then,
-     check for an outmost SUBREG on OP0 that isn't doing anything or is
+     check for an outmost SUBREG on OP0 that is not doing anything or is
      paradoxical.  The latter case can only occur when it is known that the
      "extra" bits will be zero.  Therefore, it is safe to remove the SUBREG.
      We can never remove a SUBREG for a non-equality comparison because the
@@ -10063,9 +10504,10 @@ reversible_comparison_p (x)
       x = get_last_value (XEXP (x, 0));
       return (x && GET_CODE (x) == COMPARE
              && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
+      
+    default:
+      return 0;
     }
-
-  return 0;
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
@@ -10168,11 +10610,12 @@ record_value_for_reg (reg, insn, value)
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
-  if (value && ! get_last_value_validate (&value,
+  if (value && ! get_last_value_validate (&value, insn,
                                          reg_last_set_label[regno], 0))
     {
       value = copy_rtx (value);
-      if (! get_last_value_validate (&value, reg_last_set_label[regno], 1))
+      if (! get_last_value_validate (&value, insn,
+                                    reg_last_set_label[regno], 1))
        value = 0;
     }
 
@@ -10293,8 +10736,9 @@ record_dead_and_set_regs (insn)
    we don't know exactly what registers it was produced from.  */
 
 static int
-get_last_value_validate (loc, tick, replace)
+get_last_value_validate (loc, insn, tick, replace)
      rtx *loc;
+     rtx insn;
      int tick;
      int replace;
 {
@@ -10314,20 +10758,30 @@ get_last_value_validate (loc, tick, replace)
        if (reg_last_set_invalid[j]
            /* If this is a pseudo-register that was only set once, it is
               always valid.  */
-           || (! (regno >= FIRST_PSEUDO_REGISTER && reg_n_sets[regno] == 1)
+           || (! (regno >= FIRST_PSEUDO_REGISTER && REG_N_SETS (regno) == 1)
                && reg_last_set_label[j] > tick))
          {
            if (replace)
-             *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+             *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
            return replace;
          }
 
       return 1;
     }
+  /* If this is a memory reference, make sure that there were
+     no stores after it that might have clobbered the value.  We don't
+     have alias info, so we assume any store invalidates it.  */
+  else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+          && INSN_CUID (insn) <= mem_last_set)
+    {
+      if (replace)
+       *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+      return replace;
+    }
 
   for (i = 0; i < len; i++)
     if ((fmt[i] == 'e'
-        && get_last_value_validate (&XEXP (x, i), tick, replace) == 0)
+        && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
        /* Don't bother with these.  They shouldn't occur anyway.  */
        || fmt[i] == 'E')
       return 0;
@@ -10367,7 +10821,7 @@ get_last_value (x)
      return 0.  */
 
   if (value == 0
-      || (reg_n_sets[regno] != 1
+      || (REG_N_SETS (regno) != 1
          && reg_last_set_label[regno] != label_tick))
     return 0;
 
@@ -10414,7 +10868,7 @@ get_last_value (x)
 
          if (reg_mentioned_p (x, value))
            value = replace_rtx (copy_rtx (value), x,
-                                gen_rtx (CLOBBER, GET_MODE (x), const0_rtx));
+                                gen_rtx_CLOBBER (GET_MODE (x), const0_rtx));
 
          if (reg_overlap_mentioned_p (x, value))
            return 0;
@@ -10424,14 +10878,16 @@ get_last_value (x)
     }
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 0))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 1))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 1))
     return value;
 
   return 0;
@@ -10577,8 +11033,7 @@ reg_dead_at_p (reg, insn)
     }
 
   for (i = reg_dead_regno; i < reg_dead_endregno; i++)
-    if (basic_block_live_at_start[block][i / REGSET_ELT_BITS]
-       & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
+    if (REGNO_REG_SET_P (basic_block_live_at_start[block], i))
       return 0;
 
   return 1;
@@ -10659,8 +11114,11 @@ mark_used_regs_combine (x)
          mark_used_regs_combine (XEXP (testreg, 0));
 
        mark_used_regs_combine (SET_SRC (x));
-       return;
       }
+      return;
+
+    default:
+      break;
     }
 
   /* Recursively scan the operands of this expression.  */
@@ -10697,7 +11155,7 @@ remove_death (regno, insn)
 
   if (note)
     {
-      reg_n_deaths[regno]--;
+      REG_N_DEATHS (regno)--;
       remove_note (insn, note);
     }
 
@@ -10765,7 +11223,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
 
          if (note != 0 && regno < FIRST_PSEUDO_REGISTER
              && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-                 != GET_MODE_SIZE (GET_MODE (x))))
+                 > GET_MODE_SIZE (GET_MODE (x))))
            {
              int deadregno = REGNO (XEXP (note, 0));
              int deadend
@@ -10777,23 +11235,33 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
              for (i = deadregno; i < deadend; i++)
                if (i < regno || i >= ourend)
                  REG_NOTES (where_dead)
-                   = gen_rtx (EXPR_LIST, REG_DEAD,
-                              gen_rtx (REG, reg_raw_mode[i], i),
-                              REG_NOTES (where_dead));
+                   = gen_rtx_EXPR_LIST (REG_DEAD,
+                                        gen_rtx_REG (reg_raw_mode[i], i),
+                                        REG_NOTES (where_dead));
            }
-         /* If we didn't find any note, and we have a multi-reg hard
+         /* If we didn't find any note, or if we found a REG_DEAD note that
+            covers only part of the given reg, and we have a multi-reg hard
             register, then to be safe we must check for REG_DEAD notes
             for each register other than the first.  They could have
             their own REG_DEAD notes lying around.  */
-         else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+         else if ((note == 0
+                   || (note != 0
+                       && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+                           < GET_MODE_SIZE (GET_MODE (x)))))
+                  && regno < FIRST_PSEUDO_REGISTER
                   && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
            {
              int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
-             int i;
+             int i, offset;
              rtx oldnotes = 0;
 
-             for (i = regno + 1; i < ourend; i++)
-               move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
+             if (note)
+               offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+             else
+               offset = 1;
+
+             for (i = regno + offset; i < ourend; i++)
+               move_deaths (gen_rtx_REG (reg_raw_mode[i], i),
                             maybe_kill_insn, from_cuid, to_insn, &oldnotes);
            }
 
@@ -10803,9 +11271,9 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
              *pnotes = note;
            }
          else
-           *pnotes = gen_rtx (EXPR_LIST, REG_DEAD, x, *pnotes);
+           *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
 
-         reg_n_deaths[regno]++;
+         REG_N_DEATHS (regno)++;
        }
 
       return;
@@ -10950,6 +11418,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
       next_note = XEXP (note, 1);
       switch (REG_NOTE_KIND (note))
        {
+       case REG_BR_PROB:
+       case REG_EXEC_COUNT:
+         /* Doesn't matter much where we put this, as long as it's somewhere.
+            It is preferable to keep these notes on branches, which is most
+            likely to be i3.  */
+         place = i3;
+         break;
+
        case REG_UNUSED:
          /* Any clobbers for i3 may still exist, and so we must process
             REG_UNUSED notes from that insn.
@@ -10994,6 +11470,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
        case REG_EQUAL:
        case REG_EQUIV:
        case REG_NONNEG:
+       case REG_NOALIAS:
          /* These notes say something about results of an insn.  We can
             only support them if they used to be on I3 in which case they
             remain on I3.  Otherwise they are ignored.
@@ -11096,9 +11573,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
             special case.  */
 
          if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG
-             && reg_n_refs[REGNO (XEXP (note, 0))]== 2
+             && REG_N_REFS (REGNO (XEXP (note, 0)))== 2
              && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
-           reg_n_refs[REGNO (XEXP (note, 0))] = 3;
+           REG_N_REFS (REGNO (XEXP (note, 0))) = 3;
 
          if (place == 0)
            {
@@ -11113,15 +11590,35 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                  if (reg_set_p (XEXP (note, 0), PATTERN (tem)))
                    {
                      rtx set = single_set (tem);
+                     rtx inner_dest = 0;
+#ifdef HAVE_cc0
+                     rtx cc0_setter = NULL_RTX;
+#endif
+
+                     if (set != 0)
+                       for (inner_dest = SET_DEST (set);
+                            GET_CODE (inner_dest) == STRICT_LOW_PART
+                            || GET_CODE (inner_dest) == SUBREG
+                            || GET_CODE (inner_dest) == ZERO_EXTRACT;
+                            inner_dest = XEXP (inner_dest, 0))
+                         ;
 
                      /* Verify that it was the set, and not a clobber that
-                        modified the register.  */
+                        modified the register. 
+
+                        CC0 targets must be careful to maintain setter/user
+                        pairs.  If we cannot delete the setter due to side
+                        effects, mark the user with an UNUSED note instead
+                        of deleting it.  */
 
                      if (set != 0 && ! side_effects_p (SET_SRC (set))
-                         && (rtx_equal_p (XEXP (note, 0), SET_DEST (set))
-                             || (GET_CODE (SET_DEST (set)) == SUBREG
-                                 && rtx_equal_p (XEXP (note, 0),
-                                                 XEXP (SET_DEST (set), 0)))))
+                         && rtx_equal_p (XEXP (note, 0), inner_dest)
+#ifdef HAVE_cc0
+                         && (! reg_mentioned_p (cc0_rtx, SET_SRC (set))
+                             || ((cc0_setter = prev_cc0_setter (tem)) != NULL
+                                 && sets_cc0_p (PATTERN (cc0_setter)) > 0))
+#endif
+                         )
                        {
                          /* Move the notes and links of TEM elsewhere.
                             This might delete other dead insns recursively. 
@@ -11137,6 +11634,38 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                          PUT_CODE (tem, NOTE);
                          NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED;
                          NOTE_SOURCE_FILE (tem) = 0;
+
+#ifdef HAVE_cc0
+                         /* Delete the setter too.  */
+                         if (cc0_setter)
+                           {
+                             PATTERN (cc0_setter) = pc_rtx;
+
+                             distribute_notes (REG_NOTES (cc0_setter),
+                                               cc0_setter, cc0_setter,
+                                               NULL_RTX, NULL_RTX, NULL_RTX);
+                             distribute_links (LOG_LINKS (cc0_setter));
+
+                             PUT_CODE (cc0_setter, NOTE);
+                             NOTE_LINE_NUMBER (cc0_setter) = NOTE_INSN_DELETED;
+                             NOTE_SOURCE_FILE (cc0_setter) = 0;
+                           }
+#endif
+                       }
+                     /* If the register is both set and used here, put the
+                        REG_DEAD note here, but place a REG_UNUSED note
+                        here too unless there already is one.  */
+                     else if (reg_referenced_p (XEXP (note, 0),
+                                                PATTERN (tem)))
+                       {
+                         place = tem;
+
+                         if (! find_regno_note (tem, REG_UNUSED,
+                                                REGNO (XEXP (note, 0))))
+                           REG_NOTES (tem)
+                             = gen_rtx_EXPR_LIST (REG_UNUSED,
+                                                  XEXP (note, 0),
+                                                  REG_NOTES (tem));
                        }
                      else
                        {
@@ -11183,7 +11712,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
              if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0)
                {
                  place
-                   = emit_insn_after (gen_rtx (USE, VOIDmode, XEXP (note, 0)),
+                   = emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)),
                                       tem);
 
                  /* If this insn was emitted between blocks, then update
@@ -11194,13 +11723,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
            }
 
          /* If the register is set or already dead at PLACE, we needn't do
-            anything with this note if it is still a REG_DEAD note.  
+            anything with this note if it is still a REG_DEAD note.
+            We can here if it is set at all, not if is it totally replace,
+            which is what `dead_or_set_p' checks, so also check for it being
+            set partially.  */
+
 
-            Note that we cannot use just `dead_or_set_p' here since we can
-            convert an assignment to a register into a bit-field assignment.
-            Therefore, we must also omit the note if the register is the 
-            target of a bitfield assignment.  */
-            
          if (place && REG_NOTE_KIND (note) == REG_DEAD)
            {
              int regno = REGNO (XEXP (note, 0));
@@ -11242,7 +11770,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                    if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0)
                        && ! find_regno_fusage (place, USE, i))
                      {
-                       rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
+                       rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
                        rtx p;
 
                        /* See if we already placed a USE note for this
@@ -11261,12 +11789,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                        if (p)
                          {
                            rtx use_insn
-                             = emit_insn_before (gen_rtx (USE, VOIDmode,
-                                                          piece),
+                             = emit_insn_before (gen_rtx_USE (VOIDmode,
+                                                              piece),
                                                  p);
                            REG_NOTES (use_insn)
-                             = gen_rtx (EXPR_LIST, REG_DEAD, piece,
-                                        REG_NOTES (use_insn));
+                             = gen_rtx_EXPR_LIST (REG_DEAD, piece,
+                                                  REG_NOTES (use_insn));
                          }
 
                        all_used = 0;
@@ -11289,7 +11817,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
 
                      for (i = regno; i < endregno; i++)
                        {
-                         rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
+                         rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
 
                          if ((reg_referenced_p (piece, PATTERN (place))
                               || (GET_CODE (place) == CALL_INSN
@@ -11297,9 +11825,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                              && ! dead_or_set_p (place, piece)
                              && ! reg_bitfield_target_p (piece,
                                                          PATTERN (place)))
-                           REG_NOTES (place) = gen_rtx (EXPR_LIST, REG_DEAD,
-                                                        piece,
-                                                        REG_NOTES (place));
+                           REG_NOTES (place)
+                             = gen_rtx_EXPR_LIST (REG_DEAD,
+                                                  piece, REG_NOTES (place));
                        }
 
                      place = 0;
@@ -11322,17 +11850,19 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
       else if ((REG_NOTE_KIND (note) == REG_DEAD
                || REG_NOTE_KIND (note) == REG_UNUSED)
               && GET_CODE (XEXP (note, 0)) == REG)
-       reg_n_deaths[REGNO (XEXP (note, 0))]--;
+       REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
 
       if (place2)
        {
          if ((REG_NOTE_KIND (note) == REG_DEAD
               || REG_NOTE_KIND (note) == REG_UNUSED)
              && GET_CODE (XEXP (note, 0)) == REG)
-           reg_n_deaths[REGNO (XEXP (note, 0))]++;
+           REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
 
-         REG_NOTES (place2) = gen_rtx (GET_CODE (note), REG_NOTE_KIND (note),
-                                       XEXP (note, 0), REG_NOTES (place2));
+         REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
+                                              REG_NOTE_KIND (note),
+                                              XEXP (note, 0),
+                                              REG_NOTES (place2));
        }
     }
 }