OSDN Git Service

* g++.dg/other/static11.C: Use cleanup-rtl-dump.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 0b4b4ca..297b58e 100644 (file)
@@ -1,6 +1,6 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -90,9 +90,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "real.h"
 #include "toplev.h"
 #include "target.h"
+#include "optabs.h"
+#include "insn-codes.h"
 #include "rtlhooks-def.h"
 /* Include output.h for dump_file.  */
 #include "output.h"
+#include "params.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -205,7 +208,7 @@ struct reg_stat {
   int                          last_set_label;
 
   /* These fields are maintained in parallel with last_set_value and are
-     used to store the mode in which the register was last set, te bits
+     used to store the mode in which the register was last set, the bits
      that were known to be zero when it was last set, and the number of
      sign bits copies it was known to have when it was last set.  */
 
@@ -383,6 +386,7 @@ static rtx known_cond (rtx, enum rtx_code, rtx, rtx);
 static int rtx_equal_for_field_assignment_p (rtx, rtx);
 static rtx make_field_assignment (rtx);
 static rtx apply_distributive_law (rtx);
+static rtx distribute_and_simplify_rtx (rtx, int);
 static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
                                   unsigned HOST_WIDE_INT);
 static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
@@ -391,7 +395,6 @@ static rtx simplify_shift_const     (rtx, enum rtx_code, enum machine_mode, rtx,
                                 int);
 static int recog_for_combine (rtx *, rtx, rtx *);
 static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
-static rtx gen_binary (enum rtx_code, enum machine_mode, rtx, rtx);
 static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
 static void update_table_tick (rtx);
 static void record_value_for_reg (rtx, rtx, rtx);
@@ -410,8 +413,6 @@ static void distribute_links (rtx);
 static void mark_used_regs_combine (rtx);
 static int insn_cuid (rtx);
 static void record_promoted_value (rtx, rtx);
-static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx);
-static enum rtx_code combine_reversed_comparison_code (rtx);
 static int unmentioned_reg_p_1 (rtx *, void *);
 static bool unmentioned_reg_p (rtx, rtx);
 \f
@@ -455,9 +456,8 @@ do_SUBST (rtx *into, rtx newval)
     {
       /* Sanity check that we're replacing oldval with a CONST_INT
         that is a valid sign-extension for the original mode.  */
-      if (INTVAL (newval) != trunc_int_for_mode (INTVAL (newval),
-                                                GET_MODE (oldval)))
-       abort ();
+      gcc_assert (INTVAL (newval)
+                 == trunc_int_for_mode (INTVAL (newval), GET_MODE (oldval)));
 
       /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
         CONST_INT is not valid, because after the replacement, the
@@ -465,11 +465,10 @@ do_SUBST (rtx *into, rtx newval)
         when do_SUBST is called to replace the operand thereof, so we
         perform this test on oldval instead, checking whether an
         invalid replacement took place before we got here.  */
-      if ((GET_CODE (oldval) == SUBREG
-          && GET_CODE (SUBREG_REG (oldval)) == CONST_INT)
-         || (GET_CODE (oldval) == ZERO_EXTEND
-             && GET_CODE (XEXP (oldval, 0)) == CONST_INT))
-       abort ();
+      gcc_assert (!(GET_CODE (oldval) == SUBREG
+                   && GET_CODE (SUBREG_REG (oldval)) == CONST_INT));
+      gcc_assert (!(GET_CODE (oldval) == ZERO_EXTEND
+                   && GET_CODE (XEXP (oldval, 0)) == CONST_INT));
     }
 
   if (undobuf.frees)
@@ -562,10 +561,25 @@ combine_validate_cost (rtx i1, rtx i2, rtx i3, rtx newpat, rtx newi2pat)
       new_i2_cost = 0;
     }
 
+  if (undobuf.other_insn)
+    {
+      int old_other_cost, new_other_cost;
+
+      old_other_cost = (INSN_UID (undobuf.other_insn) <= last_insn_cost
+                       ? uid_insn_cost[INSN_UID (undobuf.other_insn)] : 0);
+      new_other_cost = insn_rtx_cost (PATTERN (undobuf.other_insn));
+      if (old_other_cost > 0 && new_other_cost > 0)
+       {
+         old_cost += old_other_cost;
+         new_cost += new_other_cost;
+       }
+      else
+       old_cost = 0;
+    }
+
   /* Disallow this recombination if both new_cost and old_cost are
      greater than zero, and new_cost is greater than old cost.  */
-  if (!undobuf.other_insn
-      && old_cost > 0
+  if (old_cost > 0
       && new_cost > old_cost)
     {
       if (dump_file)
@@ -1178,6 +1192,8 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       /* Don't substitute into an incremented register.  */
       || FIND_REG_INC_NOTE (i3, dest)
       || (succ && FIND_REG_INC_NOTE (succ, dest))
+      /* Don't substitute into a non-local goto, this confuses CFG.  */
+      || (JUMP_P (i3) && find_reg_note (i3, REG_NON_LOCAL_GOTO, NULL_RTX))
 #if 0
       /* Don't combine the end of a libcall into anything.  */
       /* ??? This gives worse code, and appears to be unnecessary, since no
@@ -1251,14 +1267,14 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
       if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER)
        {
           /* Don't substitute for a register intended as a clobberable
-            operand. */
+            operand.  */
          rtx reg = XEXP (XVECEXP (PATTERN (i3), 0, i), 0);
          if (rtx_equal_p (reg, dest))
            return 0;
 
          /* If the clobber represents an earlyclobber operand, we must not
             substitute an expression containing the clobbered register.
-            As we do not analyse the constraint strings here, we have to
+            As we do not analyze the constraint strings here, we have to
             make the conservative assumption.  However, if the register is
             a fixed hard reg, the clobber cannot represent any operand;
             we leave it up to the machine description to either accept or
@@ -1298,9 +1314,9 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     if (INSN_P (p) && p != succ && volatile_insn_p (PATTERN (p)))
       return 0;
 
-  /* If INSN or I2 contains an autoincrement or autodecrement,
-     make sure that register is not used between there and I3,
-     and not already used in I3 either.
+  /* If INSN contains an autoincrement or autodecrement, make sure that
+     register is not used between there and I3, and not already used in
+     I3 either.  Neither must it be used in PRED or SUCC, if they exist.
      Also insist that I3 not be a jump; if it were one
      and the incremented register were spilled, we would lose.  */
 
@@ -1309,6 +1325,10 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ,
     if (REG_NOTE_KIND (link) == REG_INC
        && (JUMP_P (i3)
            || reg_used_between_p (XEXP (link, 0), insn, i3)
+           || (pred != NULL_RTX
+               && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (pred)))
+           || (succ != NULL_RTX
+               && reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (succ)))
            || reg_overlap_mentioned_p (XEXP (link, 0), PATTERN (i3))))
       return 0;
 #endif
@@ -1576,6 +1596,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
+  rtvec newpat_vec_with_clobbers = 0;
   int substed_i2 = 0, substed_i1 = 0;
   /* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead.  */
   int added_sets_1, added_sets_2;
@@ -1602,6 +1623,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   int i3_subst_into_i2 = 0;
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
+  int swap_i2i3 = 0;
 
   int maxreg;
   rtx temp;
@@ -1745,8 +1767,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        {
          /* We don't handle the case of the target word being wider
             than a host wide int.  */
-         if (HOST_BITS_PER_WIDE_INT < BITS_PER_WORD)
-           abort ();
+         gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD);
 
          lo &= ~(UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD (1) - 1);
          lo |= (INTVAL (SET_SRC (PATTERN (i3)))
@@ -1769,7 +1790,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       else
        /* We don't handle the case of the higher word not fitting
           entirely in either hi or lo.  */
-       abort ();
+       gcc_unreachable ();
 
       combine_merges++;
       subst_insn = i3;
@@ -2136,6 +2157,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* Note which hard regs this insn has as inputs.  */
   mark_used_regs_combine (newpat);
 
+  /* If recog_for_combine fails, it strips existing clobbers.  If we'll
+     consider splitting this pattern, we might need these clobbers.  */
+  if (i1 && GET_CODE (newpat) == PARALLEL
+      && GET_CODE (XVECEXP (newpat, 0, XVECLEN (newpat, 0) - 1)) == CLOBBER)
+    {
+      int len = XVECLEN (newpat, 0);
+
+      newpat_vec_with_clobbers = rtvec_alloc (len);
+      for (i = 0; i < len; i++)
+       RTVEC_ELT (newpat_vec_with_clobbers, i) = XVECEXP (newpat, 0, i);
+    }
+
   /* Is the result of combination a valid instruction?  */
   insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
@@ -2263,6 +2296,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
            }
        }
 
+      /* If recog_for_combine has discarded clobbers, try to use them
+        again for the split.  */
+      if (m_split == 0 && newpat_vec_with_clobbers)
+       m_split
+         = split_insns (gen_rtx_PARALLEL (VOIDmode,
+                                          newpat_vec_with_clobbers), i3);
+
       if (m_split && NEXT_INSN (m_split) == NULL_RTX)
        {
          m_split = PATTERN (m_split);
@@ -2335,11 +2375,17 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          && REG_P (i2dest)
 #endif
          /* We need I2DEST in the proper mode.  If it is a hard register
-            or the only use of a pseudo, we can change its mode.  */
+            or the only use of a pseudo, we can change its mode.
+            Make sure we don't change a hard register to have a mode that
+            isn't valid for it, or change the number of registers.  */
          && (GET_MODE (*split) == GET_MODE (i2dest)
              || GET_MODE (*split) == VOIDmode
-             || REGNO (i2dest) < FIRST_PSEUDO_REGISTER
-             || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
+             || (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
+                 && HARD_REGNO_MODE_OK (REGNO (i2dest), GET_MODE (*split))
+                 && (HARD_REGNO_NREGS (REGNO (i2dest), GET_MODE (i2dest))
+                     == HARD_REGNO_NREGS (REGNO (i2dest), GET_MODE (*split))))
+             || (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER
+                 && REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
                  && ! REG_USERVAR_P (i2dest)))
          && (next_real_insn (i2) == i3
              || ! use_crosses_set_p (*split, INSN_CUID (i2)))
@@ -2399,6 +2445,20 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          SUBST (*split, newdest);
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
+         /* recog_for_combine might have added CLOBBERs to newi2pat.
+            Make sure NEWPAT does not depend on the clobbered regs.  */
+         if (GET_CODE (newi2pat) == PARALLEL)
+           for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+             if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+               {
+                 rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+                 if (reg_overlap_mentioned_p (reg, newpat))
+                   {
+                     undo_all ();
+                     return 0;
+                   }
+               }
+
          /* If the split point was a MULT and we didn't have one before,
             don't use one now.  */
          if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
@@ -2468,40 +2528,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
 
       if (insn_code_number >= 0)
-       {
-         rtx insn;
-         rtx link;
-
-         /* If we will be able to accept this, we have made a change to the
-            destination of I3.  This requires us to do a few adjustments.  */
-         PATTERN (i3) = newpat;
-         adjust_for_new_dest (i3);
-
-         /* I3 now uses what used to be its destination and which is
-            now I2's destination.  That means we need a LOG_LINK from
-            I3 to I2.  But we used to have one, so we still will.
-
-            However, some later insn might be using I2's dest and have
-            a LOG_LINK pointing at I3.  We must remove this link.
-            The simplest way to remove the link is to point it at I1,
-            which we know will be a NOTE.  */
-
-         for (insn = NEXT_INSN (i3);
-              insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
-                       || insn != BB_HEAD (this_basic_block->next_bb));
-              insn = NEXT_INSN (insn))
-           {
-             if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
-               {
-                 for (link = LOG_LINKS (insn); link;
-                      link = XEXP (link, 1))
-                   if (XEXP (link, 0) == i3)
-                     XEXP (link, 0) = i1;
-
-                 break;
-               }
-           }
-       }
+       swap_i2i3 = 1;
     }
 
   /* Similarly, check for a case where we have a PARALLEL of two independent
@@ -2631,6 +2658,49 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   /* We now know that we can do this combination.  Merge the insns and
      update the status of registers and LOG_LINKS.  */
 
+  if (swap_i2i3)
+    {
+      rtx insn;
+      rtx link;
+      rtx ni2dest;
+
+      /* I3 now uses what used to be its destination and which is now
+         I2's destination.  This requires us to do a few adjustments.  */
+      PATTERN (i3) = newpat;
+      adjust_for_new_dest (i3);
+
+      /* We need a LOG_LINK from I3 to I2.  But we used to have one,
+         so we still will.
+
+        However, some later insn might be using I2's dest and have
+        a LOG_LINK pointing at I3.  We must remove this link.
+        The simplest way to remove the link is to point it at I1,
+        which we know will be a NOTE.  */
+
+      /* newi2pat is usually a SET here; however, recog_for_combine might
+        have added some clobbers.  */
+      if (GET_CODE (newi2pat) == PARALLEL)
+       ni2dest = SET_DEST (XVECEXP (newi2pat, 0, 0));
+      else
+       ni2dest = SET_DEST (newi2pat);
+
+      for (insn = NEXT_INSN (i3);
+          insn && (this_basic_block->next_bb == EXIT_BLOCK_PTR
+                   || insn != BB_HEAD (this_basic_block->next_bb));
+          insn = NEXT_INSN (insn))
+       {
+         if (INSN_P (insn) && reg_referenced_p (ni2dest, PATTERN (insn)))
+           {
+             for (link = LOG_LINKS (insn); link;
+                  link = XEXP (link, 1))
+               if (XEXP (link, 0) == i3)
+                 XEXP (link, 0) = i1;
+
+             break;
+           }
+       }
+    }
+
   {
     rtx i3notes, i2notes, i1notes = 0;
     rtx i3links, i2links, i1links = 0;
@@ -3149,14 +3219,16 @@ find_split_point (rtx *loc, rtx insn)
 
          if (src == mask)
            SUBST (SET_SRC (x),
-                  gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
+                  simplify_gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
          else
-           SUBST (SET_SRC (x),
-                  gen_binary (IOR, mode,
-                              gen_binary (AND, mode, dest,
-                                          gen_int_mode (~(mask << pos),
-                                                        mode)),
-                              GEN_INT (src << pos)));
+           {
+             rtx negmask = gen_int_mode (~(mask << pos), mode);
+             SUBST (SET_SRC (x),
+                    simplify_gen_binary (IOR, mode,
+                                         simplify_gen_binary (AND, mode,
+                                                              dest, negmask),
+                                         GEN_INT (src << pos)));
+           }
 
          SUBST (SET_DEST (x), dest);
 
@@ -3546,10 +3618,10 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
              /* If this is a register being set, ignore it.  */
              new = XEXP (x, i);
              if (in_dest
-                 && (code == SUBREG || code == STRICT_LOW_PART
-                     || code == ZERO_EXTRACT)
                  && i == 0
-                 && REG_P (new))
+                 && (((code == SUBREG || code == ZERO_EXTRACT)
+                      && REG_P (new))
+                     || code == STRICT_LOW_PART))
                ;
 
              else if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
@@ -3634,8 +3706,7 @@ subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
                {
                  x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
                                                new, GET_MODE (XEXP (x, 0)));
-                 if (! x)
-                   abort ();
+                 gcc_assert (x);
                }
              else
                SUBST (XEXP (x, i), new);
@@ -3731,7 +3802,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       new = simplify_shift_const (NULL_RTX, ASHIFTRT, mode, new,
                                  INTVAL (XEXP (XEXP (x, 0), 1)));
 
-      SUBST (XEXP (x, 0), gen_binary (PLUS, mode, new, temp));
+      SUBST (XEXP (x, 0), simplify_gen_binary (PLUS, mode, new, temp));
     }
 
   /* If this is a simple operation applied to an IF_THEN_ELSE, try
@@ -3788,12 +3859,14 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
              /* If the result values are STORE_FLAG_VALUE and zero, we can
                 just make the comparison operation.  */
              if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
-               x = gen_binary (cond_code, mode, cond, cop1);
+               x = simplify_gen_relational (cond_code, mode, VOIDmode,
+                                            cond, cop1);
              else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
                       && ((reversed = reversed_comparison_code_parts
                                        (cond_code, cond, cop1, NULL))
                           != UNKNOWN))
-               x = gen_binary (reversed, mode, cond, cop1);
+               x = simplify_gen_relational (reversed, mode, VOIDmode,
+                                            cond, cop1);
 
              /* Likewise, we can make the negate of a comparison operation
                 if the result values are - STORE_FLAG_VALUE and zero.  */
@@ -3801,8 +3874,9 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                       && INTVAL (true_rtx) == - STORE_FLAG_VALUE
                       && false_rtx == const0_rtx)
                x = simplify_gen_unary (NEG, mode,
-                                       gen_binary (cond_code, mode, cond,
-                                                   cop1),
+                                       simplify_gen_relational (cond_code,
+                                                                mode, VOIDmode,
+                                                                cond, cop1),
                                        mode);
              else if (GET_CODE (false_rtx) == CONST_INT
                       && INTVAL (false_rtx) == - STORE_FLAG_VALUE
@@ -3811,13 +3885,17 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                                        (cond_code, cond, cop1, NULL))
                           != UNKNOWN))
                x = simplify_gen_unary (NEG, mode,
-                                       gen_binary (reversed, mode,
-                                                   cond, cop1),
+                                       simplify_gen_relational (reversed,
+                                                                mode, VOIDmode,
+                                                                cond, cop1),
                                        mode);
              else
                return gen_rtx_IF_THEN_ELSE (mode,
-                                            gen_binary (cond_code, VOIDmode,
-                                                        cond, cop1),
+                                            simplify_gen_relational (cond_code,
+                                                                     mode,
+                                                                     VOIDmode,
+                                                                     cond,
+                                                                     cop1),
                                             true_rtx, false_rtx);
 
              code = GET_CODE (x);
@@ -3920,7 +3998,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
            }
 
          if (inner)
-           return gen_binary (code, mode, other, inner);
+           return simplify_gen_binary (code, mode, other, inner);
        }
     }
 
@@ -4022,7 +4100,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       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);
+       return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
+                                   constm1_rtx);
 
       temp = expand_compound_operation (XEXP (x, 0));
 
@@ -4250,8 +4329,9 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
          in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
          in2 = XEXP (XEXP (x, 0), 1);
-         return gen_binary (MINUS, mode, XEXP (x, 1),
-                            gen_binary (MULT, mode, in1, in2));
+         return simplify_gen_binary (MINUS, mode, XEXP (x, 1),
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2));
        }
 
       /* If we have (plus (plus (A const) B)), associate it so that CONST is
@@ -4260,10 +4340,11 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
         they are now checked elsewhere.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && CONSTANT_ADDRESS_P (XEXP (XEXP (x, 0), 1)))
-       return gen_binary (PLUS, mode,
-                          gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
-                                      XEXP (x, 1)),
-                          XEXP (XEXP (x, 0), 1));
+       return simplify_gen_binary (PLUS, mode,
+                                   simplify_gen_binary (PLUS, mode,
+                                                        XEXP (XEXP (x, 0), 0),
+                                                        XEXP (x, 1)),
+                                   XEXP (XEXP (x, 0), 1));
 
       /* (plus (xor (and <foo> (const_int pow2 - 1)) <c>) <-c>)
         when c is (const_int (pow2 + 1) / 2) is a sign extension of a
@@ -4298,9 +4379,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       if (COMPARISON_P (XEXP (x, 0))
          && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
              || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx))
-         && (reversed = reversed_comparison (XEXP (x, 0), mode,
-                                             XEXP (XEXP (x, 0), 0),
-                                             XEXP (XEXP (x, 0), 1))))
+         && (reversed = reversed_comparison (XEXP (x, 0), mode)))
        return
          simplify_gen_unary (NEG, mode, reversed, mode);
 
@@ -4329,7 +4408,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
              & nonzero_bits (XEXP (x, 1), mode)) == 0)
        {
          /* Try to simplify the expression further.  */
-         rtx tor = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
+         rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
          temp = combine_simplify_rtx (tor, mode, in_dest);
 
          /* If we could, great.  If not, do not go ahead with the IOR
@@ -4346,9 +4425,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       if (STORE_FLAG_VALUE == 1
          && XEXP (x, 0) == const1_rtx
          && COMPARISON_P (XEXP (x, 1))
-         && (reversed = reversed_comparison (XEXP (x, 1), mode,
-                                             XEXP (XEXP (x, 1), 0),
-                                             XEXP (XEXP (x, 1), 1))))
+         && (reversed = reversed_comparison (XEXP (x, 1), mode)))
        return reversed;
 
       /* (minus <foo> (and <foo> (const_int -pow2))) becomes
@@ -4369,8 +4446,10 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
          in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
          in2 = XEXP (XEXP (x, 1), 1);
-         return gen_binary (PLUS, mode, gen_binary (MULT, mode, in1, in2),
-                            XEXP (x, 0));
+         return simplify_gen_binary (PLUS, mode,
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2),
+                                     XEXP (x, 0));
        }
 
       /* Canonicalize (minus (neg A) (mult B C)) to
@@ -4382,17 +4461,20 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
          in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
          in2 = XEXP (XEXP (x, 1), 1);
-         return gen_binary (MINUS, mode, gen_binary (MULT, mode, in1, in2),
-                            XEXP (XEXP (x, 0), 0));
+         return simplify_gen_binary (MINUS, mode,
+                                     simplify_gen_binary (MULT, mode,
+                                                          in1, in2),
+                                     XEXP (XEXP (x, 0), 0));
        }
 
       /* Canonicalize (minus A (plus B C)) to (minus (minus A B) C) for
         integers.  */
       if (GET_CODE (XEXP (x, 1)) == PLUS && INTEGRAL_MODE_P (mode))
