OSDN Git Service

Set TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 9d13e52..31efa5b 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -140,9 +140,8 @@ static int max_uid_cuid;
 
 /* Get the cuid of an insn.  */
 
-#define INSN_CUID(INSN) (INSN_UID (INSN) > max_uid_cuid                \
-                        ? (abort(), 0)                         \
-                        : uid_cuid[INSN_UID (INSN)])
+#define INSN_CUID(INSN) \
+(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
 
 /* Maximum register number, which is the size of the tables below.  */
 
@@ -199,13 +198,6 @@ static HARD_REG_SET newpat_used_regs;
 
 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
-   structures.  */
-
-static int previous_num_undos;
-
 /* Basic block number of the block in which we are performing combines.  */
 static int this_basic_block;
 \f
@@ -253,7 +245,7 @@ static int this_basic_block;
    reg_last_set_invalid[i] is set non-zero when register I is being assigned
    to and reg_last_set_table_tick[i] == label_tick.  */
 
-/* Record last value assigned to (hard or pseudo) register n. */
+/* Record last value assigned to (hard or pseudo) register n.  */
 
 static rtx *reg_last_set_value;
 
@@ -263,7 +255,7 @@ static rtx *reg_last_set_value;
 static int *reg_last_set_label;
 
 /* Record the value of label_tick when an expression involving register n
-   is placed in reg_last_set_value. */
+   is placed in reg_last_set_value.  */
 
 static int *reg_last_set_table_tick;
 
@@ -272,7 +264,7 @@ static int *reg_last_set_table_tick;
 
 static char *reg_last_set_invalid;
 
-/* Incremented for each label. */
+/* Incremented for each label.  */
 
 static int label_tick;
 
@@ -320,6 +312,7 @@ static char *reg_last_set_sign_bit_copies;
 
 struct undo
 {
+  struct undo *next;
   int is_int;
   union {rtx r; int i;} old_contents;
   union {rtx *r; int *i;} where;
@@ -332,15 +325,19 @@ struct undo
    The value of storage is what to pass to obfree.
 
    other_insn is nonzero if we have modified some other insn in the process
-   of working on subst_insn.  It must be verified too.  */
+   of working on subst_insn.  It must be verified too.
 
-#define MAX_UNDO 50
+   previous_undos is the value of undobuf.undos when we started processing
+   this substitution.  This will prevent gen_rtx_combine from re-used a piece
+   from the previous expression.  Doing so can produce circular rtl
+   structures.  */
 
 struct undobuf
 {
-  int num_undo;
   char *storage;
-  struct undo undo[MAX_UNDO];
+  struct undo *undos;
+  struct undo *frees;
+  struct undo *previous_undos;
   rtx other_insn;
 };
 
@@ -353,32 +350,44 @@ static struct undobuf undobuf;
    the undo table.  */
 
 #define SUBST(INTO, NEWVAL)  \
- do { rtx _new = (NEWVAL);                                             \
-      if (undobuf.num_undo < MAX_UNDO)                                 \
-       {                                                               \
-         undobuf.undo[undobuf.num_undo].is_int = 0;                    \
-         undobuf.undo[undobuf.num_undo].where.r = &INTO;               \
-         undobuf.undo[undobuf.num_undo].old_contents.r = INTO; \
-         INTO = _new;                                                  \
-         if (undobuf.undo[undobuf.num_undo].old_contents.r != INTO)    \
-           undobuf.num_undo++;                                         \
-       }                                                               \
+ do { rtx _new = (NEWVAL);                                     \
+      struct undo *_buf;                                       \
+                                                               \
+      if (undobuf.frees)                                       \
+       _buf = undobuf.frees, undobuf.frees = _buf->next;       \
+      else                                                     \
+       _buf = (struct undo *) xmalloc (sizeof (struct undo));  \
+                                                               \
+      _buf->is_int = 0;                                                \
+      _buf->where.r = &INTO;                                   \
+      _buf->old_contents.r = INTO;                             \
+      INTO = _new;                                             \
+      if (_buf->old_contents.r == INTO)                                \
+       _buf->next = undobuf.frees, undobuf.frees = _buf;       \
+      else                                                     \
+       _buf->next = undobuf.undos, undobuf.undos = _buf;       \
     } while (0)
 
-/* Similar to SUBST, but NEWVAL is an int.  INTO will normally be an XINT
-   expression.
-   Note that substitution for the value of a CONST_INT is not safe.  */
+/* Similar to SUBST, but NEWVAL is an int expression.  Note that substitution
+   for the value of a HOST_WIDE_INT value (including CONST_INT) is
+   not safe.  */
 
 #define SUBST_INT(INTO, NEWVAL)  \
- do { if (undobuf.num_undo < MAX_UNDO)                                 \
-{                                                                      \
-         undobuf.undo[undobuf.num_undo].is_int = 1;                    \
-         undobuf.undo[undobuf.num_undo].where.i = (int *) &INTO;       \
-         undobuf.undo[undobuf.num_undo].old_contents.i = INTO;         \
-         INTO = NEWVAL;                                                \
-         if (undobuf.undo[undobuf.num_undo].old_contents.i != INTO)    \
-           undobuf.num_undo++;                                         \
-       }                                                               \
+ do { struct undo *_buf;                                       \
+                                                               \
+      if (undobuf.frees)                                       \
+       _buf = undobuf.frees, undobuf.frees = _buf->next;       \
+      else                                                     \
+       _buf = (struct undo *) xmalloc (sizeof (struct undo));  \
+                                                               \
+      _buf->is_int = 1;                                                \
+      _buf->where.i = (int *) &INTO;                           \
+      _buf->old_contents.i = INTO;                             \
+      INTO = NEWVAL;                                           \
+      if (_buf->old_contents.i == INTO)                                \
+       _buf->next = undobuf.frees, undobuf.frees = _buf;       \
+      else                                                     \
+       _buf->next = undobuf.undos, undobuf.undos = _buf;       \
      } while (0)
 
 /* Number of times the pseudo being substituted for
@@ -386,8 +395,8 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static void init_reg_last_arrays       PROTO(());
-static void setup_incoming_promotions   PROTO(());
+static void init_reg_last_arrays       PROTO((void));
+static void setup_incoming_promotions   PROTO((void));
 static void set_nonzero_bits_and_sign_copies  PROTO((rtx, rtx));
 static int can_combine_p       PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
 static int combinable_i3pat    PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
@@ -410,6 +419,7 @@ static rtx force_to_mode    PROTO((rtx, enum machine_mode,
                                       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 int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
 static rtx make_field_assignment  PROTO((rtx));
 static rtx apply_distributive_law  PROTO((rtx));
 static rtx simplify_and_const_int  PROTO((rtx, enum machine_mode, rtx,
@@ -435,16 +445,17 @@ static void update_table_tick     PROTO((rtx));
 static void record_value_for_reg  PROTO((rtx, rtx, rtx));
 static void record_dead_and_set_regs_1  PROTO((rtx, rtx));
 static void record_dead_and_set_regs  PROTO((rtx));
-static int get_last_value_validate  PROTO((rtx *, int, int));
+static int get_last_value_validate  PROTO((rtx *, rtx, int, int));
 static rtx get_last_value      PROTO((rtx));
 static int use_crosses_set_p   PROTO((rtx, int));
 static void reg_dead_at_p_1    PROTO((rtx, rtx));
 static int reg_dead_at_p       PROTO((rtx, rtx));
-static void move_deaths                PROTO((rtx, int, rtx, rtx *));
+static void move_deaths                PROTO((rtx, 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));
+static int insn_cuid           PROTO((rtx));
 \f
 /* Main entry point for combiner.  F is the first insn of the function.
    NREGS is the first unused pseudo-reg number.  */
@@ -462,7 +473,7 @@ combine_instructions (f, nregs)
   combine_merges = 0;
   combine_extras = 0;
   combine_successes = 0;
-  undobuf.num_undo = previous_num_undos = 0;
+  undobuf.undos = undobuf.previous_undos = 0;
 
   combine_max_regno = nregs;
 
@@ -535,6 +546,12 @@ combine_instructions (f, nregs)
        {
          note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
          record_dead_and_set_regs (insn);
+
+#ifdef AUTO_INC_DEC
+         for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+           if (REG_NOTE_KIND (links) == REG_INC)
+             set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX);
+#endif
        }
 
       if (GET_CODE (insn) == CODE_LABEL)
@@ -701,10 +718,8 @@ setup_incoming_promotions ()
 #endif
 }
 \f
-/* Called via note_stores.  If X is a pseudo that is used in more than
-   one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
-   set, record what bits are known zero.  If we are clobbering X,
-   ignore this "set" because the clobbered value won't be used. 
+/* Called via note_stores.  If X is a pseudo that is narrower than
+   HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
 
    If we are setting only a portion of X and we can't figure out what
    portion, assume all bits will be used since we don't know what will
@@ -723,18 +738,16 @@ set_nonzero_bits_and_sign_copies (x, set)
 
   if (GET_CODE (x) == REG
       && REGNO (x) >= FIRST_PSEUDO_REGISTER
-      && reg_n_sets[REGNO (x)] > 1
-      && reg_basic_block[REGNO (x)] < 0
       /* If this register is undefined at the start of the file, we can't
         say what its contents were.  */
       && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
            & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
-      if (GET_CODE (set) == CLOBBER)
+      if (set == 0 || GET_CODE (set) == CLOBBER)
        {
          reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 0;
+         reg_sign_bit_copies[REGNO (x)] = 1;
          return;
        }
 
@@ -784,7 +797,7 @@ set_nonzero_bits_and_sign_copies (x, set)
       else
        {
          reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
-         reg_sign_bit_copies[REGNO (x)] = 0;
+         reg_sign_bit_copies[REGNO (x)] = 1;
        }
     }
 }
@@ -939,7 +952,12 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
         insns.  Eliminate this problem by not combining with such an insn.
 
         Also, on some machines we don't want to extend the life of a hard
-        register.  */
+        register.
+
+        This is the same test done in can_combine except that we don't test
+        if SRC is a CALL operation to permit a hard register with
+        SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
+        into account.  */
 
       if (GET_CODE (src) == REG
          && ((REGNO (dest) < FIRST_PSEUDO_REGISTER
@@ -947,11 +965,17 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
              /* 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).  */
+                is going on).
+                Also avoid substituting a return register into I3, because
+                reload can't handle a conflict with constraints of other
+                inputs.  */
              || (REGNO (src) < FIRST_PSEUDO_REGISTER
                  && (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
 #ifdef SMALL_REGISTER_CLASSES
-                     || ! REG_USERVAR_P (src)
+                     || (SMALL_REGISTER_CLASSES
+                         && ((! all_adjacent && ! REG_USERVAR_P (src))
+                             || (FUNCTION_VALUE_REGNO_P (REGNO (src))
+                                 && ! REG_USERVAR_P (src))))
 #endif
                      ))))
        return 0;
@@ -1125,13 +1149,18 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
               || (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
          /* This is the same test done in can_combine_p except that we
             allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
-            CALL operation.  */
+            CALL operation.
+            Moreover, we can't test all_adjacent; we don't have to, since
+            this instruction will stay in place, thus we are not considering
+            to increase the lifetime of INNER_DEST.  */
          || (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 && ! REG_USERVAR_P (inner_dest))
+                || (SMALL_REGISTER_CLASSES
+                    && GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest)
+                    && FUNCTION_VALUE_REGNO_P (REGNO (inner_dest)))
 #endif
                  ))
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
@@ -1240,7 +1269,7 @@ try_combine (i3, i2, i1)
 
   combine_attempts++;
 
-  undobuf.num_undo = previous_num_undos = 0;
+  undobuf.undos = undobuf.previous_undos = 0;
   undobuf.other_insn = 0;
 
   /* Save the current high-water-mark so we can free storage if we didn't
@@ -1274,7 +1303,8 @@ try_combine (i3, i2, i1)
       && GET_CODE (SET_SRC (PATTERN (i3))) == REG
       && REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
 #ifdef SMALL_REGISTER_CLASSES
-      && (GET_CODE (SET_DEST (PATTERN (i3))) != REG
+      && (! SMALL_REGISTER_CLASSES
+         || GET_CODE (SET_DEST (PATTERN (i3))) != REG
          || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
          || REG_USERVAR_P (SET_DEST (PATTERN (i3))))
 #endif
@@ -1304,7 +1334,8 @@ try_combine (i3, i2, i1)
         The problem can also happen if the dest of I3 is a memory ref,
         if another dest in I2 is an indirect memory ref.  */
       for (i = 0; i < XVECLEN (p2, 0); i++)
-       if (GET_CODE (XVECEXP (p2, 0, i)) == SET
+       if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
+            || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
            && reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
                                        SET_DEST (XVECEXP (p2, 0, i))))
          break;
@@ -1513,7 +1544,7 @@ try_combine (i3, i2, i1)
          i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
        }
 
-      previous_num_undos = undobuf.num_undo;
+      undobuf.previous_undos = undobuf.undos;
     }
 
 #ifndef HAVE_cc0
@@ -1587,7 +1618,7 @@ try_combine (i3, i2, i1)
       subst_low_cuid = INSN_CUID (i2);
       newpat = subst (PATTERN (i3), i2dest, i2src, 0,
                      ! i1_feeds_i3 && i1dest_in_i1src);
-      previous_num_undos = undobuf.num_undo;
+      undobuf.previous_undos = undobuf.undos;
 
       /* Record whether i2's body now appears within i3's body.  */
       i2_is_used = n_occurrences;
@@ -1600,7 +1631,7 @@ try_combine (i3, i2, i1)
     {
       /* Before we can do this substitution, we must redo the test done
         above (see detailed comments there) that ensures  that I1DEST
-        isn't mentioned in any SETs in NEWPAT that are field assignments. */
+        isn't mentioned in any SETs in NEWPAT that are field assignments.  */
 
       if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
                              0, NULL_PTR))
@@ -1612,7 +1643,7 @@ try_combine (i3, i2, i1)
       n_occurrences = 0;
       subst_low_cuid = INSN_CUID (i1);
       newpat = subst (newpat, i1dest, i1src, 0, 0);
-      previous_num_undos = undobuf.num_undo;
+      undobuf.previous_undos = undobuf.undos;
     }
 
   /* Fail if an autoincrement side-effect has been duplicated.  Be careful
@@ -1650,7 +1681,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 ((char *) &old->elem[0], (char *) &XVECEXP (newpat, 0, 0),
+         bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
                 sizeof (old->elem[0]) * old->num_elem);
        }
       else
@@ -1798,9 +1829,12 @@ try_combine (i3, i2, i1)
                                              &i2_scratches);
 
          /* If I2 or I3 has multiple SETs, we won't know how to track
-            register status, so don't use these insns.  */
+            register status, so don't use these insns.  If I2's destination
+            is used between I2 and I3, we also can't use these insns.  */
 
-         if (i2_code_number >= 0 && i2set && i3set)
+         if (i2_code_number >= 0 && i2set && i3set
+             && (next_real_insn (i2) == i3
+                 || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
            insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
                                                  &i3_scratches); 
          if (insn_code_number >= 0)
@@ -1809,10 +1843,26 @@ try_combine (i3, i2, i1)
          /* It is possible that both insns now set the destination of I3.
             If so, we must show an extra use of it.  */
 
-         if (insn_code_number >= 0 && GET_CODE (SET_DEST (i3set)) == REG
-             && GET_CODE (SET_DEST (i2set)) == REG
-             && REGNO (SET_DEST (i3set)) == REGNO (SET_DEST (i2set)))
-           reg_n_sets[REGNO (SET_DEST (i2set))]++;
+         if (insn_code_number >= 0)
+           {
+             rtx new_i3_dest = SET_DEST (i3set);
+             rtx new_i2_dest = SET_DEST (i2set);
+
+             while (GET_CODE (new_i3_dest) == ZERO_EXTRACT
+                    || GET_CODE (new_i3_dest) == STRICT_LOW_PART
+                    || GET_CODE (new_i3_dest) == SUBREG)
+               new_i3_dest = XEXP (new_i3_dest, 0);
+
+             while (GET_CODE (new_i2_dest) == ZERO_EXTRACT
+                    || GET_CODE (new_i2_dest) == STRICT_LOW_PART
+                    || GET_CODE (new_i2_dest) == SUBREG)
+               new_i2_dest = XEXP (new_i2_dest, 0);
+
+             if (GET_CODE (new_i3_dest) == REG
+                 && GET_CODE (new_i2_dest) == REG
+                 && REGNO (new_i3_dest) == REGNO (new_i2_dest))
+               reg_n_sets[REGNO (new_i2_dest)]++;
+           }
        }
 
       /* If we can split it and use I2DEST, go ahead and see if that
@@ -2186,11 +2236,18 @@ try_combine (i3, i2, i1)
       }
 
     /* Get death notes for everything that is now used in either I3 or
-       I2 and used to die in a previous insn.  */
+       I2 and used to die in a previous insn.  If we built two new 
+       patterns, move from I1 to I2 then I2 to I3 so that we get the
+       proper movement on registers that I2 modifies.  */
 
-    move_deaths (newpat, i1 ? INSN_CUID (i1) : INSN_CUID (i2), i3, &midnotes);
     if (newi2pat)
-      move_deaths (newi2pat, INSN_CUID (i1), i2, &midnotes);
+      {
+       move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
+       move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
+      }
+    else
+      move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
+                  i3, &midnotes);
 
     /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3.  */
     if (i3notes)
@@ -2303,7 +2360,9 @@ 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 && ! i2dest_in_i2src)
+       if (! added_sets_2
+           && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
+           && ! i2dest_in_i2src)
          {
            regno = REGNO (i2dest);
            reg_n_sets[regno]--;
@@ -2379,20 +2438,22 @@ try_combine (i3, i2, i1)
 static void
 undo_all ()
 {
-  register int i;
-  if (undobuf.num_undo > MAX_UNDO)
-    undobuf.num_undo = MAX_UNDO;
-  for (i = undobuf.num_undo - 1; i >= 0; i--)
+  struct undo *undo, *next;
+
+  for (undo = undobuf.undos; undo; undo = next)
     {
-      if (undobuf.undo[i].is_int)
-       *undobuf.undo[i].where.i = undobuf.undo[i].old_contents.i;
+      next = undo->next;
+      if (undo->is_int)
+       *undo->where.i = undo->old_contents.i;
       else
-       *undobuf.undo[i].where.r = undobuf.undo[i].old_contents.r;
-      
+       *undo->where.r = undo->old_contents.r;
+
+      undo->next = undobuf.frees;
+      undobuf.frees = undo;
     }
 
   obfree (undobuf.storage);
-  undobuf.num_undo = 0;
+  undobuf.undos = undobuf.previous_undos = 0;
 
   /* Clear this here, so that subsequent get_last_value calls are not
      affected.  */
@@ -2531,6 +2592,11 @@ find_split_point (loc, insn)
       if (split && split != &SET_SRC (x))
        return split;
 
+      /* See if we can split SET_DEST as it stands.  */
+      split = find_split_point (&SET_DEST (x), insn);
+      if (split && split != &SET_DEST (x))
+       return split;
+
       /* See if this is a bitfield assignment with everything constant.  If
         so, this is an IOR of an AND, so split it into that.  */
       if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
@@ -2597,16 +2663,50 @@ find_split_point (loc, insn)
              && XEXP (*split, 0) == SET_DEST (x)
              && XEXP (*split, 1) == const0_rtx)
            {
+             rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
+                                               XEXP (SET_SRC (x), 0),
+                                               pos, NULL_RTX, 1, 1, 0, 0);
+             if (extraction != 0)
+               {
+                 SUBST (SET_SRC (x), extraction);
+                 return find_split_point (loc, insn);
+               }
+           }
+         break;
+
+       case NE:
+         /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+            is known to be on, this can be converted into a NEG of a shift. */
+         if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
+             && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
+             && 1 <= (pos = exact_log2
+                      (nonzero_bits (XEXP (SET_SRC (x), 0),
+                                     GET_MODE (XEXP (SET_SRC (x), 0))))))
+           {
+             enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
+
              SUBST (SET_SRC (x),
-                    make_extraction (GET_MODE (SET_DEST (x)),
-                                     XEXP (SET_SRC (x), 0),
-                                     pos, NULL_RTX, 1, 1, 0, 0));
-             return find_split_point (loc, insn);
+                    gen_rtx_combine (NEG, mode,
+                                     gen_rtx_combine (LSHIFTRT, mode,
+                                                      XEXP (SET_SRC (x), 0),
+                                                      GEN_INT (pos))));
+
+             split = find_split_point (&SET_SRC (x), insn);
+             if (split && split != &SET_SRC (x))
+               return split;
            }
          break;
 
        case SIGN_EXTEND:
          inner = XEXP (SET_SRC (x), 0);
