OSDN Git Service

* gcc.misc-tests/linkage.exp: Pass appropriate flags to
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 0d43891..e36cdef 100644 (file)
@@ -1,6 +1,6 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -86,26 +86,10 @@ Boston, MA 02111-1307, USA.  */
 #include "function.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"
-#include "defaults.h"
-
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
-/* Supply a default definition for PUSH_ARGS.  */
-#ifndef PUSH_ARGS
-#ifdef PUSH_ROUNDING
-#define PUSH_ARGS      !ACCUMULATE_OUTGOING_ARGS
-#else
-#define PUSH_ARGS      0
-#endif
-#endif
 
 /* It is not safe to use ordinary gen_lowpart in combine.
    Use gen_lowpart_for_combine instead.  See comments there.  */
@@ -131,12 +115,6 @@ static int combine_successes;
 
 static int total_attempts, total_merges, total_extras, total_successes;
 
-/* Define a default value for REVERSIBLE_CC_MODE.
-   We can never assume that a condition code mode is safe to reverse unless
-   the md tells us so.  */
-#ifndef REVERSIBLE_CC_MODE
-#define REVERSIBLE_CC_MODE(MODE) 0
-#endif
 \f
 /* Vector mapping INSN_UIDs to cuids.
    The cuids are like uids but increase monotonically always.
@@ -153,6 +131,12 @@ static int max_uid_cuid;
 #define INSN_CUID(INSN) \
 (INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
 
+/* In case BITS_PER_WORD == HOST_BITS_PER_WIDE_INT, shifting by
+   BITS_PER_WORD would invoke undefined behavior.  Work around it.  */
+
+#define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
+  (((unsigned HOST_WIDE_INT)(val) << (BITS_PER_WORD - 1)) << 1)
+
 /* Maximum register number, which is the size of the tables below.  */
 
 static unsigned int combine_max_regno;
@@ -330,30 +314,20 @@ struct undo
 {
   struct undo *next;
   int is_int;
-  union {rtx r; int i;} old_contents;
-  union {rtx *r; int *i;} where;
+  union {rtx r; unsigned int i;} old_contents;
+  union {rtx *r; unsigned int *i;} where;
 };
 
 /* Record a bunch of changes to be undone, up to MAX_UNDO of them.
    num_undo says how many are currently recorded.
 
-   storage is nonzero if we must undo the allocation of new storage.
-   The value of storage is what to pass to obfree.
-
    other_insn is nonzero if we have modified some other insn in the process
-   of working on subst_insn.  It must be verified too.
-
-   previous_undos is the value of undobuf.undos when we started processing
-   this substitution.  This will prevent gen_rtx_combine from re-used a piece
-   from the previous expression.  Doing so can produce circular rtl
-   structures.  */
+   of working on subst_insn.  It must be verified too.  */
 
 struct undobuf
 {
-  char *storage;
   struct undo *undos;
   struct undo *frees;
-  struct undo *previous_undos;
   rtx other_insn;
 };
 
@@ -365,10 +339,12 @@ static struct undobuf undobuf;
 static int n_occurrences;
 
 static void do_SUBST                   PARAMS ((rtx *, rtx));
-static void do_SUBST_INT               PARAMS ((int *, int));
+static void do_SUBST_INT               PARAMS ((unsigned int *,
+                                                unsigned int));
 static void init_reg_last_arrays       PARAMS ((void));
 static void setup_incoming_promotions   PARAMS ((void));
 static void set_nonzero_bits_and_sign_copies  PARAMS ((rtx, rtx, void *));
+static int cant_combine_insn_p PARAMS ((rtx));
 static int can_combine_p       PARAMS ((rtx, rtx, rtx, rtx, rtx *, rtx *));
 static int sets_function_arg_p PARAMS ((rtx));
 static int combinable_i3pat    PARAMS ((rtx, rtx *, rtx, rtx, int, rtx *));
@@ -409,14 +385,9 @@ static rtx simplify_shift_const    PARAMS ((rtx, enum rtx_code, enum machine_mode,
                                         rtx, int));
 static int recog_for_combine   PARAMS ((rtx *, rtx, rtx *));
 static rtx gen_lowpart_for_combine  PARAMS ((enum machine_mode, rtx));
-static rtx gen_rtx_combine PARAMS ((enum rtx_code code, enum machine_mode mode,
-                                   ...));
 static rtx gen_binary          PARAMS ((enum rtx_code, enum machine_mode,
                                         rtx, rtx));
-static rtx gen_unary           PARAMS ((enum rtx_code, enum machine_mode,
-                                        enum machine_mode, rtx));
 static enum rtx_code simplify_comparison  PARAMS ((enum rtx_code, rtx *, rtx *));
-static int reversible_comparison_p  PARAMS ((rtx));
 static void update_table_tick  PARAMS ((rtx));
 static void record_value_for_reg  PARAMS ((rtx, rtx, rtx));
 static void check_promoted_subreg PARAMS ((rtx, rtx));
@@ -434,6 +405,8 @@ static void distribute_links        PARAMS ((rtx));
 static void mark_used_regs_combine PARAMS ((rtx));
 static int insn_cuid           PARAMS ((rtx));
 static void record_promoted_value PARAMS ((rtx, rtx));
+static rtx reversed_comparison  PARAMS ((rtx, enum machine_mode, rtx, rtx));
+static enum rtx_code combine_reversed_comparison_code PARAMS ((rtx));
 \f
 /* Substitute NEWVAL, an rtx expression, into INTO, a place in some
    insn.  The substitution can be undone by undo_all.  If INTO is already
@@ -472,10 +445,10 @@ do_SUBST (into, newval)
 
 static void
 do_SUBST_INT (into, newval)
-     int *into, newval;
+     unsigned int *into, newval;
 {
   struct undo *buf;
-  int oldval = *into;
+  unsigned int oldval = *into;
 
   if (oldval == newval)
     return;
@@ -588,7 +561,7 @@ combine_instructions (f, nregs)
       subst_low_cuid = i;
       subst_insn = insn;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      if (INSN_P (insn))
        {
          note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies,
                       NULL);
@@ -629,7 +602,7 @@ combine_instructions (f, nregs)
       if (GET_CODE (insn) == CODE_LABEL)
        label_tick++;
 
-      else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      else if (INSN_P (insn))
        {
          /* See if we know about function return values before this
             insn based upon SUBREG flags.  */
@@ -792,15 +765,15 @@ init_reg_last_arrays ()
 {
   unsigned int nregs = combine_max_regno;
 
-  bzero ((char *) reg_last_death, nregs * sizeof (rtx));
-  bzero ((char *) reg_last_set, nregs * sizeof (rtx));
-  bzero ((char *) reg_last_set_value, nregs * sizeof (rtx));
-  bzero ((char *) reg_last_set_table_tick, nregs * sizeof (int));
-  bzero ((char *) reg_last_set_label, nregs * sizeof (int));
-  bzero (reg_last_set_invalid, nregs * sizeof (char));
-  bzero ((char *) reg_last_set_mode, nregs * sizeof (enum machine_mode));
-  bzero ((char *) reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
-  bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char));
+  memset ((char *) reg_last_death, 0, nregs * sizeof (rtx));
+  memset ((char *) reg_last_set, 0, nregs * sizeof (rtx));
+  memset ((char *) reg_last_set_value, 0, nregs * sizeof (rtx));
+  memset ((char *) reg_last_set_table_tick, 0, nregs * sizeof (int));
+  memset ((char *) reg_last_set_label, 0, nregs * sizeof (int));
+  memset (reg_last_set_invalid, 0, nregs * sizeof (char));
+  memset ((char *) reg_last_set_mode, 0, nregs * sizeof (enum machine_mode));
+  memset ((char *) reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT));
+  memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char));
 }
 \f
 /* Set up any promoted values for incoming argument registers.  */
@@ -1058,6 +1031,8 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
       /* Don't combine with an insn that sets a register to itself if it has
         a REG_EQUAL note.  This may be part of a REG_NO_CONFLICT sequence.  */
       || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
+      /* Can't merge an ASM_OPERANDS.  */
+      || GET_CODE (src) == ASM_OPERANDS
       /* Can't merge a function call.  */
       || GET_CODE (src) == CALL
       /* Don't eliminate a function call argument.  */
@@ -1117,12 +1092,7 @@ 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.
-
-        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.  */
+        register.  */
 
       if (GET_CODE (src) == REG
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
@@ -1135,11 +1105,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
                 reload can't handle a conflict with constraints of other
                 inputs.  */
              || (REGNO (src) < FIRST_PSEUDO_REGISTER
-                 && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
-                     || (SMALL_REGISTER_CLASSES
-                         && ((! all_adjacent && ! REG_USERVAR_P (src))
-                             || (FUNCTION_VALUE_REGNO_P (REGNO (src))
-                                 && ! REG_USERVAR_P (src))))))))
+                 && ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)))))
        return 0;
     }
   else if (GET_CODE (dest) != CC0)
@@ -1166,8 +1132,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
         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)))
+        if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
        return 0;
     }
 
@@ -1182,8 +1147,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
      they might affect machine state.  */
 
   for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
-    if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
-       && p != succ && volatile_insn_p (PATTERN (p)))
+    if (INSN_P (p) && p != succ && volatile_insn_p (PATTERN (p)))
       return 0;
 
   /* If INSN or I2 contains an autoincrement or autodecrement,
@@ -1294,10 +1258,6 @@ sets_function_arg_p (pat)
    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 non-zero, we don't combine
-   if the destination of a SET is a hard register that isn't a user
-   variable.
-
    Before doing the above check, we first try to expand a field assignment
    into a set of logical operations.
 
@@ -1366,11 +1326,10 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
           && (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 increasing the lifetime of INNER_DEST.
+         /* This is the same test done in can_combine_p except 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
@@ -1380,13 +1339,7 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
          || (GET_CODE (inner_dest) == REG
              && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
              && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
-                                       GET_MODE (inner_dest))
-                || (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)))))))
+                                       GET_MODE (inner_dest))))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
        return 0;
 
@@ -1458,6 +1411,49 @@ contains_muldiv (x)
     }
 }
 \f
+/* Determine whether INSN can be used in a combination.  Return nonzero if
+   not.  This is used in try_combine to detect early some cases where we
+   can't perform combinations.  */
+
+static int
+cant_combine_insn_p (insn)
+     rtx insn;
+{
+  rtx set;
+  rtx src, dest;
+  
+  /* If this isn't really an insn, we can't do anything.
+     This can occur when flow deletes an insn that it has merged into an
+     auto-increment address.  */
+  if (! INSN_P (insn))
+    return 1;
+
+  /* Never combine loads and stores involving hard regs.  The register
+     allocator can usually handle such reg-reg moves by tying.  If we allow
+     the combiner to make substitutions of hard regs, we risk aborting in
+     reload on machines that have SMALL_REGISTER_CLASSES.
+     As an exception, we allow combinations involving fixed regs; these are
+     not available to the register allocator so there's no risk involved.  */
+
+  set = single_set (insn);
+  if (! set)
+    return 0;
+  src = SET_SRC (set);
+  dest = SET_DEST (set);
+  if (GET_CODE (src) == SUBREG)
+    src = SUBREG_REG (src);
+  if (GET_CODE (dest) == SUBREG)
+    dest = SUBREG_REG (dest);
+  if (REG_P (src) && REG_P (dest)
+      && ((REGNO (src) < FIRST_PSEUDO_REGISTER
+          && ! fixed_regs[REGNO (src)])
+         || (REGNO (dest) < FIRST_PSEUDO_REGISTER
+             && ! fixed_regs[REGNO (dest)])))
+    return 1;
+
+  return 0;
+}
+
 /* Try to combine the insns I1 and I2 into I3.
    Here I1 and I2 appear earlier than I3.
    I1 can be zero; then we combine just I2 into I3.
@@ -1512,15 +1508,14 @@ try_combine (i3, i2, i1, new_direct_jump_p)
   register rtx link;
   int i;
 
-  /* If any of I1, I2, and I3 isn't really an insn, we can't do anything.
-     This can occur when flow deletes an insn that it has merged into an
-     auto-increment address.  We also can't do anything if I3 has a
-     REG_LIBCALL note since we don't want to disrupt the contiguity of a
-     libcall.  */
-
-  if (GET_RTX_CLASS (GET_CODE (i3)) != 'i'
-      || GET_RTX_CLASS (GET_CODE (i2)) != 'i'
-      || (i1 && GET_RTX_CLASS (GET_CODE (i1)) != 'i')
+  /* Exit early if one of the insns involved can't be used for
+     combinations.  */
+  if (cant_combine_insn_p (i3)
+      || cant_combine_insn_p (i2)
+      || (i1 && cant_combine_insn_p (i1))
+      /* We also can't do anything if I3 has a
+        REG_LIBCALL note since we don't want to disrupt the contiguity of a
+        libcall.  */
 #if 0
       /* ??? This gives worse code, and appears to be unnecessary, since no
         pass after flow uses REG_LIBCALL/REG_RETVAL notes.  */
@@ -1532,10 +1527,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
   combine_attempts++;
   undobuf.other_insn = 0;
 
-  /* Save the current high-water-mark so we can free storage if we didn't
-     accept this combination.  */
-  undobuf.storage = (char *) oballoc (0);
-
   /* Reset the hard register usage information.  */
   CLEAR_HARD_REG_SET (newpat_used_regs);
 
@@ -1547,13 +1538,16 @@ try_combine (i3, i2, i1, new_direct_jump_p)
   added_links_insn = 0;
 
   /* First check for one important special-case that the code below will
-     not handle.  Namely, the case where I1 is zero, I2 has multiple sets,
+     not handle.  Namely, the case where I1 is zero, I2 is a PARALLEL
      and I3 is a SET whose SET_SRC is a SET_DEST in I2.  In that case,
      we may be able to replace that destination with the destination of I3.
      This occurs in the common code where we compute both a quotient and
      remainder into a structure, in which case we want to do the computation
      directly into the structure to avoid register-register copies.
 
+     Note that this case handles both multiple sets in I2 and also
+     cases where I2 has a number of CLOBBER or PARALLELs.
+
      We make very conservative checks below and only try to handle the
      most common cases of this.  For example, we only handle the case
      where I2 and I3 are adjacent to avoid making difficult register
@@ -1562,10 +1556,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
   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
-      && (! 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)))))
       && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
       && GET_CODE (PATTERN (i2)) == PARALLEL
       && ! side_effects_p (SET_DEST (PATTERN (i3)))
@@ -1652,9 +1642,33 @@ try_combine (i3, i2, i1, new_direct_jump_p)
        }
 
       if (subreg_lowpart_p (SET_DEST (PATTERN (i3))))
-       lo = INTVAL (SET_SRC (PATTERN (i3)));
-      else
+       {
+         /* We don't handle the case of the target word being wider
+            than a host wide int.  */
+         if (HOST_BITS_PER_WIDE_INT < BITS_PER_WORD)
+           abort ();
+
+         lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
+         lo |= INTVAL (SET_SRC (PATTERN (i3)));
+       }
+      else if (HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
        hi = INTVAL (SET_SRC (PATTERN (i3)));
+      else if (HOST_BITS_PER_WIDE_INT >= 2 * BITS_PER_WORD)
+       {
+         int sign = -(int) ((unsigned HOST_WIDE_INT) lo
+                            >> (HOST_BITS_PER_WIDE_INT - 1));
+
+         lo &= ~ (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
+                  (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1));
+         lo |= (UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD
+                (INTVAL (SET_SRC (PATTERN (i3)))));
+         if (hi == sign)
+           hi = lo < 0 ? -1 : 0;
+       }
+      else
+       /* We don't handle the case of the higher word not fitting
+          entirely in either hi or lo.  */
+       abort ();
 
       combine_merges++;
       subst_insn = i3;
@@ -1666,7 +1680,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
             immed_double_const (lo, hi, GET_MODE (SET_DEST (temp))));
 
       newpat = PATTERN (i2);
-      i3_subst_into_i2 = 1;
       goto validate_replacement;
     }
 
