OSDN Git Service

(PREDICATE_CODES): Add reversible_cc_register.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 8c27d89..dd78ed3 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -74,7 +74,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    combine anyway.  */
 
 #include "config.h"
-#include "gvarargs.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
 
 /* Must precede rtl.h for FFS.  */
 #include <stdio.h>
@@ -115,6 +119,13 @@ static int combine_successes;
 /* Totals over entire compilation.  */
 
 static int total_attempts, total_merges, total_extras, total_successes;
+
+/* Define a defulat 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.
@@ -173,6 +184,17 @@ static rtx subst_prev_insn;
 
 static int subst_low_cuid;
 
+/* This contains any hard registers that are used in newpat; reg_dead_at_p
+   must consider all these registers to be always live.  */
+
+static HARD_REG_SET newpat_used_regs;
+
+/* This is an insn to which a LOG_LINKS entry has been added.  If this
+   insn is the earlier than I2 or I3, combine should rescan starting at
+   that location.  */
+
+static rtx added_links_insn;
+
 /* This is the value of undobuf.num_undo 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
@@ -369,14 +391,20 @@ static rtx try_combine            PROTO((rtx, rtx, rtx));
 static void undo_all           PROTO((void));
 static rtx *find_split_point   PROTO((rtx *, rtx));
 static rtx subst               PROTO((rtx, rtx, rtx, int, int));
+static rtx simplify_rtx                PROTO((rtx, enum machine_mode, int, int));
+static rtx simplify_if_then_else  PROTO((rtx));
+static rtx simplify_set                PROTO((rtx));
+static rtx simplify_logical    PROTO((rtx, int));
 static rtx expand_compound_operation  PROTO((rtx));
 static rtx expand_field_assignment  PROTO((rtx));
 static rtx make_extraction     PROTO((enum machine_mode, rtx, int, rtx, int,
                                       int, int, int));
+static rtx extract_left_shift  PROTO((rtx, int));
 static rtx make_compound_operation  PROTO((rtx, enum rtx_code));
 static int get_pos_from_mask   PROTO((unsigned HOST_WIDE_INT, int *));
 static rtx force_to_mode       PROTO((rtx, enum machine_mode,
-                                      unsigned HOST_WIDE_INT, rtx));
+                                      unsigned HOST_WIDE_INT, rtx, int));
+static rtx if_then_else_cond   PROTO((rtx, rtx *, rtx *));
 static rtx known_cond          PROTO((rtx, enum rtx_code, rtx, rtx));
 static rtx make_field_assignment  PROTO((rtx));
 static rtx apply_distributive_law  PROTO((rtx));
@@ -391,10 +419,12 @@ static rtx simplify_shift_const   PROTO((rtx, enum rtx_code, enum machine_mode,
                                       rtx, int));
 static int recog_for_combine   PROTO((rtx *, rtx, rtx *));
 static rtx gen_lowpart_for_combine  PROTO((enum machine_mode, rtx));
-static rtx gen_rtx_combine ();  /* This is varargs.  */
+static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
+                                 ...));
 static rtx gen_binary          PROTO((enum rtx_code, enum machine_mode,
                                       rtx, rtx));
-static rtx gen_unary           PROTO((enum rtx_code, enum machine_mode, rtx));
+static rtx gen_unary           PROTO((enum rtx_code, enum machine_mode,
+                                      enum machine_mode, rtx));
 static enum rtx_code simplify_comparison  PROTO((enum rtx_code, rtx *, rtx *));
 static int reversible_comparison_p  PROTO((rtx));
 static void update_table_tick  PROTO((rtx));
@@ -410,6 +440,7 @@ static void move_deaths             PROTO((rtx, int, rtx, rtx *));
 static int reg_bitfield_target_p  PROTO((rtx, rtx));
 static void distribute_notes   PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
 static void distribute_links   PROTO((rtx));
+static void mark_used_regs_combine PROTO((rtx));
 \f
 /* Main entry point for combiner.  F is the first insn of the function.
    NREGS is the first unused pseudo-reg number.  */
@@ -435,7 +466,7 @@ combine_instructions (f, nregs)
     = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
   reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char));
 
-  bzero (reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
+  bzero ((char *) reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
   bzero (reg_sign_bit_copies, nregs * sizeof (char));
 
   reg_last_death = (rtx *) alloca (nregs * sizeof (rtx));
@@ -628,14 +659,14 @@ init_reg_last_arrays ()
 {
   int nregs = combine_max_regno;
 
-  bzero (reg_last_death, nregs * sizeof (rtx));
-  bzero (reg_last_set, nregs * sizeof (rtx));
-  bzero (reg_last_set_value, nregs * sizeof (rtx));
-  bzero (reg_last_set_table_tick, nregs * sizeof (int));
-  bzero (reg_last_set_label, nregs * sizeof (int));
+  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 (reg_last_set_mode, nregs * sizeof (enum machine_mode));
-  bzero (reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
+  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));
 }
 \f
@@ -848,6 +879,8 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
       || (rtx_equal_p (src, dest) && find_reg_note (insn, REG_EQUAL, NULL_RTX))
       /* Can't merge a function call.  */
       || GET_CODE (src) == CALL
+      /* Don't eliminate a function call argument.  */
+      || (GET_CODE (i3) == CALL_INSN && find_reg_fusage (i3, USE, dest))
       /* Don't substitute into an incremented register.  */
       || FIND_REG_INC_NOTE (i3, dest)
       || (succ && FIND_REG_INC_NOTE (succ, dest))
@@ -898,14 +931,16 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
       if (GET_CODE (src) == REG
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
               && ! HARD_REGNO_MODE_OK (REGNO (dest), GET_MODE (dest)))
-#ifdef SMALL_REGISTER_CLASSES
-             /* Don't extend the life of a hard register.  */
-             || REGNO (src) < FIRST_PSEUDO_REGISTER
-#else
+             /* Don't extend the life of a hard register unless it is
+                user variable (if we have few registers) or it can't
+                fit into the desired register (meaning something special
+                is going on).  */
              || (REGNO (src) < FIRST_PSEUDO_REGISTER
-                 && ! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src)))
+                 && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
+#ifdef SMALL_REGISTER_CLASSES
+                     || ! REG_USERVAR_P (src)
 #endif
-         ))
+                     ))))
        return 0;
     }
   else if (GET_CODE (dest) != CC0)
@@ -1009,7 +1044,8 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
    of a SET must prevent combination from occurring.
 
    On machines where SMALL_REGISTER_CLASSES is defined, we don't combine
-   if the destination of a SET is a hard register.
+   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.
@@ -1079,14 +1115,12 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
             CALL operation.  */
          || (GET_CODE (inner_dest) == REG
              && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+             && (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
+                                       GET_MODE (inner_dest))
 #ifdef SMALL_REGISTER_CLASSES
-             && GET_CODE (src) != CALL
-#else
-             && ! HARD_REGNO_MODE_OK (REGNO (inner_dest),
-                                      GET_MODE (inner_dest))
+                || (GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest))
 #endif
-             )
-
+                 ))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
        return 0;
 
@@ -1136,8 +1170,9 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
    and I1 is pseudo-deleted by turning it into a NOTE.  Otherwise, I1 and I2
    are pseudo-deleted.
 
-   If we created two insns, return I2; otherwise return I3.
-   Return 0 if the combination does not work.  Then nothing is changed.  */
+   Return 0 if the combination does not work.  Then nothing is changed. 
+   If we did the combination, return the insn at which combine should
+   resume scanning.  */
 
 static rtx
 try_combine (i3, i2, i1)
@@ -1195,12 +1230,16 @@ try_combine (i3, i2, i1)
      accept this combination.  */
   undobuf.storage = (char *) oballoc (0);
 
+  /* Reset the hard register usage information.  */
+  CLEAR_HARD_REG_SET (newpat_used_regs);
+
   /* If I1 and I2 both feed I3, they can be in any order.  To simplify the
      code below, set I1 to be the earlier of the two insns.  */
   if (i1 && INSN_CUID (i1) > INSN_CUID (i2))
     temp = i1, i1 = i2, i2 = temp;
 
   subst_prev_insn = 0;
+  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,
@@ -1220,7 +1259,8 @@ try_combine (i3, i2, i1)
       && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
 #ifdef SMALL_REGISTER_CLASSES
       && (GET_CODE (SET_DEST (PATTERN (i3))) != REG
-         || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER)
+         || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
+         || REG_USERVAR_P (SET_DEST (PATTERN (i3))))
 #endif
       && find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
       && GET_CODE (PATTERN (i2)) == PARALLEL
@@ -1581,7 +1621,7 @@ try_combine (i3, i2, i1)
          rtvec old = XVEC (newpat, 0);
          total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
          newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
-         bcopy (&old->elem[0], &XVECEXP (newpat, 0, 0),
+         bcopy ((char *) &old->elem[0], (char *) &XVECEXP (newpat, 0, 0),
                 sizeof (old->elem[0]) * old->num_elem);
        }
       else
@@ -1615,6 +1655,9 @@ try_combine (i3, i2, i1)
      destination of I3.  */
  validate_replacement:
 
+  /* Note which hard regs this insn has as inputs.  */
+  mark_used_regs_combine (newpat);
+
   /* Is the result of combination a valid instruction?  */
   insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
@@ -1653,32 +1696,6 @@ try_combine (i3, i2, i1)
       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
     }
 
-  /* See if this is an XOR.  If so, perhaps the problem is that the
-     constant is out of range.  Replace it with a complemented XOR with
-     a complemented constant; it might be in range.  */
-
-  else if (insn_code_number < 0 && GET_CODE (newpat) == SET
-          && GET_CODE (SET_SRC (newpat)) == XOR
-          && GET_CODE (XEXP (SET_SRC (newpat), 1)) == CONST_INT
-          && ((temp = simplify_unary_operation (NOT,
-                                                GET_MODE (SET_SRC (newpat)),
-                                                XEXP (SET_SRC (newpat), 1),
-                                                GET_MODE (SET_SRC (newpat))))
-              != 0))
-    {
-      enum machine_mode i_mode = GET_MODE (SET_SRC (newpat));
-      rtx pat
-       = gen_rtx_combine (SET, VOIDmode, SET_DEST (newpat),
-                          gen_unary (NOT, i_mode,
-                                     gen_binary (XOR, i_mode,
-                                                 XEXP (SET_SRC (newpat), 0),
-                                                 temp)));
-
-      insn_code_number = recog_for_combine (&pat, i3, &new_i3_notes);
-      if (insn_code_number >= 0)
-       newpat = pat;
-    }
-                                                       
   /* If we were combining three insns and the result is a simple SET
      with no ASM_OPERANDS that wasn't recognized, try to split it into two
      insns.  There are two ways to do this.  It can be split using a 
@@ -1969,11 +1986,12 @@ try_combine (i3, i2, i1)
   /* If we had to change another insn, make sure it is valid also.  */
   if (undobuf.other_insn)
     {
-      rtx other_notes = REG_NOTES (undobuf.other_insn);
       rtx other_pat = PATTERN (undobuf.other_insn);
       rtx new_other_notes;
       rtx note, next;
 
+      CLEAR_HARD_REG_SET (newpat_used_regs);
+
       other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
                                             &new_other_notes);
 
@@ -2017,8 +2035,6 @@ try_combine (i3, i2, i1)
     rtx i3notes, i2notes, i1notes = 0;
     rtx i3links, i2links, i1links = 0;
     rtx midnotes = 0;
-    int all_adjacent = (next_real_insn (i2) == i3
-                       && (i1 == 0 || next_real_insn (i1) == i2));
     register int regno;
     /* Compute which registers we expect to eliminate.  */
     rtx elim_i2 = (newi2pat || i2dest_in_i2src || i2dest_in_i1src
@@ -2238,7 +2254,7 @@ try_combine (i3, i2, i1)
 
        /* If the reg formerly set in I2 died only once and that was in I3,
           zero its use count so it won't make `reload' do any work.  */
-       if (! added_sets_2 && newi2pat == 0)
+       if (! added_sets_2 && newi2pat == 0 && ! i2dest_in_i2src)
          {
            regno = REGNO (i2dest);
            reg_n_sets[regno]--;
@@ -2262,7 +2278,7 @@ try_combine (i3, i2, i1)
        record_value_for_reg (i1dest, i1_insn, i1_val);
 
        regno = REGNO (i1dest);
-       if (! added_sets_1)
+       if (! added_sets_1 && ! i1dest_in_i1src)
          {
            reg_n_sets[regno]--;
            if (reg_n_sets[regno] == 0
@@ -2291,7 +2307,12 @@ try_combine (i3, i2, i1)
 
   combine_successes++;
 
-  return newi2pat ? i2 : i3;
+  if (added_links_insn
+      && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
+      && INSN_CUID (added_links_insn) < INSN_CUID (i3))
+    return added_links_insn;
+  else
+    return newi2pat ? i2 : i3;
 }
 \f
 /* Undo all the modifications recorded in undobuf.  */
@@ -2699,28 +2720,11 @@ subst (x, from, to, in_dest, unique_copy)
      int in_dest;
      int unique_copy;
 {
+  register enum rtx_code code = GET_CODE (x);
+  enum machine_mode op0_mode = VOIDmode;
   register char *fmt;
   register int len, i;
-  register enum rtx_code code = GET_CODE (x), orig_code = code;
-  rtx temp;
-  enum machine_mode mode = GET_MODE (x);
-  enum machine_mode op0_mode = VOIDmode;
-  rtx other_insn;
-  rtx *cc_use;
-  int n_restarts = 0;
-
-/* FAKE_EXTEND_SAFE_P (MODE, FROM) is 1 if (subreg:MODE FROM 0) is a safe
-   replacement for (zero_extend:MODE FROM) or (sign_extend:MODE FROM).
-   If it is 0, that cannot be done.  We can now do this for any MEM
-   because (SUBREG (MEM...)) is guaranteed to cause the MEM to be reloaded.
-   If not for that, MEM's would very rarely be safe.  */
-
-/* Reject MODEs bigger than a word, because we might not be able
-   to reference a two-register group starting with an arbitrary register
-   (and currently gen_lowpart might crash for a SUBREG).  */
-
-#define FAKE_EXTEND_SAFE_P(MODE, FROM) \
-  (GET_MODE_SIZE (MODE) <= UNITS_PER_WORD)
+  rtx new;
 
 /* Two expressions are equal if they are identical copies of a shared
    RTX or if they are both registers with the same register number
@@ -2786,7 +2790,6 @@ subst (x, from, to, in_dest, unique_copy)
          register int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            {
-             register rtx new;
              if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
                {
                  new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
@@ -2806,8 +2809,6 @@ subst (x, from, to, in_dest, unique_copy)
        }
       else if (fmt[i] == 'e')
        {
-         register rtx new;
-
          if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
            {
              /* In general, don't install a subreg involving two modes not
@@ -2824,7 +2825,8 @@ subst (x, from, to, in_dest, unique_copy)
                  && ! MODES_TIEABLE_P (GET_MODE (to),
                                        GET_MODE (SUBREG_REG (to)))
                  && ! (code == SUBREG
-                       && MODES_TIEABLE_P (mode, GET_MODE (SUBREG_REG (to))))
+                       && MODES_TIEABLE_P (GET_MODE (x),
+                                           GET_MODE (SUBREG_REG (to))))
 #ifdef HAVE_cc0
                  && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
 #endif
@@ -2863,25 +2865,49 @@ subst (x, from, to, in_dest, unique_copy)
        }
     }
 
-  /* We come back to here if we have replaced the expression with one of
-     a different code and it is likely that further simplification will be
-     possible.  */
+  /* Try to simplify X.  If the simplification changed the code, it is likely
+     that further simplification will help, so loop, but limit the number
+     of repetitions that will be performed.  */
 
- restart:
+  for (i = 0; i < 4; i++)
+    {
+      /* If X is sufficiently simple, don't bother trying to do anything
+        with it.  */
+      if (code != CONST_INT && code != REG && code != CLOBBER)
+       x = simplify_rtx (x, op0_mode, i == 3, in_dest);
 
-  /* If we have restarted more than 4 times, we are probably looping, so
-     give up.  */
-  if (++n_restarts > 4)
-    return x;
+      if (GET_CODE (x) == code)
+       break;
 
-  /* If we are restarting at all, it means that we no longer know the
-     original mode of operand 0 (since we have probably changed the
-     form of X).  */
+      code = GET_CODE (x);
 
-  if (n_restarts > 1)
-    op0_mode = VOIDmode;
+      /* We no longer know the original mode of operand 0 since we
+        have changed the form of X)  */
+      op0_mode = VOIDmode;
+    }
 
-  code = GET_CODE (x);
+  return x;
+}
+\f
+/* Simplify X, a piece of RTL.  We just operate on the expression at the
+   outer level; call `subst' to simplify recursively.  Return the new
+   expression.
+
+   OP0_MODE is the original mode of XEXP (x, 0); LAST is nonzero if this
+   will be the iteration even if an expression with a code different from
+   X is returned; IN_DEST is nonzero if we are inside a SET_DEST.  */
+
+static rtx
+simplify_rtx (x, op0_mode, last, in_dest)
+     rtx x;
+     enum machine_mode op0_mode;
+     int last;
+     int in_dest;
+{
+  enum rtx_code code = GET_CODE (x);
+  enum machine_mode mode = GET_MODE (x);
+  rtx temp;
+  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.  */
@@ -2941,55 +2967,71 @@ subst (x, from, to, in_dest, unique_copy)
 
   /* If this is a simple operation applied to an IF_THEN_ELSE, try 
      applying it to the arms of the IF_THEN_ELSE.  This often simplifies
-     things.  Don't deal with operations that change modes here.  */
-
-  if ((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
-      && GET_CODE (XEXP (x, 0)) == IF_THEN_ELSE)
+     things.  Check for cases where both arms are testing the same
+     condition.
+
+     Don't do anything if all operands are very simple.  */
+
+  if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c'
+       || GET_RTX_CLASS (code) == '<')
+       && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != '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'
+              && ! (GET_CODE (XEXP (x, 1)) == SUBREG
+                    && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 1))))
+                        == 'o')))))
+      || (GET_RTX_CLASS (code) == '1'
+         && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
+              && ! (GET_CODE (XEXP (x, 0)) == SUBREG
+                    && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0))))
+                        == 'o'))))))
     {
-      /* Don't do this by using SUBST inside X since we might be messing
-        up a shared expression.  */
-      rtx cond = XEXP (XEXP (x, 0), 0);
-      rtx t_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 1),
-                                    XEXP (x, 1)),
-                        pc_rtx, pc_rtx, 0, 0);
-      rtx f_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 2),
-                                    XEXP (x, 1)),
-                        pc_rtx, pc_rtx, 0, 0);
-
-
-      x = gen_rtx (IF_THEN_ELSE, mode, cond, t_arm, f_arm);
-      goto restart;
-    }
-
-  else if ((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
-          && GET_CODE (XEXP (x, 1)) == IF_THEN_ELSE)
-    {
-      /* Don't do this by using SUBST inside X since we might be messing
-        up a shared expression.  */
-      rtx cond = XEXP (XEXP (x, 1), 0);
-      rtx t_arm = subst (gen_binary (code, mode, XEXP (x, 0),
-                                    XEXP (XEXP (x, 1), 1)),
-                        pc_rtx, pc_rtx, 0, 0);
-      rtx f_arm = subst (gen_binary (code, mode, XEXP (x, 0),
-                                    XEXP (XEXP (x, 1), 2)),
-                        pc_rtx, pc_rtx, 0, 0);
-
-      x = gen_rtx (IF_THEN_ELSE, mode, cond, t_arm, f_arm);
-      goto restart;
-    }
+      rtx cond, true, false;
+
+      cond = if_then_else_cond (x, &true, &false);
+      if (cond != 0)
+       {
+         rtx cop1 = const0_rtx;
+         enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
+
+         /* 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);
+
+         /* 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)
+           x = gen_binary (cond_code, mode, cond, cop1);
+         else if (true == const0_rtx && false == 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
+           return gen_rtx (IF_THEN_ELSE, mode,
+                           gen_binary (cond_code, VOIDmode, cond, cop1),
+                           true, false);
 
-  else if (GET_RTX_CLASS (code) == '1'
-          && GET_CODE (XEXP (x, 0)) == IF_THEN_ELSE
-          && GET_MODE (XEXP (x, 0)) == mode)
-    {
-      rtx cond = XEXP (XEXP (x, 0), 0);
-      rtx t_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 1)),
-                        pc_rtx, pc_rtx, 0, 0);
-      rtx f_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 2)),
-                        pc_rtx, pc_rtx, 0, 0);
-
-      x = gen_rtx_combine (IF_THEN_ELSE, mode, cond, t_arm, f_arm);
-      goto restart;
+         code = GET_CODE (x);
+         op0_mode = VOIDmode;
+       }
     }
 
   /* Try to fold this expression in case we have constants that weren't
@@ -3072,11 +3114,7 @@ subst (x, from, to, in_dest, unique_copy)
            }
 
          if (inner)
-           {
-             x = gen_binary (code, mode, other, inner);
-             goto restart;
-           
-           }
+           return gen_binary (code, mode, other, inner);
        }
     }
 
@@ -3194,33 +3232,28 @@ subst (x, from, to, in_dest, unique_copy)
          )
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
-      /* If we are narrowing an integral object, we need to see if we can
-        simplify the expression for the object knowing that we only need the
-        low-order bits.  */
+      /* 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))
+       return SUBREG_REG (x);
+
+      /* Note that we cannot do any narrowing for non-constants since
+        we might have been counting on using the fact that some bits were
+        zero.  We now do this in the SET.  */
 
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
-         && subreg_lowpart_p (x))
-       return force_to_mode (SUBREG_REG (x), mode, GET_MODE_MASK (mode),
-                             NULL_RTX);
       break;
 
     case NOT:
       /* (not (plus X -1)) can become (neg X).  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && XEXP (XEXP (x, 0), 1) == constm1_rtx)
-       {
-         x = gen_rtx_combine (NEG, mode, XEXP (XEXP (x, 0), 0));
-         goto restart;
-       }
+       return gen_rtx_combine (NEG, mode, XEXP (XEXP (x, 0), 0));
 
       /* Similarly, (not (neg X)) is (plus X -1).  */
       if (GET_CODE (XEXP (x, 0)) == NEG)
-       {
-         x = gen_rtx_combine (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-         goto restart;
-       }
+       return gen_rtx_combine (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
@@ -3239,11 +3272,8 @@ subst (x, from, to, in_dest, unique_copy)
         but this doesn't seem common enough to bother with.  */
       if (GET_CODE (XEXP (x, 0)) == ASHIFT
          && XEXP (XEXP (x, 0), 0) == const1_rtx)
-       {
-         x = gen_rtx (ROTATE, mode, gen_unary (NOT, mode, const1_rtx),
-                      XEXP (XEXP (x, 0), 1));
-         goto restart;
-       }
+       return gen_rtx (ROTATE, mode, gen_unary (NOT, mode, mode, const1_rtx),
+                       XEXP (XEXP (x, 0), 1));
                                            
       if (GET_CODE (XEXP (x, 0)) == SUBREG
          && subreg_lowpart_p (XEXP (x, 0))
@@ -3255,10 +3285,9 @@ subst (x, from, to, in_dest, unique_copy)
          enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
 
          x = gen_rtx (ROTATE, inner_mode,
-                      gen_unary (NOT, inner_mode, const1_rtx),
+                      gen_unary (NOT, inner_mode, inner_mode, const1_rtx),
                       XEXP (SUBREG_REG (XEXP (x, 0)), 1));
-         x = gen_lowpart_for_combine (mode, x);
-         goto restart;
+         return gen_lowpart_for_combine (mode, x);
        }
                                            
 #if STORE_FLAG_VALUE == -1
@@ -3309,9 +3338,8 @@ subst (x, from, to, in_dest, unique_copy)
             in2 = in1; in1 = tem;
           }
 
-        x = gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
-                             mode, in1, in2);
-        goto restart;
+        return gen_rtx_combine (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
+                                mode, in1, in2);
        } 
       break;
 
@@ -3319,36 +3347,25 @@ subst (x, from, to, in_dest, unique_copy)
       /* (neg (plus X 1)) can become (not X).  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && XEXP (XEXP (x, 0), 1) == const1_rtx)
-       {
-         x = gen_rtx_combine (NOT, mode, XEXP (XEXP (x, 0), 0));
-         goto restart;
-       }
+       return gen_rtx_combine (NOT, mode, XEXP (XEXP (x, 0), 0));
 
       /* Similarly, (neg (not X)) is (plus X 1).  */
       if (GET_CODE (XEXP (x, 0)) == NOT)
-       {
-         x = plus_constant (XEXP (XEXP (x, 0), 0), 1);
-         goto restart;
-       }
+       return plus_constant (XEXP (XEXP (x, 0), 0), 1);
 
       /* (neg (minus X Y)) can become (minus Y X).  */
       if (GET_CODE (XEXP (x, 0)) == MINUS
          && (! FLOAT_MODE_P (mode)
              /* x-y != -(y-x) with IEEE floating point. */
-             || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT))
-       {
-         x = gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
-                         XEXP (XEXP (x, 0), 0));
-         goto restart;
-       }
+             || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+             || flag_fast_math))
+       return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
+                          XEXP (XEXP (x, 0), 0));
 
       /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
       if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
          && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
-       {
-         x = gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
-         goto restart;
-       }
+       return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
 
       /* NEG commutes with ASHIFT since it is multiplication.  Only do this
         if we can then eliminate the NEG (e.g.,
@@ -3374,11 +3391,8 @@ subst (x, from, to, in_dest, unique_copy)
       if (GET_CODE (temp) == ASHIFTRT
          && GET_CODE (XEXP (temp, 1)) == CONST_INT
          && INTVAL (XEXP (temp, 1)) == GET_MODE_BITSIZE (mode) - 1)
-       {
-         x = simplify_shift_const (temp, LSHIFTRT, mode, XEXP (temp, 0),
-                                   INTVAL (XEXP (temp, 1)));
-         goto restart;
-       }
+       return simplify_shift_const (temp, LSHIFTRT, mode, XEXP (temp, 0),
+                                    INTVAL (XEXP (temp, 1)));
 
       /* If X has only a single bit that might be nonzero, say, bit I, convert
         (neg X) to (ashiftrt (ashift X C-I) C-I) where C is the bitsize of
@@ -3404,10 +3418,7 @@ subst (x, from, to, in_dest, unique_copy)
          if (GET_CODE (temp1) != ASHIFTRT
              || GET_CODE (XEXP (temp1, 0)) != ASHIFT
              || XEXP (XEXP (temp1, 0), 0) != temp)
-           {
-             x = temp1;
-             goto restart;
-           }
+           return temp1;
        }
       break;
 
@@ -3416,6 +3427,15 @@ subst (x, from, to, in_dest, unique_copy)
       if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
          && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
        return XEXP (XEXP (x, 0), 0);
+
+      /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
+        (OP:SF foo:SF) if OP is NEG or ABS.  */
+      if ((GET_CODE (XEXP (x, 0)) == ABS
+          || 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));
       break;  
 
 #ifdef HAVE_cc0
@@ -3428,7 +3448,8 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* 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))))
+          || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
+          || flag_fast_math)
          && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
        return XEXP (x, 0);
       break;
@@ -3482,15 +3503,12 @@ subst (x, from, to, in_dest, unique_copy)
              || (GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND
                  && (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)))
                      == i + 1))))
-       {
-         x = simplify_shift_const
-           (NULL_RTX, ASHIFTRT, mode,
-            simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                                  XEXP (XEXP (XEXP (x, 0), 0), 0),
-                                  GET_MODE_BITSIZE (mode) - (i + 1)),
-            GET_MODE_BITSIZE (mode) - (i + 1));
-         goto restart;
-       }
+       return simplify_shift_const
+         (NULL_RTX, ASHIFTRT, mode,
+          simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                                XEXP (XEXP (XEXP (x, 0), 0), 0),
+                                GET_MODE_BITSIZE (mode) - (i + 1)),
+          GET_MODE_BITSIZE (mode) - (i + 1));
 
       /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
         C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
@@ -3500,12 +3518,11 @@ subst (x, from, to, in_dest, unique_copy)
          && reversible_comparison_p (XEXP (x, 0))
          && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
              || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
-       {
-         x = gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
-                         mode, XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1));
-         x = gen_unary (NEG, mode, x);
-         goto restart;
-       }
+       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)));
 
       /* 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
@@ -3516,16 +3533,12 @@ subst (x, from, to, in_dest, unique_copy)
          && ! (GET_CODE (XEXP (x,0)) == SUBREG
                && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)
          && nonzero_bits (XEXP (x, 0), mode) == 1)
-       {
-         x = simplify_shift_const
-           (NULL_RTX, ASHIFTRT, mode,
-            simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                                  gen_rtx_combine (XOR, mode,
-                                                   XEXP (x, 0), const1_rtx),
-                                  GET_MODE_BITSIZE (mode) - 1),
-            GET_MODE_BITSIZE (mode) - 1);
-         goto restart;
-       }
+       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),
+                                GET_MODE_BITSIZE (mode) - 1),
+          GET_MODE_BITSIZE (mode) - 1);
 
       /* If we are adding two things that have no bits in common, convert
         the addition into an IOR.  This will often be further simplified,
@@ -3535,10 +3548,7 @@ subst (x, from, to, in_dest, unique_copy)
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (XEXP (x, 0), mode)
              & nonzero_bits (XEXP (x, 1), mode)) == 0)
-       {
-         x = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
-         goto restart;
-       }
+       return gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
       break;
 
     case MINUS:
@@ -3559,22 +3569,16 @@ subst (x, from, to, in_dest, unique_copy)
          && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
          && exact_log2 (- INTVAL (XEXP (XEXP (x, 1), 1))) >= 0
          && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
-       {
-         x = simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
-                                     - INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
-         goto restart;
-       }
+       return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
+                                      - INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
 
       /* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
         integers.  */
       if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
-       {
-         x = gen_binary (MINUS, mode,
-                         gen_binary (MINUS, mode, XEXP (x, 0),
-                                     XEXP (XEXP (x, 1), 0)),
-                         XEXP (XEXP (x, 1), 1));
-         goto restart;
-       }
+       return gen_binary (MINUS, mode,
+                          gen_binary (MINUS, mode, XEXP (x, 0),
+                                      XEXP (XEXP (x, 1), 0)),
+                          XEXP (XEXP (x, 1), 1));
       break;
 
     case MULT:
@@ -3592,29 +3596,8 @@ subst (x, from, to, in_dest, unique_copy)
                                     XEXP (XEXP (x, 0), 1), XEXP (x, 1))));
 
          if (GET_CODE (x) != MULT)
-           goto restart;
+           return x;
        }
-
-      /* If this is multiplication by a power of two and its first operand is
-        a shift, treat the multiply as a shift to allow the shifts to
-        possibly combine.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0
-         && (GET_CODE (XEXP (x, 0)) == ASHIFT
-             || GET_CODE (XEXP (x, 0)) == LSHIFTRT
-             || GET_CODE (XEXP (x, 0)) == ASHIFTRT
-             || GET_CODE (XEXP (x, 0)) == ROTATE
-             || GET_CODE (XEXP (x, 0)) == ROTATERT))
-       {
-         x = simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0), i);
-         goto restart;
-       }
-
-      /* Convert (mult (ashift (const_int 1) A) B) to (ashift B A).  */
-      if (GET_CODE (XEXP (x, 0)) == ASHIFT
-         && XEXP (XEXP (x, 0), 0) == const1_rtx)
-       return gen_rtx_combine (ASHIFT, mode, XEXP (x, 1),
-                               XEXP (XEXP (x, 0), 1));
       break;
 
     case UDIV:
@@ -3627,10 +3610,7 @@ subst (x, from, to, in_dest, unique_copy)
              || GET_CODE (XEXP (x, 0)) == ASHIFTRT
              || GET_CODE (XEXP (x, 0)) == ROTATE
              || GET_CODE (XEXP (x, 0)) == ROTATERT))
-       {
-         x = simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (x, 0), i);
-         goto restart;
-       }
+       return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (x, 0), i);
       break;
 
     case EQ:  case NE:
@@ -3680,8 +3660,8 @@ subst (x, from, to, in_dest, unique_copy)
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             x = gen_unary (NEG, mode, gen_lowpart_for_combine (mode, op0));
-             goto restart;
+             return gen_unary (NEG, mode, mode,
+                               gen_lowpart_for_combine (mode, op0));
            }
 
          else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
@@ -3689,10 +3669,9 @@ subst (x, from, to, in_dest, unique_copy)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             x = gen_binary (XOR, mode,
-                             gen_lowpart_for_combine (mode, op0),
-                             const1_rtx);
-             goto restart;
+             return gen_binary (XOR, mode,
+                                gen_lowpart_for_combine (mode, op0),
+                                const1_rtx);
            }
 
          else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
@@ -3701,8 +3680,7 @@ subst (x, from, to, in_dest, unique_copy)
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             x = plus_constant (gen_lowpart_for_combine (mode, op0), 1);
-             goto restart;
+             return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
            }
 #endif
 
@@ -3721,8 +3699,8 @@ subst (x, from, to, in_dest, unique_copy)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             x = gen_unary (NEG, mode, gen_lowpart_for_combine (mode, op0));
-             goto restart;
+             return gen_unary (NEG, mode, mode,
+                               gen_lowpart_for_combine (mode, op0));
            }
 
          else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
@@ -3731,8 +3709,8 @@ subst (x, from, to, in_dest, unique_copy)
                       == GET_MODE_BITSIZE (mode)))
            {
              op0 = expand_compound_operation (op0);
-             x = gen_unary (NOT, mode, gen_lowpart_for_combine (mode, op0));
-             goto restart;
+             return gen_unary (NOT, mode, mode,
+                               gen_lowpart_for_combine (mode, op0));
            }
 
          /* If X is 0/1, (eq X 0) is X-1.  */
@@ -3741,8 +3719,7 @@ subst (x, from, to, in_dest, unique_copy)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             x = plus_constant (gen_lowpart_for_combine (mode, op0), -1);
-             goto restart;
+             return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
            }
 #endif
 
@@ -3780,655 +3757,720 @@ subst (x, from, to, in_dest, unique_copy)
       break;
          
     case IF_THEN_ELSE:
-      /* 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.  */
+      return simplify_if_then_else (x);
 