-       return gen_binary (MINUS, mode,
-                          gen_binary (MINUS, mode, XEXP (x, 0),
-                                      XEXP (XEXP (x, 1), 0)),
-                          XEXP (XEXP (x, 1), 1));
+       return simplify_gen_binary (MINUS, mode,
+                                   simplify_gen_binary (MINUS, mode,
+                                                        XEXP (x, 0),
+                                                        XEXP (XEXP (x, 1), 0)),
+                                   XEXP (XEXP (x, 1), 1));
       break;
 
     case MULT:
@@ -4402,17 +4484,11 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
       if (GET_CODE (XEXP (x, 0)) == PLUS)
        {
-         x = apply_distributive_law
-           (gen_binary (PLUS, mode,
-                        gen_binary (MULT, mode,
-                                    XEXP (XEXP (x, 0), 0), XEXP (x, 1)),
-                        gen_binary (MULT, mode,
-                                    XEXP (XEXP (x, 0), 1),
-                                    copy_rtx (XEXP (x, 1)))));
-
-         if (GET_CODE (x) != MULT)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x, 0);
+         if (result)
+           return result;
        }
+
       /* Try simplify a*(b/c) as (a*b)/c.  */
       if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
          && GET_CODE (XEXP (x, 0)) == DIV)
@@ -4421,7 +4497,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                                               XEXP (XEXP (x, 0), 0),
                                               XEXP (x, 1));
          if (tem)
-           return gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
+           return simplify_gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
        }
       break;
 
@@ -4501,9 +4577,9 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                   && nonzero_bits (op0, mode) == 1)
            {
              op0 = expand_compound_operation (op0);
-             return gen_binary (XOR, mode,
-                                gen_lowpart (mode, op0),
-                                const1_rtx);
+             return simplify_gen_binary (XOR, mode,
+                                         gen_lowpart (mode, op0),
+                                         const1_rtx);
            }
 
          else if (STORE_FLAG_VALUE == 1
@@ -4688,8 +4764,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        rtx op1 = XEXP (x, 1);
        int len;
 
-       if (GET_CODE (op1) != PARALLEL)
-         abort ();
+       gcc_assert (GET_CODE (op1) == PARALLEL);
        len = XVECLEN (op1, 0);
        if (len == 1
            && GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
@@ -4746,13 +4821,13 @@ simplify_if_then_else (rtx x)
 
   /* Simplify storing of the truth value.  */
   if (comparison_p && true_rtx == const_true_rtx && false_rtx == const0_rtx)
-    return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
+    return simplify_gen_relational (true_code, mode, VOIDmode,
+                                   XEXP (cond, 0), XEXP (cond, 1));
 
   /* Also when the truth value has to be reversed.  */
   if (comparison_p
       && true_rtx == const0_rtx && false_rtx == const_true_rtx
-      && (reversed = reversed_comparison (cond, mode, XEXP (cond, 0),
-                                         XEXP (cond, 1))))
+      && (reversed = reversed_comparison (cond, mode)))
     return reversed;
 
   /* Sometimes we can simplify the arm of an IF_THEN_ELSE if a register used
@@ -4760,7 +4835,7 @@ simplify_if_then_else (rtx x)
      comparisons and see if that says anything about the value of each arm.  */
 
   if (comparison_p
-      && ((false_code = combine_reversed_comparison_code (cond))
+      && ((false_code = reversed_comparison_code (cond, NULL))
          != UNKNOWN)
       && REG_P (XEXP (cond, 0)))
     {
@@ -4818,7 +4893,7 @@ simplify_if_then_else (rtx x)
      the false arm is more complicated than the true arm.  */
 
   if (comparison_p
-      && combine_reversed_comparison_code (cond) != UNKNOWN
+      && reversed_comparison_code (cond, NULL) != UNKNOWN
       && (true_rtx == pc_rtx
          || (CONSTANT_P (true_rtx)
              && GET_CODE (false_rtx) != CONST_INT && false_rtx != pc_rtx)
@@ -4830,10 +4905,7 @@ simplify_if_then_else (rtx x)
          || rtx_equal_p (false_rtx, XEXP (cond, 0))))
     {
       true_code = reversed_comparison_code (cond, NULL);
-      SUBST (XEXP (x, 0),
-            reversed_comparison (cond, GET_MODE (cond), XEXP (cond, 0),
-                                 XEXP (cond, 1)));
-
+      SUBST (XEXP (x, 0), reversed_comparison (cond, GET_MODE (cond)));
       SUBST (XEXP (x, 1), false_rtx);
       SUBST (XEXP (x, 2), true_rtx);
 
@@ -4896,16 +4968,16 @@ simplify_if_then_else (rtx x)
       {
       case GE:
       case GT:
-       return gen_binary (SMAX, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (SMAX, mode, true_rtx, false_rtx);
       case LE:
       case LT:
-       return gen_binary (SMIN, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (SMIN, mode, true_rtx, false_rtx);
       case GEU:
       case GTU:
-       return gen_binary (UMAX, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (UMAX, mode, true_rtx, false_rtx);
       case LEU:
       case LTU:
-       return gen_binary (UMIN, mode, true_rtx, false_rtx);
+       return simplify_gen_binary (UMIN, mode, true_rtx, false_rtx);
       default:
        break;
       }
@@ -4926,7 +4998,7 @@ simplify_if_then_else (rtx x)
       rtx f = make_compound_operation (false_rtx, SET);
       rtx cond_op0 = XEXP (cond, 0);
       rtx cond_op1 = XEXP (cond, 1);
-      enum rtx_code op = NIL, extend_op = NIL;
+      enum rtx_code op = UNKNOWN, extend_op = UNKNOWN;
       enum machine_mode m = mode;
       rtx z = 0, c1 = NULL_RTX;
 
@@ -5018,14 +5090,16 @@ simplify_if_then_else (rtx x)
 
       if (z)
        {
-         temp = subst (gen_binary (true_code, m, cond_op0, cond_op1),
+         temp = subst (simplify_gen_relational (true_code, m, VOIDmode,
+                                                cond_op0, cond_op1),
                        pc_rtx, pc_rtx, 0, 0);
-         temp = gen_binary (MULT, m, temp,
-                            gen_binary (MULT, m, c1, const_true_rtx));
+         temp = simplify_gen_binary (MULT, m, temp,
+                                     simplify_gen_binary (MULT, m, c1,
+                                                          const_true_rtx));
          temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
-         temp = gen_binary (op, m, gen_lowpart (m, z), temp);
+         temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
 
-         if (extend_op != NIL)
+         if (extend_op != UNKNOWN)
            temp = simplify_gen_unary (extend_op, mode, temp, m);
 
          return temp;
@@ -5208,7 +5282,8 @@ simplify_set (rtx x)
                  PUT_CODE (*cc_use, old_code);
                  other_changed = 0;
 
-                 op0 = gen_binary (XOR, GET_MODE (op0), op0, GEN_INT (mask));
+                 op0 = simplify_gen_binary (XOR, GET_MODE (op0),
+                                            op0, GEN_INT (mask));
                }
            }
        }
@@ -5319,7 +5394,7 @@ simplify_set (rtx x)
      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
+      && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != UNKNOWN
       && SUBREG_BYTE (src) == 0
       && (GET_MODE_SIZE (GET_MODE (src))
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
@@ -5372,18 +5447,19 @@ simplify_set (rtx x)
               && rtx_equal_p (XEXP (false_rtx, 1), true_rtx))
        term1 = true_rtx, false_rtx = XEXP (false_rtx, 0), true_rtx = const0_rtx;
 
-      term2 = gen_binary (AND, GET_MODE (src),
-                         XEXP (XEXP (src, 0), 0), true_rtx);
-      term3 = gen_binary (AND, GET_MODE (src),
-                         simplify_gen_unary (NOT, GET_MODE (src),
-                                             XEXP (XEXP (src, 0), 0),
-                                             GET_MODE (src)),
-                         false_rtx);
+      term2 = simplify_gen_binary (AND, GET_MODE (src),
+                                  XEXP (XEXP (src, 0), 0), true_rtx);
+      term3 = simplify_gen_binary (AND, GET_MODE (src),
+                                  simplify_gen_unary (NOT, GET_MODE (src),
+                                                      XEXP (XEXP (src, 0), 0),
+                                                      GET_MODE (src)),
+                                  false_rtx);
 
       SUBST (SET_SRC (x),
-            gen_binary (IOR, GET_MODE (src),
-                        gen_binary (IOR, GET_MODE (src), term1, term2),
-                        term3));
+            simplify_gen_binary (IOR, GET_MODE (src),
+                                 simplify_gen_binary (IOR, GET_MODE (src),
+                                                      term1, term2),
+                                 term3));
 
       src = SET_SRC (x);
     }
@@ -5418,29 +5494,31 @@ simplify_logical (rtx x)
       if (GET_CODE (op0) == XOR
          && rtx_equal_p (XEXP (op0, 0), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode,
-                       simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
-                       op1);
+       x = simplify_gen_binary (AND, mode,
+                                simplify_gen_unary (NOT, mode,
+                                                    XEXP (op0, 1), mode),
+                                op1);
 
       if (GET_CODE (op0) == XOR
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode,
-                       simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
-                       op1);
+       x = simplify_gen_binary (AND, mode,
+                                simplify_gen_unary (NOT, mode,
+                                                    XEXP (op0, 0), mode),
+                                op1);
 
       /* Similarly for (~(A ^ B)) & A.  */
       if (GET_CODE (op0) == NOT
          && GET_CODE (XEXP (op0, 0)) == XOR
          && rtx_equal_p (XEXP (XEXP (op0, 0), 0), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
+       x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 1), op1);
 
       if (GET_CODE (op0) == NOT
          && GET_CODE (XEXP (op0, 0)) == XOR
          && rtx_equal_p (XEXP (XEXP (op0, 0), 1), op1)
          && ! side_effects_p (op1))
-       x = gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
+       x = simplify_gen_binary (AND, mode, XEXP (XEXP (op0, 0), 0), op1);
 
       /* We can call simplify_and_const_int only if we don't lose
         any (sign) bits when converting INTVAL (op1) to
@@ -5460,8 +5538,9 @@ simplify_logical (rtx x)
              && GET_CODE (XEXP (op0, 1)) == CONST_INT
              && GET_CODE (op1) == CONST_INT
              && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
-           return gen_binary (IOR, mode,
-                              gen_binary (AND, mode, XEXP (op0, 0),
+           return simplify_gen_binary (IOR, mode,
+                                       simplify_gen_binary
+                                         (AND, mode, XEXP (op0, 0),
                                           GEN_INT (INTVAL (XEXP (op0, 1))
                                                    & ~INTVAL (op1))), op1);
 
@@ -5480,54 +5559,21 @@ simplify_logical (rtx x)
          && ! side_effects_p (XEXP (op0, 1)))
        return op1;
 
-      /* In the following group of tests (and those in case IOR below),
-        we start with some combination of logical operations and apply
-        the distributive law followed by the inverse distributive law.
-        Most of the time, this results in no change.  However, if some of
-        the operands are the same or inverses of each other, simplifications
-        will result.
-
-        For example, (and (ior A B) (not B)) can occur as the result of
-        expanding a bit field assignment.  When we apply the distributive
-        law to this, we get (ior (and (A (not B))) (and (B (not B)))),
-        which then simplifies to (and (A (not B))).
-
-        If we have (and (ior A B) C), apply the distributive law and then
-        the inverse distributive law to see if things simplify.  */
-
+      /* If we have any of (and (ior A B) C) or (and (xor A B) C),
+        apply the distributive law and then the inverse distributive
+        law to see if things simplify.  */
       if (GET_CODE (op0) == IOR || GET_CODE (op0) == XOR)
        {
-         x = apply_distributive_law
-           (gen_binary (GET_CODE (op0), mode,
-                        gen_binary (AND, mode, XEXP (op0, 0), op1),
-                        gen_binary (AND, mode, XEXP (op0, 1),
-                                    copy_rtx (op1))));
-         if (GET_CODE (x) != AND)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x, 0);
+         if (result)
+           return result;
        }
-
       if (GET_CODE (op1) == IOR || GET_CODE (op1) == XOR)
-       return apply_distributive_law
-         (gen_binary (GET_CODE (op1), mode,
-                      gen_binary (AND, mode, XEXP (op1, 0), op0),
-                      gen_binary (AND, mode, XEXP (op1, 1),
-                                  copy_rtx (op0))));
-
-      /* Similarly, taking advantage of the fact that
-        (and (not A) (xor B C)) == (xor (ior A B) (ior A C))  */
-
-      if (GET_CODE (op0) == NOT && GET_CODE (op1) == XOR)
-       return apply_distributive_law
-         (gen_binary (XOR, mode,
-                      gen_binary (IOR, mode, XEXP (op0, 0), XEXP (op1, 0)),
-                      gen_binary (IOR, mode, copy_rtx (XEXP (op0, 0)),
-                                  XEXP (op1, 1))));
-
-      else if (GET_CODE (op1) == NOT && GET_CODE (op0) == XOR)
-       return apply_distributive_law
-         (gen_binary (XOR, mode,
-                      gen_binary (IOR, mode, XEXP (op1, 0), XEXP (op0, 0)),
-                      gen_binary (IOR, mode, copy_rtx (XEXP (op1, 0)), XEXP (op0, 1))));
+       {
+         rtx result = distribute_and_simplify_rtx (x, 1);
+         if (result)
+           return result;
+       }
       break;
 
     case IOR:
@@ -5550,26 +5596,16 @@ simplify_logical (rtx x)
 
       if (GET_CODE (op0) == AND)
        {
-         x = apply_distributive_law
-           (gen_binary (AND, mode,
-                        gen_binary (IOR, mode, XEXP (op0, 0), op1),
-                        gen_binary (IOR, mode, XEXP (op0, 1),
-                                    copy_rtx (op1))));
-
-         if (GET_CODE (x) != IOR)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x, 0);
+         if (result)
+           return result;
        }
 
       if (GET_CODE (op1) == AND)
        {
-         x = apply_distributive_law
-           (gen_binary (AND, mode,
-                        gen_binary (IOR, mode, XEXP (op1, 0), op0),
-                        gen_binary (IOR, mode, XEXP (op1, 1),
-                                    copy_rtx (op0))));
-
-         if (GET_CODE (x) != IOR)
-           return x;
+         rtx result = distribute_and_simplify_rtx (x, 1);
+         if (result)
+           return result;
        }
 
       /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
@@ -5618,7 +5654,7 @@ simplify_logical (rtx x)
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (op0, mode)
              & nonzero_bits (op1, mode)) == 0)
-       return (gen_binary (IOR, mode, op0, op1));
+       return (simplify_gen_binary (IOR, mode, op0, op1));
 
       /* Convert (XOR (NOT x) (NOT y)) to (XOR x y).
         Also convert (XOR (NOT x) y) to (NOT (XOR x y)), similarly for
@@ -5638,7 +5674,8 @@ simplify_logical (rtx x)
          }
        else if (num_negated == 1)
          return
-           simplify_gen_unary (NOT, mode, gen_binary (XOR, mode, op0, op1),
+           simplify_gen_unary (NOT, mode,
+                               simplify_gen_binary (XOR, mode, op0, op1),
                                mode);
       }
 
@@ -5649,24 +5686,25 @@ simplify_logical (rtx x)
       if (GET_CODE (op0) == AND
          && rtx_equal_p (XEXP (op0, 1), op1)
          && ! side_effects_p (op1))
-       return gen_binary (AND, mode,
-                          simplify_gen_unary (NOT, mode, XEXP (op0, 0), mode),
-                          op1);
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       XEXP (op0, 0), mode),
+                                   op1);
 
       else if (GET_CODE (op0) == AND
               && rtx_equal_p (XEXP (op0, 0), op1)
               && ! side_effects_p (op1))
-       return gen_binary (AND, mode,
-                          simplify_gen_unary (NOT, mode, XEXP (op0, 1), mode),
-                          op1);
+       return simplify_gen_binary (AND, mode,
+                                   simplify_gen_unary (NOT, mode,
+                                                       XEXP (op0, 1), mode),
+                                   op1);
 
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
         comparison if STORE_FLAG_VALUE is 1.  */
       if (STORE_FLAG_VALUE == 1
          && op1 == const1_rtx
          && COMPARISON_P (op0)
-         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
-                                             XEXP (op0, 1))))
+         && (reversed = reversed_comparison (op0, mode)))
        return reversed;
 
       /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
