OSDN Git Service

* MAINTAINERS (Write After Approval): Add myself.
[pf3gnuchains/gcc-fork.git] / gcc / tree-object-size.c
index dbd8af4..017f8c5 100644 (file)
@@ -1,5 +1,5 @@
 /* __builtin_object_size (ptr, object_size_type) computation
-   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>
 
@@ -24,8 +24,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
-#include "toplev.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-ssa-propagate.h"
@@ -52,7 +53,7 @@ static void expr_object_size (struct object_size_info *, tree, tree);
 static bool merge_object_sizes (struct object_size_info *, tree, tree,
                                unsigned HOST_WIDE_INT);
 static bool plus_stmt_object_size (struct object_size_info *, tree, gimple);
-static bool cond_expr_object_size (struct object_size_info *, tree, tree);
+static bool cond_expr_object_size (struct object_size_info *, tree, gimple);
 static unsigned int compute_object_sizes (void);
 static void init_offset_limit (void);
 static void check_for_plus_in_loops (struct object_size_info *, tree);
@@ -140,6 +141,10 @@ compute_object_offset (const_tree expr, const_tree var)
       off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
       break;
 
+    case MEM_REF:
+      gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR);
+      return double_int_to_tree (sizetype, mem_ref_offset (expr));
+
     default:
       return error_mark_node;
     }
@@ -161,19 +166,20 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
 
   pt_var = TREE_OPERAND (ptr, 0);
-  if (REFERENCE_CLASS_P (pt_var))
-    pt_var = get_base_address (pt_var);
+  while (handled_component_p (pt_var))
+    pt_var = TREE_OPERAND (pt_var, 0);
 
   if (pt_var
-      && TREE_CODE (pt_var) == INDIRECT_REF
-      && TREE_CODE (TREE_OPERAND (pt_var, 0)) == SSA_NAME
-      && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (pt_var, 0))))
+      && TREE_CODE (pt_var) == MEM_REF)
     {
       unsigned HOST_WIDE_INT sz;
 
-      if (!osi)
-       sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
-                                         object_size_type);
+      if (!osi || (object_size_type & 1) != 0
+         || TREE_CODE (pt_var) != SSA_NAME)
+       {
+         sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
+                                           object_size_type & ~1);
+       }
       else
        {
          tree var = TREE_OPERAND (pt_var, 0);
@@ -185,12 +191,29 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
          else
            sz = unknown[object_size_type];
        }
+      if (sz != unknown[object_size_type])
+       {
+         double_int dsz = double_int_sub (uhwi_to_double_int (sz),
+                                          mem_ref_offset (pt_var));
+         if (double_int_negative_p (dsz))
+           sz = 0;
+         else if (double_int_fits_in_uhwi_p (dsz))
+           sz = double_int_to_uhwi (dsz);
+         else
+           sz = unknown[object_size_type];
+       }
 
       if (sz != unknown[object_size_type] && sz < offset_limit)
        pt_var_size = size_int (sz);
     }
   else if (pt_var
-          && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
+          && DECL_P (pt_var)
+          && host_integerp (DECL_SIZE_UNIT (pt_var), 1)
+          && (unsigned HOST_WIDE_INT)
+               tree_low_cst (DECL_SIZE_UNIT (pt_var), 1) < offset_limit)
+    pt_var_size = DECL_SIZE_UNIT (pt_var);
+  else if (pt_var
+          && TREE_CODE (pt_var) == STRING_CST
           && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
           && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
           && (unsigned HOST_WIDE_INT)
@@ -217,14 +240,14 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
                 && TREE_CODE (var) != IMAGPART_EXPR)
            var = TREE_OPERAND (var, 0);
          if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
-             var = TREE_OPERAND (var, 0);
+           var = TREE_OPERAND (var, 0);
          if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
              || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
              || (pt_var_size
                  && tree_int_cst_lt (pt_var_size,
                                      TYPE_SIZE_UNIT (TREE_TYPE (var)))))
            var = pt_var;
-         else if (var != pt_var && TREE_CODE (pt_var) == INDIRECT_REF)
+         else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
            {
              tree v = var;
              /* For &X->fld, compute object size only if fld isn't the last
@@ -257,27 +280,47 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
                    v = NULL_TREE;
                    break;
                  case COMPONENT_REF:
-                   if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-                        == RECORD_TYPE
-                        && TREE_CHAIN (TREE_OPERAND (v, 1)))
-                       || TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
-                     v = NULL_TREE;
-                   else
+                   if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
+                     {
+                       v = NULL_TREE;
+                       break;
+                     }
+                   while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+                     if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                         != UNION_TYPE
+                         && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                         != QUAL_UNION_TYPE)
+                       break;
+                     else
+                       v = TREE_OPERAND (v, 0);
+                   if (TREE_CODE (v) == COMPONENT_REF
+                       && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                          == RECORD_TYPE)
                      {
-                       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
-                           == RECORD_TYPE)
-                         v = TREE_OPERAND (v, 0);
-                       while (v && v != pt_var && TREE_CODE (v) == COMPONENT_REF)
-                         if (TREE_CODE (TREE_TYPE (v)) != UNION_TYPE
-                             && TREE_CODE (TREE_TYPE (v)) != QUAL_UNION_TYPE)
+                       tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
+                       for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
+                         if (TREE_CODE (fld_chain) == FIELD_DECL)
+                           break;
+
+                       if (fld_chain)
+                         {
+                           v = NULL_TREE;
                            break;
-                         else
-                           v = TREE_OPERAND (v, 0);
-                       if (v && v != pt_var)
-                         v = NULL_TREE;
-                       else
-                         v = pt_var;
+                         }
+                       v = TREE_OPERAND (v, 0);
                      }
+                   while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
+                     if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                         != UNION_TYPE
+                         && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+                         != QUAL_UNION_TYPE)
+                       break;
+                     else
+                       v = TREE_OPERAND (v, 0);
+                   if (v != pt_var)
+                     v = NULL_TREE;
+                   else
+                     v = pt_var;
                    break;
                  default:
                    v = pt_var;
@@ -307,7 +350,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
        }
       if (var != pt_var
          && pt_var_size
-         && TREE_CODE (pt_var) == INDIRECT_REF
+         && TREE_CODE (pt_var) == MEM_REF
          && bytes != error_mark_node)
        {
          tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
@@ -317,7 +360,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
                  && tree_int_cst_lt (pt_var_size, bytes2))
                bytes2 = size_zero_node;
              else
-               bytes2 = size_binop (MINUS_EXPR, var_size, bytes2);
+               bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
              bytes = size_binop (MIN_EXPR, bytes, bytes2);
            }
        }
@@ -361,7 +404,7 @@ alloc_object_size (const_gimple call, int object_size_type)
       if (TREE_CHAIN (p))
         arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
     }
+
   if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (callee))
       {
@@ -370,6 +413,7 @@ alloc_object_size (const_gimple call, int object_size_type)
        /* fall through */
       case BUILT_IN_MALLOC:
       case BUILT_IN_ALLOCA:
+      case BUILT_IN_ALLOCA_WITH_ALIGN:
        arg1 = 0;
       default:
        break;
@@ -377,10 +421,10 @@ alloc_object_size (const_gimple call, int object_size_type)
 
   if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call)
       || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST
-      || (arg2 >= 0 
+      || (arg2 >= 0
          && (arg2 >= (int)gimple_call_num_args (call)
              || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST)))
-    return unknown[object_size_type];    
+    return unknown[object_size_type];
 
   if (arg2 >= 0)
     bytes = size_binop (MULT_EXPR,
@@ -423,6 +467,7 @@ pass_through_call (const_gimple call)
       case BUILT_IN_STRNCPY_CHK:
       case BUILT_IN_STRCAT_CHK:
       case BUILT_IN_STRNCAT_CHK:
+      case BUILT_IN_ASSUME_ALIGNED:
        if (gimple_call_num_args (call) >= 1)
          return gimple_call_arg (call, 0);
        break;
@@ -725,10 +770,20 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple stmt)
   unsigned HOST_WIDE_INT bytes;
   tree op0, op1;
 
-  gcc_assert (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR);
-
-  op0 = gimple_assign_rhs1 (stmt);
-  op1 = gimple_assign_rhs2 (stmt);
+  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+    {
+      op0 = gimple_assign_rhs1 (stmt);
+      op1 = gimple_assign_rhs2 (stmt);
+    }
+  else if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
+    {
+      tree rhs = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
+      gcc_assert (TREE_CODE (rhs) == MEM_REF);
+      op0 = TREE_OPERAND (rhs, 0);
+      op1 = TREE_OPERAND (rhs, 1);
+    }
+  else
+    gcc_unreachable ();
 
   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
     return false;
@@ -775,25 +830,25 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple stmt)
 }
 
 