-      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && reversible_comparison_p (XEXP (x, 0))
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
-       {
-         HOST_WIDE_INT nzb;
-         rtx from = XEXP (XEXP (x, 0), 0);
-         enum rtx_code true_code = GET_CODE (XEXP (x, 0));
-         enum rtx_code false_code = reverse_condition (true_code);
-         rtx true_val = XEXP (XEXP (x, 0), 1);
-         rtx false_val = true_val;
-         rtx true_arm = XEXP (x, 1);
-         rtx false_arm = XEXP (x, 2);
-         int swapped = 0;
-
-         /* If FALSE_CODE is EQ, swap the codes and arms.  */
-
-         if (false_code == EQ)
-           {
-             swapped = 1, true_code = EQ, false_code = NE;
-             true_arm = XEXP (x, 2), false_arm = XEXP (x, 1);
-           }
+    case ZERO_EXTRACT:
+    case SIGN_EXTRACT:
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      /* If we are processing SET_DEST, we are done. */
+      if (in_dest)
+       return x;
 
-         /* If we are comparing against zero and the expression being tested
-            has only a single bit that might be nonzero, that is its value
-            when it is not equal to zero.  Similarly if it is known to be
-            -1 or 0.  */
-
-         if (true_code == EQ && true_val == const0_rtx
-             && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
-           false_code = EQ, false_val = GEN_INT (nzb);
-         else if (true_code == EQ && true_val == const0_rtx
-                  && (num_sign_bit_copies (from, GET_MODE (from))
-                      == GET_MODE_BITSIZE (GET_MODE (from))))
-           false_code = EQ, false_val = constm1_rtx;
-
-         /* Now simplify an arm if we know the value of the register
-            in the branch and it is used in the arm.  Be carefull due to
-            the potential of locally-shared RTL.  */
-
-         if (reg_mentioned_p (from, true_arm))
-           true_arm = subst (known_cond (copy_rtx (true_arm), true_code,
-                                         from, true_val),
-                             pc_rtx, pc_rtx, 0, 0);
-         if (reg_mentioned_p (from, false_arm))
-           false_arm = subst (known_cond (copy_rtx (false_arm), false_code,
-                                          from, false_val),
-                              pc_rtx, pc_rtx, 0, 0);
-
-         SUBST (XEXP (x, 1), swapped ? false_arm : true_arm);
-         SUBST (XEXP (x, 2), swapped ? true_arm : false_arm);
-       }
+      return expand_compound_operation (x);
+
+    case SET:
+      return simplify_set (x);
+
+    case AND:
+    case IOR:
+    case XOR:
+      return simplify_logical (x, last);
+
+    case ABS:
+      /* (abs (neg <foo>)) -> (abs <foo>) */
+      if (GET_CODE (XEXP (x, 0)) == NEG)
+       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+
+      /* If operand is something known to be positive, ignore the ABS.  */
+      if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
+         || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+              <= HOST_BITS_PER_WIDE_INT)
+             && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+                  & ((HOST_WIDE_INT) 1
+                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
+                 == 0)))
+       return XEXP (x, 0);
+
+
+      /* 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));
+
+      break;
+
+    case FFS:
+      /* (ffs (*_extend <X>)) = (ffs <X>) */
+      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+         || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
+       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+      break;
+
+    case FLOAT:
+      /* (float (sign_extend <X>)) = (float <X>).  */
+      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
+       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+      break;
+
+    case ASHIFT:
+    case LSHIFTRT:
+    case ASHIFTRT:
+    case ROTATE:
+    case ROTATERT:
+      /* If this is a shift by a constant amount, simplify it.  */
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+       return simplify_shift_const (x, code, mode, XEXP (x, 0), 
+                                    INTVAL (XEXP (x, 1)));
+
+#ifdef SHIFT_COUNT_TRUNCATED
+      else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
+       SUBST (XEXP (x, 1),
+              force_to_mode (XEXP (x, 1), GET_MODE (x),
+                             ((HOST_WIDE_INT) 1 
+                              << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
+                             - 1,
+                             NULL_RTX, 0));
+#endif
+
+      break;
+    }
+
+  return x;
+}
+\f
+/* Simplify X, an IF_THEN_ELSE expression.  Return the new expression.  */
+
+static rtx
+simplify_if_then_else (x)
+     rtx x;
+{
+  enum machine_mode mode = GET_MODE (x);
+  rtx cond = XEXP (x, 0);
+  rtx true = XEXP (x, 1);
+  rtx false = XEXP (x, 2);
+  enum rtx_code true_code = GET_CODE (cond);
+  int comparison_p = GET_RTX_CLASS (true_code) == '<';
+  rtx temp;
+  int i;
+
+  /* Simplify storing of the truth value. */
+  if (comparison_p && true == const_true_rtx && false == const0_rtx)
+    return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
       
-      /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be
-        reversed, do so to avoid needing two sets of patterns for
-        subtract-and-branch insns.  Similarly if we have a constant in that
-        position or if the third operand is the same as the first operand
-        of the comparison.  */
+  /* 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));
+
+  /* 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)
+      && 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;
 
-      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && reversible_comparison_p (XEXP (x, 0))
-         && (XEXP (x, 1) == pc_rtx || GET_CODE (XEXP (x, 1)) == CONST_INT
-             || rtx_equal_p (XEXP (x, 2), XEXP (XEXP (x, 0), 0))))
-       {
-         SUBST (XEXP (x, 0),
-                gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
-                            GET_MODE (XEXP (x, 0)),
-                            XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
+      /* If FALSE_CODE is EQ, swap the codes and arms.  */
 
-         temp = XEXP (x, 1);
-         SUBST (XEXP (x, 1), XEXP (x, 2));
-         SUBST (XEXP (x, 2), temp);
+      if (false_code == EQ)
+       {
+         swapped = 1, true_code = EQ, false_code = NE;
+         temp = true, true = false, false = temp;
        }
 
-      /* If the two arms are identical, we don't need the comparison.  */
+      /* If we are comparing against zero and the expression being tested has
+        only a single bit that might be nonzero, that is its value when it is
+        not equal to zero.  Similarly if it is known to be -1 or 0.  */
 
-      if (rtx_equal_p (XEXP (x, 1), XEXP (x, 2))
-         && ! side_effects_p (XEXP (x, 0)))
-       return XEXP (x, 1);
+      if (true_code == EQ && true_val == const0_rtx
+         && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
+       false_code = EQ, false_val = GEN_INT (nzb);
+      else if (true_code == EQ && true_val == const0_rtx
+              && (num_sign_bit_copies (from, GET_MODE (from))
+                  == GET_MODE_BITSIZE (GET_MODE (from))))
+       false_code = EQ, false_val = constm1_rtx;
 
-      /* Look for cases where we have (abs x) or (neg (abs X)).  */
+      /* Now simplify an arm if we know the value of the register in the
+        branch and it is used in the arm.  Be careful due to the potential
+        of locally-shared RTL.  */
 
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && GET_CODE (XEXP (x, 2)) == NEG
-         && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 2), 0))
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && rtx_equal_p (XEXP (x, 1), XEXP (XEXP (x, 0), 0))
-         && ! side_effects_p (XEXP (x, 1)))
-       switch (GET_CODE (XEXP (x, 0)))
-         {
-         case GT:
-         case GE:
-           x = gen_unary (ABS, mode, XEXP (x, 1));
-           goto restart;
-         case LT:
-         case LE:
-           x = gen_unary (NEG, mode, gen_unary (ABS, mode, XEXP (x, 1)));
-           goto restart;
-         }
+      if (reg_mentioned_p (from, true))
+       true = subst (known_cond (copy_rtx (true), 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,
+                                  from, false_val),
+                      pc_rtx, pc_rtx, 0, 0);
 
-      /* Look for MIN or MAX.  */
+      SUBST (XEXP (x, 1), swapped ? false : true);
+      SUBST (XEXP (x, 2), swapped ? true : false);
 
-      if (! FLOAT_MODE_P (mode)
-         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-         && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
-         && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 2))
-         && ! side_effects_p (XEXP (x, 0)))
-       switch (GET_CODE (XEXP (x, 0)))
-         {
-         case GE:
-         case GT:
-           x = gen_binary (SMAX, mode, XEXP (x, 1), XEXP (x, 2));
-           goto restart;
-         case LE:
-         case LT:
-           x = gen_binary (SMIN, mode, XEXP (x, 1), XEXP (x, 2));
-           goto restart;
-         case GEU:
-         case GTU:
-           x = gen_binary (UMAX, mode, XEXP (x, 1), XEXP (x, 2));
-           goto restart;
-         case LEU:
-         case LTU:
-           x = gen_binary (UMIN, mode, XEXP (x, 1), XEXP (x, 2));
-           goto restart;
-         }
+      true = XEXP (x, 1), false = XEXP (x, 2), true_code = GET_CODE (cond);
+    }
 
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
+  /* If we have (if_then_else FOO (pc) (label_ref BAR)) and FOO can be
+     reversed, do so to avoid needing two sets of patterns for
+     subtract-and-branch insns.  Similarly if we have a constant in the true
+     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);
+      SUBST (XEXP (x, 0),
+            gen_binary (true_code, GET_MODE (cond), XEXP (cond, 0),
+                        XEXP (cond, 1)));
 
-      /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when
-        its second operand is zero, this can be done as (OP Z (mult COND C2))
-        where C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer
-        ZERO_EXTEND or SIGN_EXTEND as long as Z is already extended (so
-        we don't destroy it).  We can do this kind of thing in some
-        cases when STORE_FLAG_VALUE is neither of the above, but it isn't
-        worth checking for.  */
+      SUBST (XEXP (x, 1), false);
+      SUBST (XEXP (x, 2), true);
 
-      if (mode != VOIDmode && ! side_effects_p (x))
-       {
-         rtx t = make_compound_operation (XEXP (x, 1), SET);
-         rtx f = make_compound_operation (XEXP (x, 2), SET);
-         rtx cond_op0 = XEXP (XEXP (x, 0), 0);
-         rtx cond_op1 = XEXP (XEXP (x, 0), 1);
-         enum rtx_code cond_op = GET_CODE (XEXP (x, 0));
-         enum rtx_code op, extend_op = NIL;
-         enum machine_mode m = mode;
-         rtx z = 0, c1, c2;
-
-         if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS
-              || GET_CODE (t) == IOR || GET_CODE (t) == XOR
-              || GET_CODE (t) == ASHIFT
-              || GET_CODE (t) == LSHIFTRT || GET_CODE (t) == ASHIFTRT)
-             && rtx_equal_p (XEXP (t, 0), f))
-           c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
-         else if (GET_CODE (t) == SIGN_EXTEND
-                  && (GET_CODE (XEXP (t, 0)) == PLUS
-                      || GET_CODE (XEXP (t, 0)) == MINUS
-                      || GET_CODE (XEXP (t, 0)) == IOR
-                      || GET_CODE (XEXP (t, 0)) == XOR
-                      || GET_CODE (XEXP (t, 0)) == ASHIFT
-                      || GET_CODE (XEXP (t, 0)) == LSHIFTRT
-                      || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
-                  && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
-                  && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
-                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
-                  && (num_sign_bit_copies (f, GET_MODE (f))
-                      > (GET_MODE_BITSIZE (mode)
-                         - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0))))))
-           {
-             c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
-             extend_op = SIGN_EXTEND;
-             m = GET_MODE (XEXP (t, 0));
-           }
-         else if (GET_CODE (t) == ZERO_EXTEND
-                  && (GET_CODE (XEXP (t, 0)) == PLUS
-                      || GET_CODE (XEXP (t, 0)) == MINUS
-                      || GET_CODE (XEXP (t, 0)) == IOR
-                      || GET_CODE (XEXP (t, 0)) == XOR
-                      || GET_CODE (XEXP (t, 0)) == ASHIFT
-                      || GET_CODE (XEXP (t, 0)) == LSHIFTRT
-                      || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
-                  && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-                  && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
-                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
-                  && ((nonzero_bits (f, GET_MODE (f))
-                       & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 0))))
-                      == 0))
-           {
-             c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
-             extend_op = ZERO_EXTEND;
-             m = GET_MODE (XEXP (t, 0));
-           }
+      temp = true, true = false, false = temp, cond = XEXP (x, 0);
+    }
 
-         if (reversible_comparison_p (XEXP (x, 0))
-             && (GET_CODE (f) == PLUS || GET_CODE (f) == MINUS
-                 || GET_CODE (f) == IOR || GET_CODE (f) == XOR
-                 || GET_CODE (f) == ASHIFT
-                 || GET_CODE (f) == LSHIFTRT || GET_CODE (f) == ASHIFTRT)
-             && rtx_equal_p (XEXP (f, 0), t))
-           {
-             c1 = XEXP (f, 1), op = GET_CODE (f), z = t;
-             cond_op = reverse_condition (cond_op);
-           }
-         else if (GET_CODE (f) == SIGN_EXTEND
-                  && (GET_CODE (XEXP (f, 0)) == PLUS
-                      || GET_CODE (XEXP (f, 0)) == MINUS
-                      || GET_CODE (XEXP (f, 0)) == IOR
-                      || GET_CODE (XEXP (f, 0)) == XOR
-                      || GET_CODE (XEXP (f, 0)) == ASHIFT
-                      || GET_CODE (XEXP (f, 0)) == LSHIFTRT
-                      || GET_CODE (XEXP (f, 0)) == ASHIFTRT)
-                  && GET_CODE (XEXP (XEXP (f, 0), 0)) == SUBREG
-                  && subreg_lowpart_p (XEXP (XEXP (f, 0), 0))
-                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (f, 0), 0)), f)
-                  && (num_sign_bit_copies (t, GET_MODE (t))
-                      > (GET_MODE_BITSIZE (mode)
-                         - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (f, 0), 0))))))
-           {
-             c1 = XEXP (XEXP (f, 0), 1); z = t; op = GET_CODE (XEXP (f, 0));
-             extend_op = SIGN_EXTEND;
-             m = GET_MODE (XEXP (f, 0));
-             cond_op = reverse_condition (cond_op);
-           }
-         else if (GET_CODE (f) == ZERO_EXTEND
-                  && (GET_CODE (XEXP (f, 0)) == PLUS
-                      || GET_CODE (XEXP (f, 0)) == MINUS
-                      || GET_CODE (XEXP (f, 0)) == IOR
-                      || GET_CODE (XEXP (f, 0)) == XOR
-                      || GET_CODE (XEXP (f, 0)) == ASHIFT
-                      || GET_CODE (XEXP (f, 0)) == LSHIFTRT
-                      || GET_CODE (XEXP (f, 0)) == ASHIFTRT)
-                  && GET_CODE (XEXP (XEXP (f, 0), 0)) == SUBREG
-                  && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-                  && subreg_lowpart_p (XEXP (XEXP (f, 0), 0))
-                  && rtx_equal_p (SUBREG_REG (XEXP (XEXP (f, 0), 0)), t)
-                  && ((nonzero_bits (t, GET_MODE (t))
-                       & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (f, 0), 0))))
-                      == 0))
-           {
-             c1 = XEXP (XEXP (f, 0), 1); z = t; op = GET_CODE (XEXP (f, 0));
-             extend_op = ZERO_EXTEND;
-             m = GET_MODE (XEXP (f, 0));
-             cond_op = reverse_condition (cond_op);
-           }
+  /* If the two arms are identical, we don't need the comparison.  */
 
-         if (z)
-           {
-             temp = subst (gen_binary (cond_op, m, cond_op0, cond_op1),
-                           pc_rtx, pc_rtx, 0, 0);
+  if (rtx_equal_p (true, false) && ! side_effects_p (cond))
+    return true;
+
+  /* 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))
+      && comparison_p
+      && rtx_equal_p (true, XEXP (cond, 0))
+      && ! side_effects_p (true))
+    switch (true_code)
+      {
+      case GT:
+      case GE:
+       return gen_unary (ABS, mode, mode, true);
+      case LT:
+      case LE:
+       return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true));
+      }
 
+  /* Look for MIN or MAX.  */
 
-             temp = gen_binary (MULT, m, temp,
-                                gen_binary (MULT, m, c1,
-                                            GEN_INT (STORE_FLAG_VALUE)));
+  if ((! FLOAT_MODE_P (mode) | flag_fast_math)
+      && comparison_p
+      && rtx_equal_p (XEXP (cond, 0), true)
+      && rtx_equal_p (XEXP (cond, 1), false)
+      && ! side_effects_p (cond))
+    switch (true_code)
+      {
+      case GE:
+      case GT:
+       return gen_binary (SMAX, mode, true, false);
+      case LE:
+      case LT:
+       return gen_binary (SMIN, mode, true, false);
+      case GEU:
+      case GTU:
+       return gen_binary (UMAX, mode, true, false);
+      case LEU:
+      case LTU:
+       return gen_binary (UMIN, mode, true, false);
+      }
+  
+#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
 
-             temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
+  /* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
+     second operand is zero, this can be done as (OP Z (mult COND C2)) where
+     C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer ZERO_EXTEND or
+     SIGN_EXTEND as long as Z is already extended (so we don't destroy it).
+     We can do this kind of thing in some cases when STORE_FLAG_VALUE is
+     neither of the above, but it isn't worth checking for.  */
 
-             if (extend_op != NIL)
-               temp = gen_unary (extend_op, mode, temp);
+  if (comparison_p && mode != VOIDmode && ! side_effects_p (x))
+    {
+      rtx t = make_compound_operation (true, SET);
+      rtx f = make_compound_operation (false, SET);
+      rtx cond_op0 = XEXP (cond, 0);
+      rtx cond_op1 = XEXP (cond, 1);
+      enum rtx_code op, extend_op = NIL;
+      enum machine_mode m = mode;
+      rtx z = 0, c1;
+
+      if ((GET_CODE (t) == PLUS || GET_CODE (t) == MINUS
+          || GET_CODE (t) == IOR || GET_CODE (t) == XOR
+          || GET_CODE (t) == ASHIFT
+          || GET_CODE (t) == LSHIFTRT || GET_CODE (t) == ASHIFTRT)
+         && rtx_equal_p (XEXP (t, 0), f))
+       c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
+
+      /* If an identity-zero op is commutative, check whether there
+        would be a match if we swapped the operands. */
+      else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR
+               || GET_CODE (t) == XOR)
+              && rtx_equal_p (XEXP (t, 1), f))
+       c1 = XEXP (t, 0), op = GET_CODE (t), z = f;
+      else if (GET_CODE (t) == SIGN_EXTEND
+              && (GET_CODE (XEXP (t, 0)) == PLUS
+                  || GET_CODE (XEXP (t, 0)) == MINUS
+                  || GET_CODE (XEXP (t, 0)) == IOR
+                  || GET_CODE (XEXP (t, 0)) == XOR
+                  || GET_CODE (XEXP (t, 0)) == ASHIFT
+                  || GET_CODE (XEXP (t, 0)) == LSHIFTRT
+                  || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
+              && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
+              && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
+              && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
+              && (num_sign_bit_copies (f, GET_MODE (f))
+                  > (GET_MODE_BITSIZE (mode)
+                     - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 0))))))
+       {
+         c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
+         extend_op = SIGN_EXTEND;
+         m = GET_MODE (XEXP (t, 0));
+       }
+      else if (GET_CODE (t) == SIGN_EXTEND
+              && (GET_CODE (XEXP (t, 0)) == PLUS
+                  || GET_CODE (XEXP (t, 0)) == IOR
+                  || GET_CODE (XEXP (t, 0)) == XOR)
+              && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
+              && subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
+              && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
+              && (num_sign_bit_copies (f, GET_MODE (f))
+                  > (GET_MODE_BITSIZE (mode)
+                     - GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (t, 0), 1))))))
+       {
+         c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
+         extend_op = SIGN_EXTEND;
+         m = GET_MODE (XEXP (t, 0));
+       }
+      else if (GET_CODE (t) == ZERO_EXTEND
+              && (GET_CODE (XEXP (t, 0)) == PLUS
+                  || GET_CODE (XEXP (t, 0)) == MINUS
+                  || GET_CODE (XEXP (t, 0)) == IOR
+                  || GET_CODE (XEXP (t, 0)) == XOR
+                  || GET_CODE (XEXP (t, 0)) == ASHIFT
+                  || GET_CODE (XEXP (t, 0)) == LSHIFTRT
+                  || GET_CODE (XEXP (t, 0)) == ASHIFTRT)
+              && GET_CODE (XEXP (XEXP (t, 0), 0)) == SUBREG
+              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+              && subreg_lowpart_p (XEXP (XEXP (t, 0), 0))
+              && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 0)), f)
+              && ((nonzero_bits (f, GET_MODE (f))
+                   & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 0))))
+                  == 0))
+       {
+         c1 = XEXP (XEXP (t, 0), 1); z = f; op = GET_CODE (XEXP (t, 0));
+         extend_op = ZERO_EXTEND;
+         m = GET_MODE (XEXP (t, 0));
+       }
+      else if (GET_CODE (t) == ZERO_EXTEND
+              && (GET_CODE (XEXP (t, 0)) == PLUS
+                  || GET_CODE (XEXP (t, 0)) == IOR
+                  || GET_CODE (XEXP (t, 0)) == XOR)
+              && GET_CODE (XEXP (XEXP (t, 0), 1)) == SUBREG
+              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+              && subreg_lowpart_p (XEXP (XEXP (t, 0), 1))
+              && rtx_equal_p (SUBREG_REG (XEXP (XEXP (t, 0), 1)), f)
+              && ((nonzero_bits (f, GET_MODE (f))
+                   & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (t, 0), 1))))
+                  == 0))
+       {
+         c1 = XEXP (XEXP (t, 0), 0); z = f; op = GET_CODE (XEXP (t, 0));
+         extend_op = ZERO_EXTEND;
+         m = GET_MODE (XEXP (t, 0));
+       }
+      
+      if (z)
+       {
+         temp = subst (gen_binary (true_code, m, cond_op0, cond_op1),
+                       pc_rtx, pc_rtx, 0, 0);
+         temp = gen_binary (MULT, m, temp,
+                            gen_binary (MULT, m, c1, const_true_rtx));
+         temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
+         temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp);
 
-             return temp;
-           }
+         if (extend_op != NIL)
+           temp = gen_unary (extend_op, mode, m, temp);
+
+         return temp;
        }
