OSDN Git Service

* config/arm/arm.c, config/arm/arm.h, config/arm/arm.md,
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 3da0ebf..de72a76 100644 (file)
@@ -1,6 +1,6 @@
 /* Fold a constant sub-tree into a single node for C-compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -69,7 +69,7 @@ static tree int_const_binop (enum tree_code, tree, tree, int);
 static tree const_binop (enum tree_code, tree, tree, int);
 static hashval_t size_htab_hash (const void *);
 static int size_htab_eq (const void *, const void *);
-static tree fold_convert (tree, tree);
+static tree fold_convert_const (enum tree_code, tree, tree);
 static enum tree_code invert_tree_comparison (enum tree_code);
 static enum tree_code swap_tree_comparison (enum tree_code);
 static int comparison_to_compcode (enum tree_code);
@@ -798,7 +798,7 @@ div_and_round_double (enum tree_code code, int uns,
       abort ();
     }
 
-  /* compute true remainder:  rem = num - (quo * den)  */
+  /* Compute true remainder:  rem = num - (quo * den)  */
   mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem);
   neg_double (*lrem, *hrem, lrem, hrem);
   add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem);
@@ -1657,14 +1657,17 @@ size_diffop (tree arg0, tree arg1)
 }
 \f
 
-/* Given T, a tree representing type conversion of ARG1, a constant,
-   return a constant tree representing the result of conversion.  */
+/* Attempt to fold type conversion operation CODE of expression ARG1 to
+   type TYPE.  If no simplification can be done return NULL_TREE.  */
 
 static tree
-fold_convert (tree t, tree arg1)
+fold_convert_const (enum tree_code code, tree type, tree arg1)
 {
-  tree type = TREE_TYPE (t);
   int overflow = 0;
+  tree t;
+
+  if (TREE_TYPE (arg1) == type)
+    return arg1;
 
   if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
     {
@@ -1673,7 +1676,7 @@ fold_convert (tree t, tree arg1)
          /* If we would build a constant wider than GCC supports,
             leave the conversion unfolded.  */
          if (TYPE_PRECISION (type) > 2 * HOST_BITS_PER_WIDE_INT)
-           return t;
+           return NULL_TREE;
 
          /* If we are trying to make a sizetype for a small integer, use
             size_int to pick up cached types to reduce duplicate nodes.  */
@@ -1701,6 +1704,7 @@ fold_convert (tree t, tree arg1)
               || TREE_OVERFLOW (arg1));
          TREE_CONSTANT_OVERFLOW (t)
            = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+         return t;
        }
       else if (TREE_CODE (arg1) == REAL_CST)
        {
@@ -1715,25 +1719,43 @@ fold_convert (tree t, tree arg1)
 
          HOST_WIDE_INT high, low;
 
+         REAL_VALUE_TYPE r;
          REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
-         /* If x is NaN, return zero and show we have an overflow.  */
-         if (REAL_VALUE_ISNAN (x))
+
+         switch (code)
+           {
+           case FIX_TRUNC_EXPR:
+             real_trunc (&r, VOIDmode, &x);
+             break;
+
+           case FIX_CEIL_EXPR:
+             real_ceil (&r, VOIDmode, &x);
+             break;
+
+           case FIX_FLOOR_EXPR:
+             real_floor (&r, VOIDmode, &x);
+             break;
+
+           default:
+             abort ();
+           }
+
+         /* If R is NaN, return zero and show we have an overflow.  */
+         if (REAL_VALUE_ISNAN (r))
            {
              overflow = 1;
              high = 0;
              low = 0;
            }
 
-         /* 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.  */
+         /* See if R is less than the lower bound or greater than the
+            upper bound.  */
 
          if (! overflow)
            {
              tree lt = TYPE_MIN_VALUE (type);
              REAL_VALUE_TYPE l = real_value_from_int_cst (NULL_TREE, lt);
-             REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
-             if (! REAL_VALUES_LESS (l, x))
+             if (REAL_VALUES_LESS (r, l))
                {
                  overflow = 1;
                  high = TREE_INT_CST_HIGH (lt);
@@ -1747,8 +1769,7 @@ fold_convert (tree t, tree arg1)
              if (ut)
                {
                  REAL_VALUE_TYPE u = real_value_from_int_cst (NULL_TREE, ut);
-                 REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
-                 if (! REAL_VALUES_LESS (x, u))
+                 if (REAL_VALUES_LESS (u, r))
                    {
                      overflow = 1;
                      high = TREE_INT_CST_HIGH (ut);
@@ -1758,7 +1779,7 @@ fold_convert (tree t, tree arg1)
            }
 
          if (! overflow)
-           REAL_VALUE_TO_INT (&low, &high, x);
+           REAL_VALUE_TO_INT (&low, &high, r);
 
          t = build_int_2 (low, high);
          TREE_TYPE (t) = type;
@@ -1766,8 +1787,8 @@ fold_convert (tree t, tree arg1)
            = TREE_OVERFLOW (arg1) | force_fit_type (t, overflow);
          TREE_CONSTANT_OVERFLOW (t)
            = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
+         return t;
        }
-      TREE_TYPE (t) = type;
     }
   else if (TREE_CODE (type) == REAL_TYPE)
     {
@@ -1795,8 +1816,7 @@ fold_convert (tree t, tree arg1)
          return t;
        }
     }
-  TREE_CONSTANT (t) = 1;
-  return t;
+  return NULL_TREE;
 }
 \f
 /* Return an expr equal to X but certainly not valid as an lvalue.  */