@@ -1850,8 +1863,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          subst_low_cuid = INSN_CUID (i2);
          i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
        }
-
-      undobuf.previous_undos = undobuf.undos;
     }
 
 #ifndef HAVE_cc0
@@ -1907,8 +1918,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
              SUBST (SET_DEST (newpat), new_dest);
              SUBST (XEXP (*cc_use, 0), new_dest);
              SUBST (SET_SRC (newpat),
-                    gen_rtx_combine (COMPARE, compare_mode,
-                                     i2src, const0_rtx));
+                    gen_rtx_COMPARE (compare_mode, i2src, const0_rtx));
            }
          else
            undobuf.other_insn = 0;
@@ -1927,7 +1937,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
       subst_low_cuid = INSN_CUID (i2);
       newpat = subst (PATTERN (i3), i2dest, i2src, 0,
                      ! i1_feeds_i3 && i1dest_in_i1src);
-      undobuf.previous_undos = undobuf.undos;
 
       /* Record whether i2's body now appears within i3's body.  */
       i2_is_used = n_occurrences;
@@ -1943,7 +1952,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
         isn't mentioned in any SETs in NEWPAT that are field assignments.  */
 
       if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
-                             0, NULL_PTR))
+                             0, (rtx*)0))
        {
          undo_all ();
          return 0;
@@ -1952,7 +1961,6 @@ try_combine (i3, i2, i1, new_direct_jump_p)
       n_occurrences = 0;
       subst_low_cuid = INSN_CUID (i1);
       newpat = subst (newpat, i1dest, i1src, 0, 0);
-      undobuf.previous_undos = undobuf.undos;
     }
 
   /* Fail if an autoincrement side-effect has been duplicated.  Be careful
@@ -1990,8 +1998,8 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          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));
-         bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
-                sizeof (old->elem[0]) * old->num_elem);
+         memcpy (XVEC (newpat, 0)->elem, &old->elem[0],
+                 sizeof (old->elem[0]) * old->num_elem);
        }
       else
        {
@@ -2109,13 +2117,31 @@ try_combine (i3, i2, i1, new_direct_jump_p)
                                             gen_rtx_CLOBBER (VOIDmode,
                                                              ni2dest))),
                                 i3);
+         /* If the split with the mode-changed register didn't work, try
+            the original register.  */
+         if (! m_split && ni2dest != i2dest)
+           {
+             ni2dest = i2dest;
+             m_split = split_insns (gen_rtx_PARALLEL
+                                    (VOIDmode,
+                                     gen_rtvec (2, newpat,
+                                                gen_rtx_CLOBBER (VOIDmode,
+                                                                 i2dest))),
+                                    i3);
+           }
        }
 
-      if (m_split && GET_CODE (m_split) == SEQUENCE
-         && XVECLEN (m_split, 0) == 2
-         && (next_real_insn (i2) == i3
-             || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
-                                     INSN_CUID (i2))))
+      if (m_split && GET_CODE (m_split) != SEQUENCE)
+       {
+         insn_code_number = recog_for_combine (&m_split, i3, &new_i3_notes);
+         if (insn_code_number >= 0)
+           newpat = m_split;
+       } 
+      else if (m_split && GET_CODE (m_split) == SEQUENCE
+              && XVECLEN (m_split, 0) == 2
+              && (next_real_insn (i2) == i3
+                  || ! use_crosses_set_p (PATTERN (XVECEXP (m_split, 0, 0)),
+                                          INSN_CUID (i2))))
        {
          rtx i2set, i3set;
          rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
@@ -2211,8 +2237,8 @@ try_combine (i3, i2, i1, new_direct_jump_p)
              && GET_CODE (XEXP (*split, 1)) == CONST_INT
              && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
            {
-             SUBST (*split, gen_rtx_combine (ASHIFT, split_mode,
-                                             XEXP (*split, 0), GEN_INT (i)));
+             SUBST (*split, gen_rtx_ASHIFT (split_mode,
+                                            XEXP (*split, 0), GEN_INT (i)));
              /* Update split_code because we may not have a multiply
                 anymore.  */
              split_code = GET_CODE (*split);
@@ -2222,11 +2248,11 @@ try_combine (i3, i2, i1, new_direct_jump_p)
          /* If *SPLIT is a paradoxical SUBREG, when we split it, it should
             be written as a ZERO_EXTEND.  */
          if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
-           SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
-                                           XEXP (*split, 0)));
+           SUBST (*split, gen_rtx_ZERO_EXTEND  (split_mode,
+                                                SUBREG_REG (*split)));
 #endif
 
-         newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
+         newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
          SUBST (*split, newdest);
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
@@ -2323,8 +2349,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
                        || insn != BLOCK_HEAD (this_basic_block + 1));
               insn = NEXT_INSN (insn))
            {
-             if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-                 && reg_referenced_p (ni2dest, PATTERN (insn)))
+             if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
                {
                  for (link = LOG_LINKS (insn); link;
                       link = XEXP (link, 1))
@@ -2512,24 +2537,22 @@ try_combine (i3, i2, i1, new_direct_jump_p)
        actually came from I3, so that REG_UNUSED notes from I2 will be
        properly handled.  */
 
-    if (i3_subst_into_i2 && GET_CODE (PATTERN (i2)) == PARALLEL)
+    if (i3_subst_into_i2)
       {
-       if (GET_CODE (PATTERN (i2)) == PARALLEL)
-         {
-           for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
-             if (GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
-                 && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
-                 && ! find_reg_note (i2, REG_UNUSED,
-                                     SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
-               for (temp = NEXT_INSN (i2);
-                    temp && (this_basic_block == n_basic_blocks - 1
-                             || BLOCK_HEAD (this_basic_block) != temp);
-                    temp = NEXT_INSN (temp))
-                 if (temp != i3 && GET_RTX_CLASS (GET_CODE (temp)) == 'i')
-                   for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
-                     if (XEXP (link, 0) == i2)
-                       XEXP (link, 0) = i3;
-         }
+       for (i = 0; i < XVECLEN (PATTERN (i2), 0); i++)
+         if (GET_CODE (XVECEXP (PATTERN (i2), 0, i)) != USE
+             && GET_CODE (SET_DEST (XVECEXP (PATTERN (i2), 0, i))) == REG
+             && SET_DEST (XVECEXP (PATTERN (i2), 0, i)) != i2dest
+             && ! find_reg_note (i2, REG_UNUSED,
+                                 SET_DEST (XVECEXP (PATTERN (i2), 0, i))))
+           for (temp = NEXT_INSN (i2);
+                temp && (this_basic_block == n_basic_blocks - 1
+                         || BLOCK_HEAD (this_basic_block) != temp);
+                temp = NEXT_INSN (temp))
+             if (temp != i3 && INSN_P (temp))
+               for (link = LOG_LINKS (temp); link; link = XEXP (link, 1))
+                 if (XEXP (link, 0) == i2)
+                   XEXP (link, 0) = i3;
 
        if (i3notes)
          {
@@ -2781,8 +2804,7 @@ undo_all ()
       undobuf.frees = undo;
     }
 
-  obfree (undobuf.storage);
-  undobuf.undos = undobuf.previous_undos = 0;
+  undobuf.undos = 0;
 
   /* Clear this here, so that subsequent get_last_value calls are not
      affected.  */
@@ -2803,7 +2825,7 @@ undo_commit ()
       undo->next = undobuf.frees;
       undobuf.frees = undo;
     }
-  undobuf.undos = undobuf.previous_undos = 0;
+  undobuf.undos = 0;
 }
 
 \f
@@ -2847,9 +2869,9 @@ find_split_point (loc, insn)
          || GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
        {
          SUBST (XEXP (x, 0),
-                gen_rtx_combine (LO_SUM, Pmode,
-                                 gen_rtx_combine (HIGH, Pmode, XEXP (x, 0)),
-                                 XEXP (x, 0)));
+                gen_rtx_LO_SUM (Pmode,
+                                gen_rtx_HIGH (Pmode, XEXP (x, 0)),
+                                XEXP (x, 0)));
          return &XEXP (XEXP (x, 0), 0);
        }
 #endif
@@ -3007,7 +3029,7 @@ find_split_point (loc, insn)
              && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
              && (pos = exact_log2 (INTVAL (XEXP (SET_SRC (x), 1)))) >= 7
              && GET_CODE (SET_DEST (x)) == REG
-             && (split = find_single_use (SET_DEST (x), insn, NULL_PTR)) != 0
+             && (split = find_single_use (SET_DEST (x), insn, (rtx*)0)) != 0
              && (GET_CODE (*split) == EQ || GET_CODE (*split) == NE)
              && XEXP (*split, 0) == SET_DEST (x)
              && XEXP (*split, 1) == const0_rtx)
@@ -3035,10 +3057,10 @@ find_split_point (loc, insn)
              enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
 
              SUBST (SET_SRC (x),
-                    gen_rtx_combine (NEG, mode,
-                                     gen_rtx_combine (LSHIFTRT, mode,
-                                                      XEXP (SET_SRC (x), 0),
-                                                      GEN_INT (pos))));
+                    gen_rtx_NEG (mode,
+                                 gen_rtx_LSHIFTRT (mode,
+                                                   XEXP (SET_SRC (x), 0),
+                                                   GEN_INT (pos))));
 
              split = find_split_point (&SET_SRC (x), insn);
              if (split && split != &SET_SRC (x))
