tree-object-size.c

Go to the documentation of this file.
00001 /* __builtin_object_size (ptr, object_size_type) computation
00002    Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
00003    Contributed by Jakub Jelinek <jakub@redhat.com>
00004 
00005 This file is part of GCC.
00006 
00007 GCC is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2, or (at your option)
00010 any later version.
00011 
00012 GCC is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with GCC; see the file COPYING.  If not, write to
00019 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
00020 Boston, MA 02110-1301, USA.  */
00021 
00022 #include "config.h"
00023 #include "system.h"
00024 #include "coretypes.h"
00025 #include "tm.h"
00026 #include "tree.h"
00027 #include "diagnostic.h"
00028 #include "tree-flow.h"
00029 #include "tree-pass.h"
00030 #include "tree-ssa-propagate.h"
00031 
00032 struct object_size_info
00033 {
00034   int object_size_type;
00035   bitmap visited, reexamine;
00036   int pass;
00037   bool changed;
00038   unsigned int *depths;
00039   unsigned int *stack, *tos;
00040 };
00041 
00042 static unsigned HOST_WIDE_INT unknown[4] = { -1, -1, 0, 0 };
00043 
00044 static tree compute_object_offset (tree, tree);
00045 static unsigned HOST_WIDE_INT addr_object_size (tree, int);
00046 static unsigned HOST_WIDE_INT alloc_object_size (tree, int);
00047 static tree pass_through_call (tree);
00048 static void collect_object_sizes_for (struct object_size_info *, tree);
00049 static void expr_object_size (struct object_size_info *, tree, tree);
00050 static bool merge_object_sizes (struct object_size_info *, tree, tree,
00051                                 unsigned HOST_WIDE_INT);
00052 static bool plus_expr_object_size (struct object_size_info *, tree, tree);
00053 static unsigned int compute_object_sizes (void);
00054 static void init_offset_limit (void);
00055 static void check_for_plus_in_loops (struct object_size_info *, tree);
00056 static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
00057                                        unsigned int);
00058 
00059 /* object_sizes[0] is upper bound for number of bytes till the end of
00060    the object.
00061    object_sizes[1] is upper bound for number of bytes till the end of
00062    the subobject (innermost array or field with address taken).
00063    object_sizes[2] is lower bound for number of bytes till the end of
00064    the object and object_sizes[3] lower bound for subobject.  */
00065 static unsigned HOST_WIDE_INT *object_sizes[4];
00066 
00067 /* Bitmaps what object sizes have been computed already.  */
00068 static bitmap computed[4];
00069 
00070 /* Maximum value of offset we consider to be addition.  */
00071 static unsigned HOST_WIDE_INT offset_limit;
00072 
00073 
00074 /* Initialize OFFSET_LIMIT variable.  */
00075 static void
00076 init_offset_limit (void)
00077 {
00078   if (host_integerp (TYPE_MAX_VALUE (sizetype), 1))
00079     offset_limit = tree_low_cst (TYPE_MAX_VALUE (sizetype), 1);
00080   else
00081     offset_limit = -1;
00082   offset_limit /= 2;
00083 }
00084 
00085 
00086 /* Compute offset of EXPR within VAR.  Return error_mark_node
00087    if unknown.  */
00088 
00089 static tree
00090 compute_object_offset (tree expr, tree var)
00091 {
00092   enum tree_code code = PLUS_EXPR;
00093   tree base, off, t;
00094 
00095   if (expr == var)
00096     return size_zero_node;
00097 
00098   switch (TREE_CODE (expr))
00099     {
00100     case COMPONENT_REF:
00101       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00102       if (base == error_mark_node)
00103         return base;
00104 
00105       t = TREE_OPERAND (expr, 1);
00106       off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
00107                         size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
00108                                   / BITS_PER_UNIT));
00109       break;
00110 
00111     case REALPART_EXPR:
00112     case NOP_EXPR:
00113     case CONVERT_EXPR:
00114     case VIEW_CONVERT_EXPR:
00115     case NON_LVALUE_EXPR:
00116       return compute_object_offset (TREE_OPERAND (expr, 0), var);
00117 
00118     case IMAGPART_EXPR:
00119       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00120       if (base == error_mark_node)
00121         return base;
00122 
00123       off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
00124       break;
00125 
00126     case ARRAY_REF:
00127       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
00128       if (base == error_mark_node)
00129         return base;
00130 
00131       t = TREE_OPERAND (expr, 1);
00132       if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
00133         {
00134           code = MINUS_EXPR;
00135           t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
00136         }
00137       t = fold_convert (sizetype, t);
00138       off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
00139       break;
00140 
00141     default:
00142       return error_mark_node;
00143     }
00144 
00145   return size_binop (code, base, off);
00146 }
00147 
00148 
00149 /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
00150    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
00151    If unknown, return unknown[object_size_type].  */
00152 
00153 static unsigned HOST_WIDE_INT
00154 addr_object_size (tree ptr, int object_size_type)
00155 {
00156   tree pt_var;
00157 
00158   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
00159 
00160   pt_var = TREE_OPERAND (ptr, 0);
00161   if (REFERENCE_CLASS_P (pt_var))
00162     pt_var = get_base_address (pt_var);
00163 
00164   if (pt_var
00165       && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
00166       && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
00167       && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
00168       && (unsigned HOST_WIDE_INT)
00169          tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit)
00170     {
00171       tree bytes;
00172 
00173       if (pt_var != TREE_OPERAND (ptr, 0))
00174         {
00175           tree var;
00176 
00177           if (object_size_type & 1)
00178             {
00179               var = TREE_OPERAND (ptr, 0);
00180 
00181               while (var != pt_var
00182                       && TREE_CODE (var) != BIT_FIELD_REF
00183                       && TREE_CODE (var) != COMPONENT_REF
00184                       && TREE_CODE (var) != ARRAY_REF
00185                       && TREE_CODE (var) != ARRAY_RANGE_REF
00186                       && TREE_CODE (var) != REALPART_EXPR
00187                       && TREE_CODE (var) != IMAGPART_EXPR)
00188                 var = TREE_OPERAND (var, 0);
00189               if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
00190                 var = TREE_OPERAND (var, 0);
00191               if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
00192                   || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
00193                   || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
00194                                       TYPE_SIZE_UNIT (TREE_TYPE (var))))
00195                 var = pt_var;
00196             }
00197           else
00198             var = pt_var;
00199 
00200           bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
00201           if (bytes != error_mark_node)
00202             {
00203               if (TREE_CODE (bytes) == INTEGER_CST
00204                   && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes))
00205                 bytes = size_zero_node;
00206               else
00207                 bytes = size_binop (MINUS_EXPR,
00208                                     TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes);
00209             }
00210         }
00211       else
00212         bytes = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
00213 
00214       if (host_integerp (bytes, 1))
00215         return tree_low_cst (bytes, 1);
00216     }
00217 
00218   return unknown[object_size_type];
00219 }
00220 
00221 
00222 /* Compute __builtin_object_size for CALL, which is a CALL_EXPR.
00223    Handles various allocation calls.  OBJECT_SIZE_TYPE is the second
00224    argument from __builtin_object_size.  If unknown, return
00225    unknown[object_size_type].  */
00226 
00227 static unsigned HOST_WIDE_INT
00228 alloc_object_size (tree call, int object_size_type)
00229 {
00230   tree callee, arglist, a, bytes = NULL_TREE;
00231   unsigned int arg_mask = 0;
00232 
00233   gcc_assert (TREE_CODE (call) == CALL_EXPR);
00234 
00235   callee = get_callee_fndecl (call);
00236   arglist = TREE_OPERAND (call, 1);
00237   if (callee
00238       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
00239     switch (DECL_FUNCTION_CODE (callee))
00240       {
00241       case BUILT_IN_MALLOC:
00242       case BUILT_IN_ALLOCA:
00243         arg_mask = 1;
00244         break;
00245       /*
00246       case BUILT_IN_REALLOC:
00247         arg_mask = 2;
00248         break;
00249         */
00250       case BUILT_IN_CALLOC:
00251         arg_mask = 3;
00252         break;
00253       default:
00254         break;
00255       }
00256 
00257   for (a = arglist; arg_mask && a; arg_mask >>= 1, a = TREE_CHAIN (a))
00258     if (arg_mask & 1)
00259       {
00260         tree arg = TREE_VALUE (a);
00261 
00262         if (TREE_CODE (arg) != INTEGER_CST)
00263           break;
00264 
00265         if (! bytes)
00266           bytes = fold_convert (sizetype, arg);
00267         else
00268           bytes = size_binop (MULT_EXPR, bytes,
00269                               fold_convert (sizetype, arg));
00270       }
00271 
00272   if (! arg_mask && bytes && host_integerp (bytes, 1))
00273     return tree_low_cst (bytes, 1);
00274 
00275   return unknown[object_size_type];
00276 }
00277 
00278 
00279 /* If object size is propagated from one of function's arguments directly
00280    to its return value, return that argument for CALL_EXPR CALL.
00281    Otherwise return NULL.  */
00282 
00283 static tree
00284 pass_through_call (tree call)
00285 {
00286   tree callee = get_callee_fndecl (call);
00287   tree arglist = TREE_OPERAND (call, 1);
00288 
00289   if (callee
00290       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
00291     switch (DECL_FUNCTION_CODE (callee))
00292       {
00293       case BUILT_IN_MEMCPY:
00294       case BUILT_IN_MEMMOVE:
00295       case BUILT_IN_MEMSET:
00296       case BUILT_IN_STRCPY:
00297       case BUILT_IN_STRNCPY:
00298       case BUILT_IN_STRCAT:
00299       case BUILT_IN_STRNCAT:
00300       case BUILT_IN_MEMCPY_CHK:
00301       case BUILT_IN_MEMMOVE_CHK:
00302       case BUILT_IN_MEMSET_CHK:
00303       case BUILT_IN_STRCPY_CHK:
00304       case BUILT_IN_STRNCPY_CHK:
00305       case BUILT_IN_STRCAT_CHK:
00306       case BUILT_IN_STRNCAT_CHK:
00307         if (arglist)
00308           return TREE_VALUE (arglist);
00309         break;
00310       default:
00311         break;
00312       }
00313 
00314   return NULL_TREE;
00315 }
00316 
00317 
00318 /* Compute __builtin_object_size value for PTR.  OBJECT_SIZE_TYPE is the
00319    second argument from __builtin_object_size.  */
00320 
00321 unsigned HOST_WIDE_INT
00322 compute_builtin_object_size (tree ptr, int object_size_type)
00323 {
00324   gcc_assert (object_size_type >= 0 && object_size_type <= 3);
00325 
00326   if (! offset_limit)
00327     init_offset_limit ();
00328 
00329   if (TREE_CODE (ptr) == ADDR_EXPR)
00330     return addr_object_size (ptr, object_size_type);
00331   else if (TREE_CODE (ptr) == CALL_EXPR)
00332     {
00333       tree arg = pass_through_call (ptr);
00334 
00335       if (arg)
00336         return compute_builtin_object_size (arg, object_size_type);
00337       else
00338         return alloc_object_size (ptr, object_size_type);
00339     }
00340   else if (TREE_CODE (ptr) == SSA_NAME
00341            && POINTER_TYPE_P (TREE_TYPE (ptr))
00342            && object_sizes[object_size_type] != NULL)
00343     {
00344       if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
00345         {
00346           struct object_size_info osi;
00347           bitmap_iterator bi;
00348           unsigned int i;
00349 
00350           if (dump_file)
00351             {
00352               fprintf (dump_file, "Computing %s %sobject size for ",
00353                        (object_size_type & 2) ? "minimum" : "maximum",
00354                        (object_size_type & 1) ? "sub" : "");
00355               print_generic_expr (dump_file, ptr, dump_flags);
00356               fprintf (dump_file, ":\n");
00357             }
00358 
00359           osi.visited = BITMAP_ALLOC (NULL);
00360           osi.reexamine = BITMAP_ALLOC (NULL);
00361           osi.object_size_type = object_size_type;
00362           osi.depths = NULL;
00363           osi.stack = NULL;
00364           osi.tos = NULL;
00365 
00366           /* First pass: walk UD chains, compute object sizes that
00367              can be computed.  osi.reexamine bitmap at the end will
00368              contain what variables were found in dependency cycles
00369              and therefore need to be reexamined.  */
00370           osi.pass = 0;
00371           osi.changed = false;
00372           collect_object_sizes_for (&osi, ptr);
00373 
00374           /* Second pass: keep recomputing object sizes of variables
00375              that need reexamination, until no object sizes are
00376              increased or all object sizes are computed.  */
00377           if (! bitmap_empty_p (osi.reexamine))
00378             {
00379               bitmap reexamine = BITMAP_ALLOC (NULL);
00380 
00381               /* If looking for minimum instead of maximum object size,
00382                  detect cases where a pointer is increased in a loop.
00383                  Although even without this detection pass 2 would eventually
00384                  terminate, it could take a long time.  If a pointer is
00385                  increasing this way, we need to assume 0 object size.
00386                  E.g. p = &buf[0]; while (cond) p = p + 4;  */
00387               if (object_size_type & 2)
00388                 {
00389                   osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
00390                   osi.stack = XNEWVEC (unsigned int, num_ssa_names);
00391                   osi.tos = osi.stack;
00392                   osi.pass = 1;
00393                   /* collect_object_sizes_for is changing
00394                      osi.reexamine bitmap, so iterate over a copy.  */
00395                   bitmap_copy (reexamine, osi.reexamine);
00396                   EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
00397                     if (bitmap_bit_p (osi.reexamine, i))
00398                       check_for_plus_in_loops (&osi, ssa_name (i));
00399 
00400                   free (osi.depths);
00401                   osi.depths = NULL;
00402                   free (osi.stack);
00403                   osi.stack = NULL;
00404                   osi.tos = NULL;
00405                 }
00406 
00407               do
00408                 {
00409                   osi.pass = 2;
00410                   osi.changed = false;
00411                   /* collect_object_sizes_for is changing
00412                      osi.reexamine bitmap, so iterate over a copy.  */
00413                   bitmap_copy (reexamine, osi.reexamine);
00414                   EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
00415                     if (bitmap_bit_p (osi.reexamine, i))
00416                       {
00417                         collect_object_sizes_for (&osi, ssa_name (i));
00418                         if (dump_file && (dump_flags & TDF_DETAILS))
00419                           {
00420                             fprintf (dump_file, "Reexamining ");
00421                             print_generic_expr (dump_file, ssa_name (i),
00422                                                 dump_flags);
00423                             fprintf (dump_file, "\n");
00424                           }
00425                       }
00426                 }
00427               while (osi.changed);
00428 
00429               BITMAP_FREE (reexamine);
00430             }
00431           EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
00432             bitmap_set_bit (computed[object_size_type], i);
00433 
00434           /* Debugging dumps.  */
00435           if (dump_file)
00436             {
00437               EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
00438                 if (object_sizes[object_size_type][i]
00439                     != unknown[object_size_type])
00440                   {
00441                     print_generic_expr (dump_file, ssa_name (i),
00442                                         dump_flags);
00443                     fprintf (dump_file,
00444                              ": %s %sobject size "
00445                              HOST_WIDE_INT_PRINT_UNSIGNED "\n",
00446                              (object_size_type & 2) ? "minimum" : "maximum",
00447                              (object_size_type & 1) ? "sub" : "",
00448                              object_sizes[object_size_type][i]);
00449                   }
00450             }
00451 
00452           BITMAP_FREE (osi.reexamine);
00453           BITMAP_FREE (osi.visited);
00454         }
00455 
00456       return object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
00457     }
00458 
00459   return unknown[object_size_type];
00460 }
00461 
00462 
00463 /* Compute object_sizes for PTR, defined to VALUE, which is not
00464    a SSA_NAME.  */
00465 
00466 static void
00467 expr_object_size (struct object_size_info *osi, tree ptr, tree value)
00468 {
00469   int object_size_type = osi->object_size_type;
00470   unsigned int varno = SSA_NAME_VERSION (ptr);
00471   unsigned HOST_WIDE_INT bytes;
00472 
00473   gcc_assert (object_sizes[object_size_type][varno]
00474               != unknown[object_size_type]);
00475   gcc_assert (osi->pass == 0);
00476 
00477   if (TREE_CODE (value) == WITH_SIZE_EXPR)
00478     value = TREE_OPERAND (value, 0);
00479 
00480   /* Pointer variables should have been handled by merge_object_sizes.  */
00481   gcc_assert (TREE_CODE (value) != SSA_NAME
00482               || !POINTER_TYPE_P (TREE_TYPE (value)));
00483 
00484   if (TREE_CODE (value) == ADDR_EXPR)
00485     bytes = addr_object_size (value, object_size_type);
00486   else if (TREE_CODE (value) == CALL_EXPR)
00487     bytes = alloc_object_size (value, object_size_type);
00488   else
00489     bytes = unknown[object_size_type];
00490 
00491   if ((object_size_type & 2) == 0)
00492     {
00493       if (object_sizes[object_size_type][varno] < bytes)
00494         object_sizes[object_size_type][varno] = bytes;
00495     }
00496   else
00497     {
00498       if (object_sizes[object_size_type][varno] > bytes)
00499         object_sizes[object_size_type][varno] = bytes;
00500     }
00501 }
00502 
00503 
00504 /* Merge object sizes of ORIG + OFFSET into DEST.  Return true if
00505    the object size might need reexamination later.  */
00506 
00507 static bool
00508 merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
00509                     unsigned HOST_WIDE_INT offset)
00510 {
00511   int object_size_type = osi->object_size_type;
00512   unsigned int varno = SSA_NAME_VERSION (dest);
00513   unsigned HOST_WIDE_INT orig_bytes;
00514 
00515   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
00516     return false;
00517   if (offset >= offset_limit)
00518     {
00519       object_sizes[object_size_type][varno] = unknown[object_size_type];
00520       return false;
00521     }
00522 
00523   if (osi->pass == 0)
00524     collect_object_sizes_for (osi, orig);
00525 
00526   orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
00527   if (orig_bytes != unknown[object_size_type])
00528     orig_bytes = (offset > orig_bytes)
00529                  ? (unsigned HOST_WIDE_INT) 0 : orig_bytes - offset;
00530 
00531   if ((object_size_type & 2) == 0)
00532     {
00533       if (object_sizes[object_size_type][varno] < orig_bytes)
00534         {
00535           object_sizes[object_size_type][varno] = orig_bytes;
00536           osi->changed = true;
00537         }
00538     }
00539   else
00540     {
00541       if (object_sizes[object_size_type][varno] > orig_bytes)
00542         {
00543           object_sizes[object_size_type][varno] = orig_bytes;
00544           osi->changed = true;
00545         }
00546     }
00547   return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
00548 }
00549 
00550 
00551 /* Compute object_sizes for PTR, defined to VALUE, which is
00552    a PLUS_EXPR.  Return true if the object size might need reexamination
00553    later.  */
00554 
00555 static bool
00556 plus_expr_object_size (struct object_size_info *osi, tree var, tree value)
00557 {
00558   tree op0 = TREE_OPERAND (value, 0);
00559   tree op1 = TREE_OPERAND (value, 1);
00560   bool ptr1_p = POINTER_TYPE_P (TREE_TYPE (op0))
00561                 && TREE_CODE (op0) != INTEGER_CST;
00562   bool ptr2_p = POINTER_TYPE_P (TREE_TYPE (op1))
00563                 && TREE_CODE (op1) != INTEGER_CST;
00564   int object_size_type = osi->object_size_type;
00565   unsigned int varno = SSA_NAME_VERSION (var);
00566   unsigned HOST_WIDE_INT bytes;
00567 
00568   gcc_assert (TREE_CODE (value) == PLUS_EXPR);
00569 
00570   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
00571     return false;
00572 
00573   /* Swap operands if needed.  */
00574   if (ptr2_p && !ptr1_p)
00575     {
00576       tree tem = op0;
00577       op0 = op1;
00578       op1 = tem;
00579       ptr1_p = true;
00580       ptr2_p = false;
00581     }
00582 
00583   /* Handle PTR + OFFSET here.  */
00584   if (ptr1_p
00585       && !ptr2_p
00586       && TREE_CODE (op1) == INTEGER_CST
00587       && (TREE_CODE (op0) == SSA_NAME
00588           || TREE_CODE (op0) == ADDR_EXPR))
00589     {
00590       if (! host_integerp (op1, 1))
00591         bytes = unknown[object_size_type];
00592       else if (TREE_CODE (op0) == SSA_NAME)
00593         return merge_object_sizes (osi, var, op0, tree_low_cst (op1, 1));
00594       else
00595         {
00596           unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);
00597 
00598           bytes = compute_builtin_object_size (op0, object_size_type);
00599           if (off > offset_limit)
00600             bytes = unknown[object_size_type];
00601           else if (off > bytes)
00602             bytes = 0;
00603           else
00604             bytes -= off;
00605         }
00606     }
00607   else
00608     bytes = unknown[object_size_type];
00609 
00610   if ((object_size_type & 2) == 0)
00611     {
00612       if (object_sizes[object_size_type][varno] < bytes)
00613         object_sizes[object_size_type][varno] = bytes;
00614     }
00615   else
00616     {
00617       if (object_sizes[object_size_type][varno] > bytes)
00618         object_sizes[object_size_type][varno] = bytes;
00619     }
00620   return false;
00621 }
00622 
00623 
00624 /* Compute object sizes for VAR.
00625    For ADDR_EXPR an object size is the number of remaining bytes
00626    to the end of the object (where what is considered an object depends on
00627    OSI->object_size_type).
00628    For allocation CALL_EXPR like malloc or calloc object size is the size
00629    of the allocation.
00630    For pointer PLUS_EXPR where second operand is a constant integer,
00631    object size is object size of the first operand minus the constant.
00632    If the constant is bigger than the number of remaining bytes until the
00633    end of the object, object size is 0, but if it is instead a pointer
00634    subtraction, object size is unknown[object_size_type].
00635    To differentiate addition from subtraction, ADDR_EXPR returns
00636    unknown[object_size_type] for all objects bigger than half of the address
00637    space, and constants less than half of the address space are considered
00638    addition, while bigger constants subtraction.
00639    For a memcpy like CALL_EXPR that always returns one of its arguments, the
00640    object size is object size of that argument.
00641    Otherwise, object size is the maximum of object sizes of variables
00642    that it might be set to.  */
00643 
00644 static void
00645 collect_object_sizes_for (struct object_size_info *osi, tree var)
00646 {
00647   int object_size_type = osi->object_size_type;
00648   unsigned int varno = SSA_NAME_VERSION (var);
00649   tree stmt;
00650   bool reexamine;
00651 
00652   if (bitmap_bit_p (computed[object_size_type], varno))
00653     return;
00654 
00655   if (osi->pass == 0)
00656     {
00657       if (! bitmap_bit_p (osi->visited, varno))
00658         {
00659           bitmap_set_bit (osi->visited, varno);
00660           object_sizes[object_size_type][varno]
00661             = (object_size_type & 2) ? -1 : 0;
00662         }
00663       else
00664         {
00665           /* Found a dependency loop.  Mark the variable for later
00666              re-examination.  */
00667           bitmap_set_bit (osi->reexamine, varno);
00668           if (dump_file && (dump_flags & TDF_DETAILS))
00669             {
00670               fprintf (dump_file, "Found a dependency loop at ");
00671               print_generic_expr (dump_file, var, dump_flags);
00672               fprintf (dump_file, "\n");
00673             }
00674           return;
00675         }
00676     }
00677 
00678   if (dump_file && (dump_flags & TDF_DETAILS))
00679     {
00680       fprintf (dump_file, "Visiting use-def links for ");
00681       print_generic_expr (dump_file, var, dump_flags);
00682       fprintf (dump_file, "\n");
00683     }
00684 
00685   stmt = SSA_NAME_DEF_STMT (var);
00686   reexamine = false;
00687 
00688   switch (TREE_CODE (stmt))
00689     {
00690     case RETURN_EXPR:
00691       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00692       stmt = TREE_OPERAND (stmt, 0);
00693       /* FALLTHRU  */
00694 
00695     case MODIFY_EXPR:
00696       {
00697         tree rhs = TREE_OPERAND (stmt, 1), arg;
00698         STRIP_NOPS (rhs);
00699 
00700         if (TREE_CODE (rhs) == CALL_EXPR)
00701           {
00702             arg = pass_through_call (rhs);
00703             if (arg)
00704               rhs = arg;
00705           }
00706 
00707         if (TREE_CODE (rhs) == SSA_NAME
00708             && POINTER_TYPE_P (TREE_TYPE (rhs)))
00709           reexamine = merge_object_sizes (osi, var, rhs, 0);
00710 
00711         else if (TREE_CODE (rhs) == PLUS_EXPR)
00712           reexamine = plus_expr_object_size (osi, var, rhs);
00713 
00714         else
00715           expr_object_size (osi, var, rhs);
00716         break;
00717       }
00718 
00719     case ASM_EXPR:
00720       /* Pointers defined by __asm__ statements can point anywhere.  */
00721       object_sizes[object_size_type][varno] = unknown[object_size_type];
00722       break;
00723 
00724     case NOP_EXPR:
00725       {
00726         tree decl = SSA_NAME_VAR (var);
00727 
00728         gcc_assert (IS_EMPTY_STMT (stmt));
00729 
00730         if (TREE_CODE (decl) != PARM_DECL && DECL_INITIAL (decl))
00731           expr_object_size (osi, var, DECL_INITIAL (decl));
00732         else
00733           expr_object_size (osi, var, decl);
00734       }
00735       break;
00736 
00737     case PHI_NODE:
00738       {
00739         int i;
00740 
00741         for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
00742           {
00743             tree rhs = PHI_ARG_DEF (stmt, i);
00744 
00745             if (object_sizes[object_size_type][varno]
00746                 == unknown[object_size_type])
00747               break;
00748 
00749             if (TREE_CODE (rhs) == SSA_NAME)
00750               reexamine |= merge_object_sizes (osi, var, rhs, 0);
00751             else if (osi->pass == 0)
00752               expr_object_size (osi, var, rhs);
00753           }
00754         break;
00755       }
00756     default:
00757       gcc_unreachable ();
00758     }
00759 
00760   if (! reexamine
00761       || object_sizes[object_size_type][varno] == unknown[object_size_type])
00762     {
00763       bitmap_set_bit (computed[object_size_type], varno);
00764       bitmap_clear_bit (osi->reexamine, varno);
00765     }
00766   else
00767     {
00768       bitmap_set_bit (osi->reexamine, varno);
00769       if (dump_file && (dump_flags & TDF_DETAILS))
00770         {
00771           fprintf (dump_file, "Need to reexamine ");
00772           print_generic_expr (dump_file, var, dump_flags);
00773           fprintf (dump_file, "\n");
00774         }
00775     }
00776 }
00777 
00778 
00779 /* Helper function for check_for_plus_in_loops.  Called recursively
00780    to detect loops.  */
00781 
00782 static void
00783 check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
00784                            unsigned int depth)
00785 {
00786   tree stmt = SSA_NAME_DEF_STMT (var);
00787   unsigned int varno = SSA_NAME_VERSION (var);
00788 
00789   if (osi->depths[varno])
00790     {
00791       if (osi->depths[varno] != depth)
00792         {
00793           unsigned int *sp;
00794 
00795           /* Found a loop involving pointer addition.  */
00796           for (sp = osi->tos; sp > osi->stack; )
00797             {
00798               --sp;
00799               bitmap_clear_bit (osi->reexamine, *sp);
00800               bitmap_set_bit (computed[osi->object_size_type], *sp);
00801               object_sizes[osi->object_size_type][*sp] = 0;
00802               if (*sp == varno)
00803                 break;
00804             }
00805         }
00806       return;
00807     }
00808   else if (! bitmap_bit_p (osi->reexamine, varno))
00809     return;
00810 
00811   osi->depths[varno] = depth;
00812   *osi->tos++ = varno;
00813 
00814   switch (TREE_CODE (stmt))
00815     {
00816     case RETURN_EXPR:
00817       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00818       stmt = TREE_OPERAND (stmt, 0);
00819       /* FALLTHRU  */
00820 
00821     case MODIFY_EXPR:
00822       {
00823         tree rhs = TREE_OPERAND (stmt, 1), arg;
00824         STRIP_NOPS (rhs);
00825 
00826         if (TREE_CODE (rhs) == CALL_EXPR)
00827           {
00828             arg = pass_through_call (rhs);
00829             if (arg)
00830               rhs = arg;
00831           }
00832 
00833         if (TREE_CODE (rhs) == SSA_NAME)
00834           check_for_plus_in_loops_1 (osi, rhs, depth);
00835         else if (TREE_CODE (rhs) == PLUS_EXPR)
00836           {
00837             tree op0 = TREE_OPERAND (rhs, 0);
00838             tree op1 = TREE_OPERAND (rhs, 1);
00839             tree cst, basevar;
00840 
00841             if (TREE_CODE (op0) == SSA_NAME)
00842               {
00843                 basevar = op0;
00844                 cst = op1;
00845               }
00846             else
00847               {
00848                 basevar = op1;
00849                 cst = op0;
00850                 gcc_assert (TREE_CODE (basevar) == SSA_NAME);
00851               }
00852             gcc_assert (TREE_CODE (cst) == INTEGER_CST);
00853 
00854             check_for_plus_in_loops_1 (osi, basevar,
00855                                        depth + !integer_zerop (cst));
00856           }
00857         else
00858           gcc_unreachable ();
00859         break;
00860       }
00861     case PHI_NODE:
00862       {
00863         int i;
00864 
00865         for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
00866           {
00867             tree rhs = PHI_ARG_DEF (stmt, i);
00868 
00869             if (TREE_CODE (rhs) == SSA_NAME)
00870               check_for_plus_in_loops_1 (osi, rhs, depth);
00871           }
00872         break;
00873       }
00874     default:
00875       gcc_unreachable ();
00876     }
00877 
00878   osi->depths[varno] = 0;
00879   osi->tos--;
00880 }
00881 
00882 
00883 /* Check if some pointer we are computing object size of is being increased
00884    within a loop.  If yes, assume all the SSA variables participating in
00885    that loop have minimum object sizes 0.  */
00886 
00887 static void
00888 check_for_plus_in_loops (struct object_size_info *osi, tree var)
00889 {
00890   tree stmt = SSA_NAME_DEF_STMT (var);
00891 
00892   switch (TREE_CODE (stmt))
00893     {
00894     case RETURN_EXPR:
00895       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
00896       stmt = TREE_OPERAND (stmt, 0);
00897       /* FALLTHRU  */
00898 
00899     case MODIFY_EXPR:
00900       {
00901         tree rhs = TREE_OPERAND (stmt, 1), arg;
00902         STRIP_NOPS (rhs);
00903 
00904         if (TREE_CODE (rhs) == CALL_EXPR)
00905           {
00906             arg = pass_through_call (rhs);
00907             if (arg)
00908               rhs = arg;
00909           }
00910 
00911         if (TREE_CODE (rhs) == PLUS_EXPR)
00912           {
00913             tree op0 = TREE_OPERAND (rhs, 0);
00914             tree op1 = TREE_OPERAND (rhs, 1);
00915             tree cst, basevar;
00916 
00917             if (TREE_CODE (op0) == SSA_NAME)
00918               {
00919                 basevar = op0;
00920                 cst = op1;
00921               }
00922             else
00923               {
00924                 basevar = op1;
00925                 cst = op0;
00926                 gcc_assert (TREE_CODE (basevar) == SSA_NAME);
00927               }
00928             gcc_assert (TREE_CODE (cst) == INTEGER_CST);
00929 
00930             if (integer_zerop (cst))
00931               break;
00932 
00933             osi->depths[SSA_NAME_VERSION (basevar)] = 1;
00934             *osi->tos++ = SSA_NAME_VERSION (basevar);
00935             check_for_plus_in_loops_1 (osi, var, 2);
00936             osi->depths[SSA_NAME_VERSION (basevar)] = 0;
00937             osi->tos--;
00938           }
00939         break;
00940       }
00941     default:
00942       break;
00943     }
00944 }
00945 
00946 
00947 /* Initialize data structures for the object size computation.  */
00948 
00949 void
00950 init_object_sizes (void)
00951 {
00952   int object_size_type;
00953 
00954   if (object_sizes[0])
00955     return;
00956 
00957   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
00958     {
00959       object_sizes[object_size_type] = XNEWVEC (unsigned HOST_WIDE_INT, num_ssa_names);
00960       computed[object_size_type] = BITMAP_ALLOC (NULL);
00961     }
00962 
00963   init_offset_limit ();
00964 }
00965 
00966 
00967 /* Destroy data structures after the object size computation.  */
00968 
00969 void
00970 fini_object_sizes (void)
00971 {
00972   int object_size_type;
00973 
00974   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
00975     {
00976       free (object_sizes[object_size_type]);
00977       BITMAP_FREE (computed[object_size_type]);
00978       object_sizes[object_size_type] = NULL;
00979     }
00980 }
00981 
00982 
00983 /* Simple pass to optimize all __builtin_object_size () builtins.  */
00984 
00985 static unsigned int
00986 compute_object_sizes (void)
00987 {
00988   basic_block bb;
00989   FOR_EACH_BB (bb)
00990     {
00991       block_stmt_iterator i;
00992       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
00993         {
00994           tree *stmtp = bsi_stmt_ptr (i);
00995           tree call = get_rhs (*stmtp);
00996           tree callee, result;
00997 
00998           if (!call || TREE_CODE (call) != CALL_EXPR)
00999             continue;
01000 
01001           callee = get_callee_fndecl (call);
01002           if (!callee
01003               || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
01004               || DECL_FUNCTION_CODE (callee) != BUILT_IN_OBJECT_SIZE)
01005             continue;
01006 
01007           init_object_sizes ();
01008           result = fold_builtin (callee, TREE_OPERAND (call, 1), false);
01009           if (!result)
01010             {
01011               tree arglist = TREE_OPERAND (call, 1);
01012 
01013               if (arglist != NULL
01014                   && POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
01015                   && TREE_CHAIN (arglist) != NULL
01016                   && TREE_CHAIN (TREE_CHAIN (arglist)) == NULL)
01017                 {
01018                   tree ost = TREE_VALUE (TREE_CHAIN (arglist));
01019 
01020                   if (host_integerp (ost, 1))
01021                     {
01022                       unsigned HOST_WIDE_INT object_size_type
01023                         = tree_low_cst (ost, 1);
01024 
01025                       if (object_size_type < 2)
01026                         result = fold_convert (size_type_node,
01027                                                integer_minus_one_node);
01028                       else if (object_size_type < 4)
01029                         result = size_zero_node;
01030                     }
01031                 }
01032 
01033               if (!result)
01034                 continue;
01035             }
01036 
01037           if (dump_file && (dump_flags & TDF_DETAILS))
01038             {
01039               fprintf (dump_file, "Simplified\n  ");
01040               print_generic_stmt (dump_file, *stmtp, dump_flags);
01041             }
01042 
01043           if (!set_rhs (stmtp, result))
01044             gcc_unreachable ();
01045           update_stmt (*stmtp);
01046 
01047           if (dump_file && (dump_flags & TDF_DETAILS))
01048             {
01049               fprintf (dump_file, "to\n  ");
01050               print_generic_stmt (dump_file, *stmtp, dump_flags);
01051               fprintf (dump_file, "\n");
01052             }
01053         }
01054     }
01055 
01056   fini_object_sizes ();
01057   return 0;
01058 }
01059 
01060 struct tree_opt_pass pass_object_sizes =
01061 {
01062   "objsz",                              /* name */
01063   NULL,                                 /* gate */
01064   compute_object_sizes,                 /* execute */
01065   NULL,                                 /* sub */
01066   NULL,                                 /* next */
01067   0,                                    /* static_pass_number */
01068   0,                                    /* tv_id */
01069   PROP_cfg | PROP_ssa | PROP_alias,     /* properties_required */
01070   0,                                    /* properties_provided */
01071   0,                                    /* properties_destroyed */
01072   0,                                    /* todo_flags_start */
01073   TODO_dump_func | TODO_verify_ssa,     /* todo_flags_finish */
01074   0                                     /* letter */
01075 };

Generated on Sun Sep 17 18:03:29 2006 for Tree SSA by  doxygen 1.4.6