OSDN Git Service

* collect2.c (find_a_file): Use HAVE_DOS_BASED_FILE_SYSTEM in place
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index b146e8b..9b003c2 100644 (file)
@@ -1,5 +1,5 @@
 /* Fold a constant sub-tree into a single node for C-compiler
-   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -27,7 +27,7 @@ Boston, MA 02111-1307, USA.  */
   @@ for cross-compilers.  */
 
 
-/* The entry points in this file are fold, size_int, size_binop
+/* The entry points in this file are fold, size_int_wide, size_binop
    and force_fit_type.
 
    fold takes a tree as argument and returns a simplified tree.
@@ -42,14 +42,13 @@ Boston, MA 02111-1307, USA.  */
    force_fit_type takes a constant and prior overflow indicator, and
    forces the value to fit the type.  It returns an overflow indicator.  */
 
-#include <stdio.h>
-#include <setjmp.h>
 #include "config.h"
+#include "system.h"
+#include <setjmp.h>
 #include "flags.h"
 #include "tree.h"
-
-/* Handle floating overflow for `const_binop'.  */
-static jmp_buf float_error;
+#include "rtl.h"
+#include "toplev.h"
 
 static void encode             PROTO((HOST_WIDE_INT *,
                                       HOST_WIDE_INT, HOST_WIDE_INT));
@@ -62,6 +61,7 @@ int div_and_round_double      PROTO((enum tree_code, int, HOST_WIDE_INT,
                                       HOST_WIDE_INT *));
 static int split_tree          PROTO((tree, enum tree_code, tree *,
                                       tree *, int *));
+static tree int_const_binop    PROTO((enum tree_code, tree, tree, int, int));
 static tree const_binop                PROTO((enum tree_code, tree, tree, int));
 static tree fold_convert       PROTO((tree, tree));
 static enum tree_code invert_tree_comparison PROTO((enum tree_code));
@@ -91,6 +91,11 @@ static tree fold_range_test  PROTO((tree));
 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));
+static int multiple_of_p       PROTO((tree, tree, tree));
+static tree constant_boolean_node PROTO((int, tree));
+static int count_cond          PROTO((tree, int));
+static void const_binop_1      PROTO((PTR));
+static void fold_convert_1     PROTO((PTR));
 
 #ifndef BRANCH_COST
 #define BRANCH_COST 1
@@ -174,7 +179,7 @@ force_fit_type (t, overflow)
   low = TREE_INT_CST_LOW (t);
   high = TREE_INT_CST_HIGH (t);
 
-  if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+  if (POINTER_TYPE_P (TREE_TYPE (t)))
     prec = POINTER_SIZE;
   else
     prec = TYPE_PRECISION (TREE_TYPE (t));
@@ -354,13 +359,13 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
 
   if (count >= HOST_BITS_PER_WIDE_INT)
     {
-      *hv = (unsigned HOST_WIDE_INT) l1 << count - HOST_BITS_PER_WIDE_INT;
+      *hv = (unsigned HOST_WIDE_INT) l1 << (count - HOST_BITS_PER_WIDE_INT);
       *lv = 0;
     }
   else
     {
       *hv = (((unsigned HOST_WIDE_INT) h1 << count)
-            | ((unsigned HOST_WIDE_INT) l1 >> HOST_BITS_PER_WIDE_INT - count - 1 >> 1));
+            | ((unsigned HOST_WIDE_INT) l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
       *lv = (unsigned HOST_WIDE_INT) l1 << count;
     }
 }
@@ -373,7 +378,7 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
 void
 rshift_double (l1, h1, count, prec, lv, hv, arith)
      HOST_WIDE_INT l1, h1, count;
