1 /* __builtin_object_size (ptr, object_size_type) computation
2    Copyright (C) 2004-2018 Free Software Foundation, Inc.
3    Contributed by Jakub Jelinek <jakub@redhat.com>
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "tree.h"
26 #include "gimple.h"
27 #include "tree-pass.h"
28 #include "ssa.h"
29 #include "gimple-pretty-print.h"
30 #include "fold-const.h"
31 #include "tree-object-size.h"
32 #include "gimple-fold.h"
33 #include "gimple-iterator.h"
34 #include "tree-cfg.h"
35 #include "stringpool.h"
36 #include "attribs.h"
37 
38 struct object_size_info
39 {
40   int object_size_type;
41   unsigned char pass;
42   bool changed;
43   bitmap visited, reexamine;
44   unsigned int *depths;
45   unsigned int *stack, *tos;
46 };
47 
48 static const unsigned HOST_WIDE_INT unknown[4] = {
49   HOST_WIDE_INT_M1U,
50   HOST_WIDE_INT_M1U,
51   0,
52   0
53 };
54 
55 static tree compute_object_offset (const_tree, const_tree);
56 static bool addr_object_size (struct object_size_info *,
57 			      const_tree, int, unsigned HOST_WIDE_INT *);
58 static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int);
59 static tree pass_through_call (const gcall *);
60 static void collect_object_sizes_for (struct object_size_info *, tree);
61 static void expr_object_size (struct object_size_info *, tree, tree);
62 static bool merge_object_sizes (struct object_size_info *, tree, tree,
63 				unsigned HOST_WIDE_INT);
64 static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *);
65 static bool cond_expr_object_size (struct object_size_info *, tree, gimple *);
66 static void init_offset_limit (void);
67 static void check_for_plus_in_loops (struct object_size_info *, tree);
68 static void check_for_plus_in_loops_1 (struct object_size_info *, tree,
69 				       unsigned int);
70 
71 /* object_sizes[0] is upper bound for number of bytes till the end of
72    the object.
73    object_sizes[1] is upper bound for number of bytes till the end of
74    the subobject (innermost array or field with address taken).
75    object_sizes[2] is lower bound for number of bytes till the end of
76    the object and object_sizes[3] lower bound for subobject.  */
77 static vec<unsigned HOST_WIDE_INT> object_sizes[4];
78 
79 /* Bitmaps what object sizes have been computed already.  */
80 static bitmap computed[4];
81 
82 /* Maximum value of offset we consider to be addition.  */
83 static unsigned HOST_WIDE_INT offset_limit;
84 
85 
86 /* Initialize OFFSET_LIMIT variable.  */
87 static void
init_offset_limit(void)88 init_offset_limit (void)
89 {
90   if (tree_fits_uhwi_p (TYPE_MAX_VALUE (sizetype)))
91     offset_limit = tree_to_uhwi (TYPE_MAX_VALUE (sizetype));
92   else
93     offset_limit = -1;
94   offset_limit /= 2;
95 }
96 
97 
98 /* Compute offset of EXPR within VAR.  Return error_mark_node
99    if unknown.  */
100 
101 static tree
compute_object_offset(const_tree expr,const_tree var)102 compute_object_offset (const_tree expr, const_tree var)
103 {
104   enum tree_code code = PLUS_EXPR;
105   tree base, off, t;
106 
107   if (expr == var)
108     return size_zero_node;
109 
110   switch (TREE_CODE (expr))
111     {
112     case COMPONENT_REF:
113       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
114       if (base == error_mark_node)
115 	return base;
116 
117       t = TREE_OPERAND (expr, 1);
118       off = size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (t),
119 			size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
120 				  / BITS_PER_UNIT));
121       break;
122 
123     case REALPART_EXPR:
124     CASE_CONVERT:
125     case VIEW_CONVERT_EXPR:
126     case NON_LVALUE_EXPR:
127       return compute_object_offset (TREE_OPERAND (expr, 0), var);
128 
129     case IMAGPART_EXPR:
130       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
131       if (base == error_mark_node)
132 	return base;
133 
134       off = TYPE_SIZE_UNIT (TREE_TYPE (expr));
135       break;
136 
137     case ARRAY_REF:
138       base = compute_object_offset (TREE_OPERAND (expr, 0), var);
139       if (base == error_mark_node)
140 	return base;
141 
142       t = TREE_OPERAND (expr, 1);
143       tree low_bound, unit_size;
144       low_bound = array_ref_low_bound (CONST_CAST_TREE (expr));
145       unit_size = array_ref_element_size (CONST_CAST_TREE (expr));
146       if (! integer_zerop (low_bound))
147 	t = fold_build2 (MINUS_EXPR, TREE_TYPE (t), t, low_bound);
148       if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) < 0)
149 	{
150 	  code = MINUS_EXPR;
151 	  t = fold_build1 (NEGATE_EXPR, TREE_TYPE (t), t);
152 	}
153       t = fold_convert (sizetype, t);
154       off = size_binop (MULT_EXPR, unit_size, t);
155       break;
156 
157     case MEM_REF:
158       gcc_assert (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR);
159       return wide_int_to_tree (sizetype, mem_ref_offset (expr));
160 
161     default:
162       return error_mark_node;
163     }
164 
165   return size_binop (code, base, off);
166 }
167 
168 
169 /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
170    OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
171    If unknown, return unknown[object_size_type].  */
172 
173 static bool
addr_object_size(struct object_size_info * osi,const_tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize)174 addr_object_size (struct object_size_info *osi, const_tree ptr,
175 		  int object_size_type, unsigned HOST_WIDE_INT *psize)
176 {
177   tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
178 
179   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
180 
181   /* Set to unknown and overwrite just before returning if the size
182      could be determined.  */
183   *psize = unknown[object_size_type];
184 
185   pt_var = TREE_OPERAND (ptr, 0);
186   while (handled_component_p (pt_var))
187     pt_var = TREE_OPERAND (pt_var, 0);
188 
189   if (pt_var
190       && TREE_CODE (pt_var) == MEM_REF)
191     {
192       unsigned HOST_WIDE_INT sz;
193 
194       if (!osi || (object_size_type & 1) != 0
195 	  || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME)
196 	{
197 	  compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
198 				       object_size_type & ~1, &sz);
199 	}
200       else
201 	{
202 	  tree var = TREE_OPERAND (pt_var, 0);
203 	  if (osi->pass == 0)
204 	    collect_object_sizes_for (osi, var);
205 	  if (bitmap_bit_p (computed[object_size_type],
206 			    SSA_NAME_VERSION (var)))
207 	    sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)];
208 	  else
209 	    sz = unknown[object_size_type];
210 	}
211       if (sz != unknown[object_size_type])
212 	{
213 	  offset_int mem_offset;
214 	  if (mem_ref_offset (pt_var).is_constant (&mem_offset))
215 	    {
216 	      offset_int dsz = wi::sub (sz, mem_offset);
217 	      if (wi::neg_p (dsz))
218 		sz = 0;
219 	      else if (wi::fits_uhwi_p (dsz))
220 		sz = dsz.to_uhwi ();
221 	      else
222 		sz = unknown[object_size_type];
223 	    }
224 	  else
225 	    sz = unknown[object_size_type];
226 	}
227 
228       if (sz != unknown[object_size_type] && sz < offset_limit)
229 	pt_var_size = size_int (sz);
230     }
231   else if (pt_var
232 	   && DECL_P (pt_var)
233 	   && tree_fits_uhwi_p (DECL_SIZE_UNIT (pt_var))
234 	   && tree_to_uhwi (DECL_SIZE_UNIT (pt_var)) < offset_limit)
235     pt_var_size = DECL_SIZE_UNIT (pt_var);
236   else if (pt_var
237 	   && TREE_CODE (pt_var) == STRING_CST
238 	   && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
239 	   && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
240 	   && tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)))
241 	      < offset_limit)
242     pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
243   else
244     return false;
245 
246   if (pt_var != TREE_OPERAND (ptr, 0))
247     {
248       tree var;
249 
250       if (object_size_type & 1)
251 	{
252 	  var = TREE_OPERAND (ptr, 0);
253 
254 	  while (var != pt_var
255 		 && TREE_CODE (var) != BIT_FIELD_REF
256 		 && TREE_CODE (var) != COMPONENT_REF
257 		 && TREE_CODE (var) != ARRAY_REF
258 		 && TREE_CODE (var) != ARRAY_RANGE_REF
259 		 && TREE_CODE (var) != REALPART_EXPR
260 		 && TREE_CODE (var) != IMAGPART_EXPR)
261 	    var = TREE_OPERAND (var, 0);
262 	  if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
263 	    var = TREE_OPERAND (var, 0);
264 	  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
265 	      || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
266 	      || (pt_var_size
267 		  && tree_int_cst_lt (pt_var_size,
268 				      TYPE_SIZE_UNIT (TREE_TYPE (var)))))
269 	    var = pt_var;
270 	  else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
271 	    {
272 	      tree v = var;
273 	      /* For &X->fld, compute object size only if fld isn't the last
274 		 field, as struct { int i; char c[1]; } is often used instead
275 		 of flexible array member.  */
276 	      while (v && v != pt_var)
277 		switch (TREE_CODE (v))
278 		  {
279 		  case ARRAY_REF:
280 		    if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
281 			&& TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
282 		      {
283 			tree domain
284 			  = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
285 			if (domain
286 			    && TYPE_MAX_VALUE (domain)
287 			    && TREE_CODE (TYPE_MAX_VALUE (domain))
288 			       == INTEGER_CST
289 			    && tree_int_cst_lt (TREE_OPERAND (v, 1),
290 						TYPE_MAX_VALUE (domain)))
291 			  {
292 			    v = NULL_TREE;
293 			    break;
294 			  }
295 		      }
296 		    v = TREE_OPERAND (v, 0);
297 		    break;
298 		  case REALPART_EXPR:
299 		  case IMAGPART_EXPR:
300 		    v = NULL_TREE;
301 		    break;
302 		  case COMPONENT_REF:
303 		    if (TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE)
304 		      {
305 			v = NULL_TREE;
306 			break;
307 		      }
308 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
309 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
310 			  != UNION_TYPE
311 			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
312 			  != QUAL_UNION_TYPE)
313 			break;
314 		      else
315 			v = TREE_OPERAND (v, 0);
316 		    if (TREE_CODE (v) == COMPONENT_REF
317 			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
318 			   == RECORD_TYPE)
319 		      {
320 			tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
321 			for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
322 			  if (TREE_CODE (fld_chain) == FIELD_DECL)
323 			    break;
324 
325 			if (fld_chain)
326 			  {
327 			    v = NULL_TREE;
328 			    break;
329 			  }
330 			v = TREE_OPERAND (v, 0);
331 		      }
332 		    while (v != pt_var && TREE_CODE (v) == COMPONENT_REF)
333 		      if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
334 			  != UNION_TYPE
335 			  && TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
336 			  != QUAL_UNION_TYPE)
337 			break;
338 		      else
339 			v = TREE_OPERAND (v, 0);
340 		    if (v != pt_var)
341 		      v = NULL_TREE;
342 		    else
343 		      v = pt_var;
344 		    break;
345 		  default:
346 		    v = pt_var;
347 		    break;
348 		  }
349 	      if (v == pt_var)
350 		var = pt_var;
351 	    }
352 	}
353       else
354 	var = pt_var;
355 
356       if (var != pt_var)
357 	var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
358       else if (!pt_var_size)
359 	return false;
360       else
361 	var_size = pt_var_size;
362       bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
363       if (bytes != error_mark_node)
364 	{
365 	  if (TREE_CODE (bytes) == INTEGER_CST
366 	      && tree_int_cst_lt (var_size, bytes))
367 	    bytes = size_zero_node;
368 	  else
369 	    bytes = size_binop (MINUS_EXPR, var_size, bytes);
370 	}
371       if (var != pt_var
372 	  && pt_var_size
373 	  && TREE_CODE (pt_var) == MEM_REF
374 	  && bytes != error_mark_node)
375 	{
376 	  tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
377 	  if (bytes2 != error_mark_node)
378 	    {
379 	      if (TREE_CODE (bytes2) == INTEGER_CST
380 		  && tree_int_cst_lt (pt_var_size, bytes2))
381 		bytes2 = size_zero_node;
382 	      else
383 		bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
384 	      bytes = size_binop (MIN_EXPR, bytes, bytes2);
385 	    }
386 	}
387     }
388   else if (!pt_var_size)
389     return false;
390   else
391     bytes = pt_var_size;
392 
393   if (tree_fits_uhwi_p (bytes))
394     {
395       *psize = tree_to_uhwi (bytes);
396       return true;
397     }
398 
399   return false;
400 }
401 
402 
403 /* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL.
404    Handles various allocation calls.  OBJECT_SIZE_TYPE is the second
405    argument from __builtin_object_size.  If unknown, return
406    unknown[object_size_type].  */
407 
408 static unsigned HOST_WIDE_INT
alloc_object_size(const gcall * call,int object_size_type)409 alloc_object_size (const gcall *call, int object_size_type)
410 {
411   tree callee, bytes = NULL_TREE;
412   tree alloc_size;
413   int arg1 = -1, arg2 = -1;
414 
415   gcc_assert (is_gimple_call (call));
416 
417   callee = gimple_call_fndecl (call);
418   if (!callee)
419     return unknown[object_size_type];
420 
421   alloc_size = lookup_attribute ("alloc_size",
422 				 TYPE_ATTRIBUTES (TREE_TYPE (callee)));
423   if (alloc_size && TREE_VALUE (alloc_size))
424     {
425       tree p = TREE_VALUE (alloc_size);
426 
427       arg1 = TREE_INT_CST_LOW (TREE_VALUE (p))-1;
428       if (TREE_CHAIN (p))
429         arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
430     }
431 
432   if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
433     switch (DECL_FUNCTION_CODE (callee))
434       {
435       case BUILT_IN_CALLOC:
436 	arg2 = 1;
437 	/* fall through */
438       case BUILT_IN_MALLOC:
439       CASE_BUILT_IN_ALLOCA:
440 	arg1 = 0;
441       default:
442 	break;
443       }
444 
445   if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call)
446       || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST
447       || (arg2 >= 0
448 	  && (arg2 >= (int)gimple_call_num_args (call)
449 	      || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST)))
450     return unknown[object_size_type];
451 
452   if (arg2 >= 0)
453     bytes = size_binop (MULT_EXPR,
454 	fold_convert (sizetype, gimple_call_arg (call, arg1)),
455 	fold_convert (sizetype, gimple_call_arg (call, arg2)));
456   else if (arg1 >= 0)
457     bytes = fold_convert (sizetype, gimple_call_arg (call, arg1));
458 
459   if (bytes && tree_fits_uhwi_p (bytes))
460     return tree_to_uhwi (bytes);
461 
462   return unknown[object_size_type];
463 }
464 
465 
466 /* If object size is propagated from one of function's arguments directly
467    to its return value, return that argument for GIMPLE_CALL statement CALL.
468    Otherwise return NULL.  */
469 
470 static tree
pass_through_call(const gcall * call)471 pass_through_call (const gcall *call)
472 {
473   unsigned rf = gimple_call_return_flags (call);
474   if (rf & ERF_RETURNS_ARG)
475     {
476       unsigned argnum = rf & ERF_RETURN_ARG_MASK;
477       if (argnum < gimple_call_num_args (call))
478 	return gimple_call_arg (call, argnum);
479     }
480 
481   /* __builtin_assume_aligned is intentionally not marked RET1.  */
482   if (gimple_call_builtin_p (call, BUILT_IN_ASSUME_ALIGNED))
483     return gimple_call_arg (call, 0);
484 
485   return NULL_TREE;
486 }
487 
488 
489 /* Compute __builtin_object_size value for PTR and set *PSIZE to
490    the resulting value.  OBJECT_SIZE_TYPE is the second argument
491    to __builtin_object_size.  Return true on success and false
492    when the object size could not be determined.  */
493 
494 bool
compute_builtin_object_size(tree ptr,int object_size_type,unsigned HOST_WIDE_INT * psize)495 compute_builtin_object_size (tree ptr, int object_size_type,
496 			     unsigned HOST_WIDE_INT *psize)
497 {
498   gcc_assert (object_size_type >= 0 && object_size_type <= 3);
499 
500   /* Set to unknown and overwrite just before returning if the size
501      could be determined.  */
502   *psize = unknown[object_size_type];
503 
504   if (! offset_limit)
505     init_offset_limit ();
506 
507   if (TREE_CODE (ptr) == ADDR_EXPR)
508     return addr_object_size (NULL, ptr, object_size_type, psize);
509 
510   if (TREE_CODE (ptr) != SSA_NAME
511       || !POINTER_TYPE_P (TREE_TYPE (ptr)))
512       return false;
513 
514   if (computed[object_size_type] == NULL)
515     {
516       if (optimize || object_size_type & 1)
517 	return false;
518 
519       /* When not optimizing, rather than failing, make a small effort
520 	 to determine the object size without the full benefit of
521 	 the (costly) computation below.  */
522       gimple *def = SSA_NAME_DEF_STMT (ptr);
523       if (gimple_code (def) == GIMPLE_ASSIGN)
524 	{
525 	  tree_code code = gimple_assign_rhs_code (def);
526 	  if (code == POINTER_PLUS_EXPR)
527 	    {
528 	      tree offset = gimple_assign_rhs2 (def);
529 	      ptr = gimple_assign_rhs1 (def);
530 
531 	      if (tree_fits_shwi_p (offset)
532 		  && compute_builtin_object_size (ptr, object_size_type, psize))
533 		{
534 		  /* Return zero when the offset is out of bounds.  */
535 		  unsigned HOST_WIDE_INT off = tree_to_shwi (offset);
536 		  *psize = off < *psize ? *psize - off : 0;
537 		  return true;
538 		}
539 	    }
540 	}
541       return false;
542     }
543 
544   if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
545     {
546       struct object_size_info osi;
547       bitmap_iterator bi;
548       unsigned int i;
549 
550       if (num_ssa_names > object_sizes[object_size_type].length ())
551 	object_sizes[object_size_type].safe_grow (num_ssa_names);
552       if (dump_file)
553 	{
554 	  fprintf (dump_file, "Computing %s %sobject size for ",
555 		   (object_size_type & 2) ? "minimum" : "maximum",
556 		   (object_size_type & 1) ? "sub" : "");
557 	  print_generic_expr (dump_file, ptr, dump_flags);
558 	  fprintf (dump_file, ":\n");
559 	}
560 
561       osi.visited = BITMAP_ALLOC (NULL);
562       osi.reexamine = BITMAP_ALLOC (NULL);
563       osi.object_size_type = object_size_type;
564       osi.depths = NULL;
565       osi.stack = NULL;
566       osi.tos = NULL;
567 
568       /* First pass: walk UD chains, compute object sizes that
569 	 can be computed.  osi.reexamine bitmap at the end will
570 	 contain what variables were found in dependency cycles
571 	 and therefore need to be reexamined.  */
572       osi.pass = 0;
573       osi.changed = false;
574       collect_object_sizes_for (&osi, ptr);
575 
576       /* Second pass: keep recomputing object sizes of variables
577 	 that need reexamination, until no object sizes are
578 	 increased or all object sizes are computed.  */
579       if (! bitmap_empty_p (osi.reexamine))
580 	{
581 	  bitmap reexamine = BITMAP_ALLOC (NULL);
582 
583 	  /* If looking for minimum instead of maximum object size,
584 	     detect cases where a pointer is increased in a loop.
585 	     Although even without this detection pass 2 would eventually
586 	     terminate, it could take a long time.  If a pointer is
587 	     increasing this way, we need to assume 0 object size.
588 	     E.g. p = &buf[0]; while (cond) p = p + 4;  */
589 	  if (object_size_type & 2)
590 	    {
591 	      osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
592 	      osi.stack = XNEWVEC (unsigned int, num_ssa_names);
593 	      osi.tos = osi.stack;
594 	      osi.pass = 1;
595 	      /* collect_object_sizes_for is changing
596 		 osi.reexamine bitmap, so iterate over a copy.  */
597 	      bitmap_copy (reexamine, osi.reexamine);
598 	      EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
599 		if (bitmap_bit_p (osi.reexamine, i))
600 		  check_for_plus_in_loops (&osi, ssa_name (i));
601 
602 	      free (osi.depths);
603 	      osi.depths = NULL;
604 	      free (osi.stack);
605 	      osi.stack = NULL;
606 	      osi.tos = NULL;
607 	    }
608 
609 	  do
610 	    {
611 	      osi.pass = 2;
612 	      osi.changed = false;
613 	      /* collect_object_sizes_for is changing
614 		 osi.reexamine bitmap, so iterate over a copy.  */
615 	      bitmap_copy (reexamine, osi.reexamine);
616 	      EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
617 		if (bitmap_bit_p (osi.reexamine, i))
618 		  {
619 		    collect_object_sizes_for (&osi, ssa_name (i));
620 		    if (dump_file && (dump_flags & TDF_DETAILS))
621 		      {
622 			fprintf (dump_file, "Reexamining ");
623 			print_generic_expr (dump_file, ssa_name (i),
624 					    dump_flags);
625 			fprintf (dump_file, "\n");
626 		      }
627 		  }
628 	    }
629 	  while (osi.changed);
630 
631 	  BITMAP_FREE (reexamine);
632 	}
633       EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
634 	bitmap_set_bit (computed[object_size_type], i);
635 
636       /* Debugging dumps.  */
637       if (dump_file)
638 	{
639 	  EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
640 	    if (object_sizes[object_size_type][i]
641 		!= unknown[object_size_type])
642 	      {
643 		print_generic_expr (dump_file, ssa_name (i),
644 				    dump_flags);
645 		fprintf (dump_file,
646 			 ": %s %sobject size "
647 			 HOST_WIDE_INT_PRINT_UNSIGNED "\n",
648 			 (object_size_type & 2) ? "minimum" : "maximum",
649 			 (object_size_type & 1) ? "sub" : "",
650 			 object_sizes[object_size_type][i]);
651 	      }
652 	}
653 
654       BITMAP_FREE (osi.reexamine);
655       BITMAP_FREE (osi.visited);
656     }
657 
658   *psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
659   return *psize != unknown[object_size_type];
660 }
661 
662 /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME.  */
663 
664 static void
expr_object_size(struct object_size_info * osi,tree ptr,tree value)665 expr_object_size (struct object_size_info *osi, tree ptr, tree value)
666 {
667   int object_size_type = osi->object_size_type;
668   unsigned int varno = SSA_NAME_VERSION (ptr);
669   unsigned HOST_WIDE_INT bytes;
670 
671   gcc_assert (object_sizes[object_size_type][varno]
672 	      != unknown[object_size_type]);
673   gcc_assert (osi->pass == 0);
674 
675   if (TREE_CODE (value) == WITH_SIZE_EXPR)
676     value = TREE_OPERAND (value, 0);
677 
678   /* Pointer variables should have been handled by merge_object_sizes.  */
679   gcc_assert (TREE_CODE (value) != SSA_NAME
680 	      || !POINTER_TYPE_P (TREE_TYPE (value)));
681 
682   if (TREE_CODE (value) == ADDR_EXPR)
683     addr_object_size (osi, value, object_size_type, &bytes);
684   else
685     bytes = unknown[object_size_type];
686 
687   if ((object_size_type & 2) == 0)
688     {
689       if (object_sizes[object_size_type][varno] < bytes)
690 	object_sizes[object_size_type][varno] = bytes;
691     }
692   else
693     {
694       if (object_sizes[object_size_type][varno] > bytes)
695 	object_sizes[object_size_type][varno] = bytes;
696     }
697 }
698 
699 
700 /* Compute object_sizes for PTR, defined to the result of a call.  */
701 
702 static void
call_object_size(struct object_size_info * osi,tree ptr,gcall * call)703 call_object_size (struct object_size_info *osi, tree ptr, gcall *call)
704 {
705   int object_size_type = osi->object_size_type;
706   unsigned int varno = SSA_NAME_VERSION (ptr);
707   unsigned HOST_WIDE_INT bytes;
708 
709   gcc_assert (is_gimple_call (call));
710 
711   gcc_assert (object_sizes[object_size_type][varno]
712 	      != unknown[object_size_type]);
713   gcc_assert (osi->pass == 0);
714 
715   bytes = alloc_object_size (call, object_size_type);
716 
717   if ((object_size_type & 2) == 0)
718     {
719       if (object_sizes[object_size_type][varno] < bytes)
720 	object_sizes[object_size_type][varno] = bytes;
721     }
722   else
723     {
724       if (object_sizes[object_size_type][varno] > bytes)
725 	object_sizes[object_size_type][varno] = bytes;
726     }
727 }
728 
729 
730 /* Compute object_sizes for PTR, defined to an unknown value.  */
731 
732 static void
unknown_object_size(struct object_size_info * osi,tree ptr)733 unknown_object_size (struct object_size_info *osi, tree ptr)
734 {
735   int object_size_type = osi->object_size_type;
736   unsigned int varno = SSA_NAME_VERSION (ptr);
737   unsigned HOST_WIDE_INT bytes;
738 
739   gcc_assert (object_sizes[object_size_type][varno]
740 	      != unknown[object_size_type]);
741   gcc_assert (osi->pass == 0);
742 
743   bytes = unknown[object_size_type];
744 
745   if ((object_size_type & 2) == 0)
746     {
747       if (object_sizes[object_size_type][varno] < bytes)
748 	object_sizes[object_size_type][varno] = bytes;
749     }
750   else
751     {
752       if (object_sizes[object_size_type][varno] > bytes)
753 	object_sizes[object_size_type][varno] = bytes;
754     }
755 }
756 
757 
758 /* Merge object sizes of ORIG + OFFSET into DEST.  Return true if
759    the object size might need reexamination later.  */
760 
761 static bool
merge_object_sizes(struct object_size_info * osi,tree dest,tree orig,unsigned HOST_WIDE_INT offset)762 merge_object_sizes (struct object_size_info *osi, tree dest, tree orig,
763 		    unsigned HOST_WIDE_INT offset)
764 {
765   int object_size_type = osi->object_size_type;
766   unsigned int varno = SSA_NAME_VERSION (dest);
767   unsigned HOST_WIDE_INT orig_bytes;
768 
769   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
770     return false;
771   if (offset >= offset_limit)
772     {
773       object_sizes[object_size_type][varno] = unknown[object_size_type];
774       return false;
775     }
776 
777   if (osi->pass == 0)
778     collect_object_sizes_for (osi, orig);
779 
780   orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)];
781   if (orig_bytes != unknown[object_size_type])
782     orig_bytes = (offset > orig_bytes)
783 		 ? HOST_WIDE_INT_0U : orig_bytes - offset;
784 
785   if ((object_size_type & 2) == 0)
786     {
787       if (object_sizes[object_size_type][varno] < orig_bytes)
788 	{
789 	  object_sizes[object_size_type][varno] = orig_bytes;
790 	  osi->changed = true;
791 	}
792     }
793   else
794     {
795       if (object_sizes[object_size_type][varno] > orig_bytes)
796 	{
797 	  object_sizes[object_size_type][varno] = orig_bytes;
798 	  osi->changed = true;
799 	}
800     }
801   return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig));
802 }
803 
804 
805 /* Compute object_sizes for VAR, defined to the result of an assignment
806    with operator POINTER_PLUS_EXPR.  Return true if the object size might
807    need reexamination  later.  */
808 
809 static bool
plus_stmt_object_size(struct object_size_info * osi,tree var,gimple * stmt)810 plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
811 {
812   int object_size_type = osi->object_size_type;
813   unsigned int varno = SSA_NAME_VERSION (var);
814   unsigned HOST_WIDE_INT bytes;
815   tree op0, op1;
816 
817   if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
818     {
819       op0 = gimple_assign_rhs1 (stmt);
820       op1 = gimple_assign_rhs2 (stmt);
821     }
822   else if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
823     {
824       tree rhs = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
825       gcc_assert (TREE_CODE (rhs) == MEM_REF);
826       op0 = TREE_OPERAND (rhs, 0);
827       op1 = TREE_OPERAND (rhs, 1);
828     }
829   else
830     gcc_unreachable ();
831 
832   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
833     return false;
834 
835   /* Handle PTR + OFFSET here.  */
836   if (TREE_CODE (op1) == INTEGER_CST
837       && (TREE_CODE (op0) == SSA_NAME
838 	  || TREE_CODE (op0) == ADDR_EXPR))
839     {
840       if (! tree_fits_uhwi_p (op1))
841 	bytes = unknown[object_size_type];
842       else if (TREE_CODE (op0) == SSA_NAME)
843 	return merge_object_sizes (osi, var, op0, tree_to_uhwi (op1));
844       else
845 	{
846 	  unsigned HOST_WIDE_INT off = tree_to_uhwi (op1);
847 
848           /* op0 will be ADDR_EXPR here.  */
849 	  addr_object_size (osi, op0, object_size_type, &bytes);
850 	  if (bytes == unknown[object_size_type])
851 	    ;
852 	  else if (off > offset_limit)
853 	    bytes = unknown[object_size_type];
854 	  else if (off > bytes)
855 	    bytes = 0;
856 	  else
857 	    bytes -= off;
858 	}
859     }
860   else
861     bytes = unknown[object_size_type];
862 
863   if ((object_size_type & 2) == 0)
864     {
865       if (object_sizes[object_size_type][varno] < bytes)
866 	object_sizes[object_size_type][varno] = bytes;
867     }
868   else
869     {
870       if (object_sizes[object_size_type][varno] > bytes)
871 	object_sizes[object_size_type][varno] = bytes;
872     }
873   return false;
874 }
875 
876 
877 /* Compute object_sizes for VAR, defined at STMT, which is
878    a COND_EXPR.  Return true if the object size might need reexamination
879    later.  */
880 
881 static bool
cond_expr_object_size(struct object_size_info * osi,tree var,gimple * stmt)882 cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt)
883 {
884   tree then_, else_;
885   int object_size_type = osi->object_size_type;
886   unsigned int varno = SSA_NAME_VERSION (var);
887   bool reexamine = false;
888 
889   gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR);
890 
891   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
892     return false;
893 
894   then_ = gimple_assign_rhs2 (stmt);
895   else_ = gimple_assign_rhs3 (stmt);
896 
897   if (TREE_CODE (then_) == SSA_NAME)
898     reexamine |= merge_object_sizes (osi, var, then_, 0);
899   else
900     expr_object_size (osi, var, then_);
901 
902   if (object_sizes[object_size_type][varno] == unknown[object_size_type])
903     return reexamine;
904 
905   if (TREE_CODE (else_) == SSA_NAME)
906     reexamine |= merge_object_sizes (osi, var, else_, 0);
907   else
908     expr_object_size (osi, var, else_);
909 
910   return reexamine;
911 }
912 
913 /* Compute object sizes for VAR.
914    For ADDR_EXPR an object size is the number of remaining bytes
915    to the end of the object (where what is considered an object depends on
916    OSI->object_size_type).
917    For allocation GIMPLE_CALL like malloc or calloc object size is the size
918    of the allocation.
919    For POINTER_PLUS_EXPR where second operand is a constant integer,
920    object size is object size of the first operand minus the constant.
921    If the constant is bigger than the number of remaining bytes until the
922    end of the object, object size is 0, but if it is instead a pointer
923    subtraction, object size is unknown[object_size_type].
924    To differentiate addition from subtraction, ADDR_EXPR returns
925    unknown[object_size_type] for all objects bigger than half of the address
926    space, and constants less than half of the address space are considered
927    addition, while bigger constants subtraction.
928    For a memcpy like GIMPLE_CALL that always returns one of its arguments, the
929    object size is object size of that argument.
930    Otherwise, object size is the maximum of object sizes of variables
931    that it might be set to.  */
932 
933 static void
collect_object_sizes_for(struct object_size_info * osi,tree var)934 collect_object_sizes_for (struct object_size_info *osi, tree var)
935 {
936   int object_size_type = osi->object_size_type;
937   unsigned int varno = SSA_NAME_VERSION (var);
938   gimple *stmt;
939   bool reexamine;
940 
941   if (bitmap_bit_p (computed[object_size_type], varno))
942     return;
943 
944   if (osi->pass == 0)
945     {
946       if (bitmap_set_bit (osi->visited, varno))
947 	{
948 	  object_sizes[object_size_type][varno]
949 	    = (object_size_type & 2) ? -1 : 0;
950 	}
951       else
952 	{
953 	  /* Found a dependency loop.  Mark the variable for later
954 	     re-examination.  */
955 	  bitmap_set_bit (osi->reexamine, varno);
956 	  if (dump_file && (dump_flags & TDF_DETAILS))
957 	    {
958 	      fprintf (dump_file, "Found a dependency loop at ");
959 	      print_generic_expr (dump_file, var, dump_flags);
960 	      fprintf (dump_file, "\n");
961 	    }
962 	  return;
963 	}
964     }
965 
966   if (dump_file && (dump_flags & TDF_DETAILS))
967     {
968       fprintf (dump_file, "Visiting use-def links for ");
969       print_generic_expr (dump_file, var, dump_flags);
970       fprintf (dump_file, "\n");
971     }
972 
973   stmt = SSA_NAME_DEF_STMT (var);
974   reexamine = false;
975 
976   switch (gimple_code (stmt))
977     {
978     case GIMPLE_ASSIGN:
979       {
980 	tree rhs = gimple_assign_rhs1 (stmt);
981         if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
982 	    || (gimple_assign_rhs_code (stmt) == ADDR_EXPR
983 		&& TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF))
984           reexamine = plus_stmt_object_size (osi, var, stmt);
985 	else if (gimple_assign_rhs_code (stmt) == COND_EXPR)
986 	  reexamine = cond_expr_object_size (osi, var, stmt);
987         else if (gimple_assign_single_p (stmt)
988                  || gimple_assign_unary_nop_p (stmt))
989           {
990             if (TREE_CODE (rhs) == SSA_NAME
991                 && POINTER_TYPE_P (TREE_TYPE (rhs)))
992               reexamine = merge_object_sizes (osi, var, rhs, 0);
993             else
994               expr_object_size (osi, var, rhs);
995           }
996         else
997           unknown_object_size (osi, var);
998         break;
999       }
1000 
1001     case GIMPLE_CALL:
1002       {
1003 	gcall *call_stmt = as_a <gcall *> (stmt);
1004         tree arg = pass_through_call (call_stmt);
1005         if (arg)
1006           {
1007             if (TREE_CODE (arg) == SSA_NAME
1008                 && POINTER_TYPE_P (TREE_TYPE (arg)))
1009               reexamine = merge_object_sizes (osi, var, arg, 0);
1010             else
1011               expr_object_size (osi, var, arg);
1012           }
1013         else
1014           call_object_size (osi, var, call_stmt);
1015 	break;
1016       }
1017 
1018     case GIMPLE_ASM:
1019       /* Pointers defined by __asm__ statements can point anywhere.  */
1020       object_sizes[object_size_type][varno] = unknown[object_size_type];
1021       break;
1022 
1023     case GIMPLE_NOP:
1024       if (SSA_NAME_VAR (var)
1025 	  && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL)
1026 	expr_object_size (osi, var, SSA_NAME_VAR (var));
1027       else
1028 	/* Uninitialized SSA names point nowhere.  */
1029 	object_sizes[object_size_type][varno] = unknown[object_size_type];
1030       break;
1031 
1032     case GIMPLE_PHI:
1033       {
1034 	unsigned i;
1035 
1036 	for (i = 0; i < gimple_phi_num_args (stmt); i++)
1037 	  {
1038 	    tree rhs = gimple_phi_arg (stmt, i)->def;
1039 
1040 	    if (object_sizes[object_size_type][varno]
1041 		== unknown[object_size_type])
1042 	      break;
1043 
1044 	    if (TREE_CODE (rhs) == SSA_NAME)
1045 	      reexamine |= merge_object_sizes (osi, var, rhs, 0);
1046 	    else if (osi->pass == 0)
1047 	      expr_object_size (osi, var, rhs);
1048 	  }
1049 	break;
1050       }
1051 
1052     default:
1053       gcc_unreachable ();
1054     }
1055 
1056   if (! reexamine
1057       || object_sizes[object_size_type][varno] == unknown[object_size_type])
1058     {
1059       bitmap_set_bit (computed[object_size_type], varno);
1060       bitmap_clear_bit (osi->reexamine, varno);
1061     }
1062   else
1063     {
1064       bitmap_set_bit (osi->reexamine, varno);
1065       if (dump_file && (dump_flags & TDF_DETAILS))
1066 	{
1067 	  fprintf (dump_file, "Need to reexamine ");
1068 	  print_generic_expr (dump_file, var, dump_flags);
1069 	  fprintf (dump_file, "\n");
1070 	}
1071     }
1072 }
1073 
1074 
1075 /* Helper function for check_for_plus_in_loops.  Called recursively
1076    to detect loops.  */
1077 
1078 static void
check_for_plus_in_loops_1(struct object_size_info * osi,tree var,unsigned int depth)1079 check_for_plus_in_loops_1 (struct object_size_info *osi, tree var,
1080 			   unsigned int depth)
1081 {
1082   gimple *stmt = SSA_NAME_DEF_STMT (var);
1083   unsigned int varno = SSA_NAME_VERSION (var);
1084 
1085   if (osi->depths[varno])
1086     {
1087       if (osi->depths[varno] != depth)
1088 	{
1089 	  unsigned int *sp;
1090 
1091 	  /* Found a loop involving pointer addition.  */
1092 	  for (sp = osi->tos; sp > osi->stack; )
1093 	    {
1094 	      --sp;
1095 	      bitmap_clear_bit (osi->reexamine, *sp);
1096 	      bitmap_set_bit (computed[osi->object_size_type], *sp);
1097 	      object_sizes[osi->object_size_type][*sp] = 0;
1098 	      if (*sp == varno)
1099 		break;
1100 	    }
1101 	}
1102       return;
1103     }
1104   else if (! bitmap_bit_p (osi->reexamine, varno))
1105     return;
1106 
1107   osi->depths[varno] = depth;
1108   *osi->tos++ = varno;
1109 
1110   switch (gimple_code (stmt))
1111     {
1112 
1113     case GIMPLE_ASSIGN:
1114       {
1115         if ((gimple_assign_single_p (stmt)
1116              || gimple_assign_unary_nop_p (stmt))
1117             && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME)
1118           {
1119             tree rhs = gimple_assign_rhs1 (stmt);
1120 
1121             check_for_plus_in_loops_1 (osi, rhs, depth);
1122           }
1123         else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1124           {
1125             tree basevar = gimple_assign_rhs1 (stmt);
1126             tree cst = gimple_assign_rhs2 (stmt);
1127 
1128             gcc_assert (TREE_CODE (cst) == INTEGER_CST);
1129 
1130             check_for_plus_in_loops_1 (osi, basevar,
1131                                        depth + !integer_zerop (cst));
1132           }
1133         else
1134           gcc_unreachable ();
1135         break;
1136       }
1137 
1138     case GIMPLE_CALL:
1139       {
1140 	gcall *call_stmt = as_a <gcall *> (stmt);
1141         tree arg = pass_through_call (call_stmt);
1142         if (arg)
1143           {
1144             if (TREE_CODE (arg) == SSA_NAME)
1145               check_for_plus_in_loops_1 (osi, arg, depth);
1146             else
1147               gcc_unreachable ();
1148           }
1149         break;
1150       }
1151 
1152     case GIMPLE_PHI:
1153       {
1154 	unsigned i;
1155 
1156 	for (i = 0; i < gimple_phi_num_args (stmt); i++)
1157 	  {
1158 	    tree rhs = gimple_phi_arg (stmt, i)->def;
1159 
1160 	    if (TREE_CODE (rhs) == SSA_NAME)
1161 	      check_for_plus_in_loops_1 (osi, rhs, depth);
1162 	  }
1163 	break;
1164       }
1165 
1166     default:
1167       gcc_unreachable ();
1168     }
1169 
1170   osi->depths[varno] = 0;
1171   osi->tos--;
1172 }
1173 
1174 
1175 /* Check if some pointer we are computing object size of is being increased
1176    within a loop.  If yes, assume all the SSA variables participating in
1177    that loop have minimum object sizes 0.  */
1178 
1179 static void
check_for_plus_in_loops(struct object_size_info * osi,tree var)1180 check_for_plus_in_loops (struct object_size_info *osi, tree var)
1181 {
1182   gimple *stmt = SSA_NAME_DEF_STMT (var);
1183 
1184   /* NOTE: In the pre-tuples code, we handled a CALL_EXPR here,
1185      and looked for a POINTER_PLUS_EXPR in the pass-through
1186      argument, if any.  In GIMPLE, however, such an expression
1187      is not a valid call operand.  */
1188 
1189   if (is_gimple_assign (stmt)
1190       && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
1191     {
1192       tree basevar = gimple_assign_rhs1 (stmt);
1193       tree cst = gimple_assign_rhs2 (stmt);
1194 
1195       gcc_assert (TREE_CODE (cst) == INTEGER_CST);
1196 
1197       if (integer_zerop (cst))
1198         return;
1199 
1200       osi->depths[SSA_NAME_VERSION (basevar)] = 1;
1201       *osi->tos++ = SSA_NAME_VERSION (basevar);
1202       check_for_plus_in_loops_1 (osi, var, 2);
1203       osi->depths[SSA_NAME_VERSION (basevar)] = 0;
1204       osi->tos--;
1205     }
1206 }
1207 
1208 
1209 /* Initialize data structures for the object size computation.  */
1210 
1211 void
init_object_sizes(void)1212 init_object_sizes (void)
1213 {
1214   int object_size_type;
1215 
1216   if (computed[0])
1217     return;
1218 
1219   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
1220     {
1221       object_sizes[object_size_type].safe_grow (num_ssa_names);
1222       computed[object_size_type] = BITMAP_ALLOC (NULL);
1223     }
1224 
1225   init_offset_limit ();
1226 }
1227 
1228 
1229 /* Destroy data structures after the object size computation.  */
1230 
1231 void
fini_object_sizes(void)1232 fini_object_sizes (void)
1233 {
1234   int object_size_type;
1235 
1236   for (object_size_type = 0; object_size_type <= 3; object_size_type++)
1237     {
1238       object_sizes[object_size_type].release ();
1239       BITMAP_FREE (computed[object_size_type]);
1240     }
1241 }
1242 
1243 
1244 /* Simple pass to optimize all __builtin_object_size () builtins.  */
1245 
1246 namespace {
1247 
1248 const pass_data pass_data_object_sizes =
1249 {
1250   GIMPLE_PASS, /* type */
1251   "objsz", /* name */
1252   OPTGROUP_NONE, /* optinfo_flags */
1253   TV_NONE, /* tv_id */
1254   ( PROP_cfg | PROP_ssa ), /* properties_required */
1255   0, /* properties_provided */
1256   0, /* properties_destroyed */
1257   0, /* todo_flags_start */
1258   0, /* todo_flags_finish */
1259 };
1260 
1261 class pass_object_sizes : public gimple_opt_pass
1262 {
1263 public:
pass_object_sizes(gcc::context * ctxt)1264   pass_object_sizes (gcc::context *ctxt)
1265     : gimple_opt_pass (pass_data_object_sizes, ctxt), insert_min_max_p (false)
1266   {}
1267 
1268   /* opt_pass methods: */
clone()1269   opt_pass * clone () { return new pass_object_sizes (m_ctxt); }
set_pass_param(unsigned int n,bool param)1270   void set_pass_param (unsigned int n, bool param)
1271     {
1272       gcc_assert (n == 0);
1273       insert_min_max_p = param;
1274     }
1275   virtual unsigned int execute (function *);
1276 
1277  private:
1278   /* Determines whether the pass instance creates MIN/MAX_EXPRs.  */
1279   bool insert_min_max_p;
1280 }; // class pass_object_sizes
1281 
1282 /* Dummy valueize function.  */
1283 
1284 static tree
do_valueize(tree t)1285 do_valueize (tree t)
1286 {
1287   return t;
1288 }
1289 
1290 unsigned int
execute(function * fun)1291 pass_object_sizes::execute (function *fun)
1292 {
1293   basic_block bb;
1294   FOR_EACH_BB_FN (bb, fun)
1295     {
1296       gimple_stmt_iterator i;
1297       for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
1298 	{
1299 	  tree result;
1300 	  gimple *call = gsi_stmt (i);
1301 	  if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE))
1302 	    continue;
1303 
1304 	  init_object_sizes ();
1305 
1306 	  /* If insert_min_max_p, only attempt to fold
1307 	     __builtin_object_size (x, 1) and __builtin_object_size (x, 3),
1308 	     and rather than folding the builtin to the constant if any,
1309 	     create a MIN_EXPR or MAX_EXPR of the __builtin_object_size
1310 	     call result and the computed constant.  */
1311 	  if (insert_min_max_p)
1312 	    {
1313 	      tree ost = gimple_call_arg (call, 1);
1314 	      if (tree_fits_uhwi_p (ost))
1315 		{
1316 		  unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
1317 		  tree ptr = gimple_call_arg (call, 0);
1318 		  tree lhs = gimple_call_lhs (call);
1319 		  if ((object_size_type == 1 || object_size_type == 3)
1320 		      && (TREE_CODE (ptr) == ADDR_EXPR
1321 			  || TREE_CODE (ptr) == SSA_NAME)
1322 		      && lhs)
1323 		    {
1324 		      tree type = TREE_TYPE (lhs);
1325 		      unsigned HOST_WIDE_INT bytes;
1326 		      if (compute_builtin_object_size (ptr, object_size_type,
1327 						       &bytes)
1328 			  && wi::fits_to_tree_p (bytes, type))
1329 			{
1330 			  tree tem = make_ssa_name (type);
1331 			  gimple_call_set_lhs (call, tem);
1332 			  enum tree_code code
1333 			    = object_size_type == 1 ? MIN_EXPR : MAX_EXPR;
1334 			  tree cst = build_int_cstu (type, bytes);
1335 			  gimple *g
1336 			    = gimple_build_assign (lhs, code, tem, cst);
1337 			  gsi_insert_after (&i, g, GSI_NEW_STMT);
1338 			  update_stmt (call);
1339 			}
1340 		    }
1341 		}
1342 	      continue;
1343 	    }
1344 
1345 	  tree lhs = gimple_call_lhs (call);
1346 	  if (!lhs)
1347 	    continue;
1348 
1349 	  result = gimple_fold_stmt_to_constant (call, do_valueize);
1350 	  if (!result)
1351 	    {
1352 	      tree ost = gimple_call_arg (call, 1);
1353 
1354 	      if (tree_fits_uhwi_p (ost))
1355 		{
1356 		  unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost);
1357 
1358 		  if (object_size_type < 2)
1359 		    result = fold_convert (size_type_node,
1360 					   integer_minus_one_node);
1361 		  else if (object_size_type < 4)
1362 		    result = build_zero_cst (size_type_node);
1363 		}
1364 
1365 	      if (!result)
1366 		continue;
1367 	    }
1368 
1369 	  gcc_assert (TREE_CODE (result) == INTEGER_CST);
1370 
1371 	  if (dump_file && (dump_flags & TDF_DETAILS))
1372 	    {
1373 	      fprintf (dump_file, "Simplified\n  ");
1374 	      print_gimple_stmt (dump_file, call, 0, dump_flags);
1375 	      fprintf (dump_file, " to ");
1376 	      print_generic_expr (dump_file, result);
1377 	      fprintf (dump_file, "\n");
1378 	    }
1379 
1380 	  /* Propagate into all uses and fold those stmts.  */
1381 	  replace_uses_by (lhs, result);
1382 	}
1383     }
1384 
1385   fini_object_sizes ();
1386   return 0;
1387 }
1388 
1389 } // anon namespace
1390 
1391 gimple_opt_pass *
make_pass_object_sizes(gcc::context * ctxt)1392 make_pass_object_sizes (gcc::context *ctxt)
1393 {
1394   return new pass_object_sizes (ctxt);
1395 }
1396