OSDN Git Service

2005-12-23 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 9f910a7..2482bbd 100644 (file)
@@ -55,7 +55,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    - reg_live_length is not updated
    - reg_n_refs is not adjusted in the rare case when a register is
      no longer required in a computation
-   - there are extremely rare cases (see distribute_regnotes) when a
+   - there are extremely rare cases (see distribute_notes) when a
      REG_DEAD note is lost
    - a LOG_LINKS entry that refers to an insn with multiple SETs may be
      removed because there is no way to know which register it was
@@ -385,19 +385,23 @@ static rtx extract_left_shift (rtx, int);
 static rtx make_compound_operation (rtx, enum rtx_code);
 static int get_pos_from_mask (unsigned HOST_WIDE_INT,
                              unsigned HOST_WIDE_INT *);
+static rtx canon_reg_for_combine (rtx, rtx);
 static rtx force_to_mode (rtx, enum machine_mode,
-                         unsigned HOST_WIDE_INT, rtx, int);
+                         unsigned HOST_WIDE_INT, int);
 static rtx if_then_else_cond (rtx, rtx *, rtx *);
 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_1 (enum machine_mode, rtx,
+                                    unsigned HOST_WIDE_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,
                            HOST_WIDE_INT, enum machine_mode, int *);
-static rtx simplify_shift_const        (rtx, enum rtx_code, enum machine_mode, rtx,
+static rtx simplify_shift_const_1 (enum rtx_code, enum machine_mode, rtx, int);
+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);
@@ -1423,6 +1427,7 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
       rtx inner_dest = dest;
+      rtx subdest;
 
       while (GET_CODE (inner_dest) == STRICT_LOW_PART
             || GET_CODE (inner_dest) == SUBREG
@@ -1457,27 +1462,35 @@ combinable_i3pat (rtx i3, rtx *loc, rtx i2dest, rtx i1dest,
          || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
        return 0;
 
-      /* If DEST is used in I3, it is being killed in this insn,
-        so record that for later.
+      /* If DEST is used in I3, it is being killed in this insn, so
+        record that for later.  We have to consider paradoxical
+        subregs here, since they kill the whole register, but we
+        ignore partial subregs, STRICT_LOW_PART, etc.
         Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
         STACK_POINTER_REGNUM, since these are always considered to be
         live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
-      if (pi3dest_killed && REG_P (dest)
-         && reg_referenced_p (dest, PATTERN (i3))
-         && REGNO (dest) != FRAME_POINTER_REGNUM
+      subdest = dest;
+      if (GET_CODE (subdest) == SUBREG
+         && (GET_MODE_SIZE (GET_MODE (subdest))
+             >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
+       subdest = SUBREG_REG (subdest);
+      if (pi3dest_killed
+         && REG_P (subdest)
+         && reg_referenced_p (subdest, PATTERN (i3))
+         && REGNO (subdest) != FRAME_POINTER_REGNUM
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && REGNO (dest) != HARD_FRAME_POINTER_REGNUM
+         && REGNO (subdest) != HARD_FRAME_POINTER_REGNUM
 #endif
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && (REGNO (dest) != ARG_POINTER_REGNUM
-             || ! fixed_regs [REGNO (dest)])
+         && (REGNO (subdest) != ARG_POINTER_REGNUM
+             || ! fixed_regs [REGNO (subdest)])
 #endif
-         && REGNO (dest) != STACK_POINTER_REGNUM)
+         && REGNO (subdest) != STACK_POINTER_REGNUM)
        {
          if (*pi3dest_killed)
            return 0;
 
-         *pi3dest_killed = dest;
+         *pi3dest_killed = subdest;
        }
     }
 
@@ -2080,35 +2093,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
   subst_insn = i3;
 
-  /* It is possible that the source of I2 or I1 may be performing an
-     unneeded operation, such as a ZERO_EXTEND of something that is known
-     to have the high part zero.  Handle that case by letting subst look at
-     the innermost one of them.
-
-     Another way to do this would be to have a function that tries to
-     simplify a single insn instead of merging two or more insns.  We don't
-     do this because of the potential of infinite loops and because
-     of the potential extra memory required.  However, doing it the way
-     we are is a bit of a kludge and doesn't catch all cases.
-
-     But only do this if -fexpensive-optimizations since it slows things down
-     and doesn't usually win.  */
-
-  if (flag_expensive_optimizations)
-    {
-      /* Pass pc_rtx so no substitutions are done, just simplifications.  */
-      if (i1)
-       {
-         subst_low_cuid = INSN_CUID (i1);
-         i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
-       }
-      else
-       {
-         subst_low_cuid = INSN_CUID (i2);
-         i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
-       }
-    }
-
 #ifndef HAVE_cc0
   /* Many machines that don't use CC0 have insns that can both perform an
      arithmetic operation and set the condition code.  These operations will
@@ -2171,6 +2155,41 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
   else
 #endif
     {
+      /* It is possible that the source of I2 or I1 may be performing
+        an unneeded operation, such as a ZERO_EXTEND of something
+        that is known to have the high part zero.  Handle that case
+        by letting subst look at the innermost one of them.
+
+        Another way to do this would be to have a function that tries
+        to simplify a single insn instead of merging two or more
+        insns.  We don't do this because of the potential of infinite
+        loops and because of the potential extra memory required.
+        However, doing it the way we are is a bit of a kludge and
+        doesn't catch all cases.
+
+        But only do this if -fexpensive-optimizations since it slows
+        things down and doesn't usually win.
+
+        This is not done in the COMPARE case above because the
+        unmodified I2PAT is used in the PARALLEL and so a pattern
+        with a modified I2SRC would not match.  */
+
+      if (flag_expensive_optimizations)
+       {
+         /* Pass pc_rtx so no substitutions are done, just
+            simplifications.  */
+         if (i1)
+           {
+             subst_low_cuid = INSN_CUID (i1);
+             i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
+           }
+         else
+           {
+             subst_low_cuid = INSN_CUID (i2);
+             i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
+           }
+       }
+
       n_occurrences = 0;               /* `subst' counts here */
 
       /* If I1 feeds into I2 (not into I3) and I1DEST is in I1SRC, we
@@ -2511,6 +2530,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          rtx newdest = i2dest;
          enum rtx_code split_code = GET_CODE (*split);
          enum machine_mode split_mode = GET_MODE (*split);
+         bool subst_done = false;
+         newi2pat = NULL_RTX;
 
          /* Get NEWDEST as a register in the proper mode.  We have already
             validated that we can do this.  */
@@ -2556,8 +2577,69 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
            }
 #endif
 
-         newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
-         SUBST (*split, newdest);
+         /* Attempt to split binary operators using arithmetic identities.  */
+         if (BINARY_P (SET_SRC (newpat))
+             && split_mode == GET_MODE (SET_SRC (newpat))
+             && ! side_effects_p (SET_SRC (newpat)))
+           {
+             rtx setsrc = SET_SRC (newpat);
+             enum machine_mode mode = GET_MODE (setsrc);
+             enum rtx_code code = GET_CODE (setsrc);
+             rtx src_op0 = XEXP (setsrc, 0);
+             rtx src_op1 = XEXP (setsrc, 1);
+
+             /* Split "X = Y op Y" as "Z = Y; X = Z op Z".  */
+             if (rtx_equal_p (src_op0, src_op1))
+               {
+                 newi2pat = gen_rtx_SET (VOIDmode, newdest, src_op0);
+                 SUBST (XEXP (setsrc, 0), newdest);
+                 SUBST (XEXP (setsrc, 1), newdest);
+                 subst_done = true;
+               }
+             /* Split "((P op Q) op R) op S" where op is PLUS or MULT.  */
+             else if ((code == PLUS || code == MULT)
+                      && GET_CODE (src_op0) == code
+                      && GET_CODE (XEXP (src_op0, 0)) == code
+                      && (INTEGRAL_MODE_P (mode)
+                          || (FLOAT_MODE_P (mode)
+                              && flag_unsafe_math_optimizations)))
+               {
+                 rtx p = XEXP (XEXP (src_op0, 0), 0);
+                 rtx q = XEXP (XEXP (src_op0, 0), 1);
+                 rtx r = XEXP (src_op0, 1);
+                 rtx s = src_op1;
+
+                 /* Split both "((X op Y) op X) op Y" and
+                    "((X op Y) op Y) op X" as "T op T" where T is
+                    "X op Y".  */
+                 if ((rtx_equal_p (p,r) && rtx_equal_p (q,s))
+                      || (rtx_equal_p (p,s) && rtx_equal_p (q,r)))
+                   {
+                     newi2pat = gen_rtx_SET (VOIDmode, newdest,
+                                             XEXP (src_op0, 0));
+                     SUBST (XEXP (setsrc, 0), newdest);
+                     SUBST (XEXP (setsrc, 1), newdest);
+                     subst_done = true;
+                   }
+                 /* Split "((X op X) op Y) op Y)" as "T op T" where
+                    T is "X op Y".  */
+                 else if (rtx_equal_p (p,q) && rtx_equal_p (r,s))
+                   {
+                     rtx tmp = simplify_gen_binary (code, mode, p, r);
+                     newi2pat = gen_rtx_SET (VOIDmode, newdest, tmp);
+                     SUBST (XEXP (setsrc, 0), newdest);
+                     SUBST (XEXP (setsrc, 1), newdest);
+                     subst_done = true;
+                   }
+               }
+           }
+
+         if (!subst_done)
+           {
+             newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
+             SUBST (*split, newdest);
+           }
+
          i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
          /* recog_for_combine might have added CLOBBERs to newi2pat.
@@ -3346,13 +3428,15 @@ find_split_point (rtx *loc, rtx insn)
          rtx dest = XEXP (SET_DEST (x), 0);
          enum machine_mode mode = GET_MODE (dest);
          unsigned HOST_WIDE_INT mask = ((HOST_WIDE_INT) 1 << len) - 1;
+         rtx or_mask;
 
          if (BITS_BIG_ENDIAN)
            pos = GET_MODE_BITSIZE (mode) - len - pos;
 
+         or_mask = gen_int_mode (src << pos, mode);
          if (src == mask)
            SUBST (SET_SRC (x),
-                  simplify_gen_binary (IOR, mode, dest, GEN_INT (src << pos)));
+                  simplify_gen_binary (IOR, mode, dest, or_mask));
          else
            {
              rtx negmask = gen_int_mode (~(mask << pos), mode);
@@ -3360,7 +3444,7 @@ find_split_point (rtx *loc, rtx insn)
                     simplify_gen_binary (IOR, mode,
                                          simplify_gen_binary (AND, mode,
                                                               dest, negmask),
-                                         GEN_INT (src << pos)));
+                                         or_mask));
            }
 
          SUBST (SET_DEST (x), dest);
@@ -3884,7 +3968,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
   enum rtx_code code = GET_CODE (x);
   enum machine_mode mode = GET_MODE (x);
   rtx temp;
-  rtx reversed;
   int i;
 
   /* If this is a commutative operation, put a constant last and a complex
@@ -4141,60 +4224,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
       break;
 
-    case NOT:
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && subreg_lowpart_p (XEXP (x, 0))
-         && (GET_MODE_SIZE (GET_MODE (XEXP (x, 0)))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (x, 0)))))
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == ASHIFT
-         && XEXP (SUBREG_REG (XEXP (x, 0)), 0) == const1_rtx)
-       {
-         enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
-
-         x = gen_rtx_ROTATE (inner_mode,
-                             simplify_gen_unary (NOT, inner_mode, const1_rtx,
-                                                 inner_mode),
-                             XEXP (SUBREG_REG (XEXP (x, 0)), 1));
-         return gen_lowpart (mode, x);
-       }
-
-      /* Apply De Morgan's laws to reduce number of patterns for machines
-        with negating logical insns (and-not, nand, etc.).  If result has
-        only one NOT, put it first, since that is how the patterns are
-        coded.  */
-
-      if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
-       {
-         rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
-         enum machine_mode op_mode;
-
-         op_mode = GET_MODE (in1);
-         in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
-
-         op_mode = GET_MODE (in2);
-         if (op_mode == VOIDmode)
-           op_mode = mode;
-         in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
-
-         if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
-           {
-             rtx tem = in2;
-             in2 = in1; in1 = tem;
-           }
-
-         return gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)) == IOR ? AND : IOR,
-                                mode, in1, in2);
-       }
-      break;
-
     case NEG:
-      /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1.  */
-      if (GET_CODE (XEXP (x, 0)) == XOR
-         && XEXP (XEXP (x, 0), 1) == const1_rtx
-         && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
-       return simplify_gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0),
-                                   constm1_rtx);
-
       temp = expand_compound_operation (XEXP (x, 0));
 
       /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
@@ -4247,133 +4277,18 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                                    GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
        SUBST (XEXP (x, 0),
               force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
-                             GET_MODE_MASK (mode), NULL_RTX, 0));
-
-      /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI.  */
-      if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-          || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-         && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
-       return XEXP (XEXP (x, 0), 0);
-
-      /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
-        (OP:SI foo:SI) if OP is NEG or ABS.  */
-      if ((GET_CODE (XEXP (x, 0)) == ABS
-          || GET_CODE (XEXP (x, 0)) == NEG)
-         && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
-             || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
-         && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
-      /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
-        (truncate:SI x).  */
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
-         && subreg_lowpart_p (XEXP (x, 0)))
-       return SUBREG_REG (XEXP (x, 0));
-
-      /* If we know that the value is already truncated, we can
-         replace the TRUNCATE with a SUBREG if TRULY_NOOP_TRUNCATION
-         is nonzero for the corresponding modes.  But don't do this
-         for an (LSHIFTRT (MULT ...)) since this will cause problems
-         with the umulXi3_highpart patterns.  */
-      if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
-         && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-            >= (unsigned int) (GET_MODE_BITSIZE (mode) + 1)
-         && ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
-               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
-       return gen_lowpart (mode, XEXP (x, 0));
+                             GET_MODE_MASK (mode), 0));
 
-      /* A truncate of a comparison can be replaced with a subreg if
-         STORE_FLAG_VALUE permits.  This is like the previous test,
-         but it works even if the comparison is done in a mode larger
-         than HOST_BITS_PER_WIDE_INT.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && COMPARISON_P (XEXP (x, 0))
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0)
-       return gen_lowpart (mode, XEXP (x, 0));
-
-      /* Similarly, a truncate of a register whose value is a
-         comparison can be replaced with a subreg if STORE_FLAG_VALUE
-         permits.  */
+      /* Similarly to what we do in simplify-rtx.c, a truncate of a register
+        whose value is a comparison can be replaced with a subreg if
+        STORE_FLAG_VALUE permits.  */
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
          && ((HOST_WIDE_INT) STORE_FLAG_VALUE & ~GET_MODE_MASK (mode)) == 0
          && (temp = get_last_value (XEXP (x, 0)))
          && COMPARISON_P (temp))
        return gen_lowpart (mode, XEXP (x, 0));
-
       break;
 
-    case FLOAT_TRUNCATE:
-      /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF.  */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
-         && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
-       return XEXP (XEXP (x, 0), 0);
-
-      /* (float_truncate:SF (float_truncate:DF foo:XF))
-         = (float_truncate:SF foo:XF).
-        This may eliminate double rounding, so it is unsafe.
-
-         (float_truncate:SF (float_extend:XF foo:DF))
-         = (float_truncate:SF foo:DF).
-
-         (float_truncate:DF (float_extend:XF foo:SF))
-         = (float_extend:SF foo:DF).  */
-      if ((GET_CODE (XEXP (x, 0)) == FLOAT_TRUNCATE
-          && flag_unsafe_math_optimizations)
-         || GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND)
-       return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (XEXP (x, 0),
-                                                           0)))
-                                  > GET_MODE_SIZE (mode)
-                                  ? FLOAT_TRUNCATE : FLOAT_EXTEND,
-                                  mode,
-                                  XEXP (XEXP (x, 0), 0), mode);
-
-      /*  (float_truncate (float x)) is (float x)  */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT
-         && (flag_unsafe_math_optimizations
-             || ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
-                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
-                     - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
-                                            GET_MODE (XEXP (XEXP (x, 0), 0)))))))
-       return simplify_gen_unary (FLOAT, mode,
-                                  XEXP (XEXP (x, 0), 0),
-                                  GET_MODE (XEXP (XEXP (x, 0), 0)));
-
-      /* (float_truncate:SF (OP:DF (float_extend:DF foo:sf))) is
-        (OP:SF foo:SF) if OP is NEG or ABS.  */
-      if ((GET_CODE (XEXP (x, 0)) == ABS
-          || GET_CODE (XEXP (x, 0)) == NEG)
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == FLOAT_EXTEND
-         && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (XEXP (x, 0), 0), 0), mode);
-
-      /* (float_truncate:SF (subreg:DF (float_truncate:SF X) 0))
-        is (float_truncate:SF x).  */
-      if (GET_CODE (XEXP (x, 0)) == SUBREG
-         && subreg_lowpart_p (XEXP (x, 0))
-         && GET_CODE (SUBREG_REG (XEXP (x, 0))) == FLOAT_TRUNCATE)
-       return SUBREG_REG (XEXP (x, 0));
-      break;
-    case FLOAT_EXTEND:
-      /*  (float_extend (float_extend x)) is (float_extend x)
-
-         (float_extend (float x)) is (float x) assuming that double
-         rounding can't happen.
-          */
-      if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
-         || (GET_CODE (XEXP (x, 0)) == FLOAT
-             && ((unsigned)significand_size (GET_MODE (XEXP (x, 0)))
-                 >= (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (x, 0), 0)))
-                     - num_sign_bit_copies (XEXP (XEXP (x, 0), 0),
-                                            GET_MODE (XEXP (XEXP (x, 0), 0)))))))
-       return simplify_gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                  XEXP (XEXP (x, 0), 0),
-                                  GET_MODE (XEXP (XEXP (x, 0), 0)));
-
-      break;
 #ifdef HAVE_cc0
     case COMPARE:
       /* Convert (compare FOO (const_int 0)) to FOO unless we aren't
@@ -4412,32 +4327,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 #endif
 
     case PLUS:
-      /* Canonicalize (plus (mult (neg B) C) A) to (minus A (mult B C)).
-       */
-      if (GET_CODE (XEXP (x, 0)) == MULT
-         && GET_CODE (XEXP (XEXP (x, 0), 0)) == NEG)
-       {
-         rtx in1, in2;
-
-         in1 = XEXP (XEXP (XEXP (x, 0), 0), 0);
-         in2 = XEXP (XEXP (x, 0), 1);
-         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
-        outermost.  That's because that's the way indexed addresses are
-        supposed to appear.  This code used to check many more cases, but
-        they are now checked elsewhere.  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS
-         && CONSTANT_ADDRESS_P (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
         bit-field and can be replaced by either a sign_extend or a
@@ -4464,17 +4353,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                                 GET_MODE_BITSIZE (mode) - (i + 1)),
           GET_MODE_BITSIZE (mode) - (i + 1));
 
-      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
-        C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
-        is 1.  This produces better code than the alternative immediately
-        below.  */
-      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)))
-       return
-         simplify_gen_unary (NEG, mode, reversed, mode);
-
       /* If only the low-order bit of X is possibly nonzero, (plus x -1)
         can become (ashiftrt (ashift (xor x 1) C) C) where C is
         the bitsize of the mode - 1.  This allows simplification of
@@ -4512,14 +4390,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
       break;
 
     case MINUS:
-      /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
-        by reversing the comparison code if valid.  */
-      if (STORE_FLAG_VALUE == 1
-         && XEXP (x, 0) == const1_rtx
-         && COMPARISON_P (XEXP (x, 1))
-         && (reversed = reversed_comparison (XEXP (x, 1), mode)))
-       return reversed;
-
       /* (minus <foo> (and <foo> (const_int -pow2))) becomes
         (and <foo> (const_int pow2-1))  */
       if (GET_CODE (XEXP (x, 1)) == AND
@@ -4528,45 +4398,6 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
          && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
        return simplify_and_const_int (NULL_RTX, mode, XEXP (x, 0),
                                       -INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
-
-      /* Canonicalize (minus A (mult (neg B) C)) to (plus (mult B C) A).
-       */
-      if (GET_CODE (XEXP (x, 1)) == MULT
-         && GET_CODE (XEXP (XEXP (x, 1), 0)) == NEG)
-       {
-         rtx in1, in2;
-
-         in1 = XEXP (XEXP (XEXP (x, 1), 0), 0);
-         in2 = XEXP (XEXP (x, 1), 1);
-         return simplify_gen_binary (PLUS, mode,
-                                     simplify_gen_binary (MULT, mode,
-                                                          in1, in2),
-                                     XEXP (x, 0));
-       }
-
-      /* Canonicalize (minus (neg A) (mult B C)) to
-        (minus (mult (neg B) C) A).  */
-      if (GET_CODE (XEXP (x, 1)) == MULT
-         && GET_CODE (XEXP (x, 0)) == NEG)
-       {
-         rtx in1, in2;
-
-         in1 = simplify_gen_unary (NEG, mode, XEXP (XEXP (x, 1), 0), mode);
-         in2 = XEXP (XEXP (x, 1), 1);
-         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 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:
@@ -4782,55 +4613,8 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
 
     case AND:
     case IOR:
-    case XOR:
       return simplify_logical (x);
 
-    case ABS:
-      /* (abs (neg <foo>)) -> (abs <foo>) */
-      if (GET_CODE (XEXP (x, 0)) == NEG)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-
-      /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
-         do nothing.  */
-      if (GET_MODE (XEXP (x, 0)) == VOIDmode)
-       break;
-
-      /* If operand is something known to be positive, ignore the ABS.  */
-      if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
-         || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-              <= HOST_BITS_PER_WIDE_INT)
-             && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
-                  & ((HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
-                 == 0)))
-       return XEXP (x, 0);
-
-      /* If operand is known to be only -1 or 0, convert ABS to NEG.  */
-      if (num_sign_bit_copies (XEXP (x, 0), mode) == GET_MODE_BITSIZE (mode))
-       return gen_rtx_NEG (mode, XEXP (x, 0));
-
-      break;
-
-    case FFS:
-      /* (ffs (*_extend <X>)) = (ffs <X>) */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
-         || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
-    case POPCOUNT:
-    case PARITY:
-      /* (pop* (zero_extend <X>)) = (pop* <X>) */
-      if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
-    case FLOAT:
-      /* (float (sign_extend <X>)) = (float <X>).  */
-      if (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND)
-       SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
-      break;
-
     case ASHIFT:
     case LSHIFTRT:
     case ASHIFTRT:
@@ -4847,45 +4631,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
                              ((HOST_WIDE_INT) 1
                               << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
                              - 1,
-                             NULL_RTX, 0));
-      break;
-
-    case VEC_SELECT:
-      {
-       rtx op0 = XEXP (x, 0);
-       rtx op1 = XEXP (x, 1);
-       int len;
-
-       gcc_assert (GET_CODE (op1) == PARALLEL);
-       len = XVECLEN (op1, 0);
-       if (len == 1
-           && GET_CODE (XVECEXP (op1, 0, 0)) == CONST_INT
-           && GET_CODE (op0) == VEC_CONCAT)
-         {
-           int offset = INTVAL (XVECEXP (op1, 0, 0)) * GET_MODE_SIZE (GET_MODE (x));
-
-           /* Try to find the element in the VEC_CONCAT.  */
-           for (;;)
-             {
-               if (GET_MODE (op0) == GET_MODE (x))
-                 return op0;
-               if (GET_CODE (op0) == VEC_CONCAT)
-                 {
-                   HOST_WIDE_INT op0_size = GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)));
-                   if (offset < op0_size)
-                     op0 = XEXP (op0, 0);
-                   else
-                     {
-                       offset -= op0_size;
-                       op0 = XEXP (op0, 1);
-                     }
-                 }
-               else
-                 break;
-             }
-         }
-      }
-
+                             0));
       break;
 
     default:
@@ -5249,7 +4995,7 @@ simplify_set (rtx x)
   if (GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
     {
-      src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
+      src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, 0);
       SUBST (SET_SRC (x), src);
     }
 
@@ -5580,42 +5326,10 @@ simplify_logical (rtx x)
   enum machine_mode mode = GET_MODE (x);
   rtx op0 = XEXP (x, 0);
   rtx op1 = XEXP (x, 1);
-  rtx reversed;
 
   switch (GET_CODE (x))
     {
     case AND:
-      /* Convert (A ^ B) & A to A & (~B) since the latter is often a single
-        insn (and may simplify more).  */
-      if (GET_CODE (op0) == XOR
-         && rtx_equal_p (XEXP (op0, 0), op1)
-         && ! side_effects_p (op1))
-       x = 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 = 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 = 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 = 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
         "unsigned HOST_WIDE_INT".  */
@@ -5624,22 +5338,6 @@ simplify_logical (rtx x)
              || INTVAL (op1) > 0))
        {
          x = simplify_and_const_int (x, mode, op0, INTVAL (op1));
-
-         /* If we have (ior (and (X C1) C2)) and the next restart would be
-            the last, simplify this by making C1 as small as possible
-            and then exit.  Only do this if C1 actually changes: for now
-            this only saves memory but, should this transformation be
-            moved to simplify-rtx.c, we'd risk unbounded recursion there.  */
-         if (GET_CODE (x) == IOR && GET_CODE (op0) == AND
-             && GET_CODE (XEXP (op0, 1)) == CONST_INT
-             && GET_CODE (op1) == CONST_INT
-             && (INTVAL (XEXP (op0, 1)) & INTVAL (op1)) != 0)
-           return simplify_gen_binary (IOR, mode,
-                                       simplify_gen_binary
-                                         (AND, mode, XEXP (op0, 0),
-                                          GEN_INT (INTVAL (XEXP (op0, 1))
-                                                   & ~INTVAL (op1))), op1);
-
          if (GET_CODE (x) != AND)
            return x;
 
@@ -5647,14 +5345,6 @@ simplify_logical (rtx x)
          op1 = XEXP (x, 1);
        }
 
-      /* Convert (A | B) & A to A.  */
-      if (GET_CODE (op0) == IOR
-         && (rtx_equal_p (XEXP (op0, 0), op1)
-             || rtx_equal_p (XEXP (op0, 1), op1))
-         && ! side_effects_p (XEXP (op0, 0))
-         && ! side_effects_p (XEXP (op0, 1)))
-       return op1;
-
       /* 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.  */
@@ -5673,20 +5363,6 @@ simplify_logical (rtx x)
       break;
 
     case IOR:
-      /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
-      if (GET_CODE (op1) == CONST_INT
-         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (op0, mode) & ~INTVAL (op1)) == 0)
-       return op1;
-
-      /* Convert (A & B) | A to A.  */
-      if (GET_CODE (op0) == AND
-         && (rtx_equal_p (XEXP (op0, 0), op1)
-             || rtx_equal_p (XEXP (op0, 1), op1))
-         && ! side_effects_p (XEXP (op0, 0))
-         && ! side_effects_p (XEXP (op0, 1)))
-       return op1;
-
       /* If we have (ior (and A B) C), apply the distributive law and then
         the inverse distributive law to see if things simplify.  */
 
@@ -5703,127 +5379,6 @@ simplify_logical (rtx x)
          if (result)
            return result;
        }
-
-      /* Convert (ior (ashift A CX) (lshiftrt A CY)) where CX+CY equals the
-        mode size to (rotate A CX).  */
-
-      if (((GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
-          || (GET_CODE (op1) == ASHIFT && GET_CODE (op0) == LSHIFTRT))
-         && rtx_equal_p (XEXP (op0, 0), XEXP (op1, 0))
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && GET_CODE (XEXP (op1, 1)) == CONST_INT
-         && (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
-             == GET_MODE_BITSIZE (mode)))
-       return gen_rtx_ROTATE (mode, XEXP (op0, 0),
-                              (GET_CODE (op0) == ASHIFT
-                               ? XEXP (op0, 1) : XEXP (op1, 1)));
-
-      /* If OP0 is (ashiftrt (plus ...) C), it might actually be
-        a (sign_extend (plus ...)).  If so, OP1 is a CONST_INT, and the PLUS
-        does not affect any of the bits in OP1, it can really be done
-        as a PLUS and we can associate.  We do this by seeing if OP1
-        can be safely shifted left C bits.  */
-      if (GET_CODE (op1) == CONST_INT && GET_CODE (op0) == ASHIFTRT
-         && GET_CODE (XEXP (op0, 0)) == PLUS
-         && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT)
-       {
-         int count = INTVAL (XEXP (op0, 1));
-         HOST_WIDE_INT mask = INTVAL (op1) << count;
-
-         if (mask >> count == INTVAL (op1)
-             && (mask & nonzero_bits (XEXP (op0, 0), mode)) == 0)
-           {
-             SUBST (XEXP (XEXP (op0, 0), 1),
-                    GEN_INT (INTVAL (XEXP (XEXP (op0, 0), 1)) | mask));
-             return op0;
-           }
-       }
-      break;
-
-    case XOR:
-      /* If we are XORing two things that have no bits in common,
-        convert them into an IOR.  This helps to detect rotation encoded
-        using those methods and possibly other simplifications.  */
-
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && (nonzero_bits (op0, mode)
-             & nonzero_bits (op1, mode)) == 0)
-       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
-        (NOT y).  */
-      {
-       int num_negated = 0;
-
-       if (GET_CODE (op0) == NOT)
-         num_negated++, op0 = XEXP (op0, 0);
-       if (GET_CODE (op1) == NOT)
-         num_negated++, op1 = XEXP (op1, 0);
-
-       if (num_negated == 2)
-         {
-           SUBST (XEXP (x, 0), op0);
-           SUBST (XEXP (x, 1), op1);
-         }
-       else if (num_negated == 1)
-         return
-           simplify_gen_unary (NOT, mode,
-                               simplify_gen_binary (XOR, mode, op0, op1),
-                               mode);
-      }
-
-      /* Convert (xor (and A B) B) to (and (not A) B).  The latter may
-        correspond to a machine insn or result in further simplifications
-        if B is a constant.  */
-
-      if (GET_CODE (op0) == AND
-         && rtx_equal_p (XEXP (op0, 1), op1)
-         && ! side_effects_p (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 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)))
-       return reversed;
-
-      /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
-        is (lt foo (const_int 0)), so we can perform the above
-        simplification if STORE_FLAG_VALUE is 1.  */
-
-      if (STORE_FLAG_VALUE == 1
-         && op1 == const1_rtx
-         && GET_CODE (op0) == LSHIFTRT
-         && GET_CODE (XEXP (op0, 1)) == CONST_INT
-         && INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
-       return gen_rtx_GE (mode, XEXP (op0, 0), const0_rtx);
-
-      /* (xor (comparison foo bar) (const_int sign-bit))
-        when STORE_FLAG_VALUE is the sign bit.  */
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-             == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
-         && op1 == const_true_rtx
-         && COMPARISON_P (op0)
-         && (reversed = reversed_comparison (op0, mode)))
-       return reversed;
-
       break;
 
     default:
@@ -6357,7 +5912,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
                             len >= HOST_BITS_PER_WIDE_INT
                             ? ~(unsigned HOST_WIDE_INT) 0
                             : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
-                            NULL_RTX, 0);
+                            0);
 
       /* If this extraction is going into the destination of a SET,
         make a STRICT_LOW_PART unless we made a MEM.  */