@@ -3093,12 +3115,11 @@ find_split_point (loc, insn)
          if (unsignedp && len <= 8)
            {
              SUBST (SET_SRC (x),
-                    gen_rtx_combine
-                    (AND, mode,
-                     gen_rtx_combine (LSHIFTRT, mode,
-                                      gen_lowpart_for_combine (mode, inner),
-                                      GEN_INT (pos)),
-                     GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
+                    gen_rtx_AND (mode,
+                                 gen_rtx_LSHIFTRT
+                                 (mode, gen_lowpart_for_combine (mode, inner),
+                                  GEN_INT (pos)),
+                                 GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
 
              split = find_split_point (&SET_SRC (x), insn);
              if (split && split != &SET_SRC (x))
@@ -3107,12 +3128,12 @@ find_split_point (loc, insn)
          else
            {
              SUBST (SET_SRC (x),
-                    gen_rtx_combine
+                    gen_rtx_fmt_ee
                     (unsignedp ? LSHIFTRT : ASHIFTRT, mode,
-                     gen_rtx_combine (ASHIFT, mode,
-                                      gen_lowpart_for_combine (mode, inner),
-                                      GEN_INT (GET_MODE_BITSIZE (mode)
-                                               - len - pos)),
+                     gen_rtx_ASHIFT (mode,
+                                     gen_lowpart_for_combine (mode, inner),
+                                     GEN_INT (GET_MODE_BITSIZE (mode)
+                                              - len - pos)),
                      GEN_INT (GET_MODE_BITSIZE (mode) - len)));
 
              split = find_split_point (&SET_SRC (x), insn);
@@ -3156,11 +3177,11 @@ find_split_point (loc, insn)
       if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == NOT)
        {
          SUBST (*loc,
-                gen_rtx_combine (NOT, GET_MODE (x),
-                                 gen_rtx_combine (code == IOR ? AND : IOR,
-                                                  GET_MODE (x),
-                                                  XEXP (XEXP (x, 0), 0),
-                                                  XEXP (XEXP (x, 1), 0))));
+                gen_rtx_NOT (GET_MODE (x),
+                             gen_rtx_fmt_ee (code == IOR ? AND : IOR,
+                                             GET_MODE (x),
+                                             XEXP (XEXP (x, 0), 0),
+                                             XEXP (XEXP (x, 1), 0))));
          return find_split_point (loc, insn);
        }
 
@@ -3373,7 +3394,16 @@ subst (x, from, to, in_dest, unique_copy)
            }
          else if (fmt[i] == 'e')
            {
-             if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+             /* If this is a register being set, ignore it.  */
+             new = XEXP (x, i);
+             if (in_dest
+                 && (code == SUBREG || code == STRICT_LOW_PART
+                     || code == ZERO_EXTRACT)
+                 && i == 0
+                 && GET_CODE (new) == REG)
+               ;
+
+             else 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
@@ -3487,17 +3517,13 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
   rtx temp;
+  rtx reversed;
   int i;
 
   /* If this is a commutative operation, put a constant last and a complex
      expression first.  We don't need to do this for comparisons here.  */
   if (GET_RTX_CLASS (code) == 'c'
-      && ((CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT)
-         || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')
-         || (GET_CODE (XEXP (x, 0)) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')))
+      && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
     {
       temp = XEXP (x, 0);
       SUBST (XEXP (x, 0), XEXP (x, 1));
@@ -3568,15 +3594,15 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                     && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
                         == 'o'))))))
     {
-      rtx cond, true, false;
+      rtx cond, true_rtx, false_rtx;
 
-      cond = if_then_else_cond (x, &true, &false);
+      cond = if_then_else_cond (x, &true_rtx, &false_rtx);
       if (cond != 0
          /* If everything is a comparison, what we have is highly unlikely
             to be simpler, so don't use it.  */
          && ! (GET_RTX_CLASS (code) == '<'
-               && (GET_RTX_CLASS (GET_CODE (true)) == '<'
-                   || GET_RTX_CLASS (GET_CODE (false)) == '<')))
+               && (GET_RTX_CLASS (GET_CODE (true_rtx)) == '<'
+                   || GET_RTX_CLASS (GET_CODE (false_rtx)) == '<')))
        {
          rtx cop1 = const0_rtx;
          enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
@@ -3586,43 +3612,47 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
          /* Simplify the alternative arms; this may collapse the true and
             false arms to store-flag values.  */
-         true = subst (true, pc_rtx, pc_rtx, 0, 0);
-         false = subst (false, pc_rtx, pc_rtx, 0, 0);
+         true_rtx = subst (true_rtx, pc_rtx, pc_rtx, 0, 0);
+         false_rtx = subst (false_rtx, pc_rtx, pc_rtx, 0, 0);
 
-         /* If true and false are not general_operands, an if_then_else
+         /* If true_rtx and false_rtx are not general_operands, an if_then_else
             is unlikely to be simpler.  */
-         if (general_operand (true, VOIDmode)
-             && general_operand (false, VOIDmode))
+         if (general_operand (true_rtx, VOIDmode)
+             && general_operand (false_rtx, VOIDmode))
            {
              /* Restarting if we generate a store-flag expression will cause
                 us to loop.  Just drop through in this case.  */
 
              /* If the result values are STORE_FLAG_VALUE and zero, we can
                 just make the comparison operation.  */
-             if (true == const_true_rtx && false == const0_rtx)
+             if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
                x = gen_binary (cond_code, mode, cond, cop1);
-             else if (true == const0_rtx && false == const_true_rtx)
+             else if (true_rtx == const0_rtx && false_rtx == const_true_rtx)
                x = gen_binary (reverse_condition (cond_code),
                                mode, cond, cop1);
 
              /* Likewise, we can make the negate of a comparison operation
                 if the result values are - STORE_FLAG_VALUE and zero.  */
-             else if (GET_CODE (true) == CONST_INT
-                      && INTVAL (true) == - STORE_FLAG_VALUE
-                      && false == const0_rtx)
-               x = gen_unary (NEG, mode, mode,
-                              gen_binary (cond_code, mode, cond, cop1));
-             else if (GET_CODE (false) == CONST_INT
-                      && INTVAL (false) == - STORE_FLAG_VALUE
-                      && true == const0_rtx)
-               x = gen_unary (NEG, mode, mode,
-                              gen_binary (reverse_condition (cond_code),
-                                          mode, cond, cop1));
+             else if (GET_CODE (true_rtx) == CONST_INT
+                      && INTVAL (true_rtx) == - STORE_FLAG_VALUE
+                      && false_rtx == const0_rtx)
+               x = simplify_gen_unary (NEG, mode,
+                                       gen_binary (cond_code, mode, cond,
+                                                   cop1),
+                                       mode);
+             else if (GET_CODE (false_rtx) == CONST_INT
+                      && INTVAL (false_rtx) == - STORE_FLAG_VALUE
+                      && true_rtx == const0_rtx)
+               x = simplify_gen_unary (NEG, mode,
+                                       gen_binary (reverse_condition
+                                                   (cond_code),
+                                                   mode, cond, cop1),
+                                       mode);
              else
                return gen_rtx_IF_THEN_ELSE (mode,
                                             gen_binary (cond_code, VOIDmode,
                                                         cond, cop1),
-                                            true, false);
+                                            true_rtx, false_rtx);
 
              code = GET_CODE (x);
              op0_mode = VOIDmode;
@@ -3642,7 +3672,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       {
        enum machine_mode cmp_mode = GET_MODE (XEXP (x, 0));
        if (cmp_mode == VOIDmode)
-         cmp_mode = GET_MODE (XEXP (x, 1));
+         {
+           cmp_mode = GET_MODE (XEXP (x, 1));
+           if (cmp_mode == VOIDmode)
+             cmp_mode = op0_mode;
+         }
        temp = simplify_relational_operation (code, cmp_mode,
                                              XEXP (x, 0), XEXP (x, 1));
       }
@@ -3668,7 +3702,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     }
 
   if (temp)
-    x = temp, code = GET_CODE (temp);
+    x = temp, code = GET_CODE (temp), op0_mode = VOIDmode;
 
   /* First see if we can apply the inverse distributive law.  */
   if (code == PLUS || code == MINUS
@@ -3676,6 +3710,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     {
       x = apply_distributive_law (x);
       code = GET_CODE (x);
+      op0_mode = VOIDmode;
     }
 
   /* If CODE is an associative operation not otherwise handled, see if we
@@ -3734,125 +3769,21 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case SUBREG:
-      /* (subreg:A (mem:B X) N) becomes a modified MEM unless the SUBREG
-        is paradoxical.  If we can't do that safely, then it becomes
-        something nonsensical so that this combination won't take place.  */
-
-      if (GET_CODE (SUBREG_REG (x)) == MEM
-         && (GET_MODE_SIZE (mode)
-             <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-       {
-         rtx inner = SUBREG_REG (x);
-         int endian_offset = 0;
-         /* Don't change the mode of the MEM
-            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);
+      if (op0_mode == VOIDmode)
+       op0_mode = GET_MODE (SUBREG_REG (x));
 
-         if (BYTES_BIG_ENDIAN)
-           {
-             if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
-               endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (mode);
-             if (GET_MODE_SIZE (GET_MODE (inner)) < UNITS_PER_WORD)
-               endian_offset -= (UNITS_PER_WORD
-                                 - GET_MODE_SIZE (GET_MODE (inner)));
-           }
-         /* 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)));
-         MEM_COPY_ATTRIBUTES (x, inner);
-         return x;
-       }
-
-      /* If we are in a SET_DEST, these other cases can't apply.  */
-      if (in_dest)
-       return x;
-
-      /* Changing mode twice with SUBREG => just change it once,
-        or not at all if changing back to starting mode.  */
-      if (GET_CODE (SUBREG_REG (x)) == SUBREG)
-       {
-         if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x)))
-             && SUBREG_WORD (x) == 0 && SUBREG_WORD (SUBREG_REG (x)) == 0)
-           return SUBREG_REG (SUBREG_REG (x));
-
-         SUBST_INT (SUBREG_WORD (x),
-                    SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x)));
-         SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
-       }
-
-      /* SUBREG of a hard register => just change the register number
-        and/or mode.  If the hard register is not valid in that mode,
-        suppress this combination.  If the hard register is the stack,
-        frame, or argument pointer, leave this as a SUBREG.  */
-
-      if (GET_CODE (SUBREG_REG (x)) == REG
-         && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
-         && REGNO (SUBREG_REG (x)) != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && REGNO (SUBREG_REG (x)) != HARD_FRAME_POINTER_REGNUM
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-         && REGNO (SUBREG_REG (x)) != ARG_POINTER_REGNUM
-#endif
-         && REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
-       {
-         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));
-         else
-           return gen_rtx_CLOBBER (mode, const0_rtx);
-       }
-
-      /* For a constant, try to pick up the part we want.  Handle a full
-        word and low-order part.  Only do this if we are narrowing
-        the constant; if it is being widened, we have no idea what
-        the extra bits will have been set to.  */
-
-      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_CLASS (mode) == MODE_INT)
-       {
-         temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
-                                 0, op0_mode);
-         if (temp)
-           return temp;
-       }
-
-      /* 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.   Note that we
-        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      /* simplify_subreg can't use gen_lowpart_for_combine.  */
       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))
+         && subreg_lowpart_parts_p (mode, op0_mode, SUBREG_BYTE (x)))
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
-      /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
-        since we are saying that the high bits don't matter.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && GET_MODE (SUBREG_REG (x)) == VOIDmode
-         && GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode))
-       {
-         if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
-             && (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
-           return operand_subword (SUBREG_REG (x), SUBREG_WORD (x), 0, mode);
-         return SUBREG_REG (x);
-       }
+      {
+       rtx temp;
+       temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
+                               SUBREG_BYTE (x));
+       if (temp)
+         return temp;
+      }
 
       /* Note that we cannot do any narrowing for non-constants since
         we might have been counting on using the fact that some bits were
@@ -3864,12 +3795,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       /* (not (plus X -1)) can become (neg X).  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && XEXP (XEXP (x, 0), 1) == constm1_rtx)
-       return gen_rtx_combine (NEG, mode, XEXP (XEXP (x, 0), 0));
+       return gen_rtx_NEG (mode, XEXP (XEXP (x, 0), 0));
 
       /* Similarly, (not (neg X)) is (plus X -1).  */
       if (GET_CODE (XEXP (x, 0)) == NEG)
-       return gen_rtx_combine (PLUS, mode, XEXP (XEXP (x, 0), 0),
-                               constm1_rtx);
+       return gen_rtx_PLUS (mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
 
       /* (not (xor X C)) for C constant is (xor X D) with D = ~C.  */
       if (GET_CODE (XEXP (x, 0)) == XOR
@@ -3885,7 +3815,8 @@ combine_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),
+       return gen_rtx_ROTATE (mode, simplify_gen_unary (NOT, mode,
+                                                        const1_rtx, mode),
                               XEXP (XEXP (x, 0), 1));
 
       if (GET_CODE (XEXP (x, 0)) == SUBREG
@@ -3898,8 +3829,8 @@ combine_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),
+                             simplify_gen_unary (NOT, inner_mode, const1_rtx,
+                                                 inner_mode),
                              XEXP (SUBREG_REG (XEXP (x, 0)), 1));
          return gen_lowpart_for_combine (mode, x);
        }
@@ -3908,10 +3839,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
         reversing the comparison code if valid.  */
       if (STORE_FLAG_VALUE == -1
          && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && reversible_comparison_p (XEXP (x, 0)))
-       return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
-                               mode, XEXP (XEXP (x, 0), 0),
-                               XEXP (XEXP (x, 0), 1));
+         && (reversed = reversed_comparison (x, mode, XEXP (XEXP (x, 0), 0),
+                                             XEXP (XEXP (x, 0), 1))))
+       return reversed;
 
       /* (ashiftrt foo C) where C is the number of bits in FOO minus 1
         is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
@@ -3922,7 +3852,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && XEXP (x, 1) == const1_rtx
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
          && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
+       return gen_rtx_GE (mode, XEXP (XEXP (x, 0), 0), const0_rtx);
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
         with negating logical insns (and-not, nand, etc.).  If result has
@@ -3932,28 +3862,24 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
        {
          rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
+         enum machine_mode op_mode;
 
-         if (GET_CODE (in1) == NOT)
-           in1 = XEXP (in1, 0);
-         else
-           in1 = gen_rtx_combine (NOT, GET_MODE (in1), in1);
+         op_mode = GET_MODE (in1);
+         in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
 
-         if (GET_CODE (in2) == NOT)
-           in2 = XEXP (in2, 0);
-         else if (GET_CODE (in2) == CONST_INT
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-           in2 = GEN_INT (GET_MODE_MASK (mode) & ~INTVAL (in2));
-         else
-           in2 = gen_rtx_combine (NOT, GET_MODE (in2), in2);
+         op_mode = GET_MODE (in2);
+         if (op_mode == VOIDmode)
+           op_mode = mode;
+         in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
 
-         if (GET_CODE (in2) == NOT)
+         if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
            {
              rtx tem = in2;
              in2 = in1; in1 = tem;
            }
 
-         return gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
-                                 mode, in1, in2);
+         return gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
+                                mode, in1, in2);
        }
       break;
 
@@ -3961,7 +3887,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       /* (neg (plus X 1)) can become (not X).  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && XEXP (XEXP (x, 0), 1) == const1_rtx)
-       return gen_rtx_combine (NOT, mode, XEXP (XEXP (x, 0), 0));
+       return gen_rtx_NOT (mode, XEXP (XEXP (x, 0), 0));
 
       /* Similarly, (neg (not X)) is (plus X 1).  */
       if (GET_CODE (XEXP (x, 0)) == NOT)
@@ -3972,7 +3898,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && (! FLOAT_MODE_P (mode)
              /* x-y != -(y-x) with IEEE floating point.  */
              || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-             || flag_fast_math))
+             || flag_unsafe_math_optimizations))
        return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
                           XEXP (XEXP (x, 0), 0));
 
@@ -4063,8 +3989,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
              || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
          && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
-                         XEXP (XEXP (XEXP (x, 0), 0), 0));
+       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
+                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
 
       /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
         (truncate:SI x).  */
@@ -4118,8 +4044,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
           || GET_CODE (XEXP (x, 0)) == NEG)
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND
          && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
-                         XEXP (XEXP (XEXP (x, 0), 0), 0));
+       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
+                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
 
       /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
         is (float_truncate:SF x).  */
@@ -4140,7 +4066,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       /* In IEEE floating point, x-0 is not the same as x.  */
       if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
           || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
-          || flag_fast_math)
+          || flag_unsafe_math_optimizations)
          && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
        return XEXP (x, 0);
       break;
@@ -4208,14 +4134,13 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
         is 1.  This produces better code than the alternative immediately
         below.  */
       if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && reversible_comparison_p (XEXP (x, 0))
          && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
-             || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
+             || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
+         && (reversed = reversed_comparison (XEXP (x, 0), mode,
+                                             XEXP (XEXP (x, 0), 0),
+                                             XEXP (XEXP (x, 0), 1))))
        return
-         gen_unary (NEG, mode, mode,
-                    gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
-                                mode, XEXP (XEXP (x, 0), 0),
-                                XEXP (XEXP (x, 0), 1)));
+         simplify_gen_unary (NEG, mode, reversed, mode);
 
       /* If only the low-order bit of X is possibly nonzero, (plus x -1)
         can become (ashiftrt (ashift (xor x 1) C) C) where C is
@@ -4228,8 +4153,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && nonzero_bits (XEXP (x, 0), mode) == 1)
        return simplify_shift_const (NULL_RTX, ASHIFTRT, mode,
           simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                                gen_rtx_combine (XOR, mode,
-                                                 XEXP (x, 0), const1_rtx),
+                                gen_rtx_XOR (mode, XEXP (x, 0), const1_rtx),
                                 GET_MODE_BITSIZE (mode) - 1),
           GET_MODE_BITSIZE (mode) - 1);
 
@@ -4260,10 +4184,10 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       if (STORE_FLAG_VALUE == 1
          && XEXP (x, 0) == const1_rtx
          && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
-         && reversible_comparison_p (XEXP (x, 1)))
-       return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))), mode,
-                          XEXP (XEXP (x, 1), 0),
-                          XEXP (XEXP (x, 1), 1));
+         && (reversed = reversed_comparison (XEXP (x, 1), mode,
+                                             XEXP (XEXP (x, 1), 0),
+                                             XEXP (XEXP (x, 1), 1))))
+       return reversed;
 
       /* (minus <foo> (and <foo> (const_int -pow2))) becomes
         (and <foo> (const_int pow2-1))  */
@@ -4319,6 +4243,10 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     case EQ:  case NE:
     case GT:  case GTU:  case GE:  case GEU:
     case LT:  case LTU:  case LE:  case LEU:
+    case UNEQ:  case LTGT:
+    case UNGT:  case UNGE:  
+    case UNLT:  case UNLE:  
+    case UNORDERED: case ORDERED:
       /* If the first operand is a condition code, we can't do anything
         with it.  */
       if (GET_CODE (XEXP (x, 0)) == COMPARE
@@ -4352,24 +4280,29 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
          if (STORE_FLAG_VALUE == 1
              && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
-             && op1 == const0_rtx && nonzero_bits (op0, mode) == 1)
+             && op1 == const0_rtx
+             && mode == GET_MODE (op0)
+             && nonzero_bits (op0, mode) == 1)
            return gen_lowpart_for_combine (mode,
                                            expand_compound_operation (op0));
 
          else if (STORE_FLAG_VALUE == 1
                   && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             return gen_unary (NEG, mode, mode,
-                               gen_lowpart_for_combine (mode, op0));
+             return simplify_gen_unary (NEG, mode,
+                                        gen_lowpart_for_combine (mode, op0),
+                                        mode);
            }
 
          else if (STORE_FLAG_VALUE == 1
                   && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
@@ -4381,6 +4314,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          else if (STORE_FLAG_VALUE == 1
                   && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
            {
@@ -4401,28 +4335,33 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          else if (STORE_FLAG_VALUE == -1
                   && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             return gen_unary (NEG, mode, mode,
-                               gen_lowpart_for_combine (mode, op0));
+             return simplify_gen_unary (NEG, mode,
+                                        gen_lowpart_for_combine (mode, op0),
+                                        mode);
            }
 
          else if (STORE_FLAG_VALUE == -1
                   && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             return gen_unary (NOT, mode, mode,
-                               gen_lowpart_for_combine (mode, op0));
+             return simplify_gen_unary (NOT, mode,
+                                        gen_lowpart_for_combine (mode, op0),
+                                        mode);
            }
 
          /* If X is 0/1, (eq X 0) is X-1.  */
          else if (STORE_FLAG_VALUE == -1
                   && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
+                  && mode == GET_MODE (op0)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
@@ -4453,7 +4392,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
          /* If the code changed, return a whole new comparison.  */
          if (new_code != code)
-           return gen_rtx_combine (new_code, mode, op0, op1);
+           return gen_rtx_fmt_ee (new_code, mode, op0, op1);
 
          /* Otherwise, keep this operation, but maybe change its operands.
             This also converts (ne (compare FOO BAR) 0) to (ne FOO BAR).  */
@@ -4505,7 +4444,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
       /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
       if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode))
-       return gen_rtx_combine (NEG, mode, XEXP (x, 0));
+       return gen_rtx_NEG (mode, XEXP (x, 0));
 
       break;
 
@@ -4544,6 +4483,45 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
       break;
 
+    case VEC_SELECT:
+      {
+       rtx op0 = XEXP (x, 0);
+       rtx op1 = XEXP (x, 1);
+       int len;
+
+       if (GET_CODE (op1) != PARALLEL)
+         abort ();
+       len = XVECLEN (op1, 0);
+       if (len == 1
+           && GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
+           && GET_CODE (op0) == VEC_CONCAT)
+         {
+           int offset = INTVAL (XVECEXP (op1, 0, 0)) * GET_MODE_SIZE (GET_MODE (x));
+
+           /* Try to find the element in the VEC_CONCAT.  */
+           for (;;)
+             {
+               if (GET_MODE (op0) == GET_MODE (x))
+                 return op0;
+               if (GET_CODE (op0) == VEC_CONCAT)
+                 {
+                   HOST_WIDE_INT op0_size = GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)));
+                   if (op0_size < offset)
+                     op0 = XEXP (op0, 0);
+                   else
+                     {
+                       offset -= op0_size;
+                       op0 = XEXP (op0, 1);
+                     }
+                 }
+               else
+                 break;
+             }
+         }
+      }
+
+      break;
+      
     default:
       break;
     }
@@ -4559,33 +4537,37 @@ simplify_if_then_else (x)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx cond = XEXP (x, 0);
-  rtx true = XEXP (x, 1);
-  rtx false = XEXP (x, 2);
+  rtx true_rtx = XEXP (x, 1);
+  rtx false_rtx = XEXP (x, 2);
   enum rtx_code true_code = GET_CODE (cond);
   int comparison_p = GET_RTX_CLASS (true_code) == '<';
   rtx temp;
   int i;
+  enum rtx_code false_code;
+  rtx reversed;
 
   /* Simplify storing of the truth value.  */
-  if (comparison_p && true == const_true_rtx && false == const0_rtx)
+  if (comparison_p && true_rtx == const_true_rtx && false_rtx == const0_rtx)
     return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
 
   /* Also when the truth value has to be reversed.  */
-  if (comparison_p && reversible_comparison_p (cond)
-      && true == const0_rtx && false == const_true_rtx)
-    return gen_binary (reverse_condition (true_code),
-                      mode, XEXP (cond, 0), XEXP (cond, 1));
+  if (comparison_p
+      && true_rtx == const0_rtx && false_rtx == const_true_rtx
+      && (reversed = reversed_comparison (cond, mode, XEXP (cond, 0),
+                                         XEXP (cond, 1))))
+    return reversed;
 
   /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register used
      in it is being compared against certain values.  Get the true and false
      comparisons and see if that says anything about the value of each arm.  */
 
-  if (comparison_p && reversible_comparison_p (cond)
+  if (comparison_p
+      && ((false_code = combine_reversed_comparison_code (cond))
+         != UNKNOWN)
       && GET_CODE (XEXP (cond, 0)) == REG)
     {
       HOST_WIDE_INT nzb;
       rtx from = XEXP (cond, 0);
-      enum rtx_code false_code = reverse_condition (true_code);
       rtx true_val = XEXP (cond, 1);
       rtx false_val = true_val;
       int swapped = 0;
@@ -4595,7 +4577,7 @@ simplify_if_then_else (x)
       if (false_code == EQ)
        {
          swapped = 1, true_code = EQ, false_code = NE;
-         temp = true, true = false, false = temp;
+         temp = true_rtx, true_rtx = false_rtx, false_rtx = temp;
        }
 
       /* If we are comparing against zero and the expression being tested has
@@ -4614,18 +4596,21 @@ simplify_if_then_else (x)
         branch and it is used in the arm.  Be careful due to the potential
         of locally-shared RTL.  */
 
-      if (reg_mentioned_p (from, true))
-       true = subst (known_cond (copy_rtx (true), true_code, from, true_val),
+      if (reg_mentioned_p (from, true_rtx))
+       true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
+                                     from, true_val),
                      pc_rtx, pc_rtx, 0, 0);
-      if (reg_mentioned_p (from, false))
-       false = subst (known_cond (copy_rtx (false), false_code,
+      if (reg_mentioned_p (from, false_rtx))
+       false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
                                   from, false_val),
                       pc_rtx, pc_rtx, 0, 0);
 
-      SUBST (XEXP (x, 1), swapped ? false : true);
-      SUBST (XEXP (x, 2), swapped ? true : false);
+      SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
+      SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
 
-      true = XEXP (x, 1), false = XEXP (x, 2), true_code = GET_CODE (cond);
+      true_rtx = XEXP (x, 1);
+      false_rtx = XEXP (x, 2);
+      true_code = GET_CODE (cond);
     }
 
   /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be
@@ -4634,28 +4619,30 @@ simplify_if_then_else (x)
      arm, the false arm is the same as the first operand of the comparison, or
      the false arm is more complicated than the true arm.  */
 
-  if (comparison_p && reversible_comparison_p (cond)
-      && (true == pc_rtx
-         || (CONSTANT_P (true)
-             && GET_CODE (false) != CONST_INT && false != pc_rtx)
-         || true == const0_rtx
-         || (GET_RTX_CLASS (GET_CODE (true)) == 'o'
-             && GET_RTX_CLASS (GET_CODE (false)) != 'o')
-         || (GET_CODE (true) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (true))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (false)) != 'o')
-         || reg_mentioned_p (true, false)
-         || rtx_equal_p (false, XEXP (cond, 0))))
-    {
-      true_code = reverse_condition (true_code);
+  if (comparison_p
+      && combine_reversed_comparison_code (cond) != UNKNOWN
+      && (true_rtx == pc_rtx
+         || (CONSTANT_P (true_rtx)
+             && GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
+         || true_rtx == const0_rtx
+         || (GET_RTX_CLASS (GET_CODE (true_rtx)) == 'o'
+             && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
+         || (GET_CODE (true_rtx) == SUBREG
+             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (true_rtx))) == 'o'
+             && GET_RTX_CLASS (GET_CODE (false_rtx)) != 'o')
+         || reg_mentioned_p (true_rtx, false_rtx)
+         || rtx_equal_p (false_rtx, XEXP (cond, 0))))
+    {
+      true_code = reversed_comparison_code (cond, NULL);
       SUBST (XEXP (x, 0),
-            gen_binary (true_code, GET_MODE (cond), XEXP (cond, 0),
-                        XEXP (cond, 1)));
+            reversed_comparison (cond, GET_MODE (cond), XEXP (cond, 0),
+                                 XEXP (cond, 1)));
 
-      SUBST (XEXP (x, 1), false);
-      SUBST (XEXP (x, 2), true);
+      SUBST (XEXP (x, 1), false_rtx);
+      SUBST (XEXP (x, 2), true_rtx);
 
-      temp = true, true = false, false = temp, cond = XEXP (x, 0);
+      temp = true_rtx, true_rtx = false_rtx, false_rtx = temp;
+      cond = XEXP (x, 0);
 
       /* It is possible that the conditional has been simplified out.  */
       true_code = GET_CODE (cond);
@@ -4664,60 +4651,65 @@ simplify_if_then_else (x)
 
   /* If the two arms are identical, we don't need the comparison.  */
 
-  if (rtx_equal_p (true, false) && ! side_effects_p (cond))
-    return true;
+  if (rtx_equal_p (true_rtx, false_rtx) && ! side_effects_p (cond))
+    return true_rtx;
 
   /* Convert a == b ? b : a to "a".  */
   if (true_code == EQ && ! side_effects_p (cond)
-      && rtx_equal_p (XEXP (cond, 0), false)
-      && rtx_equal_p (XEXP (cond, 1), true))
-    return false;
+      && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+      && rtx_equal_p (XEXP (cond, 0), false_rtx)
+      && rtx_equal_p (XEXP (cond, 1), true_rtx))
+    return false_rtx;
   else if (true_code == NE && ! side_effects_p (cond)
-          && rtx_equal_p (XEXP (cond, 0), true)
-          && rtx_equal_p (XEXP (cond, 1), false))
-    return true;
+          && (! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
+          && rtx_equal_p (XEXP (cond, 0), true_rtx)
+          && rtx_equal_p (XEXP (cond, 1), false_rtx))
+    return true_rtx;
 
   /* Look for cases where we have (abs x) or (neg (abs X)).  */
 
   if (GET_MODE_CLASS (mode) == MODE_INT
-      && GET_CODE (false) == NEG
-      && rtx_equal_p (true, XEXP (false, 0))
+      && GET_CODE (false_rtx) == NEG
+      && rtx_equal_p (true_rtx, XEXP (false_rtx, 0))
       && comparison_p
-      && rtx_equal_p (true, XEXP (cond, 0))
-      && ! side_effects_p (true))
+      && rtx_equal_p (true_rtx, XEXP (cond, 0))
+      && ! side_effects_p (true_rtx))
     switch (true_code)
       {
       case GT:
       case GE:
-       return gen_unary (ABS, mode, mode, true);
+       return simplify_gen_unary (ABS, mode, true_rtx, mode);
       case LT:
       case LE:
-       return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true));
+       return
+         simplify_gen_unary (NEG, mode,
+                             simplify_gen_unary (ABS, mode, true_rtx, mode),
+                             mode);
     default:
       break;
       }
 
   /* Look for MIN or MAX.  */
 
