OSDN Git Service

(operand_equal_p): Constants are not equal if there has been an overflow.
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 1ddfd47..84e098a 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, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -1072,23 +1072,24 @@ const_binop (code, arg1, arg2, notrunc)
       register tree t;
       int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
       int overflow = 0;
+      int no_overflow = 0;
 
       switch (code)
        {
        case BIT_IOR_EXPR:
-         t = build_int_2 (int1l | int2l, int1h | int2h);
+         low = int1l | int2l, hi = int1h | int2h;
          break;
 
        case BIT_XOR_EXPR:
-         t = build_int_2 (int1l ^ int2l, int1h ^ int2h);
+         low = int1l ^ int2l, hi = int1h ^ int2h;
          break;
 
        case BIT_AND_EXPR:
-         t = build_int_2 (int1l & int2l, int1h & int2h);
+         low = int1l & int2l, hi = int1h & int2h;
          break;
 
        case BIT_ANDTC_EXPR:
-         t = build_int_2 (int1l & ~int2l, int1h & ~int2h);
+         low = int1l & ~int2l, hi = int1h & ~int2h;
          break;
 
        case RSHIFT_EXPR:
@@ -1101,14 +1102,8 @@ const_binop (code, arg1, arg2, notrunc)
                         TYPE_PRECISION (TREE_TYPE (arg1)),
                         &low, &hi,
                         !uns);
-         t = build_int_2 (low, hi);
-         TREE_TYPE (t) = TREE_TYPE (arg1);
-         if (!notrunc)
-           force_fit_type (t, 0);
-         TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
-         TREE_CONSTANT_OVERFLOW (t)
-           = TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2);
-         return t;
+         no_overflow = 1;
+         break;
 
        case RROTATE_EXPR:
          int2l = - int2l;
@@ -1116,94 +1111,76 @@ const_binop (code, arg1, arg2, notrunc)
          lrotate_double (int1l, int1h, int2l,
                          TYPE_PRECISION (TREE_TYPE (arg1)),
                          &low, &hi);
-         t = build_int_2 (low, hi);
          break;
 
        case PLUS_EXPR:
-         if (int1h == 0)
-           {
-             int2l += int1l;
-             if ((unsigned HOST_WIDE_INT) int2l < int1l)
-               {
-                 hi = int2h++;
-                 overflow = int2h < hi;
-               }
-             t = build_int_2 (int2l, int2h);
-             break;
-           }
-         if (int2h == 0)
-           {
-             int1l += int2l;
-             if ((unsigned HOST_WIDE_INT) int1l < int2l)
-               {
-                 hi = int1h++;
-                 overflow = int1h < hi;
-               }
-             t = build_int_2 (int1l, int1h);
-             break;
-           }
          overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
-         t = build_int_2 (low, hi);
          break;
 
        case MINUS_EXPR:
-         if (int2h == 0 && int2l == 0)
-           {
-             t = build_int_2 (int1l, int1h);
-             break;
-           }
          neg_double (int2l, int2h, &low, &hi);
          add_double (int1l, int1h, low, hi, &low, &hi);
          overflow = overflow_sum_sign (hi, int2h, int1h);
-         t = build_int_2 (low, hi);
          break;
 
        case MULT_EXPR:
          overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
-         t = build_int_2 (low, hi);
          break;
 
        case TRUNC_DIV_EXPR:
        case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
        case EXACT_DIV_EXPR:
-         /* This is a shortcut for a common special case.
-            It reduces the number of tree nodes generated
-            and saves time.  */
+         /* This is a shortcut for a common special case.  */
          if (int2h == 0 && int2l > 0
-             && TREE_TYPE (arg1) == sizetype
              && ! TREE_CONSTANT_OVERFLOW (arg1)
              && ! TREE_CONSTANT_OVERFLOW (arg2)
              && int1h == 0 && int1l >= 0)
            {
              if (code == CEIL_DIV_EXPR)
-               int1l += int2l-1;
-             return size_int (int1l / int2l);
+               int1l += int2l - 1;
+             low = int1l / int2l, hi = 0;
+             break;
            }
+
+         /* ... fall through ... */
+
        case ROUND_DIV_EXPR: 
          if (int2h == 0 && int2l == 1)
            {
-             t = build_int_2 (int1l, int1h);
+             low = int1l, hi = int1h;
              break;
            }
