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