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 0dbce12..9b003c2 100644 (file)
@@ -50,9 +50,6 @@ Boston, MA 02111-1307, USA.  */
 #include "rtl.h"
 #include "toplev.h"
 
-/* Handle floating overflow for `const_binop'.  */
-static jmp_buf float_error;
-
 static void encode             PROTO((HOST_WIDE_INT *,
                                       HOST_WIDE_INT, HOST_WIDE_INT));
 static void decode             PROTO((HOST_WIDE_INT *,
@@ -97,6 +94,8 @@ 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
@@ -886,6 +885,7 @@ exact_real_inverse (mode, r)
      enum machine_mode mode;
      REAL_VALUE_TYPE *r;
 {
+  jmp_buf float_error;
   union
     {
       double d;
@@ -1478,6 +1478,67 @@ int_const_binop (code, arg1, arg2, notrunc, forsize)
   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,
@@ -1502,8 +1563,8 @@ const_binop (code, arg1, arg2, notrunc)
       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);
@@ -1514,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)
@@ -1755,6 +1783,25 @@ ssize_binop (code, arg0, arg1)
   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.  */
 
@@ -1880,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)
@@ -3087,6 +3140,11 @@ make_range (exp, pin_p, plow, phigh)
            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)
        {
        case TRUTH_NOT_EXPR:
@@ -3205,8 +3263,6 @@ make_range (exp, pin_p, plow, phigh)
          continue;
 
        case NOP_EXPR:  case NON_LVALUE_EXPR:  case CONVERT_EXPR:
-         if (orig_type == NULL_TREE)
-           orig_type = type;
          if (TYPE_PRECISION (type) > TYPE_PRECISION (orig_type))
            break;
 
@@ -3654,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;
 
@@ -3792,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)
@@ -3801,19 +3857,19 @@ 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 %d", wanted_code == NE_EXPR);
@@ -3825,12 +3881,12 @@ 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 %d", wanted_code == NE_EXPR);
@@ -3863,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)
@@ -3871,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;
     }
@@ -3941,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));
@@ -4954,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
@@ -4964,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;