+
+         /* We can't optimize if either mode is a partial integer
+            mode as we don't know how many bits are significant
+            in those modes.  */
+         if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
+             || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+           break;
+
          pos = 0;
          len = GET_MODE_BITSIZE (GET_MODE (inner));
          unsignedp = 0;
@@ -2732,14 +2832,14 @@ find_split_point (loc, insn)
       split = find_split_point (&XEXP (x, 2), insn);
       if (split)
        return split;
-      /* ... fall through ... */
+      /* ... fall through ...  */
     case '2':
     case 'c':
     case '<':
       split = find_split_point (&XEXP (x, 1), insn);
       if (split)
        return split;
-      /* ... fall through ... */
+      /* ... fall through ...  */
     case '1':
       /* Some machines have (and (shift ...) ...) insns.  If X is not
         an AND, but XEXP (X, 0) is, use it as our split point.  */
@@ -2840,7 +2940,8 @@ subst (x, from, to, in_dest, unique_copy)
         || GET_CODE (SET_DEST (x)) == PC))
     fmt = "ie";
 
-  /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a constant. */
+  /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+     constant.  */
   if (fmt[0] == 'e')
     op0_mode = GET_MODE (XEXP (x, 0));
 
@@ -3052,7 +3153,12 @@ simplify_rtx (x, op0_mode, last, in_dest)
       rtx cond, true, false;
 
       cond = if_then_else_cond (x, &true, &false);
-      if (cond != 0)
+      if (cond != 0
+         /* If everything is a comparison, what we have is highly unlikely
+            to be simpler, so don't use it.  */
+         && ! (GET_RTX_CLASS (code) == '<'
+               && (GET_RTX_CLASS (GET_CODE (true)) == '<'
+                   || GET_RTX_CLASS (GET_CODE (false)) == '<')))
        {
          rtx cop1 = const0_rtx;
          enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
@@ -3277,7 +3383,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
 
       if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
          && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-         && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD
+         && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
          && GET_MODE_CLASS (mode) == MODE_INT)
        {
          temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
@@ -3289,9 +3395,17 @@ simplify_rtx (x, op0_mode, last, in_dest)
       /* If we want a subreg of a constant, at offset 0,
         take the low bits.  On a little-endian machine, that's
         always valid.  On a big-endian machine, it's valid
-        only if the constant's mode fits in one word.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+        only if the constant's mode fits in one word.   Note that we
+        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      if (CONSTANT_P (SUBREG_REG (x))
+         && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+             || ! WORDS_BIG_ENDIAN)
+             ? SUBREG_WORD (x) == 0
+             : (SUBREG_WORD (x)
+                == ((GET_MODE_SIZE (op0_mode)
+                     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+                    / UNITS_PER_WORD)))
+         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
          && (! WORDS_BIG_ENDIAN
              || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
@@ -3351,25 +3465,25 @@ simplify_rtx (x, op0_mode, last, in_dest)
          return gen_lowpart_for_combine (mode, x);
        }
                                            
-#if STORE_FLAG_VALUE == -1
-      /* (not (comparison foo bar)) can be done by reversing the comparison
-        code if valid.  */
-      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+      /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
+        reversing the comparison code if valid.  */
+      if (STORE_FLAG_VALUE == -1
+         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
          && reversible_comparison_p (XEXP (x, 0)))
        return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
                                mode, XEXP (XEXP (x, 0), 0),
                                XEXP (XEXP (x, 0), 1));
 
       /* (ashiftrt 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.  */
+        is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
+        perform the above simplification.  */
 
-      if (XEXP (x, 1) == const1_rtx
+      if (STORE_FLAG_VALUE == -1
+         && XEXP (x, 1) == const1_rtx
          && GET_CODE (XEXP (x, 0)) == ASHIFTRT
          && 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
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
         with negating logical insns (and-not, nand, etc.).  If result has
@@ -3417,13 +3531,13 @@ simplify_rtx (x, op0_mode, last, in_dest)
       /* (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. */
+             /* x-y != -(y-x) with IEEE floating point.  */
              || 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. */
+      /* (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)
        return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
@@ -3484,10 +3598,65 @@ simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case TRUNCATE:
+      /* We can't handle truncation to a partial integer mode here
+        because we don't know the real bitsize of the partial
+        integer mode.  */
+      if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+       break;
+
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        SUBST (XEXP (x, 0),
               force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
                              GET_MODE_MASK (mode), NULL_RTX, 0));
+
+      /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI.  */
+      if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+          || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
+         && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
+       return XEXP (XEXP (x, 0), 0);
+
+      /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
+        (OP:SI foo:SI) 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)) == SIGN_EXTEND
+             || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
+         && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
+       return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
+                         XEXP (XEXP (XEXP (x, 0), 0), 0));
+
+      /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
+        (truncate:SI x).  */
+      if (GET_CODE (XEXP (x, 0)) == SUBREG
+         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
+         && subreg_lowpart_p (XEXP (x, 0)))
+       return SUBREG_REG (XEXP (x, 0));
+
+      /* If we know that the value is already truncated, we can
+         replace the TRUNCATE with a SUBREG.  */
+      if (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+             &~ GET_MODE_MASK (mode)) == 0)
+       return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+      /* A truncate of a comparison can be replaced with a subreg if
+         STORE_FLAG_VALUE permits.  This is like the previous test,
+         but it works even if the comparison is done in a mode larger
+         than HOST_BITS_PER_WIDE_INT.  */
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0)
+       return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+      /* Similarly, a truncate of a register whose value is a
+         comparison can be replaced with a subreg if STORE_FLAG_VALUE
+         permits.  */
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0
+         && (temp = get_last_value (XEXP (x, 0)))
+         && GET_RTX_CLASS (GET_CODE (temp)) == '<')
+       return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
       break;
 
     case FLOAT_TRUNCATE:
@@ -3627,16 +3796,15 @@ simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case MINUS:
-#if STORE_FLAG_VALUE == 1
-      /* (minus 1 (comparison foo bar)) can be done by reversing the comparison
-        code if valid.  */
-      if (XEXP (x, 0) == const1_rtx
+      /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
+        by reversing the comparison code if valid.  */
+      if (STORE_FLAG_VALUE == 1
+         && XEXP (x, 0) == const1_rtx
          && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
          && reversible_comparison_p (XEXP (x, 1)))
        return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))),
                           mode, XEXP (XEXP (x, 1), 0),
                                XEXP (XEXP (x, 1), 1));
-#endif
 
       /* (minus <foo> (and <foo> (const_int -pow2))) becomes
         (and <foo> (const_int pow2-1))  */
@@ -3710,7 +3878,6 @@ simplify_rtx (x, op0_mode, last, in_dest)
          /* Simplify our comparison, if possible.  */
          new_code = simplify_comparison (code, &op0, &op1);
 
-#if STORE_FLAG_VALUE == 1
          /* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X
             if only the low-order bit is possibly nonzero in X (such as when
             X is a ZERO_EXTRACT of one bit).  Similarly, we can convert EQ to
@@ -3723,13 +3890,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
             ZERO_EXTRACT is indeed appropriate, it will be placed back by
             the call to make_compound_operation in the SET case.  */
 
-         if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
-             && op1 == const0_rtx
-             && nonzero_bits (op0, mode) == 1)
+         if (STORE_FLAG_VALUE == 1
+             && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+             && op1 == const0_rtx && nonzero_bits (op0, mode) == 1)
            return gen_lowpart_for_combine (mode,
                                            expand_compound_operation (op0));
 
-         else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == 1
+                  && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
@@ -3739,7 +3907,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
                                gen_lowpart_for_combine (mode, op0));
            }
 
-         else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == 1
+                  && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && nonzero_bits (op0, mode) == 1)
            {
@@ -3749,7 +3918,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
                                 const1_rtx);
            }
 
-         else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == 1
+                  && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
@@ -3757,19 +3927,19 @@ simplify_rtx (x, op0_mode, last, in_dest)
              op0 = expand_compound_operation (op0);
              return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
            }
-#endif
 
-#if STORE_FLAG_VALUE == -1
          /* If STORE_FLAG_VALUE is -1, we have cases similar to
             those above.  */
-         if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+         if (STORE_FLAG_VALUE == -1
+             && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && op1 == const0_rtx
              && (num_sign_bit_copies (op0, mode)
                  == GET_MODE_BITSIZE (mode)))
            return gen_lowpart_for_combine (mode,
                                            expand_compound_operation (op0));
 
-         else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == -1
+                  && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && nonzero_bits (op0, mode) == 1)
            {
@@ -3778,7 +3948,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
                                gen_lowpart_for_combine (mode, op0));
            }
 
-         else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == -1
+                  && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && (num_sign_bit_copies (op0, mode)
                       == GET_MODE_BITSIZE (mode)))
@@ -3789,14 +3960,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
            }
 
          /* If X is 0/1, (eq X 0) is X-1.  */
-         else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+         else if (STORE_FLAG_VALUE == -1
+                  && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
              return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
            }
-#endif
 
          /* If STORE_FLAG_VALUE says to just test the sign bit and X has just
             one bit that might be nonzero, we can convert (ne x 0) to
@@ -3805,7 +3976,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
             going to test the sign bit.  */
          if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-             && (STORE_FLAG_VALUE
+             && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
                  == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
              && op1 == const0_rtx
              && mode == GET_MODE (op0)
@@ -3838,7 +4009,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
     case SIGN_EXTRACT:
     case ZERO_EXTEND:
     case SIGN_EXTEND:
-      /* If we are processing SET_DEST, we are done. */
+      /* If we are processing SET_DEST, we are done.  */
       if (in_dest)
        return x;
 
@@ -3928,11 +4099,11 @@ simplify_if_then_else (x)
   rtx temp;
   int i;
 
-  /* Simplify storing of the truth value. */
+  /* 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));
       
-  /* Also when the truth value has to be reversed. */
+  /* 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),
@@ -4018,6 +4189,10 @@ simplify_if_then_else (x)
       SUBST (XEXP (x, 2), true);
 
       temp = true, true = false, false = temp, cond = XEXP (x, 0);
+
+      /* It is possible that the conditional has been simplified out.  */
+      true_code = GET_CODE (cond);
+      comparison_p = GET_RTX_CLASS (true_code) == '<';
     }
 
   /* If the two arms are identical, we don't need the comparison.  */
@@ -4025,6 +4200,16 @@ simplify_if_then_else (x)
   if (rtx_equal_p (true, false) && ! side_effects_p (cond))
     return true;
 
+  /* Convert a == b ? b : a to "a".  */
+  if (true_code == EQ && ! side_effects_p (cond)
+      && rtx_equal_p (XEXP (cond, 0), false)
+      && rtx_equal_p (XEXP (cond, 1), true))
+    return false;
+  else if (true_code == NE && ! side_effects_p (cond)
+          && rtx_equal_p (XEXP (cond, 0), true)
+          && rtx_equal_p (XEXP (cond, 1), false))
+    return true;
+
   /* Look for cases where we have (abs x) or (neg (abs X)).  */
 
   if (GET_MODE_CLASS (mode) == MODE_INT
@@ -4066,16 +4251,15 @@ simplify_if_then_else (x)
        return gen_binary (UMIN, mode, true, false);
       }
   
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -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.  */
+     neither 1 or -1, but it isn't worth checking for.  */
 
-  if (comparison_p && mode != VOIDmode && ! side_effects_p (x))
+  if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+      && comparison_p && mode != VOIDmode && ! side_effects_p (x))
     {
       rtx t = make_compound_operation (true, SET);
       rtx f = make_compound_operation (false, SET);
@@ -4093,7 +4277,7 @@ simplify_if_then_else (x)
        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. */
+        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))
@@ -4184,7 +4368,6 @@ simplify_if_then_else (x)
          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
@@ -4407,7 +4590,7 @@ simplify_set (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. */
+     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
@@ -4535,7 +4718,7 @@ simplify_logical (x, last)
 
          /* 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. */
+            and then exit.  */
          if (last
              && GET_CODE (x) == IOR && GET_CODE (op0) == AND
              && GET_CODE (XEXP (op0, 1)) == CONST_INT
@@ -4725,10 +4908,10 @@ simplify_logical (x, last)
                           gen_unary (NOT, mode, mode, XEXP (op0, 1)),
                           op1);
 
-#if STORE_FLAG_VALUE == 1
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
-        comparison.  */
-      if (op1 == const1_rtx
+        comparison if STORE_FLAG_VALUE is 1.  */
+      if (STORE_FLAG_VALUE == 1
+         && op1 == const1_rtx
          && GET_RTX_CLASS (GET_CODE (op0)) == '<'
          && reversible_comparison_p (op0))
        return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
@@ -4736,19 +4919,19 @@ simplify_logical (x, last)
 
       /* (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.  */
+        simplification if STORE_FLAG_VALUE is 1.  */
 
-      if (op1 == const1_rtx
+      if (STORE_FLAG_VALUE == 1
+         && 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
+         && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
              == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
          && op1 == const_true_rtx
          && GET_RTX_CLASS (GET_CODE (op0)) == '<'
@@ -4850,6 +5033,78 @@ expand_compound_operation (x)
       return x;
     }
 
+  /* We can optimize some special cases of ZERO_EXTEND.  */
+  if (GET_CODE (x) == ZERO_EXTEND)
+    {
+      /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we
+         know that the last value didn't have any inappropriate bits
+         set.  */
+      if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+         && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+         && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (XEXP (x, 0), 0), GET_MODE (x))
+             & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+       return XEXP (XEXP (x, 0), 0);
+
+      /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)).  */
+      if (GET_CODE (XEXP (x, 0)) == SUBREG
+         && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+         && subreg_lowpart_p (XEXP (x, 0))
+         && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
+             & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))) == 0)
+       return SUBREG_REG (XEXP (x, 0));
+
+      /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
+         is a comparison and STORE_FLAG_VALUE permits.  This is like
+         the first case, but it works even when GET_MODE (x) is larger
+         than HOST_WIDE_INT.  */
+      if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+         && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+         && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
+         && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+             <= HOST_BITS_PER_WIDE_INT)
+         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+             & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+       return XEXP (XEXP (x, 0), 0);
+
+      /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)).  */
+      if (GET_CODE (XEXP (x, 0)) == SUBREG
+         && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+         && subreg_lowpart_p (XEXP (x, 0))
+         && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
+         && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+             <= HOST_BITS_PER_WIDE_INT)
+         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+             & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+       return SUBREG_REG (XEXP (x, 0));
+
+      /* If sign extension is cheaper than zero extension, then use it
+        if we know that no extraneous bits are set, and that the high
+        bit is not set.  */
+      if (flag_expensive_optimizations
+         && ((GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+              && ((nonzero_bits (XEXP (x, 0), GET_MODE (x))
+                   & ~ (((unsigned HOST_WIDE_INT)
+                         GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
+                        >> 1))
+                  == 0))
+             || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+                 && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+                     <= HOST_BITS_PER_WIDE_INT)
+                 && (((HOST_WIDE_INT) STORE_FLAG_VALUE
+                      & ~ (((unsigned HOST_WIDE_INT)
+                            GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
+                           >> 1))
+                     == 0))))
+       {
+         rtx temp = gen_rtx (SIGN_EXTEND, GET_MODE (x), XEXP (x, 0));
+
+         if (rtx_cost (temp, SET) < rtx_cost (x, SET))
+           return expand_compound_operation (temp);
+       }
+    }
+
   /* If we reach here, we want to return a pair of shifts.  The inner
      shift is a left shift of BITSIZE - POS - LEN bits.  The outer
      shift is a right shift of BITSIZE - LEN bits.  It is arithmetic or
@@ -4907,7 +5162,7 @@ expand_field_assignment (x)
      rtx x;
 {
   rtx inner;
-  rtx pos;                     /* Always counts from low bit. */
+  rtx pos;                     /* Always counts from low bit.  */
   int len;
   rtx mask;
   enum machine_mode compute_mode;
@@ -4920,7 +5175,7 @@ expand_field_assignment (x)
        {
          inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
          len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
-         pos = const0_rtx;
+         pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
        }
       else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
               && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
@@ -5027,7 +5282,10 @@ expand_field_assignment (x)
    IN_COMPARE is non-zero if we are in a COMPARE.  This means that a
    ZERO_EXTRACT should be built even for bits starting at bit 0.
 
