ipa-chkp.c: Use iterate_direct_aliases.
[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 "tree-inline.h"
54 #include "ipa-chkp.h"
55
56 /* Pointer Bounds Checker has two IPA passes to support code instrumentation.
57
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.
61
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.
68
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).
74
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.
80
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).
85
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.
91
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. */
101
102 #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
103
104 /* Build a clone of FNDECL with a modified name. */
105
106 static tree
107 chkp_build_instrumented_fndecl (tree fndecl)
108 {
109 tree new_decl = copy_node (fndecl);
110 tree new_name;
111 std::string s;
112
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 ());
120
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);
133
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));
138
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));
142
143 /* Change builtin function code. */
144 if (DECL_BUILT_IN (new_decl))
145 {
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);
151 }
152
153 return new_decl;
154 }
155
156
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. */
161
162 static void
163 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
164 unsigned *indexes, int len, int delta)
165 {
166 tree attr = lookup_attribute (attr_name, attrs);
167 tree op;
168
169 if (!attr)
170 return;
171
172 TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
173 for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
174 {
175 int idx;
176
177 if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
178 continue;
179
180 idx = TREE_INT_CST_LOW (TREE_VALUE (op));
181
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);
190 }
191 }
192
193 /* Make a copy of function type ORIG_TYPE adding pointer
194 bounds as additional arguments. */
195
196 tree
197 chkp_copy_function_type_adding_bounds (tree orig_type)
198 {
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;
204
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;
215
216 /* We may use original type if there are no bounds passed. */
217 if (!arg_type)
218 return orig_type;
219
220 type = copy_node (orig_type);
221 TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
222
223 for (arg_type = TYPE_ARG_TYPES (type);
224 arg_type;
225 arg_type = TREE_CHAIN (arg_type))
226 {
227 indexes[idx++] = new_idx++;
228
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))
236 {
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;
241
242 arg_type = TREE_CHAIN (arg_type);
243 new_idx++;
244 }
245 else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
246 {
247 bitmap slots = BITMAP_ALLOC (NULL);
248 bitmap_iterator bi;
249 unsigned bnd_no;
250
251 chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
252
253 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
254 {
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;
259
260 arg_type = TREE_CHAIN (arg_type);
261 new_idx++;
262 }
263 BITMAP_FREE (slots);
264 }
265 }
266
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))
274 {
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;
281 }
282
283 t = TYPE_MAIN_VARIANT (orig_type);
284 if (orig_type != t)
285 {
286 TYPE_MAIN_VARIANT (type) = t;
287 TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
288 TYPE_NEXT_VARIANT (t) = type;
289 }
290 else
291 {
292 TYPE_MAIN_VARIANT (type) = type;
293 TYPE_NEXT_VARIANT (type) = NULL;
294 }
295
296
297 return type;
298 }
299
300 /* For given function FNDECL add bounds arguments to arguments
301 list. */
302
303 static void
304 chkp_add_bounds_params_to_function (tree fndecl)
305 {
306 tree arg;
307
308 for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
309 if (BOUNDED_P (arg))
310 {
311 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
312 tree new_arg;
313
314 if (DECL_NAME (arg))
315 new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
316 else
317 {
318 char uid[25];
319 snprintf (uid, 25, "D.%u", DECL_UID (arg));
320 new_name += uid;
321 }
322
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;
331
332 arg = DECL_CHAIN (arg);
333
334 }
335 else if (chkp_type_has_pointer (TREE_TYPE (arg)))
336 {
337 tree orig_arg = arg;
338 bitmap slots = BITMAP_ALLOC (NULL);
339 bitmap_iterator bi;
340 unsigned bnd_no;
341
342 chkp_find_bound_slots (TREE_TYPE (arg), slots);
343
344 EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
345 {
346 std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
347 tree new_arg;
348 char offs[25];
349
350 if (DECL_NAME (orig_arg))
351 new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
352 else
353 {
354 snprintf (offs, 25, "D.%u", DECL_UID (arg));
355 new_name += offs;
356 }
357 snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
358
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;
368
369 arg = DECL_CHAIN (arg);
370 }
371 BITMAP_FREE (slots);
372 }
373
374 TREE_TYPE (fndecl) =
375 chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
376 }
377
378 /* Return an instrumentation clone for builtin function
379 FNDECL. Create one if needed. */
380
381 tree
382 chkp_maybe_clone_builtin_fndecl (tree fndecl)
383 {
384 tree clone;
385 enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
386
387 gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
388 && fcode < BEGIN_CHKP_BUILTINS);
389
390 fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
391 clone = builtin_decl_explicit (fcode);
392 if (clone)
393 return clone;
394
395 clone = chkp_build_instrumented_fndecl (fndecl);
396 chkp_add_bounds_params_to_function (clone);
397
398 gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
399
400 set_builtin_decl (fcode, clone, false);
401
402 return clone;
403 }
404
405 /* Return 1 if function FNDECL should be instrumented. */
406
407 bool
408 chkp_instrumentable_p (tree fndecl)
409 {
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)));
415 }
416
417 /* Return clone created for instrumentation of NODE or NULL. */
418
419 cgraph_node *
420 chkp_maybe_create_clone (tree fndecl)
421 {
422 cgraph_node *node = cgraph_node::get_create (fndecl);
423 cgraph_node *clone = node->instrumented_version;
424
425 gcc_assert (!node->instrumentation_clone);
426
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;
431
432 clone = node->instrumented_version;
433
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)
442 {
443 enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
444 tree new_decl;
445
446 fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
447 new_decl = builtin_decl_explicit (fncode);
448
449 /* We've actually already created an instrumented clone once.
450 Restore it. */
451 if (new_decl)
452 {
453 clone = cgraph_node::get (new_decl);
454
455 if (!clone)
456 {
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;
468 }
469
470 clone->instrumented_version = node;
471 node->instrumented_version = clone;
472 }
473 }
474
475 if (!clone)
476 {
477 tree new_decl = chkp_build_instrumented_fndecl (fndecl);
478 struct cgraph_edge *e;
479 struct ipa_ref *ref;
480 int i;
481
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;
494
495 if (gimple_has_body_p (fndecl))
496 {
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))
500 {
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);
506 }
507 else
508 {
509 tree_function_versioning (fndecl, new_decl, NULL, false,
510 NULL, false, NULL, NULL);
511 clone->lowered = true;
512 }
513 }
514
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);
518
519 /* Remember builtin fndecl. */
520 if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
521 && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
522 {
523 gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
524 set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
525 clone->decl, false);
526 }
527
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);
532
533 if (gimple_has_body_p (fndecl))
534 symtab->call_cgraph_insertion_hooks (clone);
535
536 /* Clone all aliases. */
537 for (i = 0; node->iterate_direct_aliases (i, ref); i++)
538 {
539 struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
540 struct cgraph_node *chkp_alias
541 = chkp_maybe_create_clone (alias->decl);
542 chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
543 }
544
545 /* Clone all thunks. */
546 for (e = node->callers; e; e = e->next_caller)
547 if (e->caller->thunk.thunk_p
548 && !e->caller->thunk.add_pointer_bounds_args)
549 {
550 struct cgraph_node *thunk
551 = chkp_maybe_create_clone (e->caller->decl);
552 /* Redirect thunk clone edge to the node clone. */
553 thunk->callees->redirect_callee (clone);
554 }
555
556 /* For aliases and thunks we should make sure target is cloned
557 to have proper references and edges. */
558 if (node->thunk.thunk_p)
559 chkp_maybe_create_clone (node->callees->callee->decl);
560 else if (node->alias)
561 {
562 struct cgraph_node *target;
563
564 ref = node->ref_list.first_reference ();
565 if (ref)
566 chkp_maybe_create_clone (ref->referred->decl);
567
568 if (node->alias_target)
569 {
570 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
571 {
572 target = chkp_maybe_create_clone (node->alias_target);
573 clone->alias_target = target->decl;
574 }
575 else
576 clone->alias_target = node->alias_target;
577 }
578 }
579
580 /* Add IPA reference. It's main role is to keep instrumented
581 version reachable while original node is reachable. */
582 ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
583 }
584
585 return clone;
586 }
587
588 /* Create clone for all functions to be instrumented. */
589
590 static unsigned int
591 chkp_versioning (void)
592 {
593 struct cgraph_node *node;
594 const char *reason;
595
596 bitmap_obstack_initialize (NULL);
597
598 FOR_EACH_DEFINED_FUNCTION (node)
599 {
600 if (!node->instrumentation_clone
601 && !node->instrumented_version
602 && !node->alias
603 && !node->thunk.thunk_p
604 && (!DECL_BUILT_IN (node->decl)
605 || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
606 && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
607 {
608 if (chkp_instrumentable_p (node->decl))
609 chkp_maybe_create_clone (node->decl);
610 else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
611 node->decl)))
612 {
613 if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
614 "function cannot be instrumented"))
615 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
616 }
617 }
618 }
619
620 /* Mark all aliases and thunks of functions with no instrumented
621 version as legacy function. */
622 FOR_EACH_DEFINED_FUNCTION (node)
623 {
624 if (!node->instrumentation_clone
625 && !node->instrumented_version
626 && (node->alias || node->thunk.thunk_p)
627 && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
628 DECL_ATTRIBUTES (node->decl)
629 = tree_cons (get_identifier ("bnd_legacy"), NULL,
630 DECL_ATTRIBUTES (node->decl));
631 }
632
633 bitmap_obstack_release (NULL);
634
635 return 0;
636 }
637
638 /* In this pass we remove bodies of functions having
639 instrumented version. Functions with removed bodies
640 become a special kind of thunks to provide a connection
641 between calls to the original version and instrumented
642 function. */
643
644 static unsigned int
645 chkp_produce_thunks (bool early)
646 {
647 struct cgraph_node *node;
648
649 FOR_EACH_DEFINED_FUNCTION (node)
650 {
651 if (!node->instrumentation_clone
652 && node->instrumented_version
653 && gimple_has_body_p (node->decl)
654 && gimple_has_body_p (node->instrumented_version->decl)
655 && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
656 || !early))
657 {
658 node->release_body ();
659 node->remove_callees ();
660 node->remove_all_references ();
661
662 node->thunk.thunk_p = true;
663 node->thunk.add_pointer_bounds_args = true;
664 node->create_edge (node->instrumented_version, NULL,
665 0, CGRAPH_FREQ_BASE);
666 node->create_reference (node->instrumented_version,
667 IPA_REF_CHKP, NULL);
668 }
669 }
670
671 /* Mark instrumentation clones created for aliases and thunks
672 as insttrumented so they could be removed as unreachable
673 now. */
674 if (!early)
675 {
676 FOR_EACH_DEFINED_FUNCTION (node)
677 {
678 if (node->instrumentation_clone
679 && (node->alias || node->thunk.thunk_p)
680 && !chkp_function_instrumented_p (node->decl))
681 chkp_function_mark_instrumented (node->decl);
682 }
683 }
684
685 return TODO_remove_functions;
686 }
687
688 const pass_data pass_data_ipa_chkp_versioning =
689 {
690 SIMPLE_IPA_PASS, /* type */
691 "chkp_versioning", /* name */
692 OPTGROUP_NONE, /* optinfo_flags */
693 TV_NONE, /* tv_id */
694 0, /* properties_required */
695 0, /* properties_provided */
696 0, /* properties_destroyed */
697 0, /* todo_flags_start */
698 0 /* todo_flags_finish */
699 };
700
701 const pass_data pass_data_ipa_chkp_early_produce_thunks =
702 {
703 SIMPLE_IPA_PASS, /* type */
704 "chkp_ecleanup", /* name */
705 OPTGROUP_NONE, /* optinfo_flags */
706 TV_NONE, /* tv_id */
707 0, /* properties_required */
708 0, /* properties_provided */
709 0, /* properties_destroyed */
710 0, /* todo_flags_start */
711 0 /* todo_flags_finish */
712 };
713
714 const pass_data pass_data_ipa_chkp_produce_thunks =
715 {
716 SIMPLE_IPA_PASS, /* type */
717 "chkp_cleanup", /* name */
718 OPTGROUP_NONE, /* optinfo_flags */
719 TV_NONE, /* tv_id */
720 0, /* properties_required */
721 0, /* properties_provided */
722 0, /* properties_destroyed */
723 0, /* todo_flags_start */
724 0 /* todo_flags_finish */
725 };
726
727 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
728 {
729 public:
730 pass_ipa_chkp_versioning (gcc::context *ctxt)
731 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
732 {}
733
734 /* opt_pass methods: */
735 virtual opt_pass * clone ()
736 {
737 return new pass_ipa_chkp_versioning (m_ctxt);
738 }
739
740 virtual bool gate (function *)
741 {
742 return flag_check_pointer_bounds;
743 }
744
745 virtual unsigned int execute (function *)
746 {
747 return chkp_versioning ();
748 }
749
750 }; // class pass_ipa_chkp_versioning
751
752 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
753 {
754 public:
755 pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
756 : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
757 {}
758
759 /* opt_pass methods: */
760 virtual opt_pass * clone ()
761 {
762 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
763 }
764
765 virtual bool gate (function *)
766 {
767 return flag_check_pointer_bounds;
768 }
769
770 virtual unsigned int execute (function *)
771 {
772 return chkp_produce_thunks (true);
773 }
774
775 }; // class pass_chkp_produce_thunks
776
777 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
778 {
779 public:
780 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
781 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
782 {}
783
784 /* opt_pass methods: */
785 virtual opt_pass * clone ()
786 {
787 return new pass_ipa_chkp_produce_thunks (m_ctxt);
788 }
789
790 virtual bool gate (function *)
791 {
792 return flag_check_pointer_bounds;
793 }
794
795 virtual unsigned int execute (function *)
796 {
797 return chkp_produce_thunks (false);
798 }
799
800 }; // class pass_chkp_produce_thunks
801
802 simple_ipa_opt_pass *
803 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
804 {
805 return new pass_ipa_chkp_versioning (ctxt);
806 }
807
808 simple_ipa_opt_pass *
809 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
810 {
811 return new pass_ipa_chkp_early_produce_thunks (ctxt);
812 }
813
814 simple_ipa_opt_pass *
815 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
816 {
817 return new pass_ipa_chkp_produce_thunks (ctxt);
818 }