OSDN Git Service

(fold_convert): Add new arg to REAL_VALUE_FROM_INT.
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 2b5c065..d494f64 100644 (file)
@@ -1,5 +1,5 @@
 /* Fold a constant sub-tree into a single node for C-compiler
-   Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /*@@ This file should be rewritten to use an arbitrary precision
   @@ representation for "struct tree_int_cst" and "struct tree_real_cst".
@@ -70,12 +71,12 @@ static tree optimize_bit_field_compare PROTO((enum tree_code, tree,
                                              tree, tree));
 static tree decode_field_reference PROTO((tree, int *, int *,
                                          enum machine_mode *, int *,
-                                         int *, tree *));
+                                         int *, tree *, tree *));
 static int all_ones_mask_p PROTO((tree, int));
 static int simple_operand_p PROTO((tree));
 static tree range_test PROTO((enum tree_code, tree, enum tree_code,
                               enum tree_code, tree, tree, tree));
-static tree unextend   PROTO((tree, int, int));
+static tree unextend   PROTO((tree, int, int, tree));
 static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
 static tree strip_compound_expr PROTO((tree, tree));
 
@@ -83,9 +84,6 @@ static tree strip_compound_expr PROTO((tree, tree));
 #define BRANCH_COST 1
 #endif
 
-/* Yield nonzero if a signed left shift of A by B bits overflows.  */
-#define left_shift_overflows(a, b)  ((a)  !=  ((a) << (b)) >> (b))
-
 /* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow.
    Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1.
    Then this yields nonzero if overflow occurred during the addition.
@@ -337,8 +335,10 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
       return;
     }
   
-  if (count >= prec)
-    count = (unsigned HOST_WIDE_INT) count & prec;
+#ifdef SHIFT_COUNT_TRUNCATED
+  if (SHIFT_COUNT_TRUNCATED)
+    count %= prec;
+#endif
 
   if (count >= HOST_BITS_PER_WIDE_INT)
     {
@@ -370,8 +370,10 @@ rshift_double (l1, h1, count, prec, lv, hv, arith)
              ? -((unsigned HOST_WIDE_INT) h1 >> (HOST_BITS_PER_WIDE_INT - 1))
              : 0);
 
-  if (count >= prec)
-    count = (unsigned HOST_WIDE_INT) count % prec;
+#ifdef SHIFT_COUNT_TRUNCATED
+  if (SHIFT_COUNT_TRUNCATED)
+    count %= prec;
+#endif
 
   if (count >= HOST_BITS_PER_WIDE_INT)
     {
@@ -399,34 +401,16 @@ lrotate_double (l1, h1, count, prec, lv, hv)
      int prec;
      HOST_WIDE_INT *lv, *hv;
 {
-  HOST_WIDE_INT arg1[4];
-  register int i;
-  register int carry;
+  HOST_WIDE_INT s1l, s1h, s2l, s2h;
 
+  count %= prec;
   if (count < 0)
-    {
-      rrotate_double (l1, h1, - count, prec, lv, hv);
-      return;
-    }
-
-  encode (arg1, l1, h1);
-
-  if (count > prec)
-    count = prec;
-
-  carry = arg1[4 - 1] >> 16 - 1;
-  while (count > 0)
-    {
-      for (i = 0; i < 4; i++)
-       {
-         carry += arg1[i] << 1;
-         arg1[i] = LOWPART (carry);
-         carry = HIGHPART (carry);
-       }
-      count--;
-    }
+    count += prec;
 
-  decode (arg1, lv, hv);
+  lshift_double (l1, h1, count, prec, &s1l, &s1h, 0);
+  rshift_double (l1, h1, prec - count, prec, &s2l, &s2h, 0);
+  *lv = s1l | s2l;
+  *hv = s1h | s2h;
 }
 
 /* Rotate the doubleword integer in L1, H1 left by COUNT places
@@ -439,28 +423,16 @@ rrotate_double (l1, h1, count, prec, lv, hv)
      int prec;
      HOST_WIDE_INT *lv, *hv;
 {
-  HOST_WIDE_INT arg1[4];
-  register int i;
-  register int carry;
-
-  encode (arg1, l1, h1);
-
-  if (count > prec)
-    count = prec;
+  HOST_WIDE_INT s1l, s1h, s2l, s2h;
 
-  carry = arg1[0] & 1;
-  while (count > 0)
-    {
-      for (i = 4 - 1; i >= 0; i--)
-       {
-         carry *= BASE;
-         carry += arg1[i];
-         arg1[i] = LOWPART (carry >> 1);
-       }
-      count--;
-    }
+  count %= prec;
+  if (count < 0)
+    count += prec;
 
-  decode (arg1, lv, hv);
+  rshift_double (l1, h1, count, prec, &s1l, &s1h, 0);
+  lshift_double (l1, h1, prec - count, prec, &s2l, &s2h, 0);
+  *lv = s1l | s2l;
+  *hv = s1h | s2h;
 }
 \f
 /* Divide doubleword integer LNUM, HNUM by doubleword integer LDEN, HDEN
@@ -487,7 +459,7 @@ div_and_round_double (code, uns,
   HOST_WIDE_INT den[4], quo[4];
   register int i, j;
   unsigned HOST_WIDE_INT work;
-  register int carry = 0;
+  register unsigned HOST_WIDE_INT carry = 0;
   HOST_WIDE_INT lnum = lnum_orig;
   HOST_WIDE_INT hnum = hnum_orig;
   HOST_WIDE_INT lden = lden_orig;
@@ -554,7 +526,8 @@ div_and_round_double (code, uns,
     {
       /* Full double precision division,
         with thanks to Don Knuth's "Seminumerical Algorithms".  */
-    int quo_est, scale, num_hi_sig, den_hi_sig;
+    int num_hi_sig, den_hi_sig;
+    unsigned HOST_WIDE_INT quo_est, scale;
 
     /* Find the highest non-zero divisor digit.  */
     for (i = 4 - 1; ; i--)
@@ -990,6 +963,8 @@ const_binop (code, arg1, arg2, notrunc)
      register tree arg1, arg2;
      int notrunc;
 {
+  STRIP_NOPS (arg1); STRIP_NOPS (arg2);
+
   if (TREE_CODE (arg1) == INTEGER_CST)
     {
       register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1);
@@ -1163,7 +1138,7 @@ const_binop (code, arg1, arg2, notrunc)
     got_it:
       TREE_TYPE (t) = TREE_TYPE (arg1);
       TREE_OVERFLOW (t)
-       = ((notrunc ? !uns && overflow : force_fit_type (t, overflow))
+       = ((notrunc ? !uns && overflow : force_fit_type (t, overflow && !uns))
           | TREE_OVERFLOW (arg1)
           | TREE_OVERFLOW (arg2));
       TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
@@ -1382,7 +1357,7 @@ size_binop (code, arg0, arg1)
          && TREE_INT_CST_HIGH (arg0) == 0)
        return arg1;
       /* Handle general case of two integer constants.  */
-      return const_binop (code, arg0, arg1, 1);
+      return const_binop (code, arg0, arg1, 0);
     }
 
   if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -1437,10 +1412,11 @@ fold_convert (t, arg1)
          REAL_VALUE_TYPE x;
          REAL_VALUE_TYPE l;
          REAL_VALUE_TYPE u;
+         tree type1 = TREE_TYPE (arg1);
 
          x = TREE_REAL_CST (arg1);
-         l = real_value_from_int_cst (TYPE_MIN_VALUE (type));
-         u = real_value_from_int_cst (TYPE_MAX_VALUE (type));
+         l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
+         u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
          /* See if X will be in range after truncation towards 0.
             To compensate for truncation, move the bounds away from 0,
             but reject if X exactly equals the adjusted bounds.  */
@@ -1505,7 +1481,11 @@ fold_convert (t, arg1)
       if (TREE_CODE (arg1) == REAL_CST)
        {
          if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
-           return arg1;
+           {
+             t = arg1;
+             TREE_TYPE (arg1) = type;
+             return t;
+           }
          else if (setjmp (float_error))
            {
              overflow = 1;
@@ -1771,7 +1751,8 @@ operand_equal_for_comparison_p (arg0, arg1, other)
   if (operand_equal_p (arg0, arg1, 0))
     return 1;
 
-  if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
+  if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+      || ! INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
     return 0;
 
   /* Duplicate what shorten_compare does to ARG1 and see if that gives the
@@ -2117,6 +2098,10 @@ invert_truthvalue (arg)
 
     case SAVE_EXPR:
       return build1 (TRUTH_NOT_EXPR, type, arg);
+
+    case CLEANUP_POINT_EXPR:
+      return build1 (CLEANUP_POINT_EXPR, type,
+                    invert_truthvalue (TREE_OPERAND (arg, 0)));
     }
   if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE)
     abort ();
@@ -2402,17 +2387,20 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
    *PMASK is set to the mask used.  This is either contained in a
    BIT_AND_EXPR or derived from the width of the field.
 
+   *PAND_MASK is set the the mask found in a BIT_AND_EXPR, if any.
+
    Return 0 if this is not a component reference or is one that we can't
    do anything with.  */
 
 static tree
 decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
-                       pvolatilep, pmask)
+                       pvolatilep, pmask, pand_mask)
      tree exp;
      int *pbitsize, *pbitpos;
      enum machine_mode *pmode;
      int *punsignedp, *pvolatilep;
      tree *pmask;