-  if ((! FLOAT_MODE_P (mode) || flag_fast_math)
+  if ((! FLOAT_MODE_P (mode) || flag_unsafe_math_optimizations)
       && comparison_p
-      && rtx_equal_p (XEXP (cond, 0), true)
-      && rtx_equal_p (XEXP (cond, 1), false)
+      && rtx_equal_p (XEXP (cond, 0), true_rtx)
+      && rtx_equal_p (XEXP (cond, 1), false_rtx)
       && ! side_effects_p (cond))
     switch (true_code)
       {
       case GE:
       case GT:
-       return gen_binary (SMAX, mode, true, false);
+       return gen_binary (SMAX, mode, true_rtx, false_rtx);
       case LE:
       case LT:
-       return gen_binary (SMIN, mode, true, false);
+       return gen_binary (SMIN, mode, true_rtx, false_rtx);
       case GEU:
       case GTU:
-       return gen_binary (UMAX, mode, true, false);
+       return gen_binary (UMAX, mode, true_rtx, false_rtx);
       case LEU:
       case LTU:
-       return gen_binary (UMIN, mode, true, false);
+       return gen_binary (UMIN, mode, true_rtx, false_rtx);
       default:
        break;
       }
@@ -4732,8 +4724,8 @@ simplify_if_then_else (x)
   if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
       && comparison_p && mode != VOIDmode && ! side_effects_p (x))
     {
-      rtx t = make_compound_operation (true, SET);
-      rtx f = make_compound_operation (false, SET);
+      rtx t = make_compound_operation (true_rtx, SET);
+      rtx f = make_compound_operation (false_rtx, SET);
       rtx cond_op0 = XEXP (cond, 0);
       rtx cond_op1 = XEXP (cond, 1);
       enum rtx_code op = NIL, extend_op = NIL;
@@ -4834,7 +4826,7 @@ simplify_if_then_else (x)
          temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
 
          if (extend_op != NIL)
-           temp = gen_unary (extend_op, mode, m, temp);
+           temp = simplify_gen_unary (extend_op, mode, temp, m);
 
          return temp;
        }
@@ -4846,12 +4838,12 @@ simplify_if_then_else (x)
      can actually do this more generally, but it doesn't seem worth it.  */
 
   if (true_code == NE && XEXP (cond, 1) == const0_rtx
-      && false == const0_rtx && GET_CODE (true) == CONST_INT
+      && false_rtx == const0_rtx && GET_CODE (true_rtx) == CONST_INT
       && ((1 == nonzero_bits (XEXP (cond, 0), mode)
-          && (i = exact_log2 (INTVAL (true))) >= 0)
+          && (i = exact_log2 (INTVAL (true_rtx))) >= 0)
          || ((num_sign_bit_copies (XEXP (cond, 0), mode)
               == GET_MODE_BITSIZE (mode))
-             && (i = exact_log2 (-INTVAL (true))) >= 0)))
+             && (i = exact_log2 (-INTVAL (true_rtx))) >= 0)))
     return
       simplify_shift_const (NULL_RTX, ASHIFT, mode,
                            gen_lowpart_for_combine (mode, XEXP (cond, 0)), i);
@@ -4951,8 +4943,8 @@ simplify_set (x)
        {
          unsigned HOST_WIDE_INT mask;
 
-         SUBST (*cc_use, gen_rtx_combine (new_code, GET_MODE (*cc_use),
-                                          dest, const0_rtx));
+         SUBST (*cc_use, gen_rtx_fmt_ee (new_code, GET_MODE (*cc_use),
+                                         dest, const0_rtx));
 
          /* If the only change we made was to change an EQ into an NE or
             vice versa, OP0 has only one bit that might be nonzero, and OP1
@@ -4999,8 +4991,7 @@ simplify_set (x)
         correct mode, we need one.  */
       if (GET_CODE (src) != COMPARE || GET_MODE (src) != compare_mode)
        {
-         SUBST (SET_SRC (x),
-                gen_rtx_combine (COMPARE, compare_mode, op0, op1));
+         SUBST (SET_SRC (x), gen_rtx_COMPARE (compare_mode, op0, op1));
          src = SET_SRC (x);
        }
       else
@@ -5067,14 +5058,14 @@ simplify_set (x)
 
   if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
       && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
-      && SUBREG_WORD (src) == 0
+      && SUBREG_BYTE (src) == 0
       && (GET_MODE_SIZE (GET_MODE (src))
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
       && GET_CODE (SUBREG_REG (src)) == MEM)
     {
       SUBST (SET_SRC (x),
-            gen_rtx_combine (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
-                             GET_MODE (src), XEXP (src, 0)));
+            gen_rtx (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
+                     GET_MODE (src), SUBREG_REG (src)));
 
       src = SET_SRC (x);
     }
@@ -5100,29 +5091,32 @@ simplify_set (x)
          == GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (src, 0), 0))))
       && ! side_effects_p (src))
     {
-      rtx true = (GET_CODE (XEXP (src, 0)) == NE
+      rtx true_rtx = (GET_CODE (XEXP (src, 0)) == NE
                      ? XEXP (src, 1) : XEXP (src, 2));
-      rtx false = (GET_CODE (XEXP (src, 0)) == NE
+      rtx false_rtx = (GET_CODE (XEXP (src, 0)) == NE
                   ? XEXP (src, 2) : XEXP (src, 1));
       rtx term1 = const0_rtx, term2, term3;
 
-      if (GET_CODE (true) == IOR && rtx_equal_p (XEXP (true, 0), false))
-       term1 = false, true = XEXP (true, 1), false = const0_rtx;
-      else if (GET_CODE (true) == IOR
-              && rtx_equal_p (XEXP (true, 1), false))
-       term1 = false, true = XEXP (true, 0), false = const0_rtx;
-      else if (GET_CODE (false) == IOR
-              && rtx_equal_p (XEXP (false, 0), true))
-       term1 = true, false = XEXP (false, 1), true = const0_rtx;
-      else if (GET_CODE (false) == IOR
-              && rtx_equal_p (XEXP (false, 1), true))
-       term1 = true, false = XEXP (false, 0), true = const0_rtx;
-
-      term2 = gen_binary (AND, GET_MODE (src), XEXP (XEXP (src, 0), 0), true);
+      if (GET_CODE (true_rtx) == IOR
+         && rtx_equal_p (XEXP (true_rtx, 0), false_rtx))
+       term1 = false_rtx, true_rtx = XEXP(true_rtx, 1), false_rtx = const0_rtx;
+      else if (GET_CODE (true_rtx) == IOR
+              && rtx_equal_p (XEXP (true_rtx, 1), false_rtx))
+       term1 = false_rtx, true_rtx = XEXP(true_rtx, 0), false_rtx = const0_rtx;
+      else if (GET_CODE (false_rtx) == IOR
+              && rtx_equal_p (XEXP (false_rtx, 0), true_rtx))
+       term1 = true_rtx, false_rtx = XEXP(false_rtx, 1), true_rtx = const0_rtx;
+      else if (GET_CODE (false_rtx) == IOR
+              && rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
+       term1 = true_rtx, false_rtx = XEXP(false_rtx, 0), true_rtx = const0_rtx;
+
+      term2 = gen_binary (AND, GET_MODE (src),
+                         XEXP (XEXP (src, 0), 0), true_rtx);
       term3 = gen_binary (AND, GET_MODE (src),
-                         gen_unary (NOT, GET_MODE (src), GET_MODE (src),
-                                    XEXP (XEXP (src, 0), 0)),
-                         false);
+                         simplify_gen_unary (NOT, GET_MODE (src),
+                                             XEXP (XEXP (src, 0), 0),
+                                             GET_MODE (src)),
+                         false_rtx);
 
       SUBST (SET_SRC (x),
             gen_binary (IOR, GET_MODE (src),
@@ -5132,68 +5126,6 @@ simplify_set (x)
       src = SET_SRC (x);
     }
 
-#ifdef HAVE_conditional_arithmetic
-  /* If we have conditional arithmetic and the operand of a SET is
-     a conditional expression, replace this with an IF_THEN_ELSE.
-     We can either have a conditional expression or a MULT of that expression
-     with a constant.  */
-  if ((GET_RTX_CLASS (GET_CODE (src)) == '1'
-       || GET_RTX_CLASS (GET_CODE (src)) == '2'
-       || GET_RTX_CLASS (GET_CODE (src)) == 'c')
-      && (GET_RTX_CLASS (GET_CODE (XEXP (src, 0))) == '<'
-         || (GET_CODE (XEXP (src, 0)) == MULT
-             && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (src, 0), 0))) == '<'
-             && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT)))
-    {
-      rtx cond = XEXP (src, 0);
-      rtx true_val = const1_rtx;
-      rtx false_arm, true_arm;
-
-      if (GET_CODE (cond) == MULT)
-       {
-         true_val = XEXP (cond, 1);
-         cond = XEXP (cond, 0);
-       }
-
-      if (GET_RTX_CLASS (GET_CODE (src)) == '1')
-       {
-         true_arm = gen_unary (GET_CODE (src), GET_MODE (src),
-                               GET_MODE (XEXP (src, 0)), true_val);
-         false_arm = gen_unary (GET_CODE (src), GET_MODE (src),
-                                GET_MODE (XEXP (src, 0)), const0_rtx);
-       }
-      else
-       {
-         true_arm = gen_binary (GET_CODE (src), GET_MODE (src),
-                                true_val, XEXP (src, 1));
-         false_arm = gen_binary (GET_CODE (src), GET_MODE (src),
-                                 const0_rtx, XEXP (src, 1));
-       }
-
-      /* Canonicalize if true_arm is the simpler one.  */
-      if (GET_RTX_CLASS (GET_CODE (true_arm)) == 'o'
-         && GET_RTX_CLASS (GET_CODE (false_arm)) != 'o'
-         && reversible_comparison_p (cond))
-       {
-         rtx temp = true_arm;
-
-         true_arm = false_arm;
-         false_arm = temp;
-
-         cond = gen_rtx_combine (reverse_condition (GET_CODE (cond)),
-                                 GET_MODE (cond), XEXP (cond, 0),
-                                 XEXP (cond, 1));
-       }
-
-      src = gen_rtx_combine (IF_THEN_ELSE, GET_MODE (src),
-                            gen_rtx_combine (GET_CODE (cond), VOIDmode,
-                                             XEXP (cond, 0),
-                                             XEXP (cond, 1)),
-                            true_arm, false_arm);
-      SUBST (SET_SRC (x), src);
-    }
-#endif
-
   /* If either SRC or DEST is a CLOBBER of (const_int 0), make this
      whole thing fail.  */
   if (GET_CODE (src) == CLOBBER && XEXP (src, 0) == const0_rtx)
@@ -5216,6 +5148,7 @@ simplify_logical (x, last)
   enum machine_mode mode = GET_MODE (x);
   rtx op0 = XEXP (x, 0);
   rtx op1 = XEXP (x, 1);
+  rtx reversed;
 
   switch (GET_CODE (x))
     {
@@ -5226,13 +5159,15 @@ simplify_logical (x, last)
          && rtx_equal_p (XEXP (op0, 0), op1)
          && ! side_effects_p (op1))
        x = gen_binary (AND, mode,
-                       gen_unary (NOT, mode, mode, XEXP (op0, 1)), op1);
+                       simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
+                       op1);
 
       if (GET_CODE (op0) == XOR
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
        x = gen_binary (AND, mode,
-                       gen_unary (NOT, mode, mode, XEXP (op0, 0)), op1);
+                       simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
+                       op1);
 
       /* Similarly for (~(A ^ B)) & A.  */
       if (GET_CODE (op0) == NOT
@@ -5441,7 +5376,9 @@ simplify_logical (x, last)
            SUBST (XEXP (x, 1), op1);
          }
        else if (num_negated == 1)
-         return gen_unary (NOT, mode, mode, gen_binary (XOR, mode, op0, op1));
+         return
+           simplify_gen_unary (NOT, mode, gen_binary (XOR, mode, op0, op1),
+                               mode);
       }
 
       /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
@@ -5452,14 +5389,14 @@ simplify_logical (x, last)
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
        return gen_binary (AND, mode,
-                          gen_unary (NOT, mode, mode, XEXP (op0, 0)),
+                          simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
                           op1);
 
       else if (GET_CODE (op0) == AND
               && rtx_equal_p (XEXP (op0, 0), op1)
               && ! side_effects_p (op1))
        return gen_binary (AND, mode,
-                          gen_unary (NOT, mode, mode, XEXP (op0, 1)),
+                          simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
                           op1);
 
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
@@ -5467,9 +5404,9 @@ simplify_logical (x, last)
       if (STORE_FLAG_VALUE == 1
          && op1 == const1_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));
+         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
+                                             XEXP (op0, 1))))
+       return reversed;
 
       /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
         is (lt foo (const_int 0)), so we can perform the above
@@ -5480,7 +5417,7 @@ simplify_logical (x, last)
          && GET_CODE (op0) == LSHIFTRT
          && GET_CODE (XEXP (op0, 1)) == CONST_INT
          && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return gen_rtx_combine (GE, mode, XEXP (op0, 0), const0_rtx);
+       return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
 
       /* (xor (comparison foo bar) (const_int sign-bit))
         when STORE_FLAG_VALUE is the sign bit.  */
@@ -5489,9 +5426,9 @@ simplify_logical (x, last)
              == (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));
+         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
+                                             XEXP (op0, 1))))
+       return reversed;
 
       break;
 
@@ -5720,9 +5657,11 @@ expand_field_assignment (x)
       if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
          && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
        {
+         int byte_offset = SUBREG_BYTE (XEXP (SET_DEST (x), 0));
+
          inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
          len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
-         pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
+         pos = GEN_INT (BITS_PER_WORD * (byte_offset / UNITS_PER_WORD));
        }
       else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
               && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
@@ -5811,11 +5750,11 @@ expand_field_assignment (x)
        (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)),
+                                simplify_gen_unary (NOT, compute_mode,
+                                                    gen_binary (ASHIFT,
+                                                                compute_mode,
+                                                                mask, pos),
+                                                    compute_mode),
                                 inner),
                     gen_binary (ASHIFT, compute_mode,
                                 gen_binary (AND, compute_mode,
@@ -5960,22 +5899,30 @@ 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));
-         else
-           new = inner;
-       }
+           {
+             int final_word = pos / BITS_PER_WORD;
+
+             if (WORDS_BIG_ENDIAN
+                 && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+               final_word = ((GET_MODE_SIZE (inner_mode)
+                              - GET_MODE_SIZE (tmode))
+                             / UNITS_PER_WORD) - final_word;
+
+             final_word *= UNITS_PER_WORD;
+             if (BYTES_BIG_ENDIAN &&
+                 GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
+               final_word += (GET_MODE_SIZE (inner_mode)
+                              - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
+
+             new = gen_rtx_SUBREG (tmode, inner, final_word);
+           }
+         else
+           new = inner;
+       }
       else
        new = force_to_mode (inner, tmode,
                             len >= HOST_BITS_PER_WIDE_INT
-                            ? ~(HOST_WIDE_INT) 0
+                            ? ~(unsigned HOST_WIDE_INT) 0
                             : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
                             NULL_RTX, 0);
 
@@ -5986,7 +5933,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
        return (GET_CODE (new) == MEM ? new
                : (GET_CODE (new) != SUBREG
                   ? gen_rtx_CLOBBER (tmode, const0_rtx)
-                  : gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new)));
+                  : gen_rtx_STRICT_LOW_PART (VOIDmode, new)));
 
       if (mode == tmode)
        return new;