+    }
 #endif
 
-      /* If we have (if_then_else (ne A 0) C1 0) and either A is known to 
-        be 0 or 1 and C1 is a single bit or A is known to be 0 or -1 and
-        C1 is the negation of a single bit, we can convert this operation
-        to a shift.  We can actually do this in more general cases, but it
-        doesn't seem worth it.  */
+  /* If we have (if_then_else (ne A 0) C1 0) and either A is known to be 0 or
+     1 and C1 is a single bit or A is known to be 0 or -1 and C1 is the
+     negation of a single bit, we can convert this operation to a shift.  We
+     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
+      && ((1 == nonzero_bits (XEXP (cond, 0), mode)
+          && (i = exact_log2 (INTVAL (true))) >= 0)
+         || ((num_sign_bit_copies (XEXP (cond, 0), mode)
+              == GET_MODE_BITSIZE (mode))
+             && (i = exact_log2 (- INTVAL (true))) >= 0)))
+    return
+      simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                           gen_lowpart_for_combine (mode, XEXP (cond, 0)), i);
 
-      if (GET_CODE (XEXP (x, 0)) == NE && XEXP (XEXP (x, 0), 1) == const0_rtx
-         && XEXP (x, 2) == const0_rtx && GET_CODE (XEXP (x, 1)) == CONST_INT
-         && ((1 == nonzero_bits (XEXP (XEXP (x, 0), 0), mode)
-              && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
-             || ((num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
-                  == GET_MODE_BITSIZE (mode))
-                 && (i = exact_log2 (- INTVAL (XEXP (x, 1)))) >= 0)))
-       return
-         simplify_shift_const (NULL_RTX, ASHIFT, mode,
-                               gen_lowpart_for_combine (mode,
-                                                        XEXP (XEXP (x, 0), 0)),
-                               i);
-      break;
-         
-    case ZERO_EXTRACT:
-    case SIGN_EXTRACT:
-    case ZERO_EXTEND:
-    case SIGN_EXTEND:
-      /* If we are processing SET_DEST, we are done. */
-      if (in_dest)
-       return x;
+  return x;
+}
+\f
+/* Simplify X, a SET expression.  Return the new expression.  */
 
-      x = expand_compound_operation (x);
-      if (GET_CODE (x) != code)
-       goto restart;
-      break;
+static rtx
+simplify_set (x)
+     rtx x;
+{
+  rtx src = SET_SRC (x);
+  rtx dest = SET_DEST (x);
+  enum machine_mode mode
+    = GET_MODE (src) != VOIDmode ? GET_MODE (src) : GET_MODE (dest);
+  rtx other_insn;
+  rtx *cc_use;
 
-    case SET:
-      /* (set (pc) (return)) gets written as (return).  */
-      if (GET_CODE (SET_DEST (x)) == PC && GET_CODE (SET_SRC (x)) == RETURN)
-       return SET_SRC (x);
+  /* (set (pc) (return)) gets written as (return).  */
+  if (GET_CODE (dest) == PC && GET_CODE (src) == RETURN)
+    return src;
+
+  /* Now that we know for sure which bits of SRC we are using, see if we can
+     simplify the expression for the object knowing that we only need the
+     low-order bits.  */
 
-      /* Convert this into a field assignment operation, if possible.  */
-      x = make_field_assignment (x);
+  if (GET_MODE_CLASS (mode) == MODE_INT)
+    src = force_to_mode (src, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
 
-      /* If we are setting CC0 or if the source is a COMPARE, look for the
-        use of the comparison result and try to simplify it unless we already
-        have used undobuf.other_insn.  */
-      if ((GET_CODE (SET_SRC (x)) == COMPARE
+  /* If we are setting CC0 or if the source is a COMPARE, look for the use of
+     the comparison result and try to simplify it unless we already have used
+     undobuf.other_insn.  */
+  if ((GET_CODE (src) == COMPARE
 #ifdef HAVE_cc0
-          || SET_DEST (x) == cc0_rtx
+       || dest == cc0_rtx
 #endif
-          )
-         && (cc_use = find_single_use (SET_DEST (x), subst_insn,
-                                       &other_insn)) != 0
-         && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
-         && GET_RTX_CLASS (GET_CODE (*cc_use)) == '<'
-         && XEXP (*cc_use, 0) == SET_DEST (x))
-       {
-         enum rtx_code old_code = GET_CODE (*cc_use);
-         enum rtx_code new_code;
-         rtx op0, op1;
-         int other_changed = 0;
-         enum machine_mode compare_mode = GET_MODE (SET_DEST (x));
-
-         if (GET_CODE (SET_SRC (x)) == COMPARE)
-           op0 = XEXP (SET_SRC (x), 0), op1 = XEXP (SET_SRC (x), 1);
-         else
-           op0 = SET_SRC (x), op1 = const0_rtx;
+       )
+      && (cc_use = find_single_use (dest, subst_insn, &other_insn)) != 0
+      && (undobuf.other_insn == 0 || other_insn == undobuf.other_insn)
+      && GET_RTX_CLASS (GET_CODE (*cc_use)) == '<'
+      && rtx_equal_p (XEXP (*cc_use, 0), dest))
+    {
+      enum rtx_code old_code = GET_CODE (*cc_use);
+      enum rtx_code new_code;
+      rtx op0, op1;
+      int other_changed = 0;
+      enum machine_mode compare_mode = GET_MODE (dest);
+
+      if (GET_CODE (src) == COMPARE)
+       op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+      else
+       op0 = src, op1 = const0_rtx;
 
-         /* Simplify our comparison, if possible.  */
-         new_code = simplify_comparison (old_code, &op0, &op1);
+      /* Simplify our comparison, if possible.  */
+      new_code = simplify_comparison (old_code, &op0, &op1);
 
 #ifdef EXTRA_CC_MODES
-         /* If this machine has CC modes other than CCmode, check to see
-            if we need to use a different CC mode here.  */
-         compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+      /* If this machine has CC modes other than CCmode, check to see if we
+        need to use a different CC mode here.  */
+      compare_mode = SELECT_CC_MODE (new_code, op0, op1);
 #endif /* EXTRA_CC_MODES */
 
 #if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
-         /* If the mode changed, we have to change SET_DEST, the mode
-            in the compare, and the mode in the place SET_DEST is used.
-            If SET_DEST is a hard register, just build new versions with
-            the proper mode.  If it is a pseudo, we lose unless it is only
-            time we set the pseudo, in which case we can safely change
-            its mode.  */
-         if (compare_mode != GET_MODE (SET_DEST (x)))
+      /* If the mode changed, we have to change SET_DEST, the mode in the
+        compare, and the mode in the place SET_DEST is used.  If SET_DEST is
+        a hard register, just build new versions with the proper mode.  If it
+        is a pseudo, we lose unless it is only time we set the pseudo, in
+        which case we can safely change its mode.  */
+      if (compare_mode != GET_MODE (dest))
+       {
+         int regno = REGNO (dest);
+         rtx new_dest = gen_rtx (REG, compare_mode, regno);
+
+         if (regno < FIRST_PSEUDO_REGISTER
+             || (reg_n_sets[regno] == 1 && ! REG_USERVAR_P (dest)))
            {
-             int regno = REGNO (SET_DEST (x));
-             rtx new_dest = gen_rtx (REG, compare_mode, regno);
+             if (regno >= FIRST_PSEUDO_REGISTER)
+               SUBST (regno_reg_rtx[regno], new_dest);
 
-             if (regno < FIRST_PSEUDO_REGISTER
-                 || (reg_n_sets[regno] == 1
-                     && ! REG_USERVAR_P (SET_DEST (x))))
-               {
-                 if (regno >= FIRST_PSEUDO_REGISTER)
-                   SUBST (regno_reg_rtx[regno], new_dest);
+             SUBST (SET_DEST (x), new_dest);
+             SUBST (XEXP (*cc_use, 0), new_dest);
+             other_changed = 1;
 
-                 SUBST (SET_DEST (x), new_dest);
-                 SUBST (XEXP (*cc_use, 0), new_dest);
-                 other_changed = 1;
-               }
+             dest = new_dest;
            }
+       }
 #endif
 
-         /* If the code changed, we have to build a new comparison
-            in undobuf.other_insn.  */
-         if (new_code != old_code)
+      /* If the code changed, we have to build a new comparison in
+        undobuf.other_insn.  */
+      if (new_code != old_code)
+       {
+         unsigned HOST_WIDE_INT mask;
+
+         SUBST (*cc_use, gen_rtx_combine (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
+            is zero, check if changing the user of the condition code will
+            produce a valid insn.  If it won't, we can keep the original code
+            in that insn by surrounding our operation with an XOR.  */
+
+         if (((old_code == NE && new_code == EQ)
+              || (old_code == EQ && new_code == NE))
+             && ! other_changed && op1 == const0_rtx
+             && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
+             && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
            {
-             unsigned HOST_WIDE_INT mask;
+             rtx pat = PATTERN (other_insn), note = 0;
 
-             SUBST (*cc_use, gen_rtx_combine (new_code, GET_MODE (*cc_use),
-                                              SET_DEST (x), 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 is zero, check if changing the user of the condition
-                code will produce a valid insn.  If it won't, we can keep
-                the original code in that insn by surrounding our operation
-                with an XOR.  */
-
-             if (((old_code == NE && new_code == EQ)
-                  || (old_code == EQ && new_code == NE))
-                 && ! other_changed && op1 == const0_rtx
-                 && (GET_MODE_BITSIZE (GET_MODE (op0))
-                     <= HOST_BITS_PER_WIDE_INT)
-                 && (exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0)))
-                     >= 0))
+             if ((recog_for_combine (&pat, other_insn, &note) < 0
+                  && ! check_asm_operands (pat)))
                {
-                 rtx pat = PATTERN (other_insn), note = 0;
-
-                 if ((recog_for_combine (&pat, other_insn, &note) < 0
-                      && ! check_asm_operands (pat)))
-                   {
-                     PUT_CODE (*cc_use, old_code);
-                     other_insn = 0;
+                 PUT_CODE (*cc_use, old_code);
+                 other_insn = 0;
 
-                     op0 = gen_binary (XOR, GET_MODE (op0), op0,
-                                       GEN_INT (mask));
-                   }
+                 op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
                }
-
-             other_changed = 1;
            }
 
-         if (other_changed)
-           undobuf.other_insn = other_insn;
+         other_changed = 1;
+       }
+
+      if (other_changed)
+       undobuf.other_insn = other_insn;
 
 #ifdef HAVE_cc0
-         /* If we are now comparing against zero, change our source if
-            needed.  If we do not use cc0, we always have a COMPARE.  */
-         if (op1 == const0_rtx && SET_DEST (x) == cc0_rtx)
-           SUBST (SET_SRC (x), op0);
-         else
+      /* If we are now comparing against zero, change our source if
+        needed.  If we do not use cc0, we always have a COMPARE.  */
+      if (op1 == const0_rtx && dest == cc0_rtx)
+       {
+         SUBST (SET_SRC (x), op0);
+         src = op0;
+       }
+      else
 #endif
 
-         /* Otherwise, if we didn't previously have a COMPARE in the
-            correct mode, we need one.  */
-         if (GET_CODE (SET_SRC (x)) != COMPARE
-             || GET_MODE (SET_SRC (x)) != compare_mode)
-           SUBST (SET_SRC (x), gen_rtx_combine (COMPARE, compare_mode,
-                                                op0, op1));
-         else
-           {
-             /* Otherwise, update the COMPARE if needed.  */
-             SUBST (XEXP (SET_SRC (x), 0), op0);
-             SUBST (XEXP (SET_SRC (x), 1), op1);
-           }
+      /* Otherwise, if we didn't previously have a COMPARE in the
+        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));
+         src = SET_SRC (x);
        }
       else
        {
-         /* Get SET_SRC in a form where we have placed back any
-            compound expressions.  Then do the checks below.  */
-         temp = make_compound_operation (SET_SRC (x), SET);
-         SUBST (SET_SRC (x), temp);
+         /* Otherwise, update the COMPARE if needed.  */
+         SUBST (XEXP (src, 0), op0);
+         SUBST (XEXP (src, 1), op1);
        }
+    }
+  else
+    {
+      /* Get SET_SRC in a form where we have placed back any
+        compound expressions.  Then do the checks below.  */
+      src = make_compound_operation (src, SET);
+      SUBST (SET_SRC (x), src);
+    }
 
-      /* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some
-        operation, and X being a REG or (subreg (reg)), we may be able to
-        convert this to (set (subreg:m2 x) (op)).
+  /* If we have (set x (subreg:m1 (op:m2 ...) 0)) with OP being some operation,
+     and X being a REG or (subreg (reg)), we may be able to convert this to
+     (set (subreg:m2 x) (op)). 
 
-        We can always do this if M1 is narrower than M2 because that
-        means that we only care about the low bits of the result.
+     We can always do this if M1 is narrower than M2 because that means that
+     we only care about the low bits of the result.
 
-        However, on machines without WORD_REGISTER_OPERATIONS defined,
-        we cannot perform a narrower operation that requested since the
-        high-order bits will be undefined.  On machine where it is defined,
-        this transformation is safe as long as M1 and M2 have the same
-        number of words.  */
+     However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
+     perform a narrower operation that requested since the high-order bits will
+     be undefined.  On machine where it is defined, this transformation is safe
+     as long as M1 and M2 have the same number of words.  */
  
-      if (GET_CODE (SET_SRC (x)) == SUBREG
-         && subreg_lowpart_p (SET_SRC (x))
-         && GET_RTX_CLASS (GET_CODE (SUBREG_REG (SET_SRC (x)))) != 'o'
-         && (((GET_MODE_SIZE (GET_MODE (SET_SRC (x))) + (UNITS_PER_WORD - 1))
-              / UNITS_PER_WORD)
-             == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x))))
-                  + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
+  if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
+      && GET_RTX_CLASS (GET_CODE (SUBREG_REG (src))) != 'o'
+      && (((GET_MODE_SIZE (GET_MODE (src)) + (UNITS_PER_WORD - 1))
+          / UNITS_PER_WORD)
+         == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+              + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
 #ifndef WORD_REGISTER_OPERATIONS
-         && (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x)))))
+      && (GET_MODE_SIZE (GET_MODE (src))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
 #endif
-         && (GET_CODE (SET_DEST (x)) == REG
-             || (GET_CODE (SET_DEST (x)) == SUBREG
-                 && GET_CODE (SUBREG_REG (SET_DEST (x))) == REG)))
-       {
-         SUBST (SET_DEST (x),
-                gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_SRC (x))),
-                                         SET_DEST (x)));
-         SUBST (SET_SRC (x), SUBREG_REG (SET_SRC (x)));
-       }
+      && (GET_CODE (dest) == REG
+         || (GET_CODE (dest) == SUBREG
+             && GET_CODE (SUBREG_REG (dest)) == REG)))
+    {
+      SUBST (SET_DEST (x),
+            gen_lowpart_for_combine (GET_MODE (SUBREG_REG (src)),
+                                     dest));
+      SUBST (SET_SRC (x), SUBREG_REG (src));
+
+      src = SET_SRC (x), dest = SET_DEST (x);
+    }
 
 #ifdef LOAD_EXTEND_OP
-      /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with
-        M wider than N, this would require a paradoxical subreg.
-        Replace the subreg with a zero_extend to avoid the reload that
-        would otherwise be required. */
-
-      if (GET_CODE (SET_SRC (x)) == SUBREG
-         && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (SET_SRC (x)))) != NIL
-         && subreg_lowpart_p (SET_SRC (x))
-         && SUBREG_WORD (SET_SRC (x)) == 0
-         && (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x)))))
-         && GET_CODE (SUBREG_REG (SET_SRC (x))) == MEM)
-       SUBST (SET_SRC (x),
-              gen_rtx_combine (LOAD_EXTEND_OP (GET_MODE
-                                               (SUBREG_REG (SET_SRC (x)))),
-                               GET_MODE (SET_SRC (x)),
-                               XEXP (SET_SRC (x), 0)));
+  /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
+     would require a paradoxical subreg.  Replace the subreg with a
+     zero_extend to avoid the reload that would otherwise be required. */
+
+  if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
+      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
+      && SUBREG_WORD (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)));
+
+      src = SET_SRC (x);
+    }
 #endif
 
-#ifndef HAVE_conditional_move
-
-      /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE,
-        and we are comparing an item known to be 0 or -1 against 0, use a
-        logical operation instead. Check for one of the arms being an IOR
-        of the other arm with some value.  We compute three terms to be
-        IOR'ed together.  In practice, at most two will be nonzero.  Then
-        we do the IOR's.  */
-
-      if (GET_CODE (SET_DEST (x)) != PC
-         && GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
-         && (GET_CODE (XEXP (SET_SRC (x), 0)) == EQ
-             || GET_CODE (XEXP (SET_SRC (x), 0)) == NE)
-         && XEXP (XEXP (SET_SRC (x), 0), 1) == const0_rtx
-         && (num_sign_bit_copies (XEXP (XEXP (SET_SRC (x), 0), 0),
-                                  GET_MODE (XEXP (XEXP (SET_SRC (x), 0), 0)))
-             == GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (SET_SRC (x), 0), 0))))
-         && ! side_effects_p (SET_SRC (x)))
-       {
-         rtx true = (GET_CODE (XEXP (SET_SRC (x), 0)) == NE
-                     ? XEXP (SET_SRC (x), 1) : XEXP (SET_SRC (x), 2));
-         rtx false = (GET_CODE (XEXP (SET_SRC (x), 0)) == NE
-                      ? XEXP (SET_SRC (x), 2) : XEXP (SET_SRC (x), 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 (SET_SRC (x)),
-                             XEXP (XEXP (SET_SRC (x), 0), 0), true);
-         term3 = gen_binary (AND, GET_MODE (SET_SRC (x)),
-                             gen_unary (NOT, GET_MODE (SET_SRC (x)),
-                                        XEXP (XEXP (SET_SRC (x), 0), 0)),
-                             false);
+  /* If we don't have a conditional move, SET_SRC is an IF_THEN_ELSE, and we
+     are comparing an item known to be 0 or -1 against 0, use a logical
+     operation instead. Check for one of the arms being an IOR of the other
+     arm with some value.  We compute three terms to be IOR'ed together.  In
+     practice, at most two will be nonzero.  Then we do the IOR's.  */
 
-         SUBST (SET_SRC (x),
-                gen_binary (IOR, GET_MODE (SET_SRC (x)),
-                            gen_binary (IOR, GET_MODE (SET_SRC (x)),
-                                        term1, term2),
-                            term3));
-       }
+  if (GET_CODE (dest) != PC
+      && GET_CODE (src) == IF_THEN_ELSE
+#ifdef HAVE_conditional_move
+      && ! HAVE_conditional_move
 #endif
-      break;
+      && GET_MODE_CLASS (GET_MODE (src)) == MODE_INT
+      && (GET_CODE (XEXP (src, 0)) == EQ || GET_CODE (XEXP (src, 0)) == NE)
+      && XEXP (XEXP (src, 0), 1) == const0_rtx
+      && (num_sign_bit_copies (XEXP (XEXP (src, 0), 0),
+                              GET_MODE (XEXP (XEXP (src, 0), 0)))
+         == GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (src, 0), 0))))
+      && ! side_effects_p (src))
+    {
+      rtx true = (GET_CODE (XEXP (src, 0)) == NE
+                     ? XEXP (src, 1) : XEXP (src, 2));
+      rtx false = (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);
+      term3 = gen_binary (AND, GET_MODE (src),
+                         gen_unary (NOT, GET_MODE (src), GET_MODE (src),
+                                    XEXP (XEXP (src, 0), 0)),
+                         false);
+
+      SUBST (SET_SRC (x),
+            gen_binary (IOR, GET_MODE (src),
+                        gen_binary (IOR, GET_MODE (src), term1, term2),
+                        term3));
+
+      src = SET_SRC (x);
+    }
 
