]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/ipa-chkp.c
genattrtab.c (write_header): Include hash-set.h...
[thirdparty/gcc.git] / gcc / ipa-chkp.c
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "hash-set.h"
25 #include "machmode.h"
26 #include "vec.h"
27 #include "double-int.h"
28 #include "input.h"
29 #include "alias.h"
30 #include "symtab.h"
31 #include "options.h"
32 #include "wide-int.h"
33 #include "inchash.h"
34 #include "tree.h"
35 #include "fold-const.h"
36 #include "stor-layout.h"
37 #include "tree-pass.h"
38 #include "stringpool.h"
39 #include "bitmap.h"
40 #include "gimple-expr.h"
41 #include "tm.h"
42 #include "hard-reg-set.h"
43 #include "function.h"
44 #include "is-a.h"
45 #include "tree-ssa-alias.h"
46 #include "predict.h"
47 #include "basic-block.h"
48 #include "gimple.h"
49 #include "ipa-ref.h"
50 #include "lto-streamer.h"
51 #include "cgraph.h"
52 #include "tree-chkp.h"
53 #include "ipa-chkp.h"
54
55 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
56
57 In instrumented code each pointer is provided with bounds. For input
58 pointer parameters it means we also have bounds passed. For calls it
59 means we have additional bounds arguments for pointer arguments.
60
61 To have all IPA optimizations working correctly we have to express
62 dataflow between passed and received bounds explicitly via additional
63 entries in function declaration arguments list and in function type.
64 Since we may have both instrumented and not instrumented code at the
65 same time, we cannot replace all original functions with their
66 instrumented variants. Therefore we create clones (versions) instead.
67
68 Instrumentation clones creation is a separate IPA pass which is a part
69 of early local passes. Clones are created after SSA is built (because
70 instrumentation pass works on SSA) and before any transformations
71 which may change pointer flow and therefore lead to incorrect code
72 instrumentation (possibly causing false bounds check failures).
73
74 Instrumentation clones have pointer bounds arguments added right after
75 pointer arguments. Clones have assembler name of the original
76 function with suffix added. New assembler name is in transparent
77 alias chain with the original name. Thus we expect all calls to the
78 original and instrumented functions look similar in assembler.
79
80 During instrumentation versioning pass we create instrumented versions
81 of all function with body and also for all their aliases and thunks.
82 Clones for functions with no body are created on demand (usually
83 during call instrumentation).
84
85 Original and instrumented function nodes are connected with IPA
86 reference IPA_REF_CHKP. It is mostly done to have reachability
87 analysis working correctly. We may have no references to the
88 instrumented function in the code but it still should be counted
89 as reachable if the original function is reachable.
90
91 When original function bodies are not needed anymore we release
92 them and transform functions into a special kind of thunks. Each
93 thunk has a call edge to the instrumented version. These thunks
94 help to keep externally visible instrumented functions visible
95 when linker resolution files are used. Linker has no info about
96 connection between original and instrumented function and
97 therefore we may wrongly decide (due to difference in assembler
98 names) that instrumented function version is local and can be
99 removed. */
100
101 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
102
103 /* Build a clone of FNDECL with a modified name. */
104
105 static tree
106 chkp_build_instrumented_fndecl (tree fndecl)
107 {
108 tree new_decl = copy_node (fndecl);
109 tree new_name;
110 std::string s;
111
112 /* called_as_built_in checks DECL_NAME to identify calls to
113 builtins. We want instrumented calls to builtins to be
114 recognized by called_as_built_in. Therefore use original
115 DECL_NAME for cloning with no prefixes. */
116 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
117 s += ".chkp";
118 DECL_NAME (new_decl) = get_identifier (s.c_str ());
119
120 /* References to the original and to the instrumented version
121 should look the same in the output assembly. And we cannot
122 use the same assembler name for the instrumented version
123 because it conflicts with decl merging algorithms in LTO.
124 Achieve the result by using transparent alias name for the
125 instrumented version. */
126 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
127 s += ".chkp";
128 new_name = get_identifier (s.c_str ());
129 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
130 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
131 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
132
133 /* For functions with body versioning will make a copy of arguments.
134 For functions with no body we need to do it here. */
135 if (!gimple_has_body_p (fndecl))
136 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
137
138 /* We are going to modify attributes list and therefore should
139 make own copy. */
140 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
141
142 /* Change builtin function code. */
143 if (DECL_BUILT_IN (new_decl))
144 {
145 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
146 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
147 DECL_FUNCTION_CODE (new_decl)
148 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
149 + BEGIN_CHKP_BUILTINS + 1);
150 }
151
152 return new_decl;
153 }
154
155
156 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
157 Integer operands are replaced with values according to
158 INDEXES map having LEN elements. For operands out of len
159 we just add DELTA. */
160
161 static void
162 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
163 unsigned *indexes, int len, int delta)
164 {
165 tree attr = lookup_attribute (attr_name, attrs);
166 tree op;
167
168 if (!attr)
169 return;
170
171 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
172 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
173 {
174 int idx;
175
176 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
177 continue;
178
179 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
180
181 /* If idx exceeds indexes length then we just
182 keep it at the same distance from the last
183 known arg. */
184 if (idx > len)
185 idx += delta;
186 else
187 idx = indexes[idx - 1] + 1;
188 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
189 }
190 }
191
192 /* Make a copy of function type ORIG_TYPE adding pointer
193 bounds as additional arguments. */
194
195 tree
196 chkp_copy_function_type_adding_bounds (tree orig_type)
197 {
198 tree type;
199 tree arg_type, attrs, t;
200 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
201 unsigned *indexes = XALLOCAVEC (unsigned, len);
202 unsigned idx = 0, new_idx = 0;
203
204 for (arg_type = TYPE_ARG_TYPES (orig_type);
205 arg_type;
206 arg_type = TREE_CHAIN (arg_type))
207 if (TREE_VALUE (arg_type) == void_type_node)
208 continue;
209 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
210 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
211 TREE_VALUE (arg_type), true)
212 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
213 break;
214
215 /* We may use original type if there are no bounds passed. */
216 if (!arg_type)
217 return orig_type;
218
219 type = copy_node (orig_type);
220 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
221
222 for (arg_type = TYPE_ARG_TYPES (type);
223 arg_type;
224 arg_type = TREE_CHAIN (arg_type))
225 {
226 indexes[idx++] = new_idx++;
227
228 /* pass_by_reference returns 1 for void type,
229 so check for it first. */
230 if (TREE_VALUE (arg_type) == void_type_node)
231 continue;
232 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
233 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
234 TREE_VALUE (arg_type), true))
235 {
236 tree new_type = build_tree_list (NULL_TREE,
237 pointer_bounds_type_node);
238 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
239 TREE_CHAIN (arg_type) = new_type;
240
241 arg_type = TREE_CHAIN (arg_type);
242 new_idx++;
243 }
244 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
245 {
246 bitmap slots = BITMAP_ALLOC (NULL);
247 bitmap_iterator bi;
248 unsigned bnd_no;
249
250 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
251
252 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
253 {
254 tree new_type = build_tree_list (NULL_TREE,
255 pointer_bounds_type_node);
256 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
257 TREE_CHAIN (arg_type) = new_type;
258
259 arg_type = TREE_CHAIN (arg_type);
260 new_idx++;
261 }
262 BITMAP_FREE (slots);
263 }
264 }
265
266 /* If function type has attribute with arg indexes then
267 we have to copy it fixing attribute ops. Map for
268 fixing is in indexes array. */
269 attrs = TYPE_ATTRIBUTES (type);
270 if (lookup_attribute ("nonnull", attrs)
271 || lookup_attribute ("format", attrs)
272 || lookup_attribute ("format_arg", attrs))
273 {
274 int delta = new_idx - len;
275 attrs = copy_list (TYPE_ATTRIBUTES (type));
276 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
277 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
278 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
279 TYPE_ATTRIBUTES (type) = attrs;
280 }
281
282 t = TYPE_MAIN_VARIANT (orig_type);
283 if (orig_type != t)
284 {
285 TYPE_MAIN_VARIANT (type) = t;
286 TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
287 TYPE_NEXT_VARIANT (t) = type;
288 }
289 else
290 {
291 TYPE_MAIN_VARIANT (type) = type;
292 TYPE_NEXT_VARIANT (type) = NULL;
293 }
294
295
296 return type;
297 }
298
299 /* For given function FNDECL add bounds arguments to arguments
300 list. */
301
302 static void
303 chkp_add_bounds_params_to_function (tree fndecl)
304 {
305 tree arg;
306
307 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
308 if (BOUNDED_P (arg))
309 {
310 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
311 tree new_arg;
312
313 if (DECL_NAME (arg))
314 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
315 else
316 {
317 char uid[25];
318 snprintf (uid, 25, "D.%u", DECL_UID (arg));
319 new_name += uid;
320 }
321
322 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
323 get_identifier (new_name.c_str ()),
324 pointer_bounds_type_node);
325 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
326 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
327 DECL_ARTIFICIAL (new_arg) = 1;
328 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
329 DECL_CHAIN (arg) = new_arg;
330
331 arg = DECL_CHAIN (arg);
332
333 }
334 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
335 {
336 tree orig_arg = arg;
337 bitmap slots = BITMAP_ALLOC (NULL);
338 bitmap_iterator bi;
339 unsigned bnd_no;
340
341 chkp_find_bound_slots (TREE_TYPE (arg), slots);
342
343 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
344 {
345 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
346 tree new_arg;
347 char offs[25];
348
349 if (DECL_NAME (orig_arg))
350 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
351 else
352 {
353 snprintf (offs, 25, "D.%u", DECL_UID (arg));
354 new_name += offs;
355 }
356 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
357
358 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
359 PARM_DECL,
360 get_identifier (new_name.c_str ()),
361 pointer_bounds_type_node);
362 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
363 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
364 DECL_ARTIFICIAL (new_arg) = 1;
365 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
366 DECL_CHAIN (arg) = new_arg;
367
368 arg = DECL_CHAIN (arg);
369 }
370 BITMAP_FREE (slots);
371 }
372
373 TREE_TYPE (fndecl) =
374 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
375 }
376
377 /* Return an instrumentation clone for builtin function
378 FNDECL. Create one if needed. */
379
380 tree
381 chkp_maybe_clone_builtin_fndecl (tree fndecl)
382 {
383 tree clone;
384 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
385
386 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
387 && fcode < BEGIN_CHKP_BUILTINS);
388
389 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
390 clone = builtin_decl_explicit (fcode);
391 if (clone)
392 return clone;
393
394 clone = chkp_build_instrumented_fndecl (fndecl);
395 chkp_add_bounds_params_to_function (clone);
396
397 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
398
399 set_builtin_decl (fcode, clone, false);
400
401 return clone;
402 }
403
404 /* Return clone created for instrumentation of NODE or NULL. */
405
406 cgraph_node *
407 chkp_maybe_create_clone (tree fndecl)
408 {
409 cgraph_node *node = cgraph_node::get_create (fndecl);
410 cgraph_node *clone = node->instrumented_version;
411
412 gcc_assert (!node->instrumentation_clone);
413
414 if (DECL_BUILT_IN (fndecl)
415 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
416 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
417 return NULL;
418
419 clone = node->instrumented_version;
420
421 /* Some instrumented builtin function calls may be optimized and
422 cgraph nodes may be removed as unreachable. Later optimizations
423 may generate new calls to removed functions and in this case
424 we have to recreate cgraph node. FUNCTION_DECL for instrumented
425 builtin still exists and should be reused in such case. */
426 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
427 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
428 && !clone)
429 {
430 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
431 tree new_decl;
432
433 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
434 new_decl = builtin_decl_explicit (fncode);
435
436 /* We've actually already created an instrumented clone once.
437 Restore it. */
438 if (new_decl)
439 {
440 clone = cgraph_node::get (new_decl);
441
442 if (!clone)
443 {
444 gcc_assert (!gimple_has_body_p (fndecl));
445 clone = cgraph_node::get_create (new_decl);
446 clone->externally_visible = node->externally_visible;
447 clone->local = node->local;
448 clone->address_taken = node->address_taken;
449 clone->thunk = node->thunk;
450 clone->alias = node->alias;
451 clone->weakref = node->weakref;
452 clone->cpp_implicit_alias = node->cpp_implicit_alias;
453 clone->orig_decl = fndecl;
454 clone->instrumentation_clone = true;
455 }
456
457 clone->instrumented_version = node;
458 node->instrumented_version = clone;
459 }
460 }
461
462 if (!clone)
463 {
464 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
465 struct cgraph_edge *e;
466 struct ipa_ref *ref;
467 int i;
468
469 clone = node->create_version_clone (new_decl, vNULL, NULL);
470 clone->externally_visible = node->externally_visible;
471 clone->local = node->local;
472 clone->address_taken = node->address_taken;
473 clone->thunk = node->thunk;
474 clone->alias = node->alias;
475 clone->weakref = node->weakref;
476 clone->cpp_implicit_alias = node->cpp_implicit_alias;
477 clone->instrumented_version = node;
478 clone->orig_decl = fndecl;
479 clone->instrumentation_clone = true;
480 node->instrumented_version = clone;
481
482 if (gimple_has_body_p (fndecl))
483 {
484 /* If function will not be instrumented, then it's instrumented
485 version is a thunk for the original. */
486 if (lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
487 || (flag_chkp_instrument_marked_only
488 && !lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl))))
489 {
490 clone->thunk.thunk_p = true;
491 clone->thunk.add_pointer_bounds_args = true;
492 clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
493 }
494 else
495 {
496 tree_function_versioning (fndecl, new_decl, NULL, false,
497 NULL, false, NULL, NULL);
498 clone->lowered = true;
499 }
500 }
501
502 /* New params are inserted after versioning because it
503 actually copies args list from the original decl. */
504 chkp_add_bounds_params_to_function (new_decl);
505
506 /* Remember builtin fndecl. */
507 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
508 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
509 {
510 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
511 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
512 clone->decl, false);
513 }
514
515 /* Clones have the same comdat group as originals. */
516 if (node->same_comdat_group
517 || DECL_ONE_ONLY (node->decl))
518 clone->add_to_same_comdat_group (node);
519
520 if (gimple_has_body_p (fndecl))
521 symtab->call_cgraph_insertion_hooks (clone);
522
523 /* Clone all aliases. */
524 for (i = 0; node->iterate_referring (i, ref); i++)
525 if (ref->use == IPA_REF_ALIAS)
526 {
527 struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
528 struct cgraph_node *chkp_alias
529 = chkp_maybe_create_clone (alias->decl);
530 chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
531 }
532
533 /* Clone all thunks. */
534 for (e = node->callers; e; e = e->next_caller)
535 if (e->caller->thunk.thunk_p)
536 {
537 struct cgraph_node *thunk
538 = chkp_maybe_create_clone (e->caller->decl);
539 /* Redirect thunk clone edge to the node clone. */
540 thunk->callees->redirect_callee (clone);
541 }
542
543 /* For aliases and thunks we should make sure target is cloned
544 to have proper references and edges. */
545 if (node->thunk.thunk_p)
546 chkp_maybe_create_clone (node->callees->callee->decl);
547 else if (node->alias)
548 {
549 struct cgraph_node *target;
550
551 ref = node->ref_list.first_reference ();
552 if (ref)
553 chkp_maybe_create_clone (ref->referred->decl);
554
555 if (node->alias_target)
556 {
557 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
558 {
559 target = chkp_maybe_create_clone (node->alias_target);
560 clone->alias_target = target->decl;
561 }
562 else
563 clone->alias_target = node->alias_target;
564 }
565 }
566
567 /* Add IPA reference. It's main role is to keep instrumented
568 version reachable while original node is reachable. */
569 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
570 }
571
572 return clone;
573 }
574
575 /* Create clone for all functions to be instrumented. */
576
577 static unsigned int
578 chkp_versioning (void)
579 {
580 struct cgraph_node *node;
581
582 bitmap_obstack_initialize (NULL);
583
584 FOR_EACH_DEFINED_FUNCTION (node)
585 {
586 if (!node->instrumentation_clone
587 && !node->instrumented_version
588 && !node->alias
589 && !node->thunk.thunk_p
590 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl))
591 && (!flag_chkp_instrument_marked_only
592 || lookup_attribute ("bnd_instrument",
593 DECL_ATTRIBUTES (node->decl)))
594 && (!DECL_BUILT_IN (node->decl)
595 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
596 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
597 chkp_maybe_create_clone (node->decl);
598 }
599
600 /* Mark all aliases and thunks of functions with no instrumented
601 version as legacy function. */
602 FOR_EACH_DEFINED_FUNCTION (node)
603 {
604 if (!node->instrumentation_clone
605 && !node->instrumented_version
606 && (node->alias || node->thunk.thunk_p)
607 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
608 DECL_ATTRIBUTES (node->decl)
609 = tree_cons (get_identifier ("bnd_legacy"), NULL,
610 DECL_ATTRIBUTES (node->decl));
611 }
612
613 bitmap_obstack_release (NULL);
614
615 return 0;
616 }
617
618 /* In this pass we remove bodies of functions having
619 instrumented version. Functions with removed bodies
620 become a special kind of thunks to provide a connection
621 between calls to the original version and instrumented
622 function. */
623
624 static unsigned int
625 chkp_produce_thunks (void)
626 {
627 struct cgraph_node *node;
628
629 FOR_EACH_DEFINED_FUNCTION (node)
630 {
631 if (!node->instrumentation_clone
632 && node->instrumented_version
633 && gimple_has_body_p (node->decl)
634 && gimple_has_body_p (node->instrumented_version->decl))
635 {
636 node->release_body ();
637 node->remove_callees ();
638 node->remove_all_references ();
639
640 node->thunk.thunk_p = true;
641 node->thunk.add_pointer_bounds_args = true;
642 node->create_edge (node->instrumented_version, NULL,
643 0, CGRAPH_FREQ_BASE);
644 node->create_reference (node->instrumented_version,
645 IPA_REF_CHKP, NULL);
646 }
647 }
648
649 /* Mark instrumentation clones created for aliases and thunks
650 as insttrumented so they could be removed as unreachable
651 now. */
652 FOR_EACH_DEFINED_FUNCTION (node)
653 {
654 if (node->instrumentation_clone
655 && (node->alias || node->thunk.thunk_p)
656 && !chkp_function_instrumented_p (node->decl))
657 chkp_function_mark_instrumented (node->decl);
658 }
659
660 return TODO_remove_functions;
661 }
662
663 const pass_data pass_data_ipa_chkp_versioning =
664 {
665 SIMPLE_IPA_PASS, /* type */
666 "chkp_versioning", /* name */
667 OPTGROUP_NONE, /* optinfo_flags */
668 TV_NONE, /* tv_id */
669 0, /* properties_required */
670 0, /* properties_provided */
671 0, /* properties_destroyed */
672 0, /* todo_flags_start */
673 0 /* todo_flags_finish */
674 };
675
676 const pass_data pass_data_ipa_chkp_produce_thunks =
677 {
678 SIMPLE_IPA_PASS, /* type */
679 "chkp_cleanup", /* name */
680 OPTGROUP_NONE, /* optinfo_flags */
681 TV_NONE, /* tv_id */
682 0, /* properties_required */
683 0, /* properties_provided */
684 0, /* properties_destroyed */
685 0, /* todo_flags_start */
686 0 /* todo_flags_finish */
687 };
688
689 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
690 {
691 public:
692 pass_ipa_chkp_versioning (gcc::context *ctxt)
693 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
694 {}
695
696 /* opt_pass methods: */
697 virtual opt_pass * clone ()
698 {
699 return new pass_ipa_chkp_versioning (m_ctxt);
700 }
701
702 virtual bool gate (function *)
703 {
704 return flag_check_pointer_bounds;
705 }
706
707 virtual unsigned int execute (function *)
708 {
709 return chkp_versioning ();
710 }
711
712 }; // class pass_ipa_chkp_versioning
713
714 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
715 {
716 public:
717 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
718 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
719 {}
720
721 /* opt_pass methods: */
722 virtual opt_pass * clone ()
723 {
724 return new pass_ipa_chkp_produce_thunks (m_ctxt);
725 }
726
727 virtual bool gate (function *)
728 {
729 return flag_check_pointer_bounds;
730 }
731
732 virtual unsigned int execute (function *)
733 {
734 return chkp_produce_thunks ();
735 }
736
737 }; // class pass_chkp_produce_thunks
738
739 simple_ipa_opt_pass *
740 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
741 {
742 return new pass_ipa_chkp_versioning (ctxt);
743 }
744
745 simple_ipa_opt_pass *
746 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
747 {
748 return new pass_ipa_chkp_produce_thunks (ctxt);
749 }