-         if (int1l == int2l && int1h == int2h)
+         if (int1l == int2l && int1h == int2h
+             && ! (int1l == 0 && int1h == 0))
            {
-             if ((int1l | int1h) == 0)
-               abort ();
-             t = build_int_2 (1, 0);
+             low = 1, hi = 0;
              break;
            }
          overflow = div_and_round_double (code, uns,
                                           int1l, int1h, int2l, int2h,
                                           &low, &hi, &garbagel, &garbageh);
-         t = build_int_2 (low, hi);
          break;
 
-       case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR: 
+       case TRUNC_MOD_EXPR:
        case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
+         /* This is a shortcut for a common special case.  */
+         if (int2h == 0 && int2l > 0
+             && ! TREE_CONSTANT_OVERFLOW (arg1)
+             && ! TREE_CONSTANT_OVERFLOW (arg2)
+             && int1h == 0 && int1l >= 0)
+           {
+             if (code == CEIL_MOD_EXPR)
+               int1l += int2l - 1;
+             low = int1l % int2l, hi = 0;
+             break;
+           }
+
+         /* ... fall through ... */
+
+       case ROUND_MOD_EXPR: 
          overflow = div_and_round_double (code, uns,
                                           int1l, int1h, int2l, int2h,
                                           &garbagel, &garbageh, &low, &hi);
-         t = build_int_2 (low, hi);
          break;
 
        case MIN_EXPR:
@@ -1225,18 +1202,29 @@ const_binop (code, arg1, arg2, notrunc)
                             < (unsigned HOST_WIDE_INT) int2l)));
            }
          if (low == (code == MIN_EXPR))
-           t = build_int_2 (int1l, int1h);
+           low = int1l, hi = int1h;
          else
-           t = build_int_2 (int2l, int2h);
+           low = int2l, hi = int2h;
          break;
 
        default:
          abort ();
        }
     got_it:
-      TREE_TYPE (t) = TREE_TYPE (arg1);
+      if (TREE_TYPE (arg1) == sizetype && hi == 0
+         && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype))
+         && ! overflow
+         && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
+       t = size_int (low);
+      else
+       {
+         t = build_int_2 (low, hi);
+         TREE_TYPE (t) = TREE_TYPE (arg1);
+       }
+
       TREE_OVERFLOW (t)
-       = ((notrunc ? !uns && overflow : force_fit_type (t, overflow && !uns))
+       = ((notrunc ? !uns && overflow
+           : force_fit_type (t, overflow && !uns) && ! no_overflow)
           | TREE_OVERFLOW (arg1)
           | TREE_OVERFLOW (arg2));
       TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
@@ -1430,6 +1418,7 @@ size_int (number)
     {
       t = build_int_2 (number, 0);
       TREE_TYPE (t) = sizetype;
+      TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
     }
   return t;
 }
@@ -1746,46 +1735,61 @@ operand_equal_p (arg0, arg1, only_const)
   STRIP_NOPS (arg0);
   STRIP_NOPS (arg1);
 
-  /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
-     We don't care about side effects in that case because the SAVE_EXPR
-     takes care of that for us.  */
-  if (TREE_CODE (arg0) == SAVE_EXPR && arg0 == arg1)
-    return ! only_const;
-
-  if (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))
+  if (TREE_CODE (arg0) != TREE_CODE (arg1)
+      /* This is needed for conversions and for COMPONENT_REF.
+        Might as well play it safe and always test this.  */
+      || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))
     return 0;
 