+  /* 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)
+    return src;
+  else if (GET_CODE (dest) == CLOBBER && XEXP (dest, 0) == const0_rtx)
+    return dest;
+  else
+    /* Convert this into a field assignment operation, if possible.  */
+    return make_field_assignment (x);
+}
+\f
+/* Simplify, X, and AND, IOR, or XOR operation, and return the simplified
+   result.  LAST is nonzero if this is the last retry.  */
+
+static rtx
+simplify_logical (x, last)
+     rtx x;
+     int last;
+{
+  enum machine_mode mode = GET_MODE (x);
+  rtx op0 = XEXP (x, 0);
+  rtx op1 = XEXP (x, 1);
+
+  switch (GET_CODE (x))
+    {
     case AND:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+      /* Convert (A ^ B) & A to A & (~ B) since the latter is often a single
+        insn (and may simplify more).  */
+      if (GET_CODE (op0) == XOR
+         && 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);
+
+      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);
+
+      /* Similarly for (~ (A ^ B)) & A.  */
+      if (GET_CODE (op0) == NOT
+         && GET_CODE (XEXP (op0, 0)) == XOR
+         && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
+         && ! side_effects_p (op1))
+       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
+
+      if (GET_CODE (op0) == NOT
+         && GET_CODE (XEXP (op0, 0)) == XOR
+         && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
+         && ! side_effects_p (op1))
+       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
+
+      if (GET_CODE (op1) == CONST_INT)
        {
-         x = simplify_and_const_int (x, mode, XEXP (x, 0),
-                                     INTVAL (XEXP (x, 1)));
+         x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
 
          /* If we have (ior (and (X C1) C2)) and the next restart would be
             the last, simplify this by making C1 as small as possible
             and then exit. */
-         if (n_restarts >= 3 && GET_CODE (x) == IOR
-             && GET_CODE (XEXP (x, 0)) == AND
-             && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-             && GET_CODE (XEXP (x, 1)) == CONST_INT)
-           {
-             temp = gen_binary (AND, mode, XEXP (XEXP (x, 0), 0),
-                                GEN_INT (INTVAL (XEXP (XEXP (x, 0), 1))
-                                         & ~ INTVAL (XEXP (x, 1))));
-             return gen_binary (IOR, mode, temp, XEXP (x, 1));
-           }
+         if (last
+             && GET_CODE (x) == IOR && GET_CODE (op0) == AND
+             && GET_CODE (XEXP (op0, 1)) == CONST_INT
+             && GET_CODE (op1) == CONST_INT)
+           return gen_binary (IOR, mode,
+                              gen_binary (AND, mode, XEXP (op0, 0),
+                                          GEN_INT (INTVAL (XEXP (op0, 1))
+                                                   & ~ INTVAL (op1))), op1);
 
          if (GET_CODE (x) != AND)
-           goto restart;
+           return x;
        }
 
       /* Convert (A | B) & A to A.  */
-      if (GET_CODE (XEXP (x, 0)) == IOR
-         && (rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
-             || rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 1)))
-         && ! side_effects_p (XEXP (XEXP (x, 0), 0))
-         && ! side_effects_p (XEXP (XEXP (x, 0), 1)))
-       return XEXP (x, 1);
-
-      /* Convert (A ^ B) & A to A & (~ B) since the latter is often a single
-        insn (and may simplify more).  */
-      else if (GET_CODE (XEXP (x, 0)) == XOR
-         && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
-         && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode,
-                         gen_unary (NOT, mode, XEXP (XEXP (x, 0), 1)),
-                         XEXP (x, 1));
-         goto restart;
-       }
-      else if (GET_CODE (XEXP (x, 0)) == XOR
-              && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 1))
-              && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode,
-                         gen_unary (NOT, mode, XEXP (XEXP (x, 0), 0)),
-                         XEXP (x, 1));
-         goto restart;
-       }
-
-      /* Similarly for (~ (A ^ B)) & A.  */
-      else if (GET_CODE (XEXP (x, 0)) == NOT
-              && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
-              && rtx_equal_p (XEXP (XEXP (XEXP (x, 0), 0), 0), XEXP (x, 1))
-              && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode, XEXP (XEXP (XEXP (x, 0), 0), 1),
-                         XEXP (x, 1));
-         goto restart;
-       }
-      else if (GET_CODE (XEXP (x, 0)) == NOT
-              && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR
-              && rtx_equal_p (XEXP (XEXP (XEXP (x, 0), 0), 1), XEXP (x, 1))
-              && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode, XEXP (XEXP (XEXP (x, 0), 0), 0),
-                         XEXP (x, 1));
-         goto restart;
-       }
-
-      /* If we have (and A B) with A not an object but that is known to
-        be -1 or 0, this is equivalent to the expression
-        (if_then_else (ne A (const_int 0)) B (const_int 0))
-        We make this conversion because it may allow further
-        simplifications and then allow use of conditional move insns.
-        If the machine doesn't have condition moves, code in case SET
-        will convert the IF_THEN_ELSE back to the logical operation.
-        We build the IF_THEN_ELSE here in case further simplification
-        is possible (e.g., we can convert it to ABS).  */
-
-      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o'
-         && ! (GET_CODE (XEXP (x, 0)) == SUBREG
-               && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o')
-         && (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-             == GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
-       {
-         rtx op0 = XEXP (x, 0);
-         rtx op1 = const0_rtx;
-         enum rtx_code comp_code
-           = simplify_comparison (NE, &op0, &op1);
-
-         x =  gen_rtx_combine (IF_THEN_ELSE, mode,
-                               gen_binary (comp_code, VOIDmode, op0, op1),
-                               XEXP (x, 1), const0_rtx);
-         goto restart;
-       }
+      if (GET_CODE (op0) == IOR
+         && (rtx_equal_p (XEXP (op0, 0), op1)
+             || rtx_equal_p (XEXP (op0, 1), op1))
+         && ! side_effects_p (XEXP (op0, 0))
+         && ! side_effects_p (XEXP (op0, 1)))
+       return op1;
 
       /* In the following group of tests (and those in case IOR below),
         we start with some combination of logical operations and apply
@@ -4440,128 +4482,118 @@ subst (x, from, to, in_dest, unique_copy)
         For example, (and (ior A B) (not B)) can occur as the result of
         expanding a bit field assignment.  When we apply the distributive
         law to this, we get (ior (and (A (not B))) (and (B (not B)))),
-        which then simplifies to (and (A (not B))).  */
+        which then simplifies to (and (A (not B))). 
 
-      /* If we have (and (ior A B) C), apply the distributive law and then
+        If we have (and (ior A B) C), apply the distributive law and then
         the inverse distributive law to see if things simplify.  */
 
-      if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == XOR)
+      if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
        {
          x = apply_distributive_law
-           (gen_binary (GET_CODE (XEXP (x, 0)), mode,
-                        gen_binary (AND, mode,
-                                    XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
-                        gen_binary (AND, mode,
-                                    XEXP (XEXP (x, 0), 1), XEXP (x, 1))));
+           (gen_binary (GET_CODE (op0), mode,
+                        gen_binary (AND, mode, XEXP (op0, 0), op1),
+                        gen_binary (AND, mode, XEXP (op0, 1), op1)));
          if (GET_CODE (x) != AND)
-           goto restart;
+           return x;
        }
 
-      if (GET_CODE (XEXP (x, 1)) == IOR || GET_CODE (XEXP (x, 1)) == XOR)
-       {
-         x = apply_distributive_law
-           (gen_binary (GET_CODE (XEXP (x, 1)), mode,
-                        gen_binary (AND, mode,
-                                    XEXP (XEXP (x, 1), 0), XEXP (x, 0)),
-                        gen_binary (AND, mode,
-                                    XEXP (XEXP (x, 1), 1), XEXP (x, 0))));
-         if (GET_CODE (x) != AND)
-           goto restart;
-       }
+      if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
+       return apply_distributive_law
+         (gen_binary (GET_CODE (op1), mode,
+                      gen_binary (AND, mode, XEXP (op1, 0), op0),
+                      gen_binary (AND, mode, XEXP (op1, 1), op0)));
 
       /* Similarly, taking advantage of the fact that
         (and (not A) (xor B C)) == (xor (ior A B) (ior A C))  */
 
-      if (GET_CODE (XEXP (x, 0)) == NOT && GET_CODE (XEXP (x, 1)) == XOR)
-       {
-         x = apply_distributive_law
-           (gen_binary (XOR, mode,
-                        gen_binary (IOR, mode, XEXP (XEXP (x, 0), 0),
-                                    XEXP (XEXP (x, 1), 0)),
-                        gen_binary (IOR, mode, XEXP (XEXP (x, 0), 0),
-                                    XEXP (XEXP (x, 1), 1))));
-         if (GET_CODE (x) != AND)
-           goto restart;
-       }
+      if (GET_CODE (op0) == NOT && GET_CODE (op1) == XOR)
+       return apply_distributive_law
+         (gen_binary (XOR, mode,
+                      gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
+                      gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 1))));
                                                            
-      else if (GET_CODE (XEXP (x, 1)) == NOT && GET_CODE (XEXP (x, 0)) == XOR)
-       {
-         x = apply_distributive_law
-           (gen_binary (XOR, mode,
-                        gen_binary (IOR, mode, XEXP (XEXP (x, 1), 0),
-                                    XEXP (XEXP (x, 0), 0)),
-                        gen_binary (IOR, mode, XEXP (XEXP (x, 1), 0),
-                                    XEXP (XEXP (x, 0), 1))));
-         if (GET_CODE (x) != AND)
-           goto restart;
-       }
+      else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
+       return apply_distributive_law
+         (gen_binary (XOR, mode,
+                      gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)),
+                      gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 1))));
       break;
 
     case IOR:
       /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+      if (GET_CODE (op1) == CONST_INT
          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (XEXP (x, 0), mode) & ~ INTVAL (XEXP (x, 1))) == 0)
-       return XEXP (x, 1);
+         && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
+       return op1;
 
       /* Convert (A & B) | A to A.  */
-      if (GET_CODE (XEXP (x, 0)) == AND
-         && (rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
-             || rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 1)))
-         && ! side_effects_p (XEXP (XEXP (x, 0), 0))
-         && ! side_effects_p (XEXP (XEXP (x, 0), 1)))
-       return XEXP (x, 1);
+      if (GET_CODE (op0) == AND
+         && (rtx_equal_p (XEXP (op0, 0), op1)
+             || rtx_equal_p (XEXP (op0, 1), op1))
+         && ! side_effects_p (XEXP (op0, 0))
+         && ! side_effects_p (XEXP (op0, 1)))
+       return op1;
 
       /* If we have (ior (and A B) C), apply the distributive law and then
         the inverse distributive law to see if things simplify.  */
 
-      if (GET_CODE (XEXP (x, 0)) == AND)
+      if (GET_CODE (op0) == AND)
        {
          x = apply_distributive_law
            (gen_binary (AND, mode,
-                        gen_binary (IOR, mode,
-                                    XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
-                        gen_binary (IOR, mode,
-                                    XEXP (XEXP (x, 0), 1), XEXP (x, 1))));
+                        gen_binary (IOR, mode, XEXP (op0, 0), op1),
+                        gen_binary (IOR, mode, XEXP (op0, 1), op1)));
 
          if (GET_CODE (x) != IOR)
-           goto restart;
+           return x;
        }
 
-      if (GET_CODE (XEXP (x, 1)) == AND)
+      if (GET_CODE (op1) == AND)
        {
          x = apply_distributive_law
            (gen_binary (AND, mode,
-                        gen_binary (IOR, mode,
-                                    XEXP (XEXP (x, 1), 0), XEXP (x, 0)),
-                        gen_binary (IOR, mode,
-                                    XEXP (XEXP (x, 1), 1), XEXP (x, 0))));
+                        gen_binary (IOR, mode, XEXP (op1, 0), op0),
+                        gen_binary (IOR, mode, XEXP (op1, 1), op0)));
 
          if (GET_CODE (x) != IOR)
-           goto restart;
+           return x;
        }
 
       /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
         mode size to (rotate A CX).  */
 
-      if (((GET_CODE (XEXP (x, 0)) == ASHIFT
-           && GET_CODE (XEXP (x, 1)) == LSHIFTRT)
-          || (GET_CODE (XEXP (x, 1)) == ASHIFT
-              && GET_CODE (XEXP (x, 0)) == LSHIFTRT))
-         && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 1), 0))
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
-         && (INTVAL (XEXP (XEXP (x, 0), 1)) + INTVAL (XEXP (XEXP (x, 1), 1))
+      if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
+          || (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT))
+         && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT
+         && GET_CODE (XEXP (op1, 1)) == CONST_INT
+         && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
              == GET_MODE_BITSIZE (mode)))
+       return gen_rtx (ROTATE, mode, XEXP (op0, 0),
+                       (GET_CODE (op0) == ASHIFT
+                        ? XEXP (op0, 1) : XEXP (op1, 1)));
+
+      /* If OP0 is (ashiftrt (plus ...) C), it might actually be
+        a (sign_extend (plus ...)).  If so, OP1 is a CONST_INT, and the PLUS
+        does not affect any of the bits in OP1, it can really be done
+        as a PLUS and we can associate.  We do this by seeing if OP1
+        can be safely shifted left C bits.  */
+      if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
+         && GET_CODE (XEXP (op0, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT
+         && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
        {
-         rtx shift_count;
+         int count = INTVAL (XEXP (op0, 1));
+         HOST_WIDE_INT mask = INTVAL (op1) << count;
 
-         if (GET_CODE (XEXP (x, 0)) == ASHIFT)
-           shift_count = XEXP (XEXP (x, 0), 1);
-         else
-           shift_count = XEXP (XEXP (x, 1), 1);
-         x = gen_rtx (ROTATE, mode, XEXP (XEXP (x, 0), 0), shift_count);
-         goto restart;
+         if (mask >> count == INTVAL (op1)
+             && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
+           {
+             SUBST (XEXP (XEXP (op0, 0), 1),
+                    GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask));
+             return op0;
+           }
        }
       break;
 
@@ -4571,146 +4603,69 @@ subst (x, from, to, in_dest, unique_copy)
         (NOT y).  */
       {
        int num_negated = 0;
-       rtx in1 = XEXP (x, 0), in2 = XEXP (x, 1);
 
-       if (GET_CODE (in1) == NOT)
-         num_negated++, in1 = XEXP (in1, 0);
-       if (GET_CODE (in2) == NOT)
-         num_negated++, in2 = XEXP (in2, 0);
+       if (GET_CODE (op0) == NOT)
+         num_negated++, op0 = XEXP (op0, 0);
+       if (GET_CODE (op1) == NOT)
+         num_negated++, op1 = XEXP (op1, 0);
 
        if (num_negated == 2)
          {
-           SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-           SUBST (XEXP (x, 1), XEXP (XEXP (x, 1), 0));
+           SUBST (XEXP (x, 0), op0);
+           SUBST (XEXP (x, 1), op1);
          }
        else if (num_negated == 1)
-         {
-           x =  gen_unary (NOT, mode,
-                           gen_binary (XOR, mode, in1, in2));
-           goto restart;
-         }
+         return gen_unary (NOT, mode, mode, gen_binary (XOR, mode, op0, op1));
       }
 
-      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
-        correspond to a machine insn or result in further simplifications
-        if B is a constant.  */
-
-      if (GET_CODE (XEXP (x, 0)) == AND
-         && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 1))
-         && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode,
-                         gen_unary (NOT, mode, XEXP (XEXP (x, 0), 0)),
-                         XEXP (x, 1));
-         goto restart;
-       }
-      else if (GET_CODE (XEXP (x, 0)) == AND
-              && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
-              && ! side_effects_p (XEXP (x, 1)))
-       {
-         x = gen_binary (AND, mode,
-                         gen_unary (NOT, mode, XEXP (XEXP (x, 0), 1)),
-                         XEXP (x, 1));
-         goto restart;
-       }
-
-
-#if STORE_FLAG_VALUE == 1
-      /* (xor (comparison foo bar) (const_int 1)) can become the reversed
-        comparison.  */
-      if (XEXP (x, 1) == const1_rtx
-         && 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));
-
-      /* (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
-        simplification.  */
-
-      if (XEXP (x, 1) == const1_rtx
-         && GET_CODE (XEXP (x, 0)) == LSHIFTRT
-         && 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);
-#endif
-
-      /* (xor (comparison foo bar) (const_int sign-bit))
-        when STORE_FLAG_VALUE is the sign bit.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (STORE_FLAG_VALUE
-             == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
-         && XEXP (x, 1) == const_true_rtx
-         && 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));
-      break;
-
-    case ABS:
-      /* (abs (neg <foo>)) -> (abs <foo>) */
-      if (GET_CODE (XEXP (x, 0)) == NEG)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-
-      /* If operand is something known to be positive, ignore the ABS.  */
-      if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
-         || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-              <= HOST_BITS_PER_WIDE_INT)
-             && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-                  & ((HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
-                 == 0)))
-       return XEXP (x, 0);
-
-
-      /* 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))
-       {
-         x = gen_rtx_combine (NEG, mode, XEXP (x, 0));
-         goto restart;
-       }
-      break;
-
-    case FFS:
-      /* (ffs (*_extend <X>)) = (ffs <X>) */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-         || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
+      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
+        correspond to a machine insn or result in further simplifications
+        if B is a constant.  */
 
-    case FLOAT:
-      /* (float (sign_extend <X>)) = (float <X>).  */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
+      if (GET_CODE (op0) == AND
+         && rtx_equal_p (XEXP (op0, 1), op1)
+         && ! side_effects_p (op1))
+       return gen_binary (AND, mode,
+                          gen_unary (NOT, mode, mode, XEXP (op0, 0)),
+                          op1);
 