+     tree *pand_mask;
 {
   tree and_mask = 0;
   tree mask, inner, offset;
@@ -2459,6 +2447,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
                        convert (unsigned_type, and_mask), mask));
 
   *pmask = mask;
+  *pand_mask = and_mask;
   return inner;
 }
 
@@ -2640,14 +2629,16 @@ range_test (jcode, type, lo_code, hi_code, var, lo_cst, hi_cst)
 }
 \f
 /* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
-   bit value.  Arrange things so the extra bits will be set to zero if and]
-   only if C is signed-extended to its full width.  */
+   bit value.  Arrange things so the extra bits will be set to zero if and
+   only if C is signed-extended to its full width.  If MASK is nonzero,
+   it is an INTEGER_CST that should be AND'ed with the extra bits.  */
 
 static tree
-unextend (c, p, unsignedp)
+unextend (c, p, unsignedp, mask)
      tree c;
      int p;
      int unsignedp;
+     tree mask;
 {
   tree type = TREE_TYPE (c);
   int modesize = GET_MODE_BITSIZE (TYPE_MODE (type));
@@ -2660,12 +2651,15 @@ unextend (c, p, unsignedp)
     c = convert (signed_type (type), c);
 
   /* We work by getting just the sign bit into the low-order bit, then
-     into the high-order bit, then sign-extened.  We then XOR that value
+     into the high-order bit, then sign-extend.  We then XOR that value
      with C.  */
   temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0);
   temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
   temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0);
   temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0);
+  if (mask != 0)
+    temp = const_binop (BIT_AND_EXPR, temp, convert (TREE_TYPE (c), mask), 0);
+
   return convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
 }
 \f
@@ -2719,6 +2713,7 @@ fold_truthop (code, truth_type, lhs, rhs)
   enum machine_mode ll_mode, lr_mode, rl_mode, rr_mode;
   enum machine_mode lnmode, rnmode;
   tree ll_mask, lr_mask, rl_mask, rr_mask;
+  tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask;
   tree l_const, r_const;
   tree type, result;
   int first_bit, end_bit;