@@ -6547,7 +6102,7 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
                             ? ~(unsigned HOST_WIDE_INT) 0
                             : ((((unsigned HOST_WIDE_INT) 1 << len) - 1)
                                << orig_pos),
-                            NULL_RTX, 0);
+                            0);
     }
 
   /* Adjust mode of POS_RTX, if needed.  If we want a wider mode, we
@@ -6880,7 +6435,7 @@ make_compound_operation (rtx x, enum rtx_code in_code)
            && subreg_lowpart_p (x))
          {
            rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
-                                      NULL_RTX, 0);
+                                      0);
            
            /* If we have something other than a SUBREG, we might have
               done an expansion, so rerun ourselves.  */
@@ -6914,6 +6469,16 @@ make_compound_operation (rtx x, enum rtx_code in_code)
        SUBST (XEXP (x, i), new);
       }
 
+  /* If this is a commutative operation, the changes to the operands
+     may have made it noncanonical.  */
+  if (COMMUTATIVE_ARITH_P (x)
+      && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+    {
+      tem = XEXP (x, 0);
+      SUBST (XEXP (x, 0), XEXP (x, 1));
+      SUBST (XEXP (x, 1), tem);
+    }
+
   return x;
 }
 \f
@@ -6943,6 +6508,105 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
   return pos;
 }
 \f
+/* If X refers to a register that equals REG in value, replace these
+   references with REG.  */
+static rtx
+canon_reg_for_combine (rtx x, rtx reg)
+{
+  rtx op0, op1, op2;
+  const char *fmt;
+  int i;
+  bool copied;
+
+  enum rtx_code code = GET_CODE (x);
+  switch (GET_RTX_CLASS (code))
+    {
+    case RTX_UNARY:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      if (op0 != XEXP (x, 0))
+       return simplify_gen_unary (GET_CODE (x), GET_MODE (x), op0,
+                                  GET_MODE (reg));
+      break;
+
+    case RTX_BIN_ARITH:
+    case RTX_COMM_ARITH:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+       return simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1);
+      break;
+
+    case RTX_COMPARE:
+    case RTX_COMM_COMPARE:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
+       return simplify_gen_relational (GET_CODE (x), GET_MODE (x),
+                                       GET_MODE (op0), op0, op1);
+      break;
+
+    case RTX_TERNARY:
+    case RTX_BITFIELD_OPS:
+      op0 = canon_reg_for_combine (XEXP (x, 0), reg);
+      op1 = canon_reg_for_combine (XEXP (x, 1), reg);
+      op2 = canon_reg_for_combine (XEXP (x, 2), reg);
+      if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1) || op2 != XEXP (x, 2))
+       return simplify_gen_ternary (GET_CODE (x), GET_MODE (x),
+                                    GET_MODE (op0), op0, op1, op2);
+
+    case RTX_OBJ:
+      if (REG_P (x))
+       {
+         if (rtx_equal_p (get_last_value (reg), x)
+             || rtx_equal_p (reg, get_last_value (x)))
+           return reg;
+         else
+           break;
+       }
+
+      /* fall through */
+
+    default:
+      fmt = GET_RTX_FORMAT (code);
+      copied = false;
+      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+        if (fmt[i] == 'e')
+          {
+            rtx op = canon_reg_for_combine (XEXP (x, i), reg);
+           if (op != XEXP (x, i))
+             {
+               if (!copied)
+                 {
+                   copied = true;
+                   x = copy_rtx (x);
+                 }
+               XEXP (x, i) = op;
+              }
+          }
+        else if (fmt[i] == 'E')
+          {
+            int j;
+            for (j = 0; j < XVECLEN (x, i); j++)
+             {
+               rtx op = canon_reg_for_combine (XVECEXP (x, i, j), reg);
+               if (op != XVECEXP (x, i, j))
+                 {
+                   if (!copied)
+                     {
+                       copied = true;
+                       x = copy_rtx (x);
+                     }
+                   XVECEXP (x, i, j) = op;
+                 }
+             }
+         }
+
+      break;
+    }
+
+  return x;
+}
+
 /* See if X can be simplified knowing that we will only refer to it in
    MODE and will only refer to those bits that are nonzero in MASK.
    If other bits are being computed or if masking operations are done
@@ -6952,16 +6616,13 @@ get_pos_from_mask (unsigned HOST_WIDE_INT m, unsigned HOST_WIDE_INT *plen)
    Return a possibly simplified expression, but always convert X to
    MODE.  If X is a CONST_INT, AND the CONST_INT with MASK.
 
-   Also, if REG is nonzero and X is a register equal in value to REG,
-   replace X with REG.
-
    If JUST_SELECT is nonzero, don't optimize by noticing that bits in MASK
    are all off in X.  This is used when X will be complemented, by either
    NOT, NEG, or XOR.  */
 
 static rtx
 force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
-              rtx reg, int just_select)
+              int just_select)
 {
   enum rtx_code code = GET_CODE (x);
   int next_select = just_select || code == XOR || code == NOT || code == NEG;
@@ -7043,7 +6704,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         within that boundary, we don't need the USE any more.  */
       if (! BITS_BIG_ENDIAN
          && (mask & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, next_select);
       break;
 
     case SIGN_EXTEND:
@@ -7052,13 +6713,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
     case SIGN_EXTRACT:
       x = expand_compound_operation (x);
       if (GET_CODE (x) != code)
-       return force_to_mode (x, mode, mask, reg, next_select);
-      break;
-
-    case REG:
-      if (reg != 0 && (rtx_equal_p (get_last_value (reg), x)
-                      || rtx_equal_p (reg, get_last_value (x))))
-       x = reg;
+       return force_to_mode (x, mode, mask, next_select);
       break;
 
     case SUBREG:
@@ -7071,7 +6726,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              || (0 == (mask
                        & GET_MODE_MASK (GET_MODE (x))
                        & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x)))))))
-       return force_to_mode (SUBREG_REG (x), mode, mask, reg, next_select);
+       return force_to_mode (SUBREG_REG (x), mode, mask, next_select);
       break;
 
     case AND:
@@ -7147,7 +6802,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
            && (INTVAL (XEXP (x, 1)) & ~smask) != 0)
          return force_to_mode (plus_constant (XEXP (x, 0),
                                               (INTVAL (XEXP (x, 1)) & smask)),
-                               mode, smask, reg, next_select);
+                               mode, smask, next_select);
       }
 
       /* ... fall through ...  */