-    case LSHIFT:
-    case ASHIFT:
-    case LSHIFTRT:
-    case ASHIFTRT:
-    case ROTATE:
-    case ROTATERT:
-      /* If this is a shift by a constant amount, simplify it.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
-       {
-         x = simplify_shift_const (x, code, mode, XEXP (x, 0), 
-                                   INTVAL (XEXP (x, 1)));
-         if (GET_CODE (x) != code)
-           goto restart;
-       }
+      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)),
+                          op1);
 
-#ifdef SHIFT_COUNT_TRUNCATED
-      else if (SHIFT_COUNT_TRUNCATED && GET_CODE (XEXP (x, 1)) != REG)
-       SUBST (XEXP (x, 1),
-              force_to_mode (XEXP (x, 1), GET_MODE (x),
-                             ((HOST_WIDE_INT) 1 
-                              << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
-                             - 1,
-                             NULL_RTX));
+#if STORE_FLAG_VALUE == 1
+      /* (xor (comparison foo bar) (const_int 1)) can become the reversed
+        comparison.  */
+      if (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));
+
+      /* (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
+        simplification.  */
+
+      if (op1 == const1_rtx
+         && 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);
 #endif
 
+      /* (xor (comparison foo bar) (const_int sign-bit))
+        when STORE_FLAG_VALUE is the sign bit.  */
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && (STORE_FLAG_VALUE
+             == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
+         && op1 == const_true_rtx
+         && GET_RTX_CLASS (GET_CODE (op0)) == '<'
+         && reversible_comparison_p (op0))
+       return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
+                               mode, XEXP (op0, 0), XEXP (op0, 1));
       break;
     }
 
@@ -4755,7 +4710,16 @@ expand_compound_operation (x)
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
        return x;
 
-      if (! FAKE_EXTEND_SAFE_P (GET_MODE (XEXP (x, 0)), XEXP (x, 0)))
+      /* Return if (subreg:MODE FROM 0) is not a safe replacement for
+        (zero_extend:MODE FROM) or (sign_extend:MODE FROM).  It is for any MEM
+        because (SUBREG (MEM...)) is guaranteed to cause the MEM to be
+        reloaded. If not for that, MEM's would very rarely be safe.
+
+        Reject MODEs bigger than a word, because we might not be able
+        to reference a two-register group starting with an arbitrary register
+        (and currently gen_lowpart might crash for a SUBREG).  */
+  
+      if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) > UNITS_PER_WORD)
        return x;
 
       len = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)));
@@ -4934,6 +4898,7 @@ expand_field_assignment (x)
                   gen_binary (IOR, compute_mode,
                               gen_binary (AND, compute_mode,
                                           gen_unary (NOT, compute_mode,
+                                                     compute_mode,
                                                      gen_binary (ASHIFT,
                                                                  compute_mode,
                                                                  mask, pos)),
@@ -5075,20 +5040,26 @@ make_extraction (mode, inner, pos, pos_rtx, len,
          MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (inner);
        }
       else if (GET_CODE (inner) == REG)
-       /* We can't call gen_lowpart_for_combine here since we always want
-          a SUBREG and it would sometimes return a new hard register.  */
-       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)
-                       : 0));
+       {
+         /* 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)
+                           : 0));
+         else
+           new = inner;
+       }
       else
        new = force_to_mode (inner, tmode,
                             len >= HOST_BITS_PER_WIDE_INT
                             ? GET_MODE_MASK (tmode)
                             : ((HOST_WIDE_INT) 1 << len) - 1,
-                            NULL_RTX);
+                            NULL_RTX, 0);
 
       /* If this extraction is going into the destination of a SET, 
         make a STRICT_LOW_PART unless we made a MEM.  */
@@ -5114,6 +5085,16 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       && ! in_compare && ! spans_byte && unsignedp)
     return 0;
 
+  /* Unless we are allowed to span bytes, reject this if we would be
+     spanning bytes or if the position is not a constant and the length
+     is not 1.  In all other cases, we would only be going outside
+     out object in cases when an original shift would have been
+     undefined.  */
+  if (! spans_byte
+      && ((pos_rtx == 0 && pos + len > GET_MODE_BITSIZE (is_mode))
+         || (pos_rtx != 0 && len != 1)))
+    return 0;
+
   /* Get the mode to use should INNER be a MEM, the mode for the position,
      and the mode for the result.  */
 #ifdef HAVE_insv
@@ -5232,7 +5213,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
                           pos_rtx || len + orig_pos >= HOST_BITS_PER_WIDE_INT
                           ? GET_MODE_MASK (extraction_mode)
                           : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
-                          NULL_RTX);
+                          NULL_RTX, 0);
 
   /* Adjust mode of POS_RTX, if needed.  If we want a wider mode, we
      have to zero extend.  Otherwise, we can just use a SUBREG.  */
@@ -5261,6 +5242,51 @@ make_extraction (mode, inner, pos, pos_rtx, len,
   return new;
 }
 \f
+/* See if X contains an ASHIFT of COUNT or more bits that can be commuted
+   with any other operations in X.  Return X without that shift if so.  */
+
+static rtx
+extract_left_shift (x, count)
+     rtx x;
+     int count;
+{
+  enum rtx_code code = GET_CODE (x);
+  enum machine_mode mode = GET_MODE (x);
+  rtx tem;
+
+  switch (code)
+    {
+    case ASHIFT:
+      /* This is the shift itself.  If it is wide enough, we will return
+        either the value being shifted if the shift count is equal to
+        COUNT or a shift for the difference.  */
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) >= count)
+       return simplify_shift_const (NULL_RTX, ASHIFT, mode, XEXP (x, 0),
+                                    INTVAL (XEXP (x, 1)) - count);
+      break;
+
+    case NEG:  case NOT:
+      if ((tem = extract_left_shift (XEXP (x, 0), count)) != 0)
+       return gen_unary (code, mode, mode, tem);
+
+      break;
+
+    case PLUS:  case IOR:  case XOR:  case AND:
+      /* If we can safely shift this constant and we find the inner shift,
+        make a new operation.  */
+      if (GET_CODE (XEXP (x,1)) == CONST_INT
+         && (INTVAL (XEXP (x, 1)) & (((HOST_WIDE_INT) 1 << count)) - 1) == 0
+         && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
+       return gen_binary (code, mode, tem, 
+                          GEN_INT (INTVAL (XEXP (x, 1)) >> count));
+
+      break;
+    }
+
+  return 0;
+}
+\f
 /* Look at the expression rooted at X.  Look for expressions
    equivalent to ZERO_EXTRACT, SIGN_EXTRACT, ZERO_EXTEND, SIGN_EXTEND.
    Form these expressions.
@@ -5287,8 +5313,9 @@ make_compound_operation (x, in_code)
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
   int mode_width = GET_MODE_BITSIZE (mode);
+  rtx rhs, lhs;
   enum rtx_code next_code;
-  int i, count;
+  int i;
   rtx new = 0;
   rtx tem;
   char *fmt;
@@ -5308,7 +5335,6 @@ make_compound_operation (x, in_code)
   switch (code)
     {
     case ASHIFT:
-    case LSHIFT:
       /* Convert shifts by constants into multiplications if inside
         an address.  */
       if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -5346,11 +5372,11 @@ make_compound_operation (x, in_code)
        {
          new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
                                         next_code);
-         new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0,
+         new = make_extraction (mode, new, 0,
                                 XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
                                 0, in_code == COMPARE);
        }
-      /* Same as previous, but for (xor/ior (lshift...) (lshift...)).  */
+      /* Same as previous, but for (xor/ior (lshiftrt...) (lshiftrt...)).  */
       else if ((GET_CODE (XEXP (x, 0)) == XOR
                || GET_CODE (XEXP (x, 0)) == IOR)
               && GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT
@@ -5443,81 +5469,38 @@ make_compound_operation (x, in_code)
       /* ... fall through ... */
 
     case ASHIFTRT:
+      lhs = XEXP (x, 0);
+      rhs = XEXP (x, 1);
+
       /* If we have (ashiftrt (ashift foo C1) C2) with C2 >= C1,
         this is a SIGN_EXTRACT.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && GET_CODE (XEXP (x, 0)) == ASHIFT
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (x, 0), 1)))
+      if (GET_CODE (rhs) == CONST_INT
+         && GET_CODE (lhs) == ASHIFT
+         && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+         && INTVAL (rhs) >= INTVAL (XEXP (lhs, 1)))
        {
-         new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new = make_compound_operation (XEXP (lhs, 0), next_code);
          new = make_extraction (mode, new,
-                                (INTVAL (XEXP (x, 1))
-                                 - INTVAL (XEXP (XEXP (x, 0), 1))),
-                                NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
-                                code == LSHIFTRT, 0, in_code == COMPARE);
-       }
-
-      /* Similarly if we have (ashifrt (OP (ashift foo C1) C3) C2).  In these
-        cases, we are better off returning a SIGN_EXTEND of the operation.  */
-
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND
-             || GET_CODE (XEXP (x, 0)) == XOR
-             || GET_CODE (XEXP (x, 0)) == PLUS)
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
-         && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
-         && INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)) < HOST_BITS_PER_WIDE_INT
-         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && 0 == (INTVAL (XEXP (XEXP (x, 0), 1))
-                  & (((HOST_WIDE_INT) 1
-                      << (MIN (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)),
-                               INTVAL (XEXP (x, 1)))
-                          - 1)))))
-       {
-         rtx c1 = XEXP (XEXP (XEXP (x, 0), 0), 1);
-         rtx c2 = XEXP (x, 1);
-         rtx c3 = XEXP (XEXP (x, 0), 1);
-         HOST_WIDE_INT newop1;
-         rtx inner = XEXP (XEXP (XEXP (x, 0), 0), 0);
-
-         /* If C1 > C2, INNER needs to have the shift performed on it
-            for C1-C2 bits.  */
-         if (INTVAL (c1) > INTVAL (c2))
-           {
-             inner = gen_binary (ASHIFT, mode, inner,
-                                 GEN_INT (INTVAL (c1) - INTVAL (c2)));
-             c1 = c2;
-           }
-
-         newop1 = INTVAL (c3) >> INTVAL (c1);
-         new = make_compound_operation (inner,
-                                        GET_CODE (XEXP (x, 0)) == PLUS
-                                        ? MEM : GET_CODE (XEXP (x, 0)));
-         new = make_extraction (mode,
-                                gen_binary (GET_CODE (XEXP (x, 0)), mode, new,
-                                            GEN_INT (newop1)),
-                                INTVAL (c2) - INTVAL (c1),
-                                NULL_RTX, mode_width - INTVAL (c2),
+                                INTVAL (rhs) - INTVAL (XEXP (lhs, 1)),
+                                NULL_RTX, mode_width - INTVAL (rhs),
                                 code == LSHIFTRT, 0, in_code == COMPARE);
        }
 
-      /* Similarly for (ashiftrt (neg (ashift FOO C1)) C2).  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && GET_CODE (XEXP (x, 0)) == NEG
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
-         && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
-       {
-         new = make_compound_operation (XEXP (XEXP (XEXP (x, 0), 0), 0),
-                                        next_code);
-         new = make_extraction (mode,
-                                gen_unary (GET_CODE (XEXP (x, 0)), mode, new),
-                                (INTVAL (XEXP (x, 1))
-                                 - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
-                                NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
-                                code == LSHIFTRT, 0, in_code == COMPARE);
-       }
+      /* See if we have operations between an ASHIFTRT and an ASHIFT.
+        If so, try to merge the shifts into a SIGN_EXTEND.  We could
+        also do this for some cases of SIGN_EXTRACT, but it doesn't
+        seem worth the effort; the case checked for occurs on Alpha.  */
+      
+      if (GET_RTX_CLASS (GET_CODE (lhs)) != 'o'
+         && ! (GET_CODE (lhs) == SUBREG
+               && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (lhs))) == 'o'))
+         && GET_CODE (rhs) == CONST_INT
+         && INTVAL (rhs) < HOST_BITS_PER_WIDE_INT
+         && (new = extract_left_shift (lhs, INTVAL (rhs))) != 0)
+       new = make_extraction (mode, make_compound_operation (new, next_code),
+                              0, NULL_RTX, mode_width - INTVAL (rhs),
+                              code == LSHIFTRT, 0, in_code == COMPARE);
+       
       break;
 
     case SUBREG:
@@ -5531,7 +5514,7 @@ make_compound_operation (x, in_code)
          && subreg_lowpart_p (x))
        {
          rtx newer = force_to_mode (tem, mode,
-                                    GET_MODE_MASK (mode), NULL_RTX);
+                                    GET_MODE_MASK (mode), NULL_RTX, 0);
 
          /* If we have something other than a SUBREG, we might have
             done an expansion, so rerun outselves.  */
@@ -5598,27 +5581,40 @@ get_pos_from_mask (m, plen)
    MODE.  If X is a CONST_INT, AND the CONST_INT with MASK.
 
    Also, if REG is non-zero and X is a register equal in value to REG, 
-   replace X with REG.  */
+   replace X with REG.
+
+   If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
+   are all off in X.  This is used when X will be complemented, by either
+   NOT, NEG, or XOR.  */
 
 static rtx
-force_to_mode (x, mode, mask, reg)
+force_to_mode (x, mode, mask, reg, just_select)
      rtx x;
      enum machine_mode mode;
      unsigned HOST_WIDE_INT mask;
      rtx reg;
+     int just_select;
 {
   enum rtx_code code = GET_CODE (x);
+  int next_select = just_select || code == XOR || code == NOT || code == NEG;
   enum machine_mode op_mode;
   unsigned HOST_WIDE_INT fuller_mask, nonzero;
   rtx op0, op1, temp;
 
+  /* If this is a CALL, don't do anything.  Some of the code below
+     will do the wrong thing since the mode of a CALL is VOIDmode.  */
+  if (code == CALL)
+    return x;
+
   /* We want to perform the operation is its present mode unless we know
      that the operation is valid in MODE, in which case we do the operation
      in MODE.  */
-  op_mode = ((code_to_optab[(int) code] != 0
+  op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x))
+             && code_to_optab[(int) code] != 0
              && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
                  != CODE_FOR_nothing))
             ? mode : GET_MODE (x));
+
   /* It is not valid to do a right-shift in a narrower mode
      than the one it came in with.  */
   if ((code == LSHIFTRT || code == ASHIFTRT)
@@ -5643,7 +5639,7 @@ force_to_mode (x, mode, mask, reg)
   nonzero = nonzero_bits (x, mode);
 
   /* If none of the bits in X are needed, return a zero.  */
-  if ((nonzero & mask) == 0)
+  if (! just_select && (nonzero & mask) == 0)
     return const0_rtx;
 
   /* If X is a CONST_INT, return a new one.  Do this here since the
@@ -5662,13 +5658,15 @@ force_to_mode (x, mode, mask, reg)
       return GEN_INT (cval);
     }
 
-  /* If X is narrower than MODE, just get X in the proper mode.  */
-  if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
+  /* If X is narrower than MODE and we want all the bits in X's mode, just
+     get X in the proper mode.  */
+  if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)
+      && (GET_MODE_MASK (GET_MODE (x)) & ~ mask) == 0)
     return gen_lowpart_for_combine (mode, x);
 
-  /* If we aren't changing the mode and all zero bits in MASK are already
-     known to be zero in X, we need not do anything.  */
-  if (GET_MODE (x) == mode && (~ mask & nonzero) == 0)
+  /* If we aren't changing the mode, X is not a SUBREG, and all zero bits in
+     MASK are already known to be zero in X, we need not do anything.  */
+  if (GET_MODE (x) == mode && code != SUBREG && (~ mask & nonzero) == 0)
     return x;
 
   switch (code)
@@ -5684,7 +5682,7 @@ force_to_mode (x, mode, mask, reg)
         spanned the boundary of the MEM.  If we are now masking so it is
         within that boundary, we don't need the USE any more.  */
       if ((mask & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg);
+       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 #endif
 
     case SIGN_EXTEND:
@@ -5693,7 +5691,7 @@ force_to_mode (x, mode, mask, reg)
     case SIGN_EXTRACT:
       x = expand_compound_operation (x);
       if (GET_CODE (x) != code)
-       return force_to_mode (x, mode, mask, reg);
+       return force_to_mode (x, mode, mask, reg, next_select);
       break;
 
     case REG:
@@ -5704,19 +5702,15 @@ force_to_mode (x, mode, mask, reg)
 
     case SUBREG:
       if (subreg_lowpart_p (x)
-         /* We can ignore the effect this SUBREG if it narrows the mode or,
-            on machines where register operations are performed on the full
-            word, if the constant masks to zero all the bits the mode
-            doesn't have.  */
+         /* We can ignore the effect of this SUBREG if it narrows the mode or
+            if the constant masks to zero all the bits the mode doesn't
+            have.  */
          && ((GET_MODE_SIZE (GET_MODE (x))
               < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-#ifdef WORD_REGISTER_OPERATIONS
              || (0 == (mask
                        & GET_MODE_MASK (GET_MODE (x))
-                       & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))
-#endif
-             ))
-       return force_to_mode (SUBREG_REG (x), mode, mask, reg);
+                       & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
+       return force_to_mode (SUBREG_REG (x), mode, mask, reg, next_select);
       break;
 
     case AND:
@@ -5731,13 +5725,37 @@ force_to_mode (x, mode, mask, reg)
                                      mask & INTVAL (XEXP (x, 1)));
 
          /* If X is still an AND, see if it is an AND with a mask that
-            is just some low-order bits.  If so, and it is BITS wide (it
-            can't be wider), we don't need it.  */
+            is just some low-order bits.  If so, and it is MASK, we don't
+            need it.  */
 
          if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
              && INTVAL (XEXP (x, 1)) == mask)
            x = XEXP (x, 0);
 
+         /* If it remains an AND, try making another AND with the bits
+            in the mode mask that aren't in MASK turned on.  If the
+            constant in the AND is wide enough, this might make a
+            cheaper constant.  */
+
+         if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
+             && GET_MODE_MASK (GET_MODE (x)) != mask)
+           {
+             HOST_WIDE_INT cval = (INTVAL (XEXP (x, 1))
+                                   | (GET_MODE_MASK (GET_MODE (x)) & ~ mask));
+             int width = GET_MODE_BITSIZE (GET_MODE (x));
+             rtx y;
+
+             /* If MODE is narrower that HOST_WIDE_INT and CVAL is a negative
+                number, sign extend it.  */
+             if (width > 0 && width < HOST_BITS_PER_WIDE_INT
+                 && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
+               cval |= (HOST_WIDE_INT) -1 << width;
+
+             y = gen_binary (AND, GET_MODE (x), XEXP (x, 0), GEN_INT (cval));
+             if (rtx_cost (y, SET) < rtx_cost (x, SET))
+               x = y;
+           }
+
          break;
        }
 
@@ -5754,7 +5772,7 @@ force_to_mode (x, mode, mask, reg)
          && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
        return force_to_mode (plus_constant (XEXP (x, 0),
                                             INTVAL (XEXP (x, 1)) & mask),
-                             mode, mask, reg);
+                             mode, mask, reg, next_select);
 
       /* ... fall through ... */
 