-  if (TREE_CODE (arg0) == TREE_CODE (arg1)
-      && TREE_CODE (arg0) == ADDR_EXPR
-      && TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0))
-    return 1;
-
-  if (TREE_CODE (arg0) == TREE_CODE (arg1)
-      && TREE_CODE (arg0) == INTEGER_CST
-      && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
-      && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1))
+  /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
+     We don't care about side effects in that case because the SAVE_EXPR
+     takes care of that for us. In all other cases, two expressions are
+     equal if they have no side effects.  If we have two identical
+     expressions with side effects that should be treated the same due
+     to the only side effects being identical SAVE_EXPR's, that will
+     be detected in the recursive calls below.  */
+  if (arg0 == arg1 && ! only_const
+      && (TREE_CODE (arg0) == SAVE_EXPR
+         || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
     return 1;
 
-  /* Detect when real constants are equal.  */
-  if (TREE_CODE (arg0) == TREE_CODE (arg1)
-      && TREE_CODE (arg0) == REAL_CST)
-    return !bcmp ((char *) &TREE_REAL_CST (arg0),
-                 (char *) &TREE_REAL_CST (arg1),
-                 sizeof (REAL_VALUE_TYPE));
+  /* Next handle constant cases, those for which we can return 1 even
+     if ONLY_CONST is set.  */
+  if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1))
+    switch (TREE_CODE (arg0))
+      {
+      case INTEGER_CST:
+       return (! TREE_CONSTANT_OVERFLOW (arg0)
+               && ! TREE_CONSTANT_OVERFLOW (arg1)
+               && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
+               && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1));
+
+      case REAL_CST:
+       return (! TREE_CONSTANT_OVERFLOW (arg0)
+               && ! TREE_CONSTANT_OVERFLOW (arg1)
+               && REAL_VALUES_EQUAL (TREE_REAL_CST (arg0),
+                                     TREE_REAL_CST (arg1)));
+
+      case COMPLEX_CST:
+       return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1),
+                                only_const)
+               && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1),
+                                   only_const));
+
+      case STRING_CST:
+       return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1)
+               && ! strncmp (TREE_STRING_POINTER (arg0),
+                             TREE_STRING_POINTER (arg1),
+                             TREE_STRING_LENGTH (arg0)));
+
+      case ADDR_EXPR:
+       return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
+                               0);
+      }
 
   if (only_const)
     return 0;
 
-  if (arg0 == arg1)
-    return 1;
-
-  if (TREE_CODE (arg0) != TREE_CODE (arg1))
-    return 0;
-  /* This is needed for conversions and for COMPONENT_REF.
-     Might as well play it safe and always test this.  */
-  if (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))
-    return 0;
-
   switch (TREE_CODE_CLASS (TREE_CODE (arg0)))
     {
     case '1':
@@ -1800,10 +1804,22 @@ operand_equal_p (arg0, arg1, only_const)
 
     case '<':
     case '2':
-      return (operand_equal_p (TREE_OPERAND (arg0, 0),
-                              TREE_OPERAND (arg1, 0), 0)
+      if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0)
+         && operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1),
+                             0))
+       return 1;
+
+      /* For commutative ops, allow the other order.  */
+      return ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MULT_EXPR
+              || TREE_CODE (arg0) == MIN_EXPR || TREE_CODE (arg0) == MAX_EXPR
+              || TREE_CODE (arg0) == BIT_IOR_EXPR
+              || TREE_CODE (arg0) == BIT_XOR_EXPR
+              || TREE_CODE (arg0) == BIT_AND_EXPR
+              || TREE_CODE (arg0) == NE_EXPR || TREE_CODE (arg0) == EQ_EXPR)
+             && operand_equal_p (TREE_OPERAND (arg0, 0),
+                                 TREE_OPERAND (arg1, 1), 0)
              && operand_equal_p (TREE_OPERAND (arg0, 1),
-                                 TREE_OPERAND (arg1, 1), 0));
+                                 TREE_OPERAND (arg1, 0), 0));
 
     case 'r':
       switch (TREE_CODE (arg0))
@@ -2314,6 +2330,7 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
   enum machine_mode lmode, rmode, lnmode, rnmode;
   int lunsignedp, runsignedp;
   int lvolatilep = 0, rvolatilep = 0;
+  int alignment;
   tree linner, rinner;
   tree mask;
   tree offset;
@@ -2322,7 +2339,7 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
      if the same as the size of the underlying object, we aren't doing an
      extraction at all and so can do nothing.  */
   linner = get_inner_reference (lhs, &lbitsize, &lbitpos, &offset, &lmode,
-                               &lunsignedp, &lvolatilep);
+                               &lunsignedp, &lvolatilep, &alignment);
   if (linner == lhs || lbitsize == GET_MODE_BITSIZE (lmode) || lbitsize < 0
       || offset != 0)
     return 0;
@@ -2331,8 +2348,8 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
    {
      /* If this is not a constant, we can only do something if bit positions,
        sizes, and signedness are the same.   */
-     rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset,
-                                  &rmode, &runsignedp, &rvolatilep);
+     rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode,
+                                  &runsignedp, &rvolatilep, &alignment);
 
      if (rinner == rhs || lbitpos != rbitpos || lbitsize != rbitsize
         || lunsignedp != runsignedp || offset != 0)
@@ -2505,6 +2522,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
   tree mask, inner, offset;
   tree unsigned_type;
   int precision;
+  int alignment;
 
   /* All the optimizations using this function assume integer fields.  
      There are problems with FP fields since the type_for_size call
@@ -2525,7 +2543,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
 
 
   inner = get_inner_reference (exp, pbitsize, pbitpos, &offset, pmode,
-                              punsignedp, pvolatilep);
+                              punsignedp, pvolatilep, &alignment);
   if ((inner == exp && and_mask == 0)
       || *pbitsize < 0 || offset != 0)
     return 0;
@@ -2669,7 +2687,7 @@ range_binop (code, type, arg0, upper0_p, arg1, upper1_p)
      for neither.  Then compute our result treating them as never equal
      and comparing bounds to non-bounds as above.  */
   sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1);
-  sgn1 = arg1 != 0 ? 1 : (upper1_p ? 1 : -1);
+  sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1);
   switch (code)
     {
     case EQ_EXPR:  case NE_EXPR:
@@ -2715,7 +2733,8 @@ make_range (exp, pin_p, plow, phigh)
     {
       code = TREE_CODE (exp);
       arg0 = TREE_OPERAND (exp, 0), arg1 = TREE_OPERAND (exp, 1);
-      if (arg0 != 0 && tree_code_length[(int) code] > 0)
+      if (TREE_CODE_CLASS (code) == '<' || TREE_CODE_CLASS (code) == '1'
+         || TREE_CODE_CLASS (code) == '2')
        type = TREE_TYPE (arg0);
 
       switch (code)
@@ -2852,6 +2871,17 @@ make_range (exp, pin_p, plow, phigh)
       break;
     }
 
+  /* If EXP is a constant, we can evaluate whether this is true or false.  */
+  if (TREE_CODE (exp) == INTEGER_CST)
+    {
+      in_p = in_p == (integer_onep (range_binop (GE_EXPR, integer_type_node,
+                                                exp, 0, low, 0))
+                     && integer_onep (range_binop (LE_EXPR, integer_type_node,
+                                                   exp, 1, high, 1)));
+      low = high = 0;
+      exp = 0;
+    }
+
   *pin_p = in_p, *plow = low, *phigh = high;
   return exp;
 }
@@ -2964,7 +2994,7 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1)
       /* If they don't overlap, the result is the first range.  If the
         second range is a subset of the first, we can't describe this as
         a single range unless both ranges end at the same place.  If both
-        ranges also start in the same place, then the result is false.
+        ranges start in the same place, then the result is false.
         Otherwise, we go from the start of the first range to just before
         the start of the second.  */
       if (no_overlap)
@@ -2973,9 +3003,8 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1)
               && integer_zerop (range_binop (EQ_EXPR, integer_type_node,
                                              high0, 1, high1, 0)))
        return 0;
-      else if (subset
-              && integer_onep (range_binop (EQ_EXPR, integer_type_node,
-                                            low0, 0, low1, 0)))
+      else if (integer_onep (range_binop (EQ_EXPR, integer_type_node,
+                                         low0, 0, low1, 0)))
        in_p = 0, low = high = 0;
       else
        {
@@ -3053,11 +3082,15 @@ fold_range_test (exp)
     in0_p = ! in0_p, in1_p = ! in1_p;
 
   /* If both expressions are the same, if we can merge the ranges, and we
-     can build the range test, return it or it inverted.  */
-  if (operand_equal_p (lhs, rhs, 0)
+     can build the range test, return it or it inverted.  If one of the
+     ranges is always true or always false, consider it to be the same
+     expression as the other.  */
+  if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0))
       && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
                       in1_p, low1, high1)
-      && 0 != (tem = (build_range_check (TREE_TYPE (exp), lhs,
+      && 0 != (tem = (build_range_check (TREE_TYPE (exp),
+                                        lhs != 0 ? lhs
+                                        : rhs != 0 ? rhs : integer_zero_node,
                                         in_p, low, high))))
     return or_op ? invert_truthvalue (tem) : tem;
 
@@ -3113,18 +3146,28 @@ unextend (c, p, unsignedp, mask)
   if (p == modesize || unsignedp)
     return c;
 
-  if (TREE_UNSIGNED (type))
-    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-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);
+
+  /* We must use a signed type in order to get an arithmetic right shift.
+     However, we must also avoid introducing accidental overflows, so that
+     a subsequent call to integer_zerop will work.  Hence we must 
+     do the type conversion here.  At this point, the constant is either
+     zero or one, and the conversion to a signed type can never overflow.
+     We could get an overflow if this conversion is done anywhere else.  */
+  if (TREE_UNSIGNED (type))
+    temp = convert (signed_type (type), temp);
+
   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);
+  /* If necessary, convert the type back to match the type of C.  */
+  if (TREE_UNSIGNED (type))
+    temp = convert (type, temp);
 
   return convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
 }
@@ -3718,7 +3761,8 @@ fold (expr)
                      fold (build (code, type,
                                   arg0, TREE_OPERAND (arg1, 1))));
       else if (TREE_CODE (arg1) == COND_EXPR
-              || TREE_CODE_CLASS (TREE_CODE (arg1)) == '<')
+              || (TREE_CODE_CLASS (TREE_CODE (arg1)) == '<'
+                  && TREE_CODE_CLASS (code) != '<'))
        {
          tree test, true_value, false_value;
 
@@ -3774,7 +3818,8 @@ fold (expr)
        return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
                      fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
       else if (TREE_CODE (arg0) == COND_EXPR
-              || TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+              || (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
+                  && TREE_CODE_CLASS (code) != '<'))
        {
          tree test, true_value, false_value;
 
@@ -3993,7 +4038,6 @@ fold (expr)
            }
          else if (TREE_CODE (arg0) == REAL_CST)
            t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
-         TREE_TYPE (t) = type;
        }
       else if (TREE_CODE (arg0) == NEGATE_EXPR)
        return TREE_OPERAND (arg0, 0);
@@ -4032,7 +4076,6 @@ fold (expr)
                t = build_real (type,
                                REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
            }
-         TREE_TYPE (t) = type;
        }
       else if (TREE_CODE (arg0) == ABS_EXPR || TREE_CODE (arg0) == NEGATE_EXPR)
        return build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
@@ -4065,9 +4108,8 @@ fold (expr)
     case BIT_NOT_EXPR:
       if (wins)
        {
-         if (TREE_CODE (arg0) == INTEGER_CST)
-           t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
-                            ~ TREE_INT_CST_HIGH (arg0));
+         t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
+                          ~ TREE_INT_CST_HIGH (arg0));
          TREE_TYPE (t) = type;
          force_fit_type (t, 0);
          TREE_OVERFLOW (t) = TREE_OVERFLOW (arg0);
@@ -4234,7 +4276,9 @@ fold (expr)
        {
          /* The return value should always have
             the same type as the original expression.  */
-         TREE_TYPE (t1) = TREE_TYPE (t);
+         if (TREE_TYPE (t1) != TREE_TYPE (t))
+           t1 = convert (TREE_TYPE (t), t1);
+
          return t1;
        }
       return t;
@@ -4733,6 +4777,10 @@ fold (expr)
         must be evaluated.  */
       if (integer_zerop (arg1))
        return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
+        case will be handled here.  */
+      if (integer_zerop (arg0))
+       return omit_one_operand (type, arg0, arg1);
 
     truth_andor:
       /* We only do these simplifications if we are optimizing.  */
@@ -4813,6 +4861,10 @@ fold (expr)
         evaluate first arg.  */
       if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
        return omit_one_operand (type, arg1, arg0);
+      /* Likewise for first arg, but note this only occurs here for
+        TRUTH_OR_EXPR.  */
+      if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+       return omit_one_operand (type, arg0, arg1);
       goto truth_andor;
 
     case TRUTH_XOR_EXPR:
@@ -5058,6 +5110,9 @@ fold (expr)
            case LE_EXPR:
              if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
                {
+                 if (type == integer_type_node)
+                   return integer_one_node;
+
                  t = build_int_2 (1, 0);
                  TREE_TYPE (t) = type;
                  return t;
@@ -5073,6 +5128,9 @@ fold (expr)
              /* ... fall through ...  */
            case GT_EXPR:
            case LT_EXPR:
+             if (type == integer_type_node)
+               return integer_zero_node;
+
              t = build_int_2 (0, 0);
              TREE_TYPE (t) = type;
              return t;
@@ -5282,6 +5340,7 @@ fold (expr)
                              0);
        }
 
+#if 0 /* This is no longer useful, but breaks some real code.  */
       /* Assume a nonexplicit constant cannot equal an explicit one,
         since such code would be undefined anyway.
         Exception: on sysvr4, using #pragma weak,
@@ -5292,7 +5351,7 @@ fold (expr)
               && TREE_CODE (arg0) == ADDR_EXPR
               && code == EQ_EXPR)
        t1 = build_int_2 (0, 0);
-
+#endif
       /* Two real constants can be compared explicitly.  */
       else if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
        {