OSDN Git Service

2005-06-10 Keith Besaw <kbesaw@us.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 9880327..96fffe9 100644 (file)
@@ -89,7 +89,6 @@ static tree negate_expr (tree);
 static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
 static tree associate_trees (tree, tree, enum tree_code, tree);
 static tree const_binop (enum tree_code, tree, tree, int);
-static enum tree_code invert_tree_comparison (enum tree_code, bool);
 static enum comparison_code comparison_to_compcode (enum tree_code);
 static enum tree_code compcode_to_comparison (enum comparison_code);
 static tree combine_comparisons (enum tree_code, enum tree_code,
@@ -2119,7 +2118,7 @@ pedantic_non_lvalue (tree x)
    comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode
    as well: if reversing the comparison is unsafe, return ERROR_MARK.  */
 
-static enum tree_code
+enum tree_code
 invert_tree_comparison (enum tree_code code, bool honor_nans)
 {
   if (honor_nans && flag_trapping_math)
@@ -2461,7 +2460,7 @@ operand_equal_p (tree arg0, tree arg1, unsigned int flags)
              v2 = TREE_CHAIN (v2);
            }
 
-         return 1;
+         return v1 == v2;
        }
 
       case COMPLEX_CST:
@@ -5488,26 +5487,31 @@ constant_boolean_node (int value, tree type)
 
 /* Return true if expr looks like an ARRAY_REF and set base and
    offset to the appropriate trees.  If there is no offset,
-   offset is set to NULL_TREE.  */
+   offset is set to NULL_TREE.  Base will be canonicalized to
+   something you can get the element type from using
+   TREE_TYPE (TREE_TYPE (base)).  */
 
 static bool
 extract_array_ref (tree expr, tree *base, tree *offset)
 {
-  /* We have to be careful with stripping nops as with the
-     base type the meaning of the offset can change.  */
-  tree inner_expr = expr;
-  STRIP_NOPS (inner_expr);
   /* One canonical form is a PLUS_EXPR with the first
      argument being an ADDR_EXPR with a possible NOP_EXPR
      attached.  */
   if (TREE_CODE (expr) == PLUS_EXPR)
     {
       tree op0 = TREE_OPERAND (expr, 0);
+      tree inner_base, dummy1;
+      /* Strip NOP_EXPRs here because the C frontends and/or
+        folders present us (int *)&x.a + 4B possibly.  */
       STRIP_NOPS (op0);
-      if (TREE_CODE (op0) == ADDR_EXPR)
+      if (extract_array_ref (op0, &inner_base, &dummy1))
        {
-         *base = TREE_OPERAND (expr, 0);
-         *offset = TREE_OPERAND (expr, 1);
+         *base = inner_base;
+         if (dummy1 == NULL_TREE)
+           *offset = TREE_OPERAND (expr, 1);
+         else
+           *offset = fold_build2 (PLUS_EXPR, TREE_TYPE (expr),
+                                  dummy1, TREE_OPERAND (expr, 1));
          return true;
        }
     }
@@ -5516,21 +5520,33 @@ extract_array_ref (tree expr, tree *base, tree *offset)
      offset.  For other arguments to the ADDR_EXPR we assume
      zero offset and as such do not care about the ADDR_EXPR
      type and strip possible nops from it.  */
-  else if (TREE_CODE (inner_expr) == ADDR_EXPR)
+  else if (TREE_CODE (expr) == ADDR_EXPR)
     {
-      tree op0 = TREE_OPERAND (inner_expr, 0);
+      tree op0 = TREE_OPERAND (expr, 0);
       if (TREE_CODE (op0) == ARRAY_REF)
        {
-         *base = build_fold_addr_expr (TREE_OPERAND (op0, 0));
+         *base = TREE_OPERAND (op0, 0);
          *offset = TREE_OPERAND (op0, 1);
        }
       else
        {
-         *base = inner_expr;
+         /* Handle array-to-pointer decay as &a.  */
+         if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE)
+           *base = TREE_OPERAND (expr, 0);
+         else
+           *base = expr;
          *offset = NULL_TREE;
        }
       return true;
     }
+  /* The next canonical form is a VAR_DECL with POINTER_TYPE.  */
+  else if (SSA_VAR_P (expr)
+          && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
+    {
+      *base = expr;
+      *offset = NULL_TREE;
+      return true;
+    }
 
   return false;
 }
@@ -7931,7 +7947,9 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
               && (TREE_CODE (arg1) != REAL_CST
                   ||  REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
              || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
-       return fold_build2 (PLUS_EXPR, type, arg0, negate_expr (arg1));
+       return fold_build2 (PLUS_EXPR, type,
+                           fold_convert (type, arg0),
+                           fold_convert (type, negate_expr (arg1)));
 
       /* Try folding difference of addresses.  */
       {
@@ -8450,7 +8468,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
                {
                  tem = build_real (type, r);
-                 return fold_build2 (MULT_EXPR, type, arg0, tem);
+                 return fold_build2 (MULT_EXPR, type,
+                                     fold_convert (type, arg0), tem);
                }
            }
        }
