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