xref: /dflybsd-src/contrib/gcc-8.0/gcc/tree-chkp.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Pointer Bounds Checker insrumentation pass.
2*38fd1498Szrj    Copyright (C) 2014-2018 Free Software Foundation, Inc.
3*38fd1498Szrj    Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4*38fd1498Szrj 
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj 
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
8*38fd1498Szrj the terms of the GNU General Public License as published by the Free
9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
10*38fd1498Szrj version.
11*38fd1498Szrj 
12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15*38fd1498Szrj for more details.
16*38fd1498Szrj 
17*38fd1498Szrj You should have received a copy of the GNU General Public License
18*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
19*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
20*38fd1498Szrj 
21*38fd1498Szrj #include "config.h"
22*38fd1498Szrj #include "system.h"
23*38fd1498Szrj #include "coretypes.h"
24*38fd1498Szrj #include "backend.h"
25*38fd1498Szrj #include "target.h"
26*38fd1498Szrj #include "rtl.h"
27*38fd1498Szrj #include "tree.h"
28*38fd1498Szrj #include "gimple.h"
29*38fd1498Szrj #include "cfghooks.h"
30*38fd1498Szrj #include "tree-pass.h"
31*38fd1498Szrj #include "ssa.h"
32*38fd1498Szrj #include "cgraph.h"
33*38fd1498Szrj #include "diagnostic.h"
34*38fd1498Szrj #include "fold-const.h"
35*38fd1498Szrj #include "stor-layout.h"
36*38fd1498Szrj #include "varasm.h"
37*38fd1498Szrj #include "tree-iterator.h"
38*38fd1498Szrj #include "tree-cfg.h"
39*38fd1498Szrj #include "langhooks.h"
40*38fd1498Szrj #include "tree-ssa-address.h"
41*38fd1498Szrj #include "tree-ssa-loop-niter.h"
42*38fd1498Szrj #include "gimple-pretty-print.h"
43*38fd1498Szrj #include "gimple-iterator.h"
44*38fd1498Szrj #include "gimplify.h"
45*38fd1498Szrj #include "gimplify-me.h"
46*38fd1498Szrj #include "print-tree.h"
47*38fd1498Szrj #include "calls.h"
48*38fd1498Szrj #include "expr.h"
49*38fd1498Szrj #include "tree-ssa-propagate.h"
50*38fd1498Szrj #include "tree-chkp.h"
51*38fd1498Szrj #include "gimple-walk.h"
52*38fd1498Szrj #include "tree-dfa.h"
53*38fd1498Szrj #include "ipa-chkp.h"
54*38fd1498Szrj #include "params.h"
55*38fd1498Szrj #include "stringpool.h"
56*38fd1498Szrj #include "attribs.h"
57*38fd1498Szrj 
58*38fd1498Szrj /*  Pointer Bounds Checker instruments code with memory checks to find
59*38fd1498Szrj     out-of-bounds memory accesses.  Checks are performed by computing
60*38fd1498Szrj     bounds for each pointer and then comparing address of accessed
61*38fd1498Szrj     memory before pointer dereferencing.
62*38fd1498Szrj 
63*38fd1498Szrj     1. Function clones.
64*38fd1498Szrj 
65*38fd1498Szrj     See ipa-chkp.c.
66*38fd1498Szrj 
67*38fd1498Szrj     2. Instrumentation.
68*38fd1498Szrj 
69*38fd1498Szrj     There are few things to instrument:
70*38fd1498Szrj 
71*38fd1498Szrj     a) Memory accesses - add checker calls to check address of accessed memory
72*38fd1498Szrj     against bounds of dereferenced pointer.  Obviously safe memory
73*38fd1498Szrj     accesses like static variable access does not have to be instrumented
74*38fd1498Szrj     with checks.
75*38fd1498Szrj 
76*38fd1498Szrj     Example:
77*38fd1498Szrj 
78*38fd1498Szrj       val_2 = *p_1;
79*38fd1498Szrj 
80*38fd1498Szrj       with 4 bytes access is transformed into:
81*38fd1498Szrj 
82*38fd1498Szrj       __builtin___chkp_bndcl (__bound_tmp.1_3, p_1);
83*38fd1498Szrj       D.1_4 = p_1 + 3;
84*38fd1498Szrj       __builtin___chkp_bndcu (__bound_tmp.1_3, D.1_4);
85*38fd1498Szrj       val_2 = *p_1;
86*38fd1498Szrj 
87*38fd1498Szrj       where __bound_tmp.1_3 are bounds computed for pointer p_1,
88*38fd1498Szrj       __builtin___chkp_bndcl is a lower bound check and
89*38fd1498Szrj       __builtin___chkp_bndcu is an upper bound check.
90*38fd1498Szrj 
91*38fd1498Szrj     b) Pointer stores.
92*38fd1498Szrj 
93*38fd1498Szrj     When pointer is stored in memory we need to store its bounds.  To
94*38fd1498Szrj     achieve compatibility of instrumented code with regular codes
95*38fd1498Szrj     we have to keep data layout and store bounds in special bound tables
96*38fd1498Szrj     via special checker call.  Implementation of bounds table may vary for
97*38fd1498Szrj     different platforms.  It has to associate pointer value and its
98*38fd1498Szrj     location (it is required because we may have two equal pointers
99*38fd1498Szrj     with different bounds stored in different places) with bounds.
100*38fd1498Szrj     Another checker builtin allows to get bounds for specified pointer
101*38fd1498Szrj     loaded from specified location.
102*38fd1498Szrj 
103*38fd1498Szrj     Example:
104*38fd1498Szrj 
105*38fd1498Szrj       buf1[i_1] = &buf2;
106*38fd1498Szrj 
107*38fd1498Szrj       is transformed into:
108*38fd1498Szrj 
109*38fd1498Szrj       buf1[i_1] = &buf2;
110*38fd1498Szrj       D.1_2 = &buf1[i_1];
111*38fd1498Szrj       __builtin___chkp_bndstx (D.1_2, &buf2, __bound_tmp.1_2);
112*38fd1498Szrj 
113*38fd1498Szrj       where __bound_tmp.1_2 are bounds of &buf2.
114*38fd1498Szrj 
115*38fd1498Szrj     c) Static initialization.
116*38fd1498Szrj 
117*38fd1498Szrj     The special case of pointer store is static pointer initialization.
118*38fd1498Szrj     Bounds initialization is performed in a few steps:
119*38fd1498Szrj       - register all static initializations in front-end using
120*38fd1498Szrj       chkp_register_var_initializer
121*38fd1498Szrj       - when file compilation finishes we create functions with special
122*38fd1498Szrj       attribute 'chkp ctor' and put explicit initialization code
123*38fd1498Szrj       (assignments) for all statically initialized pointers.
124*38fd1498Szrj       - when checker constructor is compiled checker pass adds required
125*38fd1498Szrj       bounds initialization for all statically initialized pointers
126*38fd1498Szrj       - since we do not actually need excess pointers initialization
127*38fd1498Szrj       in checker constructor we remove such assignments from them
128*38fd1498Szrj 
129*38fd1498Szrj     d) Calls.
130*38fd1498Szrj 
131*38fd1498Szrj     For each call in the code we add additional arguments to pass
132*38fd1498Szrj     bounds for pointer arguments.  We determine type of call arguments
133*38fd1498Szrj     using arguments list from function declaration; if function
134*38fd1498Szrj     declaration is not available we use function type; otherwise
135*38fd1498Szrj     (e.g. for unnamed arguments) we use type of passed value. Function
136*38fd1498Szrj     declaration/type is replaced with the instrumented one.
137*38fd1498Szrj 
138*38fd1498Szrj     Example:
139*38fd1498Szrj 
140*38fd1498Szrj       val_1 = foo (&buf1, &buf2, &buf1, 0);
141*38fd1498Szrj 
142*38fd1498Szrj       is translated into:
143*38fd1498Szrj 
144*38fd1498Szrj       val_1 = foo.chkp (&buf1, __bound_tmp.1_2, &buf2, __bound_tmp.1_3,
145*38fd1498Szrj                         &buf1, __bound_tmp.1_2, 0);
146*38fd1498Szrj 
147*38fd1498Szrj     e) Returns.
148*38fd1498Szrj 
149*38fd1498Szrj     If function returns a pointer value we have to return bounds also.
150*38fd1498Szrj     A new operand was added for return statement to hold returned bounds.
151*38fd1498Szrj 
152*38fd1498Szrj     Example:
153*38fd1498Szrj 
154*38fd1498Szrj       return &_buf1;
155*38fd1498Szrj 
156*38fd1498Szrj       is transformed into
157*38fd1498Szrj 
158*38fd1498Szrj       return &_buf1, __bound_tmp.1_1;
159*38fd1498Szrj 
160*38fd1498Szrj     3. Bounds computation.
161*38fd1498Szrj 
162*38fd1498Szrj     Compiler is fully responsible for computing bounds to be used for each
163*38fd1498Szrj     memory access.  The first step for bounds computation is to find the
164*38fd1498Szrj     origin of pointer dereferenced for memory access.  Basing on pointer
165*38fd1498Szrj     origin we define a way to compute its bounds.  There are just few
166*38fd1498Szrj     possible cases:
167*38fd1498Szrj 
168*38fd1498Szrj     a) Pointer is returned by call.
169*38fd1498Szrj 
170*38fd1498Szrj     In this case we use corresponding checker builtin method to obtain returned
171*38fd1498Szrj     bounds.
172*38fd1498Szrj 
173*38fd1498Szrj     Example:
174*38fd1498Szrj 
175*38fd1498Szrj       buf_1 = malloc (size_2);
176*38fd1498Szrj       foo (buf_1);
177*38fd1498Szrj 
178*38fd1498Szrj       is translated into:
179*38fd1498Szrj 
180*38fd1498Szrj       buf_1 = malloc (size_2);
181*38fd1498Szrj       __bound_tmp.1_3 = __builtin___chkp_bndret (buf_1);
182*38fd1498Szrj       foo (buf_1, __bound_tmp.1_3);
183*38fd1498Szrj 
184*38fd1498Szrj     b) Pointer is an address of an object.
185*38fd1498Szrj 
186*38fd1498Szrj     In this case compiler tries to compute objects size and create corresponding
187*38fd1498Szrj     bounds.  If object has incomplete type then special checker builtin is used to
188*38fd1498Szrj     obtain its size at runtime.
189*38fd1498Szrj 
190*38fd1498Szrj     Example:
191*38fd1498Szrj 
192*38fd1498Szrj       foo ()
193*38fd1498Szrj       {
194*38fd1498Szrj         <unnamed type> __bound_tmp.3;
195*38fd1498Szrj 	static int buf[100];
196*38fd1498Szrj 
197*38fd1498Szrj 	<bb 3>:
198*38fd1498Szrj 	__bound_tmp.3_2 = __builtin___chkp_bndmk (&buf, 400);
199*38fd1498Szrj 
200*38fd1498Szrj 	<bb 2>:
201*38fd1498Szrj 	return &buf, __bound_tmp.3_2;
202*38fd1498Szrj       }
203*38fd1498Szrj 
204*38fd1498Szrj     Example:
205*38fd1498Szrj 
206*38fd1498Szrj       Address of an object 'extern int buf[]' with incomplete type is
207*38fd1498Szrj       returned.
208*38fd1498Szrj 
209*38fd1498Szrj       foo ()
210*38fd1498Szrj       {
211*38fd1498Szrj         <unnamed type> __bound_tmp.4;
212*38fd1498Szrj 	long unsigned int __size_tmp.3;
213*38fd1498Szrj 
214*38fd1498Szrj 	<bb 3>:
215*38fd1498Szrj 	__size_tmp.3_4 = __builtin_ia32_sizeof (buf);
216*38fd1498Szrj 	__bound_tmp.4_3 = __builtin_ia32_bndmk (&buf, __size_tmp.3_4);
217*38fd1498Szrj 
218*38fd1498Szrj 	<bb 2>:
219*38fd1498Szrj 	return &buf, __bound_tmp.4_3;
220*38fd1498Szrj       }
221*38fd1498Szrj 
222*38fd1498Szrj     c) Pointer is the result of object narrowing.
223*38fd1498Szrj 
224*38fd1498Szrj     It happens when we use pointer to an object to compute pointer to a part
225*38fd1498Szrj     of an object.  E.g. we take pointer to a field of a structure. In this
226*38fd1498Szrj     case we perform bounds intersection using bounds of original object and
227*38fd1498Szrj     bounds of object's part (which are computed basing on its type).
228*38fd1498Szrj 
229*38fd1498Szrj     There may be some debatable questions about when narrowing should occur
230*38fd1498Szrj     and when it should not.  To avoid false bound violations in correct
231*38fd1498Szrj     programs we do not perform narrowing when address of an array element is
232*38fd1498Szrj     obtained (it has address of the whole array) and when address of the first
233*38fd1498Szrj     structure field is obtained (because it is guaranteed to be equal to
234*38fd1498Szrj     address of the whole structure and it is legal to cast it back to structure).
235*38fd1498Szrj 
236*38fd1498Szrj     Default narrowing behavior may be changed using compiler flags.
237*38fd1498Szrj 
238*38fd1498Szrj     Example:
239*38fd1498Szrj 
240*38fd1498Szrj       In this example address of the second structure field is returned.
241*38fd1498Szrj 
242*38fd1498Szrj       foo (struct A * p, __bounds_type __bounds_of_p)
243*38fd1498Szrj       {
244*38fd1498Szrj         <unnamed type> __bound_tmp.3;
245*38fd1498Szrj 	int * _2;
246*38fd1498Szrj 	int * _5;
247*38fd1498Szrj 
248*38fd1498Szrj 	<bb 2>:
249*38fd1498Szrj 	_5 = &p_1(D)->second_field;
250*38fd1498Szrj 	__bound_tmp.3_6 = __builtin___chkp_bndmk (_5, 4);
251*38fd1498Szrj 	__bound_tmp.3_8 = __builtin___chkp_intersect (__bound_tmp.3_6,
252*38fd1498Szrj 	                                              __bounds_of_p_3(D));
253*38fd1498Szrj 	_2 = &p_1(D)->second_field;
254*38fd1498Szrj 	return _2, __bound_tmp.3_8;
255*38fd1498Szrj       }
256*38fd1498Szrj 
257*38fd1498Szrj     Example:
258*38fd1498Szrj 
259*38fd1498Szrj       In this example address of the first field of array element is returned.
260*38fd1498Szrj 
261*38fd1498Szrj       foo (struct A * p, __bounds_type __bounds_of_p, int i)
262*38fd1498Szrj       {
263*38fd1498Szrj 	long unsigned int _3;
264*38fd1498Szrj 	long unsigned int _4;
265*38fd1498Szrj 	struct A * _6;
266*38fd1498Szrj 	int * _7;
267*38fd1498Szrj 
268*38fd1498Szrj 	<bb 2>:
269*38fd1498Szrj 	_3 = (long unsigned int) i_1(D);
270*38fd1498Szrj 	_4 = _3 * 8;
271*38fd1498Szrj 	_6 = p_5(D) + _4;
272*38fd1498Szrj 	_7 = &_6->first_field;
273*38fd1498Szrj 	return _7, __bounds_of_p_2(D);
274*38fd1498Szrj       }
275*38fd1498Szrj 
276*38fd1498Szrj 
277*38fd1498Szrj     d) Pointer is the result of pointer arithmetic or type cast.
278*38fd1498Szrj 
279*38fd1498Szrj     In this case bounds of the base pointer are used.  In case of binary
280*38fd1498Szrj     operation producing a pointer we are analyzing data flow further
281*38fd1498Szrj     looking for operand's bounds.  One operand is considered as a base
282*38fd1498Szrj     if it has some valid bounds.  If we fall into a case when none of
283*38fd1498Szrj     operands (or both of them) has valid bounds, a default bounds value
284*38fd1498Szrj     is used.
285*38fd1498Szrj 
286*38fd1498Szrj     Trying to find out bounds for binary operations we may fall into
287*38fd1498Szrj     cyclic dependencies for pointers.  To avoid infinite recursion all
288*38fd1498Szrj     walked phi nodes instantly obtain corresponding bounds but created
289*38fd1498Szrj     bounds are marked as incomplete.  It helps us to stop DF walk during
290*38fd1498Szrj     bounds search.
291*38fd1498Szrj 
292*38fd1498Szrj     When we reach pointer source, some args of incomplete bounds phi obtain
293*38fd1498Szrj     valid bounds and those values are propagated further through phi nodes.
294*38fd1498Szrj     If no valid bounds were found for phi node then we mark its result as
295*38fd1498Szrj     invalid bounds.  Process stops when all incomplete bounds become either
296*38fd1498Szrj     valid or invalid and we are able to choose a pointer base.
297*38fd1498Szrj 
298*38fd1498Szrj     e) Pointer is loaded from the memory.
299*38fd1498Szrj 
300*38fd1498Szrj     In this case we just need to load bounds from the bounds table.
301*38fd1498Szrj 
302*38fd1498Szrj     Example:
303*38fd1498Szrj 
304*38fd1498Szrj       foo ()
305*38fd1498Szrj       {
306*38fd1498Szrj         <unnamed type> __bound_tmp.3;
307*38fd1498Szrj 	static int * buf;
308*38fd1498Szrj 	int * _2;
309*38fd1498Szrj 
310*38fd1498Szrj 	<bb 2>:
311*38fd1498Szrj 	_2 = buf;
312*38fd1498Szrj 	__bound_tmp.3_4 = __builtin___chkp_bndldx (&buf, _2);
313*38fd1498Szrj 	return _2, __bound_tmp.3_4;
314*38fd1498Szrj       }
315*38fd1498Szrj 
316*38fd1498Szrj */
317*38fd1498Szrj 
318*38fd1498Szrj typedef void (*assign_handler)(tree, tree, void *);
319*38fd1498Szrj 
320*38fd1498Szrj static tree chkp_get_zero_bounds ();
321*38fd1498Szrj static tree chkp_find_bounds (tree ptr, gimple_stmt_iterator *iter);
322*38fd1498Szrj static tree chkp_find_bounds_loaded (tree ptr, tree ptr_src,
323*38fd1498Szrj 				     gimple_stmt_iterator *iter);
324*38fd1498Szrj static void chkp_parse_array_and_component_ref (tree node, tree *ptr,
325*38fd1498Szrj 						tree *elt, bool *safe,
326*38fd1498Szrj 						bool *bitfield,
327*38fd1498Szrj 						tree *bounds,
328*38fd1498Szrj 						gimple_stmt_iterator *iter,
329*38fd1498Szrj 						bool innermost_bounds);
330*38fd1498Szrj static void chkp_parse_bit_field_ref (tree node, location_t loc,
331*38fd1498Szrj 				      tree *offset, tree *size);
332*38fd1498Szrj static tree
333*38fd1498Szrj chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter);
334*38fd1498Szrj 
335*38fd1498Szrj #define chkp_bndldx_fndecl \
336*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDLDX))
337*38fd1498Szrj #define chkp_bndstx_fndecl \
338*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDSTX))
339*38fd1498Szrj #define chkp_checkl_fndecl \
340*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCL))
341*38fd1498Szrj #define chkp_checku_fndecl \
342*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDCU))
343*38fd1498Szrj #define chkp_bndmk_fndecl \
344*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDMK))
345*38fd1498Szrj #define chkp_ret_bnd_fndecl \
346*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET))
347*38fd1498Szrj #define chkp_intersect_fndecl \
348*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_INTERSECT))
349*38fd1498Szrj #define chkp_narrow_bounds_fndecl \
350*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_NARROW))
351*38fd1498Szrj #define chkp_sizeof_fndecl \
352*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_SIZEOF))
353*38fd1498Szrj #define chkp_extract_lower_fndecl \
354*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_LOWER))
355*38fd1498Szrj #define chkp_extract_upper_fndecl \
356*38fd1498Szrj   (targetm.builtin_chkp_function (BUILT_IN_CHKP_EXTRACT_UPPER))
357*38fd1498Szrj 
358*38fd1498Szrj static GTY (()) tree chkp_uintptr_type;
359*38fd1498Szrj 
360*38fd1498Szrj static GTY (()) tree chkp_zero_bounds_var;
361*38fd1498Szrj static GTY (()) tree chkp_none_bounds_var;
362*38fd1498Szrj 
363*38fd1498Szrj static GTY (()) basic_block entry_block;
364*38fd1498Szrj static GTY (()) tree zero_bounds;
365*38fd1498Szrj static GTY (()) tree none_bounds;
366*38fd1498Szrj static GTY (()) tree incomplete_bounds;
367*38fd1498Szrj static GTY (()) tree tmp_var;
368*38fd1498Szrj static GTY (()) tree size_tmp_var;
369*38fd1498Szrj static GTY (()) bitmap chkp_abnormal_copies;
370*38fd1498Szrj 
371*38fd1498Szrj struct hash_set<tree> *chkp_invalid_bounds;
372*38fd1498Szrj struct hash_set<tree> *chkp_completed_bounds_set;
373*38fd1498Szrj struct hash_map<tree, tree> *chkp_reg_bounds;
374*38fd1498Szrj struct hash_map<tree, tree> *chkp_bound_vars;
375*38fd1498Szrj struct hash_map<tree, tree> *chkp_reg_addr_bounds;
376*38fd1498Szrj struct hash_map<tree, tree> *chkp_incomplete_bounds_map;
377*38fd1498Szrj struct hash_map<tree, tree> *chkp_bounds_map;
378*38fd1498Szrj struct hash_map<tree, tree> *chkp_static_var_bounds;
379*38fd1498Szrj 
380*38fd1498Szrj static bool in_chkp_pass;
381*38fd1498Szrj 
382*38fd1498Szrj #define CHKP_BOUND_TMP_NAME "__bound_tmp"
383*38fd1498Szrj #define CHKP_SIZE_TMP_NAME "__size_tmp"
384*38fd1498Szrj #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
385*38fd1498Szrj #define CHKP_STRING_BOUNDS_PREFIX "__chkp_string_bounds_"
386*38fd1498Szrj #define CHKP_VAR_BOUNDS_PREFIX "__chkp_var_bounds_"
387*38fd1498Szrj #define CHKP_ZERO_BOUNDS_VAR_NAME "__chkp_zero_bounds"
388*38fd1498Szrj #define CHKP_NONE_BOUNDS_VAR_NAME "__chkp_none_bounds"
389*38fd1498Szrj 
390*38fd1498Szrj /* Static checker constructors may become very large and their
391*38fd1498Szrj    compilation with optimization may take too much time.
392*38fd1498Szrj    Therefore we put a limit to number of statements in one
393*38fd1498Szrj    constructor.  Tests with 100 000 statically initialized
394*38fd1498Szrj    pointers showed following compilation times on Sandy Bridge
395*38fd1498Szrj    server (used -O2):
396*38fd1498Szrj    limit    100 => ~18 sec.
397*38fd1498Szrj    limit    300 => ~22 sec.
398*38fd1498Szrj    limit   1000 => ~30 sec.
399*38fd1498Szrj    limit   3000 => ~49 sec.
400*38fd1498Szrj    limit   5000 => ~55 sec.
401*38fd1498Szrj    limit  10000 => ~76 sec.
402*38fd1498Szrj    limit 100000 => ~532 sec.  */
403*38fd1498Szrj #define MAX_STMTS_IN_STATIC_CHKP_CTOR (PARAM_VALUE (PARAM_CHKP_MAX_CTOR_SIZE))
404*38fd1498Szrj 
405*38fd1498Szrj struct chkp_ctor_stmt_list
406*38fd1498Szrj {
407*38fd1498Szrj   tree stmts;
408*38fd1498Szrj   int avail;
409*38fd1498Szrj };
410*38fd1498Szrj 
411*38fd1498Szrj /* Return 1 if function FNDECL is instrumented by Pointer
412*38fd1498Szrj    Bounds Checker.  */
413*38fd1498Szrj bool
414*38fd1498Szrj chkp_function_instrumented_p (tree fndecl)
415*38fd1498Szrj {
416*38fd1498Szrj   return fndecl
417*38fd1498Szrj     && lookup_attribute ("chkp instrumented", DECL_ATTRIBUTES (fndecl));
418*38fd1498Szrj }
419*38fd1498Szrj 
420*38fd1498Szrj /* Mark function FNDECL as instrumented.  */
421*38fd1498Szrj void
422*38fd1498Szrj chkp_function_mark_instrumented (tree fndecl)
423*38fd1498Szrj {
424*38fd1498Szrj   if (chkp_function_instrumented_p (fndecl))
425*38fd1498Szrj     return;
426*38fd1498Szrj 
427*38fd1498Szrj   DECL_ATTRIBUTES (fndecl)
428*38fd1498Szrj     = tree_cons (get_identifier ("chkp instrumented"), NULL,
429*38fd1498Szrj 		 DECL_ATTRIBUTES (fndecl));
430*38fd1498Szrj }
431*38fd1498Szrj 
432*38fd1498Szrj /* Return true when STMT is builtin call to instrumentation function
433*38fd1498Szrj    corresponding to CODE.  */
434*38fd1498Szrj 
435*38fd1498Szrj bool
436*38fd1498Szrj chkp_gimple_call_builtin_p (gimple *call,
437*38fd1498Szrj 			    enum built_in_function code)
438*38fd1498Szrj {
439*38fd1498Szrj   tree fndecl;
440*38fd1498Szrj   /* We are skipping the check for address-spaces, that's
441*38fd1498Szrj      why we don't use gimple_call_builtin_p directly here.  */
442*38fd1498Szrj   if (is_gimple_call (call)
443*38fd1498Szrj       && (fndecl = gimple_call_fndecl (call)) != NULL
444*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD
445*38fd1498Szrj       && (fndecl = targetm.builtin_chkp_function (code))
446*38fd1498Szrj       && (DECL_FUNCTION_CODE (gimple_call_fndecl (call))
447*38fd1498Szrj 	  == DECL_FUNCTION_CODE (fndecl)))
448*38fd1498Szrj     return true;
449*38fd1498Szrj   return false;
450*38fd1498Szrj }
451*38fd1498Szrj 
452*38fd1498Szrj /* Emit code to build zero bounds and return RTL holding
453*38fd1498Szrj    the result.  */
454*38fd1498Szrj rtx
455*38fd1498Szrj chkp_expand_zero_bounds ()
456*38fd1498Szrj {
457*38fd1498Szrj   tree zero_bnd;
458*38fd1498Szrj 
459*38fd1498Szrj   if (flag_chkp_use_static_const_bounds)
460*38fd1498Szrj     zero_bnd = chkp_get_zero_bounds_var ();
461*38fd1498Szrj   else
462*38fd1498Szrj     zero_bnd = chkp_build_make_bounds_call (integer_zero_node,
463*38fd1498Szrj 					    integer_zero_node);
464*38fd1498Szrj   return expand_normal (zero_bnd);
465*38fd1498Szrj }
466*38fd1498Szrj 
467*38fd1498Szrj /* Emit code to store zero bounds for PTR located at MEM.  */
468*38fd1498Szrj void
469*38fd1498Szrj chkp_expand_bounds_reset_for_mem (tree mem, tree ptr)
470*38fd1498Szrj {
471*38fd1498Szrj   tree zero_bnd, bnd, addr, bndstx;
472*38fd1498Szrj 
473*38fd1498Szrj   if (flag_chkp_use_static_const_bounds)
474*38fd1498Szrj     zero_bnd = chkp_get_zero_bounds_var ();
475*38fd1498Szrj   else
476*38fd1498Szrj     zero_bnd = chkp_build_make_bounds_call (integer_zero_node,
477*38fd1498Szrj 					    integer_zero_node);
478*38fd1498Szrj   bnd = make_tree (pointer_bounds_type_node,
479*38fd1498Szrj 		   assign_temp (pointer_bounds_type_node, 0, 1));
480*38fd1498Szrj   addr = build1 (ADDR_EXPR,
481*38fd1498Szrj 		 build_pointer_type (TREE_TYPE (mem)), mem);
482*38fd1498Szrj   bndstx = chkp_build_bndstx_call (addr, ptr, bnd);
483*38fd1498Szrj 
484*38fd1498Szrj   expand_assignment (bnd, zero_bnd, false);
485*38fd1498Szrj   expand_normal (bndstx);
486*38fd1498Szrj }
487*38fd1498Szrj 
488*38fd1498Szrj /* Build retbnd call for returned value RETVAL.
489*38fd1498Szrj 
490*38fd1498Szrj    If BNDVAL is not NULL then result is stored
491*38fd1498Szrj    in it.  Otherwise a temporary is created to
492*38fd1498Szrj    hold returned value.
493*38fd1498Szrj 
494*38fd1498Szrj    GSI points to a position for a retbnd call
495*38fd1498Szrj    and is set to created stmt.
496*38fd1498Szrj 
497*38fd1498Szrj    Cgraph edge is created for a new call if
498*38fd1498Szrj    UPDATE_EDGE is 1.
499*38fd1498Szrj 
500*38fd1498Szrj    Obtained bounds are returned.  */
501*38fd1498Szrj tree
502*38fd1498Szrj chkp_insert_retbnd_call (tree bndval, tree retval,
503*38fd1498Szrj 			 gimple_stmt_iterator *gsi)
504*38fd1498Szrj {
505*38fd1498Szrj   gimple *call;
506*38fd1498Szrj 
507*38fd1498Szrj   if (!bndval)
508*38fd1498Szrj     bndval = create_tmp_reg (pointer_bounds_type_node, "retbnd");
509*38fd1498Szrj 
510*38fd1498Szrj   call = gimple_build_call (chkp_ret_bnd_fndecl, 1, retval);
511*38fd1498Szrj   gimple_call_set_lhs (call, bndval);
512*38fd1498Szrj   gsi_insert_after (gsi, call, GSI_CONTINUE_LINKING);
513*38fd1498Szrj 
514*38fd1498Szrj   return bndval;
515*38fd1498Szrj }
516*38fd1498Szrj 
517*38fd1498Szrj /* Build a GIMPLE_CALL identical to CALL but skipping bounds
518*38fd1498Szrj    arguments.  */
519*38fd1498Szrj 
520*38fd1498Szrj gcall *
521*38fd1498Szrj chkp_copy_call_skip_bounds (gcall *call)
522*38fd1498Szrj {
523*38fd1498Szrj   bitmap bounds;
524*38fd1498Szrj   unsigned i;
525*38fd1498Szrj 
526*38fd1498Szrj   bitmap_obstack_initialize (NULL);
527*38fd1498Szrj   bounds = BITMAP_ALLOC (NULL);
528*38fd1498Szrj 
529*38fd1498Szrj   for (i = 0; i < gimple_call_num_args (call); i++)
530*38fd1498Szrj     if (POINTER_BOUNDS_P (gimple_call_arg (call, i)))
531*38fd1498Szrj       bitmap_set_bit (bounds, i);
532*38fd1498Szrj 
533*38fd1498Szrj   if (!bitmap_empty_p (bounds))
534*38fd1498Szrj     call = gimple_call_copy_skip_args (call, bounds);
535*38fd1498Szrj   gimple_call_set_with_bounds (call, false);
536*38fd1498Szrj 
537*38fd1498Szrj   BITMAP_FREE (bounds);
538*38fd1498Szrj   bitmap_obstack_release (NULL);
539*38fd1498Szrj 
540*38fd1498Szrj   return call;
541*38fd1498Szrj }
542*38fd1498Szrj 
543*38fd1498Szrj /* Redirect edge E to the correct node according to call_stmt.
544*38fd1498Szrj    Return 1 if bounds removal from call_stmt should be done
545*38fd1498Szrj    instead of redirection.  */
546*38fd1498Szrj 
547*38fd1498Szrj bool
548*38fd1498Szrj chkp_redirect_edge (cgraph_edge *e)
549*38fd1498Szrj {
550*38fd1498Szrj   bool instrumented = false;
551*38fd1498Szrj   tree decl = e->callee->decl;
552*38fd1498Szrj 
553*38fd1498Szrj   if (e->callee->instrumentation_clone
554*38fd1498Szrj       || chkp_function_instrumented_p (decl))
555*38fd1498Szrj     instrumented = true;
556*38fd1498Szrj 
557*38fd1498Szrj   if (instrumented
558*38fd1498Szrj       && !gimple_call_with_bounds_p (e->call_stmt))
559*38fd1498Szrj     e->redirect_callee (cgraph_node::get_create (e->callee->orig_decl));
560*38fd1498Szrj   else if (!instrumented
561*38fd1498Szrj 	   && gimple_call_with_bounds_p (e->call_stmt)
562*38fd1498Szrj 	   && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCL)
563*38fd1498Szrj 	   && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDCU)
564*38fd1498Szrj 	   && !chkp_gimple_call_builtin_p (e->call_stmt, BUILT_IN_CHKP_BNDSTX))
565*38fd1498Szrj     {
566*38fd1498Szrj       if (e->callee->instrumented_version)
567*38fd1498Szrj 	e->redirect_callee (e->callee->instrumented_version);
568*38fd1498Szrj       else
569*38fd1498Szrj 	{
570*38fd1498Szrj 	  tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
571*38fd1498Szrj 	  /* Avoid bounds removal if all args will be removed.  */
572*38fd1498Szrj 	  if (!args || TREE_VALUE (args) != void_type_node)
573*38fd1498Szrj 	    return true;
574*38fd1498Szrj 	  else
575*38fd1498Szrj 	    gimple_call_set_with_bounds (e->call_stmt, false);
576*38fd1498Szrj 	}
577*38fd1498Szrj     }
578*38fd1498Szrj 
579*38fd1498Szrj   return false;
580*38fd1498Szrj }
581*38fd1498Szrj 
582*38fd1498Szrj /* Mark statement S to not be instrumented.  */
583*38fd1498Szrj static void
584*38fd1498Szrj chkp_mark_stmt (gimple *s)
585*38fd1498Szrj {
586*38fd1498Szrj   gimple_set_plf (s, GF_PLF_1, true);
587*38fd1498Szrj }
588*38fd1498Szrj 
589*38fd1498Szrj /* Mark statement S to be instrumented.  */
590*38fd1498Szrj static void
591*38fd1498Szrj chkp_unmark_stmt (gimple *s)
592*38fd1498Szrj {
593*38fd1498Szrj   gimple_set_plf (s, GF_PLF_1, false);
594*38fd1498Szrj }
595*38fd1498Szrj 
596*38fd1498Szrj /* Return 1 if statement S should not be instrumented.  */
597*38fd1498Szrj static bool
598*38fd1498Szrj chkp_marked_stmt_p (gimple *s)
599*38fd1498Szrj {
600*38fd1498Szrj   return gimple_plf (s, GF_PLF_1);
601*38fd1498Szrj }
602*38fd1498Szrj 
603*38fd1498Szrj /* Get var to be used for bound temps.  */
604*38fd1498Szrj static tree
605*38fd1498Szrj chkp_get_tmp_var (void)
606*38fd1498Szrj {
607*38fd1498Szrj   if (!tmp_var)
608*38fd1498Szrj     tmp_var = create_tmp_reg (pointer_bounds_type_node, CHKP_BOUND_TMP_NAME);
609*38fd1498Szrj 
610*38fd1498Szrj   return tmp_var;
611*38fd1498Szrj }
612*38fd1498Szrj 
613*38fd1498Szrj /* Get SSA_NAME to be used as temp.  */
614*38fd1498Szrj static tree
615*38fd1498Szrj chkp_get_tmp_reg (gimple *stmt)
616*38fd1498Szrj {
617*38fd1498Szrj   if (in_chkp_pass)
618*38fd1498Szrj     return make_ssa_name (chkp_get_tmp_var (), stmt);
619*38fd1498Szrj 
620*38fd1498Szrj   return make_temp_ssa_name (pointer_bounds_type_node, stmt,
621*38fd1498Szrj 			     CHKP_BOUND_TMP_NAME);
622*38fd1498Szrj }
623*38fd1498Szrj 
624*38fd1498Szrj /* Get var to be used for size temps.  */
625*38fd1498Szrj static tree
626*38fd1498Szrj chkp_get_size_tmp_var (void)
627*38fd1498Szrj {
628*38fd1498Szrj   if (!size_tmp_var)
629*38fd1498Szrj     size_tmp_var = create_tmp_reg (chkp_uintptr_type, CHKP_SIZE_TMP_NAME);
630*38fd1498Szrj 
631*38fd1498Szrj   return size_tmp_var;
632*38fd1498Szrj }
633*38fd1498Szrj 
634*38fd1498Szrj /* Register bounds BND for address of OBJ.  */
635*38fd1498Szrj static void
636*38fd1498Szrj chkp_register_addr_bounds (tree obj, tree bnd)
637*38fd1498Szrj {
638*38fd1498Szrj   if (bnd == incomplete_bounds)
639*38fd1498Szrj     return;
640*38fd1498Szrj 
641*38fd1498Szrj   chkp_reg_addr_bounds->put (obj, bnd);
642*38fd1498Szrj 
643*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
644*38fd1498Szrj     {
645*38fd1498Szrj       fprintf (dump_file, "Regsitered bound ");
646*38fd1498Szrj       print_generic_expr (dump_file, bnd);
647*38fd1498Szrj       fprintf (dump_file, " for address of ");
648*38fd1498Szrj       print_generic_expr (dump_file, obj);
649*38fd1498Szrj       fprintf (dump_file, "\n");
650*38fd1498Szrj     }
651*38fd1498Szrj }
652*38fd1498Szrj 
653*38fd1498Szrj /* Return bounds registered for address of OBJ.  */
654*38fd1498Szrj static tree
655*38fd1498Szrj chkp_get_registered_addr_bounds (tree obj)
656*38fd1498Szrj {
657*38fd1498Szrj   tree *slot = chkp_reg_addr_bounds->get (obj);
658*38fd1498Szrj   return slot ? *slot : NULL_TREE;
659*38fd1498Szrj }
660*38fd1498Szrj 
661*38fd1498Szrj /* Mark BOUNDS as completed.  */
662*38fd1498Szrj static void
663*38fd1498Szrj chkp_mark_completed_bounds (tree bounds)
664*38fd1498Szrj {
665*38fd1498Szrj   chkp_completed_bounds_set->add (bounds);
666*38fd1498Szrj 
667*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
668*38fd1498Szrj     {
669*38fd1498Szrj       fprintf (dump_file, "Marked bounds ");
670*38fd1498Szrj       print_generic_expr (dump_file, bounds);
671*38fd1498Szrj       fprintf (dump_file, " as completed\n");
672*38fd1498Szrj     }
673*38fd1498Szrj }
674*38fd1498Szrj 
675*38fd1498Szrj /* Return 1 if BOUNDS were marked as completed and 0 otherwise.  */
676*38fd1498Szrj static bool
677*38fd1498Szrj chkp_completed_bounds (tree bounds)
678*38fd1498Szrj {
679*38fd1498Szrj   return chkp_completed_bounds_set->contains (bounds);
680*38fd1498Szrj }
681*38fd1498Szrj 
682*38fd1498Szrj /* Clear comleted bound marks.  */
683*38fd1498Szrj static void
684*38fd1498Szrj chkp_erase_completed_bounds (void)
685*38fd1498Szrj {
686*38fd1498Szrj   delete chkp_completed_bounds_set;
687*38fd1498Szrj   chkp_completed_bounds_set = new hash_set<tree>;
688*38fd1498Szrj }
689*38fd1498Szrj 
690*38fd1498Szrj /* This function is used to provide a base address for
691*38fd1498Szrj    chkp_get_hard_register_fake_addr_expr.  */
692*38fd1498Szrj static tree
693*38fd1498Szrj chkp_get_hard_register_var_fake_base_address ()
694*38fd1498Szrj {
695*38fd1498Szrj   int prec = TYPE_PRECISION (ptr_type_node);
696*38fd1498Szrj   return wide_int_to_tree (ptr_type_node, wi::min_value (prec, SIGNED));
697*38fd1498Szrj }
698*38fd1498Szrj 
699*38fd1498Szrj /* If we check bounds for a hard register variable, we cannot
700*38fd1498Szrj    use its address - it is illegal, so instead of that we use
701*38fd1498Szrj    this fake value.  */
702*38fd1498Szrj static tree
703*38fd1498Szrj chkp_get_hard_register_fake_addr_expr (tree obj)
704*38fd1498Szrj {
705*38fd1498Szrj   tree addr = chkp_get_hard_register_var_fake_base_address ();
706*38fd1498Szrj   tree outer = obj;
707*38fd1498Szrj   while (TREE_CODE (outer) == COMPONENT_REF || TREE_CODE (outer) == ARRAY_REF)
708*38fd1498Szrj     {
709*38fd1498Szrj       if (TREE_CODE (outer) == COMPONENT_REF)
710*38fd1498Szrj 	{
711*38fd1498Szrj 	  addr = fold_build_pointer_plus (addr,
712*38fd1498Szrj 					  component_ref_field_offset (outer));
713*38fd1498Szrj 	  outer = TREE_OPERAND (outer, 0);
714*38fd1498Szrj 	}
715*38fd1498Szrj       else if (TREE_CODE (outer) == ARRAY_REF)
716*38fd1498Szrj 	{
717*38fd1498Szrj 	  tree indx = fold_convert(size_type_node, TREE_OPERAND(outer, 1));
718*38fd1498Szrj 	  tree offset = size_binop (MULT_EXPR,
719*38fd1498Szrj 				    array_ref_element_size (outer), indx);
720*38fd1498Szrj 	  addr = fold_build_pointer_plus (addr, offset);
721*38fd1498Szrj 	  outer = TREE_OPERAND (outer, 0);
722*38fd1498Szrj 	}
723*38fd1498Szrj     }
724*38fd1498Szrj 
725*38fd1498Szrj   return addr;
726*38fd1498Szrj }
727*38fd1498Szrj 
728*38fd1498Szrj /* Mark BOUNDS associated with PTR as incomplete.  */
729*38fd1498Szrj static void
730*38fd1498Szrj chkp_register_incomplete_bounds (tree bounds, tree ptr)
731*38fd1498Szrj {
732*38fd1498Szrj   chkp_incomplete_bounds_map->put (bounds, ptr);
733*38fd1498Szrj 
734*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
735*38fd1498Szrj     {
736*38fd1498Szrj       fprintf (dump_file, "Regsitered incomplete bounds ");
737*38fd1498Szrj       print_generic_expr (dump_file, bounds);
738*38fd1498Szrj       fprintf (dump_file, " for ");
739*38fd1498Szrj       print_generic_expr (dump_file, ptr);
740*38fd1498Szrj       fprintf (dump_file, "\n");
741*38fd1498Szrj     }
742*38fd1498Szrj }
743*38fd1498Szrj 
744*38fd1498Szrj /* Return 1 if BOUNDS are incomplete and 0 otherwise.  */
745*38fd1498Szrj static bool
746*38fd1498Szrj chkp_incomplete_bounds (tree bounds)
747*38fd1498Szrj {
748*38fd1498Szrj   if (bounds == incomplete_bounds)
749*38fd1498Szrj     return true;
750*38fd1498Szrj 
751*38fd1498Szrj   if (chkp_completed_bounds (bounds))
752*38fd1498Szrj     return false;
753*38fd1498Szrj 
754*38fd1498Szrj   return chkp_incomplete_bounds_map->get (bounds) != NULL;
755*38fd1498Szrj }
756*38fd1498Szrj 
757*38fd1498Szrj /* Clear incomleted bound marks.  */
758*38fd1498Szrj static void
759*38fd1498Szrj chkp_erase_incomplete_bounds (void)
760*38fd1498Szrj {
761*38fd1498Szrj   delete chkp_incomplete_bounds_map;
762*38fd1498Szrj   chkp_incomplete_bounds_map = new hash_map<tree, tree>;
763*38fd1498Szrj }
764*38fd1498Szrj 
765*38fd1498Szrj /* Build and return bndmk call which creates bounds for structure
766*38fd1498Szrj    pointed by PTR.  Structure should have complete type.  */
767*38fd1498Szrj tree
768*38fd1498Szrj chkp_make_bounds_for_struct_addr (tree ptr)
769*38fd1498Szrj {
770*38fd1498Szrj   tree type = TREE_TYPE (ptr);
771*38fd1498Szrj   tree size;
772*38fd1498Szrj 
773*38fd1498Szrj   gcc_assert (POINTER_TYPE_P (type));
774*38fd1498Szrj 
775*38fd1498Szrj   size = TYPE_SIZE (TREE_TYPE (type));
776*38fd1498Szrj 
777*38fd1498Szrj   gcc_assert (size);
778*38fd1498Szrj 
779*38fd1498Szrj   return build_call_nary (pointer_bounds_type_node,
780*38fd1498Szrj 			  build_fold_addr_expr (chkp_bndmk_fndecl),
781*38fd1498Szrj 			  2, ptr, size);
782*38fd1498Szrj }
783*38fd1498Szrj 
784*38fd1498Szrj /* Traversal function for chkp_may_finish_incomplete_bounds.
785*38fd1498Szrj    Set RES to 0 if at least one argument of phi statement
786*38fd1498Szrj    defining bounds (passed in KEY arg) is unknown.
787*38fd1498Szrj    Traversal stops when first unknown phi argument is found.  */
788*38fd1498Szrj bool
789*38fd1498Szrj chkp_may_complete_phi_bounds (tree const &bounds, tree *slot ATTRIBUTE_UNUSED,
790*38fd1498Szrj 			      bool *res)
791*38fd1498Szrj {
792*38fd1498Szrj   gimple *phi;
793*38fd1498Szrj   unsigned i;
794*38fd1498Szrj 
795*38fd1498Szrj   gcc_assert (TREE_CODE (bounds) == SSA_NAME);
796*38fd1498Szrj 
797*38fd1498Szrj   phi = SSA_NAME_DEF_STMT (bounds);
798*38fd1498Szrj 
799*38fd1498Szrj   gcc_assert (phi && gimple_code (phi) == GIMPLE_PHI);
800*38fd1498Szrj 
801*38fd1498Szrj   for (i = 0; i < gimple_phi_num_args (phi); i++)
802*38fd1498Szrj     {
803*38fd1498Szrj       tree phi_arg = gimple_phi_arg_def (phi, i);
804*38fd1498Szrj       if (!phi_arg)
805*38fd1498Szrj 	{
806*38fd1498Szrj 	  *res = false;
807*38fd1498Szrj 	  /* Do not need to traverse further.  */
808*38fd1498Szrj 	  return false;
809*38fd1498Szrj 	}
810*38fd1498Szrj     }
811*38fd1498Szrj 
812*38fd1498Szrj   return true;
813*38fd1498Szrj }
814*38fd1498Szrj 
815*38fd1498Szrj /* Return 1 if all phi nodes created for bounds have their
816*38fd1498Szrj    arguments computed.  */
817*38fd1498Szrj static bool
818*38fd1498Szrj chkp_may_finish_incomplete_bounds (void)
819*38fd1498Szrj {
820*38fd1498Szrj   bool res = true;
821*38fd1498Szrj 
822*38fd1498Szrj   chkp_incomplete_bounds_map
823*38fd1498Szrj     ->traverse<bool *, chkp_may_complete_phi_bounds> (&res);
824*38fd1498Szrj 
825*38fd1498Szrj   return res;
826*38fd1498Szrj }
827*38fd1498Szrj 
828*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds.
829*38fd1498Szrj    Recompute args for bounds phi node.  */
830*38fd1498Szrj bool
831*38fd1498Szrj chkp_recompute_phi_bounds (tree const &bounds, tree *slot,
832*38fd1498Szrj 			   void *res ATTRIBUTE_UNUSED)
833*38fd1498Szrj {
834*38fd1498Szrj   tree ptr = *slot;
835*38fd1498Szrj   gphi *bounds_phi;
836*38fd1498Szrj   gphi *ptr_phi;
837*38fd1498Szrj   unsigned i;
838*38fd1498Szrj 
839*38fd1498Szrj   gcc_assert (TREE_CODE (bounds) == SSA_NAME);
840*38fd1498Szrj   gcc_assert (TREE_CODE (ptr) == SSA_NAME);
841*38fd1498Szrj 
842*38fd1498Szrj   bounds_phi = as_a <gphi *> (SSA_NAME_DEF_STMT (bounds));
843*38fd1498Szrj   ptr_phi = as_a <gphi *> (SSA_NAME_DEF_STMT (ptr));
844*38fd1498Szrj 
845*38fd1498Szrj   for (i = 0; i < gimple_phi_num_args (bounds_phi); i++)
846*38fd1498Szrj     {
847*38fd1498Szrj       tree ptr_arg = gimple_phi_arg_def (ptr_phi, i);
848*38fd1498Szrj       tree bound_arg = chkp_find_bounds (ptr_arg, NULL);
849*38fd1498Szrj 
850*38fd1498Szrj       add_phi_arg (bounds_phi, bound_arg,
851*38fd1498Szrj 		   gimple_phi_arg_edge (ptr_phi, i),
852*38fd1498Szrj 		   UNKNOWN_LOCATION);
853*38fd1498Szrj     }
854*38fd1498Szrj 
855*38fd1498Szrj   return true;
856*38fd1498Szrj }
857*38fd1498Szrj 
858*38fd1498Szrj /* Mark BOUNDS as invalid.  */
859*38fd1498Szrj static void
860*38fd1498Szrj chkp_mark_invalid_bounds (tree bounds)
861*38fd1498Szrj {
862*38fd1498Szrj   chkp_invalid_bounds->add (bounds);
863*38fd1498Szrj 
864*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
865*38fd1498Szrj     {
866*38fd1498Szrj       fprintf (dump_file, "Marked bounds ");
867*38fd1498Szrj       print_generic_expr (dump_file, bounds);
868*38fd1498Szrj       fprintf (dump_file, " as invalid\n");
869*38fd1498Szrj     }
870*38fd1498Szrj }
871*38fd1498Szrj 
872*38fd1498Szrj /* Return 1 if BOUNDS were marked as invalid and 0 otherwise.  */
873*38fd1498Szrj static bool
874*38fd1498Szrj chkp_valid_bounds (tree bounds)
875*38fd1498Szrj {
876*38fd1498Szrj   if (bounds == zero_bounds || bounds == none_bounds)
877*38fd1498Szrj     return false;
878*38fd1498Szrj 
879*38fd1498Szrj   return !chkp_invalid_bounds->contains (bounds);
880*38fd1498Szrj }
881*38fd1498Szrj 
882*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds.
883*38fd1498Szrj    Check all arguments of phi nodes trying to find
884*38fd1498Szrj    valid completed bounds.  If there is at least one
885*38fd1498Szrj    such arg then bounds produced by phi node are marked
886*38fd1498Szrj    as valid completed bounds and all phi args are
887*38fd1498Szrj    recomputed.  */
888*38fd1498Szrj bool
889*38fd1498Szrj chkp_find_valid_phi_bounds (tree const &bounds, tree *slot, bool *res)
890*38fd1498Szrj {
891*38fd1498Szrj   gimple *phi;
892*38fd1498Szrj   unsigned i;
893*38fd1498Szrj 
894*38fd1498Szrj   gcc_assert (TREE_CODE (bounds) == SSA_NAME);
895*38fd1498Szrj 
896*38fd1498Szrj   if (chkp_completed_bounds (bounds))
897*38fd1498Szrj     return true;
898*38fd1498Szrj 
899*38fd1498Szrj   phi = SSA_NAME_DEF_STMT (bounds);
900*38fd1498Szrj 
901*38fd1498Szrj   gcc_assert (phi && gimple_code (phi) == GIMPLE_PHI);
902*38fd1498Szrj 
903*38fd1498Szrj   for (i = 0; i < gimple_phi_num_args (phi); i++)
904*38fd1498Szrj     {
905*38fd1498Szrj       tree phi_arg = gimple_phi_arg_def (phi, i);
906*38fd1498Szrj 
907*38fd1498Szrj       gcc_assert (phi_arg);
908*38fd1498Szrj 
909*38fd1498Szrj       if (chkp_valid_bounds (phi_arg) && !chkp_incomplete_bounds (phi_arg))
910*38fd1498Szrj 	{
911*38fd1498Szrj 	  *res = true;
912*38fd1498Szrj 	  chkp_mark_completed_bounds (bounds);
913*38fd1498Szrj 	  chkp_recompute_phi_bounds (bounds, slot, NULL);
914*38fd1498Szrj 	  return true;
915*38fd1498Szrj 	}
916*38fd1498Szrj     }
917*38fd1498Szrj 
918*38fd1498Szrj   return true;
919*38fd1498Szrj }
920*38fd1498Szrj 
921*38fd1498Szrj /* Helper function for chkp_finish_incomplete_bounds.
922*38fd1498Szrj    Marks all incompleted bounds as invalid.  */
923*38fd1498Szrj bool
924*38fd1498Szrj chkp_mark_invalid_bounds_walker (tree const &bounds,
925*38fd1498Szrj 				 tree *slot ATTRIBUTE_UNUSED,
926*38fd1498Szrj 				 void *res ATTRIBUTE_UNUSED)
927*38fd1498Szrj {
928*38fd1498Szrj   if (!chkp_completed_bounds (bounds))
929*38fd1498Szrj     {
930*38fd1498Szrj       chkp_mark_invalid_bounds (bounds);
931*38fd1498Szrj       chkp_mark_completed_bounds (bounds);
932*38fd1498Szrj     }
933*38fd1498Szrj   return true;
934*38fd1498Szrj }
935*38fd1498Szrj 
936*38fd1498Szrj /* When all bound phi nodes have all their args computed
937*38fd1498Szrj    we have enough info to find valid bounds.  We iterate
938*38fd1498Szrj    through all incompleted bounds searching for valid
939*38fd1498Szrj    bounds.  Found valid bounds are marked as completed
940*38fd1498Szrj    and all remaining incompleted bounds are recomputed.
941*38fd1498Szrj    Process continues until no new valid bounds may be
942*38fd1498Szrj    found.  All remained incompleted bounds are marked as
943*38fd1498Szrj    invalid (i.e. have no valid source of bounds).  */
944*38fd1498Szrj static void
945*38fd1498Szrj chkp_finish_incomplete_bounds (void)
946*38fd1498Szrj {
947*38fd1498Szrj   bool found_valid = true;
948*38fd1498Szrj 
949*38fd1498Szrj   while (found_valid)
950*38fd1498Szrj     {
951*38fd1498Szrj       found_valid = false;
952*38fd1498Szrj 
953*38fd1498Szrj       chkp_incomplete_bounds_map->
954*38fd1498Szrj 	traverse<bool *, chkp_find_valid_phi_bounds> (&found_valid);
955*38fd1498Szrj 
956*38fd1498Szrj       if (found_valid)
957*38fd1498Szrj 	chkp_incomplete_bounds_map->
958*38fd1498Szrj 	  traverse<void *, chkp_recompute_phi_bounds> (NULL);
959*38fd1498Szrj     }
960*38fd1498Szrj 
961*38fd1498Szrj   chkp_incomplete_bounds_map->
962*38fd1498Szrj     traverse<void *, chkp_mark_invalid_bounds_walker> (NULL);
963*38fd1498Szrj   chkp_incomplete_bounds_map->
964*38fd1498Szrj     traverse<void *, chkp_recompute_phi_bounds> (NULL);
965*38fd1498Szrj 
966*38fd1498Szrj   chkp_erase_completed_bounds ();
967*38fd1498Szrj   chkp_erase_incomplete_bounds ();
968*38fd1498Szrj }
969*38fd1498Szrj 
970*38fd1498Szrj /* Return 1 if type TYPE is a pointer type or a
971*38fd1498Szrj    structure having a pointer type as one of its fields.
972*38fd1498Szrj    Otherwise return 0.  */
973*38fd1498Szrj bool
974*38fd1498Szrj chkp_type_has_pointer (const_tree type)
975*38fd1498Szrj {
976*38fd1498Szrj   bool res = false;
977*38fd1498Szrj 
978*38fd1498Szrj   if (BOUNDED_TYPE_P (type))
979*38fd1498Szrj     res = true;
980*38fd1498Szrj   else if (RECORD_OR_UNION_TYPE_P (type))
981*38fd1498Szrj     {
982*38fd1498Szrj       tree field;
983*38fd1498Szrj 
984*38fd1498Szrj       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
985*38fd1498Szrj 	if (TREE_CODE (field) == FIELD_DECL)
986*38fd1498Szrj 	  res = res || chkp_type_has_pointer (TREE_TYPE (field));
987*38fd1498Szrj     }
988*38fd1498Szrj   else if (TREE_CODE (type) == ARRAY_TYPE)
989*38fd1498Szrj     res = chkp_type_has_pointer (TREE_TYPE (type));
990*38fd1498Szrj 
991*38fd1498Szrj   return res;
992*38fd1498Szrj }
993*38fd1498Szrj 
994*38fd1498Szrj unsigned
995*38fd1498Szrj chkp_type_bounds_count (const_tree type)
996*38fd1498Szrj {
997*38fd1498Szrj   unsigned res = 0;
998*38fd1498Szrj 
999*38fd1498Szrj   if (!type)
1000*38fd1498Szrj     res = 0;
1001*38fd1498Szrj   else if (BOUNDED_TYPE_P (type))
1002*38fd1498Szrj     res = 1;
1003*38fd1498Szrj   else if (RECORD_OR_UNION_TYPE_P (type))
1004*38fd1498Szrj     {
1005*38fd1498Szrj       bitmap have_bound;
1006*38fd1498Szrj 
1007*38fd1498Szrj       bitmap_obstack_initialize (NULL);
1008*38fd1498Szrj       have_bound = BITMAP_ALLOC (NULL);
1009*38fd1498Szrj       chkp_find_bound_slots (type, have_bound);
1010*38fd1498Szrj       res = bitmap_count_bits (have_bound);
1011*38fd1498Szrj       BITMAP_FREE (have_bound);
1012*38fd1498Szrj       bitmap_obstack_release (NULL);
1013*38fd1498Szrj     }
1014*38fd1498Szrj 
1015*38fd1498Szrj   return res;
1016*38fd1498Szrj }
1017*38fd1498Szrj 
1018*38fd1498Szrj /* Get bounds associated with NODE via
1019*38fd1498Szrj    chkp_set_bounds call.  */
1020*38fd1498Szrj tree
1021*38fd1498Szrj chkp_get_bounds (tree node)
1022*38fd1498Szrj {
1023*38fd1498Szrj   tree *slot;
1024*38fd1498Szrj 
1025*38fd1498Szrj   if (!chkp_bounds_map)
1026*38fd1498Szrj     return NULL_TREE;
1027*38fd1498Szrj 
1028*38fd1498Szrj   slot = chkp_bounds_map->get (node);
1029*38fd1498Szrj   return slot ? *slot : NULL_TREE;
1030*38fd1498Szrj }
1031*38fd1498Szrj 
1032*38fd1498Szrj /* Associate bounds VAL with NODE.  */
1033*38fd1498Szrj void
1034*38fd1498Szrj chkp_set_bounds (tree node, tree val)
1035*38fd1498Szrj {
1036*38fd1498Szrj   if (!chkp_bounds_map)
1037*38fd1498Szrj     chkp_bounds_map = new hash_map<tree, tree>;
1038*38fd1498Szrj 
1039*38fd1498Szrj   chkp_bounds_map->put (node, val);
1040*38fd1498Szrj }
1041*38fd1498Szrj 
1042*38fd1498Szrj /* Check if statically initialized variable VAR require
1043*38fd1498Szrj    static bounds initialization.  If VAR is added into
1044*38fd1498Szrj    bounds initlization list then 1 is returned. Otherwise
1045*38fd1498Szrj    return 0.  */
1046*38fd1498Szrj extern bool
1047*38fd1498Szrj chkp_register_var_initializer (tree var)
1048*38fd1498Szrj {
1049*38fd1498Szrj   if (!flag_check_pointer_bounds
1050*38fd1498Szrj       || DECL_INITIAL (var) == error_mark_node)
1051*38fd1498Szrj     return false;
1052*38fd1498Szrj 
1053*38fd1498Szrj   gcc_assert (VAR_P (var));
1054*38fd1498Szrj   gcc_assert (DECL_INITIAL (var));
1055*38fd1498Szrj 
1056*38fd1498Szrj   if (TREE_STATIC (var)
1057*38fd1498Szrj       && chkp_type_has_pointer (TREE_TYPE (var)))
1058*38fd1498Szrj     {
1059*38fd1498Szrj       varpool_node::get_create (var)->need_bounds_init = 1;
1060*38fd1498Szrj       return true;
1061*38fd1498Szrj     }
1062*38fd1498Szrj 
1063*38fd1498Szrj   return false;
1064*38fd1498Szrj }
1065*38fd1498Szrj 
1066*38fd1498Szrj /* Helper function for chkp_finish_file.
1067*38fd1498Szrj 
1068*38fd1498Szrj    Add new modification statement (RHS is assigned to LHS)
1069*38fd1498Szrj    into list of static initializer statementes (passed in ARG).
1070*38fd1498Szrj    If statements list becomes too big, emit checker constructor
1071*38fd1498Szrj    and start the new one.  */
1072*38fd1498Szrj static void
1073*38fd1498Szrj chkp_add_modification_to_stmt_list (tree lhs,
1074*38fd1498Szrj 				    tree rhs,
1075*38fd1498Szrj 				    void *arg)
1076*38fd1498Szrj {
1077*38fd1498Szrj   struct chkp_ctor_stmt_list *stmts = (struct chkp_ctor_stmt_list *)arg;
1078*38fd1498Szrj   tree modify;
1079*38fd1498Szrj 
1080*38fd1498Szrj   if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
1081*38fd1498Szrj     rhs = build1 (CONVERT_EXPR, TREE_TYPE (lhs), rhs);
1082*38fd1498Szrj 
1083*38fd1498Szrj   modify = build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs);
1084*38fd1498Szrj   append_to_statement_list (modify, &stmts->stmts);
1085*38fd1498Szrj 
1086*38fd1498Szrj   stmts->avail--;
1087*38fd1498Szrj }
1088*38fd1498Szrj 
1089*38fd1498Szrj /* Build and return ADDR_EXPR for specified object OBJ.  */
1090*38fd1498Szrj static tree
1091*38fd1498Szrj chkp_build_addr_expr (tree obj)
1092*38fd1498Szrj {
1093*38fd1498Szrj   /* We first check whether it is a "hard reg case".  */
1094*38fd1498Szrj   tree base = get_base_address (obj);
1095*38fd1498Szrj   if (VAR_P (base) && DECL_HARD_REGISTER (base))
1096*38fd1498Szrj     return chkp_get_hard_register_fake_addr_expr (obj);
1097*38fd1498Szrj 
1098*38fd1498Szrj   /* If not - return regular ADDR_EXPR.  */
1099*38fd1498Szrj   return TREE_CODE (obj) == TARGET_MEM_REF
1100*38fd1498Szrj     ? tree_mem_ref_addr (ptr_type_node, obj)
1101*38fd1498Szrj     : build_fold_addr_expr (obj);
1102*38fd1498Szrj }
1103*38fd1498Szrj 
1104*38fd1498Szrj /* Helper function for chkp_finish_file.
1105*38fd1498Szrj    Initialize bound variable BND_VAR with bounds of variable
1106*38fd1498Szrj    VAR to statements list STMTS.  If statements list becomes
1107*38fd1498Szrj    too big, emit checker constructor and start the new one.  */
1108*38fd1498Szrj static void
1109*38fd1498Szrj chkp_output_static_bounds (tree bnd_var, tree var,
1110*38fd1498Szrj 			   struct chkp_ctor_stmt_list *stmts)
1111*38fd1498Szrj {
1112*38fd1498Szrj   tree lb, ub, size;
1113*38fd1498Szrj 
1114*38fd1498Szrj   if (TREE_CODE (var) == STRING_CST)
1115*38fd1498Szrj     {
1116*38fd1498Szrj       lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
1117*38fd1498Szrj       size = build_int_cst (size_type_node, TREE_STRING_LENGTH (var) - 1);
1118*38fd1498Szrj     }
1119*38fd1498Szrj   else if (DECL_SIZE (var)
1120*38fd1498Szrj 	   && !chkp_variable_size_type (TREE_TYPE (var)))
1121*38fd1498Szrj     {
1122*38fd1498Szrj       /* Compute bounds using statically known size.  */
1123*38fd1498Szrj       lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
1124*38fd1498Szrj       size = size_binop (MINUS_EXPR, DECL_SIZE_UNIT (var), size_one_node);
1125*38fd1498Szrj     }
1126*38fd1498Szrj   else
1127*38fd1498Szrj     {
1128*38fd1498Szrj       /* Compute bounds using dynamic size.  */
1129*38fd1498Szrj       tree call;
1130*38fd1498Szrj 
1131*38fd1498Szrj       lb = build1 (CONVERT_EXPR, size_type_node, chkp_build_addr_expr (var));
1132*38fd1498Szrj       call = build1 (ADDR_EXPR,
1133*38fd1498Szrj 		     build_pointer_type (TREE_TYPE (chkp_sizeof_fndecl)),
1134*38fd1498Szrj 		     chkp_sizeof_fndecl);
1135*38fd1498Szrj       size = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_sizeof_fndecl)),
1136*38fd1498Szrj 			      call, 1, var);
1137*38fd1498Szrj 
1138*38fd1498Szrj       if (flag_chkp_zero_dynamic_size_as_infinite)
1139*38fd1498Szrj 	{
1140*38fd1498Szrj 	  tree max_size, cond;
1141*38fd1498Szrj 
1142*38fd1498Szrj 	  max_size = build2 (MINUS_EXPR, size_type_node, size_zero_node, lb);
1143*38fd1498Szrj 	  cond = build2 (NE_EXPR, boolean_type_node, size, size_zero_node);
1144*38fd1498Szrj 	  size = build3 (COND_EXPR, size_type_node, cond, size, max_size);
1145*38fd1498Szrj 	}
1146*38fd1498Szrj 
1147*38fd1498Szrj       size = size_binop (MINUS_EXPR, size, size_one_node);
1148*38fd1498Szrj     }
1149*38fd1498Szrj 
1150*38fd1498Szrj   ub = size_binop (PLUS_EXPR, lb, size);
1151*38fd1498Szrj   stmts->avail -= targetm.chkp_initialize_bounds (bnd_var, lb, ub,
1152*38fd1498Szrj 						  &stmts->stmts);
1153*38fd1498Szrj   if (stmts->avail <= 0)
1154*38fd1498Szrj     {
1155*38fd1498Szrj       cgraph_build_static_cdtor ('B', stmts->stmts,
1156*38fd1498Szrj 				 MAX_RESERVED_INIT_PRIORITY + 2);
1157*38fd1498Szrj       stmts->avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
1158*38fd1498Szrj       stmts->stmts = NULL;
1159*38fd1498Szrj     }
1160*38fd1498Szrj }
1161*38fd1498Szrj 
1162*38fd1498Szrj /* Return entry block to be used for checker initilization code.
1163*38fd1498Szrj    Create new block if required.  */
1164*38fd1498Szrj static basic_block
1165*38fd1498Szrj chkp_get_entry_block (void)
1166*38fd1498Szrj {
1167*38fd1498Szrj   if (!entry_block)
1168*38fd1498Szrj     entry_block
1169*38fd1498Szrj       = split_block_after_labels (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
1170*38fd1498Szrj 
1171*38fd1498Szrj   return entry_block;
1172*38fd1498Szrj }
1173*38fd1498Szrj 
1174*38fd1498Szrj /* Return a bounds var to be used for pointer var PTR_VAR.  */
1175*38fd1498Szrj static tree
1176*38fd1498Szrj chkp_get_bounds_var (tree ptr_var)
1177*38fd1498Szrj {
1178*38fd1498Szrj   tree bnd_var;
1179*38fd1498Szrj   tree *slot;
1180*38fd1498Szrj 
1181*38fd1498Szrj   slot = chkp_bound_vars->get (ptr_var);
1182*38fd1498Szrj   if (slot)
1183*38fd1498Szrj     bnd_var = *slot;
1184*38fd1498Szrj   else
1185*38fd1498Szrj     {
1186*38fd1498Szrj       bnd_var = create_tmp_reg (pointer_bounds_type_node,
1187*38fd1498Szrj 				CHKP_BOUND_TMP_NAME);
1188*38fd1498Szrj       chkp_bound_vars->put (ptr_var, bnd_var);
1189*38fd1498Szrj     }
1190*38fd1498Szrj 
1191*38fd1498Szrj   return bnd_var;
1192*38fd1498Szrj }
1193*38fd1498Szrj 
1194*38fd1498Szrj /* If BND is an abnormal bounds copy, return a copied value.
1195*38fd1498Szrj    Otherwise return BND.  */
1196*38fd1498Szrj static tree
1197*38fd1498Szrj chkp_get_orginal_bounds_for_abnormal_copy (tree bnd)
1198*38fd1498Szrj {
1199*38fd1498Szrj   if (bitmap_bit_p (chkp_abnormal_copies, SSA_NAME_VERSION (bnd)))
1200*38fd1498Szrj     {
1201*38fd1498Szrj       gimple *bnd_def = SSA_NAME_DEF_STMT (bnd);
1202*38fd1498Szrj       gcc_checking_assert (gimple_code (bnd_def) == GIMPLE_ASSIGN);
1203*38fd1498Szrj       bnd = gimple_assign_rhs1 (bnd_def);
1204*38fd1498Szrj     }
1205*38fd1498Szrj 
1206*38fd1498Szrj   return bnd;
1207*38fd1498Szrj }
1208*38fd1498Szrj 
1209*38fd1498Szrj /* Register bounds BND for object PTR in global bounds table.
1210*38fd1498Szrj    A copy of bounds may be created for abnormal ssa names.
1211*38fd1498Szrj    Returns bounds to use for PTR.  */
1212*38fd1498Szrj static tree
1213*38fd1498Szrj chkp_maybe_copy_and_register_bounds (tree ptr, tree bnd)
1214*38fd1498Szrj {
1215*38fd1498Szrj   bool abnormal_ptr;
1216*38fd1498Szrj 
1217*38fd1498Szrj   if (!chkp_reg_bounds)
1218*38fd1498Szrj     return bnd;
1219*38fd1498Szrj 
1220*38fd1498Szrj   /* Do nothing if bounds are incomplete_bounds
1221*38fd1498Szrj      because it means bounds will be recomputed.  */
1222*38fd1498Szrj   if (bnd == incomplete_bounds)
1223*38fd1498Szrj     return bnd;
1224*38fd1498Szrj 
1225*38fd1498Szrj   abnormal_ptr = (TREE_CODE (ptr) == SSA_NAME
1226*38fd1498Szrj 		  && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr)
1227*38fd1498Szrj 		  && gimple_code (SSA_NAME_DEF_STMT (ptr)) != GIMPLE_PHI);
1228*38fd1498Szrj 
1229*38fd1498Szrj   /* A single bounds value may be reused multiple times for
1230*38fd1498Szrj      different pointer values.  It may cause coalescing issues
1231*38fd1498Szrj      for abnormal SSA names.  To avoid it we create a bounds
1232*38fd1498Szrj      copy in case it is computed for abnormal SSA name.
1233*38fd1498Szrj 
1234*38fd1498Szrj      We also cannot reuse such created copies for other pointers  */
1235*38fd1498Szrj   if (abnormal_ptr
1236*38fd1498Szrj       || bitmap_bit_p (chkp_abnormal_copies, SSA_NAME_VERSION (bnd)))
1237*38fd1498Szrj     {
1238*38fd1498Szrj       tree bnd_var = NULL_TREE;
1239*38fd1498Szrj 
1240*38fd1498Szrj       if (abnormal_ptr)
1241*38fd1498Szrj 	{
1242*38fd1498Szrj 	  if (SSA_NAME_VAR (ptr))
1243*38fd1498Szrj 	    bnd_var = chkp_get_bounds_var (SSA_NAME_VAR (ptr));
1244*38fd1498Szrj 	}
1245*38fd1498Szrj       else
1246*38fd1498Szrj 	bnd_var = chkp_get_tmp_var ();
1247*38fd1498Szrj 
1248*38fd1498Szrj       /* For abnormal copies we may just find original
1249*38fd1498Szrj 	 bounds and use them.  */
1250*38fd1498Szrj       if (!abnormal_ptr && !SSA_NAME_IS_DEFAULT_DEF (bnd))
1251*38fd1498Szrj 	bnd = chkp_get_orginal_bounds_for_abnormal_copy (bnd);
1252*38fd1498Szrj       /* For undefined values we usually use none bounds
1253*38fd1498Szrj 	 value but in case of abnormal edge it may cause
1254*38fd1498Szrj 	 coalescing failures.  Use default definition of
1255*38fd1498Szrj 	 bounds variable instead to avoid it.  */
1256*38fd1498Szrj       else if (SSA_NAME_IS_DEFAULT_DEF (ptr)
1257*38fd1498Szrj 	       && TREE_CODE (SSA_NAME_VAR (ptr)) != PARM_DECL)
1258*38fd1498Szrj 	{
1259*38fd1498Szrj 	  bnd = get_or_create_ssa_default_def (cfun, bnd_var);
1260*38fd1498Szrj 
1261*38fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
1262*38fd1498Szrj 	    {
1263*38fd1498Szrj 	      fprintf (dump_file, "Using default def bounds ");
1264*38fd1498Szrj 	      print_generic_expr (dump_file, bnd);
1265*38fd1498Szrj 	      fprintf (dump_file, " for abnormal default def SSA name ");
1266*38fd1498Szrj 	      print_generic_expr (dump_file, ptr);
1267*38fd1498Szrj 	      fprintf (dump_file, "\n");
1268*38fd1498Szrj 	    }
1269*38fd1498Szrj 	}
1270*38fd1498Szrj       else
1271*38fd1498Szrj 	{
1272*38fd1498Szrj 	  tree copy;
1273*38fd1498Szrj 	  gimple *def = SSA_NAME_DEF_STMT (ptr);
1274*38fd1498Szrj 	  gimple *assign;
1275*38fd1498Szrj 	  gimple_stmt_iterator gsi;
1276*38fd1498Szrj 
1277*38fd1498Szrj 	  if (bnd_var)
1278*38fd1498Szrj 	    copy = make_ssa_name (bnd_var);
1279*38fd1498Szrj 	  else
1280*38fd1498Szrj 	    copy = make_temp_ssa_name (pointer_bounds_type_node,
1281*38fd1498Szrj 				       NULL,
1282*38fd1498Szrj 				       CHKP_BOUND_TMP_NAME);
1283*38fd1498Szrj 	  bnd = chkp_get_orginal_bounds_for_abnormal_copy (bnd);
1284*38fd1498Szrj 	  assign = gimple_build_assign (copy, bnd);
1285*38fd1498Szrj 
1286*38fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
1287*38fd1498Szrj 	    {
1288*38fd1498Szrj 	      fprintf (dump_file, "Creating a copy of bounds ");
1289*38fd1498Szrj 	      print_generic_expr (dump_file, bnd);
1290*38fd1498Szrj 	      fprintf (dump_file, " for abnormal SSA name ");
1291*38fd1498Szrj 	      print_generic_expr (dump_file, ptr);
1292*38fd1498Szrj 	      fprintf (dump_file, "\n");
1293*38fd1498Szrj 	    }
1294*38fd1498Szrj 
1295*38fd1498Szrj 	  if (gimple_code (def) == GIMPLE_NOP)
1296*38fd1498Szrj 	    {
1297*38fd1498Szrj 	      gsi = gsi_last_bb (chkp_get_entry_block ());
1298*38fd1498Szrj 	      if (!gsi_end_p (gsi) && is_ctrl_stmt (gsi_stmt (gsi)))
1299*38fd1498Szrj 		gsi_insert_before (&gsi, assign, GSI_CONTINUE_LINKING);
1300*38fd1498Szrj 	      else
1301*38fd1498Szrj 		gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING);
1302*38fd1498Szrj 	    }
1303*38fd1498Szrj 	  else
1304*38fd1498Szrj 	    {
1305*38fd1498Szrj 	      gimple *bnd_def = SSA_NAME_DEF_STMT (bnd);
1306*38fd1498Szrj 	      /* Sometimes (e.g. when we load a pointer from a
1307*38fd1498Szrj 		 memory) bounds are produced later than a pointer.
1308*38fd1498Szrj 		 We need to insert bounds copy appropriately.  */
1309*38fd1498Szrj 	      if (gimple_code (bnd_def) != GIMPLE_NOP
1310*38fd1498Szrj 		  && stmt_dominates_stmt_p (def, bnd_def))
1311*38fd1498Szrj 		gsi = gsi_for_stmt (bnd_def);
1312*38fd1498Szrj 	      else
1313*38fd1498Szrj 		gsi = gsi_for_stmt (def);
1314*38fd1498Szrj 	      gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING);
1315*38fd1498Szrj 	    }
1316*38fd1498Szrj 
1317*38fd1498Szrj 	  bnd = copy;
1318*38fd1498Szrj 	}
1319*38fd1498Szrj 
1320*38fd1498Szrj       if (abnormal_ptr)
1321*38fd1498Szrj 	bitmap_set_bit (chkp_abnormal_copies, SSA_NAME_VERSION (bnd));
1322*38fd1498Szrj     }
1323*38fd1498Szrj 
1324*38fd1498Szrj   chkp_reg_bounds->put (ptr, bnd);
1325*38fd1498Szrj 
1326*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
1327*38fd1498Szrj     {
1328*38fd1498Szrj       fprintf (dump_file, "Regsitered bound ");
1329*38fd1498Szrj       print_generic_expr (dump_file, bnd);
1330*38fd1498Szrj       fprintf (dump_file, " for pointer ");
1331*38fd1498Szrj       print_generic_expr (dump_file, ptr);
1332*38fd1498Szrj       fprintf (dump_file, "\n");
1333*38fd1498Szrj     }
1334*38fd1498Szrj 
1335*38fd1498Szrj   return bnd;
1336*38fd1498Szrj }
1337*38fd1498Szrj 
1338*38fd1498Szrj /* Get bounds registered for object PTR in global bounds table.  */
1339*38fd1498Szrj static tree
1340*38fd1498Szrj chkp_get_registered_bounds (tree ptr)
1341*38fd1498Szrj {
1342*38fd1498Szrj   tree *slot;
1343*38fd1498Szrj 
1344*38fd1498Szrj   if (!chkp_reg_bounds)
1345*38fd1498Szrj     return NULL_TREE;
1346*38fd1498Szrj 
1347*38fd1498Szrj   slot = chkp_reg_bounds->get (ptr);
1348*38fd1498Szrj   return slot ? *slot : NULL_TREE;
1349*38fd1498Szrj }
1350*38fd1498Szrj 
1351*38fd1498Szrj /* Add bound retvals to return statement pointed by GSI.  */
1352*38fd1498Szrj 
1353*38fd1498Szrj static void
1354*38fd1498Szrj chkp_add_bounds_to_ret_stmt (gimple_stmt_iterator *gsi)
1355*38fd1498Szrj {
1356*38fd1498Szrj   greturn *ret = as_a <greturn *> (gsi_stmt (*gsi));
1357*38fd1498Szrj   tree retval = gimple_return_retval (ret);
1358*38fd1498Szrj   tree ret_decl = DECL_RESULT (cfun->decl);
1359*38fd1498Szrj   tree bounds;
1360*38fd1498Szrj 
1361*38fd1498Szrj   if (!retval)
1362*38fd1498Szrj     return;
1363*38fd1498Szrj 
1364*38fd1498Szrj   if (BOUNDED_P (ret_decl))
1365*38fd1498Szrj     {
1366*38fd1498Szrj       bounds = chkp_find_bounds (retval, gsi);
1367*38fd1498Szrj       bounds = chkp_maybe_copy_and_register_bounds (ret_decl, bounds);
1368*38fd1498Szrj       gimple_return_set_retbnd (ret, bounds);
1369*38fd1498Szrj     }
1370*38fd1498Szrj 
1371*38fd1498Szrj   update_stmt (ret);
1372*38fd1498Szrj }
1373*38fd1498Szrj 
1374*38fd1498Szrj /* Force OP to be suitable for using as an argument for call.
1375*38fd1498Szrj    New statements (if any) go to SEQ.  */
1376*38fd1498Szrj static tree
1377*38fd1498Szrj chkp_force_gimple_call_op (tree op, gimple_seq *seq)
1378*38fd1498Szrj {
1379*38fd1498Szrj   gimple_seq stmts;
1380*38fd1498Szrj   gimple_stmt_iterator si;
1381*38fd1498Szrj 
1382*38fd1498Szrj   op = force_gimple_operand (unshare_expr (op), &stmts, true, NULL_TREE);
1383*38fd1498Szrj 
1384*38fd1498Szrj   for (si = gsi_start (stmts); !gsi_end_p (si); gsi_next (&si))
1385*38fd1498Szrj     chkp_mark_stmt (gsi_stmt (si));
1386*38fd1498Szrj 
1387*38fd1498Szrj   gimple_seq_add_seq (seq, stmts);
1388*38fd1498Szrj 
1389*38fd1498Szrj   return op;
1390*38fd1498Szrj }
1391*38fd1498Szrj 
1392*38fd1498Szrj /* Generate lower bound check for memory access by ADDR.
1393*38fd1498Szrj    Check is inserted before the position pointed by ITER.
1394*38fd1498Szrj    DIRFLAG indicates whether memory access is load or store.  */
1395*38fd1498Szrj static void
1396*38fd1498Szrj chkp_check_lower (tree addr, tree bounds,
1397*38fd1498Szrj 		  gimple_stmt_iterator iter,
1398*38fd1498Szrj 		  location_t location,
1399*38fd1498Szrj 		  tree dirflag)
1400*38fd1498Szrj {
1401*38fd1498Szrj   gimple_seq seq;
1402*38fd1498Szrj   gimple *check;
1403*38fd1498Szrj   tree node;
1404*38fd1498Szrj 
1405*38fd1498Szrj   if (!chkp_function_instrumented_p (current_function_decl)
1406*38fd1498Szrj       && bounds == chkp_get_zero_bounds ())
1407*38fd1498Szrj     return;
1408*38fd1498Szrj 
1409*38fd1498Szrj   if (dirflag == integer_zero_node
1410*38fd1498Szrj       && !flag_chkp_check_read)
1411*38fd1498Szrj     return;
1412*38fd1498Szrj 
1413*38fd1498Szrj   if (dirflag == integer_one_node
1414*38fd1498Szrj       && !flag_chkp_check_write)
1415*38fd1498Szrj     return;
1416*38fd1498Szrj 
1417*38fd1498Szrj   seq = NULL;
1418*38fd1498Szrj 
1419*38fd1498Szrj   node = chkp_force_gimple_call_op (addr, &seq);
1420*38fd1498Szrj 
1421*38fd1498Szrj   check = gimple_build_call (chkp_checkl_fndecl, 2, node, bounds);
1422*38fd1498Szrj   chkp_mark_stmt (check);
1423*38fd1498Szrj   gimple_call_set_with_bounds (check, true);
1424*38fd1498Szrj   gimple_set_location (check, location);
1425*38fd1498Szrj   gimple_seq_add_stmt (&seq, check);
1426*38fd1498Szrj 
1427*38fd1498Szrj   gsi_insert_seq_before (&iter, seq, GSI_SAME_STMT);
1428*38fd1498Szrj 
1429*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
1430*38fd1498Szrj     {
1431*38fd1498Szrj       gimple *before = gsi_stmt (iter);
1432*38fd1498Szrj       fprintf (dump_file, "Generated lower bound check for statement ");
1433*38fd1498Szrj       print_gimple_stmt (dump_file, before, 0, TDF_VOPS|TDF_MEMSYMS);
1434*38fd1498Szrj       fprintf (dump_file, "  ");
1435*38fd1498Szrj       print_gimple_stmt (dump_file, check, 0, TDF_VOPS|TDF_MEMSYMS);
1436*38fd1498Szrj     }
1437*38fd1498Szrj }
1438*38fd1498Szrj 
1439*38fd1498Szrj /* Generate upper bound check for memory access by ADDR.
1440*38fd1498Szrj    Check is inserted before the position pointed by ITER.
1441*38fd1498Szrj    DIRFLAG indicates whether memory access is load or store.  */
1442*38fd1498Szrj static void
1443*38fd1498Szrj chkp_check_upper (tree addr, tree bounds,
1444*38fd1498Szrj 		  gimple_stmt_iterator iter,
1445*38fd1498Szrj 		  location_t location,
1446*38fd1498Szrj 		  tree dirflag)
1447*38fd1498Szrj {
1448*38fd1498Szrj   gimple_seq seq;
1449*38fd1498Szrj   gimple *check;
1450*38fd1498Szrj   tree node;
1451*38fd1498Szrj 
1452*38fd1498Szrj   if (!chkp_function_instrumented_p (current_function_decl)
1453*38fd1498Szrj       && bounds == chkp_get_zero_bounds ())
1454*38fd1498Szrj     return;
1455*38fd1498Szrj 
1456*38fd1498Szrj   if (dirflag == integer_zero_node
1457*38fd1498Szrj       && !flag_chkp_check_read)
1458*38fd1498Szrj     return;
1459*38fd1498Szrj 
1460*38fd1498Szrj   if (dirflag == integer_one_node
1461*38fd1498Szrj       && !flag_chkp_check_write)
1462*38fd1498Szrj     return;
1463*38fd1498Szrj 
1464*38fd1498Szrj   seq = NULL;
1465*38fd1498Szrj 
1466*38fd1498Szrj   node = chkp_force_gimple_call_op (addr, &seq);
1467*38fd1498Szrj 
1468*38fd1498Szrj   check = gimple_build_call (chkp_checku_fndecl, 2, node, bounds);
1469*38fd1498Szrj   chkp_mark_stmt (check);
1470*38fd1498Szrj   gimple_call_set_with_bounds (check, true);
1471*38fd1498Szrj   gimple_set_location (check, location);
1472*38fd1498Szrj   gimple_seq_add_stmt (&seq, check);
1473*38fd1498Szrj 
1474*38fd1498Szrj   gsi_insert_seq_before (&iter, seq, GSI_SAME_STMT);
1475*38fd1498Szrj 
1476*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
1477*38fd1498Szrj     {
1478*38fd1498Szrj       gimple *before = gsi_stmt (iter);
1479*38fd1498Szrj       fprintf (dump_file, "Generated upper bound check for statement ");
1480*38fd1498Szrj       print_gimple_stmt (dump_file, before, 0, TDF_VOPS|TDF_MEMSYMS);
1481*38fd1498Szrj       fprintf (dump_file, "  ");
1482*38fd1498Szrj       print_gimple_stmt (dump_file, check, 0, TDF_VOPS|TDF_MEMSYMS);
1483*38fd1498Szrj     }
1484*38fd1498Szrj }
1485*38fd1498Szrj 
1486*38fd1498Szrj /* Generate lower and upper bound checks for memory access
1487*38fd1498Szrj    to memory slot [FIRST, LAST] againsr BOUNDS.  Checks
1488*38fd1498Szrj    are inserted before the position pointed by ITER.
1489*38fd1498Szrj    DIRFLAG indicates whether memory access is load or store.  */
1490*38fd1498Szrj void
1491*38fd1498Szrj chkp_check_mem_access (tree first, tree last, tree bounds,
1492*38fd1498Szrj 		       gimple_stmt_iterator iter,
1493*38fd1498Szrj 		       location_t location,
1494*38fd1498Szrj 		       tree dirflag)
1495*38fd1498Szrj {
1496*38fd1498Szrj   chkp_check_lower (first, bounds, iter, location, dirflag);
1497*38fd1498Szrj   chkp_check_upper (last, bounds, iter, location, dirflag);
1498*38fd1498Szrj }
1499*38fd1498Szrj 
1500*38fd1498Szrj /* Replace call to _bnd_chk_* pointed by GSI with
1501*38fd1498Szrj    bndcu and bndcl calls.  DIRFLAG determines whether
1502*38fd1498Szrj    check is for read or write.  */
1503*38fd1498Szrj 
1504*38fd1498Szrj void
1505*38fd1498Szrj chkp_replace_address_check_builtin (gimple_stmt_iterator *gsi,
1506*38fd1498Szrj 				    tree dirflag)
1507*38fd1498Szrj {
1508*38fd1498Szrj   gimple_stmt_iterator call_iter = *gsi;
1509*38fd1498Szrj   gimple *call = gsi_stmt (*gsi);
1510*38fd1498Szrj   tree fndecl = gimple_call_fndecl (call);
1511*38fd1498Szrj   tree addr = gimple_call_arg (call, 0);
1512*38fd1498Szrj   tree bounds = chkp_find_bounds (addr, gsi);
1513*38fd1498Szrj 
1514*38fd1498Szrj   if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
1515*38fd1498Szrj       || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS)
1516*38fd1498Szrj     chkp_check_lower (addr, bounds, *gsi, gimple_location (call), dirflag);
1517*38fd1498Szrj 
1518*38fd1498Szrj   if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS)
1519*38fd1498Szrj     chkp_check_upper (addr, bounds, *gsi, gimple_location (call), dirflag);
1520*38fd1498Szrj 
1521*38fd1498Szrj   if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS)
1522*38fd1498Szrj     {
1523*38fd1498Szrj       tree size = gimple_call_arg (call, 1);
1524*38fd1498Szrj       addr = fold_build_pointer_plus (addr, size);
1525*38fd1498Szrj       addr = fold_build_pointer_plus_hwi (addr, -1);
1526*38fd1498Szrj       chkp_check_upper (addr, bounds, *gsi, gimple_location (call), dirflag);
1527*38fd1498Szrj     }
1528*38fd1498Szrj 
1529*38fd1498Szrj   gsi_remove (&call_iter, true);
1530*38fd1498Szrj }
1531*38fd1498Szrj 
1532*38fd1498Szrj /* Replace call to _bnd_get_ptr_* pointed by GSI with
1533*38fd1498Szrj    corresponding bounds extract call.  */
1534*38fd1498Szrj 
1535*38fd1498Szrj void
1536*38fd1498Szrj chkp_replace_extract_builtin (gimple_stmt_iterator *gsi)
1537*38fd1498Szrj {
1538*38fd1498Szrj   gimple *call = gsi_stmt (*gsi);
1539*38fd1498Szrj   tree fndecl = gimple_call_fndecl (call);
1540*38fd1498Szrj   tree addr = gimple_call_arg (call, 0);
1541*38fd1498Szrj   tree bounds = chkp_find_bounds (addr, gsi);
1542*38fd1498Szrj   gimple *extract;
1543*38fd1498Szrj 
1544*38fd1498Szrj   if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_LBOUND)
1545*38fd1498Szrj     fndecl = chkp_extract_lower_fndecl;
1546*38fd1498Szrj   else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_UBOUND)
1547*38fd1498Szrj     fndecl = chkp_extract_upper_fndecl;
1548*38fd1498Szrj   else
1549*38fd1498Szrj     gcc_unreachable ();
1550*38fd1498Szrj 
1551*38fd1498Szrj   extract = gimple_build_call (fndecl, 1, bounds);
1552*38fd1498Szrj   gimple_call_set_lhs (extract, gimple_call_lhs (call));
1553*38fd1498Szrj   chkp_mark_stmt (extract);
1554*38fd1498Szrj 
1555*38fd1498Szrj   gsi_replace (gsi, extract, false);
1556*38fd1498Szrj }
1557*38fd1498Szrj 
1558*38fd1498Szrj /* Return COMPONENT_REF accessing FIELD in OBJ.  */
1559*38fd1498Szrj static tree
1560*38fd1498Szrj chkp_build_component_ref (tree obj, tree field)
1561*38fd1498Szrj {
1562*38fd1498Szrj   tree res;
1563*38fd1498Szrj 
1564*38fd1498Szrj   /* If object is TMR then we do not use component_ref but
1565*38fd1498Szrj      add offset instead.  We need it to be able to get addr
1566*38fd1498Szrj      of the reasult later.  */
1567*38fd1498Szrj   if (TREE_CODE (obj) == TARGET_MEM_REF)
1568*38fd1498Szrj     {
1569*38fd1498Szrj       tree offs = TMR_OFFSET (obj);
1570*38fd1498Szrj       offs = fold_binary_to_constant (PLUS_EXPR, TREE_TYPE (offs),
1571*38fd1498Szrj 				      offs, DECL_FIELD_OFFSET (field));
1572*38fd1498Szrj 
1573*38fd1498Szrj       gcc_assert (offs);
1574*38fd1498Szrj 
1575*38fd1498Szrj       res = copy_node (obj);
1576*38fd1498Szrj       TREE_TYPE (res) = TREE_TYPE (field);
1577*38fd1498Szrj       TMR_OFFSET (res) = offs;
1578*38fd1498Szrj     }
1579*38fd1498Szrj   else
1580*38fd1498Szrj     res = build3 (COMPONENT_REF, TREE_TYPE (field), obj, field, NULL_TREE);
1581*38fd1498Szrj 
1582*38fd1498Szrj   return res;
1583*38fd1498Szrj }
1584*38fd1498Szrj 
1585*38fd1498Szrj /* Return ARRAY_REF for array ARR and index IDX with
1586*38fd1498Szrj    specified element type ETYPE and element size ESIZE.  */
1587*38fd1498Szrj static tree
1588*38fd1498Szrj chkp_build_array_ref (tree arr, tree etype, tree esize,
1589*38fd1498Szrj 		      unsigned HOST_WIDE_INT idx)
1590*38fd1498Szrj {
1591*38fd1498Szrj   tree index = build_int_cst (size_type_node, idx);
1592*38fd1498Szrj   tree res;
1593*38fd1498Szrj 
1594*38fd1498Szrj   /* If object is TMR then we do not use array_ref but
1595*38fd1498Szrj      add offset instead.  We need it to be able to get addr
1596*38fd1498Szrj      of the reasult later.  */
1597*38fd1498Szrj   if (TREE_CODE (arr) == TARGET_MEM_REF)
1598*38fd1498Szrj     {
1599*38fd1498Szrj       tree offs = TMR_OFFSET (arr);
1600*38fd1498Szrj 
1601*38fd1498Szrj       esize = fold_binary_to_constant (MULT_EXPR, TREE_TYPE (esize),
1602*38fd1498Szrj 				     esize, index);
1603*38fd1498Szrj       gcc_assert(esize);
1604*38fd1498Szrj 
1605*38fd1498Szrj       offs = fold_binary_to_constant (PLUS_EXPR, TREE_TYPE (offs),
1606*38fd1498Szrj 				    offs, esize);
1607*38fd1498Szrj       gcc_assert (offs);
1608*38fd1498Szrj 
1609*38fd1498Szrj       res = copy_node (arr);
1610*38fd1498Szrj       TREE_TYPE (res) = etype;
1611*38fd1498Szrj       TMR_OFFSET (res) = offs;
1612*38fd1498Szrj     }
1613*38fd1498Szrj   else
1614*38fd1498Szrj     res = build4 (ARRAY_REF, etype, arr, index, NULL_TREE, NULL_TREE);
1615*38fd1498Szrj 
1616*38fd1498Szrj   return res;
1617*38fd1498Szrj }
1618*38fd1498Szrj 
1619*38fd1498Szrj /* Helper function for chkp_add_bounds_to_call_stmt.
1620*38fd1498Szrj    Fill ALL_BOUNDS output array with created bounds.
1621*38fd1498Szrj 
1622*38fd1498Szrj    OFFS is used for recursive calls and holds basic
1623*38fd1498Szrj    offset of TYPE in outer structure in bits.
1624*38fd1498Szrj 
1625*38fd1498Szrj    ITER points a position where bounds are searched.
1626*38fd1498Szrj 
1627*38fd1498Szrj    ALL_BOUNDS[i] is filled with elem bounds if there
1628*38fd1498Szrj    is a field in TYPE which has pointer type and offset
1629*38fd1498Szrj    equal to i * POINTER_SIZE in bits.  */
1630*38fd1498Szrj static void
1631*38fd1498Szrj chkp_find_bounds_for_elem (tree elem, tree *all_bounds,
1632*38fd1498Szrj 			   HOST_WIDE_INT offs,
1633*38fd1498Szrj 			   gimple_stmt_iterator *iter)
1634*38fd1498Szrj {
1635*38fd1498Szrj   tree type = TREE_TYPE (elem);
1636*38fd1498Szrj 
1637*38fd1498Szrj   if (BOUNDED_TYPE_P (type))
1638*38fd1498Szrj     {
1639*38fd1498Szrj       if (!all_bounds[offs / POINTER_SIZE])
1640*38fd1498Szrj 	{
1641*38fd1498Szrj 	  tree temp = make_temp_ssa_name (type, NULL, "");
1642*38fd1498Szrj 	  gimple *assign = gimple_build_assign (temp, elem);
1643*38fd1498Szrj 	  gimple_stmt_iterator gsi;
1644*38fd1498Szrj 
1645*38fd1498Szrj 	  gsi_insert_before (iter, assign, GSI_SAME_STMT);
1646*38fd1498Szrj 	  gsi = gsi_for_stmt (assign);
1647*38fd1498Szrj 
1648*38fd1498Szrj 	  all_bounds[offs / POINTER_SIZE] = chkp_find_bounds (temp, &gsi);
1649*38fd1498Szrj 	}
1650*38fd1498Szrj     }
1651*38fd1498Szrj   else if (RECORD_OR_UNION_TYPE_P (type))
1652*38fd1498Szrj     {
1653*38fd1498Szrj       tree field;
1654*38fd1498Szrj 
1655*38fd1498Szrj       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
1656*38fd1498Szrj 	if (TREE_CODE (field) == FIELD_DECL)
1657*38fd1498Szrj 	  {
1658*38fd1498Szrj 	    tree base = unshare_expr (elem);
1659*38fd1498Szrj 	    tree field_ref = chkp_build_component_ref (base, field);
1660*38fd1498Szrj 	    HOST_WIDE_INT field_offs
1661*38fd1498Szrj 	      = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
1662*38fd1498Szrj 	    if (DECL_FIELD_OFFSET (field))
1663*38fd1498Szrj 	      field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8;
1664*38fd1498Szrj 
1665*38fd1498Szrj 	    chkp_find_bounds_for_elem (field_ref, all_bounds,
1666*38fd1498Szrj 				       offs + field_offs, iter);
1667*38fd1498Szrj 	  }
1668*38fd1498Szrj     }
1669*38fd1498Szrj   else if (TREE_CODE (type) == ARRAY_TYPE)
1670*38fd1498Szrj     {
1671*38fd1498Szrj       tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
1672*38fd1498Szrj       tree etype = TREE_TYPE (type);
1673*38fd1498Szrj       HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
1674*38fd1498Szrj       unsigned HOST_WIDE_INT cur;
1675*38fd1498Szrj 
1676*38fd1498Szrj       if (!maxval || integer_minus_onep (maxval))
1677*38fd1498Szrj 	return;
1678*38fd1498Szrj 
1679*38fd1498Szrj       for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++)
1680*38fd1498Szrj 	{
1681*38fd1498Szrj 	  tree base = unshare_expr (elem);
1682*38fd1498Szrj 	  tree arr_elem = chkp_build_array_ref (base, etype,
1683*38fd1498Szrj 						TYPE_SIZE (etype),
1684*38fd1498Szrj 						cur);
1685*38fd1498Szrj 	  chkp_find_bounds_for_elem (arr_elem, all_bounds, offs + cur * esize,
1686*38fd1498Szrj 				     iter);
1687*38fd1498Szrj 	}
1688*38fd1498Szrj     }
1689*38fd1498Szrj }
1690*38fd1498Szrj 
1691*38fd1498Szrj /* Maximum number of elements to check in an array.  */
1692*38fd1498Szrj 
1693*38fd1498Szrj #define CHKP_ARRAY_MAX_CHECK_STEPS    4096
1694*38fd1498Szrj 
1695*38fd1498Szrj /* Fill HAVE_BOUND output bitmap with information about
1696*38fd1498Szrj    bounds requred for object of type TYPE.
1697*38fd1498Szrj 
1698*38fd1498Szrj    OFFS is used for recursive calls and holds basic
1699*38fd1498Szrj    offset of TYPE in outer structure in bits.
1700*38fd1498Szrj 
1701*38fd1498Szrj    HAVE_BOUND[i] is set to 1 if there is a field
1702*38fd1498Szrj    in TYPE which has pointer type and offset
1703*38fd1498Szrj    equal to i * POINTER_SIZE - OFFS in bits.  */
1704*38fd1498Szrj void
1705*38fd1498Szrj chkp_find_bound_slots_1 (const_tree type, bitmap have_bound,
1706*38fd1498Szrj 			 HOST_WIDE_INT offs)
1707*38fd1498Szrj {
1708*38fd1498Szrj   if (BOUNDED_TYPE_P (type))
1709*38fd1498Szrj     bitmap_set_bit (have_bound, offs / POINTER_SIZE);
1710*38fd1498Szrj   else if (RECORD_OR_UNION_TYPE_P (type))
1711*38fd1498Szrj     {
1712*38fd1498Szrj       tree field;
1713*38fd1498Szrj 
1714*38fd1498Szrj       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
1715*38fd1498Szrj 	if (TREE_CODE (field) == FIELD_DECL)
1716*38fd1498Szrj 	  {
1717*38fd1498Szrj 	    HOST_WIDE_INT field_offs = 0;
1718*38fd1498Szrj 	    if (DECL_FIELD_BIT_OFFSET (field))
1719*38fd1498Szrj 	      field_offs += TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
1720*38fd1498Szrj 	    if (DECL_FIELD_OFFSET (field))
1721*38fd1498Szrj 	      field_offs += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field)) * 8;
1722*38fd1498Szrj 	    chkp_find_bound_slots_1 (TREE_TYPE (field), have_bound,
1723*38fd1498Szrj 				     offs + field_offs);
1724*38fd1498Szrj 	  }
1725*38fd1498Szrj     }
1726*38fd1498Szrj   else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
1727*38fd1498Szrj     {
1728*38fd1498Szrj       /* The object type is an array of complete type, i.e., other
1729*38fd1498Szrj 	 than a flexible array.  */
1730*38fd1498Szrj       tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
1731*38fd1498Szrj       tree etype = TREE_TYPE (type);
1732*38fd1498Szrj       HOST_WIDE_INT esize = TREE_INT_CST_LOW (TYPE_SIZE (etype));
1733*38fd1498Szrj       unsigned HOST_WIDE_INT cur;
1734*38fd1498Szrj 
1735*38fd1498Szrj       if (!maxval
1736*38fd1498Szrj 	  || TREE_CODE (maxval) != INTEGER_CST
1737*38fd1498Szrj 	  || integer_minus_onep (maxval))
1738*38fd1498Szrj 	return;
1739*38fd1498Szrj 
1740*38fd1498Szrj       for (cur = 0;
1741*38fd1498Szrj 	  cur <= MIN (CHKP_ARRAY_MAX_CHECK_STEPS, TREE_INT_CST_LOW (maxval));
1742*38fd1498Szrj 	  cur++)
1743*38fd1498Szrj 	chkp_find_bound_slots_1 (etype, have_bound, offs + cur * esize);
1744*38fd1498Szrj     }
1745*38fd1498Szrj }
1746*38fd1498Szrj 
1747*38fd1498Szrj /* Fill bitmap RES with information about bounds for
1748*38fd1498Szrj    type TYPE.  See chkp_find_bound_slots_1 for more
1749*38fd1498Szrj    details.  */
1750*38fd1498Szrj void
1751*38fd1498Szrj chkp_find_bound_slots (const_tree type, bitmap res)
1752*38fd1498Szrj {
1753*38fd1498Szrj   bitmap_clear (res);
1754*38fd1498Szrj   chkp_find_bound_slots_1 (type, res, 0);
1755*38fd1498Szrj }
1756*38fd1498Szrj 
1757*38fd1498Szrj /* Return 1 if call to FNDECL should be instrumented
1758*38fd1498Szrj    and 0 otherwise.  */
1759*38fd1498Szrj 
1760*38fd1498Szrj static bool
1761*38fd1498Szrj chkp_instrument_normal_builtin (tree fndecl)
1762*38fd1498Szrj {
1763*38fd1498Szrj   switch (DECL_FUNCTION_CODE (fndecl))
1764*38fd1498Szrj     {
1765*38fd1498Szrj     case BUILT_IN_STRLEN:
1766*38fd1498Szrj     case BUILT_IN_STRCPY:
1767*38fd1498Szrj     case BUILT_IN_STRNCPY:
1768*38fd1498Szrj     case BUILT_IN_STPCPY:
1769*38fd1498Szrj     case BUILT_IN_STPNCPY:
1770*38fd1498Szrj     case BUILT_IN_STRCAT:
1771*38fd1498Szrj     case BUILT_IN_STRNCAT:
1772*38fd1498Szrj     case BUILT_IN_MEMCPY:
1773*38fd1498Szrj     case BUILT_IN_MEMPCPY:
1774*38fd1498Szrj     case BUILT_IN_MEMSET:
1775*38fd1498Szrj     case BUILT_IN_MEMMOVE:
1776*38fd1498Szrj     case BUILT_IN_BZERO:
1777*38fd1498Szrj     case BUILT_IN_STRCMP:
1778*38fd1498Szrj     case BUILT_IN_STRNCMP:
1779*38fd1498Szrj     case BUILT_IN_BCMP:
1780*38fd1498Szrj     case BUILT_IN_MEMCMP:
1781*38fd1498Szrj     case BUILT_IN_MEMCPY_CHK:
1782*38fd1498Szrj     case BUILT_IN_MEMPCPY_CHK:
1783*38fd1498Szrj     case BUILT_IN_MEMMOVE_CHK:
1784*38fd1498Szrj     case BUILT_IN_MEMSET_CHK:
1785*38fd1498Szrj     case BUILT_IN_STRCPY_CHK:
1786*38fd1498Szrj     case BUILT_IN_STRNCPY_CHK:
1787*38fd1498Szrj     case BUILT_IN_STPCPY_CHK:
1788*38fd1498Szrj     case BUILT_IN_STPNCPY_CHK:
1789*38fd1498Szrj     case BUILT_IN_STRCAT_CHK:
1790*38fd1498Szrj     case BUILT_IN_STRNCAT_CHK:
1791*38fd1498Szrj     case BUILT_IN_MALLOC:
1792*38fd1498Szrj     case BUILT_IN_CALLOC:
1793*38fd1498Szrj     case BUILT_IN_REALLOC:
1794*38fd1498Szrj       return 1;
1795*38fd1498Szrj 
1796*38fd1498Szrj     default:
1797*38fd1498Szrj       return 0;
1798*38fd1498Szrj     }
1799*38fd1498Szrj }
1800*38fd1498Szrj 
1801*38fd1498Szrj /* Add bound arguments to call statement pointed by GSI.
1802*38fd1498Szrj    Also performs a replacement of user checker builtins calls
1803*38fd1498Szrj    with internal ones.  */
1804*38fd1498Szrj 
1805*38fd1498Szrj static void
1806*38fd1498Szrj chkp_add_bounds_to_call_stmt (gimple_stmt_iterator *gsi)
1807*38fd1498Szrj {
1808*38fd1498Szrj   gcall *call = as_a <gcall *> (gsi_stmt (*gsi));
1809*38fd1498Szrj   unsigned arg_no = 0;
1810*38fd1498Szrj   tree fndecl = gimple_call_fndecl (call);
1811*38fd1498Szrj   tree fntype;
1812*38fd1498Szrj   tree first_formal_arg;
1813*38fd1498Szrj   tree arg;
1814*38fd1498Szrj   bool use_fntype = false;
1815*38fd1498Szrj   tree op;
1816*38fd1498Szrj   ssa_op_iter iter;
1817*38fd1498Szrj   gcall *new_call;
1818*38fd1498Szrj 
1819*38fd1498Szrj   /* Do nothing for internal functions.  */
1820*38fd1498Szrj   if (gimple_call_internal_p (call))
1821*38fd1498Szrj     return;
1822*38fd1498Szrj 
1823*38fd1498Szrj   fntype = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
1824*38fd1498Szrj 
1825*38fd1498Szrj   /* Do nothing if back-end builtin is called.  */
1826*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
1827*38fd1498Szrj     return;
1828*38fd1498Szrj 
1829*38fd1498Szrj   /* Do nothing for some middle-end builtins.  */
1830*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1831*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_OBJECT_SIZE)
1832*38fd1498Szrj     return;
1833*38fd1498Szrj 
1834*38fd1498Szrj   /* Do nothing for calls to not instrumentable functions.  */
1835*38fd1498Szrj   if (fndecl && !chkp_instrumentable_p (fndecl))
1836*38fd1498Szrj     return;
1837*38fd1498Szrj 
1838*38fd1498Szrj   /* Ignore CHKP_INIT_PTR_BOUNDS, CHKP_NULL_PTR_BOUNDS
1839*38fd1498Szrj      and CHKP_COPY_PTR_BOUNDS.  */
1840*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1841*38fd1498Szrj       && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_INIT_PTR_BOUNDS
1842*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NULL_PTR_BOUNDS
1843*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_COPY_PTR_BOUNDS
1844*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_SET_PTR_BOUNDS))
1845*38fd1498Szrj     return;
1846*38fd1498Szrj 
1847*38fd1498Szrj   /* Check user builtins are replaced with checks.  */
1848*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1849*38fd1498Szrj       && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
1850*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
1851*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_CHECK_PTR_BOUNDS))
1852*38fd1498Szrj     {
1853*38fd1498Szrj       chkp_replace_address_check_builtin (gsi, integer_minus_one_node);
1854*38fd1498Szrj       return;
1855*38fd1498Szrj     }
1856*38fd1498Szrj 
1857*38fd1498Szrj   /* Check user builtins are replaced with bound extract.  */
1858*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1859*38fd1498Szrj       && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_LBOUND
1860*38fd1498Szrj 	  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_GET_PTR_UBOUND))
1861*38fd1498Szrj     {
1862*38fd1498Szrj       chkp_replace_extract_builtin (gsi);
1863*38fd1498Szrj       return;
1864*38fd1498Szrj     }
1865*38fd1498Szrj 
1866*38fd1498Szrj   /* BUILT_IN_CHKP_NARROW_PTR_BOUNDS call is replaced with
1867*38fd1498Szrj      target narrow bounds call.  */
1868*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1869*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NARROW_PTR_BOUNDS)
1870*38fd1498Szrj     {
1871*38fd1498Szrj       tree arg = gimple_call_arg (call, 1);
1872*38fd1498Szrj       tree bounds = chkp_find_bounds (arg, gsi);
1873*38fd1498Szrj 
1874*38fd1498Szrj       gimple_call_set_fndecl (call, chkp_narrow_bounds_fndecl);
1875*38fd1498Szrj       gimple_call_set_arg (call, 1, bounds);
1876*38fd1498Szrj       update_stmt (call);
1877*38fd1498Szrj 
1878*38fd1498Szrj       return;
1879*38fd1498Szrj     }
1880*38fd1498Szrj 
1881*38fd1498Szrj   /* BUILT_IN_CHKP_STORE_PTR_BOUNDS call is replaced with
1882*38fd1498Szrj      bndstx call.  */
1883*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1884*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_STORE_PTR_BOUNDS)
1885*38fd1498Szrj     {
1886*38fd1498Szrj       tree addr = gimple_call_arg (call, 0);
1887*38fd1498Szrj       tree ptr = gimple_call_arg (call, 1);
1888*38fd1498Szrj       tree bounds = chkp_find_bounds (ptr, gsi);
1889*38fd1498Szrj       gimple_stmt_iterator iter = gsi_for_stmt (call);
1890*38fd1498Szrj 
1891*38fd1498Szrj       chkp_build_bndstx (addr, ptr, bounds, gsi);
1892*38fd1498Szrj       gsi_remove (&iter, true);
1893*38fd1498Szrj 
1894*38fd1498Szrj       return;
1895*38fd1498Szrj     }
1896*38fd1498Szrj 
1897*38fd1498Szrj   if (!flag_chkp_instrument_calls)
1898*38fd1498Szrj     return;
1899*38fd1498Szrj 
1900*38fd1498Szrj   /* We instrument only some subset of builtins.  We also instrument
1901*38fd1498Szrj      builtin calls to be inlined.  */
1902*38fd1498Szrj   if (fndecl
1903*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
1904*38fd1498Szrj       && !chkp_instrument_normal_builtin (fndecl))
1905*38fd1498Szrj     {
1906*38fd1498Szrj       if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)))
1907*38fd1498Szrj 	return;
1908*38fd1498Szrj 
1909*38fd1498Szrj       struct cgraph_node *clone = chkp_maybe_create_clone (fndecl);
1910*38fd1498Szrj       if (!clone
1911*38fd1498Szrj 	  || !gimple_has_body_p (clone->decl))
1912*38fd1498Szrj 	return;
1913*38fd1498Szrj     }
1914*38fd1498Szrj 
1915*38fd1498Szrj   /* If function decl is available then use it for
1916*38fd1498Szrj      formal arguments list.  Otherwise use function type.  */
1917*38fd1498Szrj   if (fndecl
1918*38fd1498Szrj       && DECL_ARGUMENTS (fndecl)
1919*38fd1498Szrj       && gimple_call_fntype (call) == TREE_TYPE (fndecl))
1920*38fd1498Szrj     first_formal_arg = DECL_ARGUMENTS (fndecl);
1921*38fd1498Szrj   else
1922*38fd1498Szrj     {
1923*38fd1498Szrj       first_formal_arg = TYPE_ARG_TYPES (fntype);
1924*38fd1498Szrj       use_fntype = true;
1925*38fd1498Szrj     }
1926*38fd1498Szrj 
1927*38fd1498Szrj   /* Fill vector of new call args.  */
1928*38fd1498Szrj   vec<tree> new_args = vNULL;
1929*38fd1498Szrj   new_args.create (gimple_call_num_args (call));
1930*38fd1498Szrj   arg = first_formal_arg;
1931*38fd1498Szrj   for (arg_no = 0; arg_no < gimple_call_num_args (call); arg_no++)
1932*38fd1498Szrj     {
1933*38fd1498Szrj       tree call_arg = gimple_call_arg (call, arg_no);
1934*38fd1498Szrj       tree type;
1935*38fd1498Szrj 
1936*38fd1498Szrj       /* Get arg type using formal argument description
1937*38fd1498Szrj 	 or actual argument type.  */
1938*38fd1498Szrj       if (arg)
1939*38fd1498Szrj 	if (use_fntype)
1940*38fd1498Szrj 	  if (TREE_VALUE (arg) != void_type_node)
1941*38fd1498Szrj 	    {
1942*38fd1498Szrj 	      type = TREE_VALUE (arg);
1943*38fd1498Szrj 	      arg = TREE_CHAIN (arg);
1944*38fd1498Szrj 	    }
1945*38fd1498Szrj 	  else
1946*38fd1498Szrj 	    type = TREE_TYPE (call_arg);
1947*38fd1498Szrj 	else
1948*38fd1498Szrj 	  {
1949*38fd1498Szrj 	    type = TREE_TYPE (arg);
1950*38fd1498Szrj 	    arg = TREE_CHAIN (arg);
1951*38fd1498Szrj 	  }
1952*38fd1498Szrj       else
1953*38fd1498Szrj 	type = TREE_TYPE (call_arg);
1954*38fd1498Szrj 
1955*38fd1498Szrj       new_args.safe_push (call_arg);
1956*38fd1498Szrj 
1957*38fd1498Szrj       if (BOUNDED_TYPE_P (type)
1958*38fd1498Szrj 	  || pass_by_reference (NULL, TYPE_MODE (type), type, true))
1959*38fd1498Szrj 	new_args.safe_push (chkp_find_bounds (call_arg, gsi));
1960*38fd1498Szrj       else if (chkp_type_has_pointer (type))
1961*38fd1498Szrj 	{
1962*38fd1498Szrj 	  HOST_WIDE_INT max_bounds
1963*38fd1498Szrj 	    = TREE_INT_CST_LOW (TYPE_SIZE (type)) / POINTER_SIZE;
1964*38fd1498Szrj 	  tree *all_bounds = (tree *)xmalloc (sizeof (tree) * max_bounds);
1965*38fd1498Szrj 	  HOST_WIDE_INT bnd_no;
1966*38fd1498Szrj 
1967*38fd1498Szrj 	  memset (all_bounds, 0, sizeof (tree) * max_bounds);
1968*38fd1498Szrj 
1969*38fd1498Szrj 	  chkp_find_bounds_for_elem (call_arg, all_bounds, 0, gsi);
1970*38fd1498Szrj 
1971*38fd1498Szrj 	  for (bnd_no = 0; bnd_no < max_bounds; bnd_no++)
1972*38fd1498Szrj 	    if (all_bounds[bnd_no])
1973*38fd1498Szrj 	      new_args.safe_push (all_bounds[bnd_no]);
1974*38fd1498Szrj 
1975*38fd1498Szrj            free (all_bounds);
1976*38fd1498Szrj 	}
1977*38fd1498Szrj     }
1978*38fd1498Szrj 
1979*38fd1498Szrj   if (new_args.length () == gimple_call_num_args (call))
1980*38fd1498Szrj     new_call = call;
1981*38fd1498Szrj   else
1982*38fd1498Szrj     {
1983*38fd1498Szrj       new_call = gimple_build_call_vec (gimple_op (call, 1), new_args);
1984*38fd1498Szrj       gimple_call_set_lhs (new_call, gimple_call_lhs (call));
1985*38fd1498Szrj       gimple_call_copy_flags (new_call, call);
1986*38fd1498Szrj       gimple_call_set_chain (new_call, gimple_call_chain (call));
1987*38fd1498Szrj     }
1988*38fd1498Szrj   new_args.release ();
1989*38fd1498Szrj 
1990*38fd1498Szrj   /* For direct calls fndecl is replaced with instrumented version.  */
1991*38fd1498Szrj   if (fndecl)
1992*38fd1498Szrj     {
1993*38fd1498Szrj       tree new_decl = chkp_maybe_create_clone (fndecl)->decl;
1994*38fd1498Szrj       gimple_call_set_fndecl (new_call, new_decl);
1995*38fd1498Szrj       /* In case of a type cast we should modify used function
1996*38fd1498Szrj 	 type instead of using type of new fndecl.  */
1997*38fd1498Szrj       if (gimple_call_fntype (call) != TREE_TYPE (fndecl))
1998*38fd1498Szrj 	{
1999*38fd1498Szrj 	  tree type = gimple_call_fntype (call);
2000*38fd1498Szrj 	  type = chkp_copy_function_type_adding_bounds (type);
2001*38fd1498Szrj 	  gimple_call_set_fntype (new_call, type);
2002*38fd1498Szrj 	}
2003*38fd1498Szrj       else
2004*38fd1498Szrj 	gimple_call_set_fntype (new_call, TREE_TYPE (new_decl));
2005*38fd1498Szrj     }
2006*38fd1498Szrj   /* For indirect call we should fix function pointer type if
2007*38fd1498Szrj      pass some bounds.  */
2008*38fd1498Szrj   else if (new_call != call)
2009*38fd1498Szrj     {
2010*38fd1498Szrj       tree type = gimple_call_fntype (call);
2011*38fd1498Szrj       type = chkp_copy_function_type_adding_bounds (type);
2012*38fd1498Szrj       gimple_call_set_fntype (new_call, type);
2013*38fd1498Szrj     }
2014*38fd1498Szrj 
2015*38fd1498Szrj   /* replace old call statement with the new one.  */
2016*38fd1498Szrj   if (call != new_call)
2017*38fd1498Szrj     {
2018*38fd1498Szrj       FOR_EACH_SSA_TREE_OPERAND (op, call, iter, SSA_OP_ALL_DEFS)
2019*38fd1498Szrj 	{
2020*38fd1498Szrj 	  SSA_NAME_DEF_STMT (op) = new_call;
2021*38fd1498Szrj 	}
2022*38fd1498Szrj       gsi_replace (gsi, new_call, true);
2023*38fd1498Szrj     }
2024*38fd1498Szrj   else
2025*38fd1498Szrj     update_stmt (new_call);
2026*38fd1498Szrj 
2027*38fd1498Szrj   gimple_call_set_with_bounds (new_call, true);
2028*38fd1498Szrj }
2029*38fd1498Szrj 
2030*38fd1498Szrj /* Return constant static bounds var with specified bounds LB and UB.
2031*38fd1498Szrj    If such var does not exists then new var is created with specified NAME.  */
2032*38fd1498Szrj static tree
2033*38fd1498Szrj chkp_make_static_const_bounds (HOST_WIDE_INT lb,
2034*38fd1498Szrj 			       HOST_WIDE_INT ub,
2035*38fd1498Szrj 			       const char *name)
2036*38fd1498Szrj {
2037*38fd1498Szrj   tree id = get_identifier (name);
2038*38fd1498Szrj   tree var;
2039*38fd1498Szrj   varpool_node *node;
2040*38fd1498Szrj   symtab_node *snode;
2041*38fd1498Szrj 
2042*38fd1498Szrj   var  = build_decl (UNKNOWN_LOCATION, VAR_DECL, id,
2043*38fd1498Szrj 		     pointer_bounds_type_node);
2044*38fd1498Szrj   TREE_STATIC (var) = 1;
2045*38fd1498Szrj   TREE_PUBLIC (var) = 1;
2046*38fd1498Szrj 
2047*38fd1498Szrj   /* With LTO we may have constant bounds already in varpool.
2048*38fd1498Szrj      Try to find it.  */
2049*38fd1498Szrj   if ((snode = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (var))))
2050*38fd1498Szrj     {
2051*38fd1498Szrj       /* We don't allow this symbol usage for non bounds.  */
2052*38fd1498Szrj       if (snode->type != SYMTAB_VARIABLE
2053*38fd1498Szrj 	  || !POINTER_BOUNDS_P (snode->decl))
2054*38fd1498Szrj 	sorry ("-fcheck-pointer-bounds requires %qs "
2055*38fd1498Szrj 	       "name for internal usage",
2056*38fd1498Szrj 	       IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (var)));
2057*38fd1498Szrj 
2058*38fd1498Szrj       return snode->decl;
2059*38fd1498Szrj     }
2060*38fd1498Szrj 
2061*38fd1498Szrj   TREE_USED (var) = 1;
2062*38fd1498Szrj   TREE_READONLY (var) = 1;
2063*38fd1498Szrj   TREE_ADDRESSABLE (var) = 0;
2064*38fd1498Szrj   DECL_ARTIFICIAL (var) = 1;
2065*38fd1498Szrj   DECL_READ_P (var) = 1;
2066*38fd1498Szrj   DECL_INITIAL (var) = targetm.chkp_make_bounds_constant (lb, ub);
2067*38fd1498Szrj   make_decl_one_only (var, DECL_ASSEMBLER_NAME (var));
2068*38fd1498Szrj   /* We may use this symbol during ctors generation in chkp_finish_file
2069*38fd1498Szrj      when all symbols are emitted.  Force output to avoid undefined
2070*38fd1498Szrj      symbols in ctors.  */
2071*38fd1498Szrj   node = varpool_node::get_create (var);
2072*38fd1498Szrj   node->force_output = 1;
2073*38fd1498Szrj 
2074*38fd1498Szrj   varpool_node::finalize_decl (var);
2075*38fd1498Szrj 
2076*38fd1498Szrj   return var;
2077*38fd1498Szrj }
2078*38fd1498Szrj 
2079*38fd1498Szrj /* Generate code to make bounds with specified lower bound LB and SIZE.
2080*38fd1498Szrj    if AFTER is 1 then code is inserted after position pointed by ITER
2081*38fd1498Szrj    otherwise code is inserted before position pointed by ITER.
2082*38fd1498Szrj    If ITER is NULL then code is added to entry block.  */
2083*38fd1498Szrj static tree
2084*38fd1498Szrj chkp_make_bounds (tree lb, tree size, gimple_stmt_iterator *iter, bool after)
2085*38fd1498Szrj {
2086*38fd1498Szrj   gimple_seq seq;
2087*38fd1498Szrj   gimple_stmt_iterator gsi;
2088*38fd1498Szrj   gimple *stmt;
2089*38fd1498Szrj   tree bounds;
2090*38fd1498Szrj 
2091*38fd1498Szrj   if (iter)
2092*38fd1498Szrj     gsi = *iter;
2093*38fd1498Szrj   else
2094*38fd1498Szrj     gsi = gsi_start_bb (chkp_get_entry_block ());
2095*38fd1498Szrj 
2096*38fd1498Szrj   seq = NULL;
2097*38fd1498Szrj 
2098*38fd1498Szrj   lb = chkp_force_gimple_call_op (lb, &seq);
2099*38fd1498Szrj   size = chkp_force_gimple_call_op (size, &seq);
2100*38fd1498Szrj 
2101*38fd1498Szrj   stmt = gimple_build_call (chkp_bndmk_fndecl, 2, lb, size);
2102*38fd1498Szrj   chkp_mark_stmt (stmt);
2103*38fd1498Szrj 
2104*38fd1498Szrj   bounds = chkp_get_tmp_reg (stmt);
2105*38fd1498Szrj   gimple_call_set_lhs (stmt, bounds);
2106*38fd1498Szrj 
2107*38fd1498Szrj   gimple_seq_add_stmt (&seq, stmt);
2108*38fd1498Szrj 
2109*38fd1498Szrj   if (iter && after)
2110*38fd1498Szrj     gsi_insert_seq_after (&gsi, seq, GSI_SAME_STMT);
2111*38fd1498Szrj   else
2112*38fd1498Szrj     gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
2113*38fd1498Szrj 
2114*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2115*38fd1498Szrj     {
2116*38fd1498Szrj       fprintf (dump_file, "Made bounds: ");
2117*38fd1498Szrj       print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS);
2118*38fd1498Szrj       if (iter)
2119*38fd1498Szrj 	{
2120*38fd1498Szrj 	  fprintf (dump_file, "  inserted before statement: ");
2121*38fd1498Szrj 	  print_gimple_stmt (dump_file, gsi_stmt (*iter), 0, TDF_VOPS|TDF_MEMSYMS);
2122*38fd1498Szrj 	}
2123*38fd1498Szrj       else
2124*38fd1498Szrj 	fprintf (dump_file, "  at function entry\n");
2125*38fd1498Szrj     }
2126*38fd1498Szrj 
2127*38fd1498Szrj   /* update_stmt (stmt); */
2128*38fd1498Szrj 
2129*38fd1498Szrj   return bounds;
2130*38fd1498Szrj }
2131*38fd1498Szrj 
2132*38fd1498Szrj /* Return var holding zero bounds.  */
2133*38fd1498Szrj tree
2134*38fd1498Szrj chkp_get_zero_bounds_var (void)
2135*38fd1498Szrj {
2136*38fd1498Szrj   if (!chkp_zero_bounds_var)
2137*38fd1498Szrj     chkp_zero_bounds_var
2138*38fd1498Szrj       = chkp_make_static_const_bounds (0, -1,
2139*38fd1498Szrj 				       CHKP_ZERO_BOUNDS_VAR_NAME);
2140*38fd1498Szrj   return chkp_zero_bounds_var;
2141*38fd1498Szrj }
2142*38fd1498Szrj 
2143*38fd1498Szrj /* Return var holding none bounds.  */
2144*38fd1498Szrj tree
2145*38fd1498Szrj chkp_get_none_bounds_var (void)
2146*38fd1498Szrj {
2147*38fd1498Szrj   if (!chkp_none_bounds_var)
2148*38fd1498Szrj     chkp_none_bounds_var
2149*38fd1498Szrj       = chkp_make_static_const_bounds (-1, 0,
2150*38fd1498Szrj 				       CHKP_NONE_BOUNDS_VAR_NAME);
2151*38fd1498Szrj   return chkp_none_bounds_var;
2152*38fd1498Szrj }
2153*38fd1498Szrj 
2154*38fd1498Szrj /* Return SSA_NAME used to represent zero bounds.  */
2155*38fd1498Szrj static tree
2156*38fd1498Szrj chkp_get_zero_bounds (void)
2157*38fd1498Szrj {
2158*38fd1498Szrj   if (zero_bounds)
2159*38fd1498Szrj     return zero_bounds;
2160*38fd1498Szrj 
2161*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2162*38fd1498Szrj     fprintf (dump_file, "Creating zero bounds...");
2163*38fd1498Szrj 
2164*38fd1498Szrj   if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds)
2165*38fd1498Szrj       || flag_chkp_use_static_const_bounds > 0)
2166*38fd1498Szrj     {
2167*38fd1498Szrj       gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ());
2168*38fd1498Szrj       gimple *stmt;
2169*38fd1498Szrj 
2170*38fd1498Szrj       zero_bounds = chkp_get_tmp_reg (NULL);
2171*38fd1498Szrj       stmt = gimple_build_assign (zero_bounds, chkp_get_zero_bounds_var ());
2172*38fd1498Szrj       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
2173*38fd1498Szrj     }
2174*38fd1498Szrj   else
2175*38fd1498Szrj     zero_bounds = chkp_make_bounds (integer_zero_node,
2176*38fd1498Szrj 				    integer_zero_node,
2177*38fd1498Szrj 				    NULL,
2178*38fd1498Szrj 				    false);
2179*38fd1498Szrj 
2180*38fd1498Szrj   return zero_bounds;
2181*38fd1498Szrj }
2182*38fd1498Szrj 
2183*38fd1498Szrj /* Return SSA_NAME used to represent none bounds.  */
2184*38fd1498Szrj static tree
2185*38fd1498Szrj chkp_get_none_bounds (void)
2186*38fd1498Szrj {
2187*38fd1498Szrj   if (none_bounds)
2188*38fd1498Szrj     return none_bounds;
2189*38fd1498Szrj 
2190*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2191*38fd1498Szrj     fprintf (dump_file, "Creating none bounds...");
2192*38fd1498Szrj 
2193*38fd1498Szrj 
2194*38fd1498Szrj   if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds)
2195*38fd1498Szrj       || flag_chkp_use_static_const_bounds > 0)
2196*38fd1498Szrj     {
2197*38fd1498Szrj       gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ());
2198*38fd1498Szrj       gimple *stmt;
2199*38fd1498Szrj 
2200*38fd1498Szrj       none_bounds = chkp_get_tmp_reg (NULL);
2201*38fd1498Szrj       stmt = gimple_build_assign (none_bounds, chkp_get_none_bounds_var ());
2202*38fd1498Szrj       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
2203*38fd1498Szrj     }
2204*38fd1498Szrj   else
2205*38fd1498Szrj     none_bounds = chkp_make_bounds (integer_minus_one_node,
2206*38fd1498Szrj 				    build_int_cst (size_type_node, 2),
2207*38fd1498Szrj 				    NULL,
2208*38fd1498Szrj 				    false);
2209*38fd1498Szrj 
2210*38fd1498Szrj   return none_bounds;
2211*38fd1498Szrj }
2212*38fd1498Szrj 
2213*38fd1498Szrj /* Return bounds to be used as a result of operation which
2214*38fd1498Szrj    should not create poiunter (e.g. MULT_EXPR).  */
2215*38fd1498Szrj static tree
2216*38fd1498Szrj chkp_get_invalid_op_bounds (void)
2217*38fd1498Szrj {
2218*38fd1498Szrj   return chkp_get_zero_bounds ();
2219*38fd1498Szrj }
2220*38fd1498Szrj 
2221*38fd1498Szrj /* Return bounds to be used for loads of non-pointer values.  */
2222*38fd1498Szrj static tree
2223*38fd1498Szrj chkp_get_nonpointer_load_bounds (void)
2224*38fd1498Szrj {
2225*38fd1498Szrj   return chkp_get_zero_bounds ();
2226*38fd1498Szrj }
2227*38fd1498Szrj 
2228*38fd1498Szrj /* Return 1 if may use bndret call to get bounds for pointer
2229*38fd1498Szrj    returned by CALL.  */
2230*38fd1498Szrj static bool
2231*38fd1498Szrj chkp_call_returns_bounds_p (gcall *call)
2232*38fd1498Szrj {
2233*38fd1498Szrj   if (gimple_call_internal_p (call))
2234*38fd1498Szrj     {
2235*38fd1498Szrj       if (gimple_call_internal_fn (call) == IFN_VA_ARG)
2236*38fd1498Szrj 	return true;
2237*38fd1498Szrj       return false;
2238*38fd1498Szrj     }
2239*38fd1498Szrj 
2240*38fd1498Szrj   if (gimple_call_builtin_p (call, BUILT_IN_CHKP_NARROW_PTR_BOUNDS)
2241*38fd1498Szrj       || chkp_gimple_call_builtin_p (call, BUILT_IN_CHKP_NARROW))
2242*38fd1498Szrj     return true;
2243*38fd1498Szrj 
2244*38fd1498Szrj   if (gimple_call_with_bounds_p (call))
2245*38fd1498Szrj     return true;
2246*38fd1498Szrj 
2247*38fd1498Szrj   tree fndecl = gimple_call_fndecl (call);
2248*38fd1498Szrj 
2249*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
2250*38fd1498Szrj     return false;
2251*38fd1498Szrj 
2252*38fd1498Szrj   if (fndecl && !chkp_instrumentable_p (fndecl))
2253*38fd1498Szrj     return false;
2254*38fd1498Szrj 
2255*38fd1498Szrj   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
2256*38fd1498Szrj     {
2257*38fd1498Szrj       if (chkp_instrument_normal_builtin (fndecl))
2258*38fd1498Szrj 	return true;
2259*38fd1498Szrj 
2260*38fd1498Szrj       if (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)))
2261*38fd1498Szrj 	return false;
2262*38fd1498Szrj 
2263*38fd1498Szrj       struct cgraph_node *clone = chkp_maybe_create_clone (fndecl);
2264*38fd1498Szrj       return (clone && gimple_has_body_p (clone->decl));
2265*38fd1498Szrj     }
2266*38fd1498Szrj 
2267*38fd1498Szrj   return true;
2268*38fd1498Szrj }
2269*38fd1498Szrj 
2270*38fd1498Szrj /* Build bounds returned by CALL.  */
2271*38fd1498Szrj static tree
2272*38fd1498Szrj chkp_build_returned_bound (gcall *call)
2273*38fd1498Szrj {
2274*38fd1498Szrj   gimple_stmt_iterator gsi;
2275*38fd1498Szrj   tree bounds;
2276*38fd1498Szrj   gimple *stmt;
2277*38fd1498Szrj   tree fndecl = gimple_call_fndecl (call);
2278*38fd1498Szrj   unsigned int retflags;
2279*38fd1498Szrj   tree lhs = gimple_call_lhs (call);
2280*38fd1498Szrj 
2281*38fd1498Szrj   /* To avoid fixing alloca expands in targets we handle
2282*38fd1498Szrj      it separately.  */
2283*38fd1498Szrj   if (fndecl
2284*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2285*38fd1498Szrj       && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl)))
2286*38fd1498Szrj     {
2287*38fd1498Szrj       tree size = gimple_call_arg (call, 0);
2288*38fd1498Szrj       gimple_stmt_iterator iter = gsi_for_stmt (call);
2289*38fd1498Szrj       bounds = chkp_make_bounds (lhs, size, &iter, true);
2290*38fd1498Szrj     }
2291*38fd1498Szrj   /* We know bounds returned by set_bounds builtin call.  */
2292*38fd1498Szrj   else if (fndecl
2293*38fd1498Szrj 	   && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2294*38fd1498Szrj 	   && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_SET_PTR_BOUNDS)
2295*38fd1498Szrj     {
2296*38fd1498Szrj       tree lb = gimple_call_arg (call, 0);
2297*38fd1498Szrj       tree size = gimple_call_arg (call, 1);
2298*38fd1498Szrj       gimple_stmt_iterator iter = gsi_for_stmt (call);
2299*38fd1498Szrj       bounds = chkp_make_bounds (lb, size, &iter, true);
2300*38fd1498Szrj     }
2301*38fd1498Szrj   /* Detect bounds initialization calls.  */
2302*38fd1498Szrj   else if (fndecl
2303*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2304*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_INIT_PTR_BOUNDS)
2305*38fd1498Szrj     bounds = chkp_get_zero_bounds ();
2306*38fd1498Szrj   /* Detect bounds nullification calls.  */
2307*38fd1498Szrj   else if (fndecl
2308*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2309*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_NULL_PTR_BOUNDS)
2310*38fd1498Szrj     bounds = chkp_get_none_bounds ();
2311*38fd1498Szrj   /* Detect bounds copy calls.  */
2312*38fd1498Szrj   else if (fndecl
2313*38fd1498Szrj       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
2314*38fd1498Szrj       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_COPY_PTR_BOUNDS)
2315*38fd1498Szrj     {
2316*38fd1498Szrj       gimple_stmt_iterator iter = gsi_for_stmt (call);
2317*38fd1498Szrj       bounds = chkp_find_bounds (gimple_call_arg (call, 1), &iter);
2318*38fd1498Szrj     }
2319*38fd1498Szrj   /* Do not use retbnd when returned bounds are equal to some
2320*38fd1498Szrj      of passed bounds.  */
2321*38fd1498Szrj   else if (((retflags = gimple_call_return_flags (call)) & ERF_RETURNS_ARG)
2322*38fd1498Szrj 	   && (retflags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (call))
2323*38fd1498Szrj     {
2324*38fd1498Szrj       gimple_stmt_iterator iter = gsi_for_stmt (call);
2325*38fd1498Szrj       unsigned int retarg = retflags & ERF_RETURN_ARG_MASK, argno;
2326*38fd1498Szrj       if (gimple_call_with_bounds_p (call))
2327*38fd1498Szrj 	{
2328*38fd1498Szrj 	  for (argno = 0; argno < gimple_call_num_args (call); argno++)
2329*38fd1498Szrj 	    if (!POINTER_BOUNDS_P (gimple_call_arg (call, argno)))
2330*38fd1498Szrj 	      {
2331*38fd1498Szrj 		if (retarg)
2332*38fd1498Szrj 		  retarg--;
2333*38fd1498Szrj 		else
2334*38fd1498Szrj 		  break;
2335*38fd1498Szrj 	      }
2336*38fd1498Szrj 	}
2337*38fd1498Szrj       else
2338*38fd1498Szrj 	argno = retarg;
2339*38fd1498Szrj 
2340*38fd1498Szrj       bounds = chkp_find_bounds (gimple_call_arg (call, argno), &iter);
2341*38fd1498Szrj     }
2342*38fd1498Szrj   else if (chkp_call_returns_bounds_p (call)
2343*38fd1498Szrj 	   && BOUNDED_P (lhs))
2344*38fd1498Szrj     {
2345*38fd1498Szrj       gcc_assert (TREE_CODE (lhs) == SSA_NAME);
2346*38fd1498Szrj 
2347*38fd1498Szrj       /* In general case build checker builtin call to
2348*38fd1498Szrj 	 obtain returned bounds.  */
2349*38fd1498Szrj       stmt = gimple_build_call (chkp_ret_bnd_fndecl, 1,
2350*38fd1498Szrj 				gimple_call_lhs (call));
2351*38fd1498Szrj       chkp_mark_stmt (stmt);
2352*38fd1498Szrj 
2353*38fd1498Szrj       gsi = gsi_for_stmt (call);
2354*38fd1498Szrj       gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
2355*38fd1498Szrj 
2356*38fd1498Szrj       bounds = chkp_get_tmp_reg (stmt);
2357*38fd1498Szrj       gimple_call_set_lhs (stmt, bounds);
2358*38fd1498Szrj 
2359*38fd1498Szrj       update_stmt (stmt);
2360*38fd1498Szrj     }
2361*38fd1498Szrj   else
2362*38fd1498Szrj     bounds = chkp_get_zero_bounds ();
2363*38fd1498Szrj 
2364*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2365*38fd1498Szrj     {
2366*38fd1498Szrj       fprintf (dump_file, "Built returned bounds (");
2367*38fd1498Szrj       print_generic_expr (dump_file, bounds);
2368*38fd1498Szrj       fprintf (dump_file, ") for call: ");
2369*38fd1498Szrj       print_gimple_stmt (dump_file, call, 0, TDF_VOPS | TDF_MEMSYMS);
2370*38fd1498Szrj     }
2371*38fd1498Szrj 
2372*38fd1498Szrj   bounds = chkp_maybe_copy_and_register_bounds (lhs, bounds);
2373*38fd1498Szrj 
2374*38fd1498Szrj   return bounds;
2375*38fd1498Szrj }
2376*38fd1498Szrj 
2377*38fd1498Szrj /* Return bounds used as returned by call
2378*38fd1498Szrj    which produced SSA name VAL.  */
2379*38fd1498Szrj gcall *
2380*38fd1498Szrj chkp_retbnd_call_by_val (tree val)
2381*38fd1498Szrj {
2382*38fd1498Szrj   if (TREE_CODE (val) != SSA_NAME)
2383*38fd1498Szrj     return NULL;
2384*38fd1498Szrj 
2385*38fd1498Szrj   gcc_assert (gimple_code (SSA_NAME_DEF_STMT (val)) == GIMPLE_CALL);
2386*38fd1498Szrj 
2387*38fd1498Szrj   imm_use_iterator use_iter;
2388*38fd1498Szrj   use_operand_p use_p;
2389*38fd1498Szrj   FOR_EACH_IMM_USE_FAST (use_p, use_iter, val)
2390*38fd1498Szrj     if (chkp_gimple_call_builtin_p (USE_STMT (use_p), BUILT_IN_CHKP_BNDRET))
2391*38fd1498Szrj       return as_a <gcall *> (USE_STMT (use_p));
2392*38fd1498Szrj 
2393*38fd1498Szrj   return NULL;
2394*38fd1498Szrj }
2395*38fd1498Szrj 
2396*38fd1498Szrj /* Check the next parameter for the given PARM is bounds
2397*38fd1498Szrj    and return it's default SSA_NAME (create if required).  */
2398*38fd1498Szrj static tree
2399*38fd1498Szrj chkp_get_next_bounds_parm (tree parm)
2400*38fd1498Szrj {
2401*38fd1498Szrj   tree bounds = TREE_CHAIN (parm);
2402*38fd1498Szrj   gcc_assert (POINTER_BOUNDS_P (bounds));
2403*38fd1498Szrj   bounds = ssa_default_def (cfun, bounds);
2404*38fd1498Szrj   if (!bounds)
2405*38fd1498Szrj     {
2406*38fd1498Szrj       bounds = make_ssa_name (TREE_CHAIN (parm), gimple_build_nop ());
2407*38fd1498Szrj       set_ssa_default_def (cfun, TREE_CHAIN (parm), bounds);
2408*38fd1498Szrj     }
2409*38fd1498Szrj   return bounds;
2410*38fd1498Szrj }
2411*38fd1498Szrj 
2412*38fd1498Szrj /* Return bounds to be used for input argument PARM.  */
2413*38fd1498Szrj static tree
2414*38fd1498Szrj chkp_get_bound_for_parm (tree parm)
2415*38fd1498Szrj {
2416*38fd1498Szrj   tree decl = SSA_NAME_VAR (parm);
2417*38fd1498Szrj   tree bounds;
2418*38fd1498Szrj 
2419*38fd1498Szrj   gcc_assert (TREE_CODE (decl) == PARM_DECL);
2420*38fd1498Szrj 
2421*38fd1498Szrj   bounds = chkp_get_registered_bounds (parm);
2422*38fd1498Szrj 
2423*38fd1498Szrj   if (!bounds)
2424*38fd1498Szrj     bounds = chkp_get_registered_bounds (decl);
2425*38fd1498Szrj 
2426*38fd1498Szrj   if (!bounds)
2427*38fd1498Szrj     {
2428*38fd1498Szrj       tree orig_decl = cgraph_node::get (cfun->decl)->orig_decl;
2429*38fd1498Szrj 
2430*38fd1498Szrj       /* For static chain param we return zero bounds
2431*38fd1498Szrj 	 because currently we do not check dereferences
2432*38fd1498Szrj 	 of this pointer.  */
2433*38fd1498Szrj       if (cfun->static_chain_decl == decl)
2434*38fd1498Szrj 	bounds = chkp_get_zero_bounds ();
2435*38fd1498Szrj       /* If non instrumented runtime is used then it may be useful
2436*38fd1498Szrj 	 to use zero bounds for input arguments of main
2437*38fd1498Szrj 	 function.  */
2438*38fd1498Szrj       else if (flag_chkp_zero_input_bounds_for_main
2439*38fd1498Szrj 	       && id_equal (DECL_ASSEMBLER_NAME (orig_decl), "main"))
2440*38fd1498Szrj 	bounds = chkp_get_zero_bounds ();
2441*38fd1498Szrj       else if (BOUNDED_P (parm))
2442*38fd1498Szrj 	{
2443*38fd1498Szrj 	  bounds = chkp_get_next_bounds_parm (decl);
2444*38fd1498Szrj 	  bounds = chkp_maybe_copy_and_register_bounds (decl, bounds);
2445*38fd1498Szrj 
2446*38fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
2447*38fd1498Szrj 	    {
2448*38fd1498Szrj 	      fprintf (dump_file, "Built arg bounds (");
2449*38fd1498Szrj 	      print_generic_expr (dump_file, bounds);
2450*38fd1498Szrj 	      fprintf (dump_file, ") for arg: ");
2451*38fd1498Szrj 	      print_node (dump_file, "", decl, 0);
2452*38fd1498Szrj 	    }
2453*38fd1498Szrj 	}
2454*38fd1498Szrj       else
2455*38fd1498Szrj 	bounds = chkp_get_zero_bounds ();
2456*38fd1498Szrj     }
2457*38fd1498Szrj 
2458*38fd1498Szrj   if (!chkp_get_registered_bounds (parm))
2459*38fd1498Szrj     bounds = chkp_maybe_copy_and_register_bounds (parm, bounds);
2460*38fd1498Szrj 
2461*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2462*38fd1498Szrj     {
2463*38fd1498Szrj       fprintf (dump_file, "Using bounds ");
2464*38fd1498Szrj       print_generic_expr (dump_file, bounds);
2465*38fd1498Szrj       fprintf (dump_file, " for parm ");
2466*38fd1498Szrj       print_generic_expr (dump_file, parm);
2467*38fd1498Szrj       fprintf (dump_file, " of type ");
2468*38fd1498Szrj       print_generic_expr (dump_file, TREE_TYPE (parm));
2469*38fd1498Szrj       fprintf (dump_file, ".\n");
2470*38fd1498Szrj     }
2471*38fd1498Szrj 
2472*38fd1498Szrj   return bounds;
2473*38fd1498Szrj }
2474*38fd1498Szrj 
2475*38fd1498Szrj /* Build and return CALL_EXPR for bndstx builtin with specified
2476*38fd1498Szrj    arguments.  */
2477*38fd1498Szrj tree
2478*38fd1498Szrj chkp_build_bndldx_call (tree addr, tree ptr)
2479*38fd1498Szrj {
2480*38fd1498Szrj   tree fn = build1 (ADDR_EXPR,
2481*38fd1498Szrj 		    build_pointer_type (TREE_TYPE (chkp_bndldx_fndecl)),
2482*38fd1498Szrj 		    chkp_bndldx_fndecl);
2483*38fd1498Szrj   tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndldx_fndecl)),
2484*38fd1498Szrj 			       fn, 2, addr, ptr);
2485*38fd1498Szrj   CALL_WITH_BOUNDS_P (call) = true;
2486*38fd1498Szrj   return call;
2487*38fd1498Szrj }
2488*38fd1498Szrj 
2489*38fd1498Szrj /* Insert code to load bounds for PTR located by ADDR.
2490*38fd1498Szrj    Code is inserted after position pointed by GSI.
2491*38fd1498Szrj    Loaded bounds are returned.  */
2492*38fd1498Szrj static tree
2493*38fd1498Szrj chkp_build_bndldx (tree addr, tree ptr, gimple_stmt_iterator *gsi)
2494*38fd1498Szrj {
2495*38fd1498Szrj   gimple_seq seq;
2496*38fd1498Szrj   gimple *stmt;
2497*38fd1498Szrj   tree bounds;
2498*38fd1498Szrj 
2499*38fd1498Szrj   seq = NULL;
2500*38fd1498Szrj 
2501*38fd1498Szrj   addr = chkp_force_gimple_call_op (addr, &seq);
2502*38fd1498Szrj   ptr = chkp_force_gimple_call_op (ptr, &seq);
2503*38fd1498Szrj 
2504*38fd1498Szrj   stmt = gimple_build_call (chkp_bndldx_fndecl, 2, addr, ptr);
2505*38fd1498Szrj   chkp_mark_stmt (stmt);
2506*38fd1498Szrj   bounds = chkp_get_tmp_reg (stmt);
2507*38fd1498Szrj   gimple_call_set_lhs (stmt, bounds);
2508*38fd1498Szrj 
2509*38fd1498Szrj   gimple_seq_add_stmt (&seq, stmt);
2510*38fd1498Szrj 
2511*38fd1498Szrj   gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING);
2512*38fd1498Szrj 
2513*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2514*38fd1498Szrj     {
2515*38fd1498Szrj       fprintf (dump_file, "Generated bndldx for pointer ");
2516*38fd1498Szrj       print_generic_expr (dump_file, ptr);
2517*38fd1498Szrj       fprintf (dump_file, ": ");
2518*38fd1498Szrj       print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS | TDF_MEMSYMS);
2519*38fd1498Szrj     }
2520*38fd1498Szrj 
2521*38fd1498Szrj   return bounds;
2522*38fd1498Szrj }
2523*38fd1498Szrj 
2524*38fd1498Szrj /* Build and return CALL_EXPR for bndstx builtin with specified
2525*38fd1498Szrj    arguments.  */
2526*38fd1498Szrj tree
2527*38fd1498Szrj chkp_build_bndstx_call (tree addr, tree ptr, tree bounds)
2528*38fd1498Szrj {
2529*38fd1498Szrj   tree fn = build1 (ADDR_EXPR,
2530*38fd1498Szrj 		    build_pointer_type (TREE_TYPE (chkp_bndstx_fndecl)),
2531*38fd1498Szrj 		    chkp_bndstx_fndecl);
2532*38fd1498Szrj   tree call = build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndstx_fndecl)),
2533*38fd1498Szrj 			       fn, 3, ptr, bounds, addr);
2534*38fd1498Szrj   CALL_WITH_BOUNDS_P (call) = true;
2535*38fd1498Szrj   return call;
2536*38fd1498Szrj }
2537*38fd1498Szrj 
2538*38fd1498Szrj /* Insert code to store BOUNDS for PTR stored by ADDR.
2539*38fd1498Szrj    New statements are inserted after position pointed
2540*38fd1498Szrj    by GSI.  */
2541*38fd1498Szrj void
2542*38fd1498Szrj chkp_build_bndstx (tree addr, tree ptr, tree bounds,
2543*38fd1498Szrj 		   gimple_stmt_iterator *gsi)
2544*38fd1498Szrj {
2545*38fd1498Szrj   gimple_seq seq;
2546*38fd1498Szrj   gimple *stmt;
2547*38fd1498Szrj 
2548*38fd1498Szrj   seq = NULL;
2549*38fd1498Szrj 
2550*38fd1498Szrj   addr = chkp_force_gimple_call_op (addr, &seq);
2551*38fd1498Szrj   ptr = chkp_force_gimple_call_op (ptr, &seq);
2552*38fd1498Szrj 
2553*38fd1498Szrj   stmt = gimple_build_call (chkp_bndstx_fndecl, 3, ptr, bounds, addr);
2554*38fd1498Szrj   chkp_mark_stmt (stmt);
2555*38fd1498Szrj   gimple_call_set_with_bounds (stmt, true);
2556*38fd1498Szrj 
2557*38fd1498Szrj   gimple_seq_add_stmt (&seq, stmt);
2558*38fd1498Szrj 
2559*38fd1498Szrj   gsi_insert_seq_after (gsi, seq, GSI_CONTINUE_LINKING);
2560*38fd1498Szrj 
2561*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2562*38fd1498Szrj     {
2563*38fd1498Szrj       fprintf (dump_file, "Generated bndstx for pointer store ");
2564*38fd1498Szrj       print_gimple_stmt (dump_file, gsi_stmt (*gsi), 0, TDF_VOPS|TDF_MEMSYMS);
2565*38fd1498Szrj       print_gimple_stmt (dump_file, stmt, 2, TDF_VOPS|TDF_MEMSYMS);
2566*38fd1498Szrj     }
2567*38fd1498Szrj }
2568*38fd1498Szrj 
2569*38fd1498Szrj /* This function is called when call statement
2570*38fd1498Szrj    is inlined and therefore we can't use bndret
2571*38fd1498Szrj    for its LHS anymore.  Function fixes bndret
2572*38fd1498Szrj    call using new RHS value if possible.  */
2573*38fd1498Szrj void
2574*38fd1498Szrj chkp_fixup_inlined_call (tree lhs, tree rhs)
2575*38fd1498Szrj {
2576*38fd1498Szrj   tree addr, bounds;
2577*38fd1498Szrj   gcall *retbnd, *bndldx;
2578*38fd1498Szrj 
2579*38fd1498Szrj   if (!BOUNDED_P (lhs))
2580*38fd1498Szrj     return;
2581*38fd1498Szrj 
2582*38fd1498Szrj   /* Search for retbnd call.  */
2583*38fd1498Szrj   retbnd = chkp_retbnd_call_by_val (lhs);
2584*38fd1498Szrj   if (!retbnd)
2585*38fd1498Szrj     return;
2586*38fd1498Szrj 
2587*38fd1498Szrj   /* Currently only handle cases when call is replaced
2588*38fd1498Szrj      with a memory access.  In this case bndret call
2589*38fd1498Szrj      may be replaced with bndldx call.  Otherwise we
2590*38fd1498Szrj      have to search for bounds which may cause wrong
2591*38fd1498Szrj      result due to various optimizations applied.  */
2592*38fd1498Szrj   switch (TREE_CODE (rhs))
2593*38fd1498Szrj     {
2594*38fd1498Szrj     case VAR_DECL:
2595*38fd1498Szrj       if (DECL_REGISTER (rhs))
2596*38fd1498Szrj 	return;
2597*38fd1498Szrj       break;
2598*38fd1498Szrj 
2599*38fd1498Szrj     case MEM_REF:
2600*38fd1498Szrj       break;
2601*38fd1498Szrj 
2602*38fd1498Szrj     case ARRAY_REF:
2603*38fd1498Szrj     case COMPONENT_REF:
2604*38fd1498Szrj       addr = get_base_address (rhs);
2605*38fd1498Szrj       if (!DECL_P (addr)
2606*38fd1498Szrj 	  && TREE_CODE (addr) != MEM_REF)
2607*38fd1498Szrj 	return;
2608*38fd1498Szrj       if (DECL_P (addr) && DECL_REGISTER (addr))
2609*38fd1498Szrj 	return;
2610*38fd1498Szrj       break;
2611*38fd1498Szrj 
2612*38fd1498Szrj     default:
2613*38fd1498Szrj       return;
2614*38fd1498Szrj     }
2615*38fd1498Szrj 
2616*38fd1498Szrj   /* Create a new statements sequence with bndldx call.  */
2617*38fd1498Szrj   gimple_stmt_iterator gsi = gsi_for_stmt (retbnd);
2618*38fd1498Szrj   addr = build_fold_addr_expr (rhs);
2619*38fd1498Szrj   chkp_build_bndldx (addr, lhs, &gsi);
2620*38fd1498Szrj   bndldx = as_a <gcall *> (gsi_stmt (gsi));
2621*38fd1498Szrj 
2622*38fd1498Szrj   /* Remove bndret call.  */
2623*38fd1498Szrj   bounds = gimple_call_lhs (retbnd);
2624*38fd1498Szrj   gsi = gsi_for_stmt (retbnd);
2625*38fd1498Szrj   gsi_remove (&gsi, true);
2626*38fd1498Szrj 
2627*38fd1498Szrj   /* Link new bndldx call.  */
2628*38fd1498Szrj   gimple_call_set_lhs (bndldx, bounds);
2629*38fd1498Szrj   update_stmt (bndldx);
2630*38fd1498Szrj }
2631*38fd1498Szrj 
2632*38fd1498Szrj /* Compute bounds for pointer NODE which was assigned in
2633*38fd1498Szrj    assignment statement ASSIGN.  Return computed bounds.  */
2634*38fd1498Szrj static tree
2635*38fd1498Szrj chkp_compute_bounds_for_assignment (tree node, gimple *assign)
2636*38fd1498Szrj {
2637*38fd1498Szrj   enum tree_code rhs_code = gimple_assign_rhs_code (assign);
2638*38fd1498Szrj   tree rhs1 = gimple_assign_rhs1 (assign);
2639*38fd1498Szrj   tree bounds = NULL_TREE;
2640*38fd1498Szrj   gimple_stmt_iterator iter = gsi_for_stmt (assign);
2641*38fd1498Szrj   tree base = NULL;
2642*38fd1498Szrj 
2643*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2644*38fd1498Szrj     {
2645*38fd1498Szrj       fprintf (dump_file, "Computing bounds for assignment: ");
2646*38fd1498Szrj       print_gimple_stmt (dump_file, assign, 0, TDF_VOPS|TDF_MEMSYMS);
2647*38fd1498Szrj     }
2648*38fd1498Szrj 
2649*38fd1498Szrj   switch (rhs_code)
2650*38fd1498Szrj     {
2651*38fd1498Szrj     case MEM_REF:
2652*38fd1498Szrj     case TARGET_MEM_REF:
2653*38fd1498Szrj     case COMPONENT_REF:
2654*38fd1498Szrj     case ARRAY_REF:
2655*38fd1498Szrj       /* We need to load bounds from the bounds table.  */
2656*38fd1498Szrj       bounds = chkp_find_bounds_loaded (node, rhs1, &iter);
2657*38fd1498Szrj       break;
2658*38fd1498Szrj 
2659*38fd1498Szrj     case VAR_DECL:
2660*38fd1498Szrj     case SSA_NAME:
2661*38fd1498Szrj     case ADDR_EXPR:
2662*38fd1498Szrj     case POINTER_PLUS_EXPR:
2663*38fd1498Szrj     case NOP_EXPR:
2664*38fd1498Szrj     case CONVERT_EXPR:
2665*38fd1498Szrj     case INTEGER_CST:
2666*38fd1498Szrj       /* Bounds are just propagated from RHS.  */
2667*38fd1498Szrj       bounds = chkp_find_bounds (rhs1, &iter);
2668*38fd1498Szrj       base = rhs1;
2669*38fd1498Szrj       break;
2670*38fd1498Szrj 
2671*38fd1498Szrj     case VIEW_CONVERT_EXPR:
2672*38fd1498Szrj       /* Bounds are just propagated from RHS.  */
2673*38fd1498Szrj       bounds = chkp_find_bounds (TREE_OPERAND (rhs1, 0), &iter);
2674*38fd1498Szrj       break;
2675*38fd1498Szrj 
2676*38fd1498Szrj     case PARM_DECL:
2677*38fd1498Szrj       if (BOUNDED_P (rhs1))
2678*38fd1498Szrj 	{
2679*38fd1498Szrj 	  /* We need to load bounds from the bounds table.  */
2680*38fd1498Szrj 	  bounds = chkp_build_bndldx (chkp_build_addr_expr (rhs1),
2681*38fd1498Szrj 				      node, &iter);
2682*38fd1498Szrj 	  TREE_ADDRESSABLE (rhs1) = 1;
2683*38fd1498Szrj 	}
2684*38fd1498Szrj       else
2685*38fd1498Szrj 	bounds = chkp_get_nonpointer_load_bounds ();
2686*38fd1498Szrj       break;
2687*38fd1498Szrj 
2688*38fd1498Szrj     case MINUS_EXPR:
2689*38fd1498Szrj     case PLUS_EXPR:
2690*38fd1498Szrj     case BIT_AND_EXPR:
2691*38fd1498Szrj     case BIT_IOR_EXPR:
2692*38fd1498Szrj     case BIT_XOR_EXPR:
2693*38fd1498Szrj       {
2694*38fd1498Szrj 	tree rhs2 = gimple_assign_rhs2 (assign);
2695*38fd1498Szrj 	tree bnd1 = chkp_find_bounds (rhs1, &iter);
2696*38fd1498Szrj 	tree bnd2 = chkp_find_bounds (rhs2, &iter);
2697*38fd1498Szrj 
2698*38fd1498Szrj 	/* First we try to check types of operands.  If it
2699*38fd1498Szrj 	   does not help then look at bound values.
2700*38fd1498Szrj 
2701*38fd1498Szrj 	   If some bounds are incomplete and other are
2702*38fd1498Szrj 	   not proven to be valid (i.e. also incomplete
2703*38fd1498Szrj 	   or invalid because value is not pointer) then
2704*38fd1498Szrj 	   resulting value is incomplete and will be
2705*38fd1498Szrj 	   recomputed later in chkp_finish_incomplete_bounds.  */
2706*38fd1498Szrj 	if (BOUNDED_P (rhs1)
2707*38fd1498Szrj 	    && !BOUNDED_P (rhs2))
2708*38fd1498Szrj 	  bounds = bnd1;
2709*38fd1498Szrj 	else if (BOUNDED_P (rhs2)
2710*38fd1498Szrj 		 && !BOUNDED_P (rhs1)
2711*38fd1498Szrj 		 && rhs_code != MINUS_EXPR)
2712*38fd1498Szrj 	  bounds = bnd2;
2713*38fd1498Szrj 	else if (chkp_incomplete_bounds (bnd1))
2714*38fd1498Szrj 	  if (chkp_valid_bounds (bnd2) && rhs_code != MINUS_EXPR
2715*38fd1498Szrj 	      && !chkp_incomplete_bounds (bnd2))
2716*38fd1498Szrj 	    bounds = bnd2;
2717*38fd1498Szrj 	  else
2718*38fd1498Szrj 	    bounds = incomplete_bounds;
2719*38fd1498Szrj 	else if (chkp_incomplete_bounds (bnd2))
2720*38fd1498Szrj 	  if (chkp_valid_bounds (bnd1)
2721*38fd1498Szrj 	      && !chkp_incomplete_bounds (bnd1))
2722*38fd1498Szrj 	    bounds = bnd1;
2723*38fd1498Szrj 	  else
2724*38fd1498Szrj 	    bounds = incomplete_bounds;
2725*38fd1498Szrj 	else if (!chkp_valid_bounds (bnd1))
2726*38fd1498Szrj 	  if (chkp_valid_bounds (bnd2) && rhs_code != MINUS_EXPR)
2727*38fd1498Szrj 	    bounds = bnd2;
2728*38fd1498Szrj 	  else if (bnd2 == chkp_get_zero_bounds ())
2729*38fd1498Szrj 	    bounds = bnd2;
2730*38fd1498Szrj 	  else
2731*38fd1498Szrj 	    bounds = bnd1;
2732*38fd1498Szrj 	else if (!chkp_valid_bounds (bnd2))
2733*38fd1498Szrj 	  bounds = bnd1;
2734*38fd1498Szrj 	else
2735*38fd1498Szrj 	  /* Seems both operands may have valid bounds
2736*38fd1498Szrj 	     (e.g. pointer minus pointer).  In such case
2737*38fd1498Szrj 	     use default invalid op bounds.  */
2738*38fd1498Szrj 	  bounds = chkp_get_invalid_op_bounds ();
2739*38fd1498Szrj 
2740*38fd1498Szrj 	base = (bounds == bnd1) ? rhs1 : (bounds == bnd2) ? rhs2 : NULL;
2741*38fd1498Szrj       }
2742*38fd1498Szrj       break;
2743*38fd1498Szrj 
2744*38fd1498Szrj     case BIT_NOT_EXPR:
2745*38fd1498Szrj     case NEGATE_EXPR:
2746*38fd1498Szrj     case LSHIFT_EXPR:
2747*38fd1498Szrj     case RSHIFT_EXPR:
2748*38fd1498Szrj     case LROTATE_EXPR:
2749*38fd1498Szrj     case RROTATE_EXPR:
2750*38fd1498Szrj     case EQ_EXPR:
2751*38fd1498Szrj     case NE_EXPR:
2752*38fd1498Szrj     case LT_EXPR:
2753*38fd1498Szrj     case LE_EXPR:
2754*38fd1498Szrj     case GT_EXPR:
2755*38fd1498Szrj     case GE_EXPR:
2756*38fd1498Szrj     case MULT_EXPR:
2757*38fd1498Szrj     case RDIV_EXPR:
2758*38fd1498Szrj     case TRUNC_DIV_EXPR:
2759*38fd1498Szrj     case FLOOR_DIV_EXPR:
2760*38fd1498Szrj     case CEIL_DIV_EXPR:
2761*38fd1498Szrj     case ROUND_DIV_EXPR:
2762*38fd1498Szrj     case TRUNC_MOD_EXPR:
2763*38fd1498Szrj     case FLOOR_MOD_EXPR:
2764*38fd1498Szrj     case CEIL_MOD_EXPR:
2765*38fd1498Szrj     case ROUND_MOD_EXPR:
2766*38fd1498Szrj     case EXACT_DIV_EXPR:
2767*38fd1498Szrj     case FIX_TRUNC_EXPR:
2768*38fd1498Szrj     case FLOAT_EXPR:
2769*38fd1498Szrj     case REALPART_EXPR:
2770*38fd1498Szrj     case IMAGPART_EXPR:
2771*38fd1498Szrj     case POINTER_DIFF_EXPR:
2772*38fd1498Szrj       /* No valid bounds may be produced by these exprs.  */
2773*38fd1498Szrj       bounds = chkp_get_invalid_op_bounds ();
2774*38fd1498Szrj       break;
2775*38fd1498Szrj 
2776*38fd1498Szrj     case COND_EXPR:
2777*38fd1498Szrj       {
2778*38fd1498Szrj 	tree val1 = gimple_assign_rhs2 (assign);
2779*38fd1498Szrj 	tree val2 = gimple_assign_rhs3 (assign);
2780*38fd1498Szrj 	tree bnd1 = chkp_find_bounds (val1, &iter);
2781*38fd1498Szrj 	tree bnd2 = chkp_find_bounds (val2, &iter);
2782*38fd1498Szrj 	gimple *stmt;
2783*38fd1498Szrj 
2784*38fd1498Szrj 	if (chkp_incomplete_bounds (bnd1) || chkp_incomplete_bounds (bnd2))
2785*38fd1498Szrj 	  bounds = incomplete_bounds;
2786*38fd1498Szrj 	else if (bnd1 == bnd2)
2787*38fd1498Szrj 	  bounds = bnd1;
2788*38fd1498Szrj 	else
2789*38fd1498Szrj 	  {
2790*38fd1498Szrj 	    rhs1 = unshare_expr (rhs1);
2791*38fd1498Szrj 
2792*38fd1498Szrj 	    bounds = chkp_get_tmp_reg (assign);
2793*38fd1498Szrj 	    stmt = gimple_build_assign (bounds, COND_EXPR, rhs1, bnd1, bnd2);
2794*38fd1498Szrj 	    gsi_insert_after (&iter, stmt, GSI_SAME_STMT);
2795*38fd1498Szrj 
2796*38fd1498Szrj 	    if (!chkp_valid_bounds (bnd1) && !chkp_valid_bounds (bnd2))
2797*38fd1498Szrj 	      chkp_mark_invalid_bounds (bounds);
2798*38fd1498Szrj 	  }
2799*38fd1498Szrj       }
2800*38fd1498Szrj       break;
2801*38fd1498Szrj 
2802*38fd1498Szrj     case MAX_EXPR:
2803*38fd1498Szrj     case MIN_EXPR:
2804*38fd1498Szrj       {
2805*38fd1498Szrj 	tree rhs2 = gimple_assign_rhs2 (assign);
2806*38fd1498Szrj 	tree bnd1 = chkp_find_bounds (rhs1, &iter);
2807*38fd1498Szrj 	tree bnd2 = chkp_find_bounds (rhs2, &iter);
2808*38fd1498Szrj 
2809*38fd1498Szrj 	if (chkp_incomplete_bounds (bnd1) || chkp_incomplete_bounds (bnd2))
2810*38fd1498Szrj 	  bounds = incomplete_bounds;
2811*38fd1498Szrj 	else if (bnd1 == bnd2)
2812*38fd1498Szrj 	  bounds = bnd1;
2813*38fd1498Szrj 	else
2814*38fd1498Szrj 	  {
2815*38fd1498Szrj 	    gimple *stmt;
2816*38fd1498Szrj 	    tree cond = build2 (rhs_code == MAX_EXPR ? GT_EXPR : LT_EXPR,
2817*38fd1498Szrj 				boolean_type_node, rhs1, rhs2);
2818*38fd1498Szrj 	    bounds = chkp_get_tmp_reg (assign);
2819*38fd1498Szrj 	    stmt = gimple_build_assign (bounds, COND_EXPR, cond, bnd1, bnd2);
2820*38fd1498Szrj 
2821*38fd1498Szrj 	    gsi_insert_after (&iter, stmt, GSI_SAME_STMT);
2822*38fd1498Szrj 
2823*38fd1498Szrj 	    if (!chkp_valid_bounds (bnd1) && !chkp_valid_bounds (bnd2))
2824*38fd1498Szrj 	      chkp_mark_invalid_bounds (bounds);
2825*38fd1498Szrj 	  }
2826*38fd1498Szrj       }
2827*38fd1498Szrj       break;
2828*38fd1498Szrj 
2829*38fd1498Szrj     default:
2830*38fd1498Szrj       bounds = chkp_get_zero_bounds ();
2831*38fd1498Szrj       warning (0, "pointer bounds were lost due to unexpected expression %s",
2832*38fd1498Szrj 	       get_tree_code_name (rhs_code));
2833*38fd1498Szrj     }
2834*38fd1498Szrj 
2835*38fd1498Szrj   gcc_assert (bounds);
2836*38fd1498Szrj 
2837*38fd1498Szrj   /* We may reuse bounds of other pointer we copy/modify.  But it is not
2838*38fd1498Szrj      allowed for abnormal ssa names.  If we produced a pointer using
2839*38fd1498Szrj      abnormal ssa name, we better make a bounds copy to avoid coalescing
2840*38fd1498Szrj      issues.  */
2841*38fd1498Szrj   if (base
2842*38fd1498Szrj       && TREE_CODE (base) == SSA_NAME
2843*38fd1498Szrj       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (base))
2844*38fd1498Szrj     {
2845*38fd1498Szrj       gimple *stmt = gimple_build_assign (chkp_get_tmp_reg (NULL), bounds);
2846*38fd1498Szrj       gsi_insert_after (&iter, stmt, GSI_SAME_STMT);
2847*38fd1498Szrj       bounds = gimple_assign_lhs (stmt);
2848*38fd1498Szrj     }
2849*38fd1498Szrj 
2850*38fd1498Szrj   if (node)
2851*38fd1498Szrj     bounds = chkp_maybe_copy_and_register_bounds (node, bounds);
2852*38fd1498Szrj 
2853*38fd1498Szrj   return bounds;
2854*38fd1498Szrj }
2855*38fd1498Szrj 
2856*38fd1498Szrj /* Compute bounds for ssa name NODE defined by DEF_STMT pointed by ITER.
2857*38fd1498Szrj 
2858*38fd1498Szrj    There are just few statement codes allowed: NOP (for default ssa names),
2859*38fd1498Szrj    ASSIGN, CALL, PHI, ASM.
2860*38fd1498Szrj 
2861*38fd1498Szrj    Return computed bounds.  */
2862*38fd1498Szrj static tree
2863*38fd1498Szrj chkp_get_bounds_by_definition (tree node, gimple *def_stmt,
2864*38fd1498Szrj 			       gphi_iterator *iter)
2865*38fd1498Szrj {
2866*38fd1498Szrj   tree var, bounds;
2867*38fd1498Szrj   enum gimple_code code = gimple_code (def_stmt);
2868*38fd1498Szrj   gphi *stmt;
2869*38fd1498Szrj 
2870*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
2871*38fd1498Szrj     {
2872*38fd1498Szrj       fprintf (dump_file, "Searching for bounds for node: ");
2873*38fd1498Szrj       print_generic_expr (dump_file, node);
2874*38fd1498Szrj 
2875*38fd1498Szrj       fprintf (dump_file, " using its definition: ");
2876*38fd1498Szrj       print_gimple_stmt (dump_file, def_stmt, 0, TDF_VOPS | TDF_MEMSYMS);
2877*38fd1498Szrj     }
2878*38fd1498Szrj 
2879*38fd1498Szrj   switch (code)
2880*38fd1498Szrj     {
2881*38fd1498Szrj     case GIMPLE_NOP:
2882*38fd1498Szrj       var = SSA_NAME_VAR (node);
2883*38fd1498Szrj       switch (TREE_CODE (var))
2884*38fd1498Szrj 	{
2885*38fd1498Szrj 	case PARM_DECL:
2886*38fd1498Szrj 	  bounds = chkp_get_bound_for_parm (node);
2887*38fd1498Szrj 	  break;
2888*38fd1498Szrj 
2889*38fd1498Szrj 	case VAR_DECL:
2890*38fd1498Szrj 	  /* For uninitialized pointers use none bounds.  */
2891*38fd1498Szrj 	  bounds = chkp_get_none_bounds ();
2892*38fd1498Szrj 	  bounds = chkp_maybe_copy_and_register_bounds (node, bounds);
2893*38fd1498Szrj 	  break;
2894*38fd1498Szrj 
2895*38fd1498Szrj 	case RESULT_DECL:
2896*38fd1498Szrj 	  {
2897*38fd1498Szrj 	    tree base_type;
2898*38fd1498Szrj 
2899*38fd1498Szrj 	    gcc_assert (TREE_CODE (TREE_TYPE (node)) == REFERENCE_TYPE);
2900*38fd1498Szrj 
2901*38fd1498Szrj 	    base_type = TREE_TYPE (TREE_TYPE (node));
2902*38fd1498Szrj 
2903*38fd1498Szrj 	    gcc_assert (TYPE_SIZE (base_type)
2904*38fd1498Szrj 			&& TREE_CODE (TYPE_SIZE (base_type)) == INTEGER_CST
2905*38fd1498Szrj 			&& tree_to_uhwi (TYPE_SIZE (base_type)) != 0);
2906*38fd1498Szrj 
2907*38fd1498Szrj 	    bounds = chkp_make_bounds (node, TYPE_SIZE_UNIT (base_type),
2908*38fd1498Szrj 				       NULL, false);
2909*38fd1498Szrj 	    bounds = chkp_maybe_copy_and_register_bounds (node, bounds);
2910*38fd1498Szrj 	  }
2911*38fd1498Szrj 	  break;
2912*38fd1498Szrj 
2913*38fd1498Szrj 	default:
2914*38fd1498Szrj 	  if (dump_file && (dump_flags & TDF_DETAILS))
2915*38fd1498Szrj 	    {
2916*38fd1498Szrj 	      fprintf (dump_file, "Unexpected var with no definition\n");
2917*38fd1498Szrj 	      print_generic_expr (dump_file, var);
2918*38fd1498Szrj 	    }
2919*38fd1498Szrj 	  internal_error ("chkp_get_bounds_by_definition: Unexpected var of type %s",
2920*38fd1498Szrj 			  get_tree_code_name (TREE_CODE (var)));
2921*38fd1498Szrj 	}
2922*38fd1498Szrj       break;
2923*38fd1498Szrj 
2924*38fd1498Szrj     case GIMPLE_ASSIGN:
2925*38fd1498Szrj       bounds = chkp_compute_bounds_for_assignment (node, def_stmt);
2926*38fd1498Szrj       break;
2927*38fd1498Szrj 
2928*38fd1498Szrj     case GIMPLE_CALL:
2929*38fd1498Szrj       bounds = chkp_build_returned_bound (as_a <gcall *> (def_stmt));
2930*38fd1498Szrj       break;
2931*38fd1498Szrj 
2932*38fd1498Szrj     case GIMPLE_PHI:
2933*38fd1498Szrj       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node))
2934*38fd1498Szrj 	if (SSA_NAME_VAR (node))
2935*38fd1498Szrj 	  var = chkp_get_bounds_var (SSA_NAME_VAR (node));
2936*38fd1498Szrj 	else
2937*38fd1498Szrj 	  var = make_temp_ssa_name (pointer_bounds_type_node,
2938*38fd1498Szrj 				    NULL,
2939*38fd1498Szrj 				    CHKP_BOUND_TMP_NAME);
2940*38fd1498Szrj       else
2941*38fd1498Szrj 	var = chkp_get_tmp_var ();
2942*38fd1498Szrj       stmt = create_phi_node (var, gimple_bb (def_stmt));
2943*38fd1498Szrj       bounds = gimple_phi_result (stmt);
2944*38fd1498Szrj       *iter = gsi_for_phi (stmt);
2945*38fd1498Szrj 
2946*38fd1498Szrj       bounds = chkp_maybe_copy_and_register_bounds (node, bounds);
2947*38fd1498Szrj 
2948*38fd1498Szrj       /* Created bounds do not have all phi args computed and
2949*38fd1498Szrj 	 therefore we do not know if there is a valid source
2950*38fd1498Szrj 	 of bounds for that node.  Therefore we mark bounds
2951*38fd1498Szrj 	 as incomplete and then recompute them when all phi
2952*38fd1498Szrj 	 args are computed.  */
2953*38fd1498Szrj       chkp_register_incomplete_bounds (bounds, node);
2954*38fd1498Szrj       break;
2955*38fd1498Szrj 
2956*38fd1498Szrj     case GIMPLE_ASM:
2957*38fd1498Szrj       bounds = chkp_get_zero_bounds ();
2958*38fd1498Szrj       bounds = chkp_maybe_copy_and_register_bounds (node, bounds);
2959*38fd1498Szrj       break;
2960*38fd1498Szrj 
2961*38fd1498Szrj     default:
2962*38fd1498Szrj       internal_error ("chkp_get_bounds_by_definition: Unexpected GIMPLE code %s",
2963*38fd1498Szrj 		      gimple_code_name[code]);
2964*38fd1498Szrj     }
2965*38fd1498Szrj 
2966*38fd1498Szrj   return bounds;
2967*38fd1498Szrj }
2968*38fd1498Szrj 
2969*38fd1498Szrj /* Return CALL_EXPR for bndmk with specified LOWER_BOUND and SIZE.  */
2970*38fd1498Szrj tree
2971*38fd1498Szrj chkp_build_make_bounds_call (tree lower_bound, tree size)
2972*38fd1498Szrj {
2973*38fd1498Szrj   tree call = build1 (ADDR_EXPR,
2974*38fd1498Szrj 		      build_pointer_type (TREE_TYPE (chkp_bndmk_fndecl)),
2975*38fd1498Szrj 		      chkp_bndmk_fndecl);
2976*38fd1498Szrj   return build_call_nary (TREE_TYPE (TREE_TYPE (chkp_bndmk_fndecl)),
2977*38fd1498Szrj 			  call, 2, lower_bound, size);
2978*38fd1498Szrj }
2979*38fd1498Szrj 
2980*38fd1498Szrj /* Create static bounds var of specfified OBJ which is
2981*38fd1498Szrj    is either VAR_DECL or string constant.  */
2982*38fd1498Szrj static tree
2983*38fd1498Szrj chkp_make_static_bounds (tree obj)
2984*38fd1498Szrj {
2985*38fd1498Szrj   static int string_id = 1;
2986*38fd1498Szrj   static int var_id = 1;
2987*38fd1498Szrj   tree *slot;
2988*38fd1498Szrj   const char *var_name;
2989*38fd1498Szrj   char *bnd_var_name;
2990*38fd1498Szrj   tree bnd_var;
2991*38fd1498Szrj 
2992*38fd1498Szrj   /* First check if we already have required var.  */
2993*38fd1498Szrj   if (chkp_static_var_bounds)
2994*38fd1498Szrj     {
2995*38fd1498Szrj       /* For vars we use assembler name as a key in
2996*38fd1498Szrj 	 chkp_static_var_bounds map.  It allows to
2997*38fd1498Szrj 	 avoid duplicating bound vars for decls
2998*38fd1498Szrj 	 sharing assembler name.  */
2999*38fd1498Szrj       if (VAR_P (obj))
3000*38fd1498Szrj 	{
3001*38fd1498Szrj 	  tree name = DECL_ASSEMBLER_NAME (obj);
3002*38fd1498Szrj 	  slot = chkp_static_var_bounds->get (name);
3003*38fd1498Szrj 	  if (slot)
3004*38fd1498Szrj 	    return *slot;
3005*38fd1498Szrj 	}
3006*38fd1498Szrj       else
3007*38fd1498Szrj 	{
3008*38fd1498Szrj 	  slot = chkp_static_var_bounds->get (obj);
3009*38fd1498Szrj 	  if (slot)
3010*38fd1498Szrj 	    return *slot;
3011*38fd1498Szrj 	}
3012*38fd1498Szrj     }
3013*38fd1498Szrj 
3014*38fd1498Szrj   /* Build decl for bounds var.  */
3015*38fd1498Szrj   if (VAR_P (obj))
3016*38fd1498Szrj     {
3017*38fd1498Szrj       if (DECL_IGNORED_P (obj))
3018*38fd1498Szrj 	{
3019*38fd1498Szrj 	  bnd_var_name = (char *) xmalloc (strlen (CHKP_VAR_BOUNDS_PREFIX) + 10);
3020*38fd1498Szrj 	  sprintf (bnd_var_name, "%s%d", CHKP_VAR_BOUNDS_PREFIX, var_id++);
3021*38fd1498Szrj 	}
3022*38fd1498Szrj       else
3023*38fd1498Szrj 	{
3024*38fd1498Szrj 	  var_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj));
3025*38fd1498Szrj 
3026*38fd1498Szrj 	  /* For hidden symbols we want to skip first '*' char.  */
3027*38fd1498Szrj 	  if (*var_name == '*')
3028*38fd1498Szrj 	    var_name++;
3029*38fd1498Szrj 
3030*38fd1498Szrj 	  bnd_var_name = (char *) xmalloc (strlen (var_name)
3031*38fd1498Szrj 					   + strlen (CHKP_BOUNDS_OF_SYMBOL_PREFIX) + 1);
3032*38fd1498Szrj 	  strcpy (bnd_var_name, CHKP_BOUNDS_OF_SYMBOL_PREFIX);
3033*38fd1498Szrj 	  strcat (bnd_var_name, var_name);
3034*38fd1498Szrj 	}
3035*38fd1498Szrj 
3036*38fd1498Szrj       bnd_var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
3037*38fd1498Szrj 			    get_identifier (bnd_var_name),
3038*38fd1498Szrj 			    pointer_bounds_type_node);
3039*38fd1498Szrj 
3040*38fd1498Szrj       /* Address of the obj will be used as lower bound.  */
3041*38fd1498Szrj       TREE_ADDRESSABLE (obj) = 1;
3042*38fd1498Szrj     }
3043*38fd1498Szrj   else
3044*38fd1498Szrj     {
3045*38fd1498Szrj       bnd_var_name = (char *) xmalloc (strlen (CHKP_STRING_BOUNDS_PREFIX) + 10);
3046*38fd1498Szrj       sprintf (bnd_var_name, "%s%d", CHKP_STRING_BOUNDS_PREFIX, string_id++);
3047*38fd1498Szrj 
3048*38fd1498Szrj       bnd_var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
3049*38fd1498Szrj 			    get_identifier (bnd_var_name),
3050*38fd1498Szrj 			    pointer_bounds_type_node);
3051*38fd1498Szrj     }
3052*38fd1498Szrj 
3053*38fd1498Szrj   free (bnd_var_name);
3054*38fd1498Szrj 
3055*38fd1498Szrj   TREE_PUBLIC (bnd_var) = 0;
3056*38fd1498Szrj   TREE_USED (bnd_var) = 1;
3057*38fd1498Szrj   TREE_READONLY (bnd_var) = 0;
3058*38fd1498Szrj   TREE_STATIC (bnd_var) = 1;
3059*38fd1498Szrj   TREE_ADDRESSABLE (bnd_var) = 0;
3060*38fd1498Szrj   DECL_ARTIFICIAL (bnd_var) = 1;
3061*38fd1498Szrj   DECL_COMMON (bnd_var) = 1;
3062*38fd1498Szrj   DECL_COMDAT (bnd_var) = 1;
3063*38fd1498Szrj   DECL_READ_P (bnd_var) = 1;
3064*38fd1498Szrj   DECL_INITIAL (bnd_var) = chkp_build_addr_expr (obj);
3065*38fd1498Szrj   /* Force output similar to constant bounds.
3066*38fd1498Szrj      See chkp_make_static_const_bounds. */
3067*38fd1498Szrj   varpool_node::get_create (bnd_var)->force_output = 1;
3068*38fd1498Szrj   /* Mark symbol as requiring bounds initialization.  */
3069*38fd1498Szrj   varpool_node::get_create (bnd_var)->need_bounds_init = 1;
3070*38fd1498Szrj   varpool_node::finalize_decl (bnd_var);
3071*38fd1498Szrj 
3072*38fd1498Szrj   /* Add created var to the map to use it for other references
3073*38fd1498Szrj      to obj.  */
3074*38fd1498Szrj   if (!chkp_static_var_bounds)
3075*38fd1498Szrj     chkp_static_var_bounds = new hash_map<tree, tree>;
3076*38fd1498Szrj 
3077*38fd1498Szrj   if (VAR_P (obj))
3078*38fd1498Szrj     {
3079*38fd1498Szrj       tree name = DECL_ASSEMBLER_NAME (obj);
3080*38fd1498Szrj       chkp_static_var_bounds->put (name, bnd_var);
3081*38fd1498Szrj     }
3082*38fd1498Szrj   else
3083*38fd1498Szrj     chkp_static_var_bounds->put (obj, bnd_var);
3084*38fd1498Szrj 
3085*38fd1498Szrj   return bnd_var;
3086*38fd1498Szrj }
3087*38fd1498Szrj 
3088*38fd1498Szrj /* When var has incomplete type we cannot get size to
3089*38fd1498Szrj    compute its bounds.  In such cases we use checker
3090*38fd1498Szrj    builtin call which determines object size at runtime.  */
3091*38fd1498Szrj static tree
3092*38fd1498Szrj chkp_generate_extern_var_bounds (tree var)
3093*38fd1498Szrj {
3094*38fd1498Szrj   tree bounds, size_reloc, lb, size, max_size, cond;
3095*38fd1498Szrj   gimple_stmt_iterator gsi;
3096*38fd1498Szrj   gimple_seq seq = NULL;
3097*38fd1498Szrj   gimple *stmt;
3098*38fd1498Szrj 
3099*38fd1498Szrj   /* If instrumentation is not enabled for vars having
3100*38fd1498Szrj      incomplete type then just return zero bounds to avoid
3101*38fd1498Szrj      checks for this var.  */
3102*38fd1498Szrj   if (!flag_chkp_incomplete_type)
3103*38fd1498Szrj     return chkp_get_zero_bounds ();
3104*38fd1498Szrj 
3105*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
3106*38fd1498Szrj     {
3107*38fd1498Szrj       fprintf (dump_file, "Generating bounds for extern symbol '");
3108*38fd1498Szrj       print_generic_expr (dump_file, var);
3109*38fd1498Szrj       fprintf (dump_file, "'\n");
3110*38fd1498Szrj     }
3111*38fd1498Szrj 
3112*38fd1498Szrj   stmt = gimple_build_call (chkp_sizeof_fndecl, 1, var);
3113*38fd1498Szrj 
3114*38fd1498Szrj   size_reloc = create_tmp_reg (chkp_uintptr_type, CHKP_SIZE_TMP_NAME);
3115*38fd1498Szrj   gimple_call_set_lhs (stmt, size_reloc);
3116*38fd1498Szrj 
3117*38fd1498Szrj   gimple_seq_add_stmt (&seq, stmt);
3118*38fd1498Szrj 
3119*38fd1498Szrj   lb = chkp_build_addr_expr (var);
3120*38fd1498Szrj   size = make_ssa_name (chkp_get_size_tmp_var ());
3121*38fd1498Szrj 
3122*38fd1498Szrj   if (flag_chkp_zero_dynamic_size_as_infinite)
3123*38fd1498Szrj     {
3124*38fd1498Szrj       /* We should check that size relocation was resolved.
3125*38fd1498Szrj 	 If it was not then use maximum possible size for the var.  */
3126*38fd1498Szrj       max_size = build2 (MINUS_EXPR, chkp_uintptr_type, integer_zero_node,
3127*38fd1498Szrj 			 fold_convert (chkp_uintptr_type, lb));
3128*38fd1498Szrj       max_size = chkp_force_gimple_call_op (max_size, &seq);
3129*38fd1498Szrj 
3130*38fd1498Szrj       cond = build2 (NE_EXPR, boolean_type_node,
3131*38fd1498Szrj 		     size_reloc, integer_zero_node);
3132*38fd1498Szrj       stmt = gimple_build_assign (size, COND_EXPR, cond, size_reloc, max_size);
3133*38fd1498Szrj       gimple_seq_add_stmt (&seq, stmt);
3134*38fd1498Szrj     }
3135*38fd1498Szrj   else
3136*38fd1498Szrj     {
3137*38fd1498Szrj       stmt = gimple_build_assign (size, size_reloc);
3138*38fd1498Szrj       gimple_seq_add_stmt (&seq, stmt);
3139*38fd1498Szrj     }
3140*38fd1498Szrj 
3141*38fd1498Szrj   gsi = gsi_start_bb (chkp_get_entry_block ());
3142*38fd1498Szrj   gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
3143*38fd1498Szrj 
3144*38fd1498Szrj   bounds = chkp_make_bounds (lb, size, &gsi, true);
3145*38fd1498Szrj 
3146*38fd1498Szrj   return bounds;
3147*38fd1498Szrj }
3148*38fd1498Szrj 
3149*38fd1498Szrj /* Return 1 if TYPE has fields with zero size or fields
3150*38fd1498Szrj    marked with chkp_variable_size attribute.  */
3151*38fd1498Szrj bool
3152*38fd1498Szrj chkp_variable_size_type (tree type)
3153*38fd1498Szrj {
3154*38fd1498Szrj   bool res = false;
3155*38fd1498Szrj   tree field;
3156*38fd1498Szrj 
3157*38fd1498Szrj   if (RECORD_OR_UNION_TYPE_P (type))
3158*38fd1498Szrj     for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
3159*38fd1498Szrj       {
3160*38fd1498Szrj 	if (TREE_CODE (field) == FIELD_DECL)
3161*38fd1498Szrj 	  res = res
3162*38fd1498Szrj 	    || lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field))
3163*38fd1498Szrj 	    || chkp_variable_size_type (TREE_TYPE (field));
3164*38fd1498Szrj       }
3165*38fd1498Szrj   else
3166*38fd1498Szrj     res = !TYPE_SIZE (type)
3167*38fd1498Szrj       || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
3168*38fd1498Szrj       || tree_to_uhwi (TYPE_SIZE (type)) == 0;
3169*38fd1498Szrj 
3170*38fd1498Szrj   return res;
3171*38fd1498Szrj }
3172*38fd1498Szrj 
3173*38fd1498Szrj /* Compute and return bounds for address of DECL which is
3174*38fd1498Szrj    one of VAR_DECL, PARM_DECL, RESULT_DECL.  */
3175*38fd1498Szrj static tree
3176*38fd1498Szrj chkp_get_bounds_for_decl_addr (tree decl)
3177*38fd1498Szrj {
3178*38fd1498Szrj   tree bounds;
3179*38fd1498Szrj 
3180*38fd1498Szrj   gcc_assert (VAR_P (decl)
3181*38fd1498Szrj 	      || TREE_CODE (decl) == PARM_DECL
3182*38fd1498Szrj 	      || TREE_CODE (decl) == RESULT_DECL);
3183*38fd1498Szrj 
3184*38fd1498Szrj   bounds = chkp_get_registered_addr_bounds (decl);
3185*38fd1498Szrj 
3186*38fd1498Szrj   if (bounds)
3187*38fd1498Szrj     return bounds;
3188*38fd1498Szrj 
3189*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
3190*38fd1498Szrj     {
3191*38fd1498Szrj       fprintf (dump_file, "Building bounds for address of decl ");
3192*38fd1498Szrj       print_generic_expr (dump_file, decl);
3193*38fd1498Szrj       fprintf (dump_file, "\n");
3194*38fd1498Szrj     }
3195*38fd1498Szrj 
3196*38fd1498Szrj   /* Use zero bounds if size is unknown and checks for
3197*38fd1498Szrj      unknown sizes are restricted.  */
3198*38fd1498Szrj   if ((!DECL_SIZE (decl)
3199*38fd1498Szrj        || (chkp_variable_size_type (TREE_TYPE (decl))
3200*38fd1498Szrj 	   && (TREE_STATIC (decl)
3201*38fd1498Szrj 	       || DECL_EXTERNAL (decl)
3202*38fd1498Szrj 	       || TREE_PUBLIC (decl))))
3203*38fd1498Szrj       && !flag_chkp_incomplete_type)
3204*38fd1498Szrj       return chkp_get_zero_bounds ();
3205*38fd1498Szrj 
3206*38fd1498Szrj   if (VOID_TYPE_P (TREE_TYPE (decl)))
3207*38fd1498Szrj     return chkp_get_zero_bounds ();
3208*38fd1498Szrj 
3209*38fd1498Szrj   if (flag_chkp_use_static_bounds
3210*38fd1498Szrj       && VAR_P (decl)
3211*38fd1498Szrj       && (TREE_STATIC (decl)
3212*38fd1498Szrj 	      || DECL_EXTERNAL (decl)
3213*38fd1498Szrj 	      || TREE_PUBLIC (decl))
3214*38fd1498Szrj       && !DECL_THREAD_LOCAL_P (decl))
3215*38fd1498Szrj     {
3216*38fd1498Szrj       tree bnd_var = chkp_make_static_bounds (decl);
3217*38fd1498Szrj       gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ());
3218*38fd1498Szrj       gimple *stmt;
3219*38fd1498Szrj 
3220*38fd1498Szrj       bounds = chkp_get_tmp_reg (NULL);
3221*38fd1498Szrj       stmt = gimple_build_assign (bounds, bnd_var);
3222*38fd1498Szrj       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
3223*38fd1498Szrj     }
3224*38fd1498Szrj   else if (!DECL_SIZE (decl)
3225*38fd1498Szrj       || (chkp_variable_size_type (TREE_TYPE (decl))
3226*38fd1498Szrj 	  && (TREE_STATIC (decl)
3227*38fd1498Szrj 	      || DECL_EXTERNAL (decl)
3228*38fd1498Szrj 	      || TREE_PUBLIC (decl))))
3229*38fd1498Szrj     {
3230*38fd1498Szrj       gcc_assert (VAR_P (decl));
3231*38fd1498Szrj       bounds = chkp_generate_extern_var_bounds (decl);
3232*38fd1498Szrj     }
3233*38fd1498Szrj   else
3234*38fd1498Szrj     {
3235*38fd1498Szrj       tree lb = chkp_build_addr_expr (decl);
3236*38fd1498Szrj       bounds = chkp_make_bounds (lb, DECL_SIZE_UNIT (decl), NULL, false);
3237*38fd1498Szrj     }
3238*38fd1498Szrj 
3239*38fd1498Szrj   return bounds;
3240*38fd1498Szrj }
3241*38fd1498Szrj 
3242*38fd1498Szrj /* Compute and return bounds for constant string.  */
3243*38fd1498Szrj static tree
3244*38fd1498Szrj chkp_get_bounds_for_string_cst (tree cst)
3245*38fd1498Szrj {
3246*38fd1498Szrj   tree bounds;
3247*38fd1498Szrj   tree lb;
3248*38fd1498Szrj   tree size;
3249*38fd1498Szrj 
3250*38fd1498Szrj   gcc_assert (TREE_CODE (cst) == STRING_CST);
3251*38fd1498Szrj 
3252*38fd1498Szrj   bounds = chkp_get_registered_bounds (cst);
3253*38fd1498Szrj 
3254*38fd1498Szrj   if (bounds)
3255*38fd1498Szrj     return bounds;
3256*38fd1498Szrj 
3257*38fd1498Szrj   if ((flag_chkp_use_static_bounds && flag_chkp_use_static_const_bounds)
3258*38fd1498Szrj       || flag_chkp_use_static_const_bounds > 0)
3259*38fd1498Szrj     {
3260*38fd1498Szrj       tree bnd_var = chkp_make_static_bounds (cst);
3261*38fd1498Szrj       gimple_stmt_iterator gsi = gsi_start_bb (chkp_get_entry_block ());
3262*38fd1498Szrj       gimple *stmt;
3263*38fd1498Szrj 
3264*38fd1498Szrj       bounds = chkp_get_tmp_reg (NULL);
3265*38fd1498Szrj       stmt = gimple_build_assign (bounds, bnd_var);
3266*38fd1498Szrj       gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
3267*38fd1498Szrj     }
3268*38fd1498Szrj   else
3269*38fd1498Szrj     {
3270*38fd1498Szrj       lb = chkp_build_addr_expr (cst);
3271*38fd1498Szrj       size = build_int_cst (chkp_uintptr_type, TREE_STRING_LENGTH (cst));
3272*38fd1498Szrj       bounds = chkp_make_bounds (lb, size, NULL, false);
3273*38fd1498Szrj     }
3274*38fd1498Szrj 
3275*38fd1498Szrj   bounds = chkp_maybe_copy_and_register_bounds (cst, bounds);
3276*38fd1498Szrj 
3277*38fd1498Szrj   return bounds;
3278*38fd1498Szrj }
3279*38fd1498Szrj 
3280*38fd1498Szrj /* Generate code to instersect bounds BOUNDS1 and BOUNDS2 and
3281*38fd1498Szrj    return the result.  if ITER is not NULL then Code is inserted
3282*38fd1498Szrj    before position pointed by ITER.  Otherwise code is added to
3283*38fd1498Szrj    entry block.  */
3284*38fd1498Szrj static tree
3285*38fd1498Szrj chkp_intersect_bounds (tree bounds1, tree bounds2, gimple_stmt_iterator *iter)
3286*38fd1498Szrj {
3287*38fd1498Szrj   if (!bounds1 || bounds1 == chkp_get_zero_bounds ())
3288*38fd1498Szrj     return bounds2 ? bounds2 : bounds1;
3289*38fd1498Szrj   else if (!bounds2 || bounds2 == chkp_get_zero_bounds ())
3290*38fd1498Szrj     return bounds1;
3291*38fd1498Szrj   else
3292*38fd1498Szrj     {
3293*38fd1498Szrj       gimple_seq seq;
3294*38fd1498Szrj       gimple *stmt;
3295*38fd1498Szrj       tree bounds;
3296*38fd1498Szrj 
3297*38fd1498Szrj       seq = NULL;
3298*38fd1498Szrj 
3299*38fd1498Szrj       stmt = gimple_build_call (chkp_intersect_fndecl, 2, bounds1, bounds2);
3300*38fd1498Szrj       chkp_mark_stmt (stmt);
3301*38fd1498Szrj 
3302*38fd1498Szrj       bounds = chkp_get_tmp_reg (stmt);
3303*38fd1498Szrj       gimple_call_set_lhs (stmt, bounds);
3304*38fd1498Szrj 
3305*38fd1498Szrj       gimple_seq_add_stmt (&seq, stmt);
3306*38fd1498Szrj 
3307*38fd1498Szrj       /* We are probably doing narrowing for constant expression.
3308*38fd1498Szrj 	 In such case iter may be undefined.  */
3309*38fd1498Szrj       if (!iter)
3310*38fd1498Szrj 	{
3311*38fd1498Szrj 	  gimple_stmt_iterator gsi = gsi_last_bb (chkp_get_entry_block ());
3312*38fd1498Szrj 	  iter = &gsi;
3313*38fd1498Szrj 	  gsi_insert_seq_after (iter, seq, GSI_SAME_STMT);
3314*38fd1498Szrj 	}
3315*38fd1498Szrj       else
3316*38fd1498Szrj 	gsi_insert_seq_before (iter, seq, GSI_SAME_STMT);
3317*38fd1498Szrj 
3318*38fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
3319*38fd1498Szrj 	{
3320*38fd1498Szrj 	  fprintf (dump_file, "Bounds intersection: ");
3321*38fd1498Szrj 	  print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS);
3322*38fd1498Szrj 	  fprintf (dump_file, "  inserted before statement: ");
3323*38fd1498Szrj 	  print_gimple_stmt (dump_file, gsi_stmt (*iter), 0,
3324*38fd1498Szrj 			     TDF_VOPS|TDF_MEMSYMS);
3325*38fd1498Szrj 	}
3326*38fd1498Szrj 
3327*38fd1498Szrj       return bounds;
3328*38fd1498Szrj     }
3329*38fd1498Szrj }
3330*38fd1498Szrj 
3331*38fd1498Szrj /* Return 1 if we are allowed to narrow bounds for addressed FIELD
3332*38fd1498Szrj    and 0 othersize.  REF is reference to the field.  */
3333*38fd1498Szrj 
3334*38fd1498Szrj static bool
3335*38fd1498Szrj chkp_may_narrow_to_field (tree ref, tree field)
3336*38fd1498Szrj {
3337*38fd1498Szrj   return DECL_SIZE (field) && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST
3338*38fd1498Szrj     && tree_to_uhwi (DECL_SIZE (field)) != 0
3339*38fd1498Szrj     && !(flag_chkp_flexible_struct_trailing_arrays
3340*38fd1498Szrj 	 && array_at_struct_end_p (ref))
3341*38fd1498Szrj     && (!DECL_FIELD_OFFSET (field)
3342*38fd1498Szrj 	|| TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
3343*38fd1498Szrj     && (!DECL_FIELD_BIT_OFFSET (field)
3344*38fd1498Szrj 	|| TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) == INTEGER_CST)
3345*38fd1498Szrj     && !lookup_attribute ("bnd_variable_size", DECL_ATTRIBUTES (field))
3346*38fd1498Szrj     && !chkp_variable_size_type (TREE_TYPE (field));
3347*38fd1498Szrj }
3348*38fd1498Szrj 
3349*38fd1498Szrj /* Return 1 if bounds for FIELD should be narrowed to
3350*38fd1498Szrj    field's own size.  REF is reference to the field.  */
3351*38fd1498Szrj 
3352*38fd1498Szrj static bool
3353*38fd1498Szrj chkp_narrow_bounds_for_field (tree ref, tree field)
3354*38fd1498Szrj {
3355*38fd1498Szrj   HOST_WIDE_INT offs;
3356*38fd1498Szrj   HOST_WIDE_INT bit_offs;
3357*38fd1498Szrj 
3358*38fd1498Szrj   if (!chkp_may_narrow_to_field (ref, field))
3359*38fd1498Szrj     return false;
3360*38fd1498Szrj 
3361*38fd1498Szrj   /* Access to compiler generated fields should not cause
3362*38fd1498Szrj      bounds narrowing.  */
3363*38fd1498Szrj   if (DECL_ARTIFICIAL (field))
3364*38fd1498Szrj     return false;
3365*38fd1498Szrj 
3366*38fd1498Szrj   offs = tree_to_uhwi (DECL_FIELD_OFFSET (field));
3367*38fd1498Szrj   bit_offs = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field));
3368*38fd1498Szrj 
3369*38fd1498Szrj   return (flag_chkp_narrow_bounds
3370*38fd1498Szrj 	  && (flag_chkp_first_field_has_own_bounds
3371*38fd1498Szrj 	      || offs
3372*38fd1498Szrj 	      || bit_offs));
3373*38fd1498Szrj }
3374*38fd1498Szrj 
3375*38fd1498Szrj /* Perform narrowing for BOUNDS of an INNER reference.  Shift boundary
3376*38fd1498Szrj    by OFFSET bytes and limit to SIZE bytes.  Newly created statements are
3377*38fd1498Szrj    added to ITER.  */
3378*38fd1498Szrj 
3379*38fd1498Szrj static tree
3380*38fd1498Szrj chkp_narrow_size_and_offset (tree bounds, tree inner, tree offset,
3381*38fd1498Szrj 			     tree size, gimple_stmt_iterator *iter)
3382*38fd1498Szrj {
3383*38fd1498Szrj   tree addr = chkp_build_addr_expr (unshare_expr (inner));
3384*38fd1498Szrj   tree t = TREE_TYPE (addr);
3385*38fd1498Szrj 
3386*38fd1498Szrj   gimple *stmt = gimple_build_assign (NULL_TREE, addr);
3387*38fd1498Szrj   addr = make_temp_ssa_name (t, stmt, CHKP_BOUND_TMP_NAME);
3388*38fd1498Szrj   gimple_assign_set_lhs (stmt, addr);
3389*38fd1498Szrj   gsi_insert_seq_before (iter, stmt, GSI_SAME_STMT);
3390*38fd1498Szrj 
3391*38fd1498Szrj   stmt = gimple_build_assign (NULL_TREE, POINTER_PLUS_EXPR, addr, offset);
3392*38fd1498Szrj   tree shifted = make_temp_ssa_name (t, stmt, CHKP_BOUND_TMP_NAME);
3393*38fd1498Szrj   gimple_assign_set_lhs (stmt, shifted);
3394*38fd1498Szrj   gsi_insert_seq_before (iter, stmt, GSI_SAME_STMT);
3395*38fd1498Szrj 
3396*38fd1498Szrj   tree bounds2 = chkp_make_bounds (shifted, size, iter, false);
3397*38fd1498Szrj 
3398*38fd1498Szrj   return chkp_intersect_bounds (bounds, bounds2, iter);
3399*38fd1498Szrj }
3400*38fd1498Szrj 
3401*38fd1498Szrj /* Perform narrowing for BOUNDS using bounds computed for field
3402*38fd1498Szrj    access COMPONENT.  ITER meaning is the same as for
3403*38fd1498Szrj    chkp_intersect_bounds.  */
3404*38fd1498Szrj 
3405*38fd1498Szrj static tree
3406*38fd1498Szrj chkp_narrow_bounds_to_field (tree bounds, tree component,
3407*38fd1498Szrj 			    gimple_stmt_iterator *iter)
3408*38fd1498Szrj {
3409*38fd1498Szrj   tree field = TREE_OPERAND (component, 1);
3410*38fd1498Szrj   tree size = DECL_SIZE_UNIT (field);
3411*38fd1498Szrj   tree field_ptr = chkp_build_addr_expr (component);
3412*38fd1498Szrj   tree field_bounds;
3413*38fd1498Szrj 
3414*38fd1498Szrj   field_bounds = chkp_make_bounds (field_ptr, size, iter, false);
3415*38fd1498Szrj 
3416*38fd1498Szrj   return chkp_intersect_bounds (field_bounds, bounds, iter);
3417*38fd1498Szrj }
3418*38fd1498Szrj 
3419*38fd1498Szrj /* Parse field or array access NODE.
3420*38fd1498Szrj 
3421*38fd1498Szrj    PTR ouput parameter holds a pointer to the outermost
3422*38fd1498Szrj    object.
3423*38fd1498Szrj 
3424*38fd1498Szrj    BITFIELD output parameter is set to 1 if bitfield is
3425*38fd1498Szrj    accessed and to 0 otherwise.  If it is 1 then ELT holds
3426*38fd1498Szrj    outer component for accessed bit field.
3427*38fd1498Szrj 
3428*38fd1498Szrj    SAFE outer parameter is set to 1 if access is safe and
3429*38fd1498Szrj    checks are not required.
3430*38fd1498Szrj 
3431*38fd1498Szrj    BOUNDS outer parameter holds bounds to be used to check
3432*38fd1498Szrj    access (may be NULL).
3433*38fd1498Szrj 
3434*38fd1498Szrj    If INNERMOST_BOUNDS is 1 then try to narrow bounds to the
3435*38fd1498Szrj    innermost accessed component.  */
3436*38fd1498Szrj static void
3437*38fd1498Szrj chkp_parse_array_and_component_ref (tree node, tree *ptr,
3438*38fd1498Szrj 				    tree *elt, bool *safe,
3439*38fd1498Szrj 				    bool *bitfield,
3440*38fd1498Szrj 				    tree *bounds,
3441*38fd1498Szrj 				    gimple_stmt_iterator *iter,
3442*38fd1498Szrj 				    bool innermost_bounds)
3443*38fd1498Szrj {
3444*38fd1498Szrj   tree comp_to_narrow = NULL_TREE;
3445*38fd1498Szrj   tree last_comp = NULL_TREE;
3446*38fd1498Szrj   bool array_ref_found = false;
3447*38fd1498Szrj   tree *nodes;
3448*38fd1498Szrj   tree var;
3449*38fd1498Szrj   int len;
3450*38fd1498Szrj   int i;
3451*38fd1498Szrj 
3452*38fd1498Szrj   /* Compute tree height for expression.  */
3453*38fd1498Szrj   var = node;
3454*38fd1498Szrj   len = 1;
3455*38fd1498Szrj   while (TREE_CODE (var) == COMPONENT_REF
3456*38fd1498Szrj 	 || TREE_CODE (var) == ARRAY_REF
3457*38fd1498Szrj 	 || TREE_CODE (var) == VIEW_CONVERT_EXPR
3458*38fd1498Szrj 	 || TREE_CODE (var) == BIT_FIELD_REF)
3459*38fd1498Szrj     {
3460*38fd1498Szrj       var = TREE_OPERAND (var, 0);
3461*38fd1498Szrj       len++;
3462*38fd1498Szrj     }
3463*38fd1498Szrj 
3464*38fd1498Szrj   gcc_assert (len > 1);
3465*38fd1498Szrj 
3466*38fd1498Szrj   /* It is more convenient for us to scan left-to-right,
3467*38fd1498Szrj      so walk tree again and put all node to nodes vector
3468*38fd1498Szrj      in reversed order.  */
3469*38fd1498Szrj   nodes = XALLOCAVEC (tree, len);
3470*38fd1498Szrj   nodes[len - 1] = node;
3471*38fd1498Szrj   for (i = len - 2; i >= 0; i--)
3472*38fd1498Szrj     nodes[i] = TREE_OPERAND (nodes[i + 1], 0);
3473*38fd1498Szrj 
3474*38fd1498Szrj   if (bounds)
3475*38fd1498Szrj     *bounds = NULL;
3476*38fd1498Szrj   *safe = true;
3477*38fd1498Szrj   *bitfield = ((TREE_CODE (node) == COMPONENT_REF
3478*38fd1498Szrj 	       && DECL_BIT_FIELD_TYPE (TREE_OPERAND (node, 1)))
3479*38fd1498Szrj 	       || TREE_CODE (node) == BIT_FIELD_REF);
3480*38fd1498Szrj   /* To get bitfield address we will need outer element.  */
3481*38fd1498Szrj   if (*bitfield)
3482*38fd1498Szrj     *elt = nodes[len - 2];
3483*38fd1498Szrj   else
3484*38fd1498Szrj     *elt = NULL_TREE;
3485*38fd1498Szrj 
3486*38fd1498Szrj   /* If we have indirection in expression then compute
3487*38fd1498Szrj      outermost structure bounds.  Computed bounds may be
3488*38fd1498Szrj      narrowed later.  */
3489*38fd1498Szrj   if (TREE_CODE (nodes[0]) == MEM_REF || INDIRECT_REF_P (nodes[0]))
3490*38fd1498Szrj     {
3491*38fd1498Szrj       *safe = false;
3492*38fd1498Szrj       *ptr = TREE_OPERAND (nodes[0], 0);
3493*38fd1498Szrj       if (bounds)
3494*38fd1498Szrj 	*bounds = chkp_find_bounds (*ptr, iter);
3495*38fd1498Szrj     }
3496*38fd1498Szrj   else
3497*38fd1498Szrj     {
3498*38fd1498Szrj       gcc_assert (VAR_P (var)
3499*38fd1498Szrj 		  || TREE_CODE (var) == PARM_DECL
3500*38fd1498Szrj 		  || TREE_CODE (var) == RESULT_DECL
3501*38fd1498Szrj 		  || TREE_CODE (var) == STRING_CST
3502*38fd1498Szrj 		  || TREE_CODE (var) == SSA_NAME);
3503*38fd1498Szrj 
3504*38fd1498Szrj       *ptr = chkp_build_addr_expr (var);
3505*38fd1498Szrj 
3506*38fd1498Szrj       /* For hard register cases chkp_build_addr_expr returns INTEGER_CST
3507*38fd1498Szrj 	 and later on chkp_find_bounds will fail to find proper bounds.
3508*38fd1498Szrj 	 In order to avoid that, we find/create bounds right aways using
3509*38fd1498Szrj 	 the var itself.  */
3510*38fd1498Szrj       if (VAR_P (var) && DECL_HARD_REGISTER (var))
3511*38fd1498Szrj 	*bounds = chkp_make_addressed_object_bounds (var, iter);
3512*38fd1498Szrj     }
3513*38fd1498Szrj 
3514*38fd1498Szrj   /* In this loop we are trying to find a field access
3515*38fd1498Szrj      requiring narrowing.  There are two simple rules
3516*38fd1498Szrj      for search:
3517*38fd1498Szrj      1.  Leftmost array_ref is chosen if any.
3518*38fd1498Szrj      2.  Rightmost suitable component_ref is chosen if innermost
3519*38fd1498Szrj      bounds are required and no array_ref exists.  */
3520*38fd1498Szrj   for (i = 1; i < len; i++)
3521*38fd1498Szrj     {
3522*38fd1498Szrj       var = nodes[i];
3523*38fd1498Szrj 
3524*38fd1498Szrj       if (TREE_CODE (var) == ARRAY_REF)
3525*38fd1498Szrj 	{
3526*38fd1498Szrj 	  *safe = false;
3527*38fd1498Szrj 	  array_ref_found = true;
3528*38fd1498Szrj 	  if (flag_chkp_narrow_bounds
3529*38fd1498Szrj 	      && !flag_chkp_narrow_to_innermost_arrray
3530*38fd1498Szrj 	      && (!last_comp
3531*38fd1498Szrj 		  || chkp_may_narrow_to_field (var,
3532*38fd1498Szrj 					       TREE_OPERAND (last_comp, 1))))
3533*38fd1498Szrj 	    {
3534*38fd1498Szrj 	      comp_to_narrow = last_comp;
3535*38fd1498Szrj 	      break;
3536*38fd1498Szrj 	    }
3537*38fd1498Szrj 	}
3538*38fd1498Szrj       else if (TREE_CODE (var) == COMPONENT_REF)
3539*38fd1498Szrj 	{
3540*38fd1498Szrj 	  tree field = TREE_OPERAND (var, 1);
3541*38fd1498Szrj 
3542*38fd1498Szrj 	  if (innermost_bounds
3543*38fd1498Szrj 	      && !array_ref_found
3544*38fd1498Szrj 	      && chkp_narrow_bounds_for_field (var, field))
3545*38fd1498Szrj 	    comp_to_narrow = var;
3546*38fd1498Szrj 	  last_comp = var;
3547*38fd1498Szrj 
3548*38fd1498Szrj 	  if (flag_chkp_narrow_bounds
3549*38fd1498Szrj 	      && flag_chkp_narrow_to_innermost_arrray
3550*38fd1498Szrj 	      && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
3551*38fd1498Szrj 	    {
3552*38fd1498Szrj 	      if (bounds)
3553*38fd1498Szrj 		*bounds = chkp_narrow_bounds_to_field (*bounds, var, iter);
3554*38fd1498Szrj 	      comp_to_narrow = NULL;
3555*38fd1498Szrj 	    }
3556*38fd1498Szrj 	}
3557*38fd1498Szrj       else if (TREE_CODE (var) == BIT_FIELD_REF)
3558*38fd1498Szrj 	{
3559*38fd1498Szrj 	  if (flag_chkp_narrow_bounds && bounds)
3560*38fd1498Szrj 	    {
3561*38fd1498Szrj 	      tree offset, size;
3562*38fd1498Szrj 	      chkp_parse_bit_field_ref (var, UNKNOWN_LOCATION, &offset, &size);
3563*38fd1498Szrj 	      *bounds
3564*38fd1498Szrj 		= chkp_narrow_size_and_offset (*bounds, TREE_OPERAND (var, 0),
3565*38fd1498Szrj 					       offset, size, iter);
3566*38fd1498Szrj 	    }
3567*38fd1498Szrj 	}
3568*38fd1498Szrj       else if (TREE_CODE (var) == VIEW_CONVERT_EXPR)
3569*38fd1498Szrj 	/* Nothing to do for it.  */
3570*38fd1498Szrj 	;
3571*38fd1498Szrj       else
3572*38fd1498Szrj 	gcc_unreachable ();
3573*38fd1498Szrj     }
3574*38fd1498Szrj 
3575*38fd1498Szrj   if (comp_to_narrow && DECL_SIZE (TREE_OPERAND (comp_to_narrow, 1)) && bounds)
3576*38fd1498Szrj     *bounds = chkp_narrow_bounds_to_field (*bounds, comp_to_narrow, iter);
3577*38fd1498Szrj 
3578*38fd1498Szrj   if (innermost_bounds && bounds && !*bounds)
3579*38fd1498Szrj     *bounds = chkp_find_bounds (*ptr, iter);
3580*38fd1498Szrj }
3581*38fd1498Szrj 
3582*38fd1498Szrj /* Parse BIT_FIELD_REF to a NODE for a given location LOC.  Return OFFSET
3583*38fd1498Szrj    and SIZE in bytes.  */
3584*38fd1498Szrj 
3585*38fd1498Szrj static
3586*38fd1498Szrj void chkp_parse_bit_field_ref (tree node, location_t loc, tree *offset,
3587*38fd1498Szrj 			       tree *size)
3588*38fd1498Szrj {
3589*38fd1498Szrj   tree bpu = fold_convert (size_type_node, bitsize_int (BITS_PER_UNIT));
3590*38fd1498Szrj   tree offs = fold_convert (size_type_node, TREE_OPERAND (node, 2));
3591*38fd1498Szrj   tree rem = size_binop_loc (loc, TRUNC_MOD_EXPR, offs, bpu);
3592*38fd1498Szrj   offs = size_binop_loc (loc, TRUNC_DIV_EXPR, offs, bpu);
3593*38fd1498Szrj 
3594*38fd1498Szrj   tree s = fold_convert (size_type_node, TREE_OPERAND (node, 1));
3595*38fd1498Szrj   s = size_binop_loc (loc, PLUS_EXPR, s, rem);
3596*38fd1498Szrj   s = size_binop_loc (loc, CEIL_DIV_EXPR, s, bpu);
3597*38fd1498Szrj   s = fold_convert (size_type_node, s);
3598*38fd1498Szrj 
3599*38fd1498Szrj   *offset = offs;
3600*38fd1498Szrj   *size = s;
3601*38fd1498Szrj }
3602*38fd1498Szrj 
3603*38fd1498Szrj /* Compute and return bounds for address of OBJ.  */
3604*38fd1498Szrj static tree
3605*38fd1498Szrj chkp_make_addressed_object_bounds (tree obj, gimple_stmt_iterator *iter)
3606*38fd1498Szrj {
3607*38fd1498Szrj   tree bounds = chkp_get_registered_addr_bounds (obj);
3608*38fd1498Szrj 
3609*38fd1498Szrj   if (bounds)
3610*38fd1498Szrj     return bounds;
3611*38fd1498Szrj 
3612*38fd1498Szrj   switch (TREE_CODE (obj))
3613*38fd1498Szrj     {
3614*38fd1498Szrj     case VAR_DECL:
3615*38fd1498Szrj     case PARM_DECL:
3616*38fd1498Szrj     case RESULT_DECL:
3617*38fd1498Szrj       bounds = chkp_get_bounds_for_decl_addr (obj);
3618*38fd1498Szrj       break;
3619*38fd1498Szrj 
3620*38fd1498Szrj     case STRING_CST:
3621*38fd1498Szrj       bounds = chkp_get_bounds_for_string_cst (obj);
3622*38fd1498Szrj       break;
3623*38fd1498Szrj 
3624*38fd1498Szrj     case ARRAY_REF:
3625*38fd1498Szrj     case COMPONENT_REF:
3626*38fd1498Szrj     case BIT_FIELD_REF:
3627*38fd1498Szrj       {
3628*38fd1498Szrj 	tree elt;
3629*38fd1498Szrj 	tree ptr;
3630*38fd1498Szrj 	bool safe;
3631*38fd1498Szrj 	bool bitfield;
3632*38fd1498Szrj 
3633*38fd1498Szrj 	chkp_parse_array_and_component_ref (obj, &ptr, &elt, &safe,
3634*38fd1498Szrj 					    &bitfield, &bounds, iter, true);
3635*38fd1498Szrj 
3636*38fd1498Szrj 	gcc_assert (bounds);
3637*38fd1498Szrj       }
3638*38fd1498Szrj       break;
3639*38fd1498Szrj 
3640*38fd1498Szrj     case FUNCTION_DECL:
3641*38fd1498Szrj     case LABEL_DECL:
3642*38fd1498Szrj       bounds = chkp_get_zero_bounds ();
3643*38fd1498Szrj       break;
3644*38fd1498Szrj 
3645*38fd1498Szrj     case MEM_REF:
3646*38fd1498Szrj       bounds = chkp_find_bounds (TREE_OPERAND (obj, 0), iter);
3647*38fd1498Szrj       break;
3648*38fd1498Szrj 
3649*38fd1498Szrj     case REALPART_EXPR:
3650*38fd1498Szrj     case IMAGPART_EXPR:
3651*38fd1498Szrj       bounds = chkp_make_addressed_object_bounds (TREE_OPERAND (obj, 0), iter);
3652*38fd1498Szrj       break;
3653*38fd1498Szrj 
3654*38fd1498Szrj     default:
3655*38fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
3656*38fd1498Szrj 	{
3657*38fd1498Szrj 	  fprintf (dump_file, "chkp_make_addressed_object_bounds: "
3658*38fd1498Szrj 		   "unexpected object of type %s\n",
3659*38fd1498Szrj 		   get_tree_code_name (TREE_CODE (obj)));
3660*38fd1498Szrj 	  print_node (dump_file, "", obj, 0);
3661*38fd1498Szrj 	}
3662*38fd1498Szrj       internal_error ("chkp_make_addressed_object_bounds: "
3663*38fd1498Szrj 		      "Unexpected tree code %s",
3664*38fd1498Szrj 		      get_tree_code_name (TREE_CODE (obj)));
3665*38fd1498Szrj     }
3666*38fd1498Szrj 
3667*38fd1498Szrj   chkp_register_addr_bounds (obj, bounds);
3668*38fd1498Szrj 
3669*38fd1498Szrj   return bounds;
3670*38fd1498Szrj }
3671*38fd1498Szrj 
3672*38fd1498Szrj /* Compute bounds for pointer PTR loaded from PTR_SRC.  Generate statements
3673*38fd1498Szrj    to compute bounds if required.  Computed bounds should be available at
3674*38fd1498Szrj    position pointed by ITER.
3675*38fd1498Szrj 
3676*38fd1498Szrj    If PTR_SRC is NULL_TREE then pointer definition is identified.
3677*38fd1498Szrj 
3678*38fd1498Szrj    If PTR_SRC is not NULL_TREE then ITER points to statements which loads
3679*38fd1498Szrj    PTR.  If PTR is a any memory reference then ITER points to a statement
3680*38fd1498Szrj    after which bndldx will be inserterd.  In both cases ITER will be updated
3681*38fd1498Szrj    to point to the inserted bndldx statement.  */
3682*38fd1498Szrj 
3683*38fd1498Szrj static tree
3684*38fd1498Szrj chkp_find_bounds_1 (tree ptr, tree ptr_src, gimple_stmt_iterator *iter)
3685*38fd1498Szrj {
3686*38fd1498Szrj   tree addr = NULL_TREE;
3687*38fd1498Szrj   tree bounds = NULL_TREE;
3688*38fd1498Szrj 
3689*38fd1498Szrj   if (!ptr_src)
3690*38fd1498Szrj     ptr_src = ptr;
3691*38fd1498Szrj 
3692*38fd1498Szrj   bounds = chkp_get_registered_bounds (ptr_src);
3693*38fd1498Szrj 
3694*38fd1498Szrj   if (bounds)
3695*38fd1498Szrj     return bounds;
3696*38fd1498Szrj 
3697*38fd1498Szrj   switch (TREE_CODE (ptr_src))
3698*38fd1498Szrj     {
3699*38fd1498Szrj     case MEM_REF:
3700*38fd1498Szrj     case VAR_DECL:
3701*38fd1498Szrj       if (BOUNDED_P (ptr_src))
3702*38fd1498Szrj 	if (VAR_P (ptr) && DECL_REGISTER (ptr))
3703*38fd1498Szrj 	  bounds = chkp_get_zero_bounds ();
3704*38fd1498Szrj 	else
3705*38fd1498Szrj 	  {
3706*38fd1498Szrj 	    addr = chkp_build_addr_expr (ptr_src);
3707*38fd1498Szrj 	    bounds = chkp_build_bndldx (addr, ptr, iter);
3708*38fd1498Szrj 	  }
3709*38fd1498Szrj       else
3710*38fd1498Szrj 	bounds = chkp_get_nonpointer_load_bounds ();
3711*38fd1498Szrj       break;
3712*38fd1498Szrj 
3713*38fd1498Szrj     case ARRAY_REF:
3714*38fd1498Szrj     case COMPONENT_REF:
3715*38fd1498Szrj       addr = get_base_address (ptr_src);
3716*38fd1498Szrj       if (VAR_P (addr) && DECL_HARD_REGISTER (addr))
3717*38fd1498Szrj 	{
3718*38fd1498Szrj 	  bounds = chkp_get_zero_bounds ();
3719*38fd1498Szrj 	  break;
3720*38fd1498Szrj 	}
3721*38fd1498Szrj       if (DECL_P (addr)
3722*38fd1498Szrj 	  || TREE_CODE (addr) == MEM_REF
3723*38fd1498Szrj 	  || TREE_CODE (addr) == TARGET_MEM_REF)
3724*38fd1498Szrj 	{
3725*38fd1498Szrj 	  if (BOUNDED_P (ptr_src))
3726*38fd1498Szrj 	    if (VAR_P (ptr) && DECL_REGISTER (ptr))
3727*38fd1498Szrj 	      bounds = chkp_get_zero_bounds ();
3728*38fd1498Szrj 	    else
3729*38fd1498Szrj 	      {
3730*38fd1498Szrj 		addr = chkp_build_addr_expr (ptr_src);
3731*38fd1498Szrj 		bounds = chkp_build_bndldx (addr, ptr, iter);
3732*38fd1498Szrj 	      }
3733*38fd1498Szrj 	  else
3734*38fd1498Szrj 	    bounds = chkp_get_nonpointer_load_bounds ();
3735*38fd1498Szrj 	}
3736*38fd1498Szrj       else
3737*38fd1498Szrj 	{
3738*38fd1498Szrj 	  gcc_assert (TREE_CODE (addr) == SSA_NAME);
3739*38fd1498Szrj 	  bounds = chkp_find_bounds (addr, iter);
3740*38fd1498Szrj 	}
3741*38fd1498Szrj       break;
3742*38fd1498Szrj 
3743*38fd1498Szrj     case PARM_DECL:
3744*38fd1498Szrj       /* Handled above but failed.  */
3745*38fd1498Szrj       bounds = chkp_get_invalid_op_bounds ();
3746*38fd1498Szrj       break;
3747*38fd1498Szrj 
3748*38fd1498Szrj     case TARGET_MEM_REF:
3749*38fd1498Szrj       addr = chkp_build_addr_expr (ptr_src);
3750*38fd1498Szrj       bounds = chkp_build_bndldx (addr, ptr, iter);
3751*38fd1498Szrj       break;
3752*38fd1498Szrj 
3753*38fd1498Szrj     case SSA_NAME:
3754*38fd1498Szrj       bounds = chkp_get_registered_bounds (ptr_src);
3755*38fd1498Szrj       if (!bounds)
3756*38fd1498Szrj 	{
3757*38fd1498Szrj 	  gimple *def_stmt = SSA_NAME_DEF_STMT (ptr_src);
3758*38fd1498Szrj 	  gphi_iterator phi_iter;
3759*38fd1498Szrj 
3760*38fd1498Szrj 	  bounds = chkp_get_bounds_by_definition (ptr_src, def_stmt, &phi_iter);
3761*38fd1498Szrj 
3762*38fd1498Szrj 	  gcc_assert (bounds);
3763*38fd1498Szrj 
3764*38fd1498Szrj 	  if (gphi *def_phi = dyn_cast <gphi *> (def_stmt))
3765*38fd1498Szrj 	    {
3766*38fd1498Szrj 	      unsigned i;
3767*38fd1498Szrj 
3768*38fd1498Szrj 	      for (i = 0; i < gimple_phi_num_args (def_phi); i++)
3769*38fd1498Szrj 		{
3770*38fd1498Szrj 		  tree arg = gimple_phi_arg_def (def_phi, i);
3771*38fd1498Szrj 		  tree arg_bnd;
3772*38fd1498Szrj 		  gphi *phi_bnd;
3773*38fd1498Szrj 
3774*38fd1498Szrj 		  arg_bnd = chkp_find_bounds (arg, NULL);
3775*38fd1498Szrj 
3776*38fd1498Szrj 		  /* chkp_get_bounds_by_definition created new phi
3777*38fd1498Szrj 		     statement and phi_iter points to it.
3778*38fd1498Szrj 
3779*38fd1498Szrj 		     Previous call to chkp_find_bounds could create
3780*38fd1498Szrj 		     new basic block and therefore change phi statement
3781*38fd1498Szrj 		     phi_iter points to.  */
3782*38fd1498Szrj 		  phi_bnd = phi_iter.phi ();
3783*38fd1498Szrj 
3784*38fd1498Szrj 		  add_phi_arg (phi_bnd, arg_bnd,
3785*38fd1498Szrj 			       gimple_phi_arg_edge (def_phi, i),
3786*38fd1498Szrj 			       UNKNOWN_LOCATION);
3787*38fd1498Szrj 		}
3788*38fd1498Szrj 
3789*38fd1498Szrj 	      /* If all bound phi nodes have their arg computed
3790*38fd1498Szrj 		 then we may finish its computation.  See
3791*38fd1498Szrj 		 chkp_finish_incomplete_bounds for more details.  */
3792*38fd1498Szrj 	      if (chkp_may_finish_incomplete_bounds ())
3793*38fd1498Szrj 		chkp_finish_incomplete_bounds ();
3794*38fd1498Szrj 	    }
3795*38fd1498Szrj 
3796*38fd1498Szrj 	  gcc_assert (bounds == chkp_get_registered_bounds (ptr_src)
3797*38fd1498Szrj 		      || chkp_incomplete_bounds (bounds));
3798*38fd1498Szrj 	}
3799*38fd1498Szrj       break;
3800*38fd1498Szrj 
3801*38fd1498Szrj     case ADDR_EXPR:
3802*38fd1498Szrj     case WITH_SIZE_EXPR:
3803*38fd1498Szrj       bounds = chkp_make_addressed_object_bounds (TREE_OPERAND (ptr_src, 0), iter);
3804*38fd1498Szrj       break;
3805*38fd1498Szrj 
3806*38fd1498Szrj     case INTEGER_CST:
3807*38fd1498Szrj     case COMPLEX_CST:
3808*38fd1498Szrj     case VECTOR_CST:
3809*38fd1498Szrj       if (integer_zerop (ptr_src))
3810*38fd1498Szrj 	bounds = chkp_get_none_bounds ();
3811*38fd1498Szrj       else
3812*38fd1498Szrj 	bounds = chkp_get_invalid_op_bounds ();
3813*38fd1498Szrj       break;
3814*38fd1498Szrj 
3815*38fd1498Szrj     default:
3816*38fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
3817*38fd1498Szrj 	{
3818*38fd1498Szrj 	  fprintf (dump_file, "chkp_find_bounds: unexpected ptr of type %s\n",
3819*38fd1498Szrj 		   get_tree_code_name (TREE_CODE (ptr_src)));
3820*38fd1498Szrj 	  print_node (dump_file, "", ptr_src, 0);
3821*38fd1498Szrj 	}
3822*38fd1498Szrj       internal_error ("chkp_find_bounds: Unexpected tree code %s",
3823*38fd1498Szrj 		      get_tree_code_name (TREE_CODE (ptr_src)));
3824*38fd1498Szrj     }
3825*38fd1498Szrj 
3826*38fd1498Szrj   if (!bounds)
3827*38fd1498Szrj     {
3828*38fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
3829*38fd1498Szrj 	{
3830*38fd1498Szrj 	  fprintf (stderr, "chkp_find_bounds: cannot find bounds for pointer\n");
3831*38fd1498Szrj 	  print_node (dump_file, "", ptr_src, 0);
3832*38fd1498Szrj 	}
3833*38fd1498Szrj       internal_error ("chkp_find_bounds: Cannot find bounds for pointer");
3834*38fd1498Szrj     }
3835*38fd1498Szrj 
3836*38fd1498Szrj   return bounds;
3837*38fd1498Szrj }
3838*38fd1498Szrj 
3839*38fd1498Szrj /* Normal case for bounds search without forced narrowing.  */
3840*38fd1498Szrj static tree
3841*38fd1498Szrj chkp_find_bounds (tree ptr, gimple_stmt_iterator *iter)
3842*38fd1498Szrj {
3843*38fd1498Szrj   return chkp_find_bounds_1 (ptr, NULL_TREE, iter);
3844*38fd1498Szrj }
3845*38fd1498Szrj 
3846*38fd1498Szrj /* Search bounds for pointer PTR loaded from PTR_SRC
3847*38fd1498Szrj    by statement *ITER points to.  */
3848*38fd1498Szrj static tree
3849*38fd1498Szrj chkp_find_bounds_loaded (tree ptr, tree ptr_src, gimple_stmt_iterator *iter)
3850*38fd1498Szrj {
3851*38fd1498Szrj   return chkp_find_bounds_1 (ptr, ptr_src, iter);
3852*38fd1498Szrj }
3853*38fd1498Szrj 
3854*38fd1498Szrj /* Helper function which checks type of RHS and finds all pointers in
3855*38fd1498Szrj    it.  For each found pointer we build it's accesses in LHS and RHS
3856*38fd1498Szrj    objects and then call HANDLER for them.  Function is used to copy
3857*38fd1498Szrj    or initilize bounds for copied object.  */
3858*38fd1498Szrj static void
3859*38fd1498Szrj chkp_walk_pointer_assignments (tree lhs, tree rhs, void *arg,
3860*38fd1498Szrj 			       assign_handler handler)
3861*38fd1498Szrj {
3862*38fd1498Szrj   tree type = TREE_TYPE (lhs);
3863*38fd1498Szrj 
3864*38fd1498Szrj   /* We have nothing to do with clobbers.  */
3865*38fd1498Szrj   if (TREE_CLOBBER_P (rhs))
3866*38fd1498Szrj     return;
3867*38fd1498Szrj 
3868*38fd1498Szrj   if (BOUNDED_TYPE_P (type))
3869*38fd1498Szrj     handler (lhs, rhs, arg);
3870*38fd1498Szrj   else if (RECORD_OR_UNION_TYPE_P (type))
3871*38fd1498Szrj     {
3872*38fd1498Szrj       tree field;
3873*38fd1498Szrj 
3874*38fd1498Szrj       if (TREE_CODE (rhs) == CONSTRUCTOR)
3875*38fd1498Szrj 	{
3876*38fd1498Szrj 	  unsigned HOST_WIDE_INT cnt;
3877*38fd1498Szrj 	  tree val;
3878*38fd1498Szrj 
3879*38fd1498Szrj 	  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs), cnt, field, val)
3880*38fd1498Szrj 	    {
3881*38fd1498Szrj 	      if (field && chkp_type_has_pointer (TREE_TYPE (field)))
3882*38fd1498Szrj 		{
3883*38fd1498Szrj 		  tree lhs_field = chkp_build_component_ref (lhs, field);
3884*38fd1498Szrj 		  chkp_walk_pointer_assignments (lhs_field, val, arg, handler);
3885*38fd1498Szrj 		}
3886*38fd1498Szrj 	    }
3887*38fd1498Szrj 	}
3888*38fd1498Szrj       else
3889*38fd1498Szrj 	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
3890*38fd1498Szrj 	  if (TREE_CODE (field) == FIELD_DECL
3891*38fd1498Szrj 	      && chkp_type_has_pointer (TREE_TYPE (field)))
3892*38fd1498Szrj 	    {
3893*38fd1498Szrj 	      tree rhs_field = chkp_build_component_ref (rhs, field);
3894*38fd1498Szrj 	      tree lhs_field = chkp_build_component_ref (lhs, field);
3895*38fd1498Szrj 	      chkp_walk_pointer_assignments (lhs_field, rhs_field, arg, handler);
3896*38fd1498Szrj 	    }
3897*38fd1498Szrj     }
3898*38fd1498Szrj   else if (TREE_CODE (type) == ARRAY_TYPE)
3899*38fd1498Szrj     {
3900*38fd1498Szrj       unsigned HOST_WIDE_INT cur = 0;
3901*38fd1498Szrj       tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
3902*38fd1498Szrj       tree etype = TREE_TYPE (type);
3903*38fd1498Szrj       tree esize = TYPE_SIZE (etype);
3904*38fd1498Szrj 
3905*38fd1498Szrj       if (TREE_CODE (rhs) == CONSTRUCTOR)
3906*38fd1498Szrj 	{
3907*38fd1498Szrj 	  unsigned HOST_WIDE_INT cnt;
3908*38fd1498Szrj 	  tree purp, val, lhs_elem;
3909*38fd1498Szrj 
3910*38fd1498Szrj 	  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs), cnt, purp, val)
3911*38fd1498Szrj 	    {
3912*38fd1498Szrj 	      if (purp && TREE_CODE (purp) == RANGE_EXPR)
3913*38fd1498Szrj 		{
3914*38fd1498Szrj 		  tree lo_index = TREE_OPERAND (purp, 0);
3915*38fd1498Szrj 		  tree hi_index = TREE_OPERAND (purp, 1);
3916*38fd1498Szrj 
3917*38fd1498Szrj 		  for (cur = (unsigned)tree_to_uhwi (lo_index);
3918*38fd1498Szrj 		       cur <= (unsigned)tree_to_uhwi (hi_index);
3919*38fd1498Szrj 		       cur++)
3920*38fd1498Szrj 		    {
3921*38fd1498Szrj 		      lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur);
3922*38fd1498Szrj 		      chkp_walk_pointer_assignments (lhs_elem, val, arg, handler);
3923*38fd1498Szrj 		    }
3924*38fd1498Szrj 		}
3925*38fd1498Szrj 	      else
3926*38fd1498Szrj 		{
3927*38fd1498Szrj 		  if (purp)
3928*38fd1498Szrj 		    {
3929*38fd1498Szrj 		      gcc_assert (TREE_CODE (purp) == INTEGER_CST);
3930*38fd1498Szrj 		      cur = tree_to_uhwi (purp);
3931*38fd1498Szrj 		    }
3932*38fd1498Szrj 
3933*38fd1498Szrj 		  lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur++);
3934*38fd1498Szrj 
3935*38fd1498Szrj 		  chkp_walk_pointer_assignments (lhs_elem, val, arg, handler);
3936*38fd1498Szrj 		}
3937*38fd1498Szrj 	    }
3938*38fd1498Szrj 	}
3939*38fd1498Szrj       /* Copy array only when size is known.  */
3940*38fd1498Szrj       else if (maxval && !integer_minus_onep (maxval))
3941*38fd1498Szrj 	for (cur = 0; cur <= TREE_INT_CST_LOW (maxval); cur++)
3942*38fd1498Szrj 	  {
3943*38fd1498Szrj 	    tree lhs_elem = chkp_build_array_ref (lhs, etype, esize, cur);
3944*38fd1498Szrj 	    tree rhs_elem = chkp_build_array_ref (rhs, etype, esize, cur);
3945*38fd1498Szrj 	    chkp_walk_pointer_assignments (lhs_elem, rhs_elem, arg, handler);
3946*38fd1498Szrj 	  }
3947*38fd1498Szrj     }
3948*38fd1498Szrj   else
3949*38fd1498Szrj     internal_error("chkp_walk_pointer_assignments: unexpected RHS type: %s",
3950*38fd1498Szrj 		   get_tree_code_name (TREE_CODE (type)));
3951*38fd1498Szrj }
3952*38fd1498Szrj 
3953*38fd1498Szrj /* Add code to copy bounds for assignment of RHS to LHS.
3954*38fd1498Szrj    ARG is an iterator pointing ne code position.  */
3955*38fd1498Szrj static void
3956*38fd1498Szrj chkp_copy_bounds_for_elem (tree lhs, tree rhs, void *arg)
3957*38fd1498Szrj {
3958*38fd1498Szrj   gimple_stmt_iterator *iter = (gimple_stmt_iterator *)arg;
3959*38fd1498Szrj   tree bounds = chkp_find_bounds (rhs, iter);
3960*38fd1498Szrj   tree addr = chkp_build_addr_expr(lhs);
3961*38fd1498Szrj 
3962*38fd1498Szrj   chkp_build_bndstx (addr, rhs, bounds, iter);
3963*38fd1498Szrj }
3964*38fd1498Szrj 
3965*38fd1498Szrj /* Emit static bound initilizers and size vars.  */
3966*38fd1498Szrj void
3967*38fd1498Szrj chkp_finish_file (void)
3968*38fd1498Szrj {
3969*38fd1498Szrj   struct varpool_node *node;
3970*38fd1498Szrj   struct chkp_ctor_stmt_list stmts;
3971*38fd1498Szrj 
3972*38fd1498Szrj   if (seen_error ())
3973*38fd1498Szrj     return;
3974*38fd1498Szrj 
3975*38fd1498Szrj   /* Iterate through varpool and generate bounds initialization
3976*38fd1498Szrj      constructors for all statically initialized pointers.  */
3977*38fd1498Szrj   stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
3978*38fd1498Szrj   stmts.stmts = NULL;
3979*38fd1498Szrj   FOR_EACH_VARIABLE (node)
3980*38fd1498Szrj     /* Check that var is actually emitted and we need and may initialize
3981*38fd1498Szrj        its bounds.  */
3982*38fd1498Szrj     if (node->need_bounds_init
3983*38fd1498Szrj 	&& !POINTER_BOUNDS_P (node->decl)
3984*38fd1498Szrj 	&& DECL_RTL (node->decl)
3985*38fd1498Szrj 	&& MEM_P (DECL_RTL (node->decl))
3986*38fd1498Szrj 	&& TREE_ASM_WRITTEN (node->decl))
3987*38fd1498Szrj       {
3988*38fd1498Szrj 	chkp_walk_pointer_assignments (node->decl,
3989*38fd1498Szrj 				       DECL_INITIAL (node->decl),
3990*38fd1498Szrj 				       &stmts,
3991*38fd1498Szrj 				       chkp_add_modification_to_stmt_list);
3992*38fd1498Szrj 
3993*38fd1498Szrj 	if (stmts.avail <= 0)
3994*38fd1498Szrj 	  {
3995*38fd1498Szrj 	    cgraph_build_static_cdtor ('P', stmts.stmts,
3996*38fd1498Szrj 				       MAX_RESERVED_INIT_PRIORITY + 3);
3997*38fd1498Szrj 	    stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
3998*38fd1498Szrj 	    stmts.stmts = NULL;
3999*38fd1498Szrj 	  }
4000*38fd1498Szrj       }
4001*38fd1498Szrj 
4002*38fd1498Szrj   if (stmts.stmts)
4003*38fd1498Szrj     cgraph_build_static_cdtor ('P', stmts.stmts,
4004*38fd1498Szrj 			       MAX_RESERVED_INIT_PRIORITY + 3);
4005*38fd1498Szrj 
4006*38fd1498Szrj   /* Iterate through varpool and generate bounds initialization
4007*38fd1498Szrj      constructors for all static bounds vars.  */
4008*38fd1498Szrj   stmts.avail = MAX_STMTS_IN_STATIC_CHKP_CTOR;
4009*38fd1498Szrj   stmts.stmts = NULL;
4010*38fd1498Szrj   FOR_EACH_VARIABLE (node)
4011*38fd1498Szrj     if (node->need_bounds_init
4012*38fd1498Szrj 	&& POINTER_BOUNDS_P (node->decl)
4013*38fd1498Szrj 	&& TREE_ASM_WRITTEN (node->decl))
4014*38fd1498Szrj       {
4015*38fd1498Szrj 	tree bnd = node->decl;
4016*38fd1498Szrj 	tree var;
4017*38fd1498Szrj 
4018*38fd1498Szrj 	gcc_assert (DECL_INITIAL (bnd)
4019*38fd1498Szrj 		    && TREE_CODE (DECL_INITIAL (bnd)) == ADDR_EXPR);
4020*38fd1498Szrj 
4021*38fd1498Szrj 	var = TREE_OPERAND (DECL_INITIAL (bnd), 0);
4022*38fd1498Szrj 	chkp_output_static_bounds (bnd, var, &stmts);
4023*38fd1498Szrj       }
4024*38fd1498Szrj 
4025*38fd1498Szrj   if (stmts.stmts)
4026*38fd1498Szrj     cgraph_build_static_cdtor ('B', stmts.stmts,
4027*38fd1498Szrj 			       MAX_RESERVED_INIT_PRIORITY + 2);
4028*38fd1498Szrj 
4029*38fd1498Szrj   delete chkp_static_var_bounds;
4030*38fd1498Szrj   delete chkp_bounds_map;
4031*38fd1498Szrj }
4032*38fd1498Szrj 
4033*38fd1498Szrj /* An instrumentation function which is called for each statement
4034*38fd1498Szrj    having memory access we want to instrument.  It inserts check
4035*38fd1498Szrj    code and bounds copy code.
4036*38fd1498Szrj 
4037*38fd1498Szrj    ITER points to statement to instrument.
4038*38fd1498Szrj 
4039*38fd1498Szrj    NODE holds memory access in statement to check.
4040*38fd1498Szrj 
4041*38fd1498Szrj    LOC holds the location information for statement.
4042*38fd1498Szrj 
4043*38fd1498Szrj    DIRFLAGS determines whether access is read or write.
4044*38fd1498Szrj 
4045*38fd1498Szrj    ACCESS_OFFS should be added to address used in NODE
4046*38fd1498Szrj    before check.
4047*38fd1498Szrj 
4048*38fd1498Szrj    ACCESS_SIZE holds size of checked access.
4049*38fd1498Szrj 
4050*38fd1498Szrj    SAFE indicates if NODE access is safe and should not be
4051*38fd1498Szrj    checked.  */
4052*38fd1498Szrj static void
4053*38fd1498Szrj chkp_process_stmt (gimple_stmt_iterator *iter, tree node,
4054*38fd1498Szrj 		   location_t loc, tree dirflag,
4055*38fd1498Szrj 		   tree access_offs, tree access_size,
4056*38fd1498Szrj 		   bool safe)
4057*38fd1498Szrj {
4058*38fd1498Szrj   tree node_type = TREE_TYPE (node);
4059*38fd1498Szrj   tree size = access_size ? access_size : TYPE_SIZE_UNIT (node_type);
4060*38fd1498Szrj   tree addr_first = NULL_TREE; /* address of the first accessed byte */
4061*38fd1498Szrj   tree addr_last = NULL_TREE; /* address of the last accessed byte */
4062*38fd1498Szrj   tree ptr = NULL_TREE; /* a pointer used for dereference */
4063*38fd1498Szrj   tree bounds = NULL_TREE;
4064*38fd1498Szrj   bool reg_store = false;
4065*38fd1498Szrj 
4066*38fd1498Szrj   /* We do not need instrumentation for clobbers.  */
4067*38fd1498Szrj   if (dirflag == integer_one_node
4068*38fd1498Szrj       && gimple_code (gsi_stmt (*iter)) == GIMPLE_ASSIGN
4069*38fd1498Szrj       && TREE_CLOBBER_P (gimple_assign_rhs1 (gsi_stmt (*iter))))
4070*38fd1498Szrj     return;
4071*38fd1498Szrj 
4072*38fd1498Szrj   switch (TREE_CODE (node))
4073*38fd1498Szrj     {
4074*38fd1498Szrj     case ARRAY_REF:
4075*38fd1498Szrj     case COMPONENT_REF:
4076*38fd1498Szrj       {
4077*38fd1498Szrj 	bool bitfield;
4078*38fd1498Szrj 	tree elt;
4079*38fd1498Szrj 
4080*38fd1498Szrj 	if (safe)
4081*38fd1498Szrj 	  {
4082*38fd1498Szrj 	    /* We are not going to generate any checks, so do not
4083*38fd1498Szrj 	       generate bounds as well.  */
4084*38fd1498Szrj 	    addr_first = chkp_build_addr_expr (node);
4085*38fd1498Szrj 	    break;
4086*38fd1498Szrj 	  }
4087*38fd1498Szrj 
4088*38fd1498Szrj 	chkp_parse_array_and_component_ref (node, &ptr, &elt, &safe,
4089*38fd1498Szrj 					    &bitfield, &bounds, iter, false);
4090*38fd1498Szrj 
4091*38fd1498Szrj 	/* Break if there is no dereference and operation is safe.  */
4092*38fd1498Szrj 
4093*38fd1498Szrj 	if (bitfield)
4094*38fd1498Szrj           {
4095*38fd1498Szrj             tree field = TREE_OPERAND (node, 1);
4096*38fd1498Szrj 
4097*38fd1498Szrj             if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
4098*38fd1498Szrj               size = DECL_SIZE_UNIT (field);
4099*38fd1498Szrj 
4100*38fd1498Szrj 	    if (elt)
4101*38fd1498Szrj 	      elt = chkp_build_addr_expr (elt);
4102*38fd1498Szrj             addr_first = fold_convert_loc (loc, ptr_type_node, elt ? elt : ptr);
4103*38fd1498Szrj             addr_first = fold_build_pointer_plus_loc (loc,
4104*38fd1498Szrj 						      addr_first,
4105*38fd1498Szrj 						      byte_position (field));
4106*38fd1498Szrj           }
4107*38fd1498Szrj         else
4108*38fd1498Szrj           addr_first = chkp_build_addr_expr (node);
4109*38fd1498Szrj       }
4110*38fd1498Szrj       break;
4111*38fd1498Szrj 
4112*38fd1498Szrj     case INDIRECT_REF:
4113*38fd1498Szrj       ptr = TREE_OPERAND (node, 0);
4114*38fd1498Szrj       addr_first = ptr;
4115*38fd1498Szrj       break;
4116*38fd1498Szrj 
4117*38fd1498Szrj     case MEM_REF:
4118*38fd1498Szrj       ptr = TREE_OPERAND (node, 0);
4119*38fd1498Szrj       addr_first = chkp_build_addr_expr (node);
4120*38fd1498Szrj       break;
4121*38fd1498Szrj 
4122*38fd1498Szrj     case TARGET_MEM_REF:
4123*38fd1498Szrj       ptr = TMR_BASE (node);
4124*38fd1498Szrj       addr_first = chkp_build_addr_expr (node);
4125*38fd1498Szrj       break;
4126*38fd1498Szrj 
4127*38fd1498Szrj     case ARRAY_RANGE_REF:
4128*38fd1498Szrj       printf("ARRAY_RANGE_REF\n");
4129*38fd1498Szrj       debug_gimple_stmt(gsi_stmt(*iter));
4130*38fd1498Szrj       debug_tree(node);
4131*38fd1498Szrj       gcc_unreachable ();
4132*38fd1498Szrj       break;
4133*38fd1498Szrj 
4134*38fd1498Szrj     case BIT_FIELD_REF:
4135*38fd1498Szrj       {
4136*38fd1498Szrj 	tree offset, size;
4137*38fd1498Szrj 
4138*38fd1498Szrj 	gcc_assert (!access_offs);
4139*38fd1498Szrj 	gcc_assert (!access_size);
4140*38fd1498Szrj 
4141*38fd1498Szrj 	chkp_parse_bit_field_ref (node, loc, &offset, &size);
4142*38fd1498Szrj 
4143*38fd1498Szrj 	chkp_process_stmt (iter, TREE_OPERAND (node, 0), loc,
4144*38fd1498Szrj 			   dirflag, offset, size, safe);
4145*38fd1498Szrj 	return;
4146*38fd1498Szrj       }
4147*38fd1498Szrj       break;
4148*38fd1498Szrj 
4149*38fd1498Szrj     case VAR_DECL:
4150*38fd1498Szrj     case RESULT_DECL:
4151*38fd1498Szrj     case PARM_DECL:
4152*38fd1498Szrj       if (dirflag != integer_one_node
4153*38fd1498Szrj 	  || DECL_REGISTER (node))
4154*38fd1498Szrj 	return;
4155*38fd1498Szrj 
4156*38fd1498Szrj       safe = true;
4157*38fd1498Szrj       addr_first = chkp_build_addr_expr (node);
4158*38fd1498Szrj       break;
4159*38fd1498Szrj 
4160*38fd1498Szrj     default:
4161*38fd1498Szrj       return;
4162*38fd1498Szrj     }
4163*38fd1498Szrj 
4164*38fd1498Szrj   /* If addr_last was not computed then use (addr_first + size - 1)
4165*38fd1498Szrj      expression to compute it.  */
4166*38fd1498Szrj   if (!addr_last)
4167*38fd1498Szrj     {
4168*38fd1498Szrj       addr_last = fold_build_pointer_plus_loc (loc, addr_first, size);
4169*38fd1498Szrj       addr_last = fold_build_pointer_plus_hwi_loc (loc, addr_last, -1);
4170*38fd1498Szrj     }
4171*38fd1498Szrj 
4172*38fd1498Szrj   /* Shift both first_addr and last_addr by access_offs if specified.  */
4173*38fd1498Szrj   if (access_offs)
4174*38fd1498Szrj     {
4175*38fd1498Szrj       addr_first = fold_build_pointer_plus_loc (loc, addr_first, access_offs);
4176*38fd1498Szrj       addr_last = fold_build_pointer_plus_loc (loc, addr_last, access_offs);
4177*38fd1498Szrj     }
4178*38fd1498Szrj 
4179*38fd1498Szrj   if (dirflag == integer_one_node)
4180*38fd1498Szrj     {
4181*38fd1498Szrj       tree base = get_base_address (node);
4182*38fd1498Szrj       if (VAR_P (base) && DECL_HARD_REGISTER (base))
4183*38fd1498Szrj 	reg_store = true;
4184*38fd1498Szrj     }
4185*38fd1498Szrj 
4186*38fd1498Szrj   /* Generate bndcl/bndcu checks if memory access is not safe.  */
4187*38fd1498Szrj   if (!safe)
4188*38fd1498Szrj     {
4189*38fd1498Szrj       gimple_stmt_iterator stmt_iter = *iter;
4190*38fd1498Szrj 
4191*38fd1498Szrj       if (!bounds)
4192*38fd1498Szrj 	bounds = chkp_find_bounds (ptr, iter);
4193*38fd1498Szrj 
4194*38fd1498Szrj       chkp_check_mem_access (addr_first, addr_last, bounds,
4195*38fd1498Szrj 			     stmt_iter, loc, dirflag);
4196*38fd1498Szrj     }
4197*38fd1498Szrj 
4198*38fd1498Szrj   /* We need to store bounds in case pointer is stored.  */
4199*38fd1498Szrj   if (dirflag == integer_one_node
4200*38fd1498Szrj       && !reg_store
4201*38fd1498Szrj       && chkp_type_has_pointer (node_type)
4202*38fd1498Szrj       && flag_chkp_store_bounds)
4203*38fd1498Szrj     {
4204*38fd1498Szrj       gimple *stmt = gsi_stmt (*iter);
4205*38fd1498Szrj       tree rhs1 = gimple_assign_rhs1 (stmt);
4206*38fd1498Szrj       enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
4207*38fd1498Szrj 
4208*38fd1498Szrj       if (get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS)
4209*38fd1498Szrj 	chkp_walk_pointer_assignments (node, rhs1, iter,
4210*38fd1498Szrj 				       chkp_copy_bounds_for_elem);
4211*38fd1498Szrj       else
4212*38fd1498Szrj 	{
4213*38fd1498Szrj 	  bounds = chkp_compute_bounds_for_assignment (NULL_TREE, stmt);
4214*38fd1498Szrj 	  chkp_build_bndstx (addr_first, rhs1, bounds, iter);
4215*38fd1498Szrj 	}
4216*38fd1498Szrj     }
4217*38fd1498Szrj }
4218*38fd1498Szrj 
4219*38fd1498Szrj /* Add code to copy bounds for all pointers copied
4220*38fd1498Szrj    in ASSIGN created during inline of EDGE.  */
4221*38fd1498Szrj void
4222*38fd1498Szrj chkp_copy_bounds_for_assign (gimple *assign, struct cgraph_edge *edge)
4223*38fd1498Szrj {
4224*38fd1498Szrj   tree lhs = gimple_assign_lhs (assign);
4225*38fd1498Szrj   tree rhs = gimple_assign_rhs1 (assign);
4226*38fd1498Szrj   gimple_stmt_iterator iter = gsi_for_stmt (assign);
4227*38fd1498Szrj 
4228*38fd1498Szrj   if (!flag_chkp_store_bounds)
4229*38fd1498Szrj     return;
4230*38fd1498Szrj 
4231*38fd1498Szrj   chkp_walk_pointer_assignments (lhs, rhs, &iter, chkp_copy_bounds_for_elem);
4232*38fd1498Szrj 
4233*38fd1498Szrj   /* We should create edges for all created calls to bndldx and bndstx.  */
4234*38fd1498Szrj   while (gsi_stmt (iter) != assign)
4235*38fd1498Szrj     {
4236*38fd1498Szrj       gimple *stmt = gsi_stmt (iter);
4237*38fd1498Szrj       if (gimple_code (stmt) == GIMPLE_CALL)
4238*38fd1498Szrj 	{
4239*38fd1498Szrj 	  tree fndecl = gimple_call_fndecl (stmt);
4240*38fd1498Szrj 	  struct cgraph_node *callee = cgraph_node::get_create (fndecl);
4241*38fd1498Szrj 
4242*38fd1498Szrj 	  gcc_assert (chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDSTX)
4243*38fd1498Szrj 		      || chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDLDX)
4244*38fd1498Szrj 		      || chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDRET));
4245*38fd1498Szrj 
4246*38fd1498Szrj 	  edge->caller->create_edge (callee, as_a <gcall *> (stmt), edge->count);
4247*38fd1498Szrj 	}
4248*38fd1498Szrj       gsi_prev (&iter);
4249*38fd1498Szrj     }
4250*38fd1498Szrj }
4251*38fd1498Szrj 
4252*38fd1498Szrj /* Some code transformation made during instrumentation pass
4253*38fd1498Szrj    may put code into inconsistent state.  Here we find and fix
4254*38fd1498Szrj    such flaws.  */
4255*38fd1498Szrj void
4256*38fd1498Szrj chkp_fix_cfg ()
4257*38fd1498Szrj {
4258*38fd1498Szrj   basic_block bb;
4259*38fd1498Szrj   gimple_stmt_iterator i;
4260*38fd1498Szrj 
4261*38fd1498Szrj   /* We could insert some code right after stmt which ends bb.
4262*38fd1498Szrj      We wanted to put this code on fallthru edge but did not
4263*38fd1498Szrj      add new edges from the beginning because it may cause new
4264*38fd1498Szrj      phi node creation which may be incorrect due to incomplete
4265*38fd1498Szrj      bound phi nodes.  */
4266*38fd1498Szrj   FOR_ALL_BB_FN (bb, cfun)
4267*38fd1498Szrj     for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
4268*38fd1498Szrj       {
4269*38fd1498Szrj 	gimple *stmt = gsi_stmt (i);
4270*38fd1498Szrj 	gimple_stmt_iterator next = i;
4271*38fd1498Szrj 
4272*38fd1498Szrj 	gsi_next (&next);
4273*38fd1498Szrj 
4274*38fd1498Szrj 	if (stmt_ends_bb_p (stmt)
4275*38fd1498Szrj 	    && !gsi_end_p (next))
4276*38fd1498Szrj 	  {
4277*38fd1498Szrj 	    edge fall = find_fallthru_edge (bb->succs);
4278*38fd1498Szrj 	    basic_block dest = NULL;
4279*38fd1498Szrj 	    int flags = 0;
4280*38fd1498Szrj 
4281*38fd1498Szrj 	    gcc_assert (fall);
4282*38fd1498Szrj 
4283*38fd1498Szrj 	    /* We cannot split abnormal edge.  Therefore we
4284*38fd1498Szrj 	       store its params, make it regular and then
4285*38fd1498Szrj 	       rebuild abnormal edge after split.  */
4286*38fd1498Szrj 	    if (fall->flags & EDGE_ABNORMAL)
4287*38fd1498Szrj 	      {
4288*38fd1498Szrj 		flags = fall->flags & ~EDGE_FALLTHRU;
4289*38fd1498Szrj 		dest = fall->dest;
4290*38fd1498Szrj 
4291*38fd1498Szrj 		fall->flags &= ~EDGE_COMPLEX;
4292*38fd1498Szrj 	      }
4293*38fd1498Szrj 
4294*38fd1498Szrj 	    while (!gsi_end_p (next))
4295*38fd1498Szrj 	      {
4296*38fd1498Szrj 		gimple *next_stmt = gsi_stmt (next);
4297*38fd1498Szrj 		gsi_remove (&next, false);
4298*38fd1498Szrj 		gsi_insert_on_edge (fall, next_stmt);
4299*38fd1498Szrj 	      }
4300*38fd1498Szrj 
4301*38fd1498Szrj 	    gsi_commit_edge_inserts ();
4302*38fd1498Szrj 
4303*38fd1498Szrj 	    /* Re-create abnormal edge.  */
4304*38fd1498Szrj 	    if (dest)
4305*38fd1498Szrj 	      make_edge (bb, dest, flags);
4306*38fd1498Szrj 	  }
4307*38fd1498Szrj       }
4308*38fd1498Szrj }
4309*38fd1498Szrj 
4310*38fd1498Szrj /* Walker callback for chkp_replace_function_pointers.  Replaces
4311*38fd1498Szrj    function pointer in the specified operand with pointer to the
4312*38fd1498Szrj    instrumented function version.  */
4313*38fd1498Szrj static tree
4314*38fd1498Szrj chkp_replace_function_pointer (tree *op, int *walk_subtrees,
4315*38fd1498Szrj 			       void *data ATTRIBUTE_UNUSED)
4316*38fd1498Szrj {
4317*38fd1498Szrj   if (TREE_CODE (*op) == FUNCTION_DECL
4318*38fd1498Szrj       && chkp_instrumentable_p (*op)
4319*38fd1498Szrj       && (DECL_BUILT_IN_CLASS (*op) == NOT_BUILT_IN
4320*38fd1498Szrj 	  /* For builtins we replace pointers only for selected
4321*38fd1498Szrj 	     function and functions having definitions.  */
4322*38fd1498Szrj 	  || (DECL_BUILT_IN_CLASS (*op) == BUILT_IN_NORMAL
4323*38fd1498Szrj 	      && (chkp_instrument_normal_builtin (*op)
4324*38fd1498Szrj 		  || gimple_has_body_p (*op)))))
4325*38fd1498Szrj     {
4326*38fd1498Szrj       struct cgraph_node *node = cgraph_node::get_create (*op);
4327*38fd1498Szrj       struct cgraph_node *clone = NULL;
4328*38fd1498Szrj 
4329*38fd1498Szrj       if (!node->instrumentation_clone)
4330*38fd1498Szrj 	clone = chkp_maybe_create_clone (*op);
4331*38fd1498Szrj 
4332*38fd1498Szrj       if (clone)
4333*38fd1498Szrj 	*op = clone->decl;
4334*38fd1498Szrj       *walk_subtrees = 0;
4335*38fd1498Szrj     }
4336*38fd1498Szrj 
4337*38fd1498Szrj   return NULL;
4338*38fd1498Szrj }
4339*38fd1498Szrj 
4340*38fd1498Szrj /* This function searches for function pointers in statement
4341*38fd1498Szrj    pointed by GSI and replaces them with pointers to instrumented
4342*38fd1498Szrj    function versions.  */
4343*38fd1498Szrj static void
4344*38fd1498Szrj chkp_replace_function_pointers (gimple_stmt_iterator *gsi)
4345*38fd1498Szrj {
4346*38fd1498Szrj   gimple *stmt = gsi_stmt (*gsi);
4347*38fd1498Szrj   /* For calls we want to walk call args only.  */
4348*38fd1498Szrj   if (gimple_code (stmt) == GIMPLE_CALL)
4349*38fd1498Szrj     {
4350*38fd1498Szrj       unsigned i;
4351*38fd1498Szrj       for (i = 0; i < gimple_call_num_args (stmt); i++)
4352*38fd1498Szrj 	walk_tree (gimple_call_arg_ptr (stmt, i),
4353*38fd1498Szrj 		   chkp_replace_function_pointer, NULL, NULL);
4354*38fd1498Szrj     }
4355*38fd1498Szrj   else
4356*38fd1498Szrj     walk_gimple_stmt (gsi, NULL, chkp_replace_function_pointer, NULL);
4357*38fd1498Szrj }
4358*38fd1498Szrj 
4359*38fd1498Szrj /* This function instruments all statements working with memory,
4360*38fd1498Szrj    calls and rets.
4361*38fd1498Szrj 
4362*38fd1498Szrj    It also removes excess statements from static initializers.  */
4363*38fd1498Szrj static void
4364*38fd1498Szrj chkp_instrument_function (void)
4365*38fd1498Szrj {
4366*38fd1498Szrj   basic_block bb, next;
4367*38fd1498Szrj   gimple_stmt_iterator i;
4368*38fd1498Szrj   enum gimple_rhs_class grhs_class;
4369*38fd1498Szrj   bool safe = lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl));
4370*38fd1498Szrj 
4371*38fd1498Szrj   bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
4372*38fd1498Szrj   do
4373*38fd1498Szrj     {
4374*38fd1498Szrj       next = bb->next_bb;
4375*38fd1498Szrj       for (i = gsi_start_bb (bb); !gsi_end_p (i); )
4376*38fd1498Szrj         {
4377*38fd1498Szrj 	  gimple *s = gsi_stmt (i);
4378*38fd1498Szrj 
4379*38fd1498Szrj 	  /* Skip statement marked to not be instrumented.  */
4380*38fd1498Szrj 	  if (chkp_marked_stmt_p (s))
4381*38fd1498Szrj 	    {
4382*38fd1498Szrj 	      gsi_next (&i);
4383*38fd1498Szrj 	      continue;
4384*38fd1498Szrj 	    }
4385*38fd1498Szrj 
4386*38fd1498Szrj 	  chkp_replace_function_pointers (&i);
4387*38fd1498Szrj 
4388*38fd1498Szrj           switch (gimple_code (s))
4389*38fd1498Szrj             {
4390*38fd1498Szrj             case GIMPLE_ASSIGN:
4391*38fd1498Szrj 	      chkp_process_stmt (&i, gimple_assign_lhs (s),
4392*38fd1498Szrj 				 gimple_location (s), integer_one_node,
4393*38fd1498Szrj 				 NULL_TREE, NULL_TREE, safe);
4394*38fd1498Szrj 	      chkp_process_stmt (&i, gimple_assign_rhs1 (s),
4395*38fd1498Szrj 				 gimple_location (s), integer_zero_node,
4396*38fd1498Szrj 				 NULL_TREE, NULL_TREE, safe);
4397*38fd1498Szrj 	      grhs_class = get_gimple_rhs_class (gimple_assign_rhs_code (s));
4398*38fd1498Szrj 	      if (grhs_class == GIMPLE_BINARY_RHS)
4399*38fd1498Szrj 		chkp_process_stmt (&i, gimple_assign_rhs2 (s),
4400*38fd1498Szrj 				   gimple_location (s), integer_zero_node,
4401*38fd1498Szrj 				   NULL_TREE, NULL_TREE, safe);
4402*38fd1498Szrj               break;
4403*38fd1498Szrj 
4404*38fd1498Szrj             case GIMPLE_RETURN:
4405*38fd1498Szrj 	      {
4406*38fd1498Szrj 		greturn *r = as_a <greturn *> (s);
4407*38fd1498Szrj 		if (gimple_return_retval (r) != NULL_TREE)
4408*38fd1498Szrj 		  {
4409*38fd1498Szrj 		    chkp_process_stmt (&i, gimple_return_retval (r),
4410*38fd1498Szrj 				       gimple_location (r),
4411*38fd1498Szrj 				       integer_zero_node,
4412*38fd1498Szrj 				       NULL_TREE, NULL_TREE, safe);
4413*38fd1498Szrj 
4414*38fd1498Szrj 		    /* Additionally we need to add bounds
4415*38fd1498Szrj 		       to return statement.  */
4416*38fd1498Szrj 		    chkp_add_bounds_to_ret_stmt (&i);
4417*38fd1498Szrj 		  }
4418*38fd1498Szrj 	      }
4419*38fd1498Szrj 	      break;
4420*38fd1498Szrj 
4421*38fd1498Szrj 	    case GIMPLE_CALL:
4422*38fd1498Szrj 	      chkp_add_bounds_to_call_stmt (&i);
4423*38fd1498Szrj 	      break;
4424*38fd1498Szrj 
4425*38fd1498Szrj             default:
4426*38fd1498Szrj               ;
4427*38fd1498Szrj             }
4428*38fd1498Szrj 
4429*38fd1498Szrj 	  gsi_next (&i);
4430*38fd1498Szrj 
4431*38fd1498Szrj 	  /* We do not need any actual pointer stores in checker
4432*38fd1498Szrj 	     static initializer.  */
4433*38fd1498Szrj 	  if (lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl))
4434*38fd1498Szrj 	      && gimple_code (s) == GIMPLE_ASSIGN
4435*38fd1498Szrj 	      && gimple_store_p (s))
4436*38fd1498Szrj 	    {
4437*38fd1498Szrj 	      gimple_stmt_iterator del_iter = gsi_for_stmt (s);
4438*38fd1498Szrj 	      gsi_remove (&del_iter, true);
4439*38fd1498Szrj 	      unlink_stmt_vdef (s);
4440*38fd1498Szrj 	      release_defs(s);
4441*38fd1498Szrj 	    }
4442*38fd1498Szrj         }
4443*38fd1498Szrj       bb = next;
4444*38fd1498Szrj     }
4445*38fd1498Szrj   while (bb);
4446*38fd1498Szrj 
4447*38fd1498Szrj   /* Some input params may have bounds and be address taken.  In this case
4448*38fd1498Szrj      we should store incoming bounds into bounds table.  */
4449*38fd1498Szrj   tree arg;
4450*38fd1498Szrj   if (flag_chkp_store_bounds)
4451*38fd1498Szrj     for (arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg))
4452*38fd1498Szrj       if (TREE_ADDRESSABLE (arg))
4453*38fd1498Szrj 	{
4454*38fd1498Szrj 	  if (BOUNDED_P (arg))
4455*38fd1498Szrj 	    {
4456*38fd1498Szrj 	      tree bounds = chkp_get_next_bounds_parm (arg);
4457*38fd1498Szrj 	      tree def_ptr = ssa_default_def (cfun, arg);
4458*38fd1498Szrj 	      gimple_stmt_iterator iter
4459*38fd1498Szrj 		= gsi_start_bb (chkp_get_entry_block ());
4460*38fd1498Szrj 	      chkp_build_bndstx (chkp_build_addr_expr (arg),
4461*38fd1498Szrj 				 def_ptr ? def_ptr : arg,
4462*38fd1498Szrj 				 bounds, &iter);
4463*38fd1498Szrj 
4464*38fd1498Szrj 	      /* Skip bounds arg.  */
4465*38fd1498Szrj 	      arg = TREE_CHAIN (arg);
4466*38fd1498Szrj 	    }
4467*38fd1498Szrj 	  else if (chkp_type_has_pointer (TREE_TYPE (arg)))
4468*38fd1498Szrj 	    {
4469*38fd1498Szrj 	      tree orig_arg = arg;
4470*38fd1498Szrj 	      bitmap slots = BITMAP_ALLOC (NULL);
4471*38fd1498Szrj 	      gimple_stmt_iterator iter
4472*38fd1498Szrj 		= gsi_start_bb (chkp_get_entry_block ());
4473*38fd1498Szrj 	      bitmap_iterator bi;
4474*38fd1498Szrj 	      unsigned bnd_no;
4475*38fd1498Szrj 
4476*38fd1498Szrj 	      chkp_find_bound_slots (TREE_TYPE (arg), slots);
4477*38fd1498Szrj 
4478*38fd1498Szrj 	      EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
4479*38fd1498Szrj 		{
4480*38fd1498Szrj 		  tree bounds = chkp_get_next_bounds_parm (arg);
4481*38fd1498Szrj 		  HOST_WIDE_INT offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT;
4482*38fd1498Szrj 		  tree addr = chkp_build_addr_expr (orig_arg);
4483*38fd1498Szrj 		  tree ptr = build2 (MEM_REF, ptr_type_node, addr,
4484*38fd1498Szrj 				     build_int_cst (ptr_type_node, offs));
4485*38fd1498Szrj 		  chkp_build_bndstx (chkp_build_addr_expr (ptr), ptr,
4486*38fd1498Szrj 				     bounds, &iter);
4487*38fd1498Szrj 
4488*38fd1498Szrj 		  arg = DECL_CHAIN (arg);
4489*38fd1498Szrj 		}
4490*38fd1498Szrj 	      BITMAP_FREE (slots);
4491*38fd1498Szrj 	    }
4492*38fd1498Szrj 	}
4493*38fd1498Szrj }
4494*38fd1498Szrj 
4495*38fd1498Szrj /* Find init/null/copy_ptr_bounds calls and replace them
4496*38fd1498Szrj    with assignments.  It should allow better code
4497*38fd1498Szrj    optimization.  */
4498*38fd1498Szrj 
4499*38fd1498Szrj static void
4500*38fd1498Szrj chkp_remove_useless_builtins ()
4501*38fd1498Szrj {
4502*38fd1498Szrj   basic_block bb;
4503*38fd1498Szrj   gimple_stmt_iterator gsi;
4504*38fd1498Szrj 
4505*38fd1498Szrj   FOR_EACH_BB_FN (bb, cfun)
4506*38fd1498Szrj     {
4507*38fd1498Szrj       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4508*38fd1498Szrj         {
4509*38fd1498Szrj 	  gimple *stmt = gsi_stmt (gsi);
4510*38fd1498Szrj 	  tree fndecl;
4511*38fd1498Szrj 	  enum built_in_function fcode;
4512*38fd1498Szrj 
4513*38fd1498Szrj 	  /* Find builtins returning first arg and replace
4514*38fd1498Szrj 	     them with assignments.  */
4515*38fd1498Szrj 	  if (gimple_code (stmt) == GIMPLE_CALL
4516*38fd1498Szrj 	      && (fndecl = gimple_call_fndecl (stmt))
4517*38fd1498Szrj 	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
4518*38fd1498Szrj 	      && (fcode = DECL_FUNCTION_CODE (fndecl))
4519*38fd1498Szrj 	      && (fcode == BUILT_IN_CHKP_INIT_PTR_BOUNDS
4520*38fd1498Szrj 		  || fcode == BUILT_IN_CHKP_NULL_PTR_BOUNDS
4521*38fd1498Szrj 		  || fcode == BUILT_IN_CHKP_COPY_PTR_BOUNDS
4522*38fd1498Szrj 		  || fcode == BUILT_IN_CHKP_SET_PTR_BOUNDS))
4523*38fd1498Szrj 	    {
4524*38fd1498Szrj 	      tree res = gimple_call_arg (stmt, 0);
4525*38fd1498Szrj 	      update_call_from_tree (&gsi, res);
4526*38fd1498Szrj 	      stmt = gsi_stmt (gsi);
4527*38fd1498Szrj 	      update_stmt (stmt);
4528*38fd1498Szrj 	    }
4529*38fd1498Szrj         }
4530*38fd1498Szrj     }
4531*38fd1498Szrj }
4532*38fd1498Szrj 
4533*38fd1498Szrj /* Initialize pass.  */
4534*38fd1498Szrj static void
4535*38fd1498Szrj chkp_init (void)
4536*38fd1498Szrj {
4537*38fd1498Szrj   basic_block bb;
4538*38fd1498Szrj   gimple_stmt_iterator i;
4539*38fd1498Szrj 
4540*38fd1498Szrj   in_chkp_pass = true;
4541*38fd1498Szrj 
4542*38fd1498Szrj   for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb; bb = bb->next_bb)
4543*38fd1498Szrj     for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i))
4544*38fd1498Szrj       chkp_unmark_stmt (gsi_stmt (i));
4545*38fd1498Szrj 
4546*38fd1498Szrj   chkp_invalid_bounds = new hash_set<tree>;
4547*38fd1498Szrj   chkp_completed_bounds_set = new hash_set<tree>;
4548*38fd1498Szrj   delete chkp_reg_bounds;
4549*38fd1498Szrj   chkp_reg_bounds = new hash_map<tree, tree>;
4550*38fd1498Szrj   delete chkp_bound_vars;
4551*38fd1498Szrj   chkp_bound_vars = new hash_map<tree, tree>;
4552*38fd1498Szrj   chkp_reg_addr_bounds = new hash_map<tree, tree>;
4553*38fd1498Szrj   chkp_incomplete_bounds_map = new hash_map<tree, tree>;
4554*38fd1498Szrj   delete chkp_bounds_map;
4555*38fd1498Szrj   chkp_bounds_map = new hash_map<tree, tree>;
4556*38fd1498Szrj   chkp_abnormal_copies = BITMAP_GGC_ALLOC ();
4557*38fd1498Szrj 
4558*38fd1498Szrj   entry_block = NULL;
4559*38fd1498Szrj   zero_bounds = NULL_TREE;
4560*38fd1498Szrj   none_bounds = NULL_TREE;
4561*38fd1498Szrj   incomplete_bounds = integer_zero_node;
4562*38fd1498Szrj   tmp_var = NULL_TREE;
4563*38fd1498Szrj   size_tmp_var = NULL_TREE;
4564*38fd1498Szrj 
4565*38fd1498Szrj   chkp_uintptr_type = lang_hooks.types.type_for_mode (ptr_mode, true);
4566*38fd1498Szrj 
4567*38fd1498Szrj   /* We create these constant bounds once for each object file.
4568*38fd1498Szrj      These symbols go to comdat section and result in single copy
4569*38fd1498Szrj      of each one in the final binary.  */
4570*38fd1498Szrj   chkp_get_zero_bounds_var ();
4571*38fd1498Szrj   chkp_get_none_bounds_var ();
4572*38fd1498Szrj 
4573*38fd1498Szrj   calculate_dominance_info (CDI_DOMINATORS);
4574*38fd1498Szrj   calculate_dominance_info (CDI_POST_DOMINATORS);
4575*38fd1498Szrj 
4576*38fd1498Szrj   bitmap_obstack_initialize (NULL);
4577*38fd1498Szrj }
4578*38fd1498Szrj 
4579*38fd1498Szrj /* Finalize instrumentation pass.  */
4580*38fd1498Szrj static void
4581*38fd1498Szrj chkp_fini (void)
4582*38fd1498Szrj {
4583*38fd1498Szrj   in_chkp_pass = false;
4584*38fd1498Szrj 
4585*38fd1498Szrj   delete chkp_invalid_bounds;
4586*38fd1498Szrj   delete chkp_completed_bounds_set;
4587*38fd1498Szrj   delete chkp_reg_addr_bounds;
4588*38fd1498Szrj   delete chkp_incomplete_bounds_map;
4589*38fd1498Szrj 
4590*38fd1498Szrj   free_dominance_info (CDI_DOMINATORS);
4591*38fd1498Szrj   free_dominance_info (CDI_POST_DOMINATORS);
4592*38fd1498Szrj 
4593*38fd1498Szrj   bitmap_obstack_release (NULL);
4594*38fd1498Szrj 
4595*38fd1498Szrj   entry_block = NULL;
4596*38fd1498Szrj   zero_bounds = NULL_TREE;
4597*38fd1498Szrj   none_bounds = NULL_TREE;
4598*38fd1498Szrj }
4599*38fd1498Szrj 
4600*38fd1498Szrj /* Main instrumentation pass function.  */
4601*38fd1498Szrj static unsigned int
4602*38fd1498Szrj chkp_execute (void)
4603*38fd1498Szrj {
4604*38fd1498Szrj   chkp_init ();
4605*38fd1498Szrj 
4606*38fd1498Szrj   chkp_instrument_function ();
4607*38fd1498Szrj 
4608*38fd1498Szrj   chkp_remove_useless_builtins ();
4609*38fd1498Szrj 
4610*38fd1498Szrj   chkp_function_mark_instrumented (cfun->decl);
4611*38fd1498Szrj 
4612*38fd1498Szrj   chkp_fix_cfg ();
4613*38fd1498Szrj 
4614*38fd1498Szrj   chkp_fini ();
4615*38fd1498Szrj 
4616*38fd1498Szrj   return 0;
4617*38fd1498Szrj }
4618*38fd1498Szrj 
4619*38fd1498Szrj /* Instrumentation pass gate.  */
4620*38fd1498Szrj static bool
4621*38fd1498Szrj chkp_gate (void)
4622*38fd1498Szrj {
4623*38fd1498Szrj   cgraph_node *node = cgraph_node::get (cfun->decl);
4624*38fd1498Szrj   return ((node != NULL
4625*38fd1498Szrj 	   && node->instrumentation_clone)
4626*38fd1498Szrj 	   || lookup_attribute ("chkp ctor", DECL_ATTRIBUTES (cfun->decl)));
4627*38fd1498Szrj }
4628*38fd1498Szrj 
4629*38fd1498Szrj namespace {
4630*38fd1498Szrj 
4631*38fd1498Szrj const pass_data pass_data_chkp =
4632*38fd1498Szrj {
4633*38fd1498Szrj   GIMPLE_PASS, /* type */
4634*38fd1498Szrj   "chkp", /* name */
4635*38fd1498Szrj   OPTGROUP_NONE, /* optinfo_flags */
4636*38fd1498Szrj   TV_NONE, /* tv_id */
4637*38fd1498Szrj   PROP_ssa | PROP_cfg, /* properties_required */
4638*38fd1498Szrj   0, /* properties_provided */
4639*38fd1498Szrj   0, /* properties_destroyed */
4640*38fd1498Szrj   0, /* todo_flags_start */
4641*38fd1498Szrj   TODO_verify_il
4642*38fd1498Szrj   | TODO_update_ssa /* todo_flags_finish */
4643*38fd1498Szrj };
4644*38fd1498Szrj 
4645*38fd1498Szrj class pass_chkp : public gimple_opt_pass
4646*38fd1498Szrj {
4647*38fd1498Szrj public:
4648*38fd1498Szrj   pass_chkp (gcc::context *ctxt)
4649*38fd1498Szrj     : gimple_opt_pass (pass_data_chkp, ctxt)
4650*38fd1498Szrj   {}
4651*38fd1498Szrj 
4652*38fd1498Szrj   /* opt_pass methods: */
4653*38fd1498Szrj   virtual opt_pass * clone ()
4654*38fd1498Szrj     {
4655*38fd1498Szrj       return new pass_chkp (m_ctxt);
4656*38fd1498Szrj     }
4657*38fd1498Szrj 
4658*38fd1498Szrj   virtual bool gate (function *)
4659*38fd1498Szrj     {
4660*38fd1498Szrj       return chkp_gate ();
4661*38fd1498Szrj     }
4662*38fd1498Szrj 
4663*38fd1498Szrj   virtual unsigned int execute (function *)
4664*38fd1498Szrj     {
4665*38fd1498Szrj       return chkp_execute ();
4666*38fd1498Szrj     }
4667*38fd1498Szrj 
4668*38fd1498Szrj }; // class pass_chkp
4669*38fd1498Szrj 
4670*38fd1498Szrj } // anon namespace
4671*38fd1498Szrj 
4672*38fd1498Szrj gimple_opt_pass *
4673*38fd1498Szrj make_pass_chkp (gcc::context *ctxt)
4674*38fd1498Szrj {
4675*38fd1498Szrj   return new pass_chkp (ctxt);
4676*38fd1498Szrj }
4677*38fd1498Szrj 
4678*38fd1498Szrj #include "gt-tree-chkp.h"
4679