@@ -6007,7 +5954,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
          /* Prefer ZERO_EXTENSION, since it gives more information to
             backends.  */
-         if (rtx_cost (temp, SET) < rtx_cost (temp1, SET))
+         if (rtx_cost (temp, SET) <= rtx_cost (temp1, SET))
            return temp;
          return temp1;
        }
@@ -6015,8 +5962,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       /* Otherwise, sign- or zero-extend unless we already are in the
         proper mode.  */
 
-      return (gen_rtx_combine (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
-                              mode, new));
+      return (gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+                            mode, new));
     }
 
   /* Unless this is a COMPARE or we have a funny memory reference,
@@ -6131,8 +6078,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
        pos = width - len - pos;
       else
        pos_rtx
-         = gen_rtx_combine (MINUS, GET_MODE (pos_rtx),
-                            GEN_INT (width - len), pos_rtx);
+         = gen_rtx_MINUS (GET_MODE (pos_rtx), GEN_INT (width - len), pos_rtx);
       /* POS may be less than 0 now, but we check for that below.
         Note that it can only be less than 0 if GET_CODE (inner) != MEM.  */
     }
@@ -6196,7 +6142,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       inner = force_to_mode (inner, wanted_inner_mode,
                             pos_rtx
                             || len + orig_pos >= HOST_BITS_PER_WIDE_INT
-                            ? ~(HOST_WIDE_INT) 0
+                            ? ~(unsigned HOST_WIDE_INT) 0
                             : ((((unsigned HOST_WIDE_INT) 1 << len) - 1)
                                << orig_pos),
                             NULL_RTX, 0);
@@ -6207,7 +6153,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
   if (pos_rtx != 0
       && GET_MODE_SIZE (pos_mode) > GET_MODE_SIZE (GET_MODE (pos_rtx)))
     {
-      rtx temp = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx);
+      rtx temp = gen_rtx_ZERO_EXTEND (pos_mode, pos_rtx);
 
       /* If we know that no extraneous bits are set, and that the high
         bit is not set, convert extraction to cheaper one - eighter
@@ -6223,7 +6169,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
        {
          rtx temp1 = gen_rtx_SIGN_EXTEND (pos_mode, pos_rtx);
 
-         /* Preffer ZERO_EXTENSION, since it gives more information to
+         /* Prefer ZERO_EXTENSION, since it gives more information to
             backends.  */
          if (rtx_cost (temp1, SET) < rtx_cost (temp, SET))
            temp = temp1;
@@ -6244,7 +6190,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
     pos_rtx = GEN_INT (pos);
 
   /* Make the required operation.  See if we can use existing rtx.  */
-  new = gen_rtx_combine (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
+  new = gen_rtx_fmt_eee (unsignedp ? ZERO_EXTRACT : SIGN_EXTRACT,
                         extraction_mode, inner, GEN_INT (len), pos_rtx);
   if (! in_dest)
     new = gen_lowpart_for_combine (mode, new);
@@ -6278,7 +6224,7 @@ extract_left_shift (x, count)
 
     case NEG:  case NOT:
       if ((tem = extract_left_shift (XEXP (x, 0), count)) != 0)
-       return gen_unary (code, mode, mode, tem);
+       return simplify_gen_unary (code, mode, tem, mode);
 
       break;
 
@@ -6355,9 +6301,9 @@ make_compound_operation (x, in_code)
          && INTVAL (XEXP (x, 1)) >= 0)
        {
          new = make_compound_operation (XEXP (x, 0), next_code);
-         new = gen_rtx_combine (MULT, mode, new,
-                                GEN_INT ((HOST_WIDE_INT) 1
-                                         << INTVAL (XEXP (x, 1))));
+         new = gen_rtx_MULT (mode, new,
+                             GEN_INT ((HOST_WIDE_INT) 1
+                                      << INTVAL (XEXP (x, 1))));
        }
       break;
 
@@ -6397,11 +6343,11 @@ make_compound_operation (x, in_code)
               && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
        {
          /* 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)));
+         new = gen_rtx_fmt_ee (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)));
          new = make_compound_operation (new, in_code);
        }
 
@@ -6437,10 +6383,10 @@ make_compound_operation (x, in_code)
          mask >>= INTVAL (XEXP (XEXP (x, 0), 1));
          if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
            SUBST (XEXP (x, 0),
-                  gen_rtx_combine (ASHIFTRT, mode,
-                                   make_compound_operation (XEXP (XEXP (x, 0), 0),
-                                                            next_code),
-                                   XEXP (XEXP (x, 0), 1)));
+                  gen_rtx_ASHIFTRT (mode,
+                                    make_compound_operation
+                                    (XEXP (XEXP (x, 0), 0), next_code),
+                                    XEXP (XEXP (x, 0), 1)));
        }
 
       /* If the constant is one less than a power of two, this might be
@@ -6472,10 +6418,10 @@ make_compound_operation (x, in_code)
          && mode_width <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
        {
-         new = gen_rtx_combine (ASHIFTRT, mode,
-                                make_compound_operation (XEXP (x, 0),
-                                                         next_code),
-                                XEXP (x, 1));
+         new = gen_rtx_ASHIFTRT (mode,
+                                 make_compound_operation (XEXP (x, 0),
+                                                          next_code),
+                                 XEXP (x, 1));
          break;
        }
 
@@ -6497,6 +6443,7 @@ make_compound_operation (x, in_code)
                                 INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
                                 NULL_RTX, mode_width - INTVAL (rhs),
                                 code == LSHIFTRT, 0, in_code == COMPARE);
+         break;
        }
 
       /* See if we have operations between an ASHIFTRT and an ASHIFT.
@@ -6548,7 +6495,7 @@ make_compound_operation (x, in_code)
          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));
+           tem = gen_rtx_fmt_e (GET_CODE (tem), mode, XEXP (tem, 0));
          else
            tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
          return tem;
@@ -6862,18 +6809,23 @@ force_to_mode (x, mode, mask, reg, just_select)
       /* If X is (minus C Y) where C's least set bit is larger than any bit
         in the mask, then we may replace with (neg Y).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT
-         && (INTVAL (XEXP (x, 0)) & -INTVAL (XEXP (x, 0))) > mask)
+         && (((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 0))
+                                       & -INTVAL (XEXP (x, 0))))
+             > mask))
        {
-         x = gen_unary (NEG, GET_MODE (x), GET_MODE (x), XEXP (x, 1));
+         x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
+                                 GET_MODE (x));
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
       /* Similarly, if C contains every bit in the mask, then we may
         replace with (not Y).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT
-         && (INTVAL (XEXP (x, 0)) | mask) == INTVAL (XEXP (x, 0)))
+         && ((INTVAL (XEXP (x, 0)) | (HOST_WIDE_INT) mask)
+             == INTVAL (XEXP (x, 0))))
        {
-         x = gen_unary (NOT, GET_MODE (x), GET_MODE (x), XEXP (x, 1));
+         x = simplify_gen_unary (NOT, GET_MODE (x),
+                                 XEXP (x, 1), GET_MODE (x));
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
@@ -7158,7 +7110,7 @@ force_to_mode (x, mode, mask, reg, just_select)
                                     force_to_mode (XEXP (x, 0), mode, mask,
                                                    reg, next_select));
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
-       x = gen_unary (code, op_mode, op_mode, op0);
+       x = simplify_gen_unary (code, op_mode, op0, op_mode);
       break;
 
     case NE:
@@ -7225,8 +7177,9 @@ if_then_else_cond (x, ptrue, pfalse)
   else if (GET_RTX_CLASS (code) == '1'
           && (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0)
     {
-      *ptrue = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), true0);
-      *pfalse = gen_unary (code, mode, GET_MODE (XEXP (x, 0)), false0);
+      *ptrue = simplify_gen_unary (code, mode, true0, GET_MODE (XEXP (x, 0)));
+      *pfalse = simplify_gen_unary (code, mode, false0,
+                                   GET_MODE (XEXP (x, 0)));
       return cond0;
     }
 
@@ -7277,12 +7230,11 @@ if_then_else_cond (x, ptrue, pfalse)
 
          if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
              && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
-             && reversible_comparison_p (cond1)
-             && ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1))
+             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == reverse_condition (GET_CODE (cond1)))
+                      == combine_reversed_comparison_code (cond1))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
@@ -7290,7 +7242,9 @@ if_then_else_cond (x, ptrue, pfalse)
              *ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
              *pfalse = gen_binary (MULT, mode,
                                    (code == MINUS
-                                    ? gen_unary (NEG, mode, mode, op1) : op1),
+                                    ? simplify_gen_unary (NEG, mode, op1,
+                                                          mode)
+                                    : op1),
                                    const_true_rtx);
              return cond0;
            }
@@ -7307,12 +7261,11 @@ if_then_else_cond (x, ptrue, pfalse)
 
          if (GET_RTX_CLASS (GET_CODE (cond0)) == '<'
              && GET_RTX_CLASS (GET_CODE (cond1)) == '<'
-             && reversible_comparison_p (cond1)
-             && ((GET_CODE (cond0) == reverse_condition (GET_CODE (cond1))
+             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == reverse_condition (GET_CODE (cond1)))
+                      == combine_reversed_comparison_code (cond1))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
@@ -7353,10 +7306,12 @@ if_then_else_cond (x, ptrue, pfalse)
           || GET_CODE (SUBREG_REG (x)) == MEM
           || CONSTANT_P (SUBREG_REG (x)))
          && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
-         && (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
+         && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
        {
-         true0 = operand_subword (true0, SUBREG_WORD (x), 0, mode);
-         false0 = operand_subword (false0, SUBREG_WORD (x), 0, mode);
+         true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
+                                  GET_MODE (SUBREG_REG (x)));
+         false0 = operand_subword (false0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
+                                   GET_MODE (SUBREG_REG (x)));
        }
       *ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
       *pfalse
@@ -7371,6 +7326,14 @@ if_then_else_cond (x, ptrue, pfalse)
           || ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
     ;
 
+  /* If we're in BImode, canonicalize on 0 and STORE_FLAG_VALUE, as that
+     will be least confusing to the rest of the compiler.  */
+  else if (mode == BImode)
+    {
+      *ptrue = GEN_INT (STORE_FLAG_VALUE), *pfalse = const0_rtx;
+      return x;
+    }
+
   /* If X is known to be either 0 or -1, those are the true and
      false values when testing X.  */
   else if (x == constm1_rtx || x == const0_rtx
@@ -7417,7 +7380,9 @@ known_cond (x, cond, reg, val)
   if (side_effects_p (x))
     return x;
 
-  if (cond == EQ && rtx_equal_p (x, reg))
+  if (cond == EQ && rtx_equal_p (x, reg) && !FLOAT_MODE_P (cond))
+    return val;
+  if (cond == UNEQ && rtx_equal_p (x, reg))
     return val;
 
   /* If X is (abs REG) and we know something about REG's relationship
@@ -7429,8 +7394,9 @@ known_cond (x, cond, reg, val)
       case GE:  case GT:  case EQ:
        return XEXP (x, 0);
       case LT:  case LE:
-       return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)),
-                         XEXP (x, 0));
+       return simplify_gen_unary (NEG, GET_MODE (XEXP (x, 0)),
+                                  XEXP (x, 0),
+                                  GET_MODE (XEXP (x, 0)));
       default:
        break;
       }
@@ -7450,7 +7416,7 @@ known_cond (x, cond, reg, val)
              if (comparison_dominates_p (cond, code))
                return const_true_rtx;
 
-             code = reverse_condition (code);
+             code = combine_reversed_comparison_code (x);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
                return const0_rtx;
@@ -7462,7 +7428,12 @@ known_cond (x, cond, reg, val)
            {
              int unsignedp = (code == UMIN || code == UMAX);
 
-             if (code == SMAX || code == UMAX)
+             /* Do not reverse the condition when it is NE or EQ.
+                This is because we cannot conclude anything about
+                the value of 'SMAX (x, y)' when x is not equal to y,
+                but we can when x equals y.  */ 
+             if ((code == SMAX || code == UMAX)
+                 && ! (cond == EQ || cond == NE))
                cond = reverse_condition (cond);
 
              switch (cond)
@@ -7645,11 +7616,11 @@ make_field_assignment (x)
                                             GET_MODE (src), other, pos),
                       mode,
                       GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
-                      ? ~(HOST_WIDE_INT) 0
+                      ? ~(unsigned HOST_WIDE_INT) 0
                       : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
                       dest, 0);
 
-  return gen_rtx_combine (SET, VOIDmode, assign, src);
+  return gen_rtx_SET (VOIDmode, assign, src);
 }
 \f
 /* See if X is of the form (+ (* a c) (* b c)) and convert to (* (+ a b) c)
@@ -7712,7 +7683,7 @@ apply_distributive_law (x)
 
     case SUBREG:
       /* Non-paradoxical SUBREGs distributes over all operations, provided
-        the inner modes and word numbers are the same, this is an extraction
+        the inner modes and byte offsets are the same, this is an extraction
         of a low-order part, we don't convert an fp operation to int or
         vice versa, and we would not be converting a single-word
         operation into a multi-word operation.  The latter test is not
@@ -7723,7 +7694,7 @@ apply_distributive_law (x)
         We produce the result slightly differently in this case.  */
 
       if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (rhs))