@@ -2808,16 +2803,20 @@ fold_truthop (code, truth_type, lhs, rhs)
   volatilep = 0;
   ll_inner = decode_field_reference (ll_arg,
                                     &ll_bitsize, &ll_bitpos, &ll_mode,
-                                    &ll_unsignedp, &volatilep, &ll_mask);
+                                    &ll_unsignedp, &volatilep, &ll_mask,
+                                    &ll_and_mask);
   lr_inner = decode_field_reference (lr_arg,
                                     &lr_bitsize, &lr_bitpos, &lr_mode,
-                                    &lr_unsignedp, &volatilep, &lr_mask);
+                                    &lr_unsignedp, &volatilep, &lr_mask,
+                                    &lr_and_mask);
   rl_inner = decode_field_reference (rl_arg,
                                     &rl_bitsize, &rl_bitpos, &rl_mode,
-                                    &rl_unsignedp, &volatilep, &rl_mask);
+                                    &rl_unsignedp, &volatilep, &rl_mask,
+                                    &rl_and_mask);
   rr_inner = decode_field_reference (rr_arg,
                                     &rr_bitsize, &rr_bitpos, &rr_mode,
-                                    &rr_unsignedp, &volatilep, &rr_mask);
+                                    &rr_unsignedp, &volatilep, &rr_mask,
+                                    &rr_and_mask);
 
   /* It must be true that the inner operation on the lhs of each
      comparison must be the same if we are to be able to do anything.
@@ -2886,7 +2885,8 @@ fold_truthop (code, truth_type, lhs, rhs)
 
   if (l_const)
     {
-      l_const = convert (type, unextend (l_const, ll_bitsize, ll_unsignedp));
+      l_const = convert (type, l_const);
+      l_const = unextend (l_const,  ll_bitsize, ll_unsignedp, ll_and_mask);
       l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const,
                                        fold (build1 (BIT_NOT_EXPR,
@@ -2903,7 +2903,8 @@ fold_truthop (code, truth_type, lhs, rhs)
     }
   if (r_const)
     {
-      r_const = convert (type, unextend (r_const, rl_bitsize, rl_unsignedp));
+      r_const = convert (type, r_const);
+      r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask);
       r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const,
                                        fold (build1 (BIT_NOT_EXPR,
@@ -3295,9 +3296,10 @@ fold (expr)
            }
          else
            {
+             tree testtype = TREE_TYPE (arg1);
              test = arg1;
-             true_value = integer_one_node;
-             false_value = integer_zero_node;
+             true_value = convert (testtype, integer_one_node);
+             false_value = convert (testtype, integer_zero_node);
            }
 
          /* If ARG0 is complex we want to make sure we only evaluate
@@ -3306,7 +3308,7 @@ fold (expr)
             succeed in folding one part to a constant, we do not need
             to make this SAVE_EXPR.  Since we do this optimization
             primarily to see if we do end up with constant and this
-            SAVE_EXPR interfers with later optimizations, suppressing
+            SAVE_EXPR interferes with later optimizations, suppressing
             it when we can is important.  */
 
          if (TREE_CODE (arg0) != SAVE_EXPR
@@ -3350,9 +3352,10 @@ fold (expr)
            }
          else
            {
+             tree testtype = TREE_TYPE (arg0);
              test = arg0;
-             true_value = integer_one_node;
-             false_value = integer_zero_node;
+             true_value = convert (testtype, integer_one_node);
+             false_value = convert (testtype, integer_zero_node);
            }
 
          if (TREE_CODE (arg1) != SAVE_EXPR
@@ -3447,11 +3450,14 @@ fold (expr)
             float or both integer, we don't need the middle conversion if
             it is wider than the final type and doesn't change the signedness
             (for integers).  Avoid this if the final type is a pointer
-            since then we sometimes need the inner conversion.  */
+            since then we sometimes need the inner conversion.  Likewise if
+            the outer has a precision not equal to the size of its mode.  */
          if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
               || (inter_float && inside_float))
              && inter_prec >= inside_prec
              && (inter_float || inter_unsignedp == inside_unsignedp)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
+                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
              && ! final_ptr)
            return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 
@@ -3473,7 +3479,10 @@ fold (expr)
              && ((inter_unsignedp && inter_prec > inside_prec)
                  == (final_unsignedp && final_prec > inter_prec))
              && ! (inside_ptr && inter_prec != final_prec)
-             && ! (final_ptr && inside_prec != inter_prec))
+             && ! (final_ptr && inside_prec != inter_prec)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
+                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
+             && ! final_ptr)
            return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
        }
 
@@ -3544,7 +3553,7 @@ fold (expr)
              TREE_TYPE (t) = type;
              TREE_OVERFLOW (t)
                = (TREE_OVERFLOW (arg0)
-                  | force_fit_type (t, overflow));
+                  | force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
              TREE_CONSTANT_OVERFLOW (t)
                = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
            }
@@ -3893,6 +3902,9 @@ fold (expr)
 
     case BIT_IOR_EXPR:
     bit_ior:
+      {
+      register enum tree_code code0, code1;
+
       if (integer_all_onesp (arg1))
        return omit_one_operand (type, arg1, arg0);
       if (integer_zerop (arg1))
@@ -3901,28 +3913,53 @@ fold (expr)
       if (t1 != NULL_TREE)
        return t1;
 
-      /* (a << C1) | (a >> C2) if A is unsigned and C1+C2 is the size of A
+      /* (A << C1) | (A >> C2) if A is unsigned and C1+C2 is the size of A
         is a rotate of A by C1 bits.  */
+      /* (A << B) | (A >> (Z - B)) if A is unsigned and Z is the size of A
+        is a rotate of A by B bits.  */
 
-      if ((TREE_CODE (arg0) == RSHIFT_EXPR
-          || TREE_CODE (arg0) == LSHIFT_EXPR)
-         && (TREE_CODE (arg1) == RSHIFT_EXPR
-             || TREE_CODE (arg1) == LSHIFT_EXPR)
-         && TREE_CODE (arg0) != TREE_CODE (arg1)
+      code0 = TREE_CODE (arg0);
+      code1 = TREE_CODE (arg1);
+      if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
+         || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
          && operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1,0), 0)