@@ -7169,7 +6824,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          x = simplify_gen_unary (NEG, GET_MODE (x), XEXP (x, 1),
                                  GET_MODE (x));
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       /* Similarly, if C contains every bit in the fuller_mask, then we may
@@ -7180,7 +6835,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
        {
          x = simplify_gen_unary (NOT, GET_MODE (x),
                                  XEXP (x, 1), GET_MODE (x));
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       mask = fuller_mask;
@@ -7210,7 +6865,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
                                      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);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
     binop:
@@ -7219,10 +6874,10 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
       op0 = gen_lowpart (op_mode,
                         force_to_mode (XEXP (x, 0), mode, mask,
-                                       reg, next_select));
+                                       next_select));
       op1 = gen_lowpart (op_mode,
                         force_to_mode (XEXP (x, 1), mode, mask,
-                                       reg, next_select));
+                                       next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
        x = simplify_gen_binary (code, op_mode, op0, op1);
@@ -7256,7 +6911,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
 
       op0 = gen_lowpart (op_mode,
                         force_to_mode (XEXP (x, 0), op_mode,
-                                       mask, reg, next_select));
+                                       mask, next_select));
 
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
@@ -7283,7 +6938,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          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);
+         inner = force_to_mode (inner, op_mode, inner_mask, next_select);
 
          if (GET_MODE (x) != op_mode || inner != XEXP (x, 0))
            x = simplify_gen_binary (LSHIFTRT, op_mode, inner, XEXP (x, 1));
@@ -7320,7 +6975,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
          && (mask == ((unsigned HOST_WIDE_INT) 1
                       << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, next_select);
 
       /* If this is a shift by a constant, get a mask that contains those bits
         that are not copies of the sign bit.  We then have two cases:  If
@@ -7332,7 +6987,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
        {
-         int i = -1;
+         int i;
 
          /* If the considered data is wider than HOST_WIDE_INT, we can't
             represent a mask for all its bits in a single scalar.
@@ -7359,16 +7014,22 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
              nonzero >>= INTVAL (XEXP (x, 1));
            }
 
-         if ((mask & ~nonzero) == 0
-             || (i = exact_log2 (mask)) >= 0)
+         if ((mask & ~nonzero) == 0)
+           {
+             x = simplify_shift_const (x, LSHIFTRT, GET_MODE (x),
+                                       XEXP (x, 0), INTVAL (XEXP (x, 1)));
+             if (GET_CODE (x) != ASHIFTRT)
+               return force_to_mode (x, mode, mask, next_select);
+           }
+
+         else if ((i = exact_log2 (mask)) >= 0)
            {
              x = simplify_shift_const
-               (x, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
-                i < 0 ? INTVAL (XEXP (x, 1))
-                : GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
+                 (NULL_RTX, LSHIFTRT, GET_MODE (x), XEXP (x, 0),
+                  GET_MODE_BITSIZE (GET_MODE (x)) - 1 - i);
 
              if (GET_CODE (x) != ASHIFTRT)
-               return force_to_mode (x, mode, mask, reg, next_select);
+               return force_to_mode (x, mode, mask, next_select);
            }
        }
 
@@ -7392,7 +7053,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          && GET_CODE (XEXP (x, 0)) == ASHIFT
          && XEXP (XEXP (x, 0), 1) == XEXP (x, 1))
        return force_to_mode (XEXP (XEXP (x, 0), 0), mode, mask,
-                             reg, next_select);
+                             next_select);
 
       break;
 
@@ -7411,7 +7072,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          if (temp && GET_CODE (temp) == CONST_INT)
            SUBST (XEXP (x, 0),
                   force_to_mode (XEXP (x, 0), GET_MODE (x),
-                                 INTVAL (temp), reg, next_select));
+                                 INTVAL (temp), next_select));
        }
       break;
 
@@ -7419,7 +7080,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
       /* If we just want the low-order bit, the NEG isn't needed since it
         won't change the low-order bit.  */
       if (mask == 1)
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, just_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, just_select);
 
       /* We need any bits less significant than the most significant bit in
         MASK since carries from those bits will affect the bits we are
@@ -7446,7 +7107,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          x = simplify_gen_binary (LSHIFTRT, GET_MODE (x),
                                   temp, XEXP (XEXP (x, 0), 1));
 
-         return force_to_mode (x, mode, mask, reg, next_select);
+         return force_to_mode (x, mode, mask, next_select);
        }
 
       /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
@@ -7456,7 +7117,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
     unop:
       op0 = gen_lowpart (op_mode,
                         force_to_mode (XEXP (x, 0), mode, mask,
-                                       reg, next_select));
+                                       next_select));
       if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
        x = simplify_gen_unary (code, op_mode, op0, op_mode);
       break;
@@ -7470,7 +7131,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
          && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
          && (nonzero_bits (XEXP (x, 0), mode)
              == (unsigned HOST_WIDE_INT) STORE_FLAG_VALUE))
-       return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
+       return force_to_mode (XEXP (x, 0), mode, mask, next_select);
 
       break;
 
@@ -7479,13 +7140,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
         written in a narrower mode.  We play it safe and do not do so.  */
 
       SUBST (XEXP (x, 1),
-            gen_lowpart (GET_MODE (x),
-                                     force_to_mode (XEXP (x, 1), mode,
-                                                    mask, reg, next_select)));
+            gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 1), mode,
+                                                      mask, next_select)));
       SUBST (XEXP (x, 2),
-            gen_lowpart (GET_MODE (x),
-                                     force_to_mode (XEXP (x, 2), mode,
-                                                    mask, reg, next_select)));
+            gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 2), mode,
+                                                      mask, next_select)));
       break;
 
     default:
@@ -8037,13 +7696,15 @@ make_field_assignment (rtx x)
   /* Shift OTHER right POS places and make it the source, restricting it
      to the proper length and mode.  */
 
-  src = force_to_mode (simplify_shift_const (NULL_RTX, LSHIFTRT,
-                                            GET_MODE (src), other, pos),
-                      mode,
+  src = canon_reg_for_combine (simplify_shift_const (NULL_RTX, LSHIFTRT,
+                                                    GET_MODE (src),
+                                                    other, pos),
+                              dest);
+  src = force_to_mode (src, mode,
                       GET_MODE_BITSIZE (mode) >= HOST_BITS_PER_WIDE_INT
                       ? ~(unsigned HOST_WIDE_INT) 0
                       : ((unsigned HOST_WIDE_INT) 1 << len) - 1,
-                      dest, 0);
+                      0);
 
   /* If SRC is masked by an AND that does not make a difference in
      the value being stored, strip it.  */
@@ -8252,19 +7913,24 @@ distribute_and_simplify_rtx (rtx x, int n)
   return NULL_RTX;
 }
 \f
-/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
-   in MODE.
-
-   Return an equivalent form, if different from X.  Otherwise, return X.  If
-   X is zero, we are to always construct the equivalent form.  */
+/* Simplify a logical `and' of VAROP with the constant CONSTOP, to be done
+   in MODE.  Return an equivalent form, if different from (and VAROP
+   (const_int CONSTOP)).  Otherwise, return NULL_RTX.  */
 
 static rtx
-simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
-                       unsigned HOST_WIDE_INT constop)
+simplify_and_const_int_1 (enum machine_mode mode, rtx varop,
+                         unsigned HOST_WIDE_INT constop)
 {
   unsigned HOST_WIDE_INT nonzero;
+  unsigned HOST_WIDE_INT orig_constop;
+  rtx orig_varop;
   int i;
 
+  orig_varop = varop;
+  orig_constop = constop;
+  if (GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
+
   /* Simplify VAROP knowing that we will be only looking at some of the
      bits in it.
 
@@ -8272,7 +7938,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
      CONSTOP are not significant and will never be examined.  We must
      ensure that is the case by explicitly masking out those bits
      before returning.  */
-  varop = force_to_mode (varop, mode, constop, NULL_RTX, 0);
+  varop = force_to_mode (varop, mode, constop, 0);
 
   /* If VAROP is a CLOBBER, we will fail so return it.  */
   if (GET_CODE (varop) == CLOBBER)
@@ -8326,7 +7992,7 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
                                                       XEXP (varop, 1),
                                                       constop))));
 
-  /* If VAROP is PLUS, and the constant is a mask of low bite, distribute
+  /* If VAROP is PLUS, and the constant is a mask of low bits, distribute
      the AND and see if one of the operands simplifies to zero.  If so, we
      may eliminate it.  */
 
@@ -8343,40 +8009,42 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
        return o0;
     }
 
-  /* Get VAROP in MODE.  Try to get a SUBREG if not.  Don't make a new SUBREG
-     if we already had one (just check for the simplest cases).  */
-  if (x && GET_CODE (XEXP (x, 0)) == SUBREG
-      && GET_MODE (XEXP (x, 0)) == mode
-      && SUBREG_REG (XEXP (x, 0)) == varop)
-    varop = XEXP (x, 0);
-  else
-    varop = gen_lowpart (mode, varop);
-
-  /* If we can't make the SUBREG, try to return what we were given.  */
-  if (GET_CODE (varop) == CLOBBER)
-    return x ? x : varop;
+  /* Make a SUBREG if necessary.  If we can't make it, fail.  */
+  varop = gen_lowpart (mode, varop);
+  if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
 
   /* If we are only masking insignificant bits, return VAROP.  */
   if (constop == nonzero)
