OSDN Git Service

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