-/* Compute object_sizes for VAR, defined to VALUE, which is
+/* Compute object_sizes for VAR, defined at STMT, which is
    a COND_EXPR.  Return true if the object size might need reexamination
    later.  */
 
 static bool
-cond_expr_object_size (struct object_size_info *osi, tree var, tree value)
+cond_expr_object_size (struct object_size_info *osi, tree var, gimple stmt)
 {
   tree then_, else_;
   int object_size_type = osi->object_size_type;
   unsigned int varno = SSA_NAME_VERSION (var);
   bool reexamine = false;
 
-  gcc_assert (TREE_CODE (value) == COND_EXPR);
+  gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR);
 
   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
     return false;
 
-  then_ = COND_EXPR_THEN (value);
-  else_ = COND_EXPR_ELSE (value);
+  then_ = gimple_assign_rhs2 (stmt);
+  else_ = gimple_assign_rhs3 (stmt);
 
   if (TREE_CODE (then_) == SSA_NAME)
     reexamine |= merge_object_sizes (osi, var, then_, 0);
@@ -841,9 +896,8 @@ collect_object_sizes_for (struct object_size_info *osi, tree var)
 
   if (osi->pass == 0)
     {
-      if (! bitmap_bit_p (osi->visited, varno))
+      if (bitmap_set_bit (osi->visited, varno))
        {
-         bitmap_set_bit (osi->visited, varno);
          object_sizes[object_size_type][varno]
            = (object_size_type & 2) ? -1 : 0;
        }
@@ -876,18 +930,19 @@ collect_object_sizes_for (struct object_size_info *osi, tree var)
     {
     case GIMPLE_ASSIGN:
       {
-        if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+       tree rhs = gimple_assign_rhs1 (stmt);
+        if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
+           || (gimple_assign_rhs_code (stmt) == ADDR_EXPR
+               && TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF))
           reexamine = plus_stmt_object_size (osi, var, stmt);
+       else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+         reexamine = cond_expr_object_size (osi, var, stmt);
         else if (gimple_assign_single_p (stmt)
                  || gimple_assign_unary_nop_p (stmt))
           {
-            tree rhs = gimple_assign_rhs1 (stmt);
-
             if (TREE_CODE (rhs) == SSA_NAME
                 && POINTER_TYPE_P (TREE_TYPE (rhs)))
               reexamine = merge_object_sizes (osi, var, rhs, 0);
-            else if (TREE_CODE (rhs) == COND_EXPR)
-              reexamine = cond_expr_object_size (osi, var, rhs);
             else
               expr_object_size (osi, var, rhs);
           }
@@ -904,8 +959,6 @@ collect_object_sizes_for (struct object_size_info *osi, tree var)
             if (TREE_CODE (arg) == SSA_NAME
                 && POINTER_TYPE_P (TREE_TYPE (arg)))
               reexamine = merge_object_sizes (osi, var, arg, 0);
-            else if (TREE_CODE (arg) == COND_EXPR)
-              reexamine = cond_expr_object_size (osi, var, arg);
             else
               expr_object_size (osi, var, arg);
           }
@@ -1091,7 +1144,7 @@ check_for_plus_in_loops (struct object_size_info *osi, tree var)
     {
       tree basevar = gimple_assign_rhs1 (stmt);
       tree cst = gimple_assign_rhs2 (stmt);
-           
+
       gcc_assert (TREE_CODE (cst) == INTEGER_CST);
 
       if (integer_zerop (cst))
@@ -1183,7 +1236,7 @@ compute_object_sizes (void)
                        result = fold_convert (size_type_node,
                                               integer_minus_one_node);
                      else if (object_size_type < 4)
-                       result = size_zero_node;
+                       result = build_zero_cst (size_type_node);
                    }
                }
 
@@ -1200,13 +1253,10 @@ compute_object_sizes (void)
          if (!update_call_from_tree (&i, result))
            gcc_unreachable ();
 
-          /* NOTE: In the pre-tuples code, we called update_stmt here.  This is
-             now handled by gsi_replace, called from update_call_from_tree.  */
-
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
              fprintf (dump_file, "to\n  ");
-             print_gimple_stmt (dump_file, call, 0, dump_flags);
+             print_gimple_stmt (dump_file, gsi_stmt (i), 0, dump_flags);
              fprintf (dump_file, "\n");
            }
        }
@@ -1231,6 +1281,6 @@ struct gimple_opt_pass pass_object_sizes =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa     /* todo_flags_finish */
+  TODO_verify_ssa                      /* todo_flags_finish */
  }
 };