@@ -5687,14 +5725,13 @@ simplify_logical (rtx x)
              == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
          && op1 == const_true_rtx
          && COMPARISON_P (op0)
-         && (reversed = reversed_comparison (op0, mode, XEXP (op0, 0),
-                                             XEXP (op0, 1))))
+         && (reversed = reversed_comparison (op0, mode)))
        return reversed;
 
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return x;
@@ -5766,6 +5803,9 @@ expand_compound_operation (rtx x)
 
     case ZERO_EXTRACT:
       unsignedp = 1;
+
+      /* ... fall through ...  */
+
     case SIGN_EXTRACT:
       /* If the operand is a CLOBBER, just return it.  */
       if (GET_CODE (XEXP (x, 0)) == CLOBBER)
@@ -5927,7 +5967,7 @@ expand_field_assignment (rtx x)
   rtx inner;
   rtx pos;                     /* Always counts from low bit.  */
   int len;
-  rtx mask;
+  rtx mask, cleared, masked;
   enum machine_mode compute_mode;
 
   /* Loop until we find something we can't simplify.  */
@@ -5965,10 +6005,11 @@ expand_field_assignment (rtx x)
                /* If position is ADJUST - X, new position is X.  */
                pos = XEXP (pos, 0);
              else
-               pos = gen_binary (MINUS, GET_MODE (pos),
-                                 GEN_INT (GET_MODE_BITSIZE (GET_MODE (inner))
-                                          - len),
-                                 pos);
+               pos = simplify_gen_binary (MINUS, GET_MODE (pos),
+                                          GEN_INT (GET_MODE_BITSIZE (
+                                                   GET_MODE (inner))
+                                                   - len),
+                                          pos);
            }
        }
 
@@ -6015,30 +6056,30 @@ expand_field_assignment (rtx x)
        }
 
       /* Compute a mask of LEN bits, if we can do this on the host machine.  */
-      if (len < HOST_BITS_PER_WIDE_INT)
-       mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
-      else
+      if (len >= HOST_BITS_PER_WIDE_INT)
        break;
 
       /* Now compute the equivalent expression.  Make a copy of INNER
         for the SET_DEST in case it is a MEM into which we will substitute;
         we don't want shared RTL in that case.  */
-      x = gen_rtx_SET
-       (VOIDmode, copy_rtx (inner),
-        gen_binary (IOR, compute_mode,
-                    gen_binary (AND, compute_mode,
-                                simplify_gen_unary (NOT, compute_mode,
-                                                    gen_binary (ASHIFT,
-                                                                compute_mode,
-                                                                mask, pos),
-                                                    compute_mode),
-                                inner),
-                    gen_binary (ASHIFT, compute_mode,
-                                gen_binary (AND, compute_mode,
-                                            gen_lowpart
-                                            (compute_mode, SET_SRC (x)),
-                                            mask),
-                                pos)));
+      mask = GEN_INT (((HOST_WIDE_INT) 1 << len) - 1);
+      cleared = simplify_gen_binary (AND, compute_mode,
+                                    simplify_gen_unary (NOT, compute_mode,
+                                      simplify_gen_binary (ASHIFT,
+                                                           compute_mode,
+                                                           mask, pos),
+                                      compute_mode),
+                                    inner);
+      masked = simplify_gen_binary (ASHIFT, compute_mode,
+                                   simplify_gen_binary (
+                                     AND, compute_mode,
+                                     gen_lowpart (compute_mode, SET_SRC (x)),
+                                     mask),
+                                   pos);
+
+      x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
+                      simplify_gen_binary (IOR, compute_mode,
+                                           cleared, masked));
     }
 
   return x;
@@ -6494,8 +6535,8 @@ extract_left_shift (rtx x, int count)
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
          && (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
-       return gen_binary (code, mode, tem,
-                          GEN_INT (INTVAL (XEXP (x, 1)) >> count));
+       return simplify_gen_binary (code, mode, tem,
+                                   GEN_INT (INTVAL (XEXP (x, 1)) >> count));
 
       break;
 
@@ -6898,11 +6939,6 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       && (GET_MODE_MASK (GET_MODE (x)) & ~mask) == 0)
     return gen_lowpart (mode, x);
 
-  /* If we aren't changing the mode, X is not a SUBREG, and all zero bits in
-     MASK are already known to be zero in X, we need not do anything.  */
-  if (GET_MODE (x) == mode && code != SUBREG && (~mask & nonzero) == 0)
-    return x;
-
   switch (code)
     {
     case CLOBBER:
@@ -6986,7 +7022,8 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
                  && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
                cval |= (HOST_WIDE_INT) -1 << width;
 
-             y = gen_binary (AND, GET_MODE (x), XEXP (x, 0), GEN_INT (cval));
+             y = simplify_gen_binary (AND, GET_MODE (x),
+                                      XEXP (x, 0), GEN_INT (cval));
              if (rtx_cost (y, SET) < rtx_cost (x, SET))
                x = y;
            }