-   MODE is the desired mode of the result (if IN_DEST == 0).  */
+   MODE is the desired mode of the result (if IN_DEST == 0).
+
+   The result is an RTX for the extraction or NULL_RTX if the target
+   can't handle it.  */
 
 static rtx
 make_extraction (mode, inner, pos, pos_rtx, len,
@@ -5045,7 +5303,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
      ignore the POS lowest bits, etc.  */
   enum machine_mode is_mode = GET_MODE (inner);
   enum machine_mode inner_mode;
-  enum machine_mode wanted_mem_mode = byte_mode;
+  enum machine_mode wanted_inner_mode = byte_mode;
+  enum machine_mode wanted_inner_reg_mode = word_mode;
   enum machine_mode pos_mode = word_mode;
   enum machine_mode extraction_mode = word_mode;
   enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
@@ -5092,7 +5351,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
   if (tmode != BLKmode
       && ! (spans_byte && inner_mode != tmode)
-      && ((pos_rtx == 0 && pos == 0 && GET_CODE (inner) != MEM
+      && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
+          && GET_CODE (inner) != MEM
           && (! in_dest
               || (GET_CODE (inner) == REG
                   && (movstrict_optab->handlers[(int) tmode].insn_code
@@ -5112,8 +5372,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
         field.  If the original and current mode are the same, we need not
         adjust the offset.  Otherwise, we do if bytes big endian.  
 
-        If INNER is not a MEM, get a piece consisting of the just the field
-        of interest (in this case POS must be 0).  */
+        If INNER is not a MEM, get a piece consisting of just the field
+        of interest (in this case POS % BITS_PER_WORD must be 0).  */
 
       if (GET_CODE (inner) == MEM)
        {
@@ -5137,10 +5397,11 @@ make_extraction (mode, inner, pos, pos_rtx, len,
            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));
+                           ? (((GET_MODE_SIZE (inner_mode)
+                                - GET_MODE_SIZE (tmode))
+                               / UNITS_PER_WORD)
+                              - pos / BITS_PER_WORD)
+                           : pos / BITS_PER_WORD));
          else
            new = inner;
        }
@@ -5185,12 +5446,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
          || (pos_rtx != 0 && len != 1)))
     return 0;
 
-  /* Get the mode to use should INNER be a MEM, the mode for the position,
+  /* Get the mode to use should INNER not be a MEM, the mode for the position,
      and the mode for the result.  */
 #ifdef HAVE_insv
   if (in_dest)
     {
-      wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
+      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
       pos_mode = insn_operand_mode[(int) CODE_FOR_insv][2];
       extraction_mode = insn_operand_mode[(int) CODE_FOR_insv][3];
     }
@@ -5199,7 +5460,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 #ifdef HAVE_extzv
   if (! in_dest && unsignedp)
     {
-      wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
       pos_mode = insn_operand_mode[(int) CODE_FOR_extzv][3];
       extraction_mode = insn_operand_mode[(int) CODE_FOR_extzv][0];
     }
@@ -5208,7 +5469,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 #ifdef HAVE_extv
   if (! in_dest && ! unsignedp)
     {
-      wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+      wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
       pos_mode = insn_operand_mode[(int) CODE_FOR_extv][3];
       extraction_mode = insn_operand_mode[(int) CODE_FOR_extv][0];
     }
@@ -5224,40 +5485,48 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
     pos_mode = GET_MODE (pos_rtx);
 
-  /* If this is not from memory or we have to change the mode of memory and
-     cannot, the desired mode is EXTRACTION_MODE.  */
-  if (GET_CODE (inner) != MEM
-      || (inner_mode != wanted_mem_mode
-         && (mode_dependent_address_p (XEXP (inner, 0))
-             || MEM_VOLATILE_P (inner))))
-    wanted_mem_mode = extraction_mode;
+  /* If this is not from memory, the desired mode is wanted_inner_reg_mode;
+     if we have to change the mode of memory and cannot, the desired mode is
+     EXTRACTION_MODE.  */
+  if (GET_CODE (inner) != MEM)
+    wanted_inner_mode = wanted_inner_reg_mode;
+  else if (inner_mode != wanted_inner_mode
+          && (mode_dependent_address_p (XEXP (inner, 0))
+              || MEM_VOLATILE_P (inner)))
+    wanted_inner_mode = extraction_mode;
 
   orig_pos = pos;
 
   if (BITS_BIG_ENDIAN)
     {
-      /* If position is constant, compute new position.  Otherwise,
-        build subtraction.  */
+      /* POS is passed as if BITS_BIG_ENDIAN == 0, so we need to convert it to
+        BITS_BIG_ENDIAN style.  If position is constant, compute new
+        position.  Otherwise, build subtraction.
+        Note that POS is relative to the mode of the original argument.
+        If it's a MEM we need to recompute POS relative to that.
+        However, if we're extracting from (or inserting into) a register,
+        we want to recompute POS relative to wanted_inner_mode.  */
+      int width = (GET_CODE (inner) == MEM
+                  ? GET_MODE_BITSIZE (is_mode)
+                  : GET_MODE_BITSIZE (wanted_inner_mode));
+
       if (pos_rtx == 0)
-       pos = (MAX (GET_MODE_BITSIZE (is_mode),
-                   GET_MODE_BITSIZE (wanted_mem_mode))
-              - len - pos);
+       pos = width - len - pos;
       else
        pos_rtx
          = gen_rtx_combine (MINUS, GET_MODE (pos_rtx),
-                            GEN_INT (MAX (GET_MODE_BITSIZE (is_mode),
-                                          GET_MODE_BITSIZE (wanted_mem_mode))
-                                     - len),
-                            pos_rtx);
+                            GEN_INT (width - len), pos_rtx);
+      /* POS may be less than 0 now, but we check for that below.
+        Note that it can only be less than 0 if GET_CODE (inner) != MEM.  */
     }
 
   /* If INNER has a wider mode, make it smaller.  If this is a constant
      extract, try to adjust the byte to point to the byte containing
      the value.  */
-  if (wanted_mem_mode != VOIDmode
-      && GET_MODE_SIZE (wanted_mem_mode) < GET_MODE_SIZE (is_mode)
+  if (wanted_inner_mode != VOIDmode
+      && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
       && ((GET_CODE (inner) == MEM
-          && (inner_mode == wanted_mem_mode
+          && (inner_mode == wanted_inner_mode
               || (! mode_dependent_address_p (XEXP (inner, 0))
                   && ! MEM_VOLATILE_P (inner))))))
     {
@@ -5268,7 +5537,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
         If it is mixed, we must adjust.  */
             
       /* If bytes are big endian and we had a paradoxical SUBREG, we must
-        adjust OFFSET to compensate. */
+        adjust OFFSET to compensate.  */
       if (BYTES_BIG_ENDIAN
          && ! spans_byte
          && GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode))
@@ -5278,18 +5547,18 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       if (pos_rtx == 0)
        {
          offset += pos / BITS_PER_UNIT;
-         pos %= GET_MODE_BITSIZE (wanted_mem_mode);
+         pos %= GET_MODE_BITSIZE (wanted_inner_mode);
        }
 
       if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
          && ! spans_byte
-         && is_mode != wanted_mem_mode)
+         && is_mode != wanted_inner_mode)
        offset = (GET_MODE_SIZE (is_mode)
-                 - GET_MODE_SIZE (wanted_mem_mode) - offset);
+                 - GET_MODE_SIZE (wanted_inner_mode) - offset);
 
-      if (offset != 0 || inner_mode != wanted_mem_mode)
+      if (offset != 0 || inner_mode != wanted_inner_mode)
        {
-         rtx newmem = gen_rtx (MEM, wanted_mem_mode,
+         rtx newmem = gen_rtx (MEM, wanted_inner_mode,
                                plus_constant (XEXP (inner, 0), offset));
          RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner);
          MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (inner);
@@ -5298,13 +5567,23 @@ make_extraction (mode, inner, pos, pos_rtx, len,
        }
     }
 
-  /* If INNER is not memory, we can always get it into the proper mode. */
+  /* If INNER is not memory, we can always get it into the proper mode.  If we
+     are changing its mode, POS must be a constant and smaller than the size
+     of the new mode.  */
   else if (GET_CODE (inner) != MEM)
-    inner = force_to_mode (inner, extraction_mode,
-                          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, 0);
+    {
+      if (GET_MODE (inner) != wanted_inner_mode
+         && (pos_rtx != 0
+             || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
+       return 0;
+
+      inner = force_to_mode (inner, wanted_inner_mode,
+                            pos_rtx
+                            || len + orig_pos >= HOST_BITS_PER_WIDE_INT
+                            ? GET_MODE_MASK (wanted_inner_mode)
+                            : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
+                            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.  */
@@ -5317,7 +5596,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
   /* Make POS_RTX unless we already have it and it is correct.  If we don't
      have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
-     be a CONST_INT. */
+     be a CONST_INT.  */
   if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
     pos_rtx = orig_pos_rtx;
 
@@ -5557,7 +5836,7 @@ make_compound_operation (x, in_code)
          break;
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case ASHIFTRT:
       lhs = XEXP (x, 0);
@@ -5764,7 +6043,7 @@ force_to_mode (x, mode, mask, reg, just_select)
     {
     case CLOBBER:
       /* If X is a (clobber (const_int)), return it since we know we are
-        generating something that won't match. */
+        generating something that won't match.  */
       return x;
 
     case USE:
@@ -5878,7 +6157,7 @@ force_to_mode (x, mode, mask, reg, just_select)
                                mode, mask, reg, next_select);
       }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case MINUS:
     case MULT:
@@ -5904,13 +6183,14 @@ force_to_mode (x, mode, mask, reg, just_select)
               + floor_log2 (INTVAL (XEXP (x, 1))))
              < GET_MODE_BITSIZE (GET_MODE (x)))
          && (INTVAL (XEXP (x, 1))
-             & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x)) == 0))
+             & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
        {
          temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
                              << INTVAL (XEXP (XEXP (x, 0), 1)));
          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));
+         x = gen_binary (LSHIFTRT, GET_MODE (x), temp,
+                         XEXP (XEXP (x, 0), 1));
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
@@ -6041,7 +6321,7 @@ force_to_mode (x, mode, mask, reg, just_select)
 
          if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
            {
-             nonzero = ~(HOST_WIDE_INT)0;
+             nonzero = ~ (HOST_WIDE_INT) 0;
 
              /* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
                 is the number of bits a full-width mask would have set.
@@ -6145,6 +6425,10 @@ force_to_mode (x, mode, mask, reg, just_select)
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
+      /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
+        use the full mask inside the NOT.  */
+      mask = fuller_mask;
+
     unop:
       op0 = gen_lowpart_for_combine (op_mode,
                                     force_to_mode (XEXP (x, 0), mode, mask,
@@ -6155,10 +6439,11 @@ force_to_mode (x, mode, mask, reg, just_select)
 
     case NE:
       /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included
-        in STORE_FLAG_VALUE and FOO has no bits that might be nonzero not
-        in CONST.  */
-      if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 0) == const0_rtx
-         && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0)
+        in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
+        which is equal to STORE_FLAG_VALUE.  */
+      if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+         && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
+         && nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE)
        return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 
       break;
@@ -6227,17 +6512,25 @@ if_then_else_cond (x, ptrue, pfalse)
       if ((cond0 != 0 || cond1 != 0)
          && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
        {
+         /* If if_then_else_cond returned zero, then true/false are the
+            same rtl.  We must copy one of them to prevent invalid rtl
+            sharing.  */
+         if (cond0 == 0)
+           true0 = copy_rtx (true0);
+         else if (cond1 == 0)
+           true1 = copy_rtx (true1);
+
          *ptrue = gen_binary (code, mode, true0, true1);
          *pfalse = gen_binary (code, mode, false0, false1);
          return cond0 ? cond0 : cond1;
        }
 
-#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.  */
+        operands is zero when the other is non-zero, and vice-versa,
+        and STORE_FLAG_VALUE is 1 or -1.  */
 
-      if ((code == PLUS || code == IOR || code == XOR || code == MINUS
+      if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+         && (code == PLUS || code == IOR || code == XOR || code == MINUS
           || code == UMAX)
          && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
        {
@@ -6270,7 +6563,8 @@ if_then_else_cond (x, ptrue, pfalse)
 
       /* Similarly for MULT, AND and UMIN, execpt that for these the result
         is always zero.  */
-      if ((code == MULT || code == AND || code == UMIN)
+      if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+         && (code == MULT || code == AND || code == UMIN)
          && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
        {
          cond0 = XEXP (XEXP (x, 0), 0);
@@ -6292,7 +6586,6 @@ if_then_else_cond (x, ptrue, pfalse)
              return cond0;
            }
        }
-#endif
     }
 
   else if (code == IF_THEN_ELSE)
@@ -6445,6 +6738,52 @@ known_cond (x, cond, reg, val)
   return x;
 }
 \f
+/* See if X and Y are equal for the purposes of seeing if we can rewrite an
+   assignment as a field assignment.  */
+
+static int
+rtx_equal_for_field_assignment_p (x, y)
+     rtx x;
+     rtx y;
+{
+  rtx last_x, last_y;
+
+  if (x == y || rtx_equal_p (x, y))
+    return 1;
+
+  if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y))
+    return 0;
+
+  /* Check for a paradoxical SUBREG of a MEM compared with the MEM.
+     Note that all SUBREGs of MEM are paradoxical; otherwise they
+     would have been rewritten.  */
+  if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
+      && GET_CODE (SUBREG_REG (y)) == MEM
+      && rtx_equal_p (SUBREG_REG (y),
+                     gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x)))
+    return 1;
+
+  if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG
+      && GET_CODE (SUBREG_REG (x)) == MEM
+      && rtx_equal_p (SUBREG_REG (x),
+                     gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
+    return 1;
+
+  last_x = get_last_value (x);
+  last_y = get_last_value (y);
+
+  return ((last_x != 0
+          && GET_CODE (last_x) != CLOBBER
+          && rtx_equal_for_field_assignment_p (last_x, y))
+         || (last_y != 0
+             && GET_CODE (last_y) != CLOBBER
+             && rtx_equal_for_field_assignment_p (x, last_y))
+         || (last_x != 0 && last_y != 0
+             && GET_CODE (last_x) != CLOBBER
+             && GET_CODE (last_y) != CLOBBER
+             && rtx_equal_for_field_assignment_p (last_x, last_y)));
+}
+\f
 /* See if X, a SET operation, can be rewritten as a bit-field assignment.
    Return that assignment if so.
 
@@ -6457,6 +6796,7 @@ make_field_assignment (x)
   rtx dest = SET_DEST (x);
   rtx src = SET_SRC (x);
   rtx assign;
+  rtx rhs, lhs;
   HOST_WIDE_INT c1;
   int pos, len;
   rtx other;
@@ -6470,13 +6810,13 @@ make_field_assignment (x)
   if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
       && GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT
       && INTVAL (XEXP (XEXP (src, 0), 0)) == -2
-      && (rtx_equal_p (dest, XEXP (src, 1))
-         || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
-         || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+      && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
       assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
-      return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+      if (assign != 0)
+       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+      return x;
     }
 
   else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
@@ -6485,60 +6825,63 @@ make_field_assignment (x)
               < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
           && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
           && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
-          && (rtx_equal_p (dest, XEXP (src, 1))
-              || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
-              || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+          && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
       assign = make_extraction (VOIDmode, dest, 0,
                                XEXP (SUBREG_REG (XEXP (src, 0)), 1),
                                1, 1, 1, 0);
-      return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+      if (assign != 0)
+       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+      return x;
     }
 
-  /* If SRC is (ior (ashift (const_int 1) POS DEST)), this is a set of a
+  /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a
      one-bit field.  */
   else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
           && XEXP (XEXP (src, 0), 0) == const1_rtx
-          && (rtx_equal_p (dest, XEXP (src, 1))
-              || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
-              || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+          && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
       assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
-      return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+      if (assign != 0)
+       return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+      return x;
     }
 
   /* The other case we handle is assignments into a constant-position
-     field.  They look like (ior (and DEST C1) OTHER).  If C1 represents
+     field.  They look like (ior/xor (and DEST C1) OTHER).  If C1 represents
      a mask that has all one bits except for a group of zero bits and
      OTHER is known to have zeros where C1 has ones, this is such an
      assignment.  Compute the position and length from C1.  Shift OTHER
      to the appropriate position, force it to the required mode, and
      make the extraction.  Check for the AND in both operands.  */
 
-  if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == AND
-      && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT
-      && (rtx_equal_p (XEXP (XEXP (src, 0), 0), dest)
-         || rtx_equal_p (XEXP (XEXP (src, 0), 0), get_last_value (dest))
-         || rtx_equal_p (get_last_value (XEXP (XEXP (src, 0), 1)), dest)))
-    c1 = INTVAL (XEXP (XEXP (src, 0), 1)), other = XEXP (src, 1);
-  else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 1)) == AND
-          && GET_CODE (XEXP (XEXP (src, 1), 1)) == CONST_INT
-          && (rtx_equal_p (XEXP (XEXP (src, 1), 0), dest)
-              || rtx_equal_p (XEXP (XEXP (src, 1), 0), get_last_value (dest))
-              || rtx_equal_p (get_last_value (XEXP (XEXP (src, 1), 0)),
-                              dest)))
-    c1 = INTVAL (XEXP (XEXP (src, 1), 1)), other = XEXP (src, 0);
+  if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
+    return x;
+
+  rhs = expand_compound_operation (XEXP (src, 0));
+  lhs = expand_compound_operation (XEXP (src, 1));
+
+  if (GET_CODE (rhs) == AND
+      && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+      && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
+    c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
+  else if (GET_CODE (lhs) == AND
+          && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+          && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
+    c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
   else
     return x;
 
-  pos = get_pos_from_mask (c1 ^ GET_MODE_MASK (GET_MODE (dest)), &len);
+  pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len);
   if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
       || (GET_MODE_BITSIZE (GET_MODE (other)) <= HOST_BITS_PER_WIDE_INT
          && (c1 & nonzero_bits (other, GET_MODE (other))) != 0))
     return x;
 
   assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
+  if (assign == 0)
+    return x;
 
   /* The mode to use for the source is the mode of the assignment, or of
      what is inside a possible STRICT_LOW_PART.  */
@@ -6584,7 +6927,8 @@ apply_distributive_law (x)
 
   lhs = XEXP (x, 0), rhs = XEXP (x, 1);
 
-  /* If either operand is a primitive we can't do anything, so get out fast. */
+  /* If either operand is a primitive we can't do anything, so get out
+     fast.  */
   if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
       || GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
     return x;
@@ -6769,7 +7113,7 @@ simplify_and_const_int (x, mode, varop, constop)
   else
     varop = gen_lowpart_for_combine (mode, varop);
 
-  /* If we can't make the SUBREG, try to return what we were given. */
+  /* If we can't make the SUBREG, try to return what we were given.  */
   if (GET_CODE (varop) == CLOBBER)
     return x ? x : varop;
 
@@ -6793,6 +7137,13 @@ simplify_and_const_int (x, mode, varop, constop)
   return x;
 }
 \f
+/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
+   We don't let nonzero_bits recur into num_sign_bit_copies, because that
+   is less useful.  We can't allow both, because that results in exponential
+   run time recusion.  There is a nullstone testcase that triggered
+   this.  This macro avoids accidental uses of num_sign_bit_copies.  */
+#define num_sign_bit_copies()
+
 /* Given an expression, X, compute which bits in X can be non-zero.
    We don't care about bits outside of those defined in MODE.
 
@@ -6850,32 +7201,44 @@ nonzero_bits (x, mode)
   switch (code)
     {
     case REG:
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If pointers extend unsigned and this is a pointer in Pmode, say that
+        all the bits above ptr_mode are known to be zero.  */
+      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && REGNO_POINTER_FLAG (REGNO (x)))
+       nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
+
 #ifdef STACK_BOUNDARY
       /* If this is the stack pointer, we may know something about its
         alignment.  If PUSH_ROUNDING is defined, it is possible for the
         stack to be momentarily aligned only to that amount, so we pick
         the least alignment.  */
 