-     int prec;
+     int prec ATTRIBUTE_UNUSED;
      HOST_WIDE_INT *lv, *hv;
      int arith;
 {
@@ -390,14 +395,14 @@ rshift_double (l1, h1, count, prec, lv, hv, arith)
   if (count >= HOST_BITS_PER_WIDE_INT)
     {
       *hv = signmask;
-      *lv = ((signmask << 2 * HOST_BITS_PER_WIDE_INT - count - 1 << 1)
-            | ((unsigned HOST_WIDE_INT) h1 >> count - HOST_BITS_PER_WIDE_INT));
+      *lv = ((signmask << (2 * HOST_BITS_PER_WIDE_INT - count - 1) << 1)
+            | ((unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT)));
     }
   else
     {
       *lv = (((unsigned HOST_WIDE_INT) l1 >> count)
-            | ((unsigned HOST_WIDE_INT) h1 << HOST_BITS_PER_WIDE_INT - count - 1 << 1));
-      *hv = ((signmask << HOST_BITS_PER_WIDE_INT - count)
+            | ((unsigned HOST_WIDE_INT) h1 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
+      *hv = ((signmask << (HOST_BITS_PER_WIDE_INT - count))
             | ((unsigned HOST_WIDE_INT) h1 >> count));
     }
 }
@@ -479,7 +484,7 @@ div_and_round_double (code, uns,
   int overflow = 0;
 
   if ((hden == 0) && (lden == 0))
-    abort ();
+    overflow = 1, lden = 1;
 
   /* calculate quotient sign and convert operands to unsigned.  */
   if (!uns) 
@@ -524,7 +529,7 @@ div_and_round_double (code, uns,
   encode (den, lden, hden);
 
   /* Special code for when the divisor < BASE.  */
-  if (hden == 0 && lden < BASE)
+  if (hden == 0 && lden < (HOST_WIDE_INT) BASE)
     {
       /* hnum != 0 already checked.  */
       for (i = 4 - 1; i >= 0; i--)
@@ -880,6 +885,7 @@ exact_real_inverse (mode, r)
      enum machine_mode mode;
      REAL_VALUE_TYPE *r;
 {
+  jmp_buf float_error;
   union
     {
       double d;
@@ -959,6 +965,235 @@ fail:
   *r = y.d;
   return 1;
 }
+
+
+/* Convert C9X hexadecimal floating point string constant S.  Return
+   real value type in mode MODE.  This function uses the host computer's
+   fp arithmetic when there is no REAL_ARITHMETIC.  */
+
+REAL_VALUE_TYPE
+real_hex_to_f (s, mode)
+   char *s;
+   enum machine_mode mode;
+{
+   REAL_VALUE_TYPE ip;
+   char *p = s;
+   unsigned HOST_WIDE_INT low, high;
+   int frexpon, expon, shcount, nrmcount, k;
+   int sign, expsign, decpt, isfloat, isldouble, gotp, lost;
+   char c;
+
+   isldouble = 0;
+   isfloat = 0;
+   frexpon = 0;
+   expon = 0;
+   expsign = 1;
+   ip = 0.0;
+
+   while (*p == ' ' || *p == '\t')
+     ++p;
+
+   /* Sign, if any, comes first.  */
+   sign = 1;
+   if (*p == '-')
+     {
+       sign = -1;
+       ++p;
+     }
+
+   /* The string is supposed to start with 0x or 0X .  */
+   if (*p == '0')
+     {
+       ++p;
+       if (*p == 'x' || *p == 'X')
+        ++p;
+       else
+        abort ();
+     }
+   else
+     abort ();
+
+   while (*p == '0')
+     ++p;
+
+   high = 0;
+   low = 0;
+   lost = 0; /* Nonzero low order bits shifted out and discarded.  */
+   frexpon = 0;  /* Bits after the decimal point.  */
+   expon = 0;  /* Value of exponent.  */
+   decpt = 0;  /* How many decimal points.  */
+   gotp = 0;  /* How many P's.  */
+   shcount = 0;
+   while ((c = *p) != '\0')
+     {
+       if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')
+          || (c >= 'a' && c <= 'f'))
+        {
+          k = c & 0x7f;
+          if (k >= 'a')
+            k = k - 'a' + 10;
+          else if (k >= 'A')
+            k = k - 'A' + 10;
+          else
+            k = k - '0';
+
+          if ((high & 0xf0000000) == 0)
+            {
+              high = (high << 4) + ((low >> 28) & 15);
+              low = (low << 4) + k;
+              shcount += 4;
+              if (decpt)
+                frexpon += 4;
+            }
+          else
+            {
+              /* Record nonzero lost bits.  */
+              lost |= k;
+              if (!decpt)
+                frexpon -= 4;
+            }
+          ++p;
+        }
+       else if ( c == '.')
+        {
+          ++decpt;
+          ++p;
+        }
+       else if (c == 'p' || c == 'P')
+        {
+          ++gotp;
+          ++p;
+          /* Sign of exponent.  */
+          if (*p == '-')
+            {
+              expsign = -1;
+              ++p;
+            }
+          /* Value of exponent.
+             The exponent field is a decimal integer.  */
+          while (isdigit(*p))
+            {
+              k = (*p++ & 0x7f) - '0';
+              expon = 10 * expon + k;
+            }
+          expon *= expsign;
+          /* F suffix is ambiguous in the significand part
+             so it must appear after the decimal exponent field.  */
+          if (*p == 'f' || *p == 'F')
+            {
+              isfloat = 1;
+              ++p;
+              break;
+            }
+        }
+       else if (c == 'l' || c == 'L')
+        {
+          isldouble = 1;
+          ++p;
+          break;
+        }
+       else
+        break;
+     }
+   /* Abort if last character read was not legitimate.  */
+   c = *p;
+   if ((c != '\0' && c != ' ' && c != '\n' && c != '\r') || (decpt > 1))
+     abort ();
+   /* There must be either one decimal point or one p.  */
+   if (decpt == 0 && gotp == 0)
+     abort ();
+   shcount -= 4;
+   if ((high == 0) && (low == 0))
+     {
+       return dconst0;
+     }
+
+   /* Normalize.  */
+   nrmcount = 0;
+   if (high == 0)
+     {
+       high = low;
+       low = 0;
+       nrmcount += 32;
+     }
+   /* Leave a high guard bit for carry-out.  */
+   if ((high & 0x80000000) != 0)
+     {
+       lost |= low & 1;
+       low = (low >> 1) | (high << 31);
+       high = high >> 1;
+       nrmcount -= 1;
+     }
+   if ((high & 0xffff8000) == 0)
+     {
+       high = (high << 16) + ((low >> 16) & 0xffff);
+       low = low << 16;
+       nrmcount += 16;
+     }
+   while ((high & 0xc0000000) == 0)
+     {
+       high = (high << 1) + ((low >> 31) & 1);
+       low = low << 1;
+       nrmcount += 1;
+     }
+   if (isfloat || GET_MODE_SIZE(mode) == UNITS_PER_WORD)
+     {
+       /* Keep 24 bits precision, bits 0x7fffff80.
+         Rounding bit is 0x40.  */
+       lost = lost | low | (high & 0x3f);
+       low = 0;
+       if (high & 0x40)
+        {
+          if ((high & 0x80) || lost)
+            high += 0x40;
+        }
+       high &= 0xffffff80;
+     }
+   else
+     {
+       /* We need real.c to do long double formats, so here default
+         to double precision.  */
+#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+       /* IEEE double.
+         Keep 53 bits precision, bits 0x7fffffff fffffc00.
+         Rounding bit is low word 0x200.  */
+       lost = lost | (low & 0x1ff);
+       if (low & 0x200)
+        {
+          if ((low & 0x400) || lost)
+            {
+              low = (low + 0x200) & 0xfffffc00;
+              if (low == 0)
+                high += 1;
+            }
+        }
+       low &= 0xfffffc00;
+#else
+       /* Assume it's a VAX with 56-bit significand,
+          bits 0x7fffffff ffffff80.  */
+       lost = lost | (low & 0x7f);
+       if (low & 0x40)
+        {
+          if ((low & 0x80) || lost)
+            {
+              low = (low + 0x40) & 0xffffff80;
+              if (low == 0)
+                high += 1;
+            }
+        }
+       low &= 0xffffff80;
+#endif
+     }
+   ip = (double) high;
+   ip =  REAL_VALUE_LDEXP (ip, 32) + (double) low;
+   /* Apply shifts and exponent value as power of 2.  */
+   ip = REAL_VALUE_LDEXP (ip, expon - (nrmcount + frexpon));
+
+   if (sign < 0)
+     ip = -ip;
+   return ip;
+}
+
 #endif /* no REAL_ARITHMETIC */
 \f
 /* Split a tree IN into a constant and a variable part
@@ -1050,200 +1285,286 @@ split_tree (in, code, varp, conp, varsignp)
   return 0;
 }
 \f
-/* Combine two constants ARG1 and ARG2 under operation CODE
+/* Combine two integer constants ARG1 and ARG2 under operation CODE
    to produce a new constant.
-   We assume ARG1 and ARG2 have the same data type,
-   or at least are the same kind of constant and the same machine mode.
 
-   If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
+   If NOTRUNC is nonzero, do not truncate the result to fit the data type.
+   If FORSIZE is nonzero, compute overflow for unsigned types.  */
 
 static tree
-const_binop (code, arg1, arg2, notrunc)
+int_const_binop (code, arg1, arg2, notrunc, forsize)
      enum tree_code code;
      register tree arg1, arg2;
-     int notrunc;
+     int notrunc, forsize;
 {
-  STRIP_NOPS (arg1); STRIP_NOPS (arg2);
+  HOST_WIDE_INT int1l, int1h, int2l, int2h;
+  HOST_WIDE_INT low, hi;
+  HOST_WIDE_INT garbagel, garbageh;
+  register tree t;
+  int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
+  int overflow = 0;
+  int no_overflow = 0;
 
-  if (TREE_CODE (arg1) == INTEGER_CST)
+  int1l = TREE_INT_CST_LOW (arg1);
+  int1h = TREE_INT_CST_HIGH (arg1);
+  int2l = TREE_INT_CST_LOW (arg2);
+  int2h = TREE_INT_CST_HIGH (arg2);
+
+  switch (code)
     {
-      register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1);
-      register HOST_WIDE_INT int1h = TREE_INT_CST_HIGH (arg1);
-      HOST_WIDE_INT int2l = TREE_INT_CST_LOW (arg2);
-      HOST_WIDE_INT int2h = TREE_INT_CST_HIGH (arg2);
-      HOST_WIDE_INT low, hi;
-      HOST_WIDE_INT garbagel, garbageh;
-      register tree t;
-      int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
-      int overflow = 0;
-      int no_overflow = 0;
+    case BIT_IOR_EXPR:
+      low = int1l | int2l, hi = int1h | int2h;
+      break;
 
-      switch (code)
-       {
-       case BIT_IOR_EXPR:
-         low = int1l | int2l, hi = int1h | int2h;
-         break;
+    case BIT_XOR_EXPR:
+      low = int1l ^ int2l, hi = int1h ^ int2h;
+      break;
 
-       case BIT_XOR_EXPR:
-         low = int1l ^ int2l, hi = int1h ^ int2h;
-         break;
+    case BIT_AND_EXPR:
+      low = int1l & int2l, hi = int1h & int2h;
+      break;
 
-       case BIT_AND_EXPR:
-         low = int1l & int2l, hi = int1h & int2h;
-         break;
+    case BIT_ANDTC_EXPR:
+      low = int1l & ~int2l, hi = int1h & ~int2h;
+      break;
 
-       case BIT_ANDTC_EXPR:
-         low = int1l & ~int2l, hi = int1h & ~int2h;
-         break;
+    case RSHIFT_EXPR:
+      int2l = - int2l;
+    case LSHIFT_EXPR:
+      /* It's unclear from the C standard whether shifts can overflow.
+        The following code ignores overflow; perhaps a C standard
+        interpretation ruling is needed.  */
+      lshift_double (int1l, int1h, int2l,
+                    TYPE_PRECISION (TREE_TYPE (arg1)),
+                    &low, &hi,
+                    !uns);
+      no_overflow = 1;
+      break;
 
-       case RSHIFT_EXPR:
-         int2l = - int2l;
-       case LSHIFT_EXPR:
-         /* It's unclear from the C standard whether shifts can overflow.
-            The following code ignores overflow; perhaps a C standard
-            interpretation ruling is needed.  */
-         lshift_double (int1l, int1h, int2l,
-                        TYPE_PRECISION (TREE_TYPE (arg1)),
-                        &low, &hi,
-                        !uns);
-         no_overflow = 1;
-         break;
+    case RROTATE_EXPR:
+      int2l = - int2l;
+    case LROTATE_EXPR:
+      lrotate_double (int1l, int1h, int2l,
+                     TYPE_PRECISION (TREE_TYPE (arg1)),
+                     &low, &hi);
+      break;
 
-       case RROTATE_EXPR:
-         int2l = - int2l;
-       case LROTATE_EXPR:
-         lrotate_double (int1l, int1h, int2l,
-                         TYPE_PRECISION (TREE_TYPE (arg1)),
-                         &low, &hi);
-         break;
+    case PLUS_EXPR:
+      overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
+      break;
 
-       case PLUS_EXPR:
-         overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
-         break;
+    case MINUS_EXPR:
+      neg_double (int2l, int2h, &low, &hi);
+      add_double (int1l, int1h, low, hi, &low, &hi);
+      overflow = overflow_sum_sign (hi, int2h, int1h);
+      break;
 
-       case MINUS_EXPR:
-         neg_double (int2l, int2h, &low, &hi);
-         add_double (int1l, int1h, low, hi, &low, &hi);
-         overflow = overflow_sum_sign (hi, int2h, int1h);
-         break;
+    case MULT_EXPR:
+      overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
+      break;
 
-       case MULT_EXPR:
-         overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
+    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.  */
+      if (int2h == 0 && int2l > 0
+         && ! TREE_CONSTANT_OVERFLOW (arg1)
+         && ! TREE_CONSTANT_OVERFLOW (arg2)
+         && int1h == 0 && int1l >= 0)
+       {
+         if (code == CEIL_DIV_EXPR)
+           int1l += int2l - 1;
+         low = int1l / int2l, hi = 0;
          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.  */
-         if (int2h == 0 && int2l > 0
-             && ! TREE_CONSTANT_OVERFLOW (arg1)
-             && ! TREE_CONSTANT_OVERFLOW (arg2)
-             && int1h == 0 && int1l >= 0)
-           {
-             if (code == CEIL_DIV_EXPR)
-               int1l += int2l - 1;
-             low = int1l / int2l, hi = 0;
-             break;
-           }
-
-         /* ... fall through ... */
+      /* ... fall through ... */
 
-       case ROUND_DIV_EXPR: 
-         if (int2h == 0 && int2l == 1)
-           {
-             low = int1l, hi = int1h;
-             break;
-           }
-         if (int1l == int2l && int1h == int2h
-             && ! (int1l == 0 && int1h == 0))
-           {
-             low = 1, hi = 0;
-             break;
-           }
-         overflow = div_and_round_double (code, uns,
-                                          int1l, int1h, int2l, int2h,
-                                          &low, &hi, &garbagel, &garbageh);
+    case ROUND_DIV_EXPR: 
+      if (int2h == 0 && int2l == 1)
+       {
+         low = int1l, hi = int1h;
          break;
-
-       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);
+       }
+      if (int1l == int2l && int1h == int2h
+         && ! (int1l == 0 && int1h == 0))
+       {
+         low = 1, hi = 0;
          break;
+       }
+      overflow = div_and_round_double (code, uns,
+                                      int1l, int1h, int2l, int2h,
+                                      &low, &hi, &garbagel, &garbageh);
+      break;
 
-       case MIN_EXPR:
-       case MAX_EXPR:
-         if (uns)
-           {
-             low = (((unsigned HOST_WIDE_INT) int1h
-                     < (unsigned HOST_WIDE_INT) int2h)
-                    || (((unsigned HOST_WIDE_INT) int1h
-                         == (unsigned HOST_WIDE_INT) int2h)
-                        && ((unsigned HOST_WIDE_INT) int1l
-                            < (unsigned HOST_WIDE_INT) int2l)));
-           }
-         else
-           {
-             low = ((int1h < int2h)
-                    || ((int1h == int2h)
-                        && ((unsigned HOST_WIDE_INT) int1l
-                            < (unsigned HOST_WIDE_INT) int2l)));
-           }
-         if (low == (code == MIN_EXPR))
-           low = int1l, hi = int1h;
-         else
-           low = int2l, hi = int2h;
+    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;
+       }
 
-       default:
-         abort ();
+      /* ... fall through ... */
+
+    case ROUND_MOD_EXPR: 
+      overflow = div_and_round_double (code, uns,
+                                      int1l, int1h, int2l, int2h,
+                                      &garbagel, &garbageh, &low, &hi);
+      break;
+
+    case MIN_EXPR:
+    case MAX_EXPR:
+      if (uns)
+       {
+         low = (((unsigned HOST_WIDE_INT) int1h
+                 < (unsigned HOST_WIDE_INT) int2h)
+                || (((unsigned HOST_WIDE_INT) int1h
+                     == (unsigned HOST_WIDE_INT) int2h)
+                    && ((unsigned HOST_WIDE_INT) int1l
+                        < (unsigned HOST_WIDE_INT) int2l)));
        }
-    got_it:
-      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);
+         low = ((int1h < int2h)
+                || ((int1h == int2h)
+                    && ((unsigned HOST_WIDE_INT) int1l
+                        < (unsigned HOST_WIDE_INT) int2l)));
        }
+      if (low == (code == MIN_EXPR))
+       low = int1l, hi = int1h;
+      else
+       low = int2l, hi = int2h;
+      break;
 
-      TREE_OVERFLOW (t)
-       = ((notrunc ? !uns && overflow
-           : force_fit_type (t, overflow && !uns) && ! no_overflow)
-          | TREE_OVERFLOW (arg1)
-          | TREE_OVERFLOW (arg2));
-      TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
-                                   | TREE_CONSTANT_OVERFLOW (arg1)
-                                   | TREE_CONSTANT_OVERFLOW (arg2));
-      return t;
+    default:
+      abort ();
+    }
+
+  if (TREE_TYPE (arg1) == sizetype && hi == 0
+      && low >= 0
+      && (TYPE_MAX_VALUE (sizetype) == NULL
+         || 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 || forsize) && overflow
+       : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow)
+       | TREE_OVERFLOW (arg1)
+       | TREE_OVERFLOW (arg2));
+  /* If we're doing a size calculation, unsigned arithmetic does overflow.
+     So check if force_fit_type truncated the value.  */
+  if (forsize
+      && ! TREE_OVERFLOW (t)
+      && (TREE_INT_CST_HIGH (t) != hi
+         || TREE_INT_CST_LOW (t) != low))
+    TREE_OVERFLOW (t) = 1;
+  TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
+                               | TREE_CONSTANT_OVERFLOW (arg1)
+                               | TREE_CONSTANT_OVERFLOW (arg2));
+  return t;
+}
+
+struct cb_args
+{
+  /* Input */
+  tree arg1;
+  REAL_VALUE_TYPE d1, d2;
+  enum tree_code code;
+  /* Output */
+  tree t;
+};
+
+static void
+const_binop_1 (data)
+  PTR data;
+{
+  struct cb_args * args = (struct cb_args *) data;
+  REAL_VALUE_TYPE value;
+
+#ifdef REAL_ARITHMETIC
+  REAL_ARITHMETIC (value, args->code, args->d1, args->d2);
+#else
+  switch (args->code)
+    {
+    case PLUS_EXPR:
+      value = args->d1 + args->d2;
+      break;
+      
+    case MINUS_EXPR:
+      value = args->d1 - args->d2;
+      break;
+      
+    case MULT_EXPR:
+      value = args->d1 * args->d2;
+      break;
+      
+    case RDIV_EXPR:
+#ifndef REAL_INFINITY
+      if (args->d2 == 0)
+       abort ();
+#endif
+      
+      value = args->d1 / args->d2;
+      break;
+      
+    case MIN_EXPR:
+      value = MIN (args->d1, args->d2);
+      break;
+      
+    case MAX_EXPR:
+      value = MAX (args->d1, args->d2);
+      break;
+      
+    default:
+      abort ();
+    }
+#endif /* no REAL_ARITHMETIC */
+  args->t =
+    build_real (TREE_TYPE (args->arg1),
+               real_value_truncate (TYPE_MODE (TREE_TYPE (args->arg1)),
+                                    value));
+}
+
+/* Combine two constants ARG1 and ARG2 under operation CODE
+   to produce a new constant.
+   We assume ARG1 and ARG2 have the same data type,
+   or at least are the same kind of constant and the same machine mode.
+
+   If NOTRUNC is nonzero, do not truncate the result to fit the data type.  */
+
+static tree
+const_binop (code, arg1, arg2, notrunc)
+     enum tree_code code;
+     register tree arg1, arg2;
+     int notrunc;
+{
+  STRIP_NOPS (arg1); STRIP_NOPS (arg2);
+
+  if (TREE_CODE (arg1) == INTEGER_CST)
+    return int_const_binop (code, arg1, arg2, notrunc, 0);
+
 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
   if (TREE_CODE (arg1) == REAL_CST)
     {
       REAL_VALUE_TYPE d1;
       REAL_VALUE_TYPE d2;
       int overflow = 0;
-      REAL_VALUE_TYPE value;
       tree t;
+      struct cb_args args;
 
       d1 = TREE_REAL_CST (arg1);
       d2 = TREE_REAL_CST (arg2);
@@ -1254,57 +1575,24 @@ const_binop (code, arg1, arg2, notrunc)
        return arg1;
       else if (REAL_VALUE_ISNAN (d2))
        return arg2;
-      else if (setjmp (float_error))
+
+      /* Setup input for const_binop_1() */
+      args.arg1 = arg1;
+      args.d1 = d1;
+      args.d2 = d2;
+      args.code = code;
+      
+      if (do_float_handler (const_binop_1, (PTR) &args))
        {
-         t = copy_node (arg1);
-         overflow = 1;
-         goto got_float;
+         /* Receive output from const_binop_1() */
+         t = args.t;
        }
-
-      set_float_handler (float_error);
-
-#ifdef REAL_ARITHMETIC
-      REAL_ARITHMETIC (value, code, d1, d2);
-#else
-      switch (code)
+      else
        {
-       case PLUS_EXPR:
-         value = d1 + d2;
-         break;
-
-       case MINUS_EXPR:
-         value = d1 - d2;
-         break;
-
-       case MULT_EXPR:
-         value = d1 * d2;
-         break;
-
-       case RDIV_EXPR:
-#ifndef REAL_INFINITY
-         if (d2 == 0)
-           abort ();
-#endif
-
-         value = d1 / d2;
-         break;
-
-       case MIN_EXPR:
-         value = MIN (d1, d2);
-         break;
-
-       case MAX_EXPR:
-         value = MAX (d1, d2);
-         break;
-
-       default:
-         abort ();
+         /* We got an exception from const_binop_1() */
+         t = copy_node (arg1);
+         overflow = 1;
        }
-#endif /* no REAL_ARITHMETIC */
-      t = build_real (TREE_TYPE (arg1),
-                     real_value_truncate (TYPE_MODE (TREE_TYPE (arg1)), value));
-    got_float:
-      set_float_handler (NULL_PTR);
 
       TREE_OVERFLOW (t)
        = (force_fit_type (t, overflow)
@@ -1395,33 +1683,36 @@ const_binop (code, arg1, arg2, notrunc)
   return 0;
 }
 \f
-/* Return an INTEGER_CST with value V and type from `sizetype'.  */
+/* Return an INTEGER_CST with value V .  The type is determined by bit_p:
+   if it is zero, the type is taken from sizetype; if it is one, the type
+   is taken from bitsizetype.  */
 
 tree
-size_int (number)
-     unsigned HOST_WIDE_INT number;
+size_int_wide (number, high, bit_p)
+     unsigned HOST_WIDE_INT number, high;
+     int bit_p;
 {
   register tree t;
   /* Type-size nodes already made for small sizes.  */
-  static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1];
+  static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1][2];
 
-  if (number < 2*HOST_BITS_PER_WIDE_INT + 1
-      && size_table[number] != 0)
-    return size_table[number];
-  if (number < 2*HOST_BITS_PER_WIDE_INT + 1)
+  if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high
+      && size_table[number][bit_p] != 0)
+    return size_table[number][bit_p];
+  if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high)
     {
       push_obstacks_nochange ();
       /* Make this a permanent node.  */
       end_temporary_allocation ();
       t = build_int_2 (number, 0);
-      TREE_TYPE (t) = sizetype;
-      size_table[number] = t;
+      TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
+      size_table[number][bit_p] = t;
       pop_obstacks ();
     }
   else
     {
-      t = build_int_2 (number, 0);
-      TREE_TYPE (t) = sizetype;
+      t = build_int_2 (number, high);
+      TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
       TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
     }
   return t;