@@ -4729,7 +4749,7 @@ fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
        {
          arg = save_expr (arg);
          lhs = rhs = 0;
-         save = 1;
+         save = saved_expr_p (arg);
        }
     }
 
@@ -4740,6 +4760,12 @@ fold_binary_op_with_conditional_arg (enum tree_code code, tree type,
 
   test = fold (build (COND_EXPR, type, test, lhs, rhs));
 
+  /* If ARG involves a SAVE_EXPR, we need to ensure it is evaluated
+     ahead of the COND_EXPR we made.  Otherwise we would have it only
+     evaluated in one branch, with the other branch using the result
+     but missing the evaluation code.  Beware that the save_expr call
+     above might not return a SAVE_EXPR, so testing the TREE_CODE
+     of ARG is not enough to decide here.  */
   if (save)
     return build (COMPOUND_EXPR, type,
                  convert (void_type_node, arg),
@@ -5432,8 +5458,8 @@ fold (tree expr)
     case FLOAT_EXPR:
     case CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
-      /* Other kinds of FIX are not handled properly by fold_convert.  */
-
+    case FIX_CEIL_EXPR:
+    case FIX_FLOOR_EXPR:
       if (TREE_TYPE (TREE_OPERAND (t, 0)) == TREE_TYPE (t))
        return TREE_OPERAND (t, 0);
 
@@ -5577,17 +5603,8 @@ fold (tree expr)
                                convert (TREE_TYPE (t), and1)));
        }
 
-      if (!wins)
-       {
-         if (TREE_CONSTANT (t) != TREE_CONSTANT (arg0))
-           {
-             if (t == orig_t)
-               t = copy_node (t);
-             TREE_CONSTANT (t) = TREE_CONSTANT (arg0);
-           }
-         return t;
-       }
-      return fold_convert (t, arg0);
+      tem = fold_convert_const (code, TREE_TYPE (t), arg0);
+      return tem ? tem : t;
 
     case VIEW_CONVERT_EXPR:
       if (TREE_CODE (TREE_OPERAND (t, 0)) == VIEW_CONVERT_EXPR)
@@ -7864,9 +7881,17 @@ fold (tree expr)
       /* Pedantic ANSI C says that a conditional expression is never an lvalue,
         so all simple results must be passed through pedantic_non_lvalue.  */
       if (TREE_CODE (arg0) == INTEGER_CST)
-       return pedantic_non_lvalue
-         (TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1)));
-      else if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
+       {
+         tem = TREE_OPERAND (t, (integer_zerop (arg0) ? 2 : 1));
+         /* Only optimize constant conditions when the selected branch
+            has the same type as the COND_EXPR.  This avoids optimizing
+            away "c ? x : throw", where the throw has a void type.  */
+         if (! VOID_TYPE_P (TREE_TYPE (tem))
+             || VOID_TYPE_P (TREE_TYPE (t)))
+           return pedantic_non_lvalue (tem);
+         return t;
+       }
+      if (operand_equal_p (arg1, TREE_OPERAND (expr, 2), 0))
        return pedantic_omit_one_operand (type, arg1, arg0);
 
       /* If we have A op B ? A : C, we may be able to convert this to a
@@ -8162,12 +8187,12 @@ fold (tree expr)
     case COMPOUND_EXPR:
       /* When pedantic, a compound expression can be neither an lvalue
         nor an integer constant expression.  */
-      if (TREE_SIDE_EFFECTS (arg0) || pedantic)
+      if (TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
        return t;
       /* Don't let (0, 0) be null pointer constant.  */
       if (integer_zerop (arg1))
-       return build1 (NOP_EXPR, type, arg1);
-      return convert (type, arg1);
+       return pedantic_non_lvalue (build1 (NOP_EXPR, type, arg1));
+      return pedantic_non_lvalue (convert (type, arg1));
 
     case COMPLEX_EXPR:
       if (wins)
@@ -8417,7 +8442,7 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
        case WITH_CLEANUP_EXPR: len = 2; break;
        default: break;
        }
-      /* FALLTHROUGH */
+      /* Fall through.  */
     case 'r':
     case '<':
     case '1':