-      if (x == stack_pointer_rtx)
+      /* We can't check for arg_pointer_rtx here, because it is not
+        guaranteed to have as much alignment as the stack pointer.
+        In particular, in the Irix6 n64 ABI, the stack has 128 bit
+        alignment but the argument pointer has only 64 bit alignment.  */
+
+      if (x == stack_pointer_rtx || x == frame_pointer_rtx
+         || x == hard_frame_pointer_rtx
+         || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+             && REGNO (x) <= LAST_VIRTUAL_REGISTER))
        {
          int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
 
 #ifdef PUSH_ROUNDING
-         sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
+         if (REGNO (x) == STACK_POINTER_REGNUM)
+           sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
 #endif
 
-         nonzero &= ~ (sp_alignment - 1);
+         /* We must return here, otherwise we may get a worse result from
+            one of the choices below.  There is nothing useful below as
+            far as the stack pointer is concerned.  */
+         return nonzero &= ~ (sp_alignment - 1);
        }
 #endif
 
-#ifdef POINTERS_EXTEND_UNSIGNED
-      /* If pointers extend unsigned and this is a pointer in Pmode, say that
-        all the bits above ptr_mode are known to be zero.  */
-      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && REGNO_POINTER_FLAG (REGNO (x)))
-       nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-
       /* If X is a register whose nonzero bits value is current, use it.
         Otherwise, if X is a register whose value we can find, use that
         value.  Otherwise, use the previously-computed global nonzero bits
@@ -6955,18 +7318,26 @@ nonzero_bits (x, mode)
       break;
 
     case NEG:
+#if 0
+      /* Disabled to avoid exponential mutual recursion between nonzero_bits
+        and num_sign_bit_copies.  */
       if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
          == GET_MODE_BITSIZE (GET_MODE (x)))
        nonzero = 1;
+#endif
 
       if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
        nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
       break;
 
     case ABS:
+#if 0
+      /* Disabled to avoid exponential mutual recursion between nonzero_bits
+        and num_sign_bit_copies.  */
       if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
          == GET_MODE_BITSIZE (GET_MODE (x)))
        nonzero = 1;
+#endif
       break;
 
     case TRUNCATE:
@@ -7165,6 +7536,9 @@ nonzero_bits (x, mode)
 
   return nonzero;
 }
+
+/* See the macro definition above.  */
+#undef num_sign_bit_copies
 \f
 /* Return the number of bits at the high-order end of X that are known to
    be equal to the sign bit.  X will be used in mode MODE; if MODE is
@@ -7194,7 +7568,7 @@ num_sign_bit_copies (x, mode)
 
   bitwidth = GET_MODE_BITSIZE (mode);
 
-  /* For a smaller object, just ignore the high bits. */
+  /* For a smaller object, just ignore the high bits.  */
   if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
     return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
                    - (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
@@ -7261,7 +7635,7 @@ num_sign_bit_copies (x, mode)
        return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
                    num_sign_bit_copies (SUBREG_REG (x), mode));
 
-      /* For a smaller object, just ignore the high bits. */
+      /* For a smaller object, just ignore the high bits.  */
       if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
        {
          num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode);
@@ -7300,7 +7674,7 @@ num_sign_bit_copies (x, mode)
              + num_sign_bit_copies (XEXP (x, 0), VOIDmode));
 
     case TRUNCATE:
-      /* For a smaller object, just ignore the high bits. */
+      /* For a smaller object, just ignore the high bits.  */
       num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode);
       return MAX (1, (num0 - (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
                              - bitwidth)));
@@ -7379,8 +7753,8 @@ num_sign_bit_copies (x, mode)
          && bitwidth <= HOST_BITS_PER_WIDE_INT
          && ((nonzero_bits (XEXP (x, 0), mode)
               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-         && (nonzero_bits (XEXP (x, 1), mode)
-             & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) != 0))
+         && ((nonzero_bits (XEXP (x, 1), mode)
+             & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
        result--;
 
       return MAX (1, result);
@@ -7441,11 +7815,10 @@ num_sign_bit_copies (x, mode)
       num1 = num_sign_bit_copies (XEXP (x, 2), mode);
       return MIN (num0, num1);
 
-#if STORE_FLAG_VALUE == -1
     case EQ:  case NE:  case GE:  case GT:  case LE:  case LT:
     case GEU: case GTU: case LEU: case LTU:
-      return bitwidth;
-#endif
+      if (STORE_FLAG_VALUE == -1)
+       return bitwidth;
     }
 
   /* If we haven't been able to figure it out by one of the above rules,
@@ -7691,7 +8064,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
       /* We need to determine what mode we will do the shift in.  If the
         shift is a right shift or a ROTATE, we must always do it in the mode
         it was originally done in.  Otherwise, we can do it in MODE, the
-        widest mode encountered. */
+        widest mode encountered.  */
       shift_mode
        = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
           ? result_mode : mode);
@@ -7724,7 +8097,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
 
       /* Negative counts are invalid and should not have been made (a
         programmer-specified negative count should have been handled
-        above). */
+        above).  */
       else if (count < 0)
        abort ();
 
@@ -7877,7 +8250,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case LSHIFTRT:
        case ASHIFT:
@@ -8213,9 +8586,9 @@ simplify_shift_const (x, code, result_mode, varop, count)
             STORE_FLAG_VALUE of 1 or logical with STORE_FLAG_VALUE == -1,
             we have a (neg (gt X 0)) operation.  */
 
-         if (GET_CODE (XEXP (varop, 0)) == ASHIFTRT
+         if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+             && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
              && count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
-             && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
              && (code == LSHIFTRT || code == ASHIFTRT)
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
              && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
@@ -8268,7 +8641,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
   else if (GET_MODE (varop) != shift_mode)
     varop = gen_lowpart_for_combine (shift_mode, varop);
 
-  /* If we can't make the SUBREG, try to return what we were given. */
+  /* If we can't make the SUBREG, try to return what we were given.  */
   if (GET_CODE (varop) == CLOBBER)
     return x ? x : varop;
 
@@ -8578,6 +8951,7 @@ gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
   int i, j;
   char *fmt;
   rtx rt;
+  struct undo *undo;
 
   VA_START (p, mode);
 
@@ -8604,17 +8978,17 @@ gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
   /* See if this is in undobuf.  Be sure we don't use objects that came
      from another insn; this could produce circular rtl structures.  */
 
-  for (i = previous_num_undos; i < undobuf.num_undo; i++)
-    if (!undobuf.undo[i].is_int
-       && GET_CODE (undobuf.undo[i].old_contents.r) == code
-       && GET_MODE (undobuf.undo[i].old_contents.r) == mode)
+  for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next)
+    if (!undo->is_int
+       && GET_CODE (undo->old_contents.r) == code
+       && GET_MODE (undo->old_contents.r) == mode)
       {
        for (j = 0; j < n_args; j++)
-         if (XEXP (undobuf.undo[i].old_contents.r, j) != args[j])
+         if (XEXP (undo->old_contents.r, j) != args[j])
            break;
 
        if (j == n_args)
-         return undobuf.undo[i].old_contents.r;
+         return undo->old_contents.r;
       }
 
   /* Otherwise make a new rtx.  We know we have 1, 2, or 3 args.
@@ -8653,7 +9027,7 @@ gen_binary (code, mode, op0, op1)
       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). */
+        just (REL_OP X Y).  */
       if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
        {
          op1 = XEXP (op0, 1);
@@ -8815,16 +9189,16 @@ simplify_comparison (code, pop0, pop1)
                  == 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)))))