@@ -5789,17 +5807,19 @@ force_to_mode (x, mode, mask, reg)
          temp = gen_binary (GET_CODE (x), GET_MODE (x),
                             XEXP (XEXP (x, 0), 0), temp);
          x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (x, 1));
-         return force_to_mode (x, mode, mask, reg);
+         return force_to_mode (x, mode, mask, reg, next_select);
        }
 
     binop:
       /* For most binary operations, just propagate into the operation and
         change the mode if we have an operation of that mode.   */
 
-      op0 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 0),
-                                                            mode, mask, reg));
-      op1 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 1),
-                                                            mode, mask, reg));
+      op0 = gen_lowpart_for_combine (op_mode,
+                                    force_to_mode (XEXP (x, 0), mode, mask,
+                                                   reg, next_select));
+      op1 = gen_lowpart_for_combine (op_mode,
+                                    force_to_mode (XEXP (x, 1), mode, mask,
+                                                   reg, next_select));
 
       /* If OP1 is a CONST_INT and X is an IOR or XOR, clear bits outside
         MASK since OP1 might have been sign-extended but we never want
@@ -5814,7 +5834,6 @@ force_to_mode (x, mode, mask, reg)
       break;
 
     case ASHIFT:
-    case LSHIFT:
       /* For left shifts, do the same, but just for the first operand.
         However, we cannot do anything with shifts where we cannot
         guarantee that the counts are smaller than the size of the mode
@@ -5842,7 +5861,7 @@ force_to_mode (x, mode, mask, reg)
 
       op0 = gen_lowpart_for_combine (op_mode,
                                     force_to_mode (XEXP (x, 0), op_mode,
-                                                   mask, reg));
+                                                   mask, reg, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x =  gen_binary (code, op_mode, op0, XEXP (x, 1));
@@ -5869,7 +5888,7 @@ force_to_mode (x, mode, mask, reg)
              || (mask & ~ GET_MODE_MASK (op_mode)) != 0)
            op_mode = GET_MODE (x);
 
-         inner = force_to_mode (inner, op_mode, mask, reg);
+         inner = force_to_mode (inner, op_mode, mask, reg, next_select);
 
          if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
            x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
@@ -5897,7 +5916,7 @@ force_to_mode (x, mode, mask, reg)
         all, even if it has a variable count.  */
       if (mask == ((HOST_WIDE_INT) 1
                   << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))
-       return force_to_mode (XEXP (x, 0), mode, mask, reg);
+       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 
       /* If this is a shift by a constant, get a mask that contains those bits
         that are not copies of the sign bit.  We then have two cases:  If
@@ -5923,7 +5942,7 @@ force_to_mode (x, mode, mask, reg)
                 : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
 
              if (GET_CODE (x) != ASHIFTRT)
-               return force_to_mode (x, mode, mask, reg);
+               return force_to_mode (x, mode, mask, reg, next_select);
            }
        }
 
@@ -5944,7 +5963,8 @@ force_to_mode (x, mode, mask, reg)
          && GET_CODE (XEXP (x, 0)) == ASHIFT
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
          && INTVAL (XEXP (XEXP (x, 0), 1)) == INTVAL (XEXP (x, 1)))
-       return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask, reg);
+       return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
+                             reg, next_select);
 
       break;
 
@@ -5960,14 +5980,19 @@ force_to_mode (x, mode, mask, reg)
          temp = simplify_binary_operation (code == ROTATE ? ROTATERT : ROTATE,
                                            GET_MODE (x), GEN_INT (mask),
                                            XEXP (x, 1));
-         if (temp)
+         if (temp && GET_CODE(temp) == CONST_INT)
            SUBST (XEXP (x, 0),
                   force_to_mode (XEXP (x, 0), GET_MODE (x),
-                                 INTVAL (temp), reg));
+                                 INTVAL (temp), reg, next_select));
        }
       break;
        
     case NEG:
+      /* If we just want the low-order bit, the NEG isn't needed since it
+        won't change the low-order bit.    */
+      if (mask == 1)
+       return force_to_mode (XEXP (x, 0), mode, mask, reg, just_select);
+
       /* We need any bits less significant than the most significant bit in
         MASK since carries from those bits will affect the bits we are
         interested in.  */
@@ -5990,14 +6015,15 @@ force_to_mode (x, mode, mask, reg)
          temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp);
          x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1));
 
-         return force_to_mode (x, mode, mask, reg);
+         return force_to_mode (x, mode, mask, reg, next_select);
        }
 
     unop:
-      op0 = gen_lowpart_for_combine (op_mode, force_to_mode (XEXP (x, 0), mode,
-                                                            mask, reg));
+      op0 = gen_lowpart_for_combine (op_mode,
+                                    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, op0);
+       x = gen_unary (code, op_mode, op_mode, op0);
       break;
 
     case NE:
@@ -6006,7 +6032,7 @@ force_to_mode (x, mode, mask, reg)
         in CONST.  */
       if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 0) == const0_rtx
          && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg);
+       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 
       break;
 
@@ -6017,11 +6043,11 @@ force_to_mode (x, mode, mask, reg)
       SUBST (XEXP (x, 1),
             gen_lowpart_for_combine (GET_MODE (x),
                                      force_to_mode (XEXP (x, 1), mode,
-                                                    mask, reg)));
+                                                    mask, reg, next_select)));
       SUBST (XEXP (x, 2),
             gen_lowpart_for_combine (GET_MODE (x),
                                      force_to_mode (XEXP (x, 2), mode,
-                                                    mask, reg)));
+                                                    mask, reg,next_select)));
       break;
     }
 
@@ -6029,6 +6055,178 @@ force_to_mode (x, mode, mask, reg)
   return gen_lowpart_for_combine (mode, x);
 }
 \f
+/* Return nonzero if X is an expression that has one of two values depending on
+   whether some other value is zero or nonzero.  In that case, we return the
+   value that is being tested, *PTRUE is set to the value if the rtx being
+   returned has a nonzero value, and *PFALSE is set to the other alternative.
+
+   If we return zero, we set *PTRUE and *PFALSE to X.  */
+
+static rtx
+if_then_else_cond (x, ptrue, pfalse)
+     rtx x;
+     rtx *ptrue, *pfalse;
+{
+  enum machine_mode mode = GET_MODE (x);
+  enum rtx_code code = GET_CODE (x);
+  int size = GET_MODE_BITSIZE (mode);
+  rtx cond0, cond1, true0, true1, false0, false1;
+  unsigned HOST_WIDE_INT nz;
+
+  /* If this is a unary operation whose operand has one of two values, apply
+     our opcode to compute those values.  */
+  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);
+      return cond0;
+    }
+
+  /* If this is a COMPARE, do nothing, since the IF_THEN_ELSE we would
+     make can't possibly match and would supress other optimizations.  */
+  else if (code == COMPARE)
+    ;
+
+  /* If this is a binary operation, see if either side has only one of two
+     values.  If either one does or if both do and they are conditional on
+     the same value, compute the new true and false values.  */
+  else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2'
+          || GET_RTX_CLASS (code) == '<')
+    {
+      cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0);
+      cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1);
+
+      if ((cond0 != 0 || cond1 != 0)
+         && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
+       {
+         *ptrue = gen_binary (code, mode, true0, true1);
+         *pfalse = gen_binary (code, mode, false0, false1);
+         return cond0 ? cond0 : cond1;
+       }
+
+#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
+
+      /* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the
+        operands is zero when the other is non-zero, and vice-versa.  */
+
+      if ((code == PLUS || code == IOR || code == XOR || code == MINUS
+          || code == UMAX)
+         && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
+       {
+         rtx op0 = XEXP (XEXP (x, 0), 1);
+         rtx op1 = XEXP (XEXP (x, 1), 1);
+
+         cond0 = XEXP (XEXP (x, 0), 0);
+         cond1 = XEXP (XEXP (x, 1), 0);
+
+         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))
+                  && 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)))
+                     && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
+                     && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
+             && ! side_effects_p (x))
+           {
+             *ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
+             *pfalse = gen_binary (MULT, mode, 
+                                   (code == MINUS 
+                                    ? gen_unary (NEG, mode, mode, op1) : op1),
+                                   const_true_rtx);
+             return cond0;
+           }
+       }
+
+      /* Similarly for MULT, AND and UMIN, execpt that for these the result
+        is always zero.  */
+      if ((code == MULT || code == AND || code == UMIN)
+         && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
+       {
+         cond0 = XEXP (XEXP (x, 0), 0);
+         cond1 = XEXP (XEXP (x, 1), 0);
+
+         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))
+                  && 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)))
+                     && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
+                     && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
+             && ! side_effects_p (x))
+           {
+             *ptrue = *pfalse = const0_rtx;
+             return cond0;
+           }
+       }
+#endif
+    }
+
+  else if (code == IF_THEN_ELSE)
+    {
+      /* If we have IF_THEN_ELSE already, extract the condition and
+        canonicalize it if it is NE or EQ.  */
+      cond0 = XEXP (x, 0);
+      *ptrue = XEXP (x, 1), *pfalse = XEXP (x, 2);
+      if (GET_CODE (cond0) == NE && XEXP (cond0, 1) == const0_rtx)
+       return XEXP (cond0, 0);
+      else if (GET_CODE (cond0) == EQ && XEXP (cond0, 1) == const0_rtx)
+       {
+         *ptrue = XEXP (x, 2), *pfalse = XEXP (x, 1);
+         return XEXP (cond0, 0);
+       }
+      else
+       return cond0;
+    }
+
+  /* If X is a normal SUBREG with both inner and outer modes integral,
+     we can narrow both the true and false values of the inner expression,
+     if there is a condition.  */
+  else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT
+          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
+          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+          && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
+                                              &true0, &false0)))
+    {
+      *ptrue = force_to_mode (true0, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
+      *pfalse
+       = force_to_mode (false0, mode, GET_MODE_MASK (mode), NULL_RTX, 0);
+
+      return cond0;
+    }
+
+  /* If X is a constant, this isn't special and will cause confusions
+     if we treat it as such.  Likewise if it is equivalent to a constant.  */
+  else if (CONSTANT_P (x)
+          || ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0)))
+    ;
+
+  /* If X is known to be either 0 or -1, those are the true and 
+     false values when testing X.  */
+  else if (num_sign_bit_copies (x, mode) == size)
+    {
+      *ptrue = constm1_rtx, *pfalse = const0_rtx;
+      return x;
+    }
+
+  /* Likewise for 0 or a single bit.  */
+  else if (exact_log2 (nz = nonzero_bits (x, mode)) >= 0)
+    {
+      *ptrue = GEN_INT (nz), *pfalse = const0_rtx;
+      return x;
+    }
+
+  /* Otherwise fail; show no condition with true and false values the same.  */
+  *ptrue = *pfalse = x;
+  return 0;
+}
+\f
 /* Return the value of expression X given the fact that condition COND
    is known to be true when applied to REG as its first operand and VAL
    as its second.  X is known to not be shared and so can be modified in
@@ -6044,7 +6242,7 @@ known_cond (x, cond, reg, val)
      rtx reg, val;
 {
   enum rtx_code code = GET_CODE (x);
-  rtx new, temp;
+  rtx temp;
   char *fmt;
   int i, j;
 
@@ -6063,7 +6261,8 @@ 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)), XEXP (x, 0));
+       return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)),
+                         XEXP (x, 0));
       }
 
   /* The only other cases we handle are MIN, MAX, and comparisons if the
@@ -6130,7 +6329,6 @@ make_field_assignment (x)
 {
   rtx dest = SET_DEST (x);
   rtx src = SET_SRC (x);
-  rtx ourdest;
   rtx assign;
   HOST_WIDE_INT c1;
   int pos, len;
@@ -6229,7 +6427,7 @@ make_field_assignment (x)
                       GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
                       ? GET_MODE_MASK (mode)
                       : ((HOST_WIDE_INT) 1 << len) - 1,
-                      dest);
+                      dest, 0);
 
   return gen_rtx_combine (SET, VOIDmode, assign, src);
 }
@@ -6288,8 +6486,7 @@ apply_distributive_law (x)
       break;
 
     case ASHIFT:
-    case LSHIFT:
-      /* These are also multiplies, so they distribute over everything.  */
+      /* This is also a multiply, so it distributes over everything.  */
       break;
 
     case SUBREG:
@@ -6348,7 +6545,7 @@ apply_distributive_law (x)
   if (code == XOR && inner_code == IOR)
     {
       inner_code = AND;
-      other = gen_unary (NOT, GET_MODE (x), other);
+      other = gen_unary (NOT, GET_MODE (x), GET_MODE (x), other);
     }
 
   /* We may be able to continuing distributing the result, so call
@@ -6371,14 +6568,12 @@ simplify_and_const_int (x, mode, varop, constop)
      rtx varop;
      unsigned HOST_WIDE_INT constop;
 {
-  register enum machine_mode tmode;
-  register rtx temp;
   unsigned HOST_WIDE_INT nonzero;
   int i;
 
   /* Simplify VAROP knowing that we will be only looking at some of the
      bits in it.  */
-  varop = force_to_mode (varop, mode, constop, NULL_RTX);
+  varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
 
   /* If VAROP is a CLOBBER, we will fail so return it; if it is a
      CONST_INT, we are done.  */
@@ -6474,6 +6669,10 @@ nonzero_bits (x, mode)
   int mode_width = GET_MODE_BITSIZE (mode);
   rtx tem;
 
