xref: /openbsd/gnu/gcc/gcc/tree-object-size.c (revision 404b540a)
1*404b540aSrobert /* __builtin_object_size (ptr, object_size_type) computation
2*404b540aSrobert    Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
3*404b540aSrobert    Contributed by Jakub Jelinek <jakub@redhat.com>
4*404b540aSrobert 
5*404b540aSrobert This file is part of GCC.
6*404b540aSrobert 
7*404b540aSrobert GCC is free software; you can redistribute it and/or modify
8*404b540aSrobert it under the terms of the GNU General Public License as published by
9*404b540aSrobert the Free Software Foundation; either version 2, or (at your option)
10*404b540aSrobert any later version.
11*404b540aSrobert 
12*404b540aSrobert GCC is distributed in the hope that it will be useful,
13*404b540aSrobert but WITHOUT ANY WARRANTY; without even the implied warranty of
14*404b540aSrobert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*404b540aSrobert GNU General Public License for more details.
16*404b540aSrobert 
17*404b540aSrobert You should have received a copy of the GNU General Public License
18*404b540aSrobert along with GCC; see the file COPYING.  If not, write to
19*404b540aSrobert the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20*404b540aSrobert Boston, MA 02110-1301, USA.  */
21*404b540aSrobert 
22*404b540aSrobert #include "config.h"
23*404b540aSrobert #include "system.h"
24*404b540aSrobert #include "coretypes.h"
25*404b540aSrobert #include "tm.h"
26*404b540aSrobert #include "tree.h"
27*404b540aSrobert #include "diagnostic.h"
28*404b540aSrobert #include "tree-flow.h"
29*404b540aSrobert #include "tree-pass.h"
30*404b540aSrobert #include "tree-ssa-propagate.h"
31*404b540aSrobert 
32*404b540aSrobert struct object_size_info
33*404b540aSrobert {
34*404b540aSrobert   int object_size_type;
35*404b540aSrobert   bitmap visited, reexamine;
36*404b540aSrobert   int pass;
37*404b540aSrobert   bool changed;
38*404b540aSrobert   unsigned int *depths;
39*404b540aSrobert   unsigned int *stack, *tos;
40*404b540aSrobert };
41*404b540aSrobert 
42*404b540aSrobert static unsigned HOST_WIDE_INT unknown[4] = { -1, -1, 0, 0 };
43*404b540aSrobert 
44*404b540aSrobert static tree compute_object_offset (tree, tree);
45*404b540aSrobert static unsigned HOST_WIDE_INT addr_object_size (tree, int);
46*404b540aSrobert static unsigned HOST_WIDE_INT alloc_object_size (tree, int);
47*404b540aSrobert static tree pass_through_call (tree);
48*404b540aSrobert static void collect_object_sizes_for (struct object_size_info *, tree);
49*404b540aSrobert static void expr_object_size (struct object_size_info *, tree, tree);
50*404b540aSrobert static bool merge_object_sizes (struct object_size_info *, tree, tree,
51*404b540aSrobert 				unsigned HOST_WIDE_INT);
52*404b540aSrobert static bool plus_expr_object_size (struct object_size_info *, tree, tree);
53*404b540aSrobert static unsigned int compute_object_sizes (void);
54*404b540aSrobert static void init_offset_limit (void);
55*404b540aSrobert static void check_for_plus_in_loops (struct object_size_info *, tree);
56*404b540aSrobert static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
57*404b540aSrobert 				       unsigned int);
58*404b540aSrobert 
59*404b540aSrobert /* object_sizes[0] is upper bound for number of bytes till the end of
60*404b540aSrobert    the object.
61*404b540aSrobert    object_sizes[1] is upper bound for number of bytes till the end of
62*404b540aSrobert    the subobject (innermost array or field with address taken).
63*404b540aSrobert    object_sizes[2] is lower bound for number of bytes till the end of
64*404b540aSrobert    the object and object_sizes[3] lower bound for subobject.  */
65*404b540aSrobert static unsigned HOST_WIDE_INT *object_sizes[4];
66*404b540aSrobert 
67*404b540aSrobert /* Bitmaps what object sizes have been computed already.  */
68*404b540aSrobert static bitmap computed[4];
69*404b540aSrobert 
70*404b540aSrobert /* Maximum value of offset we consider to be addition.  */
71*404b540aSrobert static unsigned HOST_WIDE_INT offset_limit;
72*404b540aSrobert 
73*404b540aSrobert 
74*404b540aSrobert /* Initialize OFFSET_LIMIT variable.  */
75*404b540aSrobert static void
init_offset_limit(void)76*404b540aSrobert init_offset_limit (void)
77*404b540aSrobert {
78*404b540aSrobert   if (host_integerp (TYPE_MAX_VALUE (sizetype), 1))
79*404b540aSrobert     offset_limit = tree_low_cst (TYPE_MAX_VALUE (sizetype), 1);
80*404b540aSrobert   else
81*404b540aSrobert     offset_limit = -1;
82*404b540aSrobert   offset_limit /= 2;
83*404b540aSrobert }
84*404b540aSrobert 
85*404b540aSrobert 
86*404b540aSrobert /* Compute offset of EXPR within VAR.  Return error_mark_node
87*404b540aSrobert    if unknown.  */
88*404b540aSrobert 
89*404b540aSrobert static tree
compute_object_offset(tree expr,tree var)90*404b540aSrobert compute_object_offset (tree expr, tree var)
91*404b540aSrobert {
92*404b540aSrobert   enum tree_code code = PLUS_EXPR;
93*404b540aSrobert   tree base, off, t;
94*404b540aSrobert 
95*404b540aSrobert   if (expr == var)
96*404b540aSrobert     return size_zero_node;
97*404b540aSrobert 
98*404b540aSrobert   switch (TREE_CODE (expr))
99*404b540aSrobert     {
100*404b540aSrobert     case COMPONENT_REF:
101*404b540aSrobert       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
102*404b540aSrobert       if (base == error_mark_node)
103*404b540aSrobert 	return base;
104*404b540aSrobert 
105*404b540aSrobert       t = TREE_OPERAND (expr, 1);
106*404b540aSrobert       off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
107*404b540aSrobert 			size_int (tree_low_cst (DECL_FIELD_BIT_OFFSET (t), 1)
108*404b540aSrobert 				  / BITS_PER_UNIT));
109*404b540aSrobert       break;
110*404b540aSrobert 
111*404b540aSrobert     case REALPART_EXPR:
112*404b540aSrobert     case NOP_EXPR:
113*404b540aSrobert     case CONVERT_EXPR:
114*404b540aSrobert     case VIEW_CONVERT_EXPR:
115*404b540aSrobert     case NON_LVALUE_EXPR:
116*404b540aSrobert       return compute_object_offset (TREE_OPERAND (expr, 0), var);
117*404b540aSrobert 
118*404b540aSrobert     case IMAGPART_EXPR:
119*404b540aSrobert       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
120*404b540aSrobert       if (base == error_mark_node)
121*404b540aSrobert 	return base;
122*404b540aSrobert 
123*404b540aSrobert       off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
124*404b540aSrobert       break;
125*404b540aSrobert 
126*404b540aSrobert     case ARRAY_REF:
127*404b540aSrobert       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
128*404b540aSrobert       if (base == error_mark_node)
129*404b540aSrobert 	return base;
130*404b540aSrobert 
131*404b540aSrobert       t = TREE_OPERAND (expr, 1);
132*404b540aSrobert       if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
133*404b540aSrobert 	{
134*404b540aSrobert 	  code = MINUS_EXPR;
135*404b540aSrobert 	  t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
136*404b540aSrobert 	}
137*404b540aSrobert       t = fold_convert (sizetype, t);
138*404b540aSrobert       off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
139*404b540aSrobert       break;
140*404b540aSrobert 
141*404b540aSrobert     default:
142*404b540aSrobert       return error_mark_node;
143*404b540aSrobert     }
144*404b540aSrobert 
145*404b540aSrobert   return size_binop (code, base, off);
146*404b540aSrobert }
147*404b540aSrobert 
148*404b540aSrobert 
149*404b540aSrobert /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
150*404b540aSrobert    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
151*404b540aSrobert    If unknown, return unknown[object_size_type].  */
152*404b540aSrobert 
153*404b540aSrobert static unsigned HOST_WIDE_INT
addr_object_size(tree ptr,int object_size_type)154*404b540aSrobert addr_object_size (tree ptr, int object_size_type)
155*404b540aSrobert {
156*404b540aSrobert   tree pt_var;
157*404b540aSrobert 
158*404b540aSrobert   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
159*404b540aSrobert 
160*404b540aSrobert   pt_var = TREE_OPERAND (ptr, 0);
161*404b540aSrobert   if (REFERENCE_CLASS_P (pt_var))
162*404b540aSrobert     pt_var = get_base_address (pt_var);
163*404b540aSrobert 
164*404b540aSrobert   if (pt_var
165*404b540aSrobert       && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
166*404b540aSrobert       && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
167*404b540aSrobert       && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
168*404b540aSrobert       && (unsigned HOST_WIDE_INT)
169*404b540aSrobert 	 tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit)
170*404b540aSrobert     {
171*404b540aSrobert       tree bytes;
172*404b540aSrobert 
173*404b540aSrobert       if (pt_var != TREE_OPERAND (ptr, 0))
174*404b540aSrobert 	{
175*404b540aSrobert 	  tree var;
176*404b540aSrobert 
177*404b540aSrobert 	  if (object_size_type & 1)
178*404b540aSrobert 	    {
179*404b540aSrobert 	      var = TREE_OPERAND (ptr, 0);
180*404b540aSrobert 
181*404b540aSrobert 	      while (var != pt_var
182*404b540aSrobert 		      && TREE_CODE (var) != BIT_FIELD_REF
183*404b540aSrobert 		      && TREE_CODE (var) != COMPONENT_REF
184*404b540aSrobert 		      && TREE_CODE (var) != ARRAY_REF
185*404b540aSrobert 		      && TREE_CODE (var) != ARRAY_RANGE_REF
186*404b540aSrobert 		      && TREE_CODE (var) != REALPART_EXPR
187*404b540aSrobert 		      && TREE_CODE (var) != IMAGPART_EXPR)
188*404b540aSrobert 		var = TREE_OPERAND (var, 0);
189*404b540aSrobert 	      if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
190*404b540aSrobert 		var = TREE_OPERAND (var, 0);
191*404b540aSrobert 	      if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
192*404b540aSrobert 		  || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
193*404b540aSrobert 		  || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
194*404b540aSrobert 				      TYPE_SIZE_UNIT (TREE_TYPE (var))))
195*404b540aSrobert 		var = pt_var;
196*404b540aSrobert 	    }
197*404b540aSrobert 	  else
198*404b540aSrobert 	    var = pt_var;
199*404b540aSrobert 
200*404b540aSrobert 	  bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
201*404b540aSrobert 	  if (bytes != error_mark_node)
202*404b540aSrobert 	    {
203*404b540aSrobert 	      if (TREE_CODE (bytes) == INTEGER_CST
204*404b540aSrobert 		  && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes))
205*404b540aSrobert 		bytes = size_zero_node;
206*404b540aSrobert 	      else
207*404b540aSrobert 		bytes = size_binop (MINUS_EXPR,
208*404b540aSrobert 				    TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes);
209*404b540aSrobert 	    }
210*404b540aSrobert 	}
211*404b540aSrobert       else
212*404b540aSrobert 	bytes = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
213*404b540aSrobert 
214*404b540aSrobert       if (host_integerp (bytes, 1))
215*404b540aSrobert 	return tree_low_cst (bytes, 1);
216*404b540aSrobert     }
217*404b540aSrobert 
218*404b540aSrobert   return unknown[object_size_type];
219*404b540aSrobert }
220*404b540aSrobert 
221*404b540aSrobert 
222*404b540aSrobert /* Compute __builtin_object_size for CALL, which is a CALL_EXPR.
223*404b540aSrobert    Handles various allocation calls.  OBJECT_SIZE_TYPE is the second
224*404b540aSrobert    argument from __builtin_object_size.  If unknown, return
225*404b540aSrobert    unknown[object_size_type].  */
226*404b540aSrobert 
227*404b540aSrobert static unsigned HOST_WIDE_INT
alloc_object_size(tree call,int object_size_type)228*404b540aSrobert alloc_object_size (tree call, int object_size_type)
229*404b540aSrobert {
230*404b540aSrobert   tree callee, arglist, a, bytes = NULL_TREE;
231*404b540aSrobert   unsigned int arg_mask = 0;
232*404b540aSrobert 
233*404b540aSrobert   gcc_assert (TREE_CODE (call) == CALL_EXPR);
234*404b540aSrobert 
235*404b540aSrobert   callee = get_callee_fndecl (call);
236*404b540aSrobert   arglist = TREE_OPERAND (call, 1);
237*404b540aSrobert   if (callee
238*404b540aSrobert       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
239*404b540aSrobert     switch (DECL_FUNCTION_CODE (callee))
240*404b540aSrobert       {
241*404b540aSrobert       case BUILT_IN_MALLOC:
242*404b540aSrobert       case BUILT_IN_ALLOCA:
243*404b540aSrobert 	arg_mask = 1;
244*404b540aSrobert 	break;
245*404b540aSrobert       /*
246*404b540aSrobert       case BUILT_IN_REALLOC:
247*404b540aSrobert 	arg_mask = 2;
248*404b540aSrobert 	break;
249*404b540aSrobert 	*/
250*404b540aSrobert       case BUILT_IN_CALLOC:
251*404b540aSrobert 	arg_mask = 3;
252*404b540aSrobert 	break;
253*404b540aSrobert       default:
254*404b540aSrobert 	break;
255*404b540aSrobert       }
256*404b540aSrobert 
257*404b540aSrobert   for (a = arglist; arg_mask && a; arg_mask >>= 1, a = TREE_CHAIN (a))
258*404b540aSrobert     if (arg_mask & 1)
259*404b540aSrobert       {
260*404b540aSrobert 	tree arg = TREE_VALUE (a);
261*404b540aSrobert 
262*404b540aSrobert 	if (TREE_CODE (arg) != INTEGER_CST)
263*404b540aSrobert 	  break;
264*404b540aSrobert 
265*404b540aSrobert 	if (! bytes)
266*404b540aSrobert 	  bytes = fold_convert (sizetype, arg);
267*404b540aSrobert 	else
268*404b540aSrobert 	  bytes = size_binop (MULT_EXPR, bytes,
269*404b540aSrobert 			      fold_convert (sizetype, arg));
270*404b540aSrobert       }
271*404b540aSrobert 
272*404b540aSrobert   if (! arg_mask && bytes && host_integerp (bytes, 1))
273*404b540aSrobert     return tree_low_cst (bytes, 1);
274*404b540aSrobert 
275*404b540aSrobert   return unknown[object_size_type];
276*404b540aSrobert }
277*404b540aSrobert 
278*404b540aSrobert 
279*404b540aSrobert /* If object size is propagated from one of function's arguments directly
280*404b540aSrobert    to its return value, return that argument for CALL_EXPR CALL.
281*404b540aSrobert    Otherwise return NULL.  */
282*404b540aSrobert 
283*404b540aSrobert static tree
pass_through_call(tree call)284*404b540aSrobert pass_through_call (tree call)
285*404b540aSrobert {
286*404b540aSrobert   tree callee = get_callee_fndecl (call);
287*404b540aSrobert   tree arglist = TREE_OPERAND (call, 1);
288*404b540aSrobert 
289*404b540aSrobert   if (callee
290*404b540aSrobert       && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
291*404b540aSrobert     switch (DECL_FUNCTION_CODE (callee))
292*404b540aSrobert       {
293*404b540aSrobert       case BUILT_IN_MEMCPY:
294*404b540aSrobert       case BUILT_IN_MEMMOVE:
295*404b540aSrobert       case BUILT_IN_MEMSET:
296*404b540aSrobert       case BUILT_IN_STRCPY:
297*404b540aSrobert       case BUILT_IN_STRNCPY:
298*404b540aSrobert       case BUILT_IN_STRCAT:
299*404b540aSrobert       case BUILT_IN_STRNCAT:
300*404b540aSrobert       case BUILT_IN_MEMCPY_CHK:
301*404b540aSrobert       case BUILT_IN_MEMMOVE_CHK:
302*404b540aSrobert       case BUILT_IN_MEMSET_CHK:
303*404b540aSrobert       case BUILT_IN_STRCPY_CHK:
304*404b540aSrobert       case BUILT_IN_STRNCPY_CHK:
305*404b540aSrobert       case BUILT_IN_STRCAT_CHK:
306*404b540aSrobert       case BUILT_IN_STRNCAT_CHK:
307*404b540aSrobert 	if (arglist)
308*404b540aSrobert 	  return TREE_VALUE (arglist);
309*404b540aSrobert 	break;
310*404b540aSrobert       default:
311*404b540aSrobert 	break;
312*404b540aSrobert       }
313*404b540aSrobert 
314*404b540aSrobert   return NULL_TREE;
315*404b540aSrobert }
316*404b540aSrobert 
317*404b540aSrobert 
318*404b540aSrobert /* Compute __builtin_object_size value for PTR.  OBJECT_SIZE_TYPE is the
319*404b540aSrobert    second argument from __builtin_object_size.  */
320*404b540aSrobert 
321*404b540aSrobert unsigned HOST_WIDE_INT
compute_builtin_object_size(tree ptr,int object_size_type)322*404b540aSrobert compute_builtin_object_size (tree ptr, int object_size_type)
323*404b540aSrobert {
324*404b540aSrobert   gcc_assert (object_size_type >= 0 && object_size_type <= 3);
325*404b540aSrobert 
326*404b540aSrobert   if (! offset_limit)
327*404b540aSrobert     init_offset_limit ();
328*404b540aSrobert 
329*404b540aSrobert   if (TREE_CODE (ptr) == ADDR_EXPR)
330*404b540aSrobert     return addr_object_size (ptr, object_size_type);
331*404b540aSrobert   else if (TREE_CODE (ptr) == CALL_EXPR)
332*404b540aSrobert     {
333*404b540aSrobert       tree arg = pass_through_call (ptr);
334*404b540aSrobert 
335*404b540aSrobert       if (arg)
336*404b540aSrobert 	return compute_builtin_object_size (arg, object_size_type);
337*404b540aSrobert       else
338*404b540aSrobert 	return alloc_object_size (ptr, object_size_type);
339*404b540aSrobert     }
340*404b540aSrobert   else if (TREE_CODE (ptr) == SSA_NAME
341*404b540aSrobert 	   && POINTER_TYPE_P (TREE_TYPE (ptr))
342*404b540aSrobert 	   && object_sizes[object_size_type] != NULL)
343*404b540aSrobert     {
344*404b540aSrobert       if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
345*404b540aSrobert 	{
346*404b540aSrobert 	  struct object_size_info osi;
347*404b540aSrobert 	  bitmap_iterator bi;
348*404b540aSrobert 	  unsigned int i;
349*404b540aSrobert 
350*404b540aSrobert 	  if (dump_file)
351*404b540aSrobert 	    {
352*404b540aSrobert 	      fprintf (dump_file, "Computing %s %sobject size for ",
353*404b540aSrobert 		       (object_size_type & 2) ? "minimum" : "maximum",
354*404b540aSrobert 		       (object_size_type & 1) ? "sub" : "");
355*404b540aSrobert 	      print_generic_expr (dump_file, ptr, dump_flags);
356*404b540aSrobert 	      fprintf (dump_file, ":\n");
357*404b540aSrobert 	    }
358*404b540aSrobert 
359*404b540aSrobert 	  osi.visited = BITMAP_ALLOC (NULL);
360*404b540aSrobert 	  osi.reexamine = BITMAP_ALLOC (NULL);
361*404b540aSrobert 	  osi.object_size_type = object_size_type;
362*404b540aSrobert 	  osi.depths = NULL;
363*404b540aSrobert 	  osi.stack = NULL;
364*404b540aSrobert 	  osi.tos = NULL;
365*404b540aSrobert 
366*404b540aSrobert 	  /* First pass: walk UD chains, compute object sizes that
367*404b540aSrobert 	     can be computed.  osi.reexamine bitmap at the end will
368*404b540aSrobert 	     contain what variables were found in dependency cycles
369*404b540aSrobert 	     and therefore need to be reexamined.  */
370*404b540aSrobert 	  osi.pass = 0;
371*404b540aSrobert 	  osi.changed = false;
372*404b540aSrobert 	  collect_object_sizes_for (&osi, ptr);
373*404b540aSrobert 
374*404b540aSrobert 	  /* Second pass: keep recomputing object sizes of variables
375*404b540aSrobert 	     that need reexamination, until no object sizes are
376*404b540aSrobert 	     increased or all object sizes are computed.  */
377*404b540aSrobert 	  if (! bitmap_empty_p (osi.reexamine))
378*404b540aSrobert 	    {
379*404b540aSrobert 	      bitmap reexamine = BITMAP_ALLOC (NULL);
380*404b540aSrobert 
381*404b540aSrobert 	      /* If looking for minimum instead of maximum object size,
382*404b540aSrobert 		 detect cases where a pointer is increased in a loop.
383*404b540aSrobert 		 Although even without this detection pass 2 would eventually
384*404b540aSrobert 		 terminate, it could take a long time.  If a pointer is
385*404b540aSrobert 		 increasing this way, we need to assume 0 object size.
386*404b540aSrobert 		 E.g. p = &buf[0]; while (cond) p = p + 4;  */
387*404b540aSrobert 	      if (object_size_type & 2)
388*404b540aSrobert 		{
389*404b540aSrobert 		  osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
390*404b540aSrobert 		  osi.stack = XNEWVEC (unsigned int, num_ssa_names);
391*404b540aSrobert 		  osi.tos = osi.stack;
392*404b540aSrobert 		  osi.pass = 1;
393*404b540aSrobert 		  /* collect_object_sizes_for is changing
394*404b540aSrobert 		     osi.reexamine bitmap, so iterate over a copy.  */
395*404b540aSrobert 		  bitmap_copy (reexamine, osi.reexamine);
396*404b540aSrobert 		  EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
397*404b540aSrobert 		    if (bitmap_bit_p (osi.reexamine, i))
398*404b540aSrobert 		      check_for_plus_in_loops (&osi, ssa_name (i));
399*404b540aSrobert 
400*404b540aSrobert 		  free (osi.depths);
401*404b540aSrobert 		  osi.depths = NULL;
402*404b540aSrobert 		  free (osi.stack);
403*404b540aSrobert 		  osi.stack = NULL;
404*404b540aSrobert 		  osi.tos = NULL;
405*404b540aSrobert 		}
406*404b540aSrobert 
407*404b540aSrobert 	      do
408*404b540aSrobert 		{
409*404b540aSrobert 		  osi.pass = 2;
410*404b540aSrobert 		  osi.changed = false;
411*404b540aSrobert 		  /* collect_object_sizes_for is changing
412*404b540aSrobert 		     osi.reexamine bitmap, so iterate over a copy.  */
413*404b540aSrobert 		  bitmap_copy (reexamine, osi.reexamine);
414*404b540aSrobert 		  EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
415*404b540aSrobert 		    if (bitmap_bit_p (osi.reexamine, i))
416*404b540aSrobert 		      {
417*404b540aSrobert 			collect_object_sizes_for (&osi, ssa_name (i));
418*404b540aSrobert 			if (dump_file && (dump_flags & TDF_DETAILS))
419*404b540aSrobert 			  {
420*404b540aSrobert 			    fprintf (dump_file, "Reexamining ");
421*404b540aSrobert 			    print_generic_expr (dump_file, ssa_name (i),
422*404b540aSrobert 						dump_flags);
423*404b540aSrobert 			    fprintf (dump_file, "\n");
424*404b540aSrobert 			  }
425*404b540aSrobert 		      }
426*404b540aSrobert 		}
427*404b540aSrobert 	      while (osi.changed);
428*404b540aSrobert 
429*404b540aSrobert 	      BITMAP_FREE (reexamine);
430*404b540aSrobert 	    }
431*404b540aSrobert 	  EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
432*404b540aSrobert 	    bitmap_set_bit (computed[object_size_type], i);
433*404b540aSrobert 
434*404b540aSrobert 	  /* Debugging dumps.  */
435*404b540aSrobert 	  if (dump_file)
436*404b540aSrobert 	    {
437*404b540aSrobert 	      EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
438*404b540aSrobert 		if (object_sizes[object_size_type][i]
439*404b540aSrobert 		    != unknown[object_size_type])
440*404b540aSrobert 		  {
441*404b540aSrobert 		    print_generic_expr (dump_file, ssa_name (i),
442*404b540aSrobert 					dump_flags);
443*404b540aSrobert 		    fprintf (dump_file,
444*404b540aSrobert 			     ": %s %sobject size "
445*404b540aSrobert 			     HOST_WIDE_INT_PRINT_UNSIGNED "\n",
446*404b540aSrobert 			     (object_size_type & 2) ? "minimum" : "maximum",
447*404b540aSrobert 			     (object_size_type & 1) ? "sub" : "",
448*404b540aSrobert 			     object_sizes[object_size_type][i]);
449*404b540aSrobert 		  }
450*404b540aSrobert 	    }
451*404b540aSrobert 
452*404b540aSrobert 	  BITMAP_FREE (osi.reexamine);
453*404b540aSrobert 	  BITMAP_FREE (osi.visited);
454*404b540aSrobert 	}
455*404b540aSrobert 
456*404b540aSrobert       return object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
457*404b540aSrobert     }
458*404b540aSrobert 
459*404b540aSrobert   return unknown[object_size_type];
460*404b540aSrobert }
461*404b540aSrobert 
462*404b540aSrobert 
463*404b540aSrobert /* Compute object_sizes for PTR, defined to VALUE, which is not
464*404b540aSrobert    a SSA_NAME.  */
465*404b540aSrobert 
466*404b540aSrobert static void
expr_object_size(struct object_size_info * osi,tree ptr,tree value)467*404b540aSrobert expr_object_size (struct object_size_info *osi, tree ptr, tree value)
468*404b540aSrobert {
469*404b540aSrobert   int object_size_type = osi->object_size_type;
470*404b540aSrobert   unsigned int varno = SSA_NAME_VERSION (ptr);
471*404b540aSrobert   unsigned HOST_WIDE_INT bytes;
472*404b540aSrobert 
473*404b540aSrobert   gcc_assert (object_sizes[object_size_type][varno]
474*404b540aSrobert 	      != unknown[object_size_type]);
475*404b540aSrobert   gcc_assert (osi->pass == 0);
476*404b540aSrobert 
477*404b540aSrobert   if (TREE_CODE (value) == WITH_SIZE_EXPR)
478*404b540aSrobert     value = TREE_OPERAND (value, 0);
479*404b540aSrobert 
480*404b540aSrobert   /* Pointer variables should have been handled by merge_object_sizes.  */
481*404b540aSrobert   gcc_assert (TREE_CODE (value) != SSA_NAME
482*404b540aSrobert 	      || !POINTER_TYPE_P (TREE_TYPE (value)));
483*404b540aSrobert 
484*404b540aSrobert   if (TREE_CODE (value) == ADDR_EXPR)
485*404b540aSrobert     bytes = addr_object_size (value, object_size_type);
486*404b540aSrobert   else if (TREE_CODE (value) == CALL_EXPR)
487*404b540aSrobert     bytes = alloc_object_size (value, object_size_type);
488*404b540aSrobert   else
489*404b540aSrobert     bytes = unknown[object_size_type];
490*404b540aSrobert 
491*404b540aSrobert   if ((object_size_type & 2) == 0)
492*404b540aSrobert     {
493*404b540aSrobert       if (object_sizes[object_size_type][varno] < bytes)
494*404b540aSrobert 	object_sizes[object_size_type][varno] = bytes;
495*404b540aSrobert     }
496*404b540aSrobert   else
497*404b540aSrobert     {
498*404b540aSrobert       if (object_sizes[object_size_type][varno] > bytes)
499*404b540aSrobert 	object_sizes[object_size_type][varno] = bytes;
500*404b540aSrobert     }
501*404b540aSrobert }
502*404b540aSrobert 
503*404b540aSrobert 
504*404b540aSrobert /* Merge object sizes of ORIG + OFFSET into DEST.  Return true if
505*404b540aSrobert    the object size might need reexamination later.  */
506*404b540aSrobert 
507*404b540aSrobert static bool
merge_object_sizes(struct object_size_info * osi,tree dest,tree orig,unsigned HOST_WIDE_INT offset)508*404b540aSrobert merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
509*404b540aSrobert 		    unsigned HOST_WIDE_INT offset)
510*404b540aSrobert {
511*404b540aSrobert   int object_size_type = osi->object_size_type;
512*404b540aSrobert   unsigned int varno = SSA_NAME_VERSION (dest);
513*404b540aSrobert   unsigned HOST_WIDE_INT orig_bytes;
514*404b540aSrobert 
515*404b540aSrobert   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
516*404b540aSrobert     return false;
517*404b540aSrobert   if (offset >= offset_limit)
518*404b540aSrobert     {
519*404b540aSrobert       object_sizes[object_size_type][varno] = unknown[object_size_type];
520*404b540aSrobert       return false;
521*404b540aSrobert     }
522*404b540aSrobert 
523*404b540aSrobert   if (osi->pass == 0)
524*404b540aSrobert     collect_object_sizes_for (osi, orig);
525*404b540aSrobert 
526*404b540aSrobert   orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
527*404b540aSrobert   if (orig_bytes != unknown[object_size_type])
528*404b540aSrobert     orig_bytes = (offset > orig_bytes)
529*404b540aSrobert 		 ? (unsigned HOST_WIDE_INT) 0 : orig_bytes - offset;
530*404b540aSrobert 
531*404b540aSrobert   if ((object_size_type & 2) == 0)
532*404b540aSrobert     {
533*404b540aSrobert       if (object_sizes[object_size_type][varno] < orig_bytes)
534*404b540aSrobert 	{
535*404b540aSrobert 	  object_sizes[object_size_type][varno] = orig_bytes;
536*404b540aSrobert 	  osi->changed = true;
537*404b540aSrobert 	}
538*404b540aSrobert     }
539*404b540aSrobert   else
540*404b540aSrobert     {
541*404b540aSrobert       if (object_sizes[object_size_type][varno] > orig_bytes)
542*404b540aSrobert 	{
543*404b540aSrobert 	  object_sizes[object_size_type][varno] = orig_bytes;
544*404b540aSrobert 	  osi->changed = true;
545*404b540aSrobert 	}
546*404b540aSrobert     }
547*404b540aSrobert   return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
548*404b540aSrobert }
549*404b540aSrobert 
550*404b540aSrobert 
551*404b540aSrobert /* Compute object_sizes for PTR, defined to VALUE, which is
552*404b540aSrobert    a PLUS_EXPR.  Return true if the object size might need reexamination
553*404b540aSrobert    later.  */
554*404b540aSrobert 
555*404b540aSrobert static bool
plus_expr_object_size(struct object_size_info * osi,tree var,tree value)556*404b540aSrobert plus_expr_object_size (struct object_size_info *osi, tree var, tree value)
557*404b540aSrobert {
558*404b540aSrobert   tree op0 = TREE_OPERAND (value, 0);
559*404b540aSrobert   tree op1 = TREE_OPERAND (value, 1);
560*404b540aSrobert   bool ptr1_p = POINTER_TYPE_P (TREE_TYPE (op0))
561*404b540aSrobert 		&& TREE_CODE (op0) != INTEGER_CST;
562*404b540aSrobert   bool ptr2_p = POINTER_TYPE_P (TREE_TYPE (op1))
563*404b540aSrobert 		&& TREE_CODE (op1) != INTEGER_CST;
564*404b540aSrobert   int object_size_type = osi->object_size_type;
565*404b540aSrobert   unsigned int varno = SSA_NAME_VERSION (var);
566*404b540aSrobert   unsigned HOST_WIDE_INT bytes;
567*404b540aSrobert 
568*404b540aSrobert   gcc_assert (TREE_CODE (value) == PLUS_EXPR);
569*404b540aSrobert 
570*404b540aSrobert   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
571*404b540aSrobert     return false;
572*404b540aSrobert 
573*404b540aSrobert   /* Swap operands if needed.  */
574*404b540aSrobert   if (ptr2_p && !ptr1_p)
575*404b540aSrobert     {
576*404b540aSrobert       tree tem = op0;
577*404b540aSrobert       op0 = op1;
578*404b540aSrobert       op1 = tem;
579*404b540aSrobert       ptr1_p = true;
580*404b540aSrobert       ptr2_p = false;
581*404b540aSrobert     }
582*404b540aSrobert 
583*404b540aSrobert   /* Handle PTR + OFFSET here.  */
584*404b540aSrobert   if (ptr1_p
585*404b540aSrobert       && !ptr2_p
586*404b540aSrobert       && TREE_CODE (op1) == INTEGER_CST
587*404b540aSrobert       && (TREE_CODE (op0) == SSA_NAME
588*404b540aSrobert 	  || TREE_CODE (op0) == ADDR_EXPR))
589*404b540aSrobert     {
590*404b540aSrobert       if (! host_integerp (op1, 1))
591*404b540aSrobert 	bytes = unknown[object_size_type];
592*404b540aSrobert       else if (TREE_CODE (op0) == SSA_NAME)
593*404b540aSrobert 	return merge_object_sizes (osi, var, op0, tree_low_cst (op1, 1));
594*404b540aSrobert       else
595*404b540aSrobert 	{
596*404b540aSrobert 	  unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);
597*404b540aSrobert 
598*404b540aSrobert 	  bytes = compute_builtin_object_size (op0, object_size_type);
599*404b540aSrobert 	  if (off > offset_limit)
600*404b540aSrobert 	    bytes = unknown[object_size_type];
601*404b540aSrobert 	  else if (off > bytes)
602*404b540aSrobert 	    bytes = 0;
603*404b540aSrobert 	  else
604*404b540aSrobert 	    bytes -= off;
605*404b540aSrobert 	}
606*404b540aSrobert     }
607*404b540aSrobert   else
608*404b540aSrobert     bytes = unknown[object_size_type];
609*404b540aSrobert 
610*404b540aSrobert   if ((object_size_type & 2) == 0)
611*404b540aSrobert     {
612*404b540aSrobert       if (object_sizes[object_size_type][varno] < bytes)
613*404b540aSrobert 	object_sizes[object_size_type][varno] = bytes;
614*404b540aSrobert     }
615*404b540aSrobert   else
616*404b540aSrobert     {
617*404b540aSrobert       if (object_sizes[object_size_type][varno] > bytes)
618*404b540aSrobert 	object_sizes[object_size_type][varno] = bytes;
619*404b540aSrobert     }
620*404b540aSrobert   return false;
621*404b540aSrobert }
622*404b540aSrobert 
623*404b540aSrobert 
624*404b540aSrobert /* Compute object sizes for VAR.
625*404b540aSrobert    For ADDR_EXPR an object size is the number of remaining bytes
626*404b540aSrobert    to the end of the object (where what is considered an object depends on
627*404b540aSrobert    OSI->object_size_type).
628*404b540aSrobert    For allocation CALL_EXPR like malloc or calloc object size is the size
629*404b540aSrobert    of the allocation.
630*404b540aSrobert    For pointer PLUS_EXPR where second operand is a constant integer,
631*404b540aSrobert    object size is object size of the first operand minus the constant.
632*404b540aSrobert    If the constant is bigger than the number of remaining bytes until the
633*404b540aSrobert    end of the object, object size is 0, but if it is instead a pointer
634*404b540aSrobert    subtraction, object size is unknown[object_size_type].
635*404b540aSrobert    To differentiate addition from subtraction, ADDR_EXPR returns
636*404b540aSrobert    unknown[object_size_type] for all objects bigger than half of the address
637*404b540aSrobert    space, and constants less than half of the address space are considered
638*404b540aSrobert    addition, while bigger constants subtraction.
639*404b540aSrobert    For a memcpy like CALL_EXPR that always returns one of its arguments, the
640*404b540aSrobert    object size is object size of that argument.
641*404b540aSrobert    Otherwise, object size is the maximum of object sizes of variables
642*404b540aSrobert    that it might be set to.  */
643*404b540aSrobert 
644*404b540aSrobert static void
collect_object_sizes_for(struct object_size_info * osi,tree var)645*404b540aSrobert collect_object_sizes_for (struct object_size_info *osi, tree var)
646*404b540aSrobert {
647*404b540aSrobert   int object_size_type = osi->object_size_type;
648*404b540aSrobert   unsigned int varno = SSA_NAME_VERSION (var);
649*404b540aSrobert   tree stmt;
650*404b540aSrobert   bool reexamine;
651*404b540aSrobert 
652*404b540aSrobert   if (bitmap_bit_p (computed[object_size_type], varno))
653*404b540aSrobert     return;
654*404b540aSrobert 
655*404b540aSrobert   if (osi->pass == 0)
656*404b540aSrobert     {
657*404b540aSrobert       if (! bitmap_bit_p (osi->visited, varno))
658*404b540aSrobert 	{
659*404b540aSrobert 	  bitmap_set_bit (osi->visited, varno);
660*404b540aSrobert 	  object_sizes[object_size_type][varno]
661*404b540aSrobert 	    = (object_size_type & 2) ? -1 : 0;
662*404b540aSrobert 	}
663*404b540aSrobert       else
664*404b540aSrobert 	{
665*404b540aSrobert 	  /* Found a dependency loop.  Mark the variable for later
666*404b540aSrobert 	     re-examination.  */
667*404b540aSrobert 	  bitmap_set_bit (osi->reexamine, varno);
668*404b540aSrobert 	  if (dump_file && (dump_flags & TDF_DETAILS))
669*404b540aSrobert 	    {
670*404b540aSrobert 	      fprintf (dump_file, "Found a dependency loop at ");
671*404b540aSrobert 	      print_generic_expr (dump_file, var, dump_flags);
672*404b540aSrobert 	      fprintf (dump_file, "\n");
673*404b540aSrobert 	    }
674*404b540aSrobert 	  return;
675*404b540aSrobert 	}
676*404b540aSrobert     }
677*404b540aSrobert 
678*404b540aSrobert   if (dump_file && (dump_flags & TDF_DETAILS))
679*404b540aSrobert     {
680*404b540aSrobert       fprintf (dump_file, "Visiting use-def links for ");
681*404b540aSrobert       print_generic_expr (dump_file, var, dump_flags);
682*404b540aSrobert       fprintf (dump_file, "\n");
683*404b540aSrobert     }
684*404b540aSrobert 
685*404b540aSrobert   stmt = SSA_NAME_DEF_STMT (var);
686*404b540aSrobert   reexamine = false;
687*404b540aSrobert 
688*404b540aSrobert   switch (TREE_CODE (stmt))
689*404b540aSrobert     {
690*404b540aSrobert     case RETURN_EXPR:
691*404b540aSrobert       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
692*404b540aSrobert       stmt = TREE_OPERAND (stmt, 0);
693*404b540aSrobert       /* FALLTHRU  */
694*404b540aSrobert 
695*404b540aSrobert     case MODIFY_EXPR:
696*404b540aSrobert       {
697*404b540aSrobert 	tree rhs = TREE_OPERAND (stmt, 1), arg;
698*404b540aSrobert 	STRIP_NOPS (rhs);
699*404b540aSrobert 
700*404b540aSrobert 	if (TREE_CODE (rhs) == CALL_EXPR)
701*404b540aSrobert 	  {
702*404b540aSrobert 	    arg = pass_through_call (rhs);
703*404b540aSrobert 	    if (arg)
704*404b540aSrobert 	      rhs = arg;
705*404b540aSrobert 	  }
706*404b540aSrobert 
707*404b540aSrobert 	if (TREE_CODE (rhs) == SSA_NAME
708*404b540aSrobert 	    && POINTER_TYPE_P (TREE_TYPE (rhs)))
709*404b540aSrobert 	  reexamine = merge_object_sizes (osi, var, rhs, 0);
710*404b540aSrobert 
711*404b540aSrobert 	else if (TREE_CODE (rhs) == PLUS_EXPR)
712*404b540aSrobert 	  reexamine = plus_expr_object_size (osi, var, rhs);
713*404b540aSrobert 
714*404b540aSrobert 	else
715*404b540aSrobert 	  expr_object_size (osi, var, rhs);
716*404b540aSrobert 	break;
717*404b540aSrobert       }
718*404b540aSrobert 
719*404b540aSrobert     case ASM_EXPR:
720*404b540aSrobert       /* Pointers defined by __asm__ statements can point anywhere.  */
721*404b540aSrobert       object_sizes[object_size_type][varno] = unknown[object_size_type];
722*404b540aSrobert       break;
723*404b540aSrobert 
724*404b540aSrobert     case NOP_EXPR:
725*404b540aSrobert       {
726*404b540aSrobert 	tree decl = SSA_NAME_VAR (var);
727*404b540aSrobert 
728*404b540aSrobert 	gcc_assert (IS_EMPTY_STMT (stmt));
729*404b540aSrobert 
730*404b540aSrobert 	if (TREE_CODE (decl) != PARM_DECL && DECL_INITIAL (decl))
731*404b540aSrobert 	  expr_object_size (osi, var, DECL_INITIAL (decl));
732*404b540aSrobert 	else
733*404b540aSrobert 	  expr_object_size (osi, var, decl);
734*404b540aSrobert       }
735*404b540aSrobert       break;
736*404b540aSrobert 
737*404b540aSrobert     case PHI_NODE:
738*404b540aSrobert       {
739*404b540aSrobert 	int i;
740*404b540aSrobert 
741*404b540aSrobert 	for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
742*404b540aSrobert 	  {
743*404b540aSrobert 	    tree rhs = PHI_ARG_DEF (stmt, i);
744*404b540aSrobert 
745*404b540aSrobert 	    if (object_sizes[object_size_type][varno]
746*404b540aSrobert 		== unknown[object_size_type])
747*404b540aSrobert 	      break;
748*404b540aSrobert 
749*404b540aSrobert 	    if (TREE_CODE (rhs) == SSA_NAME)
750*404b540aSrobert 	      reexamine |= merge_object_sizes (osi, var, rhs, 0);
751*404b540aSrobert 	    else if (osi->pass == 0)
752*404b540aSrobert 	      expr_object_size (osi, var, rhs);
753*404b540aSrobert 	  }
754*404b540aSrobert 	break;
755*404b540aSrobert       }
756*404b540aSrobert     default:
757*404b540aSrobert       gcc_unreachable ();
758*404b540aSrobert     }
759*404b540aSrobert 
760*404b540aSrobert   if (! reexamine
761*404b540aSrobert       || object_sizes[object_size_type][varno] == unknown[object_size_type])
762*404b540aSrobert     {
763*404b540aSrobert       bitmap_set_bit (computed[object_size_type], varno);
764*404b540aSrobert       bitmap_clear_bit (osi->reexamine, varno);
765*404b540aSrobert     }
766*404b540aSrobert   else
767*404b540aSrobert     {
768*404b540aSrobert       bitmap_set_bit (osi->reexamine, varno);
769*404b540aSrobert       if (dump_file && (dump_flags & TDF_DETAILS))
770*404b540aSrobert 	{
771*404b540aSrobert 	  fprintf (dump_file, "Need to reexamine ");
772*404b540aSrobert 	  print_generic_expr (dump_file, var, dump_flags);
773*404b540aSrobert 	  fprintf (dump_file, "\n");
774*404b540aSrobert 	}
775*404b540aSrobert     }
776*404b540aSrobert }
777*404b540aSrobert 
778*404b540aSrobert 
779*404b540aSrobert /* Helper function for check_for_plus_in_loops.  Called recursively
780*404b540aSrobert    to detect loops.  */
781*404b540aSrobert 
782*404b540aSrobert static void
check_for_plus_in_loops_1(struct object_size_info * osi,tree var,unsigned int depth)783*404b540aSrobert check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
784*404b540aSrobert 			   unsigned int depth)
785*404b540aSrobert {
786*404b540aSrobert   tree stmt = SSA_NAME_DEF_STMT (var);
787*404b540aSrobert   unsigned int varno = SSA_NAME_VERSION (var);
788*404b540aSrobert 
789*404b540aSrobert   if (osi->depths[varno])
790*404b540aSrobert     {
791*404b540aSrobert       if (osi->depths[varno] != depth)
792*404b540aSrobert 	{
793*404b540aSrobert 	  unsigned int *sp;
794*404b540aSrobert 
795*404b540aSrobert 	  /* Found a loop involving pointer addition.  */
796*404b540aSrobert 	  for (sp = osi->tos; sp > osi->stack; )
797*404b540aSrobert 	    {
798*404b540aSrobert 	      --sp;
799*404b540aSrobert 	      bitmap_clear_bit (osi->reexamine, *sp);
800*404b540aSrobert 	      bitmap_set_bit (computed[osi->object_size_type], *sp);
801*404b540aSrobert 	      object_sizes[osi->object_size_type][*sp] = 0;
802*404b540aSrobert 	      if (*sp == varno)
803*404b540aSrobert 		break;
804*404b540aSrobert 	    }
805*404b540aSrobert 	}
806*404b540aSrobert       return;
807*404b540aSrobert     }
808*404b540aSrobert   else if (! bitmap_bit_p (osi->reexamine, varno))
809*404b540aSrobert     return;
810*404b540aSrobert 
811*404b540aSrobert   osi->depths[varno] = depth;
812*404b540aSrobert   *osi->tos++ = varno;
813*404b540aSrobert 
814*404b540aSrobert   switch (TREE_CODE (stmt))
815*404b540aSrobert     {
816*404b540aSrobert     case RETURN_EXPR:
817*404b540aSrobert       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
818*404b540aSrobert       stmt = TREE_OPERAND (stmt, 0);
819*404b540aSrobert       /* FALLTHRU  */
820*404b540aSrobert 
821*404b540aSrobert     case MODIFY_EXPR:
822*404b540aSrobert       {
823*404b540aSrobert 	tree rhs = TREE_OPERAND (stmt, 1), arg;
824*404b540aSrobert 	STRIP_NOPS (rhs);
825*404b540aSrobert 
826*404b540aSrobert 	if (TREE_CODE (rhs) == CALL_EXPR)
827*404b540aSrobert 	  {
828*404b540aSrobert 	    arg = pass_through_call (rhs);
829*404b540aSrobert 	    if (arg)
830*404b540aSrobert 	      rhs = arg;
831*404b540aSrobert 	  }
832*404b540aSrobert 
833*404b540aSrobert 	if (TREE_CODE (rhs) == SSA_NAME)
834*404b540aSrobert 	  check_for_plus_in_loops_1 (osi, rhs, depth);
835*404b540aSrobert 	else if (TREE_CODE (rhs) == PLUS_EXPR)
836*404b540aSrobert 	  {
837*404b540aSrobert 	    tree op0 = TREE_OPERAND (rhs, 0);
838*404b540aSrobert 	    tree op1 = TREE_OPERAND (rhs, 1);
839*404b540aSrobert 	    tree cst, basevar;
840*404b540aSrobert 
841*404b540aSrobert 	    if (TREE_CODE (op0) == SSA_NAME)
842*404b540aSrobert 	      {
843*404b540aSrobert 		basevar = op0;
844*404b540aSrobert 		cst = op1;
845*404b540aSrobert 	      }
846*404b540aSrobert 	    else
847*404b540aSrobert 	      {
848*404b540aSrobert 		basevar = op1;
849*404b540aSrobert 		cst = op0;
850*404b540aSrobert 		gcc_assert (TREE_CODE (basevar) == SSA_NAME);
851*404b540aSrobert 	      }
852*404b540aSrobert 	    gcc_assert (TREE_CODE (cst) == INTEGER_CST);
853*404b540aSrobert 
854*404b540aSrobert 	    check_for_plus_in_loops_1 (osi, basevar,
855*404b540aSrobert 				       depth + !integer_zerop (cst));
856*404b540aSrobert 	  }
857*404b540aSrobert 	else
858*404b540aSrobert 	  gcc_unreachable ();
859*404b540aSrobert 	break;
860*404b540aSrobert       }
861*404b540aSrobert     case PHI_NODE:
862*404b540aSrobert       {
863*404b540aSrobert 	int i;
864*404b540aSrobert 
865*404b540aSrobert 	for (i = 0; i < PHI_NUM_ARGS (stmt); i++)
866*404b540aSrobert 	  {
867*404b540aSrobert 	    tree rhs = PHI_ARG_DEF (stmt, i);
868*404b540aSrobert 
869*404b540aSrobert 	    if (TREE_CODE (rhs) == SSA_NAME)
870*404b540aSrobert 	      check_for_plus_in_loops_1 (osi, rhs, depth);
871*404b540aSrobert 	  }
872*404b540aSrobert 	break;
873*404b540aSrobert       }
874*404b540aSrobert     default:
875*404b540aSrobert       gcc_unreachable ();
876*404b540aSrobert     }
877*404b540aSrobert 
878*404b540aSrobert   osi->depths[varno] = 0;
879*404b540aSrobert   osi->tos--;
880*404b540aSrobert }
881*404b540aSrobert 
882*404b540aSrobert 
883*404b540aSrobert /* Check if some pointer we are computing object size of is being increased
884*404b540aSrobert    within a loop.  If yes, assume all the SSA variables participating in
885*404b540aSrobert    that loop have minimum object sizes 0.  */
886*404b540aSrobert 
887*404b540aSrobert static void
check_for_plus_in_loops(struct object_size_info * osi,tree var)888*404b540aSrobert check_for_plus_in_loops (struct object_size_info *osi, tree var)
889*404b540aSrobert {
890*404b540aSrobert   tree stmt = SSA_NAME_DEF_STMT (var);
891*404b540aSrobert 
892*404b540aSrobert   switch (TREE_CODE (stmt))
893*404b540aSrobert     {
894*404b540aSrobert     case RETURN_EXPR:
895*404b540aSrobert       gcc_assert (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR);
896*404b540aSrobert       stmt = TREE_OPERAND (stmt, 0);
897*404b540aSrobert       /* FALLTHRU  */
898*404b540aSrobert 
899*404b540aSrobert     case MODIFY_EXPR:
900*404b540aSrobert       {
901*404b540aSrobert 	tree rhs = TREE_OPERAND (stmt, 1), arg;
902*404b540aSrobert 	STRIP_NOPS (rhs);
903*404b540aSrobert 
904*404b540aSrobert 	if (TREE_CODE (rhs) == CALL_EXPR)
905*404b540aSrobert 	  {
906*404b540aSrobert 	    arg = pass_through_call (rhs);
907*404b540aSrobert 	    if (arg)
908*404b540aSrobert 	      rhs = arg;
909*404b540aSrobert 	  }
910*404b540aSrobert 
911*404b540aSrobert 	if (TREE_CODE (rhs) == PLUS_EXPR)
912*404b540aSrobert 	  {
913*404b540aSrobert 	    tree op0 = TREE_OPERAND (rhs, 0);
914*404b540aSrobert 	    tree op1 = TREE_OPERAND (rhs, 1);
915*404b540aSrobert 	    tree cst, basevar;
916*404b540aSrobert 
917*404b540aSrobert 	    if (TREE_CODE (op0) == SSA_NAME)
918*404b540aSrobert 	      {
919*404b540aSrobert 		basevar = op0;
920*404b540aSrobert 		cst = op1;
921*404b540aSrobert 	      }
922*404b540aSrobert 	    else
923*404b540aSrobert 	      {
924*404b540aSrobert 		basevar = op1;
925*404b540aSrobert 		cst = op0;
926*404b540aSrobert 		gcc_assert (TREE_CODE (basevar) == SSA_NAME);
927*404b540aSrobert 	      }
928*404b540aSrobert 	    gcc_assert (TREE_CODE (cst) == INTEGER_CST);
929*404b540aSrobert 
930*404b540aSrobert 	    if (integer_zerop (cst))
931*404b540aSrobert 	      break;
932*404b540aSrobert 
933*404b540aSrobert 	    osi->depths[SSA_NAME_VERSION (basevar)] = 1;
934*404b540aSrobert 	    *osi->tos++ = SSA_NAME_VERSION (basevar);
935*404b540aSrobert 	    check_for_plus_in_loops_1 (osi, var, 2);
936*404b540aSrobert 	    osi->depths[SSA_NAME_VERSION (basevar)] = 0;
937*404b540aSrobert 	    osi->tos--;
938*404b540aSrobert 	  }
939*404b540aSrobert 	break;
940*404b540aSrobert       }
941*404b540aSrobert     default:
942*404b540aSrobert       break;
943*404b540aSrobert     }
944*404b540aSrobert }
945*404b540aSrobert 
946*404b540aSrobert 
947*404b540aSrobert /* Initialize data structures for the object size computation.  */
948*404b540aSrobert 
949*404b540aSrobert void
init_object_sizes(void)950*404b540aSrobert init_object_sizes (void)
951*404b540aSrobert {
952*404b540aSrobert   int object_size_type;
953*404b540aSrobert 
954*404b540aSrobert   if (object_sizes[0])
955*404b540aSrobert     return;
956*404b540aSrobert 
957*404b540aSrobert   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
958*404b540aSrobert     {
959*404b540aSrobert       object_sizes[object_size_type] = XNEWVEC (unsigned HOST_WIDE_INT, num_ssa_names);
960*404b540aSrobert       computed[object_size_type] = BITMAP_ALLOC (NULL);
961*404b540aSrobert     }
962*404b540aSrobert 
963*404b540aSrobert   init_offset_limit ();
964*404b540aSrobert }
965*404b540aSrobert 
966*404b540aSrobert 
967*404b540aSrobert /* Destroy data structures after the object size computation.  */
968*404b540aSrobert 
969*404b540aSrobert void
fini_object_sizes(void)970*404b540aSrobert fini_object_sizes (void)
971*404b540aSrobert {
972*404b540aSrobert   int object_size_type;
973*404b540aSrobert 
974*404b540aSrobert   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
975*404b540aSrobert     {
976*404b540aSrobert       free (object_sizes[object_size_type]);
977*404b540aSrobert       BITMAP_FREE (computed[object_size_type]);
978*404b540aSrobert       object_sizes[object_size_type] = NULL;
979*404b540aSrobert     }
980*404b540aSrobert }
981*404b540aSrobert 
982*404b540aSrobert 
983*404b540aSrobert /* Simple pass to optimize all __builtin_object_size () builtins.  */
984*404b540aSrobert 
985*404b540aSrobert static unsigned int
compute_object_sizes(void)986*404b540aSrobert compute_object_sizes (void)
987*404b540aSrobert {
988*404b540aSrobert   basic_block bb;
989*404b540aSrobert   FOR_EACH_BB (bb)
990*404b540aSrobert     {
991*404b540aSrobert       block_stmt_iterator i;
992*404b540aSrobert       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
993*404b540aSrobert 	{
994*404b540aSrobert 	  tree *stmtp = bsi_stmt_ptr (i);
995*404b540aSrobert 	  tree call = get_rhs (*stmtp);
996*404b540aSrobert 	  tree callee, result;
997*404b540aSrobert 
998*404b540aSrobert 	  if (!call || TREE_CODE (call) != CALL_EXPR)
999*404b540aSrobert 	    continue;
1000*404b540aSrobert 
1001*404b540aSrobert 	  callee = get_callee_fndecl (call);
1002*404b540aSrobert 	  if (!callee
1003*404b540aSrobert 	      || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
1004*404b540aSrobert 	      || DECL_FUNCTION_CODE (callee) != BUILT_IN_OBJECT_SIZE)
1005*404b540aSrobert 	    continue;
1006*404b540aSrobert 
1007*404b540aSrobert 	  init_object_sizes ();
1008*404b540aSrobert 	  result = fold_builtin (callee, TREE_OPERAND (call, 1), false);
1009*404b540aSrobert 	  if (!result)
1010*404b540aSrobert 	    {
1011*404b540aSrobert 	      tree arglist = TREE_OPERAND (call, 1);
1012*404b540aSrobert 
1013*404b540aSrobert 	      if (arglist != NULL
1014*404b540aSrobert 		  && POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
1015*404b540aSrobert 		  && TREE_CHAIN (arglist) != NULL
1016*404b540aSrobert 		  && TREE_CHAIN (TREE_CHAIN (arglist)) == NULL)
1017*404b540aSrobert 		{
1018*404b540aSrobert 		  tree ost = TREE_VALUE (TREE_CHAIN (arglist));
1019*404b540aSrobert 
1020*404b540aSrobert 		  if (host_integerp (ost, 1))
1021*404b540aSrobert 		    {
1022*404b540aSrobert 		      unsigned HOST_WIDE_INT object_size_type
1023*404b540aSrobert 			= tree_low_cst (ost, 1);
1024*404b540aSrobert 
1025*404b540aSrobert 		      if (object_size_type < 2)
1026*404b540aSrobert 			result = fold_convert (size_type_node,
1027*404b540aSrobert 					       integer_minus_one_node);
1028*404b540aSrobert 		      else if (object_size_type < 4)
1029*404b540aSrobert 			result = size_zero_node;
1030*404b540aSrobert 		    }
1031*404b540aSrobert 		}
1032*404b540aSrobert 
1033*404b540aSrobert 	      if (!result)
1034*404b540aSrobert 		continue;
1035*404b540aSrobert 	    }
1036*404b540aSrobert 
1037*404b540aSrobert 	  if (dump_file && (dump_flags & TDF_DETAILS))
1038*404b540aSrobert 	    {
1039*404b540aSrobert 	      fprintf (dump_file, "Simplified\n  ");
1040*404b540aSrobert 	      print_generic_stmt (dump_file, *stmtp, dump_flags);
1041*404b540aSrobert 	    }
1042*404b540aSrobert 
1043*404b540aSrobert 	  if (!set_rhs (stmtp, result))
1044*404b540aSrobert 	    gcc_unreachable ();
1045*404b540aSrobert 	  update_stmt (*stmtp);
1046*404b540aSrobert 
1047*404b540aSrobert 	  if (dump_file && (dump_flags & TDF_DETAILS))
1048*404b540aSrobert 	    {
1049*404b540aSrobert 	      fprintf (dump_file, "to\n  ");
1050*404b540aSrobert 	      print_generic_stmt (dump_file, *stmtp, dump_flags);
1051*404b540aSrobert 	      fprintf (dump_file, "\n");
1052*404b540aSrobert 	    }
1053*404b540aSrobert 	}
1054*404b540aSrobert     }
1055*404b540aSrobert 
1056*404b540aSrobert   fini_object_sizes ();
1057*404b540aSrobert   return 0;
1058*404b540aSrobert }
1059*404b540aSrobert 
1060*404b540aSrobert struct tree_opt_pass pass_object_sizes =
1061*404b540aSrobert {
1062*404b540aSrobert   "objsz",				/* name */
1063*404b540aSrobert   NULL,					/* gate */
1064*404b540aSrobert   compute_object_sizes,			/* execute */
1065*404b540aSrobert   NULL,					/* sub */
1066*404b540aSrobert   NULL,					/* next */
1067*404b540aSrobert   0,					/* static_pass_number */
1068*404b540aSrobert   0,					/* tv_id */
1069*404b540aSrobert   PROP_cfg | PROP_ssa | PROP_alias,	/* properties_required */
1070*404b540aSrobert   0,					/* properties_provided */
1071*404b540aSrobert   0,					/* properties_destroyed */
1072*404b540aSrobert   0,					/* todo_flags_start */
1073*404b540aSrobert   TODO_dump_func | TODO_verify_ssa,	/* todo_flags_finish */
1074*404b540aSrobert   0					/* letter */
1075*404b540aSrobert };
1076