+             && (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. */
+                off the original sign bit.  */
              code = unsigned_condition (code);
 
              changed = 1;
@@ -8860,8 +9234,9 @@ simplify_comparison (code, pop0, pop1)
     }
      
   /* If the first operand is a constant, swap the operands and adjust the
-     comparison code appropriately.  */
-  if (CONSTANT_P (op0))
+     comparison code appropriately, but don't do this if the second operand
+     is already a constant integer.  */
+  if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
     {
       tem = op0, op0 = op1, op1 = tem;
       code = swap_condition (code);
@@ -8963,7 +9338,7 @@ simplify_comparison (code, pop0, pop1)
          break;
 
        case GE:
-         /* >= C is equivalent to > (C - 1). */
+         /* >= C is equivalent to > (C - 1).  */
          if (const_op > 0)
            {
              const_op -= 1;
@@ -8999,11 +9374,12 @@ simplify_comparison (code, pop0, pop1)
              const_op -= 1;
              op1 = GEN_INT (const_op);
              code = LEU;
-             /* ... fall through ... */
+             /* ... fall through ...  */
            }
 
          /* (unsigned) < 0x80000000 is equivalent to >= 0.  */
-         else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+                  && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
            {
              const_op = 0, op1 = const0_rtx;
              code = GE;
@@ -9017,8 +9393,9 @@ simplify_comparison (code, pop0, pop1)
          if (const_op == 0)
            code = EQ;
 
-         /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
-         else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+         /* (unsigned) <= 0x7fffffff is equivalent to >= 0.  */
+         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+                  && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
            {
              const_op = 0, op1 = const0_rtx;
              code = GE;
@@ -9032,11 +9409,12 @@ simplify_comparison (code, pop0, pop1)
              const_op -= 1;
              op1 = GEN_INT (const_op);
              code = GTU;
-             /* ... fall through ... */
+             /* ... fall through ...  */
            }
 
          /* (unsigned) >= 0x80000000 is equivalent to < 0.  */
-         else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+                  && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
            {
              const_op = 0, op1 = const0_rtx;
              code = LT;
@@ -9051,7 +9429,8 @@ simplify_comparison (code, pop0, pop1)
            code = NE;
 
          /* (unsigned) > 0x7fffffff is equivalent to < 0.  */
-         else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+         else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+                   && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
            {
              const_op = 0, op1 = const0_rtx;
              code = LT;
@@ -9085,24 +9464,19 @@ simplify_comparison (code, pop0, pop1)
          /* If we are extracting a single bit from a variable position in
             a constant that has only a single bit set and are comparing it
             with zero, we can convert this into an equality comparison 
-            between the position and the location of the single bit.  We can't
-            do this if bit endian and we don't have an extzv since we then
-            can't know what mode to use for the endianness adjustment.  */
+            between the position and the location of the single bit.  */
 
          if (GET_CODE (XEXP (op0, 0)) == CONST_INT
              && XEXP (op0, 1) == const1_rtx
              && equality_comparison_p && const_op == 0
-             && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0
-             && (! BITS_BIG_ENDIAN
-#ifdef HAVE_extzv
-                 || HAVE_extzv
-#endif
-                 ))
+             && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
            {
-#ifdef HAVE_extzv
              if (BITS_BIG_ENDIAN)
+#ifdef HAVE_extzv
                i = (GET_MODE_BITSIZE
                     (insn_operand_mode[(int) CODE_FOR_extzv][1]) - 1 - i);
+#else
+               i = BITS_PER_WORD - 1 - i;
 #endif
 
              op0 = XEXP (op0, 2);
@@ -9114,7 +9488,7 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case SIGN_EXTRACT:
          tem = expand_compound_operation (op0);
@@ -9174,7 +9548,7 @@ simplify_comparison (code, pop0, pop1)
            }
 
          /* If we have NEG of something whose two high-order bits are the
-            same, we know that "(-a) < 0" is equivalent to "a > 0". */
+            same, we know that "(-a) < 0" is equivalent to "a > 0".  */
          if (num_sign_bit_copies (op0, mode) >= 2)
            {
              op0 = XEXP (op0, 0);
@@ -9210,7 +9584,7 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case ABS:
          /* ABS is ignorable inside an equality comparison with zero.  */
@@ -9277,7 +9651,7 @@ simplify_comparison (code, pop0, pop1)
          else
            break;
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case ZERO_EXTEND:
          if ((unsigned_comparison_p || equality_comparison_p)
@@ -9560,7 +9934,7 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
        case LSHIFTRT:
          /* If we have (compare (xshiftrt FOO N) (const_int C)) and
             the low order N bits of FOO are known to be zero, we can do this
@@ -9829,11 +10203,12 @@ record_value_for_reg (reg, insn, value)
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
-  if (value && ! get_last_value_validate (&value,
+  if (value && ! get_last_value_validate (&value, insn,
                                          reg_last_set_label[regno], 0))
     {
       value = copy_rtx (value);
-      if (! get_last_value_validate (&value, reg_last_set_label[regno], 1))
+      if (! get_last_value_validate (&value, insn,
+                                    reg_last_set_label[regno], 1))
        value = 0;
     }
 
@@ -9954,8 +10329,9 @@ record_dead_and_set_regs (insn)
    we don't know exactly what registers it was produced from.  */
 
 static int
-get_last_value_validate (loc, tick, replace)
+get_last_value_validate (loc, insn, tick, replace)
      rtx *loc;
+     rtx insn;
      int tick;
      int replace;
 {
@@ -9985,10 +10361,20 @@ get_last_value_validate (loc, tick, replace)
 
       return 1;
     }
+  /* If this is a memory reference, make sure that there were
+     no stores after it that might have clobbered the value.  We don't
+     have alias info, so we assume any store invalidates it.  */
+  else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+          && INSN_CUID (insn) <= mem_last_set)
+    {
+      if (replace)
+       *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+      return replace;
+    }
 
   for (i = 0; i < len; i++)
     if ((fmt[i] == 'e'
-        && get_last_value_validate (&XEXP (x, i), tick, replace) == 0)
+        && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
        /* Don't bother with these.  They shouldn't occur anyway.  */
        || fmt[i] == 'E')
       return 0;
@@ -10010,7 +10396,7 @@ get_last_value (x)
 
   /* If this is a non-paradoxical SUBREG, get the value of its operand and
      then convert it to the desired mode.  If this is a paradoxical SUBREG,
-     we cannot predict what values the "extra" bits might have. */
+     we cannot predict what values the "extra" bits might have.  */
   if (GET_CODE (x) == SUBREG
       && subreg_lowpart_p (x)
       && (GET_MODE_SIZE (GET_MODE (x))
@@ -10024,7 +10410,8 @@ get_last_value (x)
   regno = REGNO (x);
   value = reg_last_set_value[regno];
 
-  /* If we don't have a value or if it isn't for this basic block, return 0. */
+  /* If we don't have a value or if it isn't for this basic block,
+     return 0.  */
 
   if (value == 0
       || (reg_n_sets[regno] != 1
@@ -10084,14 +10471,16 @@ get_last_value (x)
     }
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 0))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 1))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 1))
     return value;
 
   return 0;
@@ -10369,12 +10758,15 @@ remove_death (regno, insn)
    TO_INSN (exclusive), put a REG_DEAD note for that register in the
    list headed by PNOTES. 
 
+   That said, don't move registers killed by maybe_kill_insn.
+
    This is done when X is being merged by combination into TO_INSN.  These
    notes will then be distributed as needed.  */
 
 static void
-move_deaths (x, from_cuid, to_insn, pnotes)
+move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
      rtx x;
+     rtx maybe_kill_insn;
      int from_cuid;
      rtx to_insn;
      rtx *pnotes;
@@ -10389,6 +10781,11 @@ move_deaths (x, from_cuid, to_insn, pnotes)
       register rtx where_dead = reg_last_death[regno];
       register rtx before_dead, after_dead;
 
+      /* Don't move the register if it gets killed in between from and to */
+      if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
+         && !reg_referenced_p (x, maybe_kill_insn))
+       return;
+
       /* WHERE_DEAD could be a USE insn made by combine, so first we
         make sure that we have insns with valid INSN_CUID values.  */
       before_dead = where_dead;
@@ -10417,7 +10814,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
 
          if (note != 0 && regno < FIRST_PSEUDO_REGISTER
              && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-                 != GET_MODE_SIZE (GET_MODE (x))))
+                 > GET_MODE_SIZE (GET_MODE (x))))
            {
              int deadregno = REGNO (XEXP (note, 0));
              int deadend
@@ -10433,20 +10830,30 @@ move_deaths (x, from_cuid, to_insn, pnotes)
                               gen_rtx (REG, reg_raw_mode[i], i),
                               REG_NOTES (where_dead));
            }
-         /* If we didn't find any note, and we have a multi-reg hard
+         /* If we didn't find any note, or if we found a REG_DEAD note that
+            covers only part of the given reg, and we have a multi-reg hard
             register, then to be safe we must check for REG_DEAD notes
             for each register other than the first.  They could have
             their own REG_DEAD notes lying around.  */
-         else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+         else if ((note == 0
+                   || (note != 0
+                       && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+                           < GET_MODE_SIZE (GET_MODE (x)))))
+                  && regno < FIRST_PSEUDO_REGISTER
                   && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
            {
              int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
-             int i;
+             int i, offset;
              rtx oldnotes = 0;
 
-             for (i = regno + 1; i < ourend; i++)
+             if (note)
+               offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+             else
+               offset = 1;
+
+             for (i = regno + offset; i < ourend; i++)
                move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
-                            from_cuid, to_insn, &oldnotes);
+                            maybe_kill_insn, from_cuid, to_insn, &oldnotes);
            }
 
          if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
@@ -10467,7 +10874,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
     {
       rtx dest = SET_DEST (x);
 
-      move_deaths (SET_SRC (x), from_cuid, to_insn, pnotes);
+      move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
 
       /* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG
         that accesses one word of a multi-word item, some
@@ -10482,7 +10889,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
                  == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
                       + UNITS_PER_WORD - 1) / UNITS_PER_WORD))))
        {
-         move_deaths (dest, from_cuid, to_insn, pnotes);
+         move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes);
          return;
        }
 
@@ -10496,7 +10903,8 @@ move_deaths (x, from_cuid, to_insn, pnotes)
         being replaced so the old value is not used in this insn.  */
 
       if (GET_CODE (dest) == MEM)
-       move_deaths (XEXP (dest, 0), from_cuid, to_insn, pnotes);
+       move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
+                    to_insn, pnotes);
       return;
     }
 
@@ -10512,10 +10920,11 @@ move_deaths (x, from_cuid, to_insn, pnotes)
        {
          register int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-           move_deaths (XVECEXP (x, i, j), from_cuid, to_insn, pnotes);
+           move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
+                        to_insn, pnotes);
        }
       else if (fmt[i] == 'e')
-       move_deaths (XEXP (x, i), from_cuid, to_insn, pnotes);
+       move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
     }
 }
 \f
@@ -10600,6 +11009,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
       next_note = XEXP (note, 1);
       switch (REG_NOTE_KIND (note))
        {
+       case REG_BR_PROB:
+       case REG_EXEC_COUNT:
+         /* Doesn't matter much where we put this, as long as it's somewhere.
+            It is preferable to keep these notes on branches, which is most
+            likely to be i3.  */
+         place = i3;
+         break;
+
        case REG_UNUSED:
          /* Any clobbers for i3 may still exist, and so we must process
             REG_UNUSED notes from that insn.
@@ -11079,6 +11496,22 @@ distribute_links (links)
     }
 }
 \f
+/* Compute INSN_CUID for INSN, which is an insn made by combine.  */
+
+static int
+insn_cuid (insn)
+     rtx insn;
+{
+  while (insn != 0 && INSN_UID (insn) > max_uid_cuid
+        && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
+    insn = NEXT_INSN (insn);
+
+  if (INSN_UID (insn) > max_uid_cuid)
+    abort ();
+
+  return INSN_CUID (insn);
+}
+\f
 void
 dump_combine_stats (file)
      FILE *file;