+  /* For floating-point values, assume all bits are needed.  */
+  if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
+    return nonzero;
+
   /* If X is wider than MODE, use its mode instead.  */
   if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
     {
@@ -6758,7 +6957,6 @@ nonzero_bits (x, mode)
     case ASHIFTRT:
     case LSHIFTRT:
     case ASHIFT:
-    case LSHIFT:
     case ROTATE:
       /* The nonzero bits are in two classes: any bits within MODE
         that aren't in GET_MODE (x) are always significant.  The rest of the
@@ -6793,7 +6991,7 @@ nonzero_bits (x, mode)
              if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
                inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
            }
-         else if (code == LSHIFT || code == ASHIFT)
+         else if (code == ASHIFT)
            inner <<= count;
          else
            inner = ((inner << (count % width)
@@ -6834,12 +7032,13 @@ num_sign_bit_copies (x, mode)
   rtx tem;
 
   /* If we weren't given a mode, use the mode of X.  If the mode is still
-     VOIDmode, we don't know anything.  */
+     VOIDmode, we don't know anything.  Likewise if one of the modes is
+     floating-point.  */
 
   if (mode == VOIDmode)
     mode = GET_MODE (x);
 
-  if (mode == VOIDmode)
+  if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
     return 1;
 
   bitwidth = GET_MODE_BITSIZE (mode);
@@ -6849,6 +7048,14 @@ num_sign_bit_copies (x, mode)
     return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
                    - (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
      
+#ifndef WORD_REGISTER_OPERATIONS
+  /* If this machine does not do all register operations on the entire
+     register and MODE is wider than the mode of X, we can say nothing
+     at all about the high-order bits.  */
+  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
+    return 1;
+#endif
+
   switch (code)
     {
     case REG:
@@ -7053,7 +7260,6 @@ num_sign_bit_copies (x, mode)
       return num0;
 
     case ASHIFT:
-    case LSHIFT:
       /* Left shifts destroy copies.  */
       if (GET_CODE (XEXP (x, 1)) != CONST_INT
          || INTVAL (XEXP (x, 1)) < 0
@@ -7301,10 +7507,6 @@ simplify_shift_const (x, code, result_mode, varop, count)
       if (code == ROTATERT)
        code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count;
 
-      /* Canonicalize LSHIFT to ASHIFT.  */
-      if (code == LSHIFT)
-       code = ASHIFT;
-
       /* We need to determine what mode we will do the shift in.  If the
         shift is a ASHIFTRT or ROTATE, we must always do it in the mode it
         was originally done in.  Otherwise, we can do it in MODE, the widest
@@ -7496,7 +7698,6 @@ simplify_shift_const (x, code, result_mode, varop, count)
 
        case LSHIFTRT:
        case ASHIFT:
-       case LSHIFT:
        case ROTATE:
          /* Here we have two nested shifts.  The result is usually the
             AND of a new shift with a mask.  We compute the result below.  */
@@ -7510,10 +7711,6 @@ simplify_shift_const (x, code, result_mode, varop, count)
              int first_count = INTVAL (XEXP (varop, 1));
              unsigned HOST_WIDE_INT mask;
              rtx mask_rtx;
-             rtx inner;
-
-             if (first_code == LSHIFT)
-               first_code = ASHIFT;
 
              /* We have one common special case.  We can't do any merging if
                 the inner code is an ASHIFTRT of a smaller mode.  However, if
@@ -7694,6 +7891,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
              && (new = simplify_binary_operation (code, result_mode,
                                                   XEXP (varop, 1),
                                                   GEN_INT (count))) != 0
+             && GET_CODE(new) == CONST_INT
              && merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
                                  INTVAL (new), result_mode, &complement_p))
            {
@@ -7710,7 +7908,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
            rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
                                            XEXP (varop, 1), count);
 
-           varop = gen_binary (GET_CODE (varop), GET_MODE (varop), lhs, rhs);
+           varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
            varop = apply_distributive_law (varop);
 
            count = 0;
@@ -7718,11 +7916,11 @@ simplify_shift_const (x, code, result_mode, varop, count)
          break;
 
        case EQ:
-         /* convert (lshift (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
+         /* convert (lshiftrt (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
             says that the sign bit can be tested, FOO has mode MODE, C is
-            GET_MODE_BITSIZE (MODE) - 1, and FOO has only the low-order bit
-            may be nonzero.  */
-         if (code == LSHIFT
+            GET_MODE_BITSIZE (MODE) - 1, and FOO has only its low-order bit
+            that may be nonzero.  */
+         if (code == LSHIFTRT
              && XEXP (varop, 1) == const0_rtx
              && GET_MODE (XEXP (varop, 0)) == result_mode
              && count == GET_MODE_BITSIZE (result_mode) - 1
@@ -7813,6 +8011,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
              && (new = simplify_binary_operation (ASHIFT, result_mode,
                                                   XEXP (varop, 1),
                                                   GEN_INT (count))) != 0
+             && GET_CODE(new) == CONST_INT
              && merge_outer_ops (&outer_op, &outer_const, PLUS,
                                  INTVAL (new), result_mode, &complement_p))
            {
@@ -7920,7 +8119,7 @@ simplify_shift_const (x, code, result_mode, varop, 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, x);
+    x = gen_unary (NOT, result_mode, result_mode, x);
 
   if (outer_op != NIL)
     {
@@ -7934,7 +8133,7 @@ simplify_shift_const (x, code, result_mode, varop, 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, x);
+       x = gen_unary (outer_op, result_mode, result_mode, x);
       else
        x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
     }
@@ -8147,21 +8346,26 @@ gen_lowpart_for_combine (mode, x)
 
 /*VARARGS2*/
 static rtx
-gen_rtx_combine (va_alist)
-     va_dcl
+gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 {
-  va_list p;
+#ifndef __STDC__
   enum rtx_code code;
   enum machine_mode mode;
+#endif
+  va_list p;
   int n_args;
   rtx args[3];
   int i, j;
   char *fmt;
   rtx rt;
 
-  va_start (p);
+  VA_START (p, mode);
+
+#ifndef __STDC__
   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);
 
@@ -8227,6 +8431,16 @@ gen_binary (code, mode, op0, op1)
   if (GET_RTX_CLASS (code) == '<') 
     {
       enum machine_mode op_mode = GET_MODE (op0);
+
+      /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get 
+        just (REL_OP X Y). */
+      if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+       {
+         op1 = XEXP (op0, 1);
+         op0 = XEXP (op0, 0);
+         op_mode = GET_MODE (op0);
+       }
+
       if (op_mode == VOIDmode)
        op_mode = GET_MODE (op1);
       result = simplify_relational_operation (code, op_mode, op0, op1);
@@ -8251,12 +8465,12 @@ gen_binary (code, mode, op0, op1)
 }
 
 static rtx
-gen_unary (code, mode, op0)
+gen_unary (code, mode, op0_mode, op0)
      enum rtx_code code;
-     enum machine_mode mode;
+     enum machine_mode mode, op0_mode;
      rtx op0;
 {
-  rtx result = simplify_unary_operation (code, mode, op0, mode);
+  rtx result = simplify_unary_operation (code, mode, op0, op0_mode);
 
   if (result)
     return result;
@@ -8290,6 +8504,34 @@ simplify_comparison (code, pop0, pop1)
   /* Try a few ways of applying the same transformation to both operands.  */
   while (1)
     {
+#ifndef WORD_REGISTER_OPERATIONS
+      /* The test below this one won't handle SIGN_EXTENDs on these machines,
+        so check specially.  */
+      if (code != GTU && code != GEU && code != LTU && code != LEU
+         && GET_CODE (op0) == ASHIFTRT && GET_CODE (op1) == ASHIFTRT
+         && GET_CODE (XEXP (op0, 0)) == ASHIFT
+         && GET_CODE (XEXP (op1, 0)) == ASHIFT
+         && GET_CODE (XEXP (XEXP (op0, 0), 0)) == SUBREG
+         && GET_CODE (XEXP (XEXP (op1, 0), 0)) == SUBREG
+         && (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0)))
+             == GET_MODE (SUBREG_REG (XEXP (XEXP (op1, 0), 0))))
+         && GET_CODE (XEXP (op0, 1)) == CONST_INT
+         && GET_CODE (XEXP (op1, 1)) == CONST_INT
+         && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
+         && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT
+         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (op1, 1))
+         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op0, 0), 1))
+         && INTVAL (XEXP (op0, 1)) == INTVAL (XEXP (XEXP (op1, 0), 1))
+         && (INTVAL (XEXP (op0, 1))
+             == (GET_MODE_BITSIZE (GET_MODE (op0))
+                 - (GET_MODE_BITSIZE
+                    (GET_MODE (SUBREG_REG (XEXP (XEXP (op0, 0), 0))))))))
+       {
+         op0 = SUBREG_REG (XEXP (XEXP (op0, 0), 0));
+         op1 = SUBREG_REG (XEXP (XEXP (op1, 0), 0));
+       }
+#endif
+
       /* If both operands are the same constant shift, see if we can ignore the
         shift.  We can if the shift is a rotate or if the bits shifted out of
         this shift are known to be zero for both inputs and if the type of
@@ -8297,8 +8539,7 @@ simplify_comparison (code, pop0, pop1)
       if (GET_CODE (op0) == GET_CODE (op1)
          && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
          && ((GET_CODE (op0) == ROTATE && (code == NE || code == EQ))
-             || ((GET_CODE (op0) == LSHIFTRT
-                  || GET_CODE (op0) == ASHIFT || GET_CODE (op0) == LSHIFT)
+             || ((GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFT)
                  && (code != GT && code != LT && code != GE && code != LE))
              || (GET_CODE (op0) == ASHIFTRT
                  && (code != GTU && code != LTU
@@ -8314,7 +8555,7 @@ simplify_comparison (code, pop0, pop1)
 
          if (GET_CODE (op0) == LSHIFTRT || GET_CODE (op0) == ASHIFTRT)
            mask &= (mask >> shift_count) << shift_count;
-         else if (GET_CODE (op0) == ASHIFT || GET_CODE (op0) == LSHIFT)
+         else if (GET_CODE (op0) == ASHIFT)
            mask = (mask & (mask << shift_count)) >> shift_count;
 
          if ((nonzero_bits (XEXP (op0, 0), mode) & ~ mask) == 0
@@ -8331,33 +8572,68 @@ simplify_comparison (code, pop0, pop1)
         and the operand's possibly nonzero bits are 0xffffff01; in that case
         if we only care about QImode, we don't need the AND).  This case
         occurs if the output mode of an scc insn is not SImode and
-        STORE_FLAG_VALUE == 1 (e.g., the 386).  */
+        STORE_FLAG_VALUE == 1 (e.g., the 386).
+
+        Similarly, check for a case where the AND's are ZERO_EXTEND
+        operations from some narrower mode even though a SUBREG is not
+        present.  */
 
       else if  (GET_CODE (op0) == AND && GET_CODE (op1) == AND
                && GET_CODE (XEXP (op0, 1)) == CONST_INT
-               && GET_CODE (XEXP (op1, 1)) == CONST_INT
-               && GET_CODE (XEXP (op0, 0)) == SUBREG
-               && GET_CODE (XEXP (op1, 0)) == SUBREG
-               && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
-                   > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
-               && (GET_MODE (SUBREG_REG (XEXP (op0, 0)))
-                   == GET_MODE (SUBREG_REG (XEXP (op1, 0))))
-               && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
-                   <= HOST_BITS_PER_WIDE_INT)
-               && (nonzero_bits (SUBREG_REG (XEXP (op0, 0)),
-                                     GET_MODE (SUBREG_REG (XEXP (op0, 0))))
-                   & ~ INTVAL (XEXP (op0, 1))) == 0
-               && (nonzero_bits (SUBREG_REG (XEXP (op1, 0)),
-                                     GET_MODE (SUBREG_REG (XEXP (op1, 0))))
-                   & ~ INTVAL (XEXP (op1, 1))) == 0)
-       {
-         op0 = SUBREG_REG (XEXP (op0, 0));
-         op1 = SUBREG_REG (XEXP (op1, 0));
+               && GET_CODE (XEXP (op1, 1)) == CONST_INT)
+       {
+         rtx inner_op0 = XEXP (op0, 0);
+         rtx inner_op1 = XEXP (op1, 0);
+         HOST_WIDE_INT c0 = INTVAL (XEXP (op0, 1));
+         HOST_WIDE_INT c1 = INTVAL (XEXP (op1, 1));
+         int changed = 0;
+               
+         if (GET_CODE (inner_op0) == SUBREG && GET_CODE (inner_op1) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (inner_op0))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
+             && (GET_MODE (SUBREG_REG (inner_op0))
+                 == GET_MODE (SUBREG_REG (inner_op1)))
+             && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+                 <= HOST_BITS_PER_WIDE_INT)
+             && (0 == (~c0) & nonzero_bits (SUBREG_REG (inner_op0),
+                                            GET_MODE (SUBREG_REG (op0))))
+             && (0 == (~c1) & nonzero_bits (SUBREG_REG (inner_op1),
+                                            GET_MODE (SUBREG_REG (inner_op1)))))
+           {
+             op0 = SUBREG_REG (inner_op0);
+             op1 = SUBREG_REG (inner_op1);
+
+             /* The resulting comparison is always unsigned since we masked
+                off the original sign bit. */
+             code = unsigned_condition (code);
+
+             changed = 1;
+           }
+
+         else if (c0 == c1)
+           for (tmode = GET_CLASS_NARROWEST_MODE
+                (GET_MODE_CLASS (GET_MODE (op0)));
+                tmode != GET_MODE (op0); tmode = GET_MODE_WIDER_MODE (tmode))
+             if (c0 == GET_MODE_MASK (tmode))
+               {
+                 op0 = gen_lowpart_for_combine (tmode, inner_op0);
+                 op1 = gen_lowpart_for_combine (tmode, inner_op1);
+                 changed = 1;
+                 break;
+               }
 
-         /* the resulting comparison is always unsigned since we masked off
-            the original sign bit. */
-         code = unsigned_condition (code);
+         if (! changed)
+           break;
        }
+
+      /* If both operands are NOT, we can strip off the outer operation
+        and adjust the comparison code for swapped operands; similarly for
+        NEG, except that this must be an equality comparison.  */
+      else if ((GET_CODE (op0) == NOT && GET_CODE (op1) == NOT)
+              || (GET_CODE (op0) == NEG && GET_CODE (op1) == NEG
+                  && (code == EQ || code == NE)))
+       op0 = XEXP (op0, 0), op1 = XEXP (op1, 0), code = swap_condition (code);
+
       else
        break;
     }
@@ -8575,7 +8851,7 @@ simplify_comparison (code, pop0, pop1)
        op0 = force_to_mode (op0, mode,
                             ((HOST_WIDE_INT) 1
                              << (GET_MODE_BITSIZE (mode) - 1)),
-                            NULL_RTX);
+                            NULL_RTX, 0);
 
       /* Now try cases based on the opcode of OP0.  If none of the cases
         does a "continue", we exit this loop immediately after the
@@ -8915,8 +9191,7 @@ simplify_comparison (code, pop0, pop1)
          /* Convert (and (xshift 1 X) Y) to (and (lshiftrt Y X) 1).  This
             will be converted to a ZERO_EXTRACT later.  */
          if (const_op == 0 && equality_comparison_p
-             && (GET_CODE (XEXP (op0, 0)) == ASHIFT
-                 || GET_CODE (XEXP (op0, 0)) == LSHIFT)
+             && GET_CODE (XEXP (op0, 0)) == ASHIFT
              && XEXP (XEXP (op0, 0), 0) == const1_rtx)
            {
              op0 = simplify_and_const_int
@@ -8983,8 +9258,7 @@ simplify_comparison (code, pop0, pop1)
          break;
 
        case ASHIFT:
-       case LSHIFT:
-         /* If we have (compare (xshift FOO N) (const_int C)) and
+         /* If we have (compare (ashift FOO N) (const_int C)) and
             the high order N bits of FOO (N+1 if an inequality comparison)
             are known to be zero, we can do this by comparing FOO with C
             shifted right N bits so long as the low-order N bits of C are
@@ -9151,15 +9425,13 @@ simplify_comparison (code, pop0, pop1)
          /* If the only nonzero bits in OP0 and OP1 are those in the
             narrower mode and this is an equality or unsigned comparison,
             we can use the wider mode.  Similarly for sign-extended
-            values and equality or signed comparisons.  */
+            values, in which case it is true for all comparisons.  */
          if (((code == EQ || code == NE
                || code == GEU || code == GTU || code == LEU || code == LTU)
               && (nonzero_bits (op0, tmode) & ~ GET_MODE_MASK (mode)) == 0
               && (nonzero_bits (op1, tmode) & ~ GET_MODE_MASK (mode)) == 0)
-             || ((code == EQ || code == NE
-                  || code == GE || code == GT || code == LE || code == LT)
-                 && (num_sign_bit_copies (op0, tmode)
-                     > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))
+             || ((num_sign_bit_copies (op0, tmode)
+                  > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))
                  && (num_sign_bit_copies (op1, tmode)
                      > GET_MODE_BITSIZE (tmode) - GET_MODE_BITSIZE (mode))))
            {
@@ -9183,6 +9455,12 @@ simplify_comparison (code, pop0, pop1)
            }
        }
 
+#ifdef CANONICALIZE_COMPARISON
+  /* If this machine only supports a subset of valid comparisons, see if we
+     can convert an unsupported one into a supported one.  */
+  CANONICALIZE_COMPARISON (code, op0, op1);
+#endif
+
   *pop0 = op0;
   *pop1 = op1;
 
@@ -9198,6 +9476,7 @@ reversible_comparison_p (x)
      rtx x;
 {
   if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
+      || flag_fast_math
       || GET_CODE (x) == NE || GET_CODE (x) == EQ)
     return 1;
 
@@ -9209,6 +9488,13 @@ reversible_comparison_p (x)
       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))));
@@ -9655,7 +9941,8 @@ reg_dead_at_p_1 (dest, x)
    We scan backwards from INSN.  If we hit a REG_DEAD note or a CLOBBER
    referencing REG, it is dead.  If we hit a SET referencing REG, it is
    live.  Otherwise, see if it is live or dead at the start of the basic
-   block we are in.  */
+   block we are in.  Hard regs marked as being live in NEWPAT_USED_REGS
+   must be assumed to be always live.  */
 
 static int
 reg_dead_at_p (reg, insn)
@@ -9673,6 +9960,14 @@ reg_dead_at_p (reg, insn)
 
   reg_dead_flag = 0;
 
+  /* Check that reg isn't mentioned in NEWPAT_USED_REGS.  */
+  if (reg_dead_regno < FIRST_PSEUDO_REGISTER)
+    {
+      for (i = reg_dead_regno; i < reg_dead_endregno; i++)
+       if (TEST_HARD_REG_BIT (newpat_used_regs, i))
+         return 0;
+    }
+
   /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
      beginning of function.  */
   for (; insn && GET_CODE (insn) != CODE_LABEL;
@@ -9707,6 +10002,106 @@ reg_dead_at_p (reg, insn)
   return 1;
 }
 \f
+/* Note hard registers in X that are used.  This code is similar to
+   that in flow.c, but much simpler since we don't care about pseudos.  */
+
+static void
+mark_used_regs_combine (x)
+     rtx x;
+{
+  register RTX_CODE code = GET_CODE (x);
+  register int regno;
+  int i;
+
+  switch (code)
+    {
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_INT:
+    case CONST:
+    case CONST_DOUBLE:
+    case PC:
+    case ADDR_VEC:
+    case ADDR_DIFF_VEC:
+    case ASM_INPUT:
+#ifdef HAVE_cc0
+    /* CC0 must die in the insn after it is set, so we don't need to take
+       special note of it here.  */
+    case CC0:
+#endif
+      return;
+
+    case CLOBBER:
+      /* If we are clobbering a MEM, mark any hard registers inside the
+        address as used.  */
+      if (GET_CODE (XEXP (x, 0)) == MEM)
+       mark_used_regs_combine (XEXP (XEXP (x, 0), 0));
+      return;
+
+    case REG:
+      regno = REGNO (x);
+      /* A hard reg in a wide mode may really be multiple registers.
+        If so, mark all of them just like the first.  */
+      if (regno < FIRST_PSEUDO_REGISTER)
+       {
+         /* None of this applies to the stack, frame or arg pointers */
+         if (regno == STACK_POINTER_REGNUM
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+             || regno == HARD_FRAME_POINTER_REGNUM
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+             || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+#endif
+             || regno == FRAME_POINTER_REGNUM)
+           return;
+
+         i = HARD_REGNO_NREGS (regno, GET_MODE (x));
+         while (i-- > 0)
+           SET_HARD_REG_BIT (newpat_used_regs, regno + i);
+       }
+      return;
+
+    case SET:
+      {
+       /* If setting a MEM, or a SUBREG of a MEM, then note any hard regs in
+          the address.  */
+       register rtx testreg = SET_DEST (x);
+
+       while (GET_CODE (testreg) == SUBREG
+              || GET_CODE (testreg) == ZERO_EXTRACT
+              || GET_CODE (testreg) == SIGN_EXTRACT
+              || GET_CODE (testreg) == STRICT_LOW_PART)
+         testreg = XEXP (testreg, 0);
+
+       if (GET_CODE (testreg) == MEM)
+         mark_used_regs_combine (XEXP (testreg, 0));
+
+       mark_used_regs_combine (SET_SRC (x));
+       return;
+      }
+    }
+
+  /* Recursively scan the operands of this expression.  */
+
+  {
+    register char *fmt = GET_RTX_FORMAT (code);
+
+    for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+      {
+        if (fmt[i] == 'e')
+         mark_used_regs_combine (XEXP (x, i));
+        else if (fmt[i] == 'E')
+          {
+            register int j;
+
+            for (j = 0; j < XVECLEN (x, i); j++)
+              mark_used_regs_combine (XVECEXP (x, i, j));
+          }
+      }
+  }
+}
+
+\f
 /* Remove register number REGNO from the dead registers list of INSN.
 
    Return the note used to record the death, if there was one.  */
@@ -9780,7 +10175,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
                if (i < regno || i >= ourend)
                  REG_NOTES (where_dead)
                    = gen_rtx (EXPR_LIST, REG_DEAD,
-                              gen_rtx (REG, word_mode, i),
+                              gen_rtx (REG, reg_raw_mode[i], i),
                               REG_NOTES (where_dead));
            }
 
@@ -10059,7 +10454,11 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
             In both cases, we must search to see if we can find a previous
             use of A and put the death note there.  */
 
-         if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
+         if (from_insn
+             && GET_CODE (from_insn) == CALL_INSN
+              && find_reg_fusage (from_insn, USE, XEXP (note, 0)))
+           place = from_insn;
+         else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
            place = i3;
          else if (i2 != 0 && next_nonnote_insn (i2) == i3
                   && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
@@ -10126,7 +10525,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                        break;
                      }
                  }
-               else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem)))
+               else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
+                        || (GET_CODE (tem) == CALL_INSN
+                            && find_reg_fusage (tem, USE, XEXP (note, 0))))
                  {
                    place = tem;
                    break;
@@ -10179,9 +10580,10 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                  int i;
 
                  for (i = regno; i < endregno; i++)
-                   if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0))
+                   if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0)
+                       && ! find_regno_fusage (place, USE, i))
                      {
-                       rtx piece = gen_rtx (REG, word_mode, i);
+                       rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
                        rtx p;
 
                        /* See if we already placed a USE note for this
@@ -10228,7 +10630,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
 
                      for (i = regno; i < endregno; i++)
                        {
-                         rtx piece = gen_rtx (REG, word_mode, i);
+                         rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
 
                          if (reg_referenced_p (piece, PATTERN (place))
                              && ! dead_or_set_p (place, piece)
@@ -10333,6 +10735,12 @@ distribute_links (links)
              place = insn;
            break;
          }
+       else if (GET_CODE (insn) == CALL_INSN
+             && find_reg_fusage (insn, USE, reg))
+         {
+           place = insn;
+           break;
+         }
 
       /* If we found a place to put the link, place it there unless there
         is already a link to the same insn as LINK at that point.  */
@@ -10349,6 +10757,12 @@ distribute_links (links)
            {
              XEXP (link, 1) = LOG_LINKS (place);
              LOG_LINKS (place) = link;
+
+             /* Set added_links_insn to the earliest insn we added a
+                link to.  */
+             if (added_links_insn == 0 
+                 || INSN_CUID (added_links_insn) > INSN_CUID (place))
+               added_links_insn = place;
            }
        }
     }