/cp
[official-gcc.git] / gcc / ipa-chkp.c
blob67cb7d51478aec7a3993a99b459552274ffc100c
1 /* Pointer Bounds Checker IPA passes.
2 Copyright (C) 2014-2015 Free Software Foundation, Inc.
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
5 This file is part of GCC.
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.
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.
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/>. */
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 "tree-inline.h"
54 #include "ipa-chkp.h"
56 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
58 In instrumented code each pointer is provided with bounds. For input
59 pointer parameters it means we also have bounds passed. For calls it
60 means we have additional bounds arguments for pointer arguments.
62 To have all IPA optimizations working correctly we have to express
63 dataflow between passed and received bounds explicitly via additional
64 entries in function declaration arguments list and in function type.
65 Since we may have both instrumented and not instrumented code at the
66 same time, we cannot replace all original functions with their
67 instrumented variants. Therefore we create clones (versions) instead.
69 Instrumentation clones creation is a separate IPA pass which is a part
70 of early local passes. Clones are created after SSA is built (because
71 instrumentation pass works on SSA) and before any transformations
72 which may change pointer flow and therefore lead to incorrect code
73 instrumentation (possibly causing false bounds check failures).
75 Instrumentation clones have pointer bounds arguments added right after
76 pointer arguments. Clones have assembler name of the original
77 function with suffix added. New assembler name is in transparent
78 alias chain with the original name. Thus we expect all calls to the
79 original and instrumented functions look similar in assembler.
81 During instrumentation versioning pass we create instrumented versions
82 of all function with body and also for all their aliases and thunks.
83 Clones for functions with no body are created on demand (usually
84 during call instrumentation).
86 Original and instrumented function nodes are connected with IPA
87 reference IPA_REF_CHKP. It is mostly done to have reachability
88 analysis working correctly. We may have no references to the
89 instrumented function in the code but it still should be counted
90 as reachable if the original function is reachable.
92 When original function bodies are not needed anymore we release
93 them and transform functions into a special kind of thunks. Each
94 thunk has a call edge to the instrumented version. These thunks
95 help to keep externally visible instrumented functions visible
96 when linker resolution files are used. Linker has no info about
97 connection between original and instrumented function and
98 therefore we may wrongly decide (due to difference in assembler
99 names) that instrumented function version is local and can be
100 removed. */
102 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
104 /* Build a clone of FNDECL with a modified name. */
106 static tree
107 chkp_build_instrumented_fndecl (tree fndecl)
109 tree new_decl = copy_node (fndecl);
110 tree new_name;
111 std::string s;
113 /* called_as_built_in checks DECL_NAME to identify calls to
114 builtins. We want instrumented calls to builtins to be
115 recognized by called_as_built_in. Therefore use original
116 DECL_NAME for cloning with no prefixes. */
117 s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
118 s += ".chkp";
119 DECL_NAME (new_decl) = get_identifier (s.c_str ());
121 /* References to the original and to the instrumented version
122 should look the same in the output assembly. And we cannot
123 use the same assembler name for the instrumented version
124 because it conflicts with decl merging algorithms in LTO.
125 Achieve the result by using transparent alias name for the
126 instrumented version. */
127 s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
128 s += ".chkp";
129 new_name = get_identifier (s.c_str ());
130 IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
131 TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
132 SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
134 /* For functions with body versioning will make a copy of arguments.
135 For functions with no body we need to do it here. */
136 if (!gimple_has_body_p (fndecl))
137 DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
139 /* We are going to modify attributes list and therefore should
140 make own copy. */
141 DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
143 /* Change builtin function code. */
144 if (DECL_BUILT_IN (new_decl))
146 gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
147 gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
148 DECL_FUNCTION_CODE (new_decl)
149 = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
150 + BEGIN_CHKP_BUILTINS + 1);
153 return new_decl;
157 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
158 Integer operands are replaced with values according to
159 INDEXES map having LEN elements. For operands out of len
160 we just add DELTA. */
162 static void
163 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
164 unsigned *indexes, int len, int delta)
166 tree attr = lookup_attribute (attr_name, attrs);
167 tree op;
169 if (!attr)
170 return;
172 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
173 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
175 int idx;
177 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
178 continue;
180 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
182 /* If idx exceeds indexes length then we just
183 keep it at the same distance from the last
184 known arg. */
185 if (idx > len)
186 idx += delta;
187 else
188 idx = indexes[idx - 1] + 1;
189 TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
193 /* Make a copy of function type ORIG_TYPE adding pointer
194 bounds as additional arguments. */
196 tree
197 chkp_copy_function_type_adding_bounds (tree orig_type)
199 tree type;
200 tree arg_type, attrs, t;
201 unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
202 unsigned *indexes = XALLOCAVEC (unsigned, len);
203 unsigned idx = 0, new_idx = 0;
205 for (arg_type = TYPE_ARG_TYPES (orig_type);
206 arg_type;
207 arg_type = TREE_CHAIN (arg_type))
208 if (TREE_VALUE (arg_type) == void_type_node)
209 continue;
210 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
211 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
212 TREE_VALUE (arg_type), true)
213 || chkp_type_has_pointer (TREE_VALUE (arg_type)))
214 break;
216 /* We may use original type if there are no bounds passed. */
217 if (!arg_type)
218 return orig_type;
220 type = copy_node (orig_type);
221 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
223 for (arg_type = TYPE_ARG_TYPES (type);
224 arg_type;
225 arg_type = TREE_CHAIN (arg_type))
227 indexes[idx++] = new_idx++;
229 /* pass_by_reference returns 1 for void type,
230 so check for it first. */
231 if (TREE_VALUE (arg_type) == void_type_node)
232 continue;
233 else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
234 || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
235 TREE_VALUE (arg_type), true))
237 tree new_type = build_tree_list (NULL_TREE,
238 pointer_bounds_type_node);
239 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
240 TREE_CHAIN (arg_type) = new_type;
242 arg_type = TREE_CHAIN (arg_type);
243 new_idx++;
245 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
247 bitmap slots = BITMAP_ALLOC (NULL);
248 bitmap_iterator bi;
249 unsigned bnd_no;
251 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
253 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
255 tree new_type = build_tree_list (NULL_TREE,
256 pointer_bounds_type_node);
257 TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
258 TREE_CHAIN (arg_type) = new_type;
260 arg_type = TREE_CHAIN (arg_type);
261 new_idx++;
263 BITMAP_FREE (slots);
267 /* If function type has attribute with arg indexes then
268 we have to copy it fixing attribute ops. Map for
269 fixing is in indexes array. */
270 attrs = TYPE_ATTRIBUTES (type);
271 if (lookup_attribute ("nonnull", attrs)
272 || lookup_attribute ("format", attrs)
273 || lookup_attribute ("format_arg", attrs))
275 int delta = new_idx - len;
276 attrs = copy_list (TYPE_ATTRIBUTES (type));
277 chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
278 chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
279 chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
280 TYPE_ATTRIBUTES (type) = attrs;
283 t = TYPE_MAIN_VARIANT (orig_type);
284 if (orig_type != t)
286 TYPE_MAIN_VARIANT (type) = t;
287 TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
288 TYPE_NEXT_VARIANT (t) = type;
290 else
292 TYPE_MAIN_VARIANT (type) = type;
293 TYPE_NEXT_VARIANT (type) = NULL;
297 return type;
300 /* For given function FNDECL add bounds arguments to arguments
301 list. */
303 static void
304 chkp_add_bounds_params_to_function (tree fndecl)
306 tree arg;
308 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
309 if (BOUNDED_P (arg))
311 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
312 tree new_arg;
314 if (DECL_NAME (arg))
315 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
316 else
318 char uid[25];
319 snprintf (uid, 25, "D.%u", DECL_UID (arg));
320 new_name += uid;
323 new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
324 get_identifier (new_name.c_str ()),
325 pointer_bounds_type_node);
326 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
327 DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
328 DECL_ARTIFICIAL (new_arg) = 1;
329 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
330 DECL_CHAIN (arg) = new_arg;
332 arg = DECL_CHAIN (arg);
335 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
337 tree orig_arg = arg;
338 bitmap slots = BITMAP_ALLOC (NULL);
339 bitmap_iterator bi;
340 unsigned bnd_no;
342 chkp_find_bound_slots (TREE_TYPE (arg), slots);
344 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
346 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
347 tree new_arg;
348 char offs[25];
350 if (DECL_NAME (orig_arg))
351 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
352 else
354 snprintf (offs, 25, "D.%u", DECL_UID (arg));
355 new_name += offs;
357 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
359 new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
360 PARM_DECL,
361 get_identifier (new_name.c_str ()),
362 pointer_bounds_type_node);
363 DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
364 DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
365 DECL_ARTIFICIAL (new_arg) = 1;
366 DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
367 DECL_CHAIN (arg) = new_arg;
369 arg = DECL_CHAIN (arg);
371 BITMAP_FREE (slots);
374 TREE_TYPE (fndecl) =
375 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
378 /* Return an instrumentation clone for builtin function
379 FNDECL. Create one if needed. */
381 tree
382 chkp_maybe_clone_builtin_fndecl (tree fndecl)
384 tree clone;
385 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
387 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
388 && fcode < BEGIN_CHKP_BUILTINS);
390 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
391 clone = builtin_decl_explicit (fcode);
392 if (clone)
393 return clone;
395 clone = chkp_build_instrumented_fndecl (fndecl);
396 chkp_add_bounds_params_to_function (clone);
398 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
400 set_builtin_decl (fcode, clone, false);
402 return clone;
405 /* Return 1 if function FNDECL should be instrumented. */
407 bool
408 chkp_instrumentable_p (tree fndecl)
410 struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
411 return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
412 && (!flag_chkp_instrument_marked_only
413 || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
414 && (!fn || !copy_forbidden (fn, fndecl)));
417 /* Return clone created for instrumentation of NODE or NULL. */
419 cgraph_node *
420 chkp_maybe_create_clone (tree fndecl)
422 cgraph_node *node = cgraph_node::get_create (fndecl);
423 cgraph_node *clone = node->instrumented_version;
425 gcc_assert (!node->instrumentation_clone);
427 if (DECL_BUILT_IN (fndecl)
428 && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
429 || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
430 return NULL;
432 clone = node->instrumented_version;
434 /* Some instrumented builtin function calls may be optimized and
435 cgraph nodes may be removed as unreachable. Later optimizations
436 may generate new calls to removed functions and in this case
437 we have to recreate cgraph node. FUNCTION_DECL for instrumented
438 builtin still exists and should be reused in such case. */
439 if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
440 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
441 && !clone)
443 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
444 tree new_decl;
446 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
447 new_decl = builtin_decl_explicit (fncode);
449 /* We've actually already created an instrumented clone once.
450 Restore it. */
451 if (new_decl)
453 clone = cgraph_node::get (new_decl);
455 if (!clone)
457 gcc_assert (!gimple_has_body_p (fndecl));
458 clone = cgraph_node::get_create (new_decl);
459 clone->externally_visible = node->externally_visible;
460 clone->local = node->local;
461 clone->address_taken = node->address_taken;
462 clone->thunk = node->thunk;
463 clone->alias = node->alias;
464 clone->weakref = node->weakref;
465 clone->cpp_implicit_alias = node->cpp_implicit_alias;
466 clone->orig_decl = fndecl;
467 clone->instrumentation_clone = true;
470 clone->instrumented_version = node;
471 node->instrumented_version = clone;
475 if (!clone)
477 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
478 struct cgraph_edge *e;
479 struct ipa_ref *ref;
480 int i;
482 clone = node->create_version_clone (new_decl, vNULL, NULL);
483 clone->externally_visible = node->externally_visible;
484 clone->local = node->local;
485 clone->address_taken = node->address_taken;
486 clone->thunk = node->thunk;
487 clone->alias = node->alias;
488 clone->weakref = node->weakref;
489 clone->cpp_implicit_alias = node->cpp_implicit_alias;
490 clone->instrumented_version = node;
491 clone->orig_decl = fndecl;
492 clone->instrumentation_clone = true;
493 node->instrumented_version = clone;
495 if (gimple_has_body_p (fndecl))
497 /* If function will not be instrumented, then it's instrumented
498 version is a thunk for the original. */
499 if (!chkp_instrumentable_p (fndecl))
501 clone->remove_callees ();
502 clone->remove_all_references ();
503 clone->thunk.thunk_p = true;
504 clone->thunk.add_pointer_bounds_args = true;
505 clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
507 else
509 tree_function_versioning (fndecl, new_decl, NULL, false,
510 NULL, false, NULL, NULL);
511 clone->lowered = true;
515 /* New params are inserted after versioning because it
516 actually copies args list from the original decl. */
517 chkp_add_bounds_params_to_function (new_decl);
519 /* Remember builtin fndecl. */
520 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
521 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
523 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
524 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
525 clone->decl, false);
528 /* Clones have the same comdat group as originals. */
529 if (node->same_comdat_group
530 || DECL_ONE_ONLY (node->decl))
531 clone->add_to_same_comdat_group (node);
533 if (gimple_has_body_p (fndecl))
534 symtab->call_cgraph_insertion_hooks (clone);
536 /* Clone all aliases. */
537 for (i = 0; node->iterate_referring (i, ref); i++)
538 if (ref->use == IPA_REF_ALIAS)
540 struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
541 struct cgraph_node *chkp_alias
542 = chkp_maybe_create_clone (alias->decl);
543 chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
546 /* Clone all thunks. */
547 for (e = node->callers; e; e = e->next_caller)
548 if (e->caller->thunk.thunk_p
549 && !e->caller->thunk.add_pointer_bounds_args)
551 struct cgraph_node *thunk
552 = chkp_maybe_create_clone (e->caller->decl);
553 /* Redirect thunk clone edge to the node clone. */
554 thunk->callees->redirect_callee (clone);
557 /* For aliases and thunks we should make sure target is cloned
558 to have proper references and edges. */
559 if (node->thunk.thunk_p)
560 chkp_maybe_create_clone (node->callees->callee->decl);
561 else if (node->alias)
563 struct cgraph_node *target;
565 ref = node->ref_list.first_reference ();
566 if (ref)
567 chkp_maybe_create_clone (ref->referred->decl);
569 if (node->alias_target)
571 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
573 target = chkp_maybe_create_clone (node->alias_target);
574 clone->alias_target = target->decl;
576 else
577 clone->alias_target = node->alias_target;
581 /* Add IPA reference. It's main role is to keep instrumented
582 version reachable while original node is reachable. */
583 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
586 return clone;
589 /* Create clone for all functions to be instrumented. */
591 static unsigned int
592 chkp_versioning (void)
594 struct cgraph_node *node;
595 const char *reason;
597 bitmap_obstack_initialize (NULL);
599 FOR_EACH_DEFINED_FUNCTION (node)
601 if (!node->instrumentation_clone
602 && !node->instrumented_version
603 && !node->alias
604 && !node->thunk.thunk_p
605 && (!DECL_BUILT_IN (node->decl)
606 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
607 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
609 if (chkp_instrumentable_p (node->decl))
610 chkp_maybe_create_clone (node->decl);
611 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
612 node->decl)))
614 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
615 "function cannot be instrumented"))
616 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
621 /* Mark all aliases and thunks of functions with no instrumented
622 version as legacy function. */
623 FOR_EACH_DEFINED_FUNCTION (node)
625 if (!node->instrumentation_clone
626 && !node->instrumented_version
627 && (node->alias || node->thunk.thunk_p)
628 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
629 DECL_ATTRIBUTES (node->decl)
630 = tree_cons (get_identifier ("bnd_legacy"), NULL,
631 DECL_ATTRIBUTES (node->decl));
634 bitmap_obstack_release (NULL);
636 return 0;
639 /* In this pass we remove bodies of functions having
640 instrumented version. Functions with removed bodies
641 become a special kind of thunks to provide a connection
642 between calls to the original version and instrumented
643 function. */
645 static unsigned int
646 chkp_produce_thunks (bool early)
648 struct cgraph_node *node;
650 FOR_EACH_DEFINED_FUNCTION (node)
652 if (!node->instrumentation_clone
653 && node->instrumented_version
654 && gimple_has_body_p (node->decl)
655 && gimple_has_body_p (node->instrumented_version->decl)
656 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
657 || !early))
659 node->release_body ();
660 node->remove_callees ();
661 node->remove_all_references ();
663 node->thunk.thunk_p = true;
664 node->thunk.add_pointer_bounds_args = true;
665 node->create_edge (node->instrumented_version, NULL,
666 0, CGRAPH_FREQ_BASE);
667 node->create_reference (node->instrumented_version,
668 IPA_REF_CHKP, NULL);
672 /* Mark instrumentation clones created for aliases and thunks
673 as insttrumented so they could be removed as unreachable
674 now. */
675 if (!early)
677 FOR_EACH_DEFINED_FUNCTION (node)
679 if (node->instrumentation_clone
680 && (node->alias || node->thunk.thunk_p)
681 && !chkp_function_instrumented_p (node->decl))
682 chkp_function_mark_instrumented (node->decl);
686 return TODO_remove_functions;
689 const pass_data pass_data_ipa_chkp_versioning =
691 SIMPLE_IPA_PASS, /* type */
692 "chkp_versioning", /* name */
693 OPTGROUP_NONE, /* optinfo_flags */
694 TV_NONE, /* tv_id */
695 0, /* properties_required */
696 0, /* properties_provided */
697 0, /* properties_destroyed */
698 0, /* todo_flags_start */
699 0 /* todo_flags_finish */
702 const pass_data pass_data_ipa_chkp_early_produce_thunks =
704 SIMPLE_IPA_PASS, /* type */
705 "chkp_ecleanup", /* name */
706 OPTGROUP_NONE, /* optinfo_flags */
707 TV_NONE, /* tv_id */
708 0, /* properties_required */
709 0, /* properties_provided */
710 0, /* properties_destroyed */
711 0, /* todo_flags_start */
712 0 /* todo_flags_finish */
715 const pass_data pass_data_ipa_chkp_produce_thunks =
717 SIMPLE_IPA_PASS, /* type */
718 "chkp_cleanup", /* name */
719 OPTGROUP_NONE, /* optinfo_flags */
720 TV_NONE, /* tv_id */
721 0, /* properties_required */
722 0, /* properties_provided */
723 0, /* properties_destroyed */
724 0, /* todo_flags_start */
725 0 /* todo_flags_finish */
728 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
730 public:
731 pass_ipa_chkp_versioning (gcc::context *ctxt)
732 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
735 /* opt_pass methods: */
736 virtual opt_pass * clone ()
738 return new pass_ipa_chkp_versioning (m_ctxt);
741 virtual bool gate (function *)
743 return flag_check_pointer_bounds;
746 virtual unsigned int execute (function *)
748 return chkp_versioning ();
751 }; // class pass_ipa_chkp_versioning
753 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
755 public:
756 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
757 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
760 /* opt_pass methods: */
761 virtual opt_pass * clone ()
763 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
766 virtual bool gate (function *)
768 return flag_check_pointer_bounds;
771 virtual unsigned int execute (function *)
773 return chkp_produce_thunks (true);
776 }; // class pass_chkp_produce_thunks
778 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
780 public:
781 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
782 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
785 /* opt_pass methods: */
786 virtual opt_pass * clone ()
788 return new pass_ipa_chkp_produce_thunks (m_ctxt);
791 virtual bool gate (function *)
793 return flag_check_pointer_bounds;
796 virtual unsigned int execute (function *)
798 return chkp_produce_thunks (false);
801 }; // class pass_chkp_produce_thunks
803 simple_ipa_opt_pass *
804 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
806 return new pass_ipa_chkp_versioning (ctxt);
809 simple_ipa_opt_pass *
810 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
812 return new pass_ipa_chkp_early_produce_thunks (ctxt);
815 simple_ipa_opt_pass *
816 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
818 return new pass_ipa_chkp_produce_thunks (ctxt);