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