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