@@ -9017,6 +9036,12 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              && extract_array_ref (arg1, &base1, &offset1)
              && operand_equal_p (base0, base1, 0))
            {
+             if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base0)))
+                 && integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base0)))))
+               offset0 = NULL_TREE;
+             if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base1)))
+                 && integer_zerop (TYPE_SIZE (TREE_TYPE (TREE_TYPE (base1)))))
+               offset1 = NULL_TREE;
              if (offset0 == NULL_TREE
                  && offset1 == NULL_TREE)
                {
@@ -9278,12 +9303,16 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          switch (code)
            {
            case GE_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold_build2 (GT_EXPR, type, arg0, arg1);
+             arg1 = const_binop (MINUS_EXPR, arg1,
+                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
+             return fold_build2 (GT_EXPR, type, arg0,
+                                 fold_convert (TREE_TYPE (arg0), arg1));
 
            case LT_EXPR:
-             arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
-             return fold_build2 (LE_EXPR, type, arg0, arg1);
+             arg1 = const_binop (MINUS_EXPR, arg1,
+                                 build_int_cst (TREE_TYPE (arg1), 1), 0);
+             return fold_build2 (LE_EXPR, type, arg0,
+                                 fold_convert (TREE_TYPE (arg0), arg1));
 
            default:
              break;
@@ -9892,11 +9921,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              && (arglist = TREE_OPERAND (arg0, 1))
              && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE
              && ! TREE_CHAIN (arglist))
-           return fold_build2 (code, type,
-                               build1 (INDIRECT_REF, char_type_node,
-                                       TREE_VALUE (arglist)),
-                               fold_convert (char_type_node,
-                                             integer_zero_node));
+           {
+             tree iref = build_fold_indirect_ref (TREE_VALUE (arglist));
+             return fold_build2 (code, type, iref,
+                                 build_int_cst (TREE_TYPE (iref), 0));
+           }
        }
 
       /* We can fold X/C1 op C2 where C1 and C2 are integer constants
@@ -10261,6 +10290,32 @@ fold_ternary (enum tree_code code, tree type, tree op0, tree op1, tree op2)
        }
       return NULL_TREE;
 
+    case BIT_FIELD_REF:
+      if (TREE_CODE (arg0) == VECTOR_CST
+         && type == TREE_TYPE (TREE_TYPE (arg0))
+         && host_integerp (arg1, 1)
+         && host_integerp (op2, 1))
+       {
+         unsigned HOST_WIDE_INT width = tree_low_cst (arg1, 1);
+         unsigned HOST_WIDE_INT idx = tree_low_cst (op2, 1);
+
+         if (width != 0
+             && simple_cst_equal (arg1, TYPE_SIZE (type)) == 1
+             && (idx % width) == 0
+             && (idx = idx / width)
+                < TYPE_VECTOR_SUBPARTS (TREE_TYPE (arg0)))
+           {
+             tree elements = TREE_VECTOR_CST_ELTS (arg0);
+             while (idx-- > 0 && elements)
+               elements = TREE_CHAIN (elements);
+             if (elements)
+               return TREE_VALUE (elements);
+             else
+               return fold_convert (type, integer_zero_node);
+           }
+       }
+      return NULL_TREE;
+
     default:
       return NULL_TREE;
     } /* switch (code) */
@@ -10396,6 +10451,8 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
   enum tree_code code;
   char buf[sizeof (struct tree_decl)];
   int i, len;
+  
+recursive_label:
 
   gcc_assert ((sizeof (struct tree_exp) + 5 * sizeof (tree)
               <= sizeof (struct tree_decl))
@@ -10417,11 +10474,13 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
     }
   else if (TREE_CODE_CLASS (code) == tcc_type
           && (TYPE_POINTER_TO (expr) || TYPE_REFERENCE_TO (expr)
-              || TYPE_CACHED_VALUES_P (expr)))
+              || TYPE_CACHED_VALUES_P (expr)
+              || TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr)))
     {
       /* Allow these fields to be modified.  */
       memcpy (buf, expr, tree_size (expr));
       expr = (tree) buf;
+      TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) = 0;
       TYPE_POINTER_TO (expr) = NULL;
       TYPE_REFERENCE_TO (expr) = NULL;
       if (TYPE_CACHED_VALUES_P (expr))
@@ -10433,7 +10492,8 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
   md5_process_bytes (expr, tree_size (expr), ctx);
   fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
   if (TREE_CODE_CLASS (code) != tcc_type
-      && TREE_CODE_CLASS (code) != tcc_declaration)
+      && TREE_CODE_CLASS (code) != tcc_declaration
+      && code != TREE_LIST)
     fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
   switch (TREE_CODE_CLASS (code))
     {
@@ -10461,6 +10521,8 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
        case TREE_LIST:
          fold_checksum_tree (TREE_PURPOSE (expr), ctx, ht);
          fold_checksum_tree (TREE_VALUE (expr), ctx, ht);
+         expr = TREE_CHAIN (expr);
+         goto recursive_label;
          break;
        case TREE_VEC:
          for (i = 0; i < TREE_VEC_LENGTH (expr); ++i)
@@ -11455,7 +11517,7 @@ build_fold_addr_expr (tree t)
    of an indirection through OP0, or NULL_TREE if no simplification is
    possible.  */
 
-static tree
+tree
 fold_indirect_ref_1 (tree type, tree op0)
 {
   tree sub = op0;