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>
5 This file is part of GCC.
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 2, or (at your option)
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.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to
19 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
24 #include "coretypes.h"
27 #include "diagnostic.h"
28 #include "tree-flow.h"
29 #include "tree-pass.h"
30 #include "tree-ssa-propagate.h"
32 struct object_size_info
35 bitmap visited
, reexamine
;
39 unsigned int *stack
, *tos
;
42 static unsigned HOST_WIDE_INT unknown
[4] = { -1, -1, 0, 0 };
44 static tree
compute_object_offset (tree
, tree
);
45 static unsigned HOST_WIDE_INT
addr_object_size (tree
, int);
46 static unsigned HOST_WIDE_INT
alloc_object_size (tree
, int);
47 static tree
pass_through_call (tree
);
48 static void collect_object_sizes_for (struct object_size_info
*, tree
);
49 static void expr_object_size (struct object_size_info
*, tree
, tree
);
50 static bool merge_object_sizes (struct object_size_info
*, tree
, tree
,
51 unsigned HOST_WIDE_INT
);
52 static bool plus_expr_object_size (struct object_size_info
*, tree
, tree
);
53 static void compute_object_sizes (void);
54 static void init_offset_limit (void);
55 static void check_for_plus_in_loops (struct object_size_info
*, tree
);
56 static void check_for_plus_in_loops_1 (struct object_size_info
*, tree
,
59 /* object_sizes[0] is upper bound for number of bytes till the end of
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. */
65 static unsigned HOST_WIDE_INT
*object_sizes
[4];
67 /* Bitmaps what object sizes have been computed already. */
68 static bitmap computed
[4];
70 /* Maximum value of offset we consider to be addition. */
71 static unsigned HOST_WIDE_INT offset_limit
;
74 /* Initialize OFFSET_LIMIT variable. */
76 init_offset_limit (void)
78 if (host_integerp (TYPE_MAX_VALUE (sizetype
), 1))
79 offset_limit
= tree_low_cst (TYPE_MAX_VALUE (sizetype
), 1);
86 /* Compute offset of EXPR within VAR. Return error_mark_node
90 compute_object_offset (tree expr
, tree var
)
92 enum tree_code code
= PLUS_EXPR
;
96 return size_zero_node
;
98 switch (TREE_CODE (expr
))
101 base
= compute_object_offset (TREE_OPERAND (expr
, 0), var
);
102 if (base
== error_mark_node
)
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)
114 case VIEW_CONVERT_EXPR
:
115 case NON_LVALUE_EXPR
:
116 return compute_object_offset (TREE_OPERAND (expr
, 0), var
);
119 base
= compute_object_offset (TREE_OPERAND (expr
, 0), var
);
120 if (base
== error_mark_node
)
123 off
= TYPE_SIZE_UNIT (TREE_TYPE (expr
));
127 base
= compute_object_offset (TREE_OPERAND (expr
, 0), var
);
128 if (base
== error_mark_node
)
131 t
= TREE_OPERAND (expr
, 1);
132 if (TREE_CODE (t
) == INTEGER_CST
&& tree_int_cst_sgn (t
) < 0)
135 t
= fold_build1 (NEGATE_EXPR
, TREE_TYPE (t
), t
);
137 t
= convert (sizetype
, t
);
138 off
= size_binop (MULT_EXPR
, TYPE_SIZE_UNIT (TREE_TYPE (expr
)), t
);
142 return error_mark_node
;
145 return size_binop (code
, base
, off
);
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]. */
153 static unsigned HOST_WIDE_INT
154 addr_object_size (tree ptr
, int object_size_type
)
158 gcc_assert (TREE_CODE (ptr
) == ADDR_EXPR
);
160 pt_var
= TREE_OPERAND (ptr
, 0);
161 if (REFERENCE_CLASS_P (pt_var
))
162 pt_var
= get_base_address (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
)
173 if (pt_var
!= TREE_OPERAND (ptr
, 0))
177 if (object_size_type
& 1)
179 var
= TREE_OPERAND (ptr
, 0);
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
))))
200 bytes
= compute_object_offset (TREE_OPERAND (ptr
, 0), var
);
201 if (bytes
!= error_mark_node
)
203 if (TREE_CODE (bytes
) == INTEGER_CST
204 && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var
)), bytes
))
205 bytes
= size_zero_node
;
207 bytes
= size_binop (MINUS_EXPR
,
208 TYPE_SIZE_UNIT (TREE_TYPE (var
)), bytes
);
212 bytes
= TYPE_SIZE_UNIT (TREE_TYPE (pt_var
));
214 if (host_integerp (bytes
, 1))
215 return tree_low_cst (bytes
, 1);
218 return unknown
[object_size_type
];
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]. */
227 static unsigned HOST_WIDE_INT
228 alloc_object_size (tree call
, int object_size_type
)
230 tree callee
, arglist
, a
, bytes
= NULL_TREE
;
231 unsigned int arg_mask
= 0;
233 gcc_assert (TREE_CODE (call
) == CALL_EXPR
);
235 callee
= get_callee_fndecl (call
);
236 arglist
= TREE_OPERAND (call
, 1);
238 && DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
)
239 switch (DECL_FUNCTION_CODE (callee
))
241 case BUILT_IN_MALLOC
:
242 case BUILT_IN_ALLOCA
:
246 case BUILT_IN_REALLOC:
250 case BUILT_IN_CALLOC
:
257 for (a
= arglist
; arg_mask
&& a
; arg_mask
>>= 1, a
= TREE_CHAIN (a
))
260 tree arg
= TREE_VALUE (a
);
262 if (TREE_CODE (arg
) != INTEGER_CST
)
266 bytes
= fold_convert (sizetype
, arg
);
268 bytes
= size_binop (MULT_EXPR
, bytes
,
269 fold_convert (sizetype
, arg
));
272 if (! arg_mask
&& bytes
&& host_integerp (bytes
, 1))
273 return tree_low_cst (bytes
, 1);
275 return unknown
[object_size_type
];
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. */
284 pass_through_call (tree call
)
286 tree callee
= get_callee_fndecl (call
);
287 tree arglist
= TREE_OPERAND (call
, 1);
290 && DECL_BUILT_IN_CLASS (callee
) == BUILT_IN_NORMAL
)
291 switch (DECL_FUNCTION_CODE (callee
))
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
:
308 return TREE_VALUE (arglist
);
318 /* Compute __builtin_object_size value for PTR. OBJECT_SIZE_TYPE is the
319 second argument from __builtin_object_size. */
321 unsigned HOST_WIDE_INT
322 compute_builtin_object_size (tree ptr
, int object_size_type
)
324 gcc_assert (object_size_type
>= 0 && object_size_type
<= 3);
327 init_offset_limit ();
329 if (TREE_CODE (ptr
) == ADDR_EXPR
)
330 return addr_object_size (ptr
, object_size_type
);
331 else if (TREE_CODE (ptr
) == CALL_EXPR
)
333 tree arg
= pass_through_call (ptr
);
336 return compute_builtin_object_size (arg
, object_size_type
);
338 return alloc_object_size (ptr
, object_size_type
);
340 else if (TREE_CODE (ptr
) == SSA_NAME
341 && POINTER_TYPE_P (TREE_TYPE (ptr
))
342 && object_sizes
[object_size_type
] != NULL
)
344 if (!bitmap_bit_p (computed
[object_size_type
], SSA_NAME_VERSION (ptr
)))
346 struct object_size_info osi
;
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");
359 osi
.visited
= BITMAP_ALLOC (NULL
);
360 osi
.reexamine
= BITMAP_ALLOC (NULL
);
361 osi
.object_size_type
= object_size_type
;
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. */
372 collect_object_sizes_for (&osi
, ptr
);
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
))
379 bitmap reexamine
= BITMAP_ALLOC (NULL
);
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)
389 osi
.depths
= XCNEWVEC (unsigned int, num_ssa_names
);
390 osi
.stack
= XNEWVEC (unsigned int, num_ssa_names
);
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
));
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
))
417 collect_object_sizes_for (&osi
, ssa_name (i
));
418 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
420 fprintf (dump_file
, "Reexamining ");
421 print_generic_expr (dump_file
, ssa_name (i
),
423 fprintf (dump_file
, "\n");
429 BITMAP_FREE (reexamine
);
431 EXECUTE_IF_SET_IN_BITMAP (osi
.reexamine
, 0, i
, bi
)
432 bitmap_set_bit (computed
[object_size_type
], i
);
434 /* Debugging dumps. */
437 EXECUTE_IF_SET_IN_BITMAP (osi
.visited
, 0, i
, bi
)
438 if (object_sizes
[object_size_type
][i
]
439 != unknown
[object_size_type
])
441 print_generic_expr (dump_file
, ssa_name (i
),
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
]);
452 BITMAP_FREE (osi
.reexamine
);
453 BITMAP_FREE (osi
.visited
);
456 return object_sizes
[object_size_type
][SSA_NAME_VERSION (ptr
)];
459 return unknown
[object_size_type
];
463 /* Compute object_sizes for PTR, defined to VALUE, which is not
467 expr_object_size (struct object_size_info
*osi
, tree ptr
, tree value
)
469 int object_size_type
= osi
->object_size_type
;
470 unsigned int varno
= SSA_NAME_VERSION (ptr
);
471 unsigned HOST_WIDE_INT bytes
;
473 gcc_assert (object_sizes
[object_size_type
][varno
]
474 != unknown
[object_size_type
]);
475 gcc_assert (osi
->pass
== 0);
477 if (TREE_CODE (value
) == WITH_SIZE_EXPR
)
478 value
= TREE_OPERAND (value
, 0);
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
)));
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
);
489 bytes
= unknown
[object_size_type
];
491 if ((object_size_type
& 2) == 0)
493 if (object_sizes
[object_size_type
][varno
] < bytes
)
494 object_sizes
[object_size_type
][varno
] = bytes
;
498 if (object_sizes
[object_size_type
][varno
] > bytes
)
499 object_sizes
[object_size_type
][varno
] = bytes
;
504 /* Merge object sizes of ORIG + OFFSET into DEST. Return true if
505 the object size might need reexamination later. */
508 merge_object_sizes (struct object_size_info
*osi
, tree dest
, tree orig
,
509 unsigned HOST_WIDE_INT offset
)
511 int object_size_type
= osi
->object_size_type
;
512 unsigned int varno
= SSA_NAME_VERSION (dest
);
513 unsigned HOST_WIDE_INT orig_bytes
;
515 if (object_sizes
[object_size_type
][varno
] == unknown
[object_size_type
])
517 if (offset
>= offset_limit
)
519 object_sizes
[object_size_type
][varno
] = unknown
[object_size_type
];
524 collect_object_sizes_for (osi
, orig
);
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
;
531 if ((object_size_type
& 2) == 0)
533 if (object_sizes
[object_size_type
][varno
] < orig_bytes
)
535 object_sizes
[object_size_type
][varno
] = orig_bytes
;
541 if (object_sizes
[object_size_type
][varno
] > orig_bytes
)
543 object_sizes
[object_size_type
][varno
] = orig_bytes
;
547 return bitmap_bit_p (osi
->reexamine
, SSA_NAME_VERSION (orig
));
551 /* Compute object_sizes for PTR, defined to VALUE, which is
552 a PLUS_EXPR. Return true if the object size might need reexamination
556 plus_expr_object_size (struct object_size_info
*osi
, tree var
, tree value
)
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
;
568 gcc_assert (TREE_CODE (value
) == PLUS_EXPR
);
570 if (object_sizes
[object_size_type
][varno
] == unknown
[object_size_type
])
573 /* Swap operands if needed. */
574 if (ptr2_p
&& !ptr1_p
)
583 /* Handle PTR + OFFSET here. */
586 && TREE_CODE (op1
) == INTEGER_CST
587 && (TREE_CODE (op0
) == SSA_NAME
588 || TREE_CODE (op0
) == ADDR_EXPR
))
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));
596 unsigned HOST_WIDE_INT off
= tree_low_cst (op1
, 1);
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
)
608 bytes
= unknown
[object_size_type
];
610 if ((object_size_type
& 2) == 0)
612 if (object_sizes
[object_size_type
][varno
] < bytes
)
613 object_sizes
[object_size_type
][varno
] = bytes
;
617 if (object_sizes
[object_size_type
][varno
] > bytes
)
618 object_sizes
[object_size_type
][varno
] = bytes
;
624 /* Compute object sizes for VAR.
625 For ADDR_EXPR an object size is the number of remaining bytes
626 to the end of the object (where what is considered an object depends on
627 OSI->object_size_type).
628 For allocation CALL_EXPR like malloc or calloc object size is the size
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. */
645 collect_object_sizes_for (struct object_size_info
*osi
, tree var
)
647 int object_size_type
= osi
->object_size_type
;
648 unsigned int varno
= SSA_NAME_VERSION (var
);
652 if (bitmap_bit_p (computed
[object_size_type
], varno
))
657 if (! bitmap_bit_p (osi
->visited
, varno
))
659 bitmap_set_bit (osi
->visited
, varno
);
660 object_sizes
[object_size_type
][varno
]
661 = (object_size_type
& 2) ? -1 : 0;
665 /* Found a dependency loop. Mark the variable for later
667 bitmap_set_bit (osi
->reexamine
, varno
);
668 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
670 fprintf (dump_file
, "Found a dependency loop at ");
671 print_generic_expr (dump_file
, var
, dump_flags
);
672 fprintf (dump_file
, "\n");
678 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
680 fprintf (dump_file
, "Visiting use-def links for ");
681 print_generic_expr (dump_file
, var
, dump_flags
);
682 fprintf (dump_file
, "\n");
685 stmt
= SSA_NAME_DEF_STMT (var
);
688 switch (TREE_CODE (stmt
))
691 gcc_assert (TREE_CODE (TREE_OPERAND (stmt
, 0)) == MODIFY_EXPR
);
692 stmt
= TREE_OPERAND (stmt
, 0);
697 tree rhs
= TREE_OPERAND (stmt
, 1), arg
;
700 if (TREE_CODE (rhs
) == CALL_EXPR
)
702 arg
= pass_through_call (rhs
);
707 if (TREE_CODE (rhs
) == SSA_NAME
708 && POINTER_TYPE_P (TREE_TYPE (rhs
)))
709 reexamine
= merge_object_sizes (osi
, var
, rhs
, 0);
711 else if (TREE_CODE (rhs
) == PLUS_EXPR
)
712 reexamine
= plus_expr_object_size (osi
, var
, rhs
);
715 expr_object_size (osi
, var
, rhs
);
720 /* Pointers defined by __asm__ statements can point anywhere. */
721 object_sizes
[object_size_type
][varno
] = unknown
[object_size_type
];
726 tree decl
= SSA_NAME_VAR (var
);
728 gcc_assert (IS_EMPTY_STMT (stmt
));
730 if (TREE_CODE (decl
) != PARM_DECL
&& DECL_INITIAL (decl
))
731 expr_object_size (osi
, var
, DECL_INITIAL (decl
));
733 expr_object_size (osi
, var
, decl
);
741 for (i
= 0; i
< PHI_NUM_ARGS (stmt
); i
++)
743 tree rhs
= PHI_ARG_DEF (stmt
, i
);
745 if (object_sizes
[object_size_type
][varno
]
746 == unknown
[object_size_type
])
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
);
761 || object_sizes
[object_size_type
][varno
] == unknown
[object_size_type
])
763 bitmap_set_bit (computed
[object_size_type
], varno
);
764 bitmap_clear_bit (osi
->reexamine
, varno
);
768 bitmap_set_bit (osi
->reexamine
, varno
);
769 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
771 fprintf (dump_file
, "Need to reexamine ");
772 print_generic_expr (dump_file
, var
, dump_flags
);
773 fprintf (dump_file
, "\n");
779 /* Helper function for check_for_plus_in_loops. Called recursively
783 check_for_plus_in_loops_1 (struct object_size_info
*osi
, tree var
,
786 tree stmt
= SSA_NAME_DEF_STMT (var
);
787 unsigned int varno
= SSA_NAME_VERSION (var
);
789 if (osi
->depths
[varno
])
791 if (osi
->depths
[varno
] != depth
)
795 /* Found a loop involving pointer addition. */
796 for (sp
= osi
->tos
; sp
> osi
->stack
; )
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;
808 else if (! bitmap_bit_p (osi
->reexamine
, varno
))
811 osi
->depths
[varno
] = depth
;
814 switch (TREE_CODE (stmt
))
817 gcc_assert (TREE_CODE (TREE_OPERAND (stmt
, 0)) == MODIFY_EXPR
);
818 stmt
= TREE_OPERAND (stmt
, 0);
823 tree rhs
= TREE_OPERAND (stmt
, 1), arg
;
826 if (TREE_CODE (rhs
) == CALL_EXPR
)
828 arg
= pass_through_call (rhs
);
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
)
837 tree op0
= TREE_OPERAND (rhs
, 0);
838 tree op1
= TREE_OPERAND (rhs
, 1);
841 if (TREE_CODE (op0
) == SSA_NAME
)
850 gcc_assert (TREE_CODE (basevar
) == SSA_NAME
);
852 gcc_assert (TREE_CODE (cst
) == INTEGER_CST
);
854 check_for_plus_in_loops_1 (osi
, basevar
,
855 depth
+ !integer_zerop (cst
));
865 for (i
= 0; i
< PHI_NUM_ARGS (stmt
); i
++)
867 tree rhs
= PHI_ARG_DEF (stmt
, i
);
869 if (TREE_CODE (rhs
) == SSA_NAME
)
870 check_for_plus_in_loops_1 (osi
, rhs
, depth
);
878 osi
->depths
[varno
] = 0;
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. */
888 check_for_plus_in_loops (struct object_size_info
*osi
, tree var
)
890 tree stmt
= SSA_NAME_DEF_STMT (var
);
892 switch (TREE_CODE (stmt
))
895 gcc_assert (TREE_CODE (TREE_OPERAND (stmt
, 0)) == MODIFY_EXPR
);
896 stmt
= TREE_OPERAND (stmt
, 0);
901 tree rhs
= TREE_OPERAND (stmt
, 1), arg
;
904 if (TREE_CODE (rhs
) == CALL_EXPR
)
906 arg
= pass_through_call (rhs
);
911 if (TREE_CODE (rhs
) == PLUS_EXPR
)
913 tree op0
= TREE_OPERAND (rhs
, 0);
914 tree op1
= TREE_OPERAND (rhs
, 1);
917 if (TREE_CODE (op0
) == SSA_NAME
)
926 gcc_assert (TREE_CODE (basevar
) == SSA_NAME
);
928 gcc_assert (TREE_CODE (cst
) == INTEGER_CST
);
930 if (integer_zerop (cst
))
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;
947 /* Initialize data structures for the object size computation. */
950 init_object_sizes (void)
952 int object_size_type
;
957 for (object_size_type
= 0; object_size_type
<= 3; object_size_type
++)
959 object_sizes
[object_size_type
] = XNEWVEC (unsigned HOST_WIDE_INT
, num_ssa_names
);
960 computed
[object_size_type
] = BITMAP_ALLOC (NULL
);
963 init_offset_limit ();
967 /* Destroy data structures after the object size computation. */
970 fini_object_sizes (void)
972 int object_size_type
;
974 for (object_size_type
= 0; object_size_type
<= 3; object_size_type
++)
976 free (object_sizes
[object_size_type
]);
977 BITMAP_FREE (computed
[object_size_type
]);
978 object_sizes
[object_size_type
] = NULL
;
983 /* Simple pass to optimize all __builtin_object_size () builtins. */
986 compute_object_sizes (void)
991 block_stmt_iterator i
;
992 for (i
= bsi_start (bb
); !bsi_end_p (i
); bsi_next (&i
))
994 tree
*stmtp
= bsi_stmt_ptr (i
);
995 tree call
= get_rhs (*stmtp
);
998 if (!call
|| TREE_CODE (call
) != CALL_EXPR
)
1001 callee
= get_callee_fndecl (call
);
1003 || DECL_BUILT_IN_CLASS (callee
) != BUILT_IN_NORMAL
1004 || DECL_FUNCTION_CODE (callee
) != BUILT_IN_OBJECT_SIZE
)
1007 init_object_sizes ();
1008 result
= fold_builtin (callee
, TREE_OPERAND (call
, 1), false);
1011 tree arglist
= TREE_OPERAND (call
, 1);
1014 && POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist
)))
1015 && TREE_CHAIN (arglist
) != NULL
1016 && TREE_CHAIN (TREE_CHAIN (arglist
)) == NULL
)
1018 tree ost
= TREE_VALUE (TREE_CHAIN (arglist
));
1020 if (host_integerp (ost
, 1))
1022 unsigned HOST_WIDE_INT object_size_type
1023 = tree_low_cst (ost
, 1);
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
;
1037 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1039 fprintf (dump_file
, "Simplified\n ");
1040 print_generic_stmt (dump_file
, *stmtp
, dump_flags
);
1043 if (!set_rhs (stmtp
, result
))
1045 update_stmt (*stmtp
);
1047 if (dump_file
&& (dump_flags
& TDF_DETAILS
))
1049 fprintf (dump_file
, "to\n ");
1050 print_generic_stmt (dump_file
, *stmtp
, dump_flags
);
1051 fprintf (dump_file
, "\n");
1056 fini_object_sizes ();
1059 struct tree_opt_pass pass_object_sizes
=
1063 compute_object_sizes
, /* execute */
1066 0, /* static_pass_number */
1068 PROP_cfg
| PROP_ssa
| PROP_alias
, /* properties_required */
1069 0, /* properties_provided */
1070 0, /* properties_destroyed */
1071 0, /* todo_flags_start */
1072 TODO_dump_func
| TODO_verify_ssa
, /* todo_flags_finish */