@@ -1449,7 +1740,7 @@ size_binop (code, arg0, arg1)
        return arg1;
 
       /* Handle general case of two integer constants.  */
-      return const_binop (code, arg0, arg1, 0);
+      return int_const_binop (code, arg0, arg1, 0, 1);
     }
 
   if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -1457,7 +1748,60 @@ size_binop (code, arg0, arg1)
 
   return fold (build (code, sizetype, arg0, arg1));
 }
+
+/* Combine operands OP1 and OP2 with arithmetic operation CODE.
+   CODE is a tree code.  Data type is taken from `ssizetype',
+   If the operands are constant, so is the result.  */
+
+tree
+ssize_binop (code, arg0, arg1)
+     enum tree_code code;
+     tree arg0, arg1;
+{
+  /* Handle the special case of two integer constants faster.  */
+  if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+    {
+      /* And some specific cases even faster than that.  */
+      if (code == PLUS_EXPR && integer_zerop (arg0))
+       return arg1;
+      else if ((code == MINUS_EXPR || code == PLUS_EXPR)
+              && integer_zerop (arg1))
+       return arg0;
+      else if (code == MULT_EXPR && integer_onep (arg0))
+       return arg1;
+
+      /* Handle general case of two integer constants.  We convert
+         arg0 to ssizetype because int_const_binop uses its type for the
+        return value.  */
+      arg0 = convert (ssizetype, arg0);
+      return int_const_binop (code, arg0, arg1, 0, 0);
+    }
+
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return error_mark_node;
+
+  return fold (build (code, ssizetype, arg0, arg1));
+}
 \f
+struct fc_args
+{
+  /* Input */
+  tree arg1, type;
+  /* Output */
+  tree t;
+};
+
+static void
+fold_convert_1 (data)
+  PTR data;
+{
+  struct fc_args * args = (struct fc_args *) data;
+
+  args->t = build_real (args->type,
+                       real_value_truncate (TYPE_MODE (args->type),
+                                            TREE_REAL_CST (args->arg1)));
+}
+
 /* Given T, a tree representing type conversion of ARG1, a constant,
    return a constant tree representing the result of conversion.  */
 
@@ -1469,7 +1813,7 @@ fold_convert (t, arg1)
   register tree type = TREE_TYPE (t);
   int overflow = 0;
 
-  if (TREE_CODE (type) == POINTER_TYPE || INTEGRAL_TYPE_P (type))
+  if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
     {
       if (TREE_CODE (arg1) == INTEGER_CST)
        {
@@ -1486,13 +1830,15 @@ fold_convert (t, arg1)
          /* Indicate an overflow if (1) ARG1 already overflowed,
             or (2) force_fit_type indicates an overflow.
             Tell force_fit_type that an overflow has already occurred
-            if ARG1 is a too-large unsigned value and T is signed.  */
+            if ARG1 is a too-large unsigned value and T is signed.
+            But don't indicate an overflow if converting a pointer.  */
          TREE_OVERFLOW (t)
-           = (TREE_OVERFLOW (arg1)
-              | force_fit_type (t,
-                                (TREE_INT_CST_HIGH (arg1) < 0
-                                 & (TREE_UNSIGNED (type)
-                                    < TREE_UNSIGNED (TREE_TYPE (arg1))))));
+           = ((force_fit_type (t,
+                               (TREE_INT_CST_HIGH (arg1) < 0
+                                && (TREE_UNSIGNED (type)
+                                   < TREE_UNSIGNED (TREE_TYPE (arg1)))))
+               && ! POINTER_TYPE_P (TREE_TYPE (arg1)))
+              || TREE_OVERFLOW (arg1));
          TREE_CONSTANT_OVERFLOW (t)
            = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
        }
@@ -1505,25 +1851,34 @@ fold_convert (t, arg1)
          REAL_VALUE_TYPE l;
          REAL_VALUE_TYPE u;
          tree type1 = TREE_TYPE (arg1);
+         int no_upper_bound;
 
          x = TREE_REAL_CST (arg1);
          l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
-         u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
+
+         no_upper_bound = (TYPE_MAX_VALUE (type) == NULL);
+         if (!no_upper_bound)
+           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.  */
 #ifdef REAL_ARITHMETIC
          REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
-         REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
+         if (!no_upper_bound)
+           REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
 #else
          l--;
-         u++;
+         if (!no_upper_bound)
+           u++;
 #endif
          /* If X is a NaN, use zero instead and show we have an overflow.
             Otherwise, range check.  */
          if (REAL_VALUE_ISNAN (x))
            overflow = 1, x = dconst0;
-         else if (! (REAL_VALUES_LESS (l, x) && REAL_VALUES_LESS (x, u)))
+         else if (! (REAL_VALUES_LESS (l, x)
+                     && !no_upper_bound
+                     && REAL_VALUES_LESS (x, u)))
            overflow = 1;
 
 #ifndef REAL_ARITHMETIC
@@ -1572,25 +1927,31 @@ fold_convert (t, arg1)
 #endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
       if (TREE_CODE (arg1) == REAL_CST)
        {
+         struct fc_args args;
+         
          if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
            {
              t = arg1;
              TREE_TYPE (arg1) = type;
              return t;
            }
-         else if (setjmp (float_error))
+
+         /* Setup input for fold_convert_1() */
+         args.arg1 = arg1;
+         args.type = type;
+         
+         if (do_float_handler (fold_convert_1, (PTR) &args))
            {
+             /* Receive output from fold_convert_1() */
+             t = args.t;
+           }
+         else
+           {
+             /* We got an exception from fold_convert_1() */
              overflow = 1;
              t = copy_node (arg1);
-             goto got_it;
            }
-         set_float_handler (float_error);
-
-         t = build_real (type, real_value_truncate (TYPE_MODE (type),
-                                                    TREE_REAL_CST (arg1)));
-         set_float_handler (NULL_PTR);
 
-       got_it:
          TREE_OVERFLOW (t)
            = TREE_OVERFLOW (arg1) | force_fit_type (t, overflow);
          TREE_CONSTANT_OVERFLOW (t)
@@ -1602,8 +1963,7 @@ fold_convert (t, arg1)
   return t;
 }
 \f
-/* Return an expr equal to X but certainly not valid as an lvalue.
-   Also make sure it is not valid as an null pointer constant.  */
+/* Return an expr equal to X but certainly not valid as an lvalue.  */
 
 tree
 non_lvalue (x)
@@ -1617,18 +1977,7 @@ non_lvalue (x)
       || TREE_CODE (x) == REAL_CST
       || TREE_CODE (x) == STRING_CST
       || TREE_CODE (x) == ADDR_EXPR)
-    {
-      if (TREE_CODE (x) == INTEGER_CST && integer_zerop (x))
-       {
-         /* Use NOP_EXPR instead of NON_LVALUE_EXPR
-            so convert_for_assignment won't strip it.
-            This is so this 0 won't be treated as a null pointer constant.  */
-         result = build1 (NOP_EXPR, TREE_TYPE (x), x);
-         TREE_CONSTANT (result) = TREE_CONSTANT (x);
-         return result;
-       }
-      return x;
-    }
+    return x;
 
   result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
   TREE_CONSTANT (result) = TREE_CONSTANT (x);