-    x = varop;
-  else
-    {
-      /* Otherwise, return an AND.  */
-      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 = simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+    return varop;
 
-      else
-       {
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT
-             || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
-           SUBST (XEXP (x, 1), GEN_INT (constop));
+  if (varop == orig_varop && constop == orig_constop)
+    return NULL_RTX;
 
-         SUBST (XEXP (x, 0), varop);
-       }
-    }
+  /* Otherwise, return an AND.  */
+  constop = trunc_int_for_mode (constop, mode);
+  return simplify_gen_binary (AND, mode, varop, GEN_INT (constop));
+}
+
+
+/* We have X, a logical `and' of VAROP with the constant CONSTOP, to be done
+   in MODE.
 
+   Return an equivalent form, if different from X.  Otherwise, return X.  If
+   X is zero, we are to always construct the equivalent form.  */
+
+static rtx
+simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
+                       unsigned HOST_WIDE_INT constop)
+{
+  rtx tem = simplify_and_const_int_1 (mode, varop, constop);
+  if (tem)
+    return tem;
+
+  if (!x)
+    x = simplify_gen_binary (AND, GET_MODE (varop), varop, GEN_INT (constop));
+  if (GET_MODE (x) != mode)
+    x = gen_lowpart (mode, x);
   return x;
 }
 \f
@@ -8652,21 +8320,20 @@ merge_outer_ops (enum rtx_code *pop0, HOST_WIDE_INT *pconst0, enum rtx_code op1,
 }
 \f
 /* Simplify a shift of VAROP by COUNT bits.  CODE says what kind of shift.
-   The result of the shift is RESULT_MODE.  X, if nonzero, is an expression
-   that we started with.
+   The result of the shift is RESULT_MODE.  Return NULL_RTX if we cannot
+   simplify it.  Otherwise, return a simplified value.
 
    The shift is normally computed in the widest mode we find in VAROP, as
    long as it isn't a different number of words than RESULT_MODE.  Exceptions
-   are ASHIFTRT and ROTATE, which are always done in their original mode,  */
+   are ASHIFTRT and ROTATE, which are always done in their original mode.  */
 
 static rtx
-simplify_shift_const (rtx x, enum rtx_code code,
-                     enum machine_mode result_mode, rtx varop,
-                     int orig_count)
+simplify_shift_const_1 (enum rtx_code code, enum machine_mode result_mode,
+                       rtx varop, int orig_count)
 {
   enum rtx_code orig_code = code;
-  unsigned int count;
-  int signed_count;
+  rtx orig_varop = varop;
+  int count;
   enum machine_mode mode = result_mode;
   enum machine_mode shift_mode, tmode;
   unsigned int mode_words
@@ -8674,9 +8341,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
   /* We form (outer_op (code varop count) (outer_const)).  */
   enum rtx_code outer_op = UNKNOWN;
   HOST_WIDE_INT outer_const = 0;
-  rtx const_rtx;
   int complement_p = 0;
-  rtx new;
+  rtx new, x;
 
   /* Make sure and truncate the "natural" shift on the way in.  We don't
      want to do this inside the loop as it makes it more difficult to
@@ -8688,12 +8354,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
      what was requested.  */
 
   if (orig_count < 0 || orig_count >= (int) GET_MODE_BITSIZE (mode))
-    {
-      if (x)
-       return x;
-
-      return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (orig_count));
-    }
+    return NULL_RTX;
 
   count = orig_count;
 