@@ -7078,10 +7115,10 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          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 (XEXP (x, 0), 1));
+         temp = simplify_gen_binary (GET_CODE (x), GET_MODE (x),
+                                     XEXP (XEXP (x, 0), 0), temp);
+         x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), temp,
+                                  XEXP (XEXP (x, 0), 1));
          return force_to_mode (x, mode, mask, reg, next_select);
        }
 
@@ -7097,7 +7134,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
                                        reg, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
-       x = gen_binary (code, op_mode, op0, op1);
+       x = simplify_gen_binary (code, op_mode, op0, op1);
       break;
 
     case ASHIFT:
@@ -7131,7 +7168,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
                                        mask, reg, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
-       x = gen_binary (code, op_mode, op0, XEXP (x, 1));
+       x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
       break;
 
     case LSHIFTRT:
@@ -7151,15 +7188,14 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
          /* We can only change the mode of the shift if we can do arithmetic
             in the mode of the shift and INNER_MASK is no wider than the
-            width of OP_MODE.  */
-         if (GET_MODE_BITSIZE (op_mode) > HOST_BITS_PER_WIDE_INT
-             || (inner_mask & ~GET_MODE_MASK (op_mode)) != 0)
+            width of X's mode.  */
+         if ((inner_mask & ~GET_MODE_MASK (GET_MODE (x))) != 0)
            op_mode = GET_MODE (x);
 
          inner = force_to_mode (inner, op_mode, inner_mask, reg, next_select);
 
          if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
-           x = gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
+           x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
        }
 
       /* If we have (and (lshiftrt FOO C1) C2) where the combination of the
@@ -7181,9 +7217,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          /* Must be more sign bit copies than the mask needs.  */
          && ((int) num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
              >= exact_log2 (mask + 1)))
-       x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
-                       GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
-                                - exact_log2 (mask + 1)));
+       x = simplify_gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+                                GEN_INT (GET_MODE_BITSIZE (GET_MODE (x))
+                                         - exact_log2 (mask + 1)));
 
       goto shiftrt;
 
@@ -7248,7 +7284,8 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* If MASK is 1, convert this to an LSHIFTRT.  This can be done
         even if the shift count isn't a constant.  */
       if (mask == 1)
-       x = gen_binary (LSHIFTRT, GET_MODE (x), XEXP (x, 0), XEXP (x, 1));
+       x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
+                                XEXP (x, 0), XEXP (x, 1));
 
     shiftrt:
 
@@ -7313,8 +7350,10 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          temp = gen_int_mode (mask << INTVAL (XEXP (XEXP (x, 0), 1)),
                               GET_MODE (x));
-         temp = gen_binary (XOR, GET_MODE (x), XEXP (XEXP (x, 0), 0), temp);
-         x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (XEXP (x, 0), 1));
+         temp = simplify_gen_binary (XOR, GET_MODE (x),
+                                     XEXP (XEXP (x, 0), 0), temp);
+         x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
+                                  temp, XEXP (XEXP (x, 0), 1));
 
          return force_to_mode (x, mode, mask, reg, next_select);
        }
@@ -7336,6 +7375,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         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
+         && GET_MODE (XEXP (x, 0)) == mode
          && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
          && (nonzero_bits (XEXP (x, 0), mode)
              == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
@@ -7424,8 +7464,19 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
          else if (cond1 == 0)
            true1 = copy_rtx (true1);
 
-         *ptrue = gen_binary (code, mode, true0, true1);
-         *pfalse = gen_binary (code, mode, false0, false1);
+         if (COMPARISON_P (x))
+           {
+             *ptrue = simplify_gen_relational (code, mode, VOIDmode,
+                                               true0, true1);
+             *pfalse = simplify_gen_relational (code, mode, VOIDmode,
+                                                false0, false1);
+            }
+         else
+           {
+             *ptrue = simplify_gen_binary (code, mode, true0, true1);
+             *pfalse = simplify_gen_binary (code, mode, false0, false1);
+           }
+
          return cond0 ? cond0 : cond1;
        }
 
@@ -7446,22 +7497,22 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
-             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
+             && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == combine_reversed_comparison_code (cond1))
+                      == reversed_comparison_code (cond1, NULL))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
            {
-             *ptrue = gen_binary (MULT, mode, op0, const_true_rtx);
-             *pfalse = gen_binary (MULT, mode,
-                                   (code == MINUS
-                                    ? simplify_gen_unary (NEG, mode, op1,
-                                                          mode)
-                                    : op1),
-                                   const_true_rtx);
+             *ptrue = simplify_gen_binary (MULT, mode, op0, const_true_rtx);
+             *pfalse = simplify_gen_binary (MULT, mode,
+                                            (code == MINUS
+                                             ? simplify_gen_unary (NEG, mode,
+                                                                   op1, mode)
+                                             : op1),
+                                             const_true_rtx);
              return cond0;
            }
        }
@@ -7477,11 +7528,11 @@ if_then_else_cond (rtx x, rtx *ptrue, rtx *pfalse)
 
          if (COMPARISON_P (cond0)
              && COMPARISON_P (cond1)
-             && ((GET_CODE (cond0) == combine_reversed_comparison_code (cond1)
+             && ((GET_CODE (cond0) == reversed_comparison_code (cond1, NULL)
                   && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 0))
                   && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 1)))
                  || ((swap_condition (GET_CODE (cond0))
-                      == combine_reversed_comparison_code (cond1))
+                      == reversed_comparison_code (cond1, NULL))
                      && rtx_equal_p (XEXP (cond0, 0), XEXP (cond1, 1))
                      && rtx_equal_p (XEXP (cond0, 1), XEXP (cond1, 0))))
              && ! side_effects_p (x))
@@ -7626,7 +7677,7 @@ known_cond (rtx x, enum rtx_code cond, rtx reg, rtx val)
              if (comparison_dominates_p (cond, code))
                return const_true_rtx;
 
-             code = combine_reversed_comparison_code (x);
+             code = reversed_comparison_code (x, NULL);
              if (code != UNKNOWN
                  && comparison_dominates_p (cond, code))
                return const0_rtx;
@@ -7791,14 +7842,14 @@ make_field_assignment (rtx x)
       return x;
     }
 
