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