@@ -1771,8 +2120,8 @@ operand_equal_p (arg0, arg1, only_const)
       case REAL_CST:
        return (! TREE_CONSTANT_OVERFLOW (arg0)
                && ! TREE_CONSTANT_OVERFLOW (arg1)
-               && REAL_VALUES_EQUAL (TREE_REAL_CST (arg0),
-                                     TREE_REAL_CST (arg1)));
+               && REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0),
+                                         TREE_REAL_CST (arg1)));
 
       case COMPLEX_CST:
        return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1),
@@ -1789,6 +2138,8 @@ operand_equal_p (arg0, arg1, only_const)
       case ADDR_EXPR:
        return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
                                0);
+      default:
+       break;
       }
 
   if (only_const)
@@ -1846,11 +2197,18 @@ operand_equal_p (arg0, arg1, only_const)
                                      TREE_OPERAND (arg1, 1), 0)
                  && operand_equal_p (TREE_OPERAND (arg0, 2),
                                      TREE_OPERAND (arg1, 2), 0));
+       default:
+         return 0;
        }
-      break;
-    }
 
-  return 0;
+    case 'e':
+      if (TREE_CODE (arg0) == RTL_EXPR)
+       return rtx_equal_p (RTL_EXPR_RTL (arg0), RTL_EXPR_RTL (arg1));
+      return 0;
+      
+    default:
+      return 0;
+    }
 }
 \f
 /* Similar to operand_equal_p, but see if ARG0 might have been made by
@@ -1864,7 +2222,7 @@ operand_equal_for_comparison_p (arg0, arg1, other)
      tree other;
 {
   int unsignedp1, unsignedpo;
-  tree primarg1, primother;
+  tree primarg0, primarg1, primother;
   unsigned correct_width;
 
   if (operand_equal_p (arg0, arg1, 0))
@@ -1874,6 +2232,14 @@ operand_equal_for_comparison_p (arg0, arg1, other)
       || ! INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
     return 0;
 
+  /* Discard any conversions that don't change the modes of ARG0 and ARG1
+     and see if the inner values are the same.  This removes any
+     signedness comparison, which doesn't matter here.  */
+  primarg0 = arg0, primarg1 = arg1;
+  STRIP_NOPS (primarg0);  STRIP_NOPS (primarg1);
+  if (operand_equal_p (primarg0, primarg1, 0))
+    return 1;
+
   /* Duplicate what shorten_compare does to ARG1 and see if that gives the
      actual comparison operand, ARG0.
 
@@ -2001,9 +2367,10 @@ twoval_comparison_p (arg, cval1, cval2, save_p)
        return 0;
 
       return 1;
-    }
 
-  return 0;
+    default:
+      return 0;
+    }
 }
 \f
 /* ARG is a tree that is known to contain just arithmetic operations and
@@ -2058,7 +2425,10 @@ eval_subst (arg, old0, new0, old1, new1)
                                          old0, new0, old1, new1),
                              eval_subst (TREE_OPERAND (arg, 2),
                                          old0, new0, old1, new1)));
+       default:
+         break;
        }
+      /* fall through - ??? */
 
     case '<':
       {
@@ -2081,9 +2451,10 @@ eval_subst (arg, old0, new0, old1, new1)
 
        return fold (build (code, type, arg0, arg1));
       }
-    }
 
-  return arg;
+    default:
+      return arg;
+    }
 }
 \f
 /* Return a tree for the case when the result of an expression is RESULT
@@ -2142,7 +2513,7 @@ invert_truthvalue (arg)
   if (TREE_CODE_CLASS (code) == '<')
     {
       if (FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0)))
-         && code != NE_EXPR && code != EQ_EXPR)
+         && !flag_fast_math && code != NE_EXPR && code != EQ_EXPR)
        return build1 (TRUTH_NOT_EXPR, type, arg);
       else
        return build (invert_tree_comparison (code), type,
@@ -2221,6 +2592,9 @@ invert_truthvalue (arg)
     case CLEANUP_POINT_EXPR:
       return build1 (CLEANUP_POINT_EXPR, type,
                     invert_truthvalue (TREE_OPERAND (arg, 0)));
+
+    default:
+      break;
     }
   if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE)
     abort ();
@@ -2293,7 +2667,7 @@ make_bit_field_ref (inner, type, bitsize, bitpos, unsignedp)
      int unsignedp;
 {
   tree result = build (BIT_FIELD_REF, type, inner,
-                      size_int (bitsize), size_int (bitpos));
+                      size_int (bitsize), bitsize_int (bitpos, 0L));
 
   TREE_UNSIGNED (result) = unsignedp;
 
@@ -2327,15 +2701,15 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
      tree lhs, rhs;
 {
   int lbitpos, lbitsize, rbitpos, rbitsize;
-  int lnbitpos, lnbitsize, rnbitpos, rnbitsize;
+  int lnbitpos, lnbitsize, rnbitpos = 0, rnbitsize = 0;
   tree type = TREE_TYPE (lhs);
   tree signed_type, unsigned_type;
   int const_p = TREE_CODE (rhs) == INTEGER_CST;
-  enum machine_mode lmode, rmode, lnmode, rnmode;
+  enum machine_mode lmode, rmode, lnmode, rnmode = VOIDmode;
   int lunsignedp, runsignedp;
   int lvolatilep = 0, rvolatilep = 0;
   int alignment;
-  tree linner, rinner;
+  tree linner, rinner = NULL_TREE;
   tree mask;
   tree offset;
 
@@ -2440,8 +2814,8 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
                                        convert (unsigned_type, rhs),
                                        size_int (lbitsize), 0)))
        {
-         warning ("comparison is always %s due to width of bitfield",
-                  code == NE_EXPR ? "one" : "zero");
+         warning ("comparison is always %d due to width of bitfield",
+                  code == NE_EXPR);
          return convert (compare_type,
                          (code == NE_EXPR
                           ? integer_one_node : integer_zero_node));
@@ -2453,8 +2827,8 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
                              size_int (lbitsize - 1), 0);
       if (! integer_zerop (tem) && ! integer_all_onesp (tem))
        {
-         warning ("comparison is always %s due to width of bitfield",
-                  code == NE_EXPR ? "one" : "zero");
+         warning ("comparison is always %d due to width of bitfield",
+                  code == NE_EXPR);
          return convert (compare_type,
                          (code == NE_EXPR
                           ? integer_one_node : integer_zero_node));
@@ -2507,7 +2881,7 @@ 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.
+   *PAND_MASK is set to 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.  */
@@ -2635,13 +3009,13 @@ simple_operand_p (exp)
    are converted to
        (unsigned) (X - 2) <= 3
 
-   We decribe each set of comparisons as being either inside or outside
+   We describe each set of comparisons as being either inside or outside
    a range, using a variable named like IN_P, and then describe the
    range with a lower and upper bound.  If one of the bounds is omitted,
    it represents either the highest or lowest value of the type.
 
    In the comments below, we represent a range by two numbers in brackets
-   preceeded by a "+" to designate being inside that range, or a "-" to
+   preceded by a "+" to designate being inside that range, or a "-" to
    designate being outside that range, so the condition can be inverted by
    flipping the prefix.  An omitted bound is represented by a "-".  For
    example, "- [-, 10]" means being outside the range starting at the lowest
@@ -2688,21 +3062,35 @@ range_binop (code, type, arg0, upper0_p, arg1, upper1_p)
     return 0;
 
   /* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0
-     for neither.  Then compute our result treating them as never equal
-     and comparing bounds to non-bounds as above.  */
+     for neither.  In real maths, we cannot assume open ended ranges are
+     the same. But, this is computer arithmetic, where numbers are finite.
+     We can therefore make the transformation of any unbounded range with
+     the value Z, Z being greater than any representable number. This permits
+     us to treat unbounded ranges as equal. */
   sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1);
   sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1);
   switch (code)
     {
-    case EQ_EXPR:  case NE_EXPR:
-      result = (code == NE_EXPR);
+    case EQ_EXPR:
+      result = sgn0 == sgn1;
       break;
-    case LT_EXPR:  case LE_EXPR:
+    case NE_EXPR:
+      result = sgn0 != sgn1;
+      break;
+    case LT_EXPR:
       result = sgn0 < sgn1;
       break;
-    case GT_EXPR:  case GE_EXPR:
+    case LE_EXPR:
+      result = sgn0 <= sgn1;
+      break;
+    case GT_EXPR:
       result = sgn0 > sgn1;
       break;
+    case GE_EXPR:
+      result = sgn0 >= sgn1;
+      break;
+    default:
+      abort ();
     }
 
   return convert (type, result ? integer_one_node : integer_zero_node);
@@ -2721,7 +3109,8 @@ make_range (exp, pin_p, plow, phigh)
      tree *plow, *phigh;
 {
   enum tree_code code;
-  tree arg0, arg1, type;
+  tree arg0, arg1, type = NULL_TREE;
+  tree orig_type = NULL_TREE;
   int in_p, n_in_p;
   tree low, high, n_low, n_high;
 
@@ -2736,10 +3125,25 @@ make_range (exp, pin_p, plow, phigh)
   while (1)
     {
       code = TREE_CODE (exp);
-      arg0 = TREE_OPERAND (exp, 0), arg1 = TREE_OPERAND (exp, 1);
-      if (TREE_CODE_CLASS (code) == '<' || TREE_CODE_CLASS (code) == '1'
-         || TREE_CODE_CLASS (code) == '2')
-       type = TREE_TYPE (arg0);
+
+      if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+       {
+         arg0 = TREE_OPERAND (exp, 0);
+         if (TREE_CODE_CLASS (code) == '<' 
+             || TREE_CODE_CLASS (code) == '1'
+             || TREE_CODE_CLASS (code) == '2')
+           type = TREE_TYPE (arg0);
+         if (TREE_CODE_CLASS (code) == '2' 
+             || TREE_CODE_CLASS (code) == '<'
+             || (TREE_CODE_CLASS (code) == 'e' 
+                 && tree_code_length[(int) code] > 1))
+           arg1 = TREE_OPERAND (exp, 1);
+       }
+
+      /* Set ORIG_TYPE as soon as TYPE is non-null so that we do not
+        lose a cast by accident.  */
+      if (type != NULL_TREE && orig_type == NULL_TREE)
+       orig_type = type;
 
       switch (code)
        {
@@ -2779,6 +3183,8 @@ make_range (exp, pin_p, plow, phigh)
            case LE_EXPR:  /* + [-, c] */
              in_p = ! in_p, low = 0, high = arg1;
              break;
+           default:
+             abort ();
            }
 
          exp = arg0;
@@ -2857,19 +3263,81 @@ make_range (exp, pin_p, plow, phigh)
          continue;
 
        case NOP_EXPR:  case NON_LVALUE_EXPR:  case CONVERT_EXPR:
+         if (TYPE_PRECISION (type) > TYPE_PRECISION (orig_type))
+           break;
+
          if (! INTEGRAL_TYPE_P (type)
              || (low != 0 && ! int_fits_type_p (low, type))
              || (high != 0 && ! int_fits_type_p (high, type)))
            break;
 
-         if (low != 0)
-           low = convert (type, low);
+         n_low = low, n_high = high;
+
+         if (n_low != 0)
+           n_low = convert (type, n_low);
+
+         if (n_high != 0)
+           n_high = convert (type, n_high);
+
+         /* If we're converting from an unsigned to a signed type,
+            we will be doing the comparison as unsigned.  The tests above
+            have already verified that LOW and HIGH are both positive.
 
-         if (high != 0)
-           high = convert (type, high);
+            So we have to make sure that the original unsigned value will
+            be interpreted as positive.  */
+         if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp)))
+           {
+             tree equiv_type = type_for_mode (TYPE_MODE (type), 1);
+             tree high_positive;
+
+             /* A range without an upper bound is, naturally, unbounded.
+                Since convert would have cropped a very large value, use
+                 the max value for the destination type.  */
+
+             high_positive = TYPE_MAX_VALUE (equiv_type);
+             if (!high_positive)
+               {
+                 high_positive = TYPE_MAX_VALUE (type);
+                 if (!high_positive)
+                   abort();
+               }
+             high_positive = fold (build (RSHIFT_EXPR, type,
+                                          convert (type, high_positive),
+                                          convert (type, integer_one_node)));
+                       
+             /* If the low bound is specified, "and" the range with the
+                range for which the original unsigned value will be
+                positive.  */
+             if (low != 0)
+               {
+                 if (! merge_ranges (&n_in_p, &n_low, &n_high,
+                                     1, n_low, n_high,
+                                     1, convert (type, integer_zero_node),
+                                     high_positive))
+                   break;
+
+                 in_p = (n_in_p == in_p);
+               }
+             else
+               {
+                 /* Otherwise, "or" the range with the range of the input
+                    that will be interpreted as negative.  */
+                 if (! merge_ranges (&n_in_p, &n_low, &n_high,
+                                     0, n_low, n_high,
+                                     1, convert (type, integer_zero_node),
+                                     high_positive))
+                   break;
+
+                 in_p = (in_p != n_in_p);
+               }
+           }
 
          exp = arg0;
+         low = n_low, high = n_high;
          continue;
+
+       default:
+         break;
        }
 
       break;
@@ -2955,15 +3423,20 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1)
   tree tem;
   int in_p;
   tree low, high;
-
-  /* Make range 0 be the range that starts first.  Swap them if it isn't.  */
+  int lowequal = ((low0 == 0 && low1 == 0)
+                 || integer_onep (range_binop (EQ_EXPR, integer_type_node,
+                                               low0, 0, low1, 0)));
+  int highequal = ((high0 == 0 && high1 == 0)
+                  || integer_onep (range_binop (EQ_EXPR, integer_type_node,
+                                                high0, 1, high1, 1)));
+
+  /* Make range 0 be the range that starts first, or ends last if they
+     start at the same value.  Swap them if it isn't.  */
   if (integer_onep (range_binop (GT_EXPR, integer_type_node, 
                                 low0, 0, low1, 0))
-      || (((low0 == 0 && low1 == 0)
-          || integer_onep (range_binop (EQ_EXPR, integer_type_node,
-                                        low0, 0, low1, 0)))
+      || (lowequal
          && integer_onep (range_binop (GT_EXPR, integer_type_node,
-                                       high0, 1, high1, 1))))
+                                       high1, 1, high0, 1))))
     {
       temp = in0_p, in0_p = in1_p, in1_p = temp;
       tem = low0, low0 = low1, low1 = tem;
@@ -2995,27 +3468,32 @@ merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1)
 
   else if (in0_p && ! in1_p)
     {
-      /* 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 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 they don't overlap, the result is the first range.  If they are
+        equal, the result is false.  If the second range is a subset of the
+        first, and the ranges begin at the same place, we go from just after
+        the end of the first range to the end of the second.  If the second
+        range is not a subset of the first, or if it is a subset and both
+        ranges end at the same place, the range starts at the start of the
+        first range and ends just before the second range.
+        Otherwise, we can't describe this as a single range.  */
       if (no_overlap)
        in_p = 1, low = low0, high = high0;
-      else if (subset
-              && integer_zerop (range_binop (EQ_EXPR, integer_type_node,
-                                             high0, 1, high1, 0)))
-       return 0;
-      else if (integer_onep (range_binop (EQ_EXPR, integer_type_node,
-                                         low0, 0, low1, 0)))
+      else if (lowequal && highequal)
        in_p = 0, low = high = 0;
-      else
+      else if (subset && lowequal)
+       {
+         in_p = 1, high = high0;
+         low = range_binop (PLUS_EXPR, NULL_TREE, high1, 0,
+                            integer_one_node, 0);        
+       }
+      else if (! subset || highequal)
        {
          in_p = 1, low = low0;
          high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0,
                              integer_one_node, 0);
        }
+      else
+       return 0;
     }
 
   else if (! in0_p && in1_p)
@@ -3107,14 +3585,16 @@ fold_range_test (exp)
           && operand_equal_p (lhs, rhs, 0))
     {
       /* If simple enough, just rewrite.  Otherwise, make a SAVE_EXPR
-        unless we are at top level, in which case we can't do this.  */
+        unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
+        which cases we can't do this.  */
       if (simple_operand_p (lhs))
        return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
                      ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
                      TREE_TYPE (exp), TREE_OPERAND (exp, 0),
                      TREE_OPERAND (exp, 1));
 
-      else if (current_function_decl != 0)
+      else if (current_function_decl != 0
+              && ! contains_placeholder_p (lhs))
        {
          tree common = save_expr (lhs);
 
@@ -3129,8 +3609,8 @@ fold_range_test (exp)
                          TREE_TYPE (exp), lhs, rhs);
        }
     }
-  else
-    return 0;
+
+  return 0;
 }
 \f
 /* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
@@ -3230,7 +3710,7 @@ fold_truthop (code, truth_type, lhs, rhs)
   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;
+  tree lntype, rntype, result;
   int first_bit, end_bit;
   int volatilep;
 
@@ -3325,7 +3805,17 @@ fold_truthop (code, truth_type, lhs, rhs)
   if (lcode != wanted_code)
     {
       if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask))
-       l_const = ll_mask;
+       {
+         if (ll_unsignedp || tree_log2 (ll_mask) + 1 < ll_bitsize)
+           l_const = ll_mask;
+       else
+         /* Since ll_arg is a single bit bit mask, we can sign extend
+            it appropriately with a NEGATE_EXPR.
+            l_const is made a signed value here, but since for l_const != NULL
+            lr_unsignedp is not used, we don't need to clear the latter.  */
+         l_const = fold (build1 (NEGATE_EXPR, TREE_TYPE (ll_arg),
+                                 convert (TREE_TYPE (ll_arg), ll_mask)));
+       }
       else
        return 0;
     }
@@ -3333,7 +3823,14 @@ fold_truthop (code, truth_type, lhs, rhs)
   if (rcode != wanted_code)
     {
       if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask))
-       r_const = rl_mask;
+       {
+         if (rl_unsignedp || tree_log2 (rl_mask) + 1 < rl_bitsize)
+           r_const = rl_mask;
+       else
+         /* This is analogous to the code for l_const above.  */
+         r_const = fold (build1 (NEGATE_EXPR, TREE_TYPE (rl_arg),
+                                 convert (TREE_TYPE (rl_arg), rl_mask)));
+       }
       else
        return 0;
     }
@@ -3351,7 +3848,7 @@ fold_truthop (code, truth_type, lhs, rhs)
 
   lnbitsize = GET_MODE_BITSIZE (lnmode);
   lnbitpos = first_bit & ~ (lnbitsize - 1);
-  type = type_for_size (lnbitsize, 1);
+  lntype = type_for_size (lnbitsize, 1);
   xll_bitpos = ll_bitpos - lnbitpos, xrl_bitpos = rl_bitpos - lnbitpos;
 
   if (BYTES_BIG_ENDIAN)
@@ -3360,23 +3857,22 @@ fold_truthop (code, truth_type, lhs, rhs)
       xrl_bitpos = lnbitsize - xrl_bitpos - rl_bitsize;
     }
 
-  ll_mask = const_binop (LSHIFT_EXPR, convert (type, ll_mask),
+  ll_mask = const_binop (LSHIFT_EXPR, convert (lntype, ll_mask),
                         size_int (xll_bitpos), 0);
-  rl_mask = const_binop (LSHIFT_EXPR, convert (type, rl_mask),
+  rl_mask = const_binop (LSHIFT_EXPR, convert (lntype, rl_mask),
                         size_int (xrl_bitpos), 0);
 
   if (l_const)
     {
-      l_const = convert (type, l_const);
+      l_const = convert (lntype, 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,
-                                                     type, ll_mask)),
+                                                     lntype, ll_mask)),
                                        0)))
        {
-         warning ("comparison is always %s",
-                  wanted_code == NE_EXPR ? "one" : "zero");
+         warning ("comparison is always %d", wanted_code == NE_EXPR);
          
          return convert (truth_type,
                          wanted_code == NE_EXPR
@@ -3385,17 +3881,16 @@ fold_truthop (code, truth_type, lhs, rhs)
     }
   if (r_const)
     {
-      r_const = convert (type, r_const);
+      r_const = convert (lntype, 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,
-                                                     type, rl_mask)),
+                                                     lntype, rl_mask)),
                                        0)))
        {
-         warning ("comparison is always %s",
-                  wanted_code == NE_EXPR ? "one" : "zero");
-         
+         warning ("comparison is always %d", wanted_code == NE_EXPR);
+
          return convert (truth_type,
                          wanted_code == NE_EXPR
                          ? integer_one_node : integer_zero_node);
@@ -3424,6 +3919,7 @@ fold_truthop (code, truth_type, lhs, rhs)
 
       rnbitsize = GET_MODE_BITSIZE (rnmode);
       rnbitpos = first_bit & ~ (rnbitsize - 1);
+      rntype = type_for_size (rnbitsize, 1);
       xlr_bitpos = lr_bitpos - rnbitpos, xrr_bitpos = rr_bitpos - rnbitpos;
 
       if (BYTES_BIG_ENDIAN)
@@ -3432,47 +3928,83 @@ fold_truthop (code, truth_type, lhs, rhs)
          xrr_bitpos = rnbitsize - xrr_bitpos - rr_bitsize;
        }
 