-  else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
-          && subreg_lowpart_p (XEXP (src, 0))
-          && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
-              < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
-          && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
-          && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT
-          && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
-          && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
+  if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
+      && subreg_lowpart_p (XEXP (src, 0))
+      && (GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
+      && GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
+      && GET_CODE (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == CONST_INT
+      && INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
+      && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
     {
       assign = make_extraction (VOIDmode, dest, 0,
                                XEXP (SUBREG_REG (XEXP (src, 0)), 1),
@@ -7810,9 +7861,9 @@ make_field_assignment (rtx x)
 
   /* 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_for_field_assignment_p (dest, XEXP (src, 1)))
+  if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
+      && XEXP (XEXP (src, 0), 0) == const1_rtx
+      && 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);
@@ -7821,6 +7872,37 @@ make_field_assignment (rtx x)
       return x;
     }
 
+  /* If DEST is already a field assignment, i.e. ZERO_EXTRACT, and the
+     SRC is an AND with all bits of that field set, then we can discard
+     the AND.  */
+  if (GET_CODE (dest) == ZERO_EXTRACT
+      && GET_CODE (XEXP (dest, 1)) == CONST_INT
+      && GET_CODE (src) == AND
+      && GET_CODE (XEXP (src, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT width = INTVAL (XEXP (dest, 1));
+      unsigned HOST_WIDE_INT and_mask = INTVAL (XEXP (src, 1));
+      unsigned HOST_WIDE_INT ze_mask;
+
+      if (width >= HOST_BITS_PER_WIDE_INT)
+       ze_mask = -1;
+      else
+       ze_mask = ((unsigned HOST_WIDE_INT)1 << width) - 1;
+
+      /* Complete overlap.  We can remove the source AND.  */
+      if ((and_mask & ze_mask) == ze_mask)
+       return gen_rtx_SET (VOIDmode, dest, XEXP (src, 0));
+
+      /* Partial overlap.  We can reduce the source AND.  */
+      if ((and_mask & ze_mask) != and_mask)
+       {
+         mode = GET_MODE (src);
+         src = gen_rtx_AND (mode, XEXP (src, 0),
+                            gen_int_mode (and_mask & ze_mask, mode));
+         return gen_rtx_SET (VOIDmode, dest, src);
+       }
+    }
+
   /* The other case we handle is assignments into a constant-position
      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
@@ -7965,8 +8047,8 @@ apply_distributive_law (rtx x)
          || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
        return x;
 
-      tem = gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
-                       SUBREG_REG (lhs), SUBREG_REG (rhs));
+      tem = simplify_gen_binary (code, GET_MODE (SUBREG_REG (lhs)),
+                                SUBREG_REG (lhs), SUBREG_REG (rhs));
       return gen_lowpart (GET_MODE (x), tem);
 
     default:
@@ -7992,7 +8074,7 @@ apply_distributive_law (rtx x)
     return x;
 
   /* Form the new inner operation, seeing if it simplifies first.  */
-  tem = gen_binary (code, GET_MODE (x), lhs, rhs);
+  tem = simplify_gen_binary (code, GET_MODE (x), lhs, rhs);
 
   /* There is one exception to the general way of distributing:
      (a | c) ^ (b | c) -> (a ^ b) & ~c  */
@@ -8005,8 +8087,76 @@ apply_distributive_law (rtx x)
   /* We may be able to continuing distributing the result, so call
      ourselves recursively on the inner operation before forming the
      outer operation, which we return.  */
-  return gen_binary (inner_code, GET_MODE (x),
-                    apply_distributive_law (tem), other);
+  return simplify_gen_binary (inner_code, GET_MODE (x),
+                             apply_distributive_law (tem), other);
+}
+
+/* See if X is of the form (* (+ A B) C), and if so convert to
+   (+ (* A C) (* B C)) and try to simplify.
+
+   Most of the time, this results in no change.  However, if some of
+   the operands are the same or inverses of each other, simplifications
+   will result.
+
+   For example, (and (ior A B) (not B)) can occur as the result of
+   expanding a bit field assignment.  When we apply the distributive
+   law to this, we get (ior (and (A (not B))) (and (B (not B)))),
+   which then simplifies to (and (A (not B))).
+   Note that no checks happen on the validity of applying the inverse
+   distributive law.  This is pointless since we can do it in the
+   few places where this routine is called.
+
+   N is the index of the term that is decomposed (the arithmetic operation,
+   i.e. (+ A B) in the first example above).  !N is the index of the term that
+   is distributed, i.e. of C in the first example above.  */
+static rtx
+distribute_and_simplify_rtx (rtx x, int n)
+{
+  enum machine_mode mode;
+  enum rtx_code outer_code, inner_code;
+  rtx decomposed, distributed, inner_op0, inner_op1, new_op0, new_op1, tmp;
+
+  decomposed = XEXP (x, n);
+  if (!ARITHMETIC_P (decomposed))
+    return NULL_RTX;
+
+  mode = GET_MODE (x);
+  outer_code = GET_CODE (x);
+  distributed = XEXP (x, !n);
+
+  inner_code = GET_CODE (decomposed);
+  inner_op0 = XEXP (decomposed, 0);
+  inner_op1 = XEXP (decomposed, 1);
+
+  /* Special case (and (xor B C) (not A)), which is equivalent to
+     (xor (ior A B) (ior A C))  */
+  if (outer_code == AND && inner_code == XOR && GET_CODE (distributed) == NOT)
+    {
+      distributed = XEXP (distributed, 0);
+      outer_code = IOR;
+    }
+
+  if (n == 0)
+    {
+      /* Distribute the second term.  */
+      new_op0 = simplify_gen_binary (outer_code, mode, inner_op0, distributed);
+      new_op1 = simplify_gen_binary (outer_code, mode, inner_op1, distributed);
+    }
+  else
+    {
+      /* Distribute the first term.  */
+      new_op0 = simplify_gen_binary (outer_code, mode, distributed, inner_op0);
+      new_op1 = simplify_gen_binary (outer_code, mode, distributed, inner_op1);
+    }
+
+  tmp = apply_distributive_law (simplify_gen_binary (inner_code, mode,
+                                                    new_op0, new_op1));
+  if (GET_CODE (tmp) != outer_code
+      && rtx_cost (tmp, SET) < rtx_cost (x, SET))
+    return tmp;
+
+  return NULL_RTX;
 }
 \f
 /* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
@@ -8038,7 +8188,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
   /* If VAROP is a CONST_INT, then we need to apply the mask in CONSTOP
      to VAROP and return the new constant.  */
   if (GET_CODE (varop) == CONST_INT)
-    return GEN_INT (trunc_int_for_mode (INTVAL (varop) & constop, mode));
+    return gen_int_mode (INTVAL (varop) & constop, mode);
 
   /* See what bits may be nonzero in VAROP.  Unlike the general case of
      a call to nonzero_bits, here we don't care about bits outside
@@ -8073,11 +8223,15 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
       gen_lowpart
        (mode,
         apply_distributive_law
-        (gen_binary (GET_CODE (varop), GET_MODE (varop),
-                     simplify_and_const_int (NULL_RTX, GET_MODE (varop),
-                                             XEXP (varop, 0), constop),
-                     simplify_and_const_int (NULL_RTX, GET_MODE (varop),
-                                             XEXP (varop, 1), constop))));
+        (simplify_gen_binary (GET_CODE (varop), GET_MODE (varop),
+                              simplify_and_const_int (NULL_RTX,
+                                                      GET_MODE (varop),
+                                                      XEXP (varop, 0),
+                                                      constop),
+                              simplify_and_const_int (NULL_RTX,
+                                                      GET_MODE (varop),
+                                                      XEXP (varop, 1),
+                                                      constop))));
 
   /* If VAROP is PLUS, and the constant is a mask of low bite, distribute
      the AND and see if one of the operands simplifies to zero.  If so, we
@@ -8118,7 +8272,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
       constop = trunc_int_for_mode (constop, mode);
       /* See how much, if any, of X we can use.  */
       if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
-       x = gen_binary (AND, mode, varop, GEN_INT (constop));
+       x = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
 
       else
        {
@@ -8285,7 +8439,7 @@ extended_count (rtx x, enum machine_mode mode, int unsignedp)
    the width of this mode matter.  It is assumed that the width of this mode
    is smaller than or equal to HOST_BITS_PER_WIDE_INT.
 
-   If *POP0 or OP1 are NIL, it means no operation is required.  Only NEG, PLUS,
+   If *POP0 or OP1 are UNKNOWN, it means no operation is required.  Only NEG, PLUS,
    IOR, XOR, and AND are supported.  We may set *POP0 to SET if the proper
    result is simply *PCONST0.
 
@@ -8305,13 +8459,13 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
   if (op0 == AND)
     const1 &= const0;
 
-  /* If OP0 or OP1 is NIL, this is easy.  Similarly if they are the same or
+  /* If OP0 or OP1 is UNKNOWN, this is easy.  Similarly if they are the same or
      if OP0 is SET.  */
 
-  if (op1 == NIL || op0 == SET)
+  if (op1 == UNKNOWN || op0 == SET)
     return 1;
 
-  else if (op0 == NIL)
+  else if (op0 == UNKNOWN)
     op0 = op1, const0 = const1;
 
   else if (op0 == op1)
@@ -8331,7 +8485,7 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
          const0 += const1;
          break;
        case NEG:
-         op0 = NIL;
+         op0 = UNKNOWN;
          break;
        default:
          break;
@@ -8384,12 +8538,12 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
   const0 &= GET_MODE_MASK (mode);
   if (const0 == 0
       && (op0 == IOR || op0 == XOR || op0 == PLUS))
-    op0 = NIL;
+    op0 = UNKNOWN;
   else if (const0 == 0 && op0 == AND)
     op0 = SET;
   else if ((unsigned HOST_WIDE_INT) const0 == GET_MODE_MASK (mode)
           && op0 == AND)
-    op0 = NIL;
+    op0 = UNKNOWN;
 
   /* ??? Slightly redundant with the above mask, but not entirely.
      Moving this above means we'd have to sign-extend the mode mask
@@ -8423,7 +8577,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
   unsigned int mode_words
     = (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
   /* We form (outer_op (code varop count) (outer_const)).  */
-  enum rtx_code outer_op = NIL;
+  enum rtx_code outer_op = UNKNOWN;
   HOST_WIDE_INT outer_const = 0;
   rtx const_rtx;
   int complement_p = 0;
@@ -8637,8 +8791,10 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
-               = gen_binary (ASHIFT, GET_MODE (varop), XEXP (varop, 0),
-                             GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));
+               = simplify_gen_binary (ASHIFT, GET_MODE (varop),
+                                      XEXP (varop, 0),
+                                      GEN_INT (exact_log2 (
+                                               INTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -8649,8 +8805,10 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && exact_log2 (INTVAL (XEXP (varop, 1))) >= 0)
            {
              varop
-               = gen_binary (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
-                             GEN_INT (exact_log2 (INTVAL (XEXP (varop, 1)))));
+               = simplify_gen_binary (LSHIFTRT, GET_MODE (varop),
+                                      XEXP (varop, 0),
+                                      GEN_INT (exact_log2 (
+                                               INTVAL (XEXP (varop, 1)))));
              continue;
            }
          break;
@@ -8905,7 +9063,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
              rtx rhs = simplify_shift_const (NULL_RTX, code, shift_mode,
                                              XEXP (varop, 1), count);
 
-             varop = gen_binary (GET_CODE (varop), shift_mode, lhs, rhs);
+             varop = simplify_gen_binary (GET_CODE (varop), shift_mode,
+                                          lhs, rhs);
              varop = apply_distributive_law (varop);
 
              count = 0;
@@ -9019,6 +9178,26 @@ simplify_shift_const (rtx x, enum rtx_code code,
              varop = XEXP (varop, 0);
              continue;
            }
+
+         /* Check for 'PLUS signbit', which is the canonical form of 'XOR
+            signbit', and attempt to change the PLUS to an XOR and move it to
+            the outer operation as is done above in the AND/IOR/XOR case
+            leg for shift(logical). See details in logical handling above
+            for reasoning in doing so.  */
+         if (code == LSHIFTRT
+             && GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && mode_signbit_p (result_mode, XEXP (varop, 1))
+             && (new = simplify_binary_operation (code, result_mode,
+                                                  XEXP (varop, 1),
+                                                  GEN_INT (count))) != 0
+             && GET_CODE (new) == CONST_INT
+             && merge_outer_ops (&outer_op, &outer_const, XOR,
+                                 INTVAL (new), result_mode, &complement_p))
+           {
+             varop = XEXP (varop, 0);
+             continue;
+           }
+
          break;
 
        case MINUS:
@@ -9091,7 +9270,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   /* We have now finished analyzing the shift.  The result should be
      a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places.  If
-     OUTER_OP is non-NIL, it is an operation that needs to be applied
+     OUTER_OP is non-UNKNOWN, it is an operation that needs to be applied
      to the result of the shift.  OUTER_CONST is the relevant constant,
      but we must turn off all bits turned off in the shift.
 
@@ -9127,7 +9306,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
      for the outer operation.  So try to do the simplification
      recursively.  */
 
-  if (outer_op != NIL && GET_CODE (x) == code
+  if (outer_op != UNKNOWN && GET_CODE (x) == code
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
                              INTVAL (XEXP (x, 1)));
@@ -9146,7 +9325,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
   if (complement_p)
     x = simplify_gen_unary (NOT, result_mode, x, result_mode);
 
-  if (outer_op != NIL)
+  if (outer_op != UNKNOWN)
     {
       if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
        outer_const = trunc_int_for_mode (outer_const, result_mode);
@@ -9160,7 +9339,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
       else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
        x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
       else
-       x = gen_binary (outer_op, result_mode, x, GEN_INT (outer_const));
+       x = simplify_gen_binary (outer_op, result_mode, x,
+                                GEN_INT (outer_const));
     }
 
   return x;
@@ -9285,16 +9465,18 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
    An insn containing that will not be recognized.  */
 
 static rtx
-gen_lowpart_for_combine (enum machine_mode mode, rtx x)
+gen_lowpart_for_combine (enum machine_mode omode, rtx x)
 {
+  enum machine_mode imode = GET_MODE (x);
+  unsigned int osize = GET_MODE_SIZE (omode);
+  unsigned int isize = GET_MODE_SIZE (imode);
   rtx result;
 
-  if (GET_MODE (x) == mode)
+  if (omode == imode)
     return x;
 
-  /* Return identity if this is a CONST or symbolic
-     reference.  */
-  if (mode == Pmode
+  /* Return identity if this is a CONST or symbolic reference.  */
+  if (omode == Pmode
       && (GET_CODE (x) == CONST
          || GET_CODE (x) == SYMBOL_REF
          || GET_CODE (x) == LABEL_REF))
@@ -9302,13 +9484,12 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
 
   /* We can only support MODE being wider than a word if X is a
      constant integer or has a mode the same size.  */
-
-  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
-      && ! ((GET_MODE (x) == VOIDmode
+  if (GET_MODE_SIZE (omode) > UNITS_PER_WORD
+      && ! ((imode == VOIDmode
             && (GET_CODE (x) == CONST_INT
                 || GET_CODE (x) == CONST_DOUBLE))
-           || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
-    return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+           || isize == osize))
+    goto fail;
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
      won't know what to do.  So we will strip off the SUBREG here and
@@ -9316,19 +9497,23 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
   if (GET_CODE (x) == SUBREG && MEM_P (SUBREG_REG (x)))
     {
       x = SUBREG_REG (x);
-      if (GET_MODE (x) == mode)
+
+      /* For use in case we fall down into the address adjustments
+        further below, we need to adjust the known mode and size of
+        x; imode and isize, since we just adjusted x.  */
+      imode = GET_MODE (x);
+
+      if (imode == omode)
        return x;
+
+      isize = GET_MODE_SIZE (imode);
     }
 
-  result = gen_lowpart_common (mode, x);
+  result = gen_lowpart_common (omode, x);
+
 #ifdef CANNOT_CHANGE_MODE_CLASS
-  if (result != 0
-      && GET_CODE (result) == SUBREG
-      && REG_P (SUBREG_REG (result))
-      && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER)
-    bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (result))
-                                     * MAX_MACHINE_MODE
-                                     + GET_MODE (result));
+  if (result != 0 && GET_CODE (result) == SUBREG)
+    record_subregs_of_mode (result);
 #endif
 
   if (result)
@@ -9341,33 +9526,29 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
       /* Refuse to work on a volatile memory ref or one with a mode-dependent
         address.  */
       if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
-       return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+       goto fail;
 
       /* If we want to refer to something bigger than the original memref,
         generate a paradoxical subreg instead.  That will force a reload
         of the original memref X.  */
-      if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
-       return gen_rtx_SUBREG (mode, x, 0);
+      if (isize < osize)
+       return gen_rtx_SUBREG (omode, x, 0);
 
       if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+       offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
 
+      /* Adjust the address so that the address-after-the-data is
+        unchanged.  */
       if (BYTES_BIG_ENDIAN)
-       {
-         /* Adjust the address so that the address-after-the-data is
-            unchanged.  */
-         offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-       }
+       offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
 
-      return adjust_address_nv (x, mode, offset);
+      return adjust_address_nv (x, omode, offset);
     }
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
      probably won't match, but may allow further simplifications.  */
   else if (COMPARISON_P (x))
-    return gen_rtx_fmt_ee (GET_CODE (x), mode, XEXP (x, 0), XEXP (x, 1));
+    return gen_rtx_fmt_ee (GET_CODE (x), omode, XEXP (x, 0), XEXP (x, 1));
 
   /* If we couldn't simplify X any other way, just enclose it in a
      SUBREG.  Normally, this SUBREG won't match, but some patterns may
@@ -9376,78 +9557,22 @@ gen_lowpart_for_combine (enum machine_mode mode, rtx x)
     {
       int offset = 0;
       rtx res;
-      enum machine_mode sub_mode = GET_MODE (x);
 
-      offset = subreg_lowpart_offset (mode, sub_mode);
-      if (sub_mode == VOIDmode)
+      offset = subreg_lowpart_offset (omode, imode);
+      if (imode == VOIDmode)
        {
-         sub_mode = int_mode_for_mode (mode);
-         x = gen_lowpart_common (sub_mode, x);
-         if (x == 0)
-           return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
+         imode = int_mode_for_mode (omode);
+         x = gen_lowpart_common (imode, x);
+         if (x == NULL)
+           goto fail;
        }
-      res = simplify_gen_subreg (mode, x, sub_mode, offset);
+      res = simplify_gen_subreg (omode, x, imode, offset);
       if (res)
        return res;
-      return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
-    }
-}
-\f
-/* These routines make binary and unary operations by first seeing if they
-   fold; if not, a new expression is allocated.  */
-
-static rtx
-gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1)
-{
-  rtx result;
-  rtx tem;
-
-  if (GET_CODE (op0) == CLOBBER)
-    return op0;
-  else if (GET_CODE (op1) == CLOBBER)
-    return op1;
-  
-  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
-      && swap_commutative_operands_p (op0, op1))
-    tem = op0, op0 = op1, op1 = tem;
-
-  if (GET_RTX_CLASS (code) == RTX_COMPARE
-      || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
-    {
-      enum machine_mode op_mode = GET_MODE (op0);
-
-      /* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
-        just (REL_OP X Y).  */
-      if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
-       {
-         op1 = XEXP (op0, 1);
-         op0 = XEXP (op0, 0);
-         op_mode = GET_MODE (op0);
-       }
-
-      if (op_mode == VOIDmode)
-       op_mode = GET_MODE (op1);
-      result = simplify_relational_operation (code, mode, op_mode, op0, op1);
     }
-  else
-    result = simplify_binary_operation (code, mode, op0, op1);
-
-  if (result)
-    return result;
-
-  /* Put complex operands first and constants second.  */
-  if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
-      && swap_commutative_operands_p (op0, op1))
-    return gen_rtx_fmt_ee (code, mode, op1, op0);
-
-  /* If we are turning off bits already known off in OP0, we need not do
-     an AND.  */
-  else if (code == AND && GET_CODE (op1) == CONST_INT
-          && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-          && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
-    return op0;
 
-  return gen_rtx_fmt_ee (code, mode, op0, op1);
+ fail:
+  return gen_rtx_CLOBBER (imode, const0_rtx);
 }
 \f
 /* Simplify a comparison between *POP0 and *POP1 where CODE is the
@@ -9978,16 +10103,22 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          break;
 
        case SIGN_EXTEND:
-         /* Can simplify (compare (zero/sign_extend FOO) CONST)
-            to (compare FOO CONST) if CONST fits in FOO's mode and we
-            are either testing inequality or have an unsigned comparison
-            with ZERO_EXTEND or a signed comparison with SIGN_EXTEND.  */
-         if (! unsigned_comparison_p
-             && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
-                 <= HOST_BITS_PER_WIDE_INT)
+         /* Can simplify (compare (zero/sign_extend FOO) CONST) to
+            (compare FOO CONST) if CONST fits in FOO's mode and we
+            are either testing inequality or have an unsigned
+            comparison with ZERO_EXTEND or a signed comparison with
+            SIGN_EXTEND.  But don't do it if we don't have a compare
+            insn of the given mode, since we'd have to revert it
+            later on, and then we wouldn't know whether to sign- or
+            zero-extend.  */
+         mode = GET_MODE (XEXP (op0, 0));
+         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+             && ! unsigned_comparison_p
+             && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
              && ((unsigned HOST_WIDE_INT) const_op
-                 < (((unsigned HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0))) - 1)))))
+                 < (((unsigned HOST_WIDE_INT) 1 
+                     << (GET_MODE_BITSIZE (mode) - 1))))
+             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -9995,34 +10126,61 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          break;
 
        case SUBREG:
-         /* Check for the case where we are comparing A - C1 with C2,
-            both constants are smaller than 1/2 the maximum positive
-            value in MODE, and the comparison is equality or unsigned.
-            In that case, if A is either zero-extended to MODE or has
-            sufficient sign bits so that the high-order bit in MODE
-            is a copy of the sign in the inner mode, we can prove that it is
-            safe to do the operation in the wider mode.  This simplifies
-            many range checks.  */
+         /* Check for the case where we are comparing A - C1 with C2, that is
+
+              (subreg:MODE (plus (A) (-C1))) op (C2)
+
+            with C1 a constant, and try to lift the SUBREG, i.e. to do the
+            comparison in the wider mode.  One of the following two conditions
+            must be true in order for this to be valid:
+
+              1. The mode extension results in the same bit pattern being added
+                 on both sides and the comparison is equality or unsigned.  As
+                 C2 has been truncated to fit in MODE, the pattern can only be
+                 all 0s or all 1s.
+
+              2. The mode extension results in the sign bit being copied on
+                 each side.
+
+            The difficulty here is that we have predicates for A but not for
+            (A - C1) so we need to check that C1 is within proper bounds so
+            as to perturbate A as little as possible.  */
 
          if (mode_width <= HOST_BITS_PER_WIDE_INT
              && subreg_lowpart_p (op0)
+             && GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width
              && GET_CODE (SUBREG_REG (op0)) == PLUS
-             && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT
-             && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
-             && (-INTVAL (XEXP (SUBREG_REG (op0), 1))
-                 < (HOST_WIDE_INT) (GET_MODE_MASK (mode) / 2))
-             && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
-             && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
-                                     GET_MODE (SUBREG_REG (op0)))
-                       & ~GET_MODE_MASK (mode))
-                 || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0),
-                                          GET_MODE (SUBREG_REG (op0)))
-                     > (unsigned int)
-                       (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
-                        - GET_MODE_BITSIZE (mode)))))
-           {
-             op0 = SUBREG_REG (op0);
-             continue;
+             && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT)
+           {
+             enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+             rtx a = XEXP (SUBREG_REG (op0), 0);
+             HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1));
+
+             if ((c1 > 0
+                  && (unsigned HOST_WIDE_INT) c1
+                      < (unsigned HOST_WIDE_INT) 1 << (mode_width - 1)
+                  && (equality_comparison_p || unsigned_comparison_p)
+                  /* (A - C1) zero-extends if it is positive and sign-extends
+                     if it is negative, C2 both zero- and sign-extends.  */
+                  && ((0 == (nonzero_bits (a, inner_mode)
+                             & ~GET_MODE_MASK (mode))
+                       && const_op >= 0)
+                      /* (A - C1) sign-extends if it is positive and 1-extends
+                         if it is negative, C2 both sign- and 1-extends.  */
+                      || (num_sign_bit_copies (a, inner_mode)
+                          > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+                                            - mode_width)
+                          && const_op < 0)))
+                 || ((unsigned HOST_WIDE_INT) c1
+                      < (unsigned HOST_WIDE_INT) 1 << (mode_width - 2)
+                     /* (A - C1) always sign-extends, like C2.  */
+                     && num_sign_bit_copies (a, inner_mode)
+                        > (unsigned int) (GET_MODE_BITSIZE (inner_mode)
+                                          - mode_width - 1)))
+               {
+                 op0 = SUBREG_REG (op0);
+                 continue;
+               }
            }
 
          /* If the inner mode is narrower and we are extracting the low part,
@@ -10036,11 +10194,12 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          /* ... fall through ...  */
 
        case ZERO_EXTEND:
-         if ((unsigned_comparison_p || equality_comparison_p)
-             && (GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))
-                 <= HOST_BITS_PER_WIDE_INT)
-             && ((unsigned HOST_WIDE_INT) const_op
-                 < GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))))
+         mode = GET_MODE (XEXP (op0, 0));
+         if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
+             && (unsigned_comparison_p || equality_comparison_p)
+             && (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+             && ((unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode))
+             && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
              op0 = XEXP (op0, 0);
              continue;
@@ -10157,7 +10316,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              if (code == LT || code == NE)
                new_code = GET_CODE (op0);
              else
-               new_code = combine_reversed_comparison_code (op0);
+               new_code = reversed_comparison_code (op0, NULL);
 
              if (new_code != UNKNOWN)
                {
@@ -10284,9 +10443,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                  && c1 != mask
                  && c1 != GET_MODE_MASK (tmode))
                {
-                 op0 = gen_binary (AND, tmode,
-                                   SUBREG_REG (XEXP (op0, 0)),
-                                   gen_int_mode (c1, tmode));
+                 op0 = simplify_gen_binary (AND, tmode,
+                                            SUBREG_REG (XEXP (op0, 0)),
+                                            gen_int_mode (c1, tmode));
                  op0 = gen_lowpart (mode, op0);
                  continue;
                }
@@ -10430,12 +10589,12 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
            {
              rtx inner = XEXP (XEXP (XEXP (op0, 0), 0), 0);
              rtx add_const = XEXP (XEXP (op0, 0), 1);
-             rtx new_const = gen_binary (ASHIFTRT, GET_MODE (op0), add_const,
-                                         XEXP (op0, 1));
+             rtx new_const = simplify_gen_binary (ASHIFTRT, GET_MODE (op0),
+                                                  add_const, XEXP (op0, 1));
 
-             op0 = gen_binary (PLUS, tmode,
-                               gen_lowpart (tmode, inner),
-                               new_const);
+             op0 = simplify_gen_binary (PLUS, tmode,
+                                        gen_lowpart (tmode, inner),
+                                        new_const);
              continue;
            }
 
@@ -10506,7 +10665,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
      those bits.
 
      3. SUBREG_REG (op0) is a memory and LOAD_EXTEND_OP is defined and not
-     NIL.  In that case we know those bits are zeros or ones.  We must
+     UNKNOWN.  In that case we know those bits are zeros or ones.  We must
      also be sure that they are the same as the upper bits of op1.
 
      We can never remove a SUBREG for a non-equality comparison because
@@ -10588,11 +10747,11 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                 make a new AND in the proper mode.  */
              if (GET_CODE (op0) == AND
                  && !have_insn_for (AND, mode))
-               op0 = gen_binary (AND, tmode,
-                                 gen_lowpart (tmode,
-                                              XEXP (op0, 0)),
-                                 gen_lowpart (tmode,
-                                              XEXP (op0, 1)));
+               op0 = simplify_gen_binary (AND, tmode,
+                                          gen_lowpart (tmode,
+                                                       XEXP (op0, 0)),
+                                          gen_lowpart (tmode,
+                                                       XEXP (op0, 1)));
 
              op0 = gen_lowpart (tmode, op0);
              if (zero_extended && GET_CODE (op1) == CONST_INT)
@@ -10607,10 +10766,11 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
          if (op1 == const0_rtx && (code == LT || code == GE)
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
            {
-             op0 = gen_binary (AND, tmode,
-                               gen_lowpart (tmode, op0),
-                               GEN_INT ((HOST_WIDE_INT) 1
-                                        << (GET_MODE_BITSIZE (mode) - 1)));
+             op0 = simplify_gen_binary (AND, tmode,
+                                        gen_lowpart (tmode, op0),
+                                        GEN_INT ((HOST_WIDE_INT) 1
+                                                 << (GET_MODE_BITSIZE (mode)
+                                                     - 1)));
              code = (code == LT) ? NE : EQ;
              break;
            }
@@ -10628,36 +10788,45 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
   return code;
 }
 \f
-/* Like jump.c' reversed_comparison_code, but use combine infrastructure for
-   searching backward.  */
-static enum rtx_code
-combine_reversed_comparison_code (rtx exp)
+/* Utility function for record_value_for_reg.  Count number of
+   rtxs in X.  */
+static int
+count_rtxs (rtx x)
 {
-  enum rtx_code code1 = reversed_comparison_code (exp, NULL);
-  rtx x;
-
-  if (code1 != UNKNOWN
-      || GET_MODE_CLASS (GET_MODE (XEXP (exp, 0))) != MODE_CC)
-    return code1;
-  /* Otherwise try and find where the condition codes were last set and
-     use that.  */
-  x = get_last_value (XEXP (exp, 0));
-  if (!x || GET_CODE (x) != COMPARE)
-    return UNKNOWN;
-  return reversed_comparison_code_parts (GET_CODE (exp),
-                                        XEXP (x, 0), XEXP (x, 1), NULL);
-}
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i, ret = 1;
 
-/* Return comparison with reversed code of EXP and operands OP0 and OP1.
-   Return NULL_RTX in case we fail to do the reversal.  */
-static rtx
-reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1)
-{
-  enum rtx_code reversed_code = combine_reversed_comparison_code (exp);
-  if (reversed_code == UNKNOWN)
-    return NULL_RTX;
-  else
-    return gen_binary (reversed_code, mode, op0, op1);
+  if (GET_RTX_CLASS (code) == '2'
+      || GET_RTX_CLASS (code) == 'c')
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x1 = XEXP (x, 1);
+
+      if (x0 == x1)
+       return 1 + 2 * count_rtxs (x0);
+
+      if ((GET_RTX_CLASS (GET_CODE (x1)) == '2'
+          || GET_RTX_CLASS (GET_CODE (x1)) == 'c')
+         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+       return 2 + 2 * count_rtxs (x0)
+              + count_rtxs (x == XEXP (x1, 0)
+                            ? XEXP (x1, 1) : XEXP (x1, 0));
+
+      if ((GET_RTX_CLASS (GET_CODE (x0)) == '2'
+          || GET_RTX_CLASS (GET_CODE (x0)) == 'c')
+         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+       return 2 + 2 * count_rtxs (x1)
+              + count_rtxs (x == XEXP (x0, 0)
+                            ? XEXP (x0, 1) : XEXP (x0, 0));
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    if (fmt[i] == 'e')
+      ret += count_rtxs (XEXP (x, i));
+
+  return ret;
 }
 \f
 /* Utility function for following routine.  Called when X is part of a value
@@ -10762,6 +10931,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
              && GET_CODE (XEXP (tem, 0)) == CLOBBER
              && GET_CODE (XEXP (tem, 1)) == CLOBBER)
            tem = XEXP (tem, 0);
+         else if (count_occurrences (value, reg, 1) >= 2)
+           {
+             /* If there are two or more occurrences of REG in VALUE,
+                prevent the value from growing too much.  */
+             if (count_rtxs (tem) > MAX_LAST_VALUE_RTL)
+               tem = gen_rtx_CLOBBER (GET_MODE (tem), const0_rtx);
+           }
 
          value = replace_rtx (copy_rtx (value), reg, tem);
        }
