xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-object-size.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg /* __builtin_object_size (ptr, object_size_type) computation
2*8feb0f0bSmrg    Copyright (C) 2004-2020 Free Software Foundation, Inc.
31debfc3dSmrg    Contributed by Jakub Jelinek <jakub@redhat.com>
41debfc3dSmrg 
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg 
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg 
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg 
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3.  If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>.  */
201debfc3dSmrg 
211debfc3dSmrg #include "config.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "backend.h"
251debfc3dSmrg #include "tree.h"
261debfc3dSmrg #include "gimple.h"
271debfc3dSmrg #include "tree-pass.h"
281debfc3dSmrg #include "ssa.h"
291debfc3dSmrg #include "gimple-pretty-print.h"
301debfc3dSmrg #include "fold-const.h"
311debfc3dSmrg #include "tree-object-size.h"
321debfc3dSmrg #include "gimple-fold.h"
331debfc3dSmrg #include "gimple-iterator.h"
341debfc3dSmrg #include "tree-cfg.h"
35a2dc1f3fSmrg #include "stringpool.h"
36a2dc1f3fSmrg #include "attribs.h"
371debfc3dSmrg 
381debfc3dSmrg struct object_size_info
391debfc3dSmrg {
401debfc3dSmrg   int object_size_type;
411debfc3dSmrg   unsigned char pass;
421debfc3dSmrg   bool changed;
431debfc3dSmrg   bitmap visited, reexamine;
441debfc3dSmrg   unsigned int *depths;
451debfc3dSmrg   unsigned int *stack, *tos;
461debfc3dSmrg };
471debfc3dSmrg 
481debfc3dSmrg static const unsigned HOST_WIDE_INT unknown[4] = {
491debfc3dSmrg   HOST_WIDE_INT_M1U,
501debfc3dSmrg   HOST_WIDE_INT_M1U,
511debfc3dSmrg   0,
521debfc3dSmrg   0
531debfc3dSmrg };
541debfc3dSmrg 
551debfc3dSmrg static tree compute_object_offset (const_tree, const_tree);
561debfc3dSmrg static bool addr_object_size (struct object_size_info *,
57*8feb0f0bSmrg 			      const_tree, int, unsigned HOST_WIDE_INT *,
58*8feb0f0bSmrg 			      tree * = NULL, tree * = NULL);
591debfc3dSmrg static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int);
601debfc3dSmrg static tree pass_through_call (const gcall *);
611debfc3dSmrg static void collect_object_sizes_for (struct object_size_info *, tree);
621debfc3dSmrg static void expr_object_size (struct object_size_info *, tree, tree);
631debfc3dSmrg static bool merge_object_sizes (struct object_size_info *, tree, tree,
641debfc3dSmrg 				unsigned HOST_WIDE_INT);
651debfc3dSmrg static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *);
661debfc3dSmrg static bool cond_expr_object_size (struct object_size_info *, tree, gimple *);
671debfc3dSmrg static void init_offset_limit (void);
681debfc3dSmrg static void check_for_plus_in_loops (struct object_size_info *, tree);
691debfc3dSmrg static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
701debfc3dSmrg 				       unsigned int);
711debfc3dSmrg 
721debfc3dSmrg /* object_sizes[0] is upper bound for number of bytes till the end of
731debfc3dSmrg    the object.
741debfc3dSmrg    object_sizes[1] is upper bound for number of bytes till the end of
751debfc3dSmrg    the subobject (innermost array or field with address taken).
761debfc3dSmrg    object_sizes[2] is lower bound for number of bytes till the end of
771debfc3dSmrg    the object and object_sizes[3] lower bound for subobject.  */
781debfc3dSmrg static vec<unsigned HOST_WIDE_INT> object_sizes[4];
791debfc3dSmrg 
801debfc3dSmrg /* Bitmaps what object sizes have been computed already.  */
811debfc3dSmrg static bitmap computed[4];
821debfc3dSmrg 
831debfc3dSmrg /* Maximum value of offset we consider to be addition.  */
841debfc3dSmrg static unsigned HOST_WIDE_INT offset_limit;
851debfc3dSmrg 
861debfc3dSmrg 
871debfc3dSmrg /* Initialize OFFSET_LIMIT variable.  */
881debfc3dSmrg static void
init_offset_limit(void)891debfc3dSmrg init_offset_limit (void)
901debfc3dSmrg {
911debfc3dSmrg   if (tree_fits_uhwi_p (TYPE_MAX_VALUE (sizetype)))
921debfc3dSmrg     offset_limit = tree_to_uhwi (TYPE_MAX_VALUE (sizetype));
931debfc3dSmrg   else
941debfc3dSmrg     offset_limit = -1;
951debfc3dSmrg   offset_limit /= 2;
961debfc3dSmrg }
971debfc3dSmrg 
981debfc3dSmrg 
991debfc3dSmrg /* Compute offset of EXPR within VAR.  Return error_mark_node
1001debfc3dSmrg    if unknown.  */
1011debfc3dSmrg 
1021debfc3dSmrg static tree
compute_object_offset(const_tree expr,const_tree var)1031debfc3dSmrg compute_object_offset (const_tree expr, const_tree var)
1041debfc3dSmrg {
1051debfc3dSmrg   enum tree_code code = PLUS_EXPR;
1061debfc3dSmrg   tree base, off, t;
1071debfc3dSmrg 
1081debfc3dSmrg   if (expr == var)
1091debfc3dSmrg     return size_zero_node;
1101debfc3dSmrg 
1111debfc3dSmrg   switch (TREE_CODE (expr))
1121debfc3dSmrg     {
1131debfc3dSmrg     case COMPONENT_REF:
1141debfc3dSmrg       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1151debfc3dSmrg       if (base == error_mark_node)
1161debfc3dSmrg 	return base;
1171debfc3dSmrg 
1181debfc3dSmrg       t = TREE_OPERAND (expr, 1);
1191debfc3dSmrg       off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
1201debfc3dSmrg 			size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
1211debfc3dSmrg 				  / BITS_PER_UNIT));
1221debfc3dSmrg       break;
1231debfc3dSmrg 
1241debfc3dSmrg     case REALPART_EXPR:
1251debfc3dSmrg     CASE_CONVERT:
1261debfc3dSmrg     case VIEW_CONVERT_EXPR:
1271debfc3dSmrg     case NON_LVALUE_EXPR:
1281debfc3dSmrg       return compute_object_offset (TREE_OPERAND (expr, 0), var);
1291debfc3dSmrg 
1301debfc3dSmrg     case IMAGPART_EXPR:
1311debfc3dSmrg       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1321debfc3dSmrg       if (base == error_mark_node)
1331debfc3dSmrg 	return base;
1341debfc3dSmrg 
1351debfc3dSmrg       off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
1361debfc3dSmrg       break;
1371debfc3dSmrg 
1381debfc3dSmrg     case ARRAY_REF:
1391debfc3dSmrg       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
1401debfc3dSmrg       if (base == error_mark_node)
1411debfc3dSmrg 	return base;
1421debfc3dSmrg 
1431debfc3dSmrg       t = TREE_OPERAND (expr, 1);
1441debfc3dSmrg       tree low_bound, unit_size;
1451debfc3dSmrg       low_bound = array_ref_low_bound (CONST_CAST_TREE (expr));
1461debfc3dSmrg       unit_size = array_ref_element_size (CONST_CAST_TREE (expr));
1471debfc3dSmrg       if (! integer_zerop (low_bound))
1481debfc3dSmrg 	t = fold_build2 (MINUS_EXPR, TREE_TYPE (t), t, low_bound);
1491debfc3dSmrg       if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
1501debfc3dSmrg 	{
1511debfc3dSmrg 	  code = MINUS_EXPR;
1521debfc3dSmrg 	  t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
1531debfc3dSmrg 	}
1541debfc3dSmrg       t = fold_convert (sizetype, t);
1551debfc3dSmrg       off = size_binop (MULT_EXPR, unit_size, t);
1561debfc3dSmrg       break;
1571debfc3dSmrg 
1581debfc3dSmrg     case MEM_REF:
1591debfc3dSmrg       gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR);
1601debfc3dSmrg       return wide_int_to_tree (sizetype, mem_ref_offset (expr));
1611debfc3dSmrg 
1621debfc3dSmrg     default:
1631debfc3dSmrg       return error_mark_node;
1641debfc3dSmrg     }
1651debfc3dSmrg 
1661debfc3dSmrg   return size_binop (code, base, off);
1671debfc3dSmrg }
1681debfc3dSmrg 
1691debfc3dSmrg 
1701debfc3dSmrg /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
1711debfc3dSmrg    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
1721debfc3dSmrg    If unknown, return unknown[object_size_type].  */
1731debfc3dSmrg 
1741debfc3dSmrg static bool
addr_object_size(struct object_size_info * osi,const_tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize,tree * pdecl,tree * poff)1751debfc3dSmrg addr_object_size (struct object_size_info *osi, const_tree ptr,
176*8feb0f0bSmrg 		  int object_size_type, unsigned HOST_WIDE_INT *psize,
177*8feb0f0bSmrg 		  tree *pdecl /* = NULL */, tree *poff /* = NULL */)
1781debfc3dSmrg {
1791debfc3dSmrg   tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
1801debfc3dSmrg 
181*8feb0f0bSmrg   tree dummy_decl, dummy_off = size_zero_node;
182*8feb0f0bSmrg   if (!pdecl)
183*8feb0f0bSmrg     pdecl = &dummy_decl;
184*8feb0f0bSmrg   if (!poff)
185*8feb0f0bSmrg     poff = &dummy_off;
186*8feb0f0bSmrg 
1871debfc3dSmrg   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
1881debfc3dSmrg 
1891debfc3dSmrg   /* Set to unknown and overwrite just before returning if the size
1901debfc3dSmrg      could be determined.  */
1911debfc3dSmrg   *psize = unknown[object_size_type];
1921debfc3dSmrg 
1931debfc3dSmrg   pt_var = TREE_OPERAND (ptr, 0);
1941debfc3dSmrg   while (handled_component_p (pt_var))
1951debfc3dSmrg     pt_var = TREE_OPERAND (pt_var, 0);
1961debfc3dSmrg 
1971debfc3dSmrg   if (pt_var
1981debfc3dSmrg       && TREE_CODE (pt_var) == MEM_REF)
1991debfc3dSmrg     {
2001debfc3dSmrg       unsigned HOST_WIDE_INT sz;
2011debfc3dSmrg 
2021debfc3dSmrg       if (!osi || (object_size_type & 1) != 0
2031debfc3dSmrg 	  || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME)
2041debfc3dSmrg 	{
2051debfc3dSmrg 	  compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
206*8feb0f0bSmrg 				       object_size_type & ~1, &sz, pdecl, poff);
2071debfc3dSmrg 	}
2081debfc3dSmrg       else
2091debfc3dSmrg 	{
2101debfc3dSmrg 	  tree var = TREE_OPERAND (pt_var, 0);
2111debfc3dSmrg 	  if (osi->pass == 0)
2121debfc3dSmrg 	    collect_object_sizes_for (osi, var);
2131debfc3dSmrg 	  if (bitmap_bit_p (computed[object_size_type],
2141debfc3dSmrg 			    SSA_NAME_VERSION (var)))
2151debfc3dSmrg 	    sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)];
2161debfc3dSmrg 	  else
2171debfc3dSmrg 	    sz = unknown[object_size_type];
2181debfc3dSmrg 	}
2191debfc3dSmrg       if (sz != unknown[object_size_type])
2201debfc3dSmrg 	{
221a2dc1f3fSmrg 	  offset_int mem_offset;
222a2dc1f3fSmrg 	  if (mem_ref_offset (pt_var).is_constant (&mem_offset))
223a2dc1f3fSmrg 	    {
224a2dc1f3fSmrg 	      offset_int dsz = wi::sub (sz, mem_offset);
2251debfc3dSmrg 	      if (wi::neg_p (dsz))
2261debfc3dSmrg 		sz = 0;
2271debfc3dSmrg 	      else if (wi::fits_uhwi_p (dsz))
2281debfc3dSmrg 		sz = dsz.to_uhwi ();
2291debfc3dSmrg 	      else
2301debfc3dSmrg 		sz = unknown[object_size_type];
2311debfc3dSmrg 	    }
232a2dc1f3fSmrg 	  else
233a2dc1f3fSmrg 	    sz = unknown[object_size_type];
234a2dc1f3fSmrg 	}
2351debfc3dSmrg 
2361debfc3dSmrg       if (sz != unknown[object_size_type] && sz < offset_limit)
2371debfc3dSmrg 	pt_var_size = size_int (sz);
2381debfc3dSmrg     }
2391debfc3dSmrg   else if (pt_var
2401debfc3dSmrg 	   && DECL_P (pt_var)
2411debfc3dSmrg 	   && tree_fits_uhwi_p (DECL_SIZE_UNIT (pt_var))
2421debfc3dSmrg 	   && tree_to_uhwi (DECL_SIZE_UNIT (pt_var)) < offset_limit)
243*8feb0f0bSmrg     {
244*8feb0f0bSmrg       *pdecl = pt_var;
2451debfc3dSmrg       pt_var_size = DECL_SIZE_UNIT (pt_var);
246*8feb0f0bSmrg     }
2471debfc3dSmrg   else if (pt_var
2481debfc3dSmrg 	   && TREE_CODE (pt_var) == STRING_CST
2491debfc3dSmrg 	   && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
2501debfc3dSmrg 	   && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
2511debfc3dSmrg 	   && tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
2521debfc3dSmrg 	      < offset_limit)
2531debfc3dSmrg     pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
2541debfc3dSmrg   else
2551debfc3dSmrg     return false;
2561debfc3dSmrg 
2571debfc3dSmrg   if (pt_var != TREE_OPERAND (ptr, 0))
2581debfc3dSmrg     {
2591debfc3dSmrg       tree var;
2601debfc3dSmrg 
2611debfc3dSmrg       if (object_size_type & 1)
2621debfc3dSmrg 	{
2631debfc3dSmrg 	  var = TREE_OPERAND (ptr, 0);
2641debfc3dSmrg 
2651debfc3dSmrg 	  while (var != pt_var
2661debfc3dSmrg 		 && TREE_CODE (var) != BIT_FIELD_REF
2671debfc3dSmrg 		 && TREE_CODE (var) != COMPONENT_REF
2681debfc3dSmrg 		 && TREE_CODE (var) != ARRAY_REF
2691debfc3dSmrg 		 && TREE_CODE (var) != ARRAY_RANGE_REF
2701debfc3dSmrg 		 && TREE_CODE (var) != REALPART_EXPR
2711debfc3dSmrg 		 && TREE_CODE (var) != IMAGPART_EXPR)
2721debfc3dSmrg 	    var = TREE_OPERAND (var, 0);
2731debfc3dSmrg 	  if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
2741debfc3dSmrg 	    var = TREE_OPERAND (var, 0);
2751debfc3dSmrg 	  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
2761debfc3dSmrg 	      || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
2771debfc3dSmrg 	      || (pt_var_size
2781debfc3dSmrg 		  && tree_int_cst_lt (pt_var_size,
2791debfc3dSmrg 				      TYPE_SIZE_UNIT (TREE_TYPE (var)))))
2801debfc3dSmrg 	    var = pt_var;
2811debfc3dSmrg 	  else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
2821debfc3dSmrg 	    {
2831debfc3dSmrg 	      tree v = var;
2841debfc3dSmrg 	      /* For &X->fld, compute object size only if fld isn't the last
2851debfc3dSmrg 		 field, as struct { int i; char c[1]; } is often used instead
2861debfc3dSmrg 		 of flexible array member.  */
2871debfc3dSmrg 	      while (v && v != pt_var)
2881debfc3dSmrg 		switch (TREE_CODE (v))
2891debfc3dSmrg 		  {
2901debfc3dSmrg 		  case ARRAY_REF:
2911debfc3dSmrg 		    if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
2921debfc3dSmrg 			&& TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
2931debfc3dSmrg 		      {
2941debfc3dSmrg 			tree domain
2951debfc3dSmrg 			  = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
2961debfc3dSmrg 			if (domain
2971debfc3dSmrg 			    && TYPE_MAX_VALUE (domain)
2981debfc3dSmrg 			    && TREE_CODE (TYPE_MAX_VALUE (domain))
2991debfc3dSmrg 			       == INTEGER_CST
3001debfc3dSmrg 			    && tree_int_cst_lt (TREE_OPERAND (v, 1),
3011debfc3dSmrg 						TYPE_MAX_VALUE (domain)))
3021debfc3dSmrg 			  {
3031debfc3dSmrg 			    v = NULL_TREE;
3041debfc3dSmrg 			    break;
3051debfc3dSmrg 			  }
3061debfc3dSmrg 		      }
3071debfc3dSmrg 		    v = TREE_OPERAND (v, 0);
3081debfc3dSmrg 		    break;
3091debfc3dSmrg 		  case REALPART_EXPR:
3101debfc3dSmrg 		  case IMAGPART_EXPR:
3111debfc3dSmrg 		    v = NULL_TREE;
3121debfc3dSmrg 		    break;
3131debfc3dSmrg 		  case COMPONENT_REF:
3141debfc3dSmrg 		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
3151debfc3dSmrg 		      {
3161debfc3dSmrg 			v = NULL_TREE;
3171debfc3dSmrg 			break;
3181debfc3dSmrg 		      }
3191debfc3dSmrg 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
3201debfc3dSmrg 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3211debfc3dSmrg 			  != UNION_TYPE
3221debfc3dSmrg 			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3231debfc3dSmrg 			  != QUAL_UNION_TYPE)
3241debfc3dSmrg 			break;
3251debfc3dSmrg 		      else
3261debfc3dSmrg 			v = TREE_OPERAND (v, 0);
3271debfc3dSmrg 		    if (TREE_CODE (v) == COMPONENT_REF
3281debfc3dSmrg 			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3291debfc3dSmrg 			   == RECORD_TYPE)
3301debfc3dSmrg 		      {
3311debfc3dSmrg 			tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
3321debfc3dSmrg 			for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
3331debfc3dSmrg 			  if (TREE_CODE (fld_chain) == FIELD_DECL)
3341debfc3dSmrg 			    break;
3351debfc3dSmrg 
3361debfc3dSmrg 			if (fld_chain)
3371debfc3dSmrg 			  {
3381debfc3dSmrg 			    v = NULL_TREE;
3391debfc3dSmrg 			    break;
3401debfc3dSmrg 			  }
3411debfc3dSmrg 			v = TREE_OPERAND (v, 0);
3421debfc3dSmrg 		      }
3431debfc3dSmrg 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
3441debfc3dSmrg 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3451debfc3dSmrg 			  != UNION_TYPE
3461debfc3dSmrg 			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
3471debfc3dSmrg 			  != QUAL_UNION_TYPE)
3481debfc3dSmrg 			break;
3491debfc3dSmrg 		      else
3501debfc3dSmrg 			v = TREE_OPERAND (v, 0);
3511debfc3dSmrg 		    if (v != pt_var)
3521debfc3dSmrg 		      v = NULL_TREE;
3531debfc3dSmrg 		    else
3541debfc3dSmrg 		      v = pt_var;
3551debfc3dSmrg 		    break;
3561debfc3dSmrg 		  default:
3571debfc3dSmrg 		    v = pt_var;
3581debfc3dSmrg 		    break;
3591debfc3dSmrg 		  }
3601debfc3dSmrg 	      if (v == pt_var)
3611debfc3dSmrg 		var = pt_var;
3621debfc3dSmrg 	    }
3631debfc3dSmrg 	}
3641debfc3dSmrg       else
3651debfc3dSmrg 	var = pt_var;
3661debfc3dSmrg 
3671debfc3dSmrg       if (var != pt_var)
3681debfc3dSmrg 	var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
3691debfc3dSmrg       else if (!pt_var_size)
3701debfc3dSmrg 	return false;
3711debfc3dSmrg       else
3721debfc3dSmrg 	var_size = pt_var_size;
3731debfc3dSmrg       bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
3741debfc3dSmrg       if (bytes != error_mark_node)
3751debfc3dSmrg 	{
3761debfc3dSmrg 	  if (TREE_CODE (bytes) == INTEGER_CST
3771debfc3dSmrg 	      && tree_int_cst_lt (var_size, bytes))
3781debfc3dSmrg 	    bytes = size_zero_node;
3791debfc3dSmrg 	  else
3801debfc3dSmrg 	    bytes = size_binop (MINUS_EXPR, var_size, bytes);
381*8feb0f0bSmrg 	  *poff = bytes;
3821debfc3dSmrg 	}
3831debfc3dSmrg       if (var != pt_var
3841debfc3dSmrg 	  && pt_var_size
3851debfc3dSmrg 	  && TREE_CODE (pt_var) == MEM_REF
3861debfc3dSmrg 	  && bytes != error_mark_node)
3871debfc3dSmrg 	{
3881debfc3dSmrg 	  tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
3891debfc3dSmrg 	  if (bytes2 != error_mark_node)
3901debfc3dSmrg 	    {
3911debfc3dSmrg 	      if (TREE_CODE (bytes2) == INTEGER_CST
3921debfc3dSmrg 		  && tree_int_cst_lt (pt_var_size, bytes2))
3931debfc3dSmrg 		bytes2 = size_zero_node;
3941debfc3dSmrg 	      else
3951debfc3dSmrg 		bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
396*8feb0f0bSmrg 	      *poff = size_binop (PLUS_EXPR, *poff, bytes2);
3971debfc3dSmrg 	      bytes = size_binop (MIN_EXPR, bytes, bytes2);
3981debfc3dSmrg 	    }
3991debfc3dSmrg 	}
4001debfc3dSmrg     }
4011debfc3dSmrg   else if (!pt_var_size)
4021debfc3dSmrg     return false;
4031debfc3dSmrg   else
4041debfc3dSmrg     bytes = pt_var_size;
4051debfc3dSmrg 
4061debfc3dSmrg   if (tree_fits_uhwi_p (bytes))
4071debfc3dSmrg     {
4081debfc3dSmrg       *psize = tree_to_uhwi (bytes);
4091debfc3dSmrg       return true;
4101debfc3dSmrg     }
4111debfc3dSmrg 
4121debfc3dSmrg   return false;
4131debfc3dSmrg }
4141debfc3dSmrg 
4151debfc3dSmrg 
4161debfc3dSmrg /* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL.
417c0a68be4Smrg    Handles calls to functions declared with attribute alloc_size.
418c0a68be4Smrg    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
419c0a68be4Smrg    If unknown, return unknown[object_size_type].  */
4201debfc3dSmrg 
4211debfc3dSmrg static unsigned HOST_WIDE_INT
alloc_object_size(const gcall * call,int object_size_type)4221debfc3dSmrg alloc_object_size (const gcall *call, int object_size_type)
4231debfc3dSmrg {
4241debfc3dSmrg   gcc_assert (is_gimple_call (call));
4251debfc3dSmrg 
426c0a68be4Smrg   tree calltype;
427c0a68be4Smrg   if (tree callfn = gimple_call_fndecl (call))
428c0a68be4Smrg     calltype = TREE_TYPE (callfn);
429c0a68be4Smrg   else
430c0a68be4Smrg     calltype = gimple_call_fntype (call);
431c0a68be4Smrg 
432c0a68be4Smrg   if (!calltype)
4331debfc3dSmrg     return unknown[object_size_type];
4341debfc3dSmrg 
435c0a68be4Smrg   /* Set to positions of alloc_size arguments.  */
436c0a68be4Smrg   int arg1 = -1, arg2 = -1;
437c0a68be4Smrg   tree alloc_size = lookup_attribute ("alloc_size",
438c0a68be4Smrg 				      TYPE_ATTRIBUTES (calltype));
4391debfc3dSmrg   if (alloc_size && TREE_VALUE (alloc_size))
4401debfc3dSmrg     {
4411debfc3dSmrg       tree p = TREE_VALUE (alloc_size);
4421debfc3dSmrg 
4431debfc3dSmrg       arg1 = TREE_INT_CST_LOW (TREE_VALUE (p))-1;
4441debfc3dSmrg       if (TREE_CHAIN (p))
4451debfc3dSmrg         arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
4461debfc3dSmrg     }
4471debfc3dSmrg 
4481debfc3dSmrg   if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call)
4491debfc3dSmrg       || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST
4501debfc3dSmrg       || (arg2 >= 0
4511debfc3dSmrg 	  && (arg2 >= (int)gimple_call_num_args (call)
4521debfc3dSmrg 	      || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST)))
4531debfc3dSmrg     return unknown[object_size_type];
4541debfc3dSmrg 
455c0a68be4Smrg   tree bytes = NULL_TREE;
4561debfc3dSmrg   if (arg2 >= 0)
4571debfc3dSmrg     bytes = size_binop (MULT_EXPR,
4581debfc3dSmrg 	fold_convert (sizetype, gimple_call_arg (call, arg1)),
4591debfc3dSmrg 	fold_convert (sizetype, gimple_call_arg (call, arg2)));
4601debfc3dSmrg   else if (arg1 >= 0)
4611debfc3dSmrg     bytes = fold_convert (sizetype, gimple_call_arg (call, arg1));
4621debfc3dSmrg 
4631debfc3dSmrg   if (bytes && tree_fits_uhwi_p (bytes))
4641debfc3dSmrg     return tree_to_uhwi (bytes);
4651debfc3dSmrg 
4661debfc3dSmrg   return unknown[object_size_type];
4671debfc3dSmrg }
4681debfc3dSmrg 
4691debfc3dSmrg 
4701debfc3dSmrg /* If object size is propagated from one of function's arguments directly
4711debfc3dSmrg    to its return value, return that argument for GIMPLE_CALL statement CALL.
4721debfc3dSmrg    Otherwise return NULL.  */
4731debfc3dSmrg 
4741debfc3dSmrg static tree
pass_through_call(const gcall * call)4751debfc3dSmrg pass_through_call (const gcall *call)
4761debfc3dSmrg {
477a2dc1f3fSmrg   unsigned rf = gimple_call_return_flags (call);
478a2dc1f3fSmrg   if (rf & ERF_RETURNS_ARG)
4791debfc3dSmrg     {
480a2dc1f3fSmrg       unsigned argnum = rf & ERF_RETURN_ARG_MASK;
481a2dc1f3fSmrg       if (argnum < gimple_call_num_args (call))
482a2dc1f3fSmrg 	return gimple_call_arg (call, argnum);
4831debfc3dSmrg     }
4841debfc3dSmrg 
485a2dc1f3fSmrg   /* __builtin_assume_aligned is intentionally not marked RET1.  */
486a2dc1f3fSmrg   if (gimple_call_builtin_p (call, BUILT_IN_ASSUME_ALIGNED))
487a2dc1f3fSmrg     return gimple_call_arg (call, 0);
488a2dc1f3fSmrg 
4891debfc3dSmrg   return NULL_TREE;
4901debfc3dSmrg }
4911debfc3dSmrg 
4921debfc3dSmrg 
4931debfc3dSmrg /* Compute __builtin_object_size value for PTR and set *PSIZE to
494*8feb0f0bSmrg    the resulting value.  If the declared object is known and PDECL
495*8feb0f0bSmrg    is nonnull, sets *PDECL to the object's DECL.  OBJECT_SIZE_TYPE
496*8feb0f0bSmrg    is the second argument   to __builtin_object_size.
497*8feb0f0bSmrg    Returns true on success and false when the object size could not
498*8feb0f0bSmrg    be determined.  */
4991debfc3dSmrg 
5001debfc3dSmrg bool
compute_builtin_object_size(tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize,tree * pdecl,tree * poff)5011debfc3dSmrg compute_builtin_object_size (tree ptr, int object_size_type,
502*8feb0f0bSmrg 			     unsigned HOST_WIDE_INT *psize,
503*8feb0f0bSmrg 			     tree *pdecl /* = NULL */, tree *poff /* = NULL */)
5041debfc3dSmrg {
5051debfc3dSmrg   gcc_assert (object_size_type >= 0 && object_size_type <= 3);
5061debfc3dSmrg 
507*8feb0f0bSmrg   tree dummy_decl, dummy_off = size_zero_node;
508*8feb0f0bSmrg   if (!pdecl)
509*8feb0f0bSmrg     pdecl = &dummy_decl;
510*8feb0f0bSmrg   if (!poff)
511*8feb0f0bSmrg     poff = &dummy_off;
512*8feb0f0bSmrg 
5131debfc3dSmrg   /* Set to unknown and overwrite just before returning if the size
5141debfc3dSmrg      could be determined.  */
5151debfc3dSmrg   *psize = unknown[object_size_type];
5161debfc3dSmrg 
5171debfc3dSmrg   if (! offset_limit)
5181debfc3dSmrg     init_offset_limit ();
5191debfc3dSmrg 
5201debfc3dSmrg   if (TREE_CODE (ptr) == ADDR_EXPR)
521*8feb0f0bSmrg     return addr_object_size (NULL, ptr, object_size_type, psize, pdecl, poff);
5221debfc3dSmrg 
5231debfc3dSmrg   if (TREE_CODE (ptr) != SSA_NAME
5241debfc3dSmrg       || !POINTER_TYPE_P (TREE_TYPE (ptr)))
5251debfc3dSmrg       return false;
5261debfc3dSmrg 
5271debfc3dSmrg   if (computed[object_size_type] == NULL)
5281debfc3dSmrg     {
5291debfc3dSmrg       if (optimize || object_size_type & 1)
5301debfc3dSmrg 	return false;
5311debfc3dSmrg 
5321debfc3dSmrg       /* When not optimizing, rather than failing, make a small effort
5331debfc3dSmrg 	 to determine the object size without the full benefit of
5341debfc3dSmrg 	 the (costly) computation below.  */
5351debfc3dSmrg       gimple *def = SSA_NAME_DEF_STMT (ptr);
5361debfc3dSmrg       if (gimple_code (def) == GIMPLE_ASSIGN)
5371debfc3dSmrg 	{
5381debfc3dSmrg 	  tree_code code = gimple_assign_rhs_code (def);
5391debfc3dSmrg 	  if (code == POINTER_PLUS_EXPR)
5401debfc3dSmrg 	    {
5411debfc3dSmrg 	      tree offset = gimple_assign_rhs2 (def);
5421debfc3dSmrg 	      ptr = gimple_assign_rhs1 (def);
5431debfc3dSmrg 
5441debfc3dSmrg 	      if (tree_fits_shwi_p (offset)
545*8feb0f0bSmrg 		  && compute_builtin_object_size (ptr, object_size_type,
546*8feb0f0bSmrg 						  psize, pdecl, poff))
5471debfc3dSmrg 		{
5481debfc3dSmrg 		  /* Return zero when the offset is out of bounds.  */
5491debfc3dSmrg 		  unsigned HOST_WIDE_INT off = tree_to_shwi (offset);
5501debfc3dSmrg 		  *psize = off < *psize ? *psize - off : 0;
551*8feb0f0bSmrg 		  *poff = offset;
5521debfc3dSmrg 		  return true;
5531debfc3dSmrg 		}
5541debfc3dSmrg 	    }
5551debfc3dSmrg 	}
5561debfc3dSmrg       return false;
5571debfc3dSmrg     }
5581debfc3dSmrg 
5591debfc3dSmrg   if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
5601debfc3dSmrg     {
5611debfc3dSmrg       struct object_size_info osi;
5621debfc3dSmrg       bitmap_iterator bi;
5631debfc3dSmrg       unsigned int i;
5641debfc3dSmrg 
5651debfc3dSmrg       if (num_ssa_names > object_sizes[object_size_type].length ())
5661debfc3dSmrg 	object_sizes[object_size_type].safe_grow (num_ssa_names);
5671debfc3dSmrg       if (dump_file)
5681debfc3dSmrg 	{
5691debfc3dSmrg 	  fprintf (dump_file, "Computing %s %sobject size for ",
5701debfc3dSmrg 		   (object_size_type & 2) ? "minimum" : "maximum",
5711debfc3dSmrg 		   (object_size_type & 1) ? "sub" : "");
5721debfc3dSmrg 	  print_generic_expr (dump_file, ptr, dump_flags);
5731debfc3dSmrg 	  fprintf (dump_file, ":\n");
5741debfc3dSmrg 	}
5751debfc3dSmrg 
5761debfc3dSmrg       osi.visited = BITMAP_ALLOC (NULL);
5771debfc3dSmrg       osi.reexamine = BITMAP_ALLOC (NULL);
5781debfc3dSmrg       osi.object_size_type = object_size_type;
5791debfc3dSmrg       osi.depths = NULL;
5801debfc3dSmrg       osi.stack = NULL;
5811debfc3dSmrg       osi.tos = NULL;
5821debfc3dSmrg 
5831debfc3dSmrg       /* First pass: walk UD chains, compute object sizes that
5841debfc3dSmrg 	 can be computed.  osi.reexamine bitmap at the end will
5851debfc3dSmrg 	 contain what variables were found in dependency cycles
5861debfc3dSmrg 	 and therefore need to be reexamined.  */
5871debfc3dSmrg       osi.pass = 0;
5881debfc3dSmrg       osi.changed = false;
5891debfc3dSmrg       collect_object_sizes_for (&osi, ptr);
5901debfc3dSmrg 
5911debfc3dSmrg       /* Second pass: keep recomputing object sizes of variables
5921debfc3dSmrg 	 that need reexamination, until no object sizes are
5931debfc3dSmrg 	 increased or all object sizes are computed.  */
5941debfc3dSmrg       if (! bitmap_empty_p (osi.reexamine))
5951debfc3dSmrg 	{
5961debfc3dSmrg 	  bitmap reexamine = BITMAP_ALLOC (NULL);
5971debfc3dSmrg 
5981debfc3dSmrg 	  /* If looking for minimum instead of maximum object size,
5991debfc3dSmrg 	     detect cases where a pointer is increased in a loop.
6001debfc3dSmrg 	     Although even without this detection pass 2 would eventually
6011debfc3dSmrg 	     terminate, it could take a long time.  If a pointer is
6021debfc3dSmrg 	     increasing this way, we need to assume 0 object size.
6031debfc3dSmrg 	     E.g. p = &buf[0]; while (cond) p = p + 4;  */
6041debfc3dSmrg 	  if (object_size_type & 2)
6051debfc3dSmrg 	    {
6061debfc3dSmrg 	      osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
6071debfc3dSmrg 	      osi.stack = XNEWVEC (unsigned int, num_ssa_names);
6081debfc3dSmrg 	      osi.tos = osi.stack;
6091debfc3dSmrg 	      osi.pass = 1;
6101debfc3dSmrg 	      /* collect_object_sizes_for is changing
6111debfc3dSmrg 		 osi.reexamine bitmap, so iterate over a copy.  */
6121debfc3dSmrg 	      bitmap_copy (reexamine, osi.reexamine);
6131debfc3dSmrg 	      EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
6141debfc3dSmrg 		if (bitmap_bit_p (osi.reexamine, i))
6151debfc3dSmrg 		  check_for_plus_in_loops (&osi, ssa_name (i));
6161debfc3dSmrg 
6171debfc3dSmrg 	      free (osi.depths);
6181debfc3dSmrg 	      osi.depths = NULL;
6191debfc3dSmrg 	      free (osi.stack);
6201debfc3dSmrg 	      osi.stack = NULL;
6211debfc3dSmrg 	      osi.tos = NULL;
6221debfc3dSmrg 	    }
6231debfc3dSmrg 
6241debfc3dSmrg 	  do
6251debfc3dSmrg 	    {
6261debfc3dSmrg 	      osi.pass = 2;
6271debfc3dSmrg 	      osi.changed = false;
6281debfc3dSmrg 	      /* collect_object_sizes_for is changing
6291debfc3dSmrg 		 osi.reexamine bitmap, so iterate over a copy.  */
6301debfc3dSmrg 	      bitmap_copy (reexamine, osi.reexamine);
6311debfc3dSmrg 	      EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
6321debfc3dSmrg 		if (bitmap_bit_p (osi.reexamine, i))
6331debfc3dSmrg 		  {
6341debfc3dSmrg 		    collect_object_sizes_for (&osi, ssa_name (i));
6351debfc3dSmrg 		    if (dump_file && (dump_flags & TDF_DETAILS))
6361debfc3dSmrg 		      {
6371debfc3dSmrg 			fprintf (dump_file, "Reexamining ");
6381debfc3dSmrg 			print_generic_expr (dump_file, ssa_name (i),
6391debfc3dSmrg 					    dump_flags);
6401debfc3dSmrg 			fprintf (dump_file, "\n");
6411debfc3dSmrg 		      }
6421debfc3dSmrg 		  }
6431debfc3dSmrg 	    }
6441debfc3dSmrg 	  while (osi.changed);
6451debfc3dSmrg 
6461debfc3dSmrg 	  BITMAP_FREE (reexamine);
6471debfc3dSmrg 	}
6481debfc3dSmrg       EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
6491debfc3dSmrg 	bitmap_set_bit (computed[object_size_type], i);
6501debfc3dSmrg 
6511debfc3dSmrg       /* Debugging dumps.  */
6521debfc3dSmrg       if (dump_file)
6531debfc3dSmrg 	{
6541debfc3dSmrg 	  EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
6551debfc3dSmrg 	    if (object_sizes[object_size_type][i]
6561debfc3dSmrg 		!= unknown[object_size_type])
6571debfc3dSmrg 	      {
6581debfc3dSmrg 		print_generic_expr (dump_file, ssa_name (i),
6591debfc3dSmrg 				    dump_flags);
6601debfc3dSmrg 		fprintf (dump_file,
6611debfc3dSmrg 			 ": %s %sobject size "
6621debfc3dSmrg 			 HOST_WIDE_INT_PRINT_UNSIGNED "\n",
6631debfc3dSmrg 			 (object_size_type & 2) ? "minimum" : "maximum",
6641debfc3dSmrg 			 (object_size_type & 1) ? "sub" : "",
6651debfc3dSmrg 			 object_sizes[object_size_type][i]);
6661debfc3dSmrg 	      }
6671debfc3dSmrg 	}
6681debfc3dSmrg 
6691debfc3dSmrg       BITMAP_FREE (osi.reexamine);
6701debfc3dSmrg       BITMAP_FREE (osi.visited);
6711debfc3dSmrg     }
6721debfc3dSmrg 
6731debfc3dSmrg   *psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
6741debfc3dSmrg   return *psize != unknown[object_size_type];
6751debfc3dSmrg }
6761debfc3dSmrg 
6771debfc3dSmrg /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME.  */
6781debfc3dSmrg 
6791debfc3dSmrg static void
expr_object_size(struct object_size_info * osi,tree ptr,tree value)6801debfc3dSmrg expr_object_size (struct object_size_info *osi, tree ptr, tree value)
6811debfc3dSmrg {
6821debfc3dSmrg   int object_size_type = osi->object_size_type;
6831debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (ptr);
6841debfc3dSmrg   unsigned HOST_WIDE_INT bytes;
6851debfc3dSmrg 
6861debfc3dSmrg   gcc_assert (object_sizes[object_size_type][varno]
6871debfc3dSmrg 	      != unknown[object_size_type]);
6881debfc3dSmrg   gcc_assert (osi->pass == 0);
6891debfc3dSmrg 
6901debfc3dSmrg   if (TREE_CODE (value) == WITH_SIZE_EXPR)
6911debfc3dSmrg     value = TREE_OPERAND (value, 0);
6921debfc3dSmrg 
6931debfc3dSmrg   /* Pointer variables should have been handled by merge_object_sizes.  */
6941debfc3dSmrg   gcc_assert (TREE_CODE (value) != SSA_NAME
6951debfc3dSmrg 	      || !POINTER_TYPE_P (TREE_TYPE (value)));
6961debfc3dSmrg 
6971debfc3dSmrg   if (TREE_CODE (value) == ADDR_EXPR)
6981debfc3dSmrg     addr_object_size (osi, value, object_size_type, &bytes);
6991debfc3dSmrg   else
7001debfc3dSmrg     bytes = unknown[object_size_type];
7011debfc3dSmrg 
7021debfc3dSmrg   if ((object_size_type & 2) == 0)
7031debfc3dSmrg     {
7041debfc3dSmrg       if (object_sizes[object_size_type][varno] < bytes)
7051debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7061debfc3dSmrg     }
7071debfc3dSmrg   else
7081debfc3dSmrg     {
7091debfc3dSmrg       if (object_sizes[object_size_type][varno] > bytes)
7101debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7111debfc3dSmrg     }
7121debfc3dSmrg }
7131debfc3dSmrg 
7141debfc3dSmrg 
7151debfc3dSmrg /* Compute object_sizes for PTR, defined to the result of a call.  */
7161debfc3dSmrg 
7171debfc3dSmrg static void
call_object_size(struct object_size_info * osi,tree ptr,gcall * call)7181debfc3dSmrg call_object_size (struct object_size_info *osi, tree ptr, gcall *call)
7191debfc3dSmrg {
7201debfc3dSmrg   int object_size_type = osi->object_size_type;
7211debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (ptr);
7221debfc3dSmrg   unsigned HOST_WIDE_INT bytes;
7231debfc3dSmrg 
7241debfc3dSmrg   gcc_assert (is_gimple_call (call));
7251debfc3dSmrg 
7261debfc3dSmrg   gcc_assert (object_sizes[object_size_type][varno]
7271debfc3dSmrg 	      != unknown[object_size_type]);
7281debfc3dSmrg   gcc_assert (osi->pass == 0);
7291debfc3dSmrg 
7301debfc3dSmrg   bytes = alloc_object_size (call, object_size_type);
7311debfc3dSmrg 
7321debfc3dSmrg   if ((object_size_type & 2) == 0)
7331debfc3dSmrg     {
7341debfc3dSmrg       if (object_sizes[object_size_type][varno] < bytes)
7351debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7361debfc3dSmrg     }
7371debfc3dSmrg   else
7381debfc3dSmrg     {
7391debfc3dSmrg       if (object_sizes[object_size_type][varno] > bytes)
7401debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7411debfc3dSmrg     }
7421debfc3dSmrg }
7431debfc3dSmrg 
7441debfc3dSmrg 
7451debfc3dSmrg /* Compute object_sizes for PTR, defined to an unknown value.  */
7461debfc3dSmrg 
7471debfc3dSmrg static void
unknown_object_size(struct object_size_info * osi,tree ptr)7481debfc3dSmrg unknown_object_size (struct object_size_info *osi, tree ptr)
7491debfc3dSmrg {
7501debfc3dSmrg   int object_size_type = osi->object_size_type;
7511debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (ptr);
7521debfc3dSmrg   unsigned HOST_WIDE_INT bytes;
7531debfc3dSmrg 
7541debfc3dSmrg   gcc_assert (object_sizes[object_size_type][varno]
7551debfc3dSmrg 	      != unknown[object_size_type]);
7561debfc3dSmrg   gcc_assert (osi->pass == 0);
7571debfc3dSmrg 
7581debfc3dSmrg   bytes = unknown[object_size_type];
7591debfc3dSmrg 
7601debfc3dSmrg   if ((object_size_type & 2) == 0)
7611debfc3dSmrg     {
7621debfc3dSmrg       if (object_sizes[object_size_type][varno] < bytes)
7631debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7641debfc3dSmrg     }
7651debfc3dSmrg   else
7661debfc3dSmrg     {
7671debfc3dSmrg       if (object_sizes[object_size_type][varno] > bytes)
7681debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
7691debfc3dSmrg     }
7701debfc3dSmrg }
7711debfc3dSmrg 
7721debfc3dSmrg 
7731debfc3dSmrg /* Merge object sizes of ORIG + OFFSET into DEST.  Return true if
7741debfc3dSmrg    the object size might need reexamination later.  */
7751debfc3dSmrg 
7761debfc3dSmrg static bool
merge_object_sizes(struct object_size_info * osi,tree dest,tree orig,unsigned HOST_WIDE_INT offset)7771debfc3dSmrg merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
7781debfc3dSmrg 		    unsigned HOST_WIDE_INT offset)
7791debfc3dSmrg {
7801debfc3dSmrg   int object_size_type = osi->object_size_type;
7811debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (dest);
7821debfc3dSmrg   unsigned HOST_WIDE_INT orig_bytes;
7831debfc3dSmrg 
7841debfc3dSmrg   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
7851debfc3dSmrg     return false;
7861debfc3dSmrg   if (offset >= offset_limit)
7871debfc3dSmrg     {
7881debfc3dSmrg       object_sizes[object_size_type][varno] = unknown[object_size_type];
7891debfc3dSmrg       return false;
7901debfc3dSmrg     }
7911debfc3dSmrg 
7921debfc3dSmrg   if (osi->pass == 0)
7931debfc3dSmrg     collect_object_sizes_for (osi, orig);
7941debfc3dSmrg 
7951debfc3dSmrg   orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
7961debfc3dSmrg   if (orig_bytes != unknown[object_size_type])
7971debfc3dSmrg     orig_bytes = (offset > orig_bytes)
7981debfc3dSmrg 		 ? HOST_WIDE_INT_0U : orig_bytes - offset;
7991debfc3dSmrg 
8001debfc3dSmrg   if ((object_size_type & 2) == 0)
8011debfc3dSmrg     {
8021debfc3dSmrg       if (object_sizes[object_size_type][varno] < orig_bytes)
8031debfc3dSmrg 	{
8041debfc3dSmrg 	  object_sizes[object_size_type][varno] = orig_bytes;
8051debfc3dSmrg 	  osi->changed = true;
8061debfc3dSmrg 	}
8071debfc3dSmrg     }
8081debfc3dSmrg   else
8091debfc3dSmrg     {
8101debfc3dSmrg       if (object_sizes[object_size_type][varno] > orig_bytes)
8111debfc3dSmrg 	{
8121debfc3dSmrg 	  object_sizes[object_size_type][varno] = orig_bytes;
8131debfc3dSmrg 	  osi->changed = true;
8141debfc3dSmrg 	}
8151debfc3dSmrg     }
8161debfc3dSmrg   return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
8171debfc3dSmrg }
8181debfc3dSmrg 
8191debfc3dSmrg 
8201debfc3dSmrg /* Compute object_sizes for VAR, defined to the result of an assignment
8211debfc3dSmrg    with operator POINTER_PLUS_EXPR.  Return true if the object size might
8221debfc3dSmrg    need reexamination  later.  */
8231debfc3dSmrg 
8241debfc3dSmrg static bool
plus_stmt_object_size(struct object_size_info * osi,tree var,gimple * stmt)8251debfc3dSmrg plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
8261debfc3dSmrg {
8271debfc3dSmrg   int object_size_type = osi->object_size_type;
8281debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (var);
8291debfc3dSmrg   unsigned HOST_WIDE_INT bytes;
8301debfc3dSmrg   tree op0, op1;
8311debfc3dSmrg 
8321debfc3dSmrg   if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
8331debfc3dSmrg     {
8341debfc3dSmrg       op0 = gimple_assign_rhs1 (stmt);
8351debfc3dSmrg       op1 = gimple_assign_rhs2 (stmt);
8361debfc3dSmrg     }
8371debfc3dSmrg   else if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
8381debfc3dSmrg     {
8391debfc3dSmrg       tree rhs = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
8401debfc3dSmrg       gcc_assert (TREE_CODE (rhs) == MEM_REF);
8411debfc3dSmrg       op0 = TREE_OPERAND (rhs, 0);
8421debfc3dSmrg       op1 = TREE_OPERAND (rhs, 1);
8431debfc3dSmrg     }
8441debfc3dSmrg   else
8451debfc3dSmrg     gcc_unreachable ();
8461debfc3dSmrg 
8471debfc3dSmrg   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
8481debfc3dSmrg     return false;
8491debfc3dSmrg 
8501debfc3dSmrg   /* Handle PTR + OFFSET here.  */
8511debfc3dSmrg   if (TREE_CODE (op1) == INTEGER_CST
8521debfc3dSmrg       && (TREE_CODE (op0) == SSA_NAME
8531debfc3dSmrg 	  || TREE_CODE (op0) == ADDR_EXPR))
8541debfc3dSmrg     {
8551debfc3dSmrg       if (! tree_fits_uhwi_p (op1))
8561debfc3dSmrg 	bytes = unknown[object_size_type];
8571debfc3dSmrg       else if (TREE_CODE (op0) == SSA_NAME)
8581debfc3dSmrg 	return merge_object_sizes (osi, var, op0, tree_to_uhwi (op1));
8591debfc3dSmrg       else
8601debfc3dSmrg 	{
8611debfc3dSmrg 	  unsigned HOST_WIDE_INT off = tree_to_uhwi (op1);
8621debfc3dSmrg 
8631debfc3dSmrg           /* op0 will be ADDR_EXPR here.  */
8641debfc3dSmrg 	  addr_object_size (osi, op0, object_size_type, &bytes);
8651debfc3dSmrg 	  if (bytes == unknown[object_size_type])
8661debfc3dSmrg 	    ;
8671debfc3dSmrg 	  else if (off > offset_limit)
8681debfc3dSmrg 	    bytes = unknown[object_size_type];
8691debfc3dSmrg 	  else if (off > bytes)
8701debfc3dSmrg 	    bytes = 0;
8711debfc3dSmrg 	  else
8721debfc3dSmrg 	    bytes -= off;
8731debfc3dSmrg 	}
8741debfc3dSmrg     }
8751debfc3dSmrg   else
8761debfc3dSmrg     bytes = unknown[object_size_type];
8771debfc3dSmrg 
8781debfc3dSmrg   if ((object_size_type & 2) == 0)
8791debfc3dSmrg     {
8801debfc3dSmrg       if (object_sizes[object_size_type][varno] < bytes)
8811debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
8821debfc3dSmrg     }
8831debfc3dSmrg   else
8841debfc3dSmrg     {
8851debfc3dSmrg       if (object_sizes[object_size_type][varno] > bytes)
8861debfc3dSmrg 	object_sizes[object_size_type][varno] = bytes;
8871debfc3dSmrg     }
8881debfc3dSmrg   return false;
8891debfc3dSmrg }
8901debfc3dSmrg 
8911debfc3dSmrg 
8921debfc3dSmrg /* Compute object_sizes for VAR, defined at STMT, which is
8931debfc3dSmrg    a COND_EXPR.  Return true if the object size might need reexamination
8941debfc3dSmrg    later.  */
8951debfc3dSmrg 
8961debfc3dSmrg static bool
cond_expr_object_size(struct object_size_info * osi,tree var,gimple * stmt)8971debfc3dSmrg cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt)
8981debfc3dSmrg {
8991debfc3dSmrg   tree then_, else_;
9001debfc3dSmrg   int object_size_type = osi->object_size_type;
9011debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (var);
9021debfc3dSmrg   bool reexamine = false;
9031debfc3dSmrg 
9041debfc3dSmrg   gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR);
9051debfc3dSmrg 
9061debfc3dSmrg   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
9071debfc3dSmrg     return false;
9081debfc3dSmrg 
9091debfc3dSmrg   then_ = gimple_assign_rhs2 (stmt);
9101debfc3dSmrg   else_ = gimple_assign_rhs3 (stmt);
9111debfc3dSmrg 
9121debfc3dSmrg   if (TREE_CODE (then_) == SSA_NAME)
9131debfc3dSmrg     reexamine |= merge_object_sizes (osi, var, then_, 0);
9141debfc3dSmrg   else
9151debfc3dSmrg     expr_object_size (osi, var, then_);
9161debfc3dSmrg 
917a2dc1f3fSmrg   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
918a2dc1f3fSmrg     return reexamine;
919a2dc1f3fSmrg 
9201debfc3dSmrg   if (TREE_CODE (else_) == SSA_NAME)
9211debfc3dSmrg     reexamine |= merge_object_sizes (osi, var, else_, 0);
9221debfc3dSmrg   else
9231debfc3dSmrg     expr_object_size (osi, var, else_);
9241debfc3dSmrg 
9251debfc3dSmrg   return reexamine;
9261debfc3dSmrg }
9271debfc3dSmrg 
9281debfc3dSmrg /* Compute object sizes for VAR.
9291debfc3dSmrg    For ADDR_EXPR an object size is the number of remaining bytes
9301debfc3dSmrg    to the end of the object (where what is considered an object depends on
9311debfc3dSmrg    OSI->object_size_type).
9321debfc3dSmrg    For allocation GIMPLE_CALL like malloc or calloc object size is the size
9331debfc3dSmrg    of the allocation.
9341debfc3dSmrg    For POINTER_PLUS_EXPR where second operand is a constant integer,
9351debfc3dSmrg    object size is object size of the first operand minus the constant.
9361debfc3dSmrg    If the constant is bigger than the number of remaining bytes until the
9371debfc3dSmrg    end of the object, object size is 0, but if it is instead a pointer
9381debfc3dSmrg    subtraction, object size is unknown[object_size_type].
9391debfc3dSmrg    To differentiate addition from subtraction, ADDR_EXPR returns
9401debfc3dSmrg    unknown[object_size_type] for all objects bigger than half of the address
9411debfc3dSmrg    space, and constants less than half of the address space are considered
9421debfc3dSmrg    addition, while bigger constants subtraction.
9431debfc3dSmrg    For a memcpy like GIMPLE_CALL that always returns one of its arguments, the
9441debfc3dSmrg    object size is object size of that argument.
9451debfc3dSmrg    Otherwise, object size is the maximum of object sizes of variables
9461debfc3dSmrg    that it might be set to.  */
9471debfc3dSmrg 
9481debfc3dSmrg static void
collect_object_sizes_for(struct object_size_info * osi,tree var)9491debfc3dSmrg collect_object_sizes_for (struct object_size_info *osi, tree var)
9501debfc3dSmrg {
9511debfc3dSmrg   int object_size_type = osi->object_size_type;
9521debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (var);
9531debfc3dSmrg   gimple *stmt;
9541debfc3dSmrg   bool reexamine;
9551debfc3dSmrg 
9561debfc3dSmrg   if (bitmap_bit_p (computed[object_size_type], varno))
9571debfc3dSmrg     return;
9581debfc3dSmrg 
9591debfc3dSmrg   if (osi->pass == 0)
9601debfc3dSmrg     {
9611debfc3dSmrg       if (bitmap_set_bit (osi->visited, varno))
9621debfc3dSmrg 	{
9631debfc3dSmrg 	  object_sizes[object_size_type][varno]
9641debfc3dSmrg 	    = (object_size_type & 2) ? -1 : 0;
9651debfc3dSmrg 	}
9661debfc3dSmrg       else
9671debfc3dSmrg 	{
9681debfc3dSmrg 	  /* Found a dependency loop.  Mark the variable for later
9691debfc3dSmrg 	     re-examination.  */
9701debfc3dSmrg 	  bitmap_set_bit (osi->reexamine, varno);
9711debfc3dSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
9721debfc3dSmrg 	    {
9731debfc3dSmrg 	      fprintf (dump_file, "Found a dependency loop at ");
9741debfc3dSmrg 	      print_generic_expr (dump_file, var, dump_flags);
9751debfc3dSmrg 	      fprintf (dump_file, "\n");
9761debfc3dSmrg 	    }
9771debfc3dSmrg 	  return;
9781debfc3dSmrg 	}
9791debfc3dSmrg     }
9801debfc3dSmrg 
9811debfc3dSmrg   if (dump_file && (dump_flags & TDF_DETAILS))
9821debfc3dSmrg     {
9831debfc3dSmrg       fprintf (dump_file, "Visiting use-def links for ");
9841debfc3dSmrg       print_generic_expr (dump_file, var, dump_flags);
9851debfc3dSmrg       fprintf (dump_file, "\n");
9861debfc3dSmrg     }
9871debfc3dSmrg 
9881debfc3dSmrg   stmt = SSA_NAME_DEF_STMT (var);
9891debfc3dSmrg   reexamine = false;
9901debfc3dSmrg 
9911debfc3dSmrg   switch (gimple_code (stmt))
9921debfc3dSmrg     {
9931debfc3dSmrg     case GIMPLE_ASSIGN:
9941debfc3dSmrg       {
9951debfc3dSmrg 	tree rhs = gimple_assign_rhs1 (stmt);
9961debfc3dSmrg         if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
9971debfc3dSmrg 	    || (gimple_assign_rhs_code (stmt) == ADDR_EXPR
9981debfc3dSmrg 		&& TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF))
9991debfc3dSmrg           reexamine = plus_stmt_object_size (osi, var, stmt);
10001debfc3dSmrg 	else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
10011debfc3dSmrg 	  reexamine = cond_expr_object_size (osi, var, stmt);
10021debfc3dSmrg         else if (gimple_assign_single_p (stmt)
10031debfc3dSmrg                  || gimple_assign_unary_nop_p (stmt))
10041debfc3dSmrg           {
10051debfc3dSmrg             if (TREE_CODE (rhs) == SSA_NAME
10061debfc3dSmrg                 && POINTER_TYPE_P (TREE_TYPE (rhs)))
10071debfc3dSmrg               reexamine = merge_object_sizes (osi, var, rhs, 0);
10081debfc3dSmrg             else
10091debfc3dSmrg               expr_object_size (osi, var, rhs);
10101debfc3dSmrg           }
10111debfc3dSmrg         else
10121debfc3dSmrg           unknown_object_size (osi, var);
10131debfc3dSmrg         break;
10141debfc3dSmrg       }
10151debfc3dSmrg 
10161debfc3dSmrg     case GIMPLE_CALL:
10171debfc3dSmrg       {
10181debfc3dSmrg 	gcall *call_stmt = as_a <gcall *> (stmt);
10191debfc3dSmrg         tree arg = pass_through_call (call_stmt);
10201debfc3dSmrg         if (arg)
10211debfc3dSmrg           {
10221debfc3dSmrg             if (TREE_CODE (arg) == SSA_NAME
10231debfc3dSmrg                 && POINTER_TYPE_P (TREE_TYPE (arg)))
10241debfc3dSmrg               reexamine = merge_object_sizes (osi, var, arg, 0);
10251debfc3dSmrg             else
10261debfc3dSmrg               expr_object_size (osi, var, arg);
10271debfc3dSmrg           }
10281debfc3dSmrg         else
10291debfc3dSmrg           call_object_size (osi, var, call_stmt);
10301debfc3dSmrg 	break;
10311debfc3dSmrg       }
10321debfc3dSmrg 
10331debfc3dSmrg     case GIMPLE_ASM:
10341debfc3dSmrg       /* Pointers defined by __asm__ statements can point anywhere.  */
10351debfc3dSmrg       object_sizes[object_size_type][varno] = unknown[object_size_type];
10361debfc3dSmrg       break;
10371debfc3dSmrg 
10381debfc3dSmrg     case GIMPLE_NOP:
10391debfc3dSmrg       if (SSA_NAME_VAR (var)
10401debfc3dSmrg 	  && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL)
10411debfc3dSmrg 	expr_object_size (osi, var, SSA_NAME_VAR (var));
10421debfc3dSmrg       else
10431debfc3dSmrg 	/* Uninitialized SSA names point nowhere.  */
10441debfc3dSmrg 	object_sizes[object_size_type][varno] = unknown[object_size_type];
10451debfc3dSmrg       break;
10461debfc3dSmrg 
10471debfc3dSmrg     case GIMPLE_PHI:
10481debfc3dSmrg       {
10491debfc3dSmrg 	unsigned i;
10501debfc3dSmrg 
10511debfc3dSmrg 	for (i = 0; i < gimple_phi_num_args (stmt); i++)
10521debfc3dSmrg 	  {
10531debfc3dSmrg 	    tree rhs = gimple_phi_arg (stmt, i)->def;
10541debfc3dSmrg 
10551debfc3dSmrg 	    if (object_sizes[object_size_type][varno]
10561debfc3dSmrg 		== unknown[object_size_type])
10571debfc3dSmrg 	      break;
10581debfc3dSmrg 
10591debfc3dSmrg 	    if (TREE_CODE (rhs) == SSA_NAME)
10601debfc3dSmrg 	      reexamine |= merge_object_sizes (osi, var, rhs, 0);
10611debfc3dSmrg 	    else if (osi->pass == 0)
10621debfc3dSmrg 	      expr_object_size (osi, var, rhs);
10631debfc3dSmrg 	  }
10641debfc3dSmrg 	break;
10651debfc3dSmrg       }
10661debfc3dSmrg 
10671debfc3dSmrg     default:
10681debfc3dSmrg       gcc_unreachable ();
10691debfc3dSmrg     }
10701debfc3dSmrg 
10711debfc3dSmrg   if (! reexamine
10721debfc3dSmrg       || object_sizes[object_size_type][varno] == unknown[object_size_type])
10731debfc3dSmrg     {
10741debfc3dSmrg       bitmap_set_bit (computed[object_size_type], varno);
10751debfc3dSmrg       bitmap_clear_bit (osi->reexamine, varno);
10761debfc3dSmrg     }
10771debfc3dSmrg   else
10781debfc3dSmrg     {
10791debfc3dSmrg       bitmap_set_bit (osi->reexamine, varno);
10801debfc3dSmrg       if (dump_file && (dump_flags & TDF_DETAILS))
10811debfc3dSmrg 	{
10821debfc3dSmrg 	  fprintf (dump_file, "Need to reexamine ");
10831debfc3dSmrg 	  print_generic_expr (dump_file, var, dump_flags);
10841debfc3dSmrg 	  fprintf (dump_file, "\n");
10851debfc3dSmrg 	}
10861debfc3dSmrg     }
10871debfc3dSmrg }
10881debfc3dSmrg 
10891debfc3dSmrg 
10901debfc3dSmrg /* Helper function for check_for_plus_in_loops.  Called recursively
10911debfc3dSmrg    to detect loops.  */
10921debfc3dSmrg 
10931debfc3dSmrg static void
check_for_plus_in_loops_1(struct object_size_info * osi,tree var,unsigned int depth)10941debfc3dSmrg check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
10951debfc3dSmrg 			   unsigned int depth)
10961debfc3dSmrg {
10971debfc3dSmrg   gimple *stmt = SSA_NAME_DEF_STMT (var);
10981debfc3dSmrg   unsigned int varno = SSA_NAME_VERSION (var);
10991debfc3dSmrg 
11001debfc3dSmrg   if (osi->depths[varno])
11011debfc3dSmrg     {
11021debfc3dSmrg       if (osi->depths[varno] != depth)
11031debfc3dSmrg 	{
11041debfc3dSmrg 	  unsigned int *sp;
11051debfc3dSmrg 
11061debfc3dSmrg 	  /* Found a loop involving pointer addition.  */
11071debfc3dSmrg 	  for (sp = osi->tos; sp > osi->stack; )
11081debfc3dSmrg 	    {
11091debfc3dSmrg 	      --sp;
11101debfc3dSmrg 	      bitmap_clear_bit (osi->reexamine, *sp);
11111debfc3dSmrg 	      bitmap_set_bit (computed[osi->object_size_type], *sp);
11121debfc3dSmrg 	      object_sizes[osi->object_size_type][*sp] = 0;
11131debfc3dSmrg 	      if (*sp == varno)
11141debfc3dSmrg 		break;
11151debfc3dSmrg 	    }
11161debfc3dSmrg 	}
11171debfc3dSmrg       return;
11181debfc3dSmrg     }
11191debfc3dSmrg   else if (! bitmap_bit_p (osi->reexamine, varno))
11201debfc3dSmrg     return;
11211debfc3dSmrg 
11221debfc3dSmrg   osi->depths[varno] = depth;
11231debfc3dSmrg   *osi->tos++ = varno;
11241debfc3dSmrg 
11251debfc3dSmrg   switch (gimple_code (stmt))
11261debfc3dSmrg     {
11271debfc3dSmrg 
11281debfc3dSmrg     case GIMPLE_ASSIGN:
11291debfc3dSmrg       {
11301debfc3dSmrg         if ((gimple_assign_single_p (stmt)
11311debfc3dSmrg              || gimple_assign_unary_nop_p (stmt))
11321debfc3dSmrg             && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
11331debfc3dSmrg           {
11341debfc3dSmrg             tree rhs = gimple_assign_rhs1 (stmt);
11351debfc3dSmrg 
11361debfc3dSmrg             check_for_plus_in_loops_1 (osi, rhs, depth);
11371debfc3dSmrg           }
11381debfc3dSmrg         else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
11391debfc3dSmrg           {
11401debfc3dSmrg             tree basevar = gimple_assign_rhs1 (stmt);
11411debfc3dSmrg             tree cst = gimple_assign_rhs2 (stmt);
11421debfc3dSmrg 
11431debfc3dSmrg             gcc_assert (TREE_CODE (cst) == INTEGER_CST);
11441debfc3dSmrg 
11451debfc3dSmrg             check_for_plus_in_loops_1 (osi, basevar,
11461debfc3dSmrg                                        depth + !integer_zerop (cst));
11471debfc3dSmrg           }
11481debfc3dSmrg         else
11491debfc3dSmrg           gcc_unreachable ();
11501debfc3dSmrg         break;
11511debfc3dSmrg       }
11521debfc3dSmrg 
11531debfc3dSmrg     case GIMPLE_CALL:
11541debfc3dSmrg       {
11551debfc3dSmrg 	gcall *call_stmt = as_a <gcall *> (stmt);
11561debfc3dSmrg         tree arg = pass_through_call (call_stmt);
11571debfc3dSmrg         if (arg)
11581debfc3dSmrg           {
11591debfc3dSmrg             if (TREE_CODE (arg) == SSA_NAME)
11601debfc3dSmrg               check_for_plus_in_loops_1 (osi, arg, depth);
11611debfc3dSmrg             else
11621debfc3dSmrg               gcc_unreachable ();
11631debfc3dSmrg           }
11641debfc3dSmrg         break;
11651debfc3dSmrg       }
11661debfc3dSmrg 
11671debfc3dSmrg     case GIMPLE_PHI:
11681debfc3dSmrg       {
11691debfc3dSmrg 	unsigned i;
11701debfc3dSmrg 
11711debfc3dSmrg 	for (i = 0; i < gimple_phi_num_args (stmt); i++)
11721debfc3dSmrg 	  {
11731debfc3dSmrg 	    tree rhs = gimple_phi_arg (stmt, i)->def;
11741debfc3dSmrg 
11751debfc3dSmrg 	    if (TREE_CODE (rhs) == SSA_NAME)
11761debfc3dSmrg 	      check_for_plus_in_loops_1 (osi, rhs, depth);
11771debfc3dSmrg 	  }
11781debfc3dSmrg 	break;
11791debfc3dSmrg       }
11801debfc3dSmrg 
11811debfc3dSmrg     default:
11821debfc3dSmrg       gcc_unreachable ();
11831debfc3dSmrg     }
11841debfc3dSmrg 
11851debfc3dSmrg   osi->depths[varno] = 0;
11861debfc3dSmrg   osi->tos--;
11871debfc3dSmrg }
11881debfc3dSmrg 
11891debfc3dSmrg 
11901debfc3dSmrg /* Check if some pointer we are computing object size of is being increased
11911debfc3dSmrg    within a loop.  If yes, assume all the SSA variables participating in
11921debfc3dSmrg    that loop have minimum object sizes 0.  */
11931debfc3dSmrg 
11941debfc3dSmrg static void
check_for_plus_in_loops(struct object_size_info * osi,tree var)11951debfc3dSmrg check_for_plus_in_loops (struct object_size_info *osi, tree var)
11961debfc3dSmrg {
11971debfc3dSmrg   gimple *stmt = SSA_NAME_DEF_STMT (var);
11981debfc3dSmrg 
11991debfc3dSmrg   /* NOTE: In the pre-tuples code, we handled a CALL_EXPR here,
12001debfc3dSmrg      and looked for a POINTER_PLUS_EXPR in the pass-through
12011debfc3dSmrg      argument, if any.  In GIMPLE, however, such an expression
12021debfc3dSmrg      is not a valid call operand.  */
12031debfc3dSmrg 
12041debfc3dSmrg   if (is_gimple_assign (stmt)
12051debfc3dSmrg       && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
12061debfc3dSmrg     {
12071debfc3dSmrg       tree basevar = gimple_assign_rhs1 (stmt);
12081debfc3dSmrg       tree cst = gimple_assign_rhs2 (stmt);
12091debfc3dSmrg 
12101debfc3dSmrg       gcc_assert (TREE_CODE (cst) == INTEGER_CST);
12111debfc3dSmrg 
12121debfc3dSmrg       if (integer_zerop (cst))
12131debfc3dSmrg         return;
12141debfc3dSmrg 
12151debfc3dSmrg       osi->depths[SSA_NAME_VERSION (basevar)] = 1;
12161debfc3dSmrg       *osi->tos++ = SSA_NAME_VERSION (basevar);
12171debfc3dSmrg       check_for_plus_in_loops_1 (osi, var, 2);
12181debfc3dSmrg       osi->depths[SSA_NAME_VERSION (basevar)] = 0;
12191debfc3dSmrg       osi->tos--;
12201debfc3dSmrg     }
12211debfc3dSmrg }
12221debfc3dSmrg 
12231debfc3dSmrg 
12241debfc3dSmrg /* Initialize data structures for the object size computation.  */
12251debfc3dSmrg 
12261debfc3dSmrg void
init_object_sizes(void)12271debfc3dSmrg init_object_sizes (void)
12281debfc3dSmrg {
12291debfc3dSmrg   int object_size_type;
12301debfc3dSmrg 
12311debfc3dSmrg   if (computed[0])
12321debfc3dSmrg     return;
12331debfc3dSmrg 
12341debfc3dSmrg   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
12351debfc3dSmrg     {
12361debfc3dSmrg       object_sizes[object_size_type].safe_grow (num_ssa_names);
12371debfc3dSmrg       computed[object_size_type] = BITMAP_ALLOC (NULL);
12381debfc3dSmrg     }
12391debfc3dSmrg 
12401debfc3dSmrg   init_offset_limit ();
12411debfc3dSmrg }
12421debfc3dSmrg 
12431debfc3dSmrg 
12441debfc3dSmrg /* Destroy data structures after the object size computation.  */
12451debfc3dSmrg 
12461debfc3dSmrg void
fini_object_sizes(void)12471debfc3dSmrg fini_object_sizes (void)
12481debfc3dSmrg {
12491debfc3dSmrg   int object_size_type;
12501debfc3dSmrg 
12511debfc3dSmrg   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
12521debfc3dSmrg     {
12531debfc3dSmrg       object_sizes[object_size_type].release ();
12541debfc3dSmrg       BITMAP_FREE (computed[object_size_type]);
12551debfc3dSmrg     }
12561debfc3dSmrg }
12571debfc3dSmrg 
12581debfc3dSmrg 
12591debfc3dSmrg /* Simple pass to optimize all __builtin_object_size () builtins.  */
12601debfc3dSmrg 
12611debfc3dSmrg namespace {
12621debfc3dSmrg 
12631debfc3dSmrg const pass_data pass_data_object_sizes =
12641debfc3dSmrg {
12651debfc3dSmrg   GIMPLE_PASS, /* type */
12661debfc3dSmrg   "objsz", /* name */
12671debfc3dSmrg   OPTGROUP_NONE, /* optinfo_flags */
12681debfc3dSmrg   TV_NONE, /* tv_id */
12691debfc3dSmrg   ( PROP_cfg | PROP_ssa ), /* properties_required */
12701debfc3dSmrg   0, /* properties_provided */
12711debfc3dSmrg   0, /* properties_destroyed */
12721debfc3dSmrg   0, /* todo_flags_start */
12731debfc3dSmrg   0, /* todo_flags_finish */
12741debfc3dSmrg };
12751debfc3dSmrg 
12761debfc3dSmrg class pass_object_sizes : public gimple_opt_pass
12771debfc3dSmrg {
12781debfc3dSmrg public:
pass_object_sizes(gcc::context * ctxt)12791debfc3dSmrg   pass_object_sizes (gcc::context *ctxt)
12801debfc3dSmrg     : gimple_opt_pass (pass_data_object_sizes, ctxt), insert_min_max_p (false)
12811debfc3dSmrg   {}
12821debfc3dSmrg 
12831debfc3dSmrg   /* opt_pass methods: */
clone()12841debfc3dSmrg   opt_pass * clone () { return new pass_object_sizes (m_ctxt); }
set_pass_param(unsigned int n,bool param)12851debfc3dSmrg   void set_pass_param (unsigned int n, bool param)
12861debfc3dSmrg     {
12871debfc3dSmrg       gcc_assert (n == 0);
12881debfc3dSmrg       insert_min_max_p = param;
12891debfc3dSmrg     }
12901debfc3dSmrg   virtual unsigned int execute (function *);
12911debfc3dSmrg 
12921debfc3dSmrg  private:
12931debfc3dSmrg   /* Determines whether the pass instance creates MIN/MAX_EXPRs.  */
12941debfc3dSmrg   bool insert_min_max_p;
12951debfc3dSmrg }; // class pass_object_sizes
12961debfc3dSmrg 
12971debfc3dSmrg /* Dummy valueize function.  */
12981debfc3dSmrg 
12991debfc3dSmrg static tree
do_valueize(tree t)13001debfc3dSmrg do_valueize (tree t)
13011debfc3dSmrg {
13021debfc3dSmrg   return t;
13031debfc3dSmrg }
13041debfc3dSmrg 
13051debfc3dSmrg unsigned int
execute(function * fun)13061debfc3dSmrg pass_object_sizes::execute (function *fun)
13071debfc3dSmrg {
13081debfc3dSmrg   basic_block bb;
13091debfc3dSmrg   FOR_EACH_BB_FN (bb, fun)
13101debfc3dSmrg     {
13111debfc3dSmrg       gimple_stmt_iterator i;
13121debfc3dSmrg       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
13131debfc3dSmrg 	{
13141debfc3dSmrg 	  tree result;
13151debfc3dSmrg 	  gimple *call = gsi_stmt (i);
13161debfc3dSmrg 	  if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE))
13171debfc3dSmrg 	    continue;
13181debfc3dSmrg 
13191debfc3dSmrg 	  init_object_sizes ();
13201debfc3dSmrg 
13211debfc3dSmrg 	  /* If insert_min_max_p, only attempt to fold
13221debfc3dSmrg 	     __builtin_object_size (x, 1) and __builtin_object_size (x, 3),
13231debfc3dSmrg 	     and rather than folding the builtin to the constant if any,
13241debfc3dSmrg 	     create a MIN_EXPR or MAX_EXPR of the __builtin_object_size
13251debfc3dSmrg 	     call result and the computed constant.  */
13261debfc3dSmrg 	  if (insert_min_max_p)
13271debfc3dSmrg 	    {
13281debfc3dSmrg 	      tree ost = gimple_call_arg (call, 1);
13291debfc3dSmrg 	      if (tree_fits_uhwi_p (ost))
13301debfc3dSmrg 		{
13311debfc3dSmrg 		  unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
13321debfc3dSmrg 		  tree ptr = gimple_call_arg (call, 0);
13331debfc3dSmrg 		  tree lhs = gimple_call_lhs (call);
13341debfc3dSmrg 		  if ((object_size_type == 1 || object_size_type == 3)
13351debfc3dSmrg 		      && (TREE_CODE (ptr) == ADDR_EXPR
13361debfc3dSmrg 			  || TREE_CODE (ptr) == SSA_NAME)
13371debfc3dSmrg 		      && lhs)
13381debfc3dSmrg 		    {
13391debfc3dSmrg 		      tree type = TREE_TYPE (lhs);
13401debfc3dSmrg 		      unsigned HOST_WIDE_INT bytes;
13411debfc3dSmrg 		      if (compute_builtin_object_size (ptr, object_size_type,
13421debfc3dSmrg 						       &bytes)
13431debfc3dSmrg 			  && wi::fits_to_tree_p (bytes, type))
13441debfc3dSmrg 			{
13451debfc3dSmrg 			  tree tem = make_ssa_name (type);
13461debfc3dSmrg 			  gimple_call_set_lhs (call, tem);
13471debfc3dSmrg 			  enum tree_code code
13481debfc3dSmrg 			    = object_size_type == 1 ? MIN_EXPR : MAX_EXPR;
13491debfc3dSmrg 			  tree cst = build_int_cstu (type, bytes);
13501debfc3dSmrg 			  gimple *g
13511debfc3dSmrg 			    = gimple_build_assign (lhs, code, tem, cst);
13521debfc3dSmrg 			  gsi_insert_after (&i, g, GSI_NEW_STMT);
13531debfc3dSmrg 			  update_stmt (call);
13541debfc3dSmrg 			}
13551debfc3dSmrg 		    }
13561debfc3dSmrg 		}
13571debfc3dSmrg 	      continue;
13581debfc3dSmrg 	    }
13591debfc3dSmrg 
13601debfc3dSmrg 	  tree lhs = gimple_call_lhs (call);
13611debfc3dSmrg 	  if (!lhs)
13621debfc3dSmrg 	    continue;
13631debfc3dSmrg 
13641debfc3dSmrg 	  result = gimple_fold_stmt_to_constant (call, do_valueize);
13651debfc3dSmrg 	  if (!result)
13661debfc3dSmrg 	    {
13671debfc3dSmrg 	      tree ost = gimple_call_arg (call, 1);
13681debfc3dSmrg 
13691debfc3dSmrg 	      if (tree_fits_uhwi_p (ost))
13701debfc3dSmrg 		{
13711debfc3dSmrg 		  unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
13721debfc3dSmrg 
13731debfc3dSmrg 		  if (object_size_type < 2)
13741debfc3dSmrg 		    result = fold_convert (size_type_node,
13751debfc3dSmrg 					   integer_minus_one_node);
13761debfc3dSmrg 		  else if (object_size_type < 4)
13771debfc3dSmrg 		    result = build_zero_cst (size_type_node);
13781debfc3dSmrg 		}
13791debfc3dSmrg 
13801debfc3dSmrg 	      if (!result)
13811debfc3dSmrg 		continue;
13821debfc3dSmrg 	    }
13831debfc3dSmrg 
13841debfc3dSmrg 	  gcc_assert (TREE_CODE (result) == INTEGER_CST);
13851debfc3dSmrg 
13861debfc3dSmrg 	  if (dump_file && (dump_flags & TDF_DETAILS))
13871debfc3dSmrg 	    {
13881debfc3dSmrg 	      fprintf (dump_file, "Simplified\n  ");
13891debfc3dSmrg 	      print_gimple_stmt (dump_file, call, 0, dump_flags);
13901debfc3dSmrg 	      fprintf (dump_file, " to ");
1391a2dc1f3fSmrg 	      print_generic_expr (dump_file, result);
13921debfc3dSmrg 	      fprintf (dump_file, "\n");
13931debfc3dSmrg 	    }
13941debfc3dSmrg 
13951debfc3dSmrg 	  /* Propagate into all uses and fold those stmts.  */
1396*8feb0f0bSmrg 	  if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
13971debfc3dSmrg 	    replace_uses_by (lhs, result);
1398*8feb0f0bSmrg 	  else
1399*8feb0f0bSmrg 	    replace_call_with_value (&i, result);
14001debfc3dSmrg 	}
14011debfc3dSmrg     }
14021debfc3dSmrg 
14031debfc3dSmrg   fini_object_sizes ();
14041debfc3dSmrg   return 0;
14051debfc3dSmrg }
14061debfc3dSmrg 
14071debfc3dSmrg } // anon namespace
14081debfc3dSmrg 
14091debfc3dSmrg gimple_opt_pass *
make_pass_object_sizes(gcc::context * ctxt)14101debfc3dSmrg make_pass_object_sizes (gcc::context *ctxt)
14111debfc3dSmrg {
14121debfc3dSmrg   return new pass_object_sizes (ctxt);
14131debfc3dSmrg }
1414