-      lr_mask = const_binop (LSHIFT_EXPR, convert (type, lr_mask),
+      lr_mask = const_binop (LSHIFT_EXPR, convert (rntype, lr_mask),
                             size_int (xlr_bitpos), 0);
-      rr_mask = const_binop (LSHIFT_EXPR, convert (type, rr_mask),
+      rr_mask = const_binop (LSHIFT_EXPR, convert (rntype, rr_mask),
                             size_int (xrr_bitpos), 0);
 
       /* Make a mask that corresponds to both fields being compared.
-        Do this for both items being compared.  If the masks agree,
-        we can do this by masking both and comparing the masked
+        Do this for both items being compared.  If the operands are the
+        same size and the bits being compared are in the same position
+        then we can do this by masking both and comparing the masked
         results.  */
       ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
       lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask, 0);
-      if (operand_equal_p (ll_mask, lr_mask, 0) && lnbitsize == rnbitsize)
+      if (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos)
        {
-         lhs = make_bit_field_ref (ll_inner, type, lnbitsize, lnbitpos,
+         lhs = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
                                    ll_unsignedp || rl_unsignedp);
-         rhs = make_bit_field_ref (lr_inner, type, rnbitsize, rnbitpos,
-                                   lr_unsignedp || rr_unsignedp);
          if (! all_ones_mask_p (ll_mask, lnbitsize))
-           {
-             lhs = build (BIT_AND_EXPR, type, lhs, ll_mask);
-             rhs = build (BIT_AND_EXPR, type, rhs, ll_mask);
-           }
+           lhs = build (BIT_AND_EXPR, lntype, lhs, ll_mask);
+
+         rhs = make_bit_field_ref (lr_inner, rntype, rnbitsize, rnbitpos,
+                                   lr_unsignedp || rr_unsignedp);
+         if (! all_ones_mask_p (lr_mask, rnbitsize))
+           rhs = build (BIT_AND_EXPR, rntype, rhs, lr_mask);
+
          return build (wanted_code, truth_type, lhs, rhs);
        }
 
       /* There is still another way we can do something:  If both pairs of
         fields being compared are adjacent, we may be able to make a wider
-        field containing them both.  */
+        field containing them both.
+
+        Note that we still must mask the lhs/rhs expressions.  Furthermore,
+        the mask must be shifted to account for the shift done by 
+        make_bit_field_ref.  */
       if ((ll_bitsize + ll_bitpos == rl_bitpos
           && lr_bitsize + lr_bitpos == rr_bitpos)
          || (ll_bitpos == rl_bitpos + rl_bitsize
              && lr_bitpos == rr_bitpos + rr_bitsize))
-       return build (wanted_code, truth_type,
-                     make_bit_field_ref (ll_inner, type,
-                                         ll_bitsize + rl_bitsize,
-                                         MIN (ll_bitpos, rl_bitpos),
-                                         ll_unsignedp),
-                     make_bit_field_ref (lr_inner, type,
-                                         lr_bitsize + rr_bitsize,
-                                         MIN (lr_bitpos, rr_bitpos),
-                                         lr_unsignedp));
+       {
+         tree type;
+
+         lhs = make_bit_field_ref (ll_inner, lntype, ll_bitsize + rl_bitsize,
+                                   MIN (ll_bitpos, rl_bitpos), ll_unsignedp);
+         rhs = make_bit_field_ref (lr_inner, rntype, lr_bitsize + rr_bitsize,
+                                   MIN (lr_bitpos, rr_bitpos), lr_unsignedp);
+
+         ll_mask = const_binop (RSHIFT_EXPR, ll_mask,
+                                size_int (MIN (xll_bitpos, xrl_bitpos)), 0);
+         lr_mask = const_binop (RSHIFT_EXPR, lr_mask,
+                                size_int (MIN (xlr_bitpos, xrr_bitpos)), 0);
+
+         /* Convert to the smaller type before masking out unwanted bits.  */
+         type = lntype;
+         if (lntype != rntype)
+           {
+             if (lnbitsize > rnbitsize)
+               {
+                 lhs = convert (rntype, lhs);
+                 ll_mask = convert (rntype, ll_mask);
+                 type = rntype;
+               }
+             else if (lnbitsize < rnbitsize)
+               {
+                 rhs = convert (lntype, rhs);
+                 lr_mask = convert (lntype, lr_mask);
+                 type = lntype;
+               }
+           }
+
+         if (! all_ones_mask_p (ll_mask, ll_bitsize + rl_bitsize))
+           lhs = build (BIT_AND_EXPR, type, lhs, ll_mask);
+
+         if (! all_ones_mask_p (lr_mask, lr_bitsize + rr_bitsize))
+           rhs = build (BIT_AND_EXPR, type, rhs, lr_mask);
+
+         return build (wanted_code, truth_type, lhs, rhs);
+       }
 
       return 0;
     }
@@ -3493,7 +4025,7 @@ fold_truthop (code, truth_type, lhs, rhs)
        }
       else
        {
-         warning ("`and' of mutually exclusive equal-tests is always zero");
+         warning ("`and' of mutually exclusive equal-tests is always 0");
          return convert (truth_type, integer_zero_node);
        }
     }
@@ -3502,12 +4034,12 @@ fold_truthop (code, truth_type, lhs, rhs)
      reference we will make.  Unless the mask is all ones the width of
      that field, perform the mask operation.  Then compare with the
      merged constant.  */
-  result = make_bit_field_ref (ll_inner, type, lnbitsize, lnbitpos,
+  result = make_bit_field_ref (ll_inner, lntype, lnbitsize, lnbitpos,
                               ll_unsignedp || rl_unsignedp);
 
   ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask, 0);
   if (! all_ones_mask_p (ll_mask, lnbitsize))
-    result = build (BIT_AND_EXPR, type, result, ll_mask);
+    result = build (BIT_AND_EXPR, lntype, result, ll_mask);
 
   return build (wanted_code, truth_type, result,
                const_binop (BIT_IOR_EXPR, l_const, r_const, 0));
@@ -3522,7 +4054,6 @@ strip_compound_expr (t, s)
      tree t;
      tree s;
 {
-  tree type = TREE_TYPE (t);
   enum tree_code code = TREE_CODE (t);
 
   /* See if this is the COMPOUND_EXPR we want to eliminate.  */
@@ -3550,6 +4081,48 @@ strip_compound_expr (t, s)
   return t;
 }
 \f
+/* Return a node which has the indicated constant VALUE (either 0 or
+   1), and is of the indicated TYPE.  */
+
+static tree
+constant_boolean_node (value, type)
+     int value;
+     tree type;
+{
+  if (type == integer_type_node)
+    return value ? integer_one_node : integer_zero_node;
+  else if (TREE_CODE (type) == BOOLEAN_TYPE)
+    return truthvalue_conversion (value ? integer_one_node :
+                                 integer_zero_node); 
+  else 
+    {
+      tree t = build_int_2 (value, 0);
+      TREE_TYPE (t) = type;
+      return t;
+    }
+}
+
+/* Utility function for the following routine, to see how complex a nesting of
+   COND_EXPRs can be.  EXPR is the expression and LIMIT is a count beyond which
+   we don't care (to avoid spending too much time on complex expressions.).  */
+
+static int
+count_cond (expr, lim)
+     tree expr;
+     int lim;
+{
+  int true, false;
+
+  if (TREE_CODE (expr) != COND_EXPR)
+    return 0;
+  else if (lim <= 0)
+    return 0;
+
+  true = count_cond (TREE_OPERAND (expr, 1), lim - 1);
+  false = count_cond (TREE_OPERAND (expr, 2), lim - 1 - true);
+  return MIN (lim, 1 + true + false);
+}
+\f
 /* Perform constant folding and related simplification of EXPR.
    The related simplifications include x*1 => x, x*0 => 0, etc.,
    and application of the associative law.
@@ -3566,7 +4139,7 @@ fold (expr)
   tree t1 = NULL_TREE;
   tree tem;
   tree type = TREE_TYPE (expr);
-  register tree arg0, arg1;
+  register tree arg0 = NULL_TREE, arg1 = NULL_TREE;
   register enum tree_code code = TREE_CODE (t);
   register int kind;
   int invert;
@@ -3589,6 +4162,10 @@ fold (expr)
       return t;
     }
   
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+  check_max_integer_computation_mode (expr);
+#endif
+
   kind = TREE_CODE_CLASS (code);
   if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
     {
@@ -3769,9 +4346,14 @@ fold (expr)
       else if ((TREE_CODE (arg1) == COND_EXPR
                || (TREE_CODE_CLASS (TREE_CODE (arg1)) == '<'
                    && TREE_CODE_CLASS (code) != '<'))
-              && (! TREE_SIDE_EFFECTS (arg0) || current_function_decl != 0))
+              && (TREE_CODE (arg0) != COND_EXPR
+                  || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
+              && (! TREE_SIDE_EFFECTS (arg0)
+                  || (current_function_decl != 0
+                      && ! contains_placeholder_p (arg0))))
        {
          tree test, true_value, false_value;
+         tree lhs = 0, rhs = 0;
 
          if (TREE_CODE (arg1) == COND_EXPR)
            {
@@ -3794,26 +4376,37 @@ fold (expr)
             to make this SAVE_EXPR.  Since we do this optimization
             primarily to see if we do end up with constant and this
             SAVE_EXPR interferes with later optimizations, suppressing
-            it when we can is important.  */
+            it when we can is important.
 
-         if (TREE_CODE (arg0) != SAVE_EXPR
+            If we are not in a function, we can't make a SAVE_EXPR, so don't
+            try to do so.  Don't try to see if the result is a constant
+            if an arm is a COND_EXPR since we get exponential behavior
+            in that case.  */
+
+         if (TREE_CODE (arg0) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+             && current_function_decl != 0
              && ((TREE_CODE (arg0) != VAR_DECL
                   && TREE_CODE (arg0) != PARM_DECL)
                  || TREE_SIDE_EFFECTS (arg0)))
            {
-             tree lhs = fold (build (code, type, arg0, true_value));
-             tree rhs = fold (build (code, type, arg0, false_value));
+             if (TREE_CODE (true_value) != COND_EXPR)
+               lhs = fold (build (code, type, arg0, true_value));
 
-             if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs))
-               return fold (build (COND_EXPR, type, test, lhs, rhs));
+             if (TREE_CODE (false_value) != COND_EXPR)
+               rhs = fold (build (code, type, arg0, false_value));
 
-             if (current_function_decl != 0)
-               arg0 = save_expr (arg0);
+             if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+                 && (rhs == 0 || !TREE_CONSTANT (rhs)))
+               arg0 = save_expr (arg0), lhs = rhs = 0;
            }
 
-         test = fold (build (COND_EXPR, type, test,
-                             fold (build (code, type, arg0, true_value)),
-                             fold (build (code, type, arg0, false_value))));
+         if (lhs == 0)
+           lhs = fold (build (code, type, arg0, true_value));
+         if (rhs == 0)
+           rhs = fold (build (code, type, arg0, false_value));
+
+         test = fold (build (COND_EXPR, type, test, lhs, rhs));
+
          if (TREE_CODE (arg0) == SAVE_EXPR)
            return build (COMPOUND_EXPR, type,
                          convert (void_type_node, arg0),
@@ -3828,9 +4421,14 @@ fold (expr)
       else if ((TREE_CODE (arg0) == COND_EXPR
                || (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
                    && TREE_CODE_CLASS (code) != '<'))
-              && (! TREE_SIDE_EFFECTS (arg1) || current_function_decl != 0))
+              && (TREE_CODE (arg1) != COND_EXPR
+                  || count_cond (arg0, 25) + count_cond (arg1, 25) <= 25)
+              && (! TREE_SIDE_EFFECTS (arg1)
+                  || (current_function_decl != 0
+                      && ! contains_placeholder_p (arg1))))
        {
          tree test, true_value, false_value;
+         tree lhs = 0, rhs = 0;
 
          if (TREE_CODE (arg0) == COND_EXPR)
            {
@@ -3846,25 +4444,30 @@ fold (expr)
              false_value = convert (testtype, integer_zero_node);
            }
 
-         if (TREE_CODE (arg1) != SAVE_EXPR
+         if (TREE_CODE (arg1) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+             && current_function_decl != 0
              && ((TREE_CODE (arg1) != VAR_DECL
                   && TREE_CODE (arg1) != PARM_DECL)
                  || TREE_SIDE_EFFECTS (arg1)))
            {
-             tree lhs = fold (build (code, type, true_value, arg1));
-             tree rhs = fold (build (code, type, false_value, arg1));
+             if (TREE_CODE (true_value) != COND_EXPR)
+               lhs = fold (build (code, type, true_value, arg1));
 
-             if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs)
-                 || TREE_CONSTANT (arg1))
-               return fold (build (COND_EXPR, type, test, lhs, rhs));
+             if (TREE_CODE (false_value) != COND_EXPR)
+               rhs = fold (build (code, type, false_value, arg1));
 
-             if (current_function_decl != 0)
-               arg1 = save_expr (arg1);
+             if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+                 && (rhs == 0 || !TREE_CONSTANT (rhs)))
+               arg1 = save_expr (arg1), lhs = rhs = 0;
            }
 
-         test = fold (build (COND_EXPR, type, test,
-                             fold (build (code, type, true_value, arg1)),
-                             fold (build (code, type, false_value, arg1))));
+         if (lhs == 0)
+           lhs = fold (build (code, type, true_value, arg1));
+
+         if (rhs == 0)
+           rhs = fold (build (code, type, false_value, arg1));
+
+         test = fold (build (COND_EXPR, type, test, lhs, rhs));
          if (TREE_CODE (arg1) == SAVE_EXPR)
            return build (COMPOUND_EXPR, type,
                          convert (void_type_node, arg1),
@@ -3950,6 +4553,13 @@ fold (expr)
              && ! final_ptr)
            return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 
+         /* If we have a sign-extension of a zero-extended value, we can
+            replace that by a single zero-extension.  */
+         if (inside_int && inter_int && final_int
+             && inside_prec < inter_prec && inter_prec < final_prec
+             && inside_unsignedp && !inter_unsignedp)
+           return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+
          /* Two conversions in a row are not needed unless:
             - some conversion is floating-point (overstrict for now), or
             - the intermediate type is narrower than both initial and
@@ -4154,18 +4764,36 @@ fold (expr)
              goto bit_ior;
            }
 
-         /* (A * C) + (B * C) -> (A+B) * C.  Since we are most concerned
-            about the case where C is a constant, just try one of the
-            four possibilities.  */
-
-         if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR
-             && operand_equal_p (TREE_OPERAND (arg0, 1),
-                                 TREE_OPERAND (arg1, 1), 0))
-           return fold (build (MULT_EXPR, type,
-                               fold (build (PLUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 0),
-                                            TREE_OPERAND (arg1, 0))),
-                               TREE_OPERAND (arg0, 1)));
+         if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
+           {
+             tree arg00, arg01, arg10, arg11;
+             tree alt0, alt1, same;
+
+             /* (A * C) + (B * C) -> (A+B) * C.
+                We are most concerned about the case where C is a constant,
+                but other combinations show up during loop reduction.  Since
+                it is not difficult, try all four possibilities.  */
+
+             arg00 = TREE_OPERAND (arg0, 0);
+             arg01 = TREE_OPERAND (arg0, 1);
+             arg10 = TREE_OPERAND (arg1, 0);
+             arg11 = TREE_OPERAND (arg1, 1);
+             same = NULL_TREE;
+
+             if (operand_equal_p (arg01, arg11, 0))
+               same = arg01, alt0 = arg00, alt1 = arg10;
+             else if (operand_equal_p (arg00, arg10, 0))
+               same = arg00, alt0 = arg01, alt1 = arg11;
+             else if (operand_equal_p (arg00, arg11, 0))
+               same = arg00, alt0 = arg01, alt1 = arg10;
+             else if (operand_equal_p (arg01, arg10, 0))
+               same = arg01, alt0 = arg00, alt1 = arg11;
+
+             if (same)
+               return fold (build (MULT_EXPR, type,
+                                   fold (build (PLUS_EXPR, type, alt0, alt1)),
+                                   same));
+           }
        }
       /* In IEEE floating point, x+0 may not equal x.  */
       else if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
@@ -4380,7 +5008,8 @@ fold (expr)
          if (real_onep (arg1))
            return non_lvalue (convert (type, arg0));
          /* x*2 is x+x */
-         if (! wins && real_twop (arg1) && current_function_decl != 0)
+         if (! wins && real_twop (arg1) && current_function_decl != 0
+             && ! contains_placeholder_p (arg0))
            {
              tree arg = save_expr (arg0);
              return build (PLUS_EXPR, type, arg, arg);
@@ -4418,6 +5047,8 @@ fold (expr)
 
          tree01 = TREE_OPERAND (arg0, 1);
          tree11 = TREE_OPERAND (arg1, 1);
+         STRIP_NOPS (tree01);
+         STRIP_NOPS (tree11);
          code01 = TREE_CODE (tree01);
          code11 = TREE_CODE (tree11);
          if (code01 == INTEGER_CST
@@ -4428,22 +5059,40 @@ fold (expr)
              == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
            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);
+         else if (code11 == MINUS_EXPR)
+           {
+             tree tree110, tree111;
+             tree110 = TREE_OPERAND (tree11, 0);
+             tree111 = TREE_OPERAND (tree11, 1);
+             STRIP_NOPS (tree110);
+             STRIP_NOPS (tree111);
+             if (TREE_CODE (tree110) == INTEGER_CST
+                 && TREE_INT_CST_HIGH (tree110) == 0
+                 && (TREE_INT_CST_LOW (tree110)
+                     == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+                 && operand_equal_p (tree01, tree111, 0))
+               return build ((code0 == LSHIFT_EXPR 
+                              ? LROTATE_EXPR 
+                              : RROTATE_EXPR),
+                             type, TREE_OPERAND (arg0, 0), tree01);
+           }
+         else if (code01 == MINUS_EXPR)
+           {
+             tree tree010, tree011;
+             tree010 = TREE_OPERAND (tree01, 0);
+             tree011 = TREE_OPERAND (tree01, 1);
+             STRIP_NOPS (tree010);
+             STRIP_NOPS (tree011);
+             if (TREE_CODE (tree010) == INTEGER_CST
+                 && TREE_INT_CST_HIGH (tree010) == 0
+                 && (TREE_INT_CST_LOW (tree010)
+                     == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+                 && operand_equal_p (tree11, tree011, 0))
+               return build ((code0 != LSHIFT_EXPR 
+                              ? LROTATE_EXPR 
+                              : RROTATE_EXPR),
+                              type, TREE_OPERAND (arg0, 0), tree11);
+           }
        }
 
       goto associate;
@@ -4548,6 +5197,16 @@ fold (expr)
       if (integer_zerop (arg1))
        return t;
 
+      /* If arg0 is a multiple of arg1, then rewrite to the fastest div
+        operation, EXACT_DIV_EXPR.
+
+        Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now.
+        At one time others generated faster code, it's not clear if they do
+        after the last round to changes to the DIV code in expmed.c.  */
+      if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
+         && multiple_of_p (type, arg0, arg1))
+       return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
+
       /* If we have ((a / C1) / C2) where both division are the same type, try
         to simplify.  First see if C1 * C2 overflows or not.  */
       if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
@@ -4586,6 +5245,37 @@ fold (expr)
 
          STRIP_NOPS (xarg0);
 
+         /* Look inside the dividend and simplify using EXACT_DIV_EXPR
+            if possible.  */
+         if (TREE_CODE (xarg0) == MULT_EXPR
+             && multiple_of_p (type, TREE_OPERAND (xarg0, 0), arg1))
+           {
+             tree t;
+
+             t = fold (build (MULT_EXPR, type,
+                              fold (build (EXACT_DIV_EXPR, type,
+                                           TREE_OPERAND (xarg0, 0), arg1)),
+                              TREE_OPERAND (xarg0, 1)));
+             if (have_save_expr)
+               t = save_expr (t);
+             return t;
+
+           }
+
+         if (TREE_CODE (xarg0) == MULT_EXPR
+             && multiple_of_p (type, TREE_OPERAND (xarg0, 1), arg1))
+           {
+             tree t;
+
+             t = fold (build (MULT_EXPR, type,
+                              fold (build (EXACT_DIV_EXPR, type,
+                                           TREE_OPERAND (xarg0, 1), arg1)),
+                              TREE_OPERAND (xarg0, 0)));
+             if (have_save_expr)
+               t = save_expr (t);
+             return t;
+           }
+
          if (TREE_CODE (xarg0) == PLUS_EXPR
              && TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
            c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
@@ -4755,6 +5445,7 @@ fold (expr)
       if (operand_equal_p (arg0, arg1, 0))
        return arg0;
       if (INTEGRAL_TYPE_P (type)
+         && TYPE_MAX_VALUE (type)
          && operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1))
        return omit_one_operand (type, arg1, arg0);
       goto associate;
@@ -4914,7 +5605,7 @@ fold (expr)
         First, see if one arg is constant; find the constant arg
         and the other one.  */
       {
-       tree constop = 0, varop;
+       tree constop = 0, varop = NULL_TREE;
        int constopnum = -1;
 
        if (TREE_CONSTANT (arg1))
@@ -4928,7 +5619,7 @@ fold (expr)
               if CONST+INCR overflows or if foo+incr might overflow.
               This optimization is invalid for floating point due to rounding.
               For pointer types we assume overflow doesn't happen.  */
-           if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+           if (POINTER_TYPE_P (TREE_TYPE (varop))
                || (! FLOAT_TYPE_P (TREE_TYPE (varop))
                    && (code == EQ_EXPR || code == NE_EXPR)))
              {
@@ -4947,11 +5638,35 @@ fold (expr)
                      = TREE_INT_CST_LOW (DECL_SIZE
                                          (TREE_OPERAND
                                           (TREE_OPERAND (varop, 0), 1)));
-
+                   tree mask, unsigned_type;
+                   int precision;
+                   tree folded_compare;
+
+                   /* First check whether the comparison would come out
+                      always the same.  If we don't do that we would
+                      change the meaning with the masking.  */
+                   if (constopnum == 0)
+                     folded_compare = fold (build (code, type, constop,
+                                                   TREE_OPERAND (varop, 0)));
+                   else
+                     folded_compare = fold (build (code, type,
+                                                   TREE_OPERAND (varop, 0),
+                                                   constop));
+                   if (integer_zerop (folded_compare)
+                       || integer_onep (folded_compare))
+                     return omit_one_operand (type, folded_compare, varop);
+
+                   unsigned_type = type_for_size (size, 1);
+                   precision = TYPE_PRECISION (unsigned_type);
+                   mask = build_int_2 (~0, ~0);
+                   TREE_TYPE (mask) = unsigned_type;
+                   force_fit_type (mask, 0);
+                   mask = const_binop (RSHIFT_EXPR, mask,
+                                       size_int (precision - size), 0);
                    newconst = fold (build (BIT_AND_EXPR,
                                            TREE_TYPE (varop), newconst,
                                            convert (TREE_TYPE (varop),
-                                                    build_int_2 (size, 0))));
+                                                    mask)));
                  }
                                                         
 
@@ -4963,7 +5678,7 @@ fold (expr)
          }
        else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
          {
-           if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+           if (POINTER_TYPE_P (TREE_TYPE (varop))
                || (! FLOAT_TYPE_P (TREE_TYPE (varop))
                    && (code == EQ_EXPR || code == NE_EXPR)))
              {
@@ -4980,11 +5695,32 @@ fold (expr)
                      = TREE_INT_CST_LOW (DECL_SIZE
                                          (TREE_OPERAND
                                           (TREE_OPERAND (varop, 0), 1)));
-
+                   tree mask, unsigned_type;
+                   int precision;
+                   tree folded_compare;
+
+                   if (constopnum == 0)
+                     folded_compare = fold (build (code, type, constop,
+                                                   TREE_OPERAND (varop, 0)));
+                   else
+                     folded_compare = fold (build (code, type,
+                                                   TREE_OPERAND (varop, 0),
+                                                   constop));
+                   if (integer_zerop (folded_compare)
+                       || integer_onep (folded_compare))
+                     return omit_one_operand (type, folded_compare, varop);
+
+                   unsigned_type = type_for_size (size, 1);
+                   precision = TYPE_PRECISION (unsigned_type);
+                   mask = build_int_2 (~0, ~0);
+                   TREE_TYPE (mask) = TREE_TYPE (varop);
+                   force_fit_type (mask, 0);
+                   mask = const_binop (RSHIFT_EXPR, mask,
+                                       size_int (precision - size), 0);
                    newconst = fold (build (BIT_AND_EXPR,
                                            TREE_TYPE (varop), newconst,
                                            convert (TREE_TYPE (varop),
-                                                    build_int_2 (size, 0))));
+                                                    mask)));
                  }
                                                         
 
@@ -5014,13 +5750,16 @@ fold (expr)
              arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
              t = build (code, type, TREE_OPERAND (t, 0), arg1);
              break;
+
+           default:
+             break;
            }
        }
 
       /* If this is an EQ or NE comparison with zero and ARG0 is
         (1 << foo) & bar, convert it to (bar >> foo) & 1.  Both require
         two operations, but the latter can be done in one less insn
-        one machine that have only two-operand insns or on which a
+        on machines that have only two-operand insns or on which a
         constant cannot be the first operand.  */
       if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
          && TREE_CODE (arg0) == BIT_AND_EXPR)
@@ -5121,14 +5860,7 @@ fold (expr)
            case GE_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;
-               }
+               return constant_boolean_node (1, type);
              code = EQ_EXPR;
              TREE_SET_CODE (t, code);
              break;
@@ -5140,19 +5872,16 @@ 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;
+             return constant_boolean_node (0, type);
+           default:
+             abort ();
            }
        }
 
       /* An unsigned comparison against 0 can be simplified.  */
       if (integer_zerop (arg1)
          && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
-             || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
+             || POINTER_TYPE_P (TREE_TYPE (arg1)))
          && TREE_UNSIGNED (TREE_TYPE (arg1)))
        {
          switch (TREE_CODE (t))
@@ -5173,9 +5902,43 @@ fold (expr)
              return omit_one_operand (type,
                                       convert (type, integer_zero_node),
                                       arg0);
+           default:
+             break;
            }
        }
 
+      /* An unsigned <= 0x7fffffff can be simplified.  */
+      {
+       int width = TYPE_PRECISION (TREE_TYPE (arg1));
+       if (TREE_CODE (arg1) == INTEGER_CST
+           && ! TREE_CONSTANT_OVERFLOW (arg1)
+           && width <= HOST_BITS_PER_WIDE_INT
+           && TREE_INT_CST_LOW (arg1) == ((HOST_WIDE_INT) 1 << (width - 1)) - 1
+           && TREE_INT_CST_HIGH (arg1) == 0
+           && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+               || POINTER_TYPE_P (TREE_TYPE (arg1)))
+           && TREE_UNSIGNED (TREE_TYPE (arg1)))
+         {
+           switch (TREE_CODE (t))
+             {
+             case LE_EXPR:
+               return fold (build (GE_EXPR, type,
+                                   convert (signed_type (TREE_TYPE (arg0)),
+                                            arg0),
+                                   convert (signed_type (TREE_TYPE (arg1)),
+                                            integer_zero_node)));
+             case GT_EXPR:
+               return fold (build (LT_EXPR, type,
+                                   convert (signed_type (TREE_TYPE (arg0)),
+                                            arg0),
+                                   convert (signed_type (TREE_TYPE (arg1)),
+                                            integer_zero_node)));
+             default:
+               break;
+             }
+         }
+      }
+
       /* If we are comparing an expression that just has comparisons
         of two integer values, arithmetic expressions of those comparisons,
         and constants, we can simplify it.  There are only three cases
@@ -5201,6 +5964,8 @@ fold (expr)
              && ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
              && TREE_TYPE (cval1) == TREE_TYPE (cval2)
              && INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+             && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+             && TYPE_MAX_VALUE (TREE_TYPE (cval2))
              && ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
                                    TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
            {
@@ -5287,20 +6052,26 @@ fold (expr)
          return t1 ? t1 : t;
        }
 
-      /* If this is a comparison of complex values and either or both
-        sizes are a COMPLEX_EXPR, it is best to split up the comparisons
-        and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.  This
-        may prevent needless evaluations.  */
+      /* If this is a comparison of complex values and either or both sides
+        are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
+        comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
+        This may prevent needless evaluations.  */
       if ((code == EQ_EXPR || code == NE_EXPR)
          && TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
          && (TREE_CODE (arg0) == COMPLEX_EXPR
-             || TREE_CODE (arg1) == COMPLEX_EXPR))
+             || TREE_CODE (arg1) == COMPLEX_EXPR
+             || TREE_CODE (arg0) == COMPLEX_CST
+             || TREE_CODE (arg1) == COMPLEX_CST))
        {
          tree subtype = TREE_TYPE (TREE_TYPE (arg0));
-         tree real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
-         tree imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
-         tree real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
-         tree imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
+         tree real0, imag0, real1, imag1;
+
+         arg0 = save_expr (arg0);
+         arg1 = save_expr (arg1);
+         real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
+         imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
+         real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
+         imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
 
          return fold (build ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
                               : TRUTH_ORIF_EXPR),
@@ -5395,6 +6166,8 @@ fold (expr)
        TREE_INT_CST_LOW (t1) ^= 1;
 
       TREE_TYPE (t1) = type;
+      if (TREE_CODE (type) == BOOLEAN_TYPE)
+       return truthvalue_conversion (t1);
       return t1;
 
     case COND_EXPR:
@@ -5428,7 +6201,8 @@ fold (expr)
              t = build (code, type, tem,
                         TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
              arg0 = tem;
-             arg1 = TREE_OPERAND (t, 2);
+             /* arg1 should be the first argument of the new T.  */
+             arg1 = TREE_OPERAND (t, 1);
              STRIP_NOPS (arg1);
            }
        }
@@ -5466,17 +6240,23 @@ fold (expr)
                return pedantic_non_lvalue (convert (type, arg1));
              case GE_EXPR:
              case GT_EXPR:
+               if (TREE_UNSIGNED (TREE_TYPE (arg1)))
+                 arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
                return pedantic_non_lvalue
                  (convert (type, fold (build1 (ABS_EXPR,
                                                TREE_TYPE (arg1), arg1))));
              case LE_EXPR:
              case LT_EXPR:
+               if (TREE_UNSIGNED (TREE_TYPE (arg1)))
+                 arg1 = convert (signed_type (TREE_TYPE (arg1)), arg1);
                return pedantic_non_lvalue
                  (fold (build1 (NEGATE_EXPR, type,
                                 convert (type,
                                          fold (build1 (ABS_EXPR,
                                                        TREE_TYPE (arg1),
                                                        arg1))))));
+             default:
+               abort ();
              }
 
          /* If this is A != 0 ? A : 0, this is simply A.  For ==, it is
@@ -5508,21 +6288,28 @@ fold (expr)
                  return pedantic_non_lvalue (convert (type, arg1));
                case LE_EXPR:
                case LT_EXPR:
-                 /* In C++ a ?: expression can be an lvalue, so we can't
-                    do this; we would lose the distinction between
-                    LT and LE.  */
-                 if (pedantic_lvalues)
-                   return pedantic_non_lvalue
-                     (convert (type, (fold (build (MIN_EXPR, comp_type,
-                                                   comp_op0, comp_op1)))));
+                 /* In C++ a ?: expression can be an lvalue, so put the
+                    operand which will be used if they are equal first
+                    so that we can convert this back to the 
+                    corresponding COND_EXPR.  */
+                 return pedantic_non_lvalue
+                   (convert (type, (fold (build (MIN_EXPR, comp_type,
+                                                 (comp_code == LE_EXPR
+                                                  ? comp_op0 : comp_op1),
+                                                 (comp_code == LE_EXPR
+                                                  ? comp_op1 : comp_op0))))));
                  break;
                case GE_EXPR:
                case GT_EXPR:
-                 if (pedantic_lvalues)
-                   return pedantic_non_lvalue
-                     (convert (type, fold (build (MAX_EXPR, comp_type,
-                                                  comp_op0, comp_op1))));
+                 return pedantic_non_lvalue
+                   (convert (type, fold (build (MAX_EXPR, comp_type,
+                                                (comp_code == GE_EXPR
+                                                 ? comp_op0 : comp_op1),
+                                                (comp_code == GE_EXPR
+                                                 ? comp_op1 : comp_op0)))));
                  break;
+               default:
+                 abort ();
                }
            }
 
@@ -5583,6 +6370,10 @@ fold (expr)
                  return pedantic_non_lvalue
                    (fold (build (MAX_EXPR, type, arg1, arg2)));
                break;
+             case NE_EXPR:
+               break;
+             default:
+               abort ();
              }
        }
 
@@ -5604,7 +6395,8 @@ fold (expr)
              t = build (code, type, tem,
                         TREE_OPERAND (t, 2), TREE_OPERAND (t, 1));
              arg0 = tem;
-             arg1 = TREE_OPERAND (t, 2);
+             /* arg1 should be the first argument of the new T.  */
+             arg1 = TREE_OPERAND (t, 1);
              STRIP_NOPS (arg1);
            }
        }
@@ -5640,7 +6432,7 @@ fold (expr)
        return t;
       /* Don't let (0, 0) be null pointer constant.  */
       if (integer_zerop (arg1))
-       return non_lvalue (arg1);
+       return build1 (NOP_EXPR, TREE_TYPE (arg1), arg1);
       return arg1;
 
     case COMPLEX_EXPR:
@@ -5683,7 +6475,7 @@ fold (expr)
       /* Pull arithmetic ops out of the CLEANUP_POINT_EXPR where
          appropriate.  */
     case CLEANUP_POINT_EXPR:
-      if (! TREE_SIDE_EFFECTS (arg0))
+      if (! has_cleanups (arg0))
        return TREE_OPERAND (t, 0);
 
       {
@@ -5704,12 +6496,14 @@ fold (expr)
          {
            arg01 = TREE_OPERAND (arg0, 1);
 
-           if (! TREE_SIDE_EFFECTS (arg00))
+           if (TREE_CONSTANT (arg00)
+               || ((code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR)
+                   && ! has_cleanups (arg00)))
              return fold (build (code0, type, arg00,
                                  fold (build1 (CLEANUP_POINT_EXPR,
                                                TREE_TYPE (arg01), arg01))));
 
-           if (! TREE_SIDE_EFFECTS (arg01))
+           if (TREE_CONSTANT (arg01))
              return fold (build (code0, type,
                                  fold (build1 (CLEANUP_POINT_EXPR,
                                                TREE_TYPE (arg00), arg00)),
@@ -5723,3 +6517,104 @@ fold (expr)
       return t;
     } /* switch (code) */
 }
+
+/* Determine if first argument is a multiple of second argument.
+   Return 0 if it is not, or is not easily determined to so be.
+
+   An example of the sort of thing we care about (at this point --
+   this routine could surely be made more general, and expanded
+   to do what the *_DIV_EXPR's fold() cases do now) is discovering
+   that
+
+     SAVE_EXPR (I) * SAVE_EXPR (J * 8)
+
+   is a multiple of
+
+     SAVE_EXPR (J * 8)
+
+   when we know that the two `SAVE_EXPR (J * 8)' nodes are the
+   same node (which means they will have the same value at run
+   time, even though we don't know when they'll be assigned).
+
+   This code also handles discovering that
+
+     SAVE_EXPR (I) * SAVE_EXPR (J * 8)
+
+   is a multiple of
+
+     8
+
+   (of course) so we don't have to worry about dealing with a
+   possible remainder.
+
+   Note that we _look_ inside a SAVE_EXPR only to determine
+   how it was calculated; it is not safe for fold() to do much
+   of anything else with the internals of a SAVE_EXPR, since
+   fold() cannot know when it will be evaluated at run time.
+   For example, the latter example above _cannot_ be implemented
+   as
+
+     SAVE_EXPR (I) * J
+
+   or any variant thereof, since the value of J at evaluation time
+   of the original SAVE_EXPR is not necessarily the same at the time
+   the new expression is evaluated.  The only optimization of this
+   sort that would be valid is changing
+
+     SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8)
+   divided by
+     8
+
+   to
+
+     SAVE_EXPR (I) * SAVE_EXPR (J)
+
+   (where the same SAVE_EXPR (J) is used in the original and the
+   transformed version).  */
+
+static int
+multiple_of_p (type, top, bottom)
+     tree type;
+     tree top;
+     tree bottom;
+{
+  if (operand_equal_p (top, bottom, 0))
+    return 1;
+
+  if (TREE_CODE (type) != INTEGER_TYPE)
+    return 0;
+
+  switch (TREE_CODE (top))
+    {
+    case MULT_EXPR:
+      return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
+             || multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
+             && multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+
+    case NOP_EXPR:
+      /* Punt if conversion from non-integral or wider integral type.  */
+      if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE)
+         || (TYPE_PRECISION (type)
+             < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0)))))
+       return 0;
+      /* Fall through. */
+    case SAVE_EXPR:
+      return multiple_of_p (type, TREE_OPERAND (top, 0), bottom);
+
+    case INTEGER_CST:
+      if ((TREE_CODE (bottom) != INTEGER_CST)
+         || (tree_int_cst_sgn (top) < 0)
+         || (tree_int_cst_sgn (bottom) < 0))
+       return 0;
+      return integer_zerop (const_binop (TRUNC_MOD_EXPR,
+                                        top, bottom, 0));
+
+    default:
+      return 0;
+    }
+}
+\f