OSDN Git Service

Set TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 9427060..31efa5b 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -198,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
@@ -252,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;
 
@@ -262,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;
 
@@ -271,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;
 
@@ -319,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;
@@ -331,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;
 };
 
@@ -352,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
@@ -435,12 +445,12 @@ 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));
@@ -463,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;
 
@@ -942,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
@@ -950,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;
@@ -1128,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)))
@@ -1243,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
@@ -1277,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
@@ -1517,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
@@ -1591,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;
@@ -1604,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))
@@ -1616,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
@@ -1654,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
@@ -1802,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)
@@ -1823,10 +1853,15 @@ try_combine (i3, i2, i1)
                     || 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 (SET_DEST (i2set))]++;
+               reg_n_sets[REGNO (new_i2_dest)]++;
            }
        }
 
@@ -2201,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)
@@ -2318,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]--;
@@ -2394,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.  */
@@ -2628,8 +2674,39 @@ 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),
+                    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;
@@ -2755,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.  */
@@ -2863,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));
 
@@ -3075,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);
@@ -3300,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),
@@ -3312,8 +3395,16 @@ simplify_rtx (x, op0_mode, last, in_dest)
       /* If we want a subreg of a constant, at offset 0,
         take the low bits.  On a little-endian machine, that's
         always valid.  On a big-endian machine, it's valid
-        only if the constant's mode fits in one word.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
+        only if the constant's mode fits in one word.   Note that we
+        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      if (CONSTANT_P (SUBREG_REG (x))
+         && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+             || ! WORDS_BIG_ENDIAN)
+             ? SUBREG_WORD (x) == 0
+             : (SUBREG_WORD (x)
+                == ((GET_MODE_SIZE (op0_mode)
+                     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+                    / UNITS_PER_WORD)))
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
          && (! WORDS_BIG_ENDIAN
              || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
@@ -3374,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
@@ -3440,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);
@@ -3507,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:
@@ -3650,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))  */
@@ -3733,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
@@ -3746,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)))
@@ -3762,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)
            {
@@ -3772,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)))
@@ -3780,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)
            {
@@ -3801,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)))
@@ -3812,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
@@ -3828,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)
@@ -3861,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;
 
@@ -3951,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),
@@ -4042,7 +4190,7 @@ simplify_if_then_else (x)
 
       temp = true, true = false, false = temp, cond = XEXP (x, 0);
 
-      /* It is possible that the conditional has been simplified out. */
+      /* It is possible that the conditional has been simplified out.  */
       true_code = GET_CODE (cond);
       comparison_p = GET_RTX_CLASS (true_code) == '<';
     }
@@ -4103,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);
@@ -4130,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))
@@ -4221,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
@@ -4444,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
@@ -4572,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
@@ -4762,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)),
@@ -4773,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)) == '<'
@@ -4887,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
@@ -4944,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;
@@ -5319,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))
@@ -5378,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;
 
@@ -5618,7 +5836,7 @@ make_compound_operation (x, in_code)
          break;
        }
 
-      /* ... fall through ... */
+      /* ... fall through ...  */
 
     case ASHIFTRT:
       lhs = XEXP (x, 0);
@@ -5825,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:
@@ -5939,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:
@@ -6103,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.
@@ -6221,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;
@@ -6293,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)
        {
@@ -6336,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);
@@ -6358,7 +6586,6 @@ if_then_else_cond (x, ptrue, pfalse)
              return cond0;
            }
        }
-#endif
     }
 
   else if (code == IF_THEN_ELSE)
@@ -6545,9 +6772,15 @@ rtx_equal_for_field_assignment_p (x, y)
   last_x = get_last_value (x);
   last_y = get_last_value (y);
 
-  return ((last_x != 0 && rtx_equal_for_field_assignment_p (last_x, y))
-         || (last_y != 0 && rtx_equal_for_field_assignment_p (x, last_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
@@ -6694,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;
@@ -6879,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;
 
@@ -6903,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.
 
@@ -7077,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:
@@ -7287,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
@@ -7316,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)));
@@ -7383,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);
@@ -7422,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)));
@@ -7563,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,
@@ -7813,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);
@@ -7846,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 ();
 
@@ -7999,7 +8250,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case LSHIFTRT:
        case ASHIFT:
@@ -8335,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
@@ -8390,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;
 
@@ -8700,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);
 
@@ -8726,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.
@@ -8775,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);
@@ -8946,7 +9198,7 @@ simplify_comparison (code, pop0, pop1)
              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;
@@ -8982,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);
@@ -9085,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;
@@ -9121,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;
@@ -9139,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;
@@ -9154,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;
@@ -9173,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;
@@ -9231,7 +9488,7 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case SIGN_EXTRACT:
          tem = expand_compound_operation (op0);
@@ -9291,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);
@@ -9327,7 +9584,7 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case ABS:
          /* ABS is ignorable inside an equality comparison with zero.  */
@@ -9394,7 +9651,7 @@ simplify_comparison (code, pop0, pop1)
          else
            break;
 
-         /* ... fall through ... */
+         /* ... fall through ...  */
 
        case ZERO_EXTEND:
          if ((unsigned_comparison_p || equality_comparison_p)
@@ -9677,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
@@ -9946,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;
     }
 
@@ -10071,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;
 {
@@ -10102,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;
@@ -10127,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))
@@ -10141,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
@@ -10201,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;
@@ -10486,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;
@@ -10506,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;
@@ -10534,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
@@ -10550,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))
@@ -10584,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
@@ -10599,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;
        }
 
@@ -10613,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;
     }
 
@@ -10629,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
@@ -10717,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.