-         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
-         && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
-         && TREE_INT_CST_HIGH (TREE_OPERAND (arg1, 1)) == 0
-         && ((TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
-              + TREE_INT_CST_LOW (TREE_OPERAND (arg1, 1)))
+         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+       {
+         register tree tree01, tree11;
+         register enum tree_code code01, code11;
+
+         tree01 = TREE_OPERAND (arg0, 1);
+         tree11 = TREE_OPERAND (arg1, 1);
+         code01 = TREE_CODE (tree01);
+         code11 = TREE_CODE (tree11);
+         if (code01 == INTEGER_CST
+           && code11 == INTEGER_CST
+           && TREE_INT_CST_HIGH (tree01) == 0
+           && TREE_INT_CST_HIGH (tree11) == 0
+           && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
              == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
-       return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
-                     TREE_CODE (arg0) == LSHIFT_EXPR
-                     ? TREE_OPERAND (arg0, 1) : TREE_OPERAND (arg1, 1));
+           return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
+                     code0 == LSHIFT_EXPR ? tree01 : tree11);
+         else if (code11 == MINUS_EXPR
+               && TREE_CODE (TREE_OPERAND (tree11, 0)) == INTEGER_CST
+               && TREE_INT_CST_HIGH (TREE_OPERAND (tree11, 0)) == 0
+               && TREE_INT_CST_LOW (TREE_OPERAND (tree11, 0))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+               && operand_equal_p (tree01, TREE_OPERAND (tree11, 1), 0))
+           return build (code0 == LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+                       type, TREE_OPERAND (arg0, 0), tree01);
+         else if (code01 == MINUS_EXPR
+               && TREE_CODE (TREE_OPERAND (tree01, 0)) == INTEGER_CST
+               && TREE_INT_CST_HIGH (TREE_OPERAND (tree01, 0)) == 0
+               && TREE_INT_CST_LOW (TREE_OPERAND (tree01, 0))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+               && operand_equal_p (tree11, TREE_OPERAND (tree01, 1), 0))
+           return build (code0 != LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+                       type, TREE_OPERAND (arg0, 0), tree11);
+       }
 
       goto associate;
+      }
 
     case BIT_XOR_EXPR:
       if (integer_zerop (arg1))
@@ -4043,7 +4080,7 @@ fold (expr)
          tree c2 = integer_zero_node;
          tree xarg0 = arg0;
 
-         if (TREE_CODE (xarg0) == SAVE_EXPR)
+         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
            have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
 
          STRIP_NOPS (xarg0);
@@ -4061,7 +4098,7 @@ fold (expr)
              xarg0 = TREE_OPERAND (xarg0, 0);
            }
 
-         if (TREE_CODE (xarg0) == SAVE_EXPR)
+         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
            have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
 
          STRIP_NOPS (xarg0);
@@ -4158,8 +4195,51 @@ fold (expr)
        return non_lvalue (convert (type, arg0));
       /* Since negative shift count is not well-defined,
         don't try to compute it in the compiler.  */
-      if (tree_int_cst_sgn (arg1) < 0)
+      if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_sgn (arg1) < 0)
        return t;
+      /* Rewrite an LROTATE_EXPR by a constant into an
+        RROTATE_EXPR by a new constant.  */
+      if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
+       {
+         TREE_SET_CODE (t, RROTATE_EXPR);
+         code = RROTATE_EXPR;
+         TREE_OPERAND (t, 1) = arg1
+           = const_binop
+             (MINUS_EXPR,
+              convert (TREE_TYPE (arg1),
+                       build_int_2 (GET_MODE_BITSIZE (TYPE_MODE (type)), 0)),
+              arg1, 0);
+         if (tree_int_cst_sgn (arg1) < 0)
+           return t;
+       }
+
+      /* If we have a rotate of a bit operation with the rotate count and
+        the second operand of the bit operation both constant,
+        permute the two operations.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+         && (TREE_CODE (arg0) == BIT_AND_EXPR
+             || TREE_CODE (arg0) == BIT_ANDTC_EXPR
+             || TREE_CODE (arg0) == BIT_IOR_EXPR
+             || TREE_CODE (arg0) == BIT_XOR_EXPR)
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+       return fold (build (TREE_CODE (arg0), type,
+                           fold (build (code, type,
+                                        TREE_OPERAND (arg0, 0), arg1)),
+                           fold (build (code, type,
+                                        TREE_OPERAND (arg0, 1), arg1))));
+
+      /* Two consecutive rotates adding up to the width of the mode can
+        be ignored.  */
+      if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
+         && TREE_CODE (arg0) == RROTATE_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
+         && TREE_INT_CST_HIGH (arg1) == 0
+         && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
+         && ((TREE_INT_CST_LOW (arg1)
+              + TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1)))
+             == GET_MODE_BITSIZE (TYPE_MODE (type))))
+       return TREE_OPERAND (arg0, 0);
+
       goto binary;
 
     case MIN_EXPR:
@@ -4183,7 +4263,11 @@ fold (expr)
         and its values must be 0 or 1.
         ("true" is a fixed value perhaps depending on the language,
         but we don't handle values other than 1 correctly yet.)  */
-      return invert_truthvalue (arg0);
+      tem = invert_truthvalue (arg0);
+      /* Avoid infinite recursion.  */
+      if (TREE_CODE (tem) == TRUTH_NOT_EXPR)
+       return t;
+      return convert (type, tem);
 
     case TRUTH_ANDIF_EXPR:
       /* Note that the operands of this must be ints
@@ -4826,12 +4910,16 @@ fold (expr)
              case GE_EXPR:
              case GT_EXPR:
                return pedantic_non_lvalue
-                 (fold (build1 (ABS_EXPR, type, arg1)));
+                 (convert (type, fold (build1 (ABS_EXPR,
+                                               TREE_TYPE (arg1), arg1))));
              case LE_EXPR:
              case LT_EXPR:
                return pedantic_non_lvalue
                  (fold (build1 (NEGATE_EXPR, type,
-                                fold (build1 (ABS_EXPR, type, arg1)))));
+                                convert (type,
+                                         fold (build1 (ABS_EXPR,
+                                                       TREE_TYPE (arg1),
+                                                       arg1))))));
              }
 
          /* If this is A != 0 ? A : 0, this is simply A.  For ==, it is
@@ -5032,7 +5120,7 @@ fold (expr)
          appropriate.  */
     case CLEANUP_POINT_EXPR:
       if (! TREE_SIDE_EFFECTS (arg0))
-       return arg0;
+       return convert (type, arg0);
 
       {
        enum tree_code code0 = TREE_CODE (arg0);
@@ -5040,16 +5128,29 @@ fold (expr)
        tree arg00 = TREE_OPERAND (arg0, 0);
        tree arg01;
 
-       if (kind0 == '1')
+       if (kind0 == '1' || code0 == TRUTH_NOT_EXPR)
          return fold (build1 (code0, type, 
                               fold (build1 (CLEANUP_POINT_EXPR,
                                             TREE_TYPE (arg00), arg00))));
-       if ((kind0 == '<' || kind0 == '2')
-           && ! TREE_SIDE_EFFECTS (arg01 = TREE_OPERAND (arg0, 1)))
-         return fold (build (code0, type,
-                             fold (build1 (CLEANUP_POINT_EXPR,
-                                           TREE_TYPE (arg00), arg00)),
-                             arg01));
+
+       if (kind0 == '<' || kind0 == '2'
+           || code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR
+           || code0 == TRUTH_AND_EXPR   || code0 == TRUTH_OR_EXPR
+           || code0 == TRUTH_XOR_EXPR)
+         {
+           arg01 = TREE_OPERAND (arg0, 1);
+
+           if (! TREE_SIDE_EFFECTS (arg00))
+             return fold (build (code0, type, arg00,
+                                 fold (build1 (CLEANUP_POINT_EXPR,
+                                               TREE_TYPE (arg01), arg01))));
+
+           if (! TREE_SIDE_EFFECTS (arg01))
+             return fold (build (code0, type,
+                                 fold (build1 (CLEANUP_POINT_EXPR,
+                                               TREE_TYPE (arg00), arg00)),
+                                 arg01));
+         }
 
        return t;
       }