@@ -11053,7 +11229,7 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace)
   /* 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 (MEM_P (x) && ! RTX_UNCHANGING_P (x)
+  else if (MEM_P (x) && !MEM_READONLY_P (x)
           && INSN_CUID (insn) <= mem_last_set)
     {
       if (replace)
@@ -11386,7 +11562,6 @@ mark_used_regs_combine (rtx x)
 
        while (GET_CODE (testreg) == SUBREG
               || GET_CODE (testreg) == ZERO_EXTRACT
-              || GET_CODE (testreg) == SIGN_EXTRACT
               || GET_CODE (testreg) == STRICT_LOW_PART)
          testreg = XEXP (testreg, 0);
 
@@ -11698,19 +11873,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
          /* Just get rid of this note, as it is unused later anyway.  */
          break;
 
-       case REG_VTABLE_REF:
-         /* ??? Should remain with *a particular* memory load.  Given the
-            nature of vtable data, the last insn seems relatively safe.  */
-         place = i3;
-         break;
-
        case REG_NON_LOCAL_GOTO:
          if (JUMP_P (i3))
            place = i3;
-         else if (i2 && JUMP_P (i2))
-           place = i2;
          else
-           abort ();
+           {
+             gcc_assert (i2 && JUMP_P (i2));
+             place = i2;
+           }
          break;
 
        case REG_EH_REGION:
@@ -11719,8 +11889,9 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
            place = i3;
          else if (i2 && CALL_P (i2))
            place = i2;
-         else if (flag_non_call_exceptions)
+         else
            {
+             gcc_assert (flag_non_call_exceptions);
              if (may_trap_p (i3))
                place = i3;
              else if (i2 && may_trap_p (i2))
@@ -11729,21 +11900,19 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                 can now prove that the instructions can't trap.  Drop the
                 note in this case.  */
            }
-         else
-           abort ();
          break;
 
-       case REG_ALWAYS_RETURN:
        case REG_NORETURN:
        case REG_SETJMP:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
          if (CALL_P (i3))
            place = i3;
-         else if (i2 && CALL_P (i2))
-           place = i2;
          else
-           abort ();
+           {
+             gcc_assert (i2 && CALL_P (i2));
+             place = i2;
+           }
          break;
 
        case REG_UNUSED:
@@ -11846,22 +12015,34 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
                place = i2;
            }
 
-         /* Don't attach REG_LABEL note to a JUMP_INSN which has
-            JUMP_LABEL already.  Instead, decrement LABEL_NUSES.  */
-         if (place && JUMP_P (place) && JUMP_LABEL (place))
+         /* Don't attach REG_LABEL note to a JUMP_INSN.  Add
+            a JUMP_LABEL instead or decrement LABEL_NUSES.  */
+         if (place && JUMP_P (place))
            {
-             if (JUMP_LABEL (place) != XEXP (note, 0))
-               abort ();
-             if (LABEL_P (JUMP_LABEL (place)))
-               LABEL_NUSES (JUMP_LABEL (place))--;
+             rtx label = JUMP_LABEL (place);
+             
+             if (!label)
+               JUMP_LABEL (place) = XEXP (note, 0);
+             else
+               {
+                 gcc_assert (label == XEXP (note, 0));
+                 if (LABEL_P (label))
+                   LABEL_NUSES (label)--;
+               }
              place = 0;
            }
-         if (place2 && JUMP_P (place2) && JUMP_LABEL (place2))
+         if (place2 && JUMP_P (place2))
            {
-             if (JUMP_LABEL (place2) != XEXP (note, 0))
-               abort ();
-             if (LABEL_P (JUMP_LABEL (place2)))
-               LABEL_NUSES (JUMP_LABEL (place2))--;
+             rtx label = JUMP_LABEL (place2);
+             
+             if (!label)
+               JUMP_LABEL (place2) = XEXP (note, 0);
+             else
+               {
+                 gcc_assert (label == XEXP (note, 0));
+                 if (LABEL_P (label))
+                   LABEL_NUSES (label)--;
+               }
              place2 = 0;
            }
          break;
@@ -12190,7 +12371,7 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2)
        default:
          /* Any other notes should not be present at this point in the
             compilation.  */
-         abort ();
+         gcc_unreachable ();
        }
 
       if (place)
@@ -12252,7 +12433,6 @@ distribute_links (rtx links)
 
       reg = SET_DEST (set);
       while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
-            || GET_CODE (reg) == SIGN_EXTRACT
             || GET_CODE (reg) == STRICT_LOW_PART)
        reg = XEXP (reg, 0);
 
@@ -12346,8 +12526,7 @@ insn_cuid (rtx insn)
         && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE)
     insn = NEXT_INSN (insn);
 
-  if (INSN_UID (insn) > max_uid_cuid)
-    abort ();
+  gcc_assert (INSN_UID (insn) <= max_uid_cuid);
 
   return INSN_CUID (insn);
 }