@@ -8702,10 +8363,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   while (count != 0)
     {
-      /* If we have an operand of (clobber (const_int 0)), just return that
-        value.  */
+      /* If we have an operand of (clobber (const_int 0)), fail.  */
       if (GET_CODE (varop) == CLOBBER)
-       return varop;
+       return NULL_RTX;
 
       /* If we discovered we had to complement VAROP, leave.  Making a NOT
         here would cause an infinite loop.  */
@@ -8741,7 +8401,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
         multiple operations, each of which are defined, we know what the
         result is supposed to be.  */
 
-      if (count > (unsigned int) (GET_MODE_BITSIZE (shift_mode) - 1))
+      if (count > (GET_MODE_BITSIZE (shift_mode) - 1))
        {
          if (code == ASHIFTRT)
            count = GET_MODE_BITSIZE (shift_mode) - 1;
@@ -8915,7 +8575,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
             interpreted as the sign bit in a narrower mode, so, if
             the result is narrower, don't discard the shift.  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && (GET_MODE_BITSIZE (result_mode)
                  >= GET_MODE_BITSIZE (GET_MODE (varop))))
            {
@@ -8949,8 +8609,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
                 (ashiftrt:M1 (ashift:M1 (and:M1 (subreg:M1 FOO 0 C2) C3) C1).
                 This simplifies certain SIGN_EXTEND operations.  */
              if (code == ASHIFT && first_code == ASHIFTRT
-                 && count == (unsigned int)
-                             (GET_MODE_BITSIZE (result_mode)
+                 && count == (GET_MODE_BITSIZE (result_mode)
                               - GET_MODE_BITSIZE (GET_MODE (varop))))
                {
                  /* C3 has the low-order C1 bits zero.  */
@@ -8980,12 +8639,12 @@ simplify_shift_const (rtx x, enum rtx_code code,
                      > first_count))
                {
                  varop = XEXP (varop, 0);
-
-                 signed_count = count - first_count;
-                 if (signed_count < 0)
-                   count = -signed_count, code = ASHIFT;
-                 else
-                   count = signed_count;
+                 count -= first_count;
+                 if (count < 0)
+                   {
+                     count = -count;
+                     code = ASHIFT;
+                   }
 
                  continue;
                }
@@ -9033,8 +8692,8 @@ simplify_shift_const (rtx x, enum rtx_code code,
              mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
 
              mask_rtx
-               = simplify_binary_operation (code, result_mode, mask_rtx,
-                                            GEN_INT (count));
+               = simplify_const_binary_operation (code, result_mode, mask_rtx,
+                                                  GEN_INT (count));
 
              /* Give up if we can't compute an outer operation to use.  */
              if (mask_rtx == 0
@@ -9046,25 +8705,22 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
              /* If the shifts are in the same direction, we add the
                 counts.  Otherwise, we subtract them.  */
-             signed_count = count;
              if ((code == ASHIFTRT || code == LSHIFTRT)
                  == (first_code == ASHIFTRT || first_code == LSHIFTRT))
-               signed_count += first_count;
+               count += first_count;
              else
-               signed_count -= first_count;
+               count -= first_count;
 
              /* If COUNT is positive, the new shift is usually CODE,
                 except for the two exceptions below, in which case it is
                 FIRST_CODE.  If the count is negative, FIRST_CODE should
                 always be used  */
-             if (signed_count > 0
+             if (count > 0
                  && ((first_code == ROTATE && code == ASHIFT)
                      || (first_code == ASHIFTRT && code == LSHIFTRT)))
-               code = first_code, count = signed_count;
-             else if (signed_count < 0)
-               code = first_code, count = -signed_count;
-             else
-               count = signed_count;
+               code = first_code;
+             else if (count < 0)
+               code = first_code, count = -count;
 
              varop = XEXP (varop, 0);
              continue;
@@ -9075,12 +8731,12 @@ simplify_shift_const (rtx x, enum rtx_code code,
             B is not a constant.  */
 
          else if (GET_CODE (varop) == code
-                  && GET_CODE (XEXP (varop, 1)) != CONST_INT
-                  && 0 != (new
-                           = simplify_binary_operation (code, mode,
-                                                        XEXP (varop, 0),
-                                                        GEN_INT (count))))
+                  && GET_CODE (XEXP (varop, 0)) == CONST_INT
+                  && GET_CODE (XEXP (varop, 1)) != CONST_INT)
            {
+             rtx new = simplify_const_binary_operation (code, mode,
+                                                        XEXP (varop, 0),
+                                                        GEN_INT (count));
              varop = gen_rtx_fmt_ee (code, mode, new, XEXP (varop, 1));
              count = 0;
              continue;
@@ -9107,8 +8763,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && XEXP (XEXP (varop, 0), 1) == constm1_rtx
              && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
              && (code == LSHIFTRT || code == ASHIFTRT)
-             && count == (unsigned int)
-                         (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+             && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
@@ -9133,9 +8788,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
              && !(code == ASHIFTRT && GET_CODE (varop) == XOR
                   && 0 > trunc_int_for_mode (INTVAL (XEXP (varop, 1)),
                                              shift_mode))
-             && (new = simplify_binary_operation (code, result_mode,
-                                                  XEXP (varop, 1),
-                                                  GEN_INT (count))) != 0
+             && (new = simplify_const_binary_operation (code, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
              && GET_CODE (new) == CONST_INT
              && merge_outer_ops (&outer_op, &outer_const, GET_CODE (varop),
                                  INTVAL (new), result_mode, &complement_p))
@@ -9175,11 +8830,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
          if (code == LSHIFTRT
              && XEXP (varop, 1) == const0_rtx
              && GET_MODE (XEXP (varop, 0)) == result_mode
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
-             && ((STORE_FLAG_VALUE
-                  & ((HOST_WIDE_INT) 1
-                     < (GET_MODE_BITSIZE (result_mode) - 1))))
+             && STORE_FLAG_VALUE == -1
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
                                  (HOST_WIDE_INT) 1, result_mode,
@@ -9195,7 +8848,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
          /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
             than the number of bits in the mode is equivalent to A.  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1)
            {
              varop = XEXP (varop, 0);
@@ -9220,7 +8873,7 @@ simplify_shift_const (rtx x, enum rtx_code code,
             is one less than the number of bits in the mode is
             equivalent to (xor A 1).  */
          if (code == LSHIFTRT
-             && count == (unsigned int) (GET_MODE_BITSIZE (result_mode) - 1)
+             && count == (GET_MODE_BITSIZE (result_mode) - 1)
              && XEXP (varop, 1) == constm1_rtx
              && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
@@ -9263,10 +8916,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
          /* (ashift (plus foo C) N) is (plus (ashift foo N) C').  */
          if (code == ASHIFT
              && GET_CODE (XEXP (varop, 1)) == CONST_INT
-             && (new = simplify_binary_operation (ASHIFT, result_mode,
-                                                  XEXP (varop, 1),
-                                                  GEN_INT (count))) != 0
-             && GET_CODE (new) == CONST_INT
+             && (new = simplify_const_binary_operation (ASHIFT, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
              && merge_outer_ops (&outer_op, &outer_const, PLUS,
                                  INTVAL (new), result_mode, &complement_p))
            {
@@ -9282,10 +8934,9 @@ simplify_shift_const (rtx x, enum rtx_code code,
          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
+             && (new = simplify_const_binary_operation (code, result_mode,
+                                                        XEXP (varop, 1),
+                                                        GEN_INT (count))) != 0
              && merge_outer_ops (&outer_op, &outer_const, XOR,
                                  INTVAL (new), result_mode, &complement_p))
            {
@@ -9305,12 +8956,10 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
          if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
              && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
-             && count == (unsigned int)
-                         (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
+             && count == (GET_MODE_BITSIZE (GET_MODE (varop)) - 1)
              && (code == LSHIFTRT || code == ASHIFTRT)
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (XEXP (varop, 0), 1))
-                == count
+             && INTVAL (XEXP (XEXP (varop, 0), 1)) == count
              && rtx_equal_p (XEXP (XEXP (varop, 0), 0), XEXP (varop, 1)))
            {
              count = 0;
@@ -9367,44 +9016,31 @@ simplify_shift_const (rtx x, enum rtx_code code,
      a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places.  If
      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.
+     but we must turn off all bits turned off in the shift.  */
 
-     If we were passed a value for X, see if we can use any pieces of
-     it.  If not, make new rtx.  */
-
-  if (x && GET_RTX_CLASS (GET_CODE (x)) == RTX_BIN_ARITH
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == count)
-    const_rtx = XEXP (x, 1);
-  else
-    const_rtx = GEN_INT (count);
-
-  if (x && GET_CODE (XEXP (x, 0)) == SUBREG
-      && GET_MODE (XEXP (x, 0)) == shift_mode
-      && SUBREG_REG (XEXP (x, 0)) == varop)
-    varop = XEXP (x, 0);
-  else if (GET_MODE (varop) != shift_mode)
-    varop = gen_lowpart (shift_mode, varop);
-
-  /* If we can't make the SUBREG, try to return what we were given.  */
-  if (GET_CODE (varop) == CLOBBER)
-    return x ? x : varop;
+  if (outer_op == UNKNOWN
+      && orig_code == code && orig_count == count
+      && varop == orig_varop
+      && shift_mode == GET_MODE (varop))
+    return NULL_RTX;
 
-  new = simplify_binary_operation (code, shift_mode, varop, const_rtx);
-  if (new != 0)
-    x = new;
-  else
-    x = gen_rtx_fmt_ee (code, shift_mode, varop, const_rtx);
+  /* Make a SUBREG if necessary.  If we can't make it, fail.  */
+  varop = gen_lowpart (shift_mode, varop);
+  if (varop == NULL_RTX || GET_CODE (varop) == CLOBBER)
+    return NULL_RTX;
 
   /* If we have an outer operation and we just made a shift, it is
      possible that we could have simplified the shift were it not
      for the outer operation.  So try to do the simplification
      recursively.  */
 
-  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)));
+  if (outer_op != UNKNOWN)
+    x = simplify_shift_const_1 (code, shift_mode, varop, count);
+  else
+    x = NULL_RTX;
+
+  if (x == NULL_RTX)
+    x = simplify_gen_binary (code, shift_mode, varop, GEN_INT (count));
 
   /* If we were doing an LSHIFTRT in a wider mode than it was originally,
      turn off all the bits that the shift would have turned off.  */
@@ -9440,6 +9076,31 @@ simplify_shift_const (rtx x, enum rtx_code code,
 
   return x;
 }
+
+/* Simplify a shift of VAROP by COUNT bits.  CODE says what kind of shift.
+   The result of the shift is RESULT_MODE.  If we cannot simplify it,
+   return X or, if it is NULL, synthesize the expression with
+   simplify_gen_binary.  Otherwise, return a simplified value.
+
+   The shift is normally computed in the widest mode we find in VAROP, as
+   long as it isn't a different number of words than RESULT_MODE.  Exceptions
+   are ASHIFTRT and ROTATE, which are always done in their original mode.  */
+
+static rtx
+simplify_shift_const (rtx x, enum rtx_code code, enum machine_mode result_mode,
+                     rtx varop, int count)
+{
+  rtx tem = simplify_shift_const_1 (code, result_mode, varop, count);
+  if (tem)
+    return tem;
+
+  if (!x)
+    x = simplify_gen_binary (code, GET_MODE (varop), varop, GEN_INT (count));
+  if (GET_MODE (x) != result_mode)
+    x = gen_lowpart (result_mode, x);
+  return x;
+}
+
 \f
 /* Like recog, but we receive the address of a pointer to a new pattern.
    We try to match the rtx that the pointer points to.
@@ -10047,7 +9708,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
        op0 = force_to_mode (op0, mode,
                             ((HOST_WIDE_INT) 1
                              << (GET_MODE_BITSIZE (mode) - 1)),
-                            NULL_RTX, 0);
+                            0);
 
       /* Now try cases based on the opcode of OP0.  If none of the cases
         does a "continue", we exit this loop immediately after the
@@ -10444,9 +10105,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
              && XEXP (XEXP (op0, 0), 0) == const1_rtx)
            {
              op0 = simplify_and_const_int
-               (op0, mode, gen_rtx_LSHIFTRT (mode,
-                                             XEXP (op0, 1),
-                                             XEXP (XEXP (op0, 0), 1)),
+               (NULL_RTX, mode, gen_rtx_LSHIFTRT (mode,
+                                                  XEXP (op0, 1),
+                                                  XEXP (XEXP (op0, 0), 1)),
                 (HOST_WIDE_INT) 1);
              continue;
            }