-         || SUBREG_WORD (lhs) != SUBREG_WORD (rhs)
+         || SUBREG_BYTE (lhs) != SUBREG_BYTE (rhs)
          || ! subreg_lowpart_p (lhs)
          || (GET_MODE_CLASS (GET_MODE (lhs))
              != GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
@@ -7766,7 +7737,7 @@ apply_distributive_law (x)
   if (code == XOR && inner_code == IOR)
     {
       inner_code = AND;
-      other = gen_unary (NOT, GET_MODE (x), GET_MODE (x), other);
+      other = simplify_gen_unary (NOT, GET_MODE (x), other, GET_MODE (x));
     }
 
   /* We may be able to continuing distributing the result, so call
@@ -7942,7 +7913,7 @@ nonzero_bits (x, mode)
       /* If pointers extend unsigned and this is a pointer in Pmode, say that
         all the bits above ptr_mode are known to be zero.  */
       if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && REGNO_POINTER_FLAG (REGNO (x)))
+         && REG_POINTER (x))
        nonzero &= GET_MODE_MASK (ptr_mode);
 #endif
 
@@ -8048,10 +8019,12 @@ nonzero_bits (x, mode)
       break;
 
     case EQ:  case NE:
-    case GT:  case GTU:
-    case LT:  case LTU:
-    case GE:  case GEU:
-    case LE:  case LEU:
+    case UNEQ:  case LTGT:
+    case GT:  case GTU:  case UNGT:
+    case LT:  case LTU:  case UNLT:
+    case GE:  case GEU:  case UNGE:
+    case LE:  case LEU:  case UNLE:
+    case UNORDERED: case ORDERED:
 
       /* If this produces an integer result, we know which bits are set.
         Code here used to clear bits outside the mode of X, but that is
@@ -8200,6 +8173,16 @@ nonzero_bits (x, mode)
 
        if (result_low > 0)
          nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+       /* If pointers extend unsigned and this is an addition or subtraction
+          to a pointer in Pmode, all the bits above ptr_mode are known to be
+          zero.  */
+       if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+           && (code == PLUS || code == MINUS)
+           && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
+         nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
       }
       break;
 
@@ -8380,7 +8363,7 @@ num_sign_bit_copies (x, mode)
       /* If pointers extend signed and this is a pointer in Pmode, say that
         all the bits above ptr_mode are known to be sign bit copies.  */
       if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
-         && REGNO_POINTER_FLAG (REGNO (x)))
+         && REG_POINTER (x))
        return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
 #endif
 
@@ -8538,7 +8521,20 @@ num_sign_bit_copies (x, mode)
 
       num0 = num_sign_bit_copies (XEXP (x, 0), mode);
       num1 = num_sign_bit_copies (XEXP (x, 1), mode);
-      return MAX (1, MIN (num0, num1) - 1);
+      result = MAX (1, MIN (num0, num1) - 1);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If pointers extend signed and this is an addition or subtraction
+        to a pointer in Pmode, all the bits above ptr_mode are known to be
+        sign bit copies.  */
+      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && (code == PLUS || code == MINUS)
+         && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
+       result = MAX ((GET_MODE_BITSIZE (Pmode)
+                      - GET_MODE_BITSIZE (ptr_mode) + 1),
+                     result);
+#endif
+      return result;
 
     case MULT:
       /* The number of bits of the product is the sum of the number of
@@ -8625,9 +8621,17 @@ num_sign_bit_copies (x, mode)
       return MIN (num0, num1);
 
     case EQ:  case NE:  case GE:  case GT:  case LE:  case LT:
+    case UNEQ:  case LTGT:  case UNGE:  case UNGT:  case UNLE:  case UNLT:
     case GEU: case GTU: case LEU: case LTU:
-      if (STORE_FLAG_VALUE == -1)
-       return bitwidth;
+    case UNORDERED: case ORDERED:
+      /* If the constant is negative, take its 1's complement and remask.
+        Then see how many zero bits we have.  */
+      nonzero = STORE_FLAG_VALUE;
+      if (bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+       nonzero = (~nonzero) & GET_MODE_MASK (mode);
+
+      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
       break;
 
     default:
@@ -8856,6 +8860,14 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
 
   count = input_count;
 
+  /* Make sure and truncate the "natural" shift on the way in.  We don't
+     want to do this inside the loop as it makes it more difficult to
+     combine shifts.  */
+#ifdef SHIFT_COUNT_TRUNCATED
+  if (SHIFT_COUNT_TRUNCATED)
+    count %= GET_MODE_BITSIZE (mode);
+#endif
+
   /* Unless one of the branches of the `if' in this loop does a `continue',
      we will `break' the loop after the `if'.  */
 
@@ -8972,8 +8984,8 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
                                                  count / BITS_PER_UNIT));
 
              MEM_COPY_ATTRIBUTES (new, varop);
-             varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND
-                                      : ZERO_EXTEND, mode, new);
+             varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
+                                    : ZERO_EXTEND, mode, new);
              count = 0;
              continue;
            }
@@ -8999,8 +9011,8 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
                                        count / BITS_PER_UNIT));
                }
 
-             varop = gen_rtx_combine (code == ASHIFTRT ? SIGN_EXTEND
-                                      : ZERO_EXTEND, mode, new);
+             varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
+                                    : ZERO_EXTEND, mode, new);
              count = 0;
              continue;
            }
@@ -9051,9 +9063,14 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
          break;
 
        case ASHIFTRT:
-         /* If we are extracting just the sign bit of an arithmetic right
-            shift, that shift is not needed.  */
-         if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1)
+         /* If we are extracting just the sign bit of an arithmetic
+            right shift, that shift is not needed.  However, the sign
+            bit of a wider mode may be different from what would be
+            interpreted as the sign bit in a narrower mode, so, if
+            the result is narrower, don't discard the shift.  */
+         if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
+             && (GET_MODE_BITSIZE (result_mode)
+                 >= GET_MODE_BITSIZE (GET_MODE (varop))))
            {
              varop = XEXP (varop, 0);
              continue;
@@ -9216,7 +9233,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
                                                         XEXP (varop, 0),
                                                         GEN_INT (count))))
            {
-             varop = gen_rtx_combine (code, mode, new, XEXP (varop, 1));
+             varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
              count = 0;
              continue;
            }
@@ -9224,8 +9241,8 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
 
        case NOT:
          /* Make this fit the case below.  */
-         varop = gen_rtx_combine (XOR, mode, XEXP (varop, 0),
-                                  GEN_INT (GET_MODE_MASK (mode)));
+         varop = gen_rtx_XOR (mode, XEXP (varop, 0),
+                              GEN_INT (GET_MODE_MASK (mode)));
          continue;
 
        case IOR:
@@ -9246,11 +9263,11 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
-             varop = gen_rtx_combine (LE, GET_MODE (varop), XEXP (varop, 1),
-                                      const0_rtx);
+             varop = gen_rtx_LE (GET_MODE (varop), XEXP (varop, 1),
+                                 const0_rtx);
 
              if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
-               varop = gen_rtx_combine (NEG, GET_MODE (varop), varop);
+               varop = gen_rtx_NEG (GET_MODE (varop), varop);
 
              continue;
            }
@@ -9412,11 +9429,11 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
-             varop = gen_rtx_combine (GT, GET_MODE (varop), XEXP (varop, 1),
-                                      const0_rtx);
+             varop = gen_rtx_GT (GET_MODE (varop), XEXP (varop, 1),
+                                 const0_rtx);
 
              if (STORE_FLAG_VALUE == 1 ? code == ASHIFTRT : code == LSHIFTRT)
-               varop = gen_rtx_combine (NEG, GET_MODE (varop), varop);
+               varop = gen_rtx_NEG (GET_MODE (varop), varop);
 
              continue;
            }
@@ -9435,12 +9452,11 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
              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);
+               = gen_rtx_LSHIFTRT (GET_MODE (varop_inner),
+                                   XEXP (varop_inner, 0),
+                                   GEN_INT
+                                   (count + INTVAL (XEXP (varop_inner, 1))));
+             varop = gen_rtx_TRUNCATE (GET_MODE (varop), varop_inner);
              count = 0;
              continue;
            }
@@ -9495,7 +9511,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
   else
     {
       if (x == 0 || GET_CODE (x) != code || GET_MODE (x) != shift_mode)
-       x = gen_rtx_combine (code, shift_mode, varop, const_rtx);
+       x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
 
       SUBST (XEXP (x, 0), varop);
       SUBST (XEXP (x, 1), const_rtx);
@@ -9523,7 +9539,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
   /* If COMPLEMENT_P is set, we have to complement X before doing the outer
      operation.  */
   if (complement_p)
-    x = gen_unary (NOT, result_mode, result_mode, x);
+    x =simplify_gen_unary (NOT, result_mode, x, result_mode);
 
   if (outer_op != NIL)
     {
@@ -9537,7 +9553,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
           equivalent to a constant.  This should be rare.  */
        x = GEN_INT (outer_const);
       else if (GET_RTX_CLASS (outer_op) == '1')
-       x = gen_unary (outer_op, result_mode, result_mode, x);
+       x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
       else
        x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
     }
@@ -9620,10 +9636,10 @@ recog_for_combine (pnewpat, insn, pnotes)
   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));
+                                    rtvec_alloc (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++)
@@ -9741,100 +9757,29 @@ gen_lowpart_for_combine (mode, x)
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
   else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
-    return gen_rtx_combine (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
+    return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
      SUBREG.  Normally, this SUBREG won't match, but some patterns may
      include an explicit SUBREG or we may simplify it further in combine.  */
   else
     {
-      int word = 0;
+      int offset = 0;
 
-      if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
-       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);
+      if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+         && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
+       {
+         int difference = (GET_MODE_SIZE (GET_MODE (x))
+                           - GET_MODE_SIZE (mode));
+         if (WORDS_BIG_ENDIAN)
+           offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+         if (BYTES_BIG_ENDIAN)
+           offset += difference % UNITS_PER_WORD;
+       }
+      return gen_rtx_SUBREG (mode, x, offset);
     }
 }
 \f
-/* Make an rtx expression.  This is a subset of gen_rtx and only supports
-   expressions of 1, 2, or 3 operands, each of which are rtx expressions.
-
-   If the identical expression was previously in the insn (in the undobuf),
-   it will be returned.  Only if it is not found will a new expression
-   be made.  */
-
-/*VARARGS2*/
-static rtx
-gen_rtx_combine VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  enum rtx_code code;
-  enum machine_mode mode;
-#endif
-  va_list p;
-  int n_args;
-  rtx args[3];
-  int j;
-  const char *fmt;
-  rtx rt;
-  struct undo *undo;
-
-  VA_START (p, mode);
-
-#ifndef ANSI_PROTOTYPES
-  code = va_arg (p, enum rtx_code);
-  mode = va_arg (p, enum machine_mode);
-#endif
-
-  n_args = GET_RTX_LENGTH (code);
-  fmt = GET_RTX_FORMAT (code);
-
-  if (n_args == 0 || n_args > 3)
-    abort ();
-
-  /* Get each arg and verify that it is supposed to be an expression.  */
-  for (j = 0; j < n_args; j++)
-    {
-      if (*fmt++ != 'e')
-       abort ();
-
-      args[j] = va_arg (p, rtx);
-    }
-
-  va_end (p);
-
-  /* See if this is in undobuf.  Be sure we don't use objects that came
-     from another insn; this could produce circular rtl structures.  */
-
-  for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next)
-    if (!undo->is_int
-       && GET_CODE (undo->old_contents.r) == code
-       && GET_MODE (undo->old_contents.r) == mode)
-      {
-       for (j = 0; j < n_args; j++)
-         if (XEXP (undo->old_contents.r, j) != args[j])
-           break;
-
-       if (j == n_args)
-         return undo->old_contents.r;
-      }
-
-  /* Otherwise make a new rtx.  We know we have 1, 2, or 3 args.
-     Use rtx_alloc instead of gen_rtx because it's faster on RISC.  */
-  rt = rtx_alloc (code);
-  PUT_MODE (rt, mode);
-  XEXP (rt, 0) = args[0];
-  if (n_args > 1)
-    {
-      XEXP (rt, 1) = args[1];
-      if (n_args > 2)
-       XEXP (rt, 2) = args[2];
-    }
-  return rt;
-}
-
 /* These routines make binary and unary operations by first seeing if they
    fold; if not, a new expression is allocated.  */
 
@@ -9848,8 +9793,7 @@ gen_binary (code, mode, op0, op1)
   rtx tem;
 
   if (GET_RTX_CLASS (code) == 'c'
-      && (GET_CODE (op0) == CONST_INT
-         || (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
+      && swap_commutative_operands_p (op0, op1))
     tem = op0, op0 = op1, op1 = tem;
 
   if (GET_RTX_CLASS (code) == '<')
@@ -9877,13 +9821,8 @@ gen_binary (code, mode, op0, op1)
 
   /* Put complex operands first and constants second.  */
   if (GET_RTX_CLASS (code) == 'c'
-      && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
-         || (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
-             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')
-         || (GET_CODE (op0) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
-    return gen_rtx_combine (code, mode, op1, op0);
+      && swap_commutative_operands_p (op0, op1))
+    return gen_rtx_fmt_ee (code, mode, op1, op0);
 
   /* If we are turning off bits already known off in OP0, we need not do
      an AND.  */
@@ -9892,21 +9831,7 @@ gen_binary (code, mode, op0, op1)
           && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
     return op0;
 
-  return gen_rtx_combine (code, mode, op0, op1);
-}
-
-static rtx
-gen_unary (code, mode, op0_mode, op0)
-     enum rtx_code code;
-     enum machine_mode mode, op0_mode;
-     rtx op0;
-{
-  rtx result = simplify_unary_operation (code, mode, op0, op0_mode);
-
-  if (result)
-    return result;
-
-  return gen_rtx_combine (code, mode, op0);
+  return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
 \f
 /* Simplify a comparison between *POP0 and *POP1 where CODE is the
@@ -9974,7 +9899,7 @@ simplify_comparison (code, pop0, pop1)
                  && (code != GT && code != LT && code != GE && code != LE))
              || (GET_CODE (op0) == ASHIFTRT
                  && (code != GTU && code != LTU
-                     && code != GEU && code != GEU)))
+                     && code != GEU && code != LEU)))
          && GET_CODE (XEXP (op0, 1)) == CONST_INT
          && INTVAL (XEXP (op0, 1)) >= 0
          && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
@@ -10073,7 +9998,7 @@ simplify_comparison (code, pop0, pop1)
   /* If the first operand is a constant, swap the operands and adjust the
      comparison code appropriately, but don't do this if the second operand
      is already a constant integer.  */
-  if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
+  if (swap_commutative_operands_p (op0, op1))
     {
       tem = op0, op0 = op1, op1 = tem;
       code = swap_condition (code);
@@ -10108,6 +10033,7 @@ simplify_comparison (code, pop0, pop1)
       /* Get the constant we are comparing against and turn off all bits
         not on in our mode.  */
       const_op = trunc_int_for_mode (INTVAL (op1), mode);
+      op1 = GEN_INT (const_op);
 
       /* If we are comparing against a constant power of two and the value
         being compared can only have that single bit nonzero (e.g., it was
@@ -10584,8 +10510,10 @@ simplify_comparison (code, pop0, pop1)
          break;
 
        case EQ:  case NE:
-       case LT:  case LTU:  case LE:  case LEU:
-       case GT:  case GTU:  case GE:  case GEU:
+       case UNEQ:  case LTGT:
+       case LT:  case LTU:  case UNLT:  case LE:  case LEU:  case UNLE:
+       case GT:  case GTU:  case UNGT:  case GE:  case GEU:  case UNGE:
+        case UNORDERED: case ORDERED:
          /* We can't do anything if OP0 is a condition code value, rather
             than an actual data value.  */
          if (const_op != 0
@@ -10603,20 +10531,27 @@ simplify_comparison (code, pop0, pop1)
 
          /* Check for the cases where we simply want the result of the
             earlier test or the opposite of that result.  */
-         if (code == NE
-             || (code == EQ && reversible_comparison_p (op0))
+         if (code == NE || code == EQ
              || (GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
                  && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
                  && (STORE_FLAG_VALUE
                      & (((HOST_WIDE_INT) 1
                          << (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
-                 && (code == LT
-                     || (code == GE && reversible_comparison_p (op0)))))
+                 && (code == LT || code == GE)))
            {
-             code = (code == LT || code == NE
-                     ? GET_CODE (op0) : reverse_condition (GET_CODE (op0)));
-             op0 = tem, op1 = tem1;
-             continue;
+             enum rtx_code new_code;
+             if (code == LT || code == NE)
+               new_code = GET_CODE (op0);
+             else
+               new_code = combine_reversed_comparison_code (op0);
+         
+             if (new_code != UNKNOWN)
+               {
+                 code = new_code;
+                 op0 = tem;
+                 op1 = tem1;
+                 continue;
+               }
            }
          break;
 
@@ -10641,9 +10576,9 @@ simplify_comparison (code, pop0, pop1)
              && XEXP (XEXP (op0, 0), 0) == const1_rtx)
            {
              op0 = simplify_and_const_int
-               (op0, mode, gen_rtx_combine (LSHIFTRT, mode,
-                                            XEXP (op0, 1),
-                                            XEXP (XEXP (op0, 0), 1)),
+               (op0, mode, gen_rtx_LSHIFTRT (mode,
+                                             XEXP (op0, 1),
+                                             XEXP (XEXP (op0, 0), 1)),
                 (HOST_WIDE_INT) 1);
              continue;
            }
@@ -10748,6 +10683,21 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
+         /* Convert (ne (and (lshiftrt (not X)) 1) 0) to
+            (eq (and (lshiftrt X) 1) 0).  */
+         if (const_op == 0 && equality_comparison_p
+             && XEXP (op0, 1) == const1_rtx
+             && GET_CODE (XEXP (op0, 0)) == LSHIFTRT
+             && GET_CODE (XEXP (XEXP (op0, 0), 0)) == NOT)
+           {
+             op0 = simplify_and_const_int
+               (op0, mode,
+                gen_rtx_LSHIFTRT (mode, XEXP (XEXP (XEXP (op0, 0), 0), 0),
+                                  XEXP (XEXP (op0, 0), 1)),
+                (HOST_WIDE_INT) 1);
+             code = (code == NE ? EQ : NE);
+             continue;
+           }
          break;
 
        case ASHIFT:
@@ -11004,42 +10954,38 @@ simplify_comparison (code, pop0, pop1)
   return code;
 }
 \f
-/* Return 1 if we know that X, a comparison operation, is not operating
-   on a floating-point value or is EQ or NE, meaning that we can safely
-   reverse it.  */
-
-static int
-reversible_comparison_p (x)
-     rtx x;
+/* Like jump.c' reversed_comparison_code, but use combine infrastructure for
+   searching backward.  */
+static enum rtx_code
+combine_reversed_comparison_code (exp)
+     rtx exp;
 {
-  if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-      || flag_fast_math
-      || GET_CODE (x) == NE || GET_CODE (x) == EQ
-      || GET_CODE (x) == UNORDERED || GET_CODE (x) == ORDERED)
-    return 1;
-
-  switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
-    {
-    case MODE_INT:
-    case MODE_PARTIAL_INT:
-    case MODE_COMPLEX_INT:
-      return 1;
-
-    case MODE_CC:
-      /* If the mode of the condition codes tells us that this is safe,
-        we need look no further.  */
-      if (REVERSIBLE_CC_MODE (GET_MODE (XEXP (x, 0))))
-       return 1;
-
-      /* Otherwise try and find where the condition codes were last set and
-        use that.  */
-      x = get_last_value (XEXP (x, 0));
-      return (x && GET_CODE (x) == COMPARE
-             && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
-
-    default:
-      return 0;
-    }
+   enum rtx_code code1 = reversed_comparison_code (exp, NULL);
+   rtx x;
+
+   if (code1 != UNKNOWN
+       || GET_MODE_CLASS (GET_MODE (XEXP (exp, 0))) != MODE_CC)
+     return code1;
+   /* Otherwise try and find where the condition codes were last set and
+      use that.  */
+   x = get_last_value (XEXP (exp, 0));
+   if (!x || GET_CODE (x) != COMPARE)
+     return UNKNOWN;
+   return reversed_comparison_code_parts (GET_CODE (exp),
+                                         XEXP (x, 0), XEXP (x, 1), NULL);
+}
+/* Return comparison with reversed code of EXP and operands OP0 and OP1.
+   Return NULL_RTX in case we fail to do the reversal.  */
+static rtx
+reversed_comparison (exp, mode, op0, op1)
+     rtx exp, op0, op1;
+     enum machine_mode mode;
+{
+  enum rtx_code reversed_code = combine_reversed_comparison_code (exp);
+  if (reversed_code == UNKNOWN)
+    return NULL_RTX;
+  else
+    return gen_binary (reversed_code, mode, op0, op1);
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
@@ -11893,6 +11839,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
         that accesses one word of a multi-word item, some
         piece of everything register in the expression is used by
         this insn, so remove any old death.  */
+      /* ??? So why do we test for equality of the sizes?  */
 
       if (GET_CODE (dest) == ZERO_EXTRACT
          || GET_CODE (dest) == STRICT_LOW_PART
@@ -12030,8 +11977,37 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
          place = i3;
          break;
 
+       case REG_NON_LOCAL_GOTO:
+         if (GET_CODE (i3) == JUMP_INSN)
+           place = i3;
+         else if (i2 && GET_CODE (i2) == JUMP_INSN)
+           place = i2;
+         else
+           abort();
+         break;
+
        case REG_EH_REGION:
+         /* These notes must remain with the call or trapping instruction.  */
+         if (GET_CODE (i3) == CALL_INSN)
+           place = i3;
+         else if (i2 && GET_CODE (i2) == CALL_INSN)
+           place = i2;
+         else if (flag_non_call_exceptions)
+           {
+             if (may_trap_p (i3))
+               place = i3;
+             else if (i2 && may_trap_p (i2))
+               place = i2;
+             /* ??? Otherwise assume we've combined things such that we
+                can now prove that the instructions can't trap.  Drop the
+                note in this case.  */
+           }
+         else
+           abort ();
+         break;
+
        case REG_EH_RETHROW:
+       case REG_NORETURN:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
          if (GET_CODE (i3) == CALL_INSN)
@@ -12163,6 +12139,10 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
              place = prev_real_insn (from_insn);
              if (tem && place)
                XEXP (tem, 0) = place;
+             /* If we're deleting the last remaining instruction of a
+                libcall sequence, don't add the notes.  */
+             else if (XEXP (note, 0) == from_insn)
+               tem = place = 0;
            }
          break;
 
@@ -12176,6 +12156,10 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
              place = next_real_insn (from_insn);
              if (tem && place)
                XEXP (tem, 0) = place;
+             /* If we're deleting the last remaining instruction of a
+                libcall sequence, don't add the notes.  */
+             else if (XEXP (note, 0) == from_insn)
+               tem = place = 0;
            }
          break;
 
@@ -12204,7 +12188,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                   && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
            place = i2;
 
-         if (XEXP (note, 0) == elim_i2 || XEXP (note, 0) == elim_i1)
+         if (rtx_equal_p (XEXP (note, 0), elim_i2)
+             || rtx_equal_p (XEXP (note, 0), elim_i1))
            break;
 
          if (place == 0)
@@ -12213,7 +12198,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
 
              for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
                {
-                 if (GET_RTX_CLASS (GET_CODE (tem)) != 'i')
+                 if (! INSN_P (tem))
                    {
                      if (tem == bb->head)
                        break;
@@ -12384,13 +12369,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
              /* If this is a death note for a hard reg that is occupying
                 multiple registers, ensure that we are still using all
                 parts of the object.  If we find a piece of the object
-                that is unused, we must add a USE for that piece before
-                PLACE and put the appropriate REG_DEAD note on it.
-
-                An alternative would be to put a REG_UNUSED for the pieces
-                on the insn that set the register, but that can't be done if
-                it is not in the same block.  It is simpler, though less
-                efficient, to add the USE insns.  */
+                that is unused, we must arrange for an appropriate REG_DEAD
+                note to be added for it.  However, we can't just emit a USE
+                and tag the note to it, since the register might actually
+                be dead; so we recourse, and the recursive call then finds
+                the previous insn that used this register.  */
 
              if (place && regno < FIRST_PSEUDO_REGISTER
                  && HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0))) > 1)
@@ -12402,67 +12385,60 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                  unsigned int i;
 
                  for (i = regno; i < endregno; i++)
-                   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 p;
-
-                       /* See if we already placed a USE note for this
-                          register in front of PLACE.  */
-                       for (p = place;
-                            GET_CODE (PREV_INSN (p)) == INSN
-                            && GET_CODE (PATTERN (PREV_INSN (p))) == USE;
-                            p = PREV_INSN (p))
-                         if (rtx_equal_p (piece,
-                                          XEXP (PATTERN (PREV_INSN (p)), 0)))
-                           {
-                             p = 0;
-                             break;
-                           }
-
-                       if (p)
-                         {
-                           rtx use_insn
-                             = emit_insn_before (gen_rtx_USE (VOIDmode,
-                                                              piece),
-                                                 p);
-                           REG_NOTES (use_insn)
-                             = gen_rtx_EXPR_LIST (REG_DEAD, piece,
-                                                  REG_NOTES (use_insn));
-                         }
-
-                       all_used = 0;
-                     }
-
-                 /* Check for the case where the register dying partially
-                    overlaps the register set by this insn.  */
-                 if (all_used)
-                   for (i = regno; i < endregno; i++)
-                     if (dead_or_set_regno_p (place, i))
-                       {
-                         all_used = 0;
-                         break;
-                       }
+                   if ((! refers_to_regno_p (i, i + 1, PATTERN (place), 0)
+                        && ! find_regno_fusage (place, USE, i))
+                       || dead_or_set_regno_p (place, i))
+                     all_used = 0;
 
                  if (! all_used)
                    {
                      /* Put only REG_DEAD notes for pieces that are
-                        still used and that are not already dead or set.  */
+                        not already dead or set.  */
 
-                     for (i = regno; i < endregno; i++)
+                     for (i = regno; i < endregno;
+                          i += HARD_REGNO_NREGS (i, reg_raw_mode[i]))
                        {
                          rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
+                         basic_block bb = BASIC_BLOCK (this_basic_block);
 
-                         if ((reg_referenced_p (piece, PATTERN (place))
-                              || (GET_CODE (place) == CALL_INSN
-                                  && find_reg_fusage (place, USE, piece)))
-                             && ! dead_or_set_p (place, piece)
+                         if (! 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));
+                           {
+                             rtx new_note
+                               = gen_rtx_EXPR_LIST (REG_DEAD, piece, NULL_RTX);
+
+                             distribute_notes (new_note, place, place,
+                                               NULL_RTX, NULL_RTX, NULL_RTX);
+                           }
+                         else if (! refers_to_regno_p (i, i + 1,
+                                                       PATTERN (place), 0)
+                                  && ! find_regno_fusage (place, USE, i))
+                           for (tem = PREV_INSN (place); ;
+                                tem = PREV_INSN (tem))
+                             {
+                               if (! INSN_P (tem))
+                                 {
+                                   if (tem == bb->head)
+                                     {
+                                       SET_BIT (refresh_blocks,
+                                                this_basic_block);
+                                       need_refresh = 1;
+                                       break;
+                                     }
+                                   continue;
+                                 }
+                               if (dead_or_set_p (tem, piece)
+                                   || reg_bitfield_target_p (piece,
+                                                             PATTERN (tem)))
+                                 {
+                                   REG_NOTES (tem)
+                                     = gen_rtx_EXPR_LIST (REG_UNUSED, piece,
+                                                          REG_NOTES (tem));
+                                   break;
+                                 }
+                             }
+
                        }
 
                      place = 0;
@@ -12554,8 +12530,7 @@ distribute_links (links)
           (insn && (this_basic_block == n_basic_blocks - 1
                     || BLOCK_HEAD (this_basic_block + 1) != insn));
           insn = NEXT_INSN (insn))
-       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-           && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+       if (INSN_P (insn) && reg_overlap_mentioned_p (reg, PATTERN (insn)))
          {
            if (reg_referenced_p (reg, PATTERN (insn)))
              place = insn;