OSDN Git Service

* config/i386/xmmintrin.h (_mm_prefetch): Added const to first arg.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index 19d8256..f9f1217 100644 (file)
@@ -1588,6 +1588,7 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
 {
   tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
   tree array_type, elt_type, elt_size;
+  tree domain_type;
 
   /* If BASE is an ARRAY_REF, we can pick up another offset (this time
      measured in units of the size of elements type) from that ARRAY_REF).
@@ -1659,9 +1660,10 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
      low bound, if any, convert the index into that type, and add the
      low bound.  */
   min_idx = build_int_cst (idx_type, 0);
-  if (TYPE_DOMAIN (array_type))
+  domain_type = TYPE_DOMAIN (array_type);
+  if (domain_type)
     {
-      idx_type = TYPE_DOMAIN (array_type);
+      idx_type = domain_type;
       if (TYPE_MIN_VALUE (idx_type))
        min_idx = TYPE_MIN_VALUE (idx_type);
       else
@@ -1681,6 +1683,24 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
   /* Make sure to possibly truncate late after offsetting.  */
   idx = fold_convert (idx_type, idx);
 
+  /* We don't want to construct access past array bounds. For example
+     char *(c[4]);
+
+     c[3][2]; should not be simplified into (*c)[14] or tree-vrp will give false
+     warning.  */
+  if (domain_type && TYPE_MAX_VALUE (domain_type) 
+      && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST)
+    {
+      tree up_bound = TYPE_MAX_VALUE (domain_type);
+
+      if (tree_int_cst_lt (up_bound, idx)
+         /* Accesses after the end of arrays of size 0 (gcc
+            extension) and 1 are likely intentional ("struct
+            hack").  */
+         && compare_tree_int (up_bound, 1) > 0)
+       return NULL_TREE;
+    }
+
   return build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE);
 }
 
@@ -2708,6 +2728,78 @@ optimize_stack_restore (basic_block bb, tree call, block_stmt_iterator i)
   return integer_zero_node;
 }
 \f
+/* If va_list type is a simple pointer and nothing special is needed,
+   optimize __builtin_va_start (&ap, 0) into ap = __builtin_next_arg (0),
+   __builtin_va_end (&ap) out as NOP and __builtin_va_copy into a simple
+   pointer assignment.  */
+
+static tree
+optimize_stdarg_builtin (tree call)
+{
+  tree callee, lhs, rhs;
+  bool va_list_simple_ptr;
+
+  if (TREE_CODE (call) != CALL_EXPR)
+    return NULL_TREE;
+
+  va_list_simple_ptr = POINTER_TYPE_P (va_list_type_node)
+                      && (TREE_TYPE (va_list_type_node) == void_type_node
+                          || TREE_TYPE (va_list_type_node) == char_type_node);
+
+  callee = get_callee_fndecl (call);
+  switch (DECL_FUNCTION_CODE (callee))
+    {
+    case BUILT_IN_VA_START:
+      if (!va_list_simple_ptr
+         || targetm.expand_builtin_va_start != NULL
+         || built_in_decls[BUILT_IN_NEXT_ARG] == NULL)
+       return NULL_TREE;
+
+      if (call_expr_nargs (call) != 2)
+       return NULL_TREE;
+
+      lhs = CALL_EXPR_ARG (call, 0);
+      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
+            != TYPE_MAIN_VARIANT (va_list_type_node))
+       return NULL_TREE;
+
+      lhs = build_fold_indirect_ref (lhs);
+      rhs = build_call_expr (built_in_decls[BUILT_IN_NEXT_ARG],
+                            1, integer_zero_node);
+      rhs = fold_convert (TREE_TYPE (lhs), rhs);
+      return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);
+
+    case BUILT_IN_VA_COPY:
+      if (!va_list_simple_ptr)
+       return NULL_TREE;
+
+      if (call_expr_nargs (call) != 2)
+       return NULL_TREE;
+
+      lhs = CALL_EXPR_ARG (call, 0);
+      if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+         || TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (lhs)))
+            != TYPE_MAIN_VARIANT (va_list_type_node))
+       return NULL_TREE;
+
+      lhs = build_fold_indirect_ref (lhs);
+      rhs = CALL_EXPR_ARG (call, 1);
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs))
+         != TYPE_MAIN_VARIANT (va_list_type_node))
+       return NULL_TREE;
+
+      rhs = fold_convert (TREE_TYPE (lhs), rhs);
+      return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);
+
+    case BUILT_IN_VA_END:
+      return integer_zero_node;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+\f
 /* Convert EXPR into a GIMPLE value suitable for substitution on the
    RHS of an assignment.  Insert the necessary statements before
    iterator *SI_P. 
@@ -2796,6 +2888,16 @@ execute_fold_all_builtins (void)
                result = optimize_stack_restore (bb, *stmtp, i);
                if (result)
                  break;
+               bsi_next (&i);
+               continue;
+
+             case BUILT_IN_VA_START:
+             case BUILT_IN_VA_END:
+             case BUILT_IN_VA_COPY:
+               /* These shouldn't be folded before pass_stdarg.  */
+               result = optimize_stdarg_builtin (*stmtp);
+               if (result)
+                 break;
                /* FALLTHRU */
 
              default: