[ARM/AArch64][testsuite] Add vmull tests.
[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_referring (i, ref); i++)
538 if (ref->use == IPA_REF_ALIAS)
539 {
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);
544 }
545
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)
550 {
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);
555 }
556
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)
562 {
563 struct cgraph_node *target;
564
565 ref = node->ref_list.first_reference ();
566 if (ref)
567 chkp_maybe_create_clone (ref->referred->decl);
568
569 if (node->alias_target)
570 {
571 if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
572 {
573 target = chkp_maybe_create_clone (node->alias_target);
574 clone->alias_target = target->decl;
575 }
576 else
577 clone->alias_target = node->alias_target;
578 }
579 }
580
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);
584 }
585
586 return clone;
587 }
588
589 /* Create clone for all functions to be instrumented. */
590
591 static unsigned int
592 chkp_versioning (void)
593 {
594 struct cgraph_node *node;
595 const char *reason;
596
597 bitmap_obstack_initialize (NULL);
598
599 FOR_EACH_DEFINED_FUNCTION (node)
600 {
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)))
608 {
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)))
613 {
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);
617 }
618 }
619 }
620
621 /* Mark all aliases and thunks of functions with no instrumented
622 version as legacy function. */
623 FOR_EACH_DEFINED_FUNCTION (node)
624 {
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));
632 }
633
634 bitmap_obstack_release (NULL);
635
636 return 0;
637 }
638
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. */
644
645 static unsigned int
646 chkp_produce_thunks (bool early)
647 {
648 struct cgraph_node *node;
649
650 FOR_EACH_DEFINED_FUNCTION (node)
651 {
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))
658 {
659 node->release_body ();
660 node->remove_callees ();
661 node->remove_all_references ();
662
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);
669 }
670 }
671
672 /* Mark instrumentation clones created for aliases and thunks
673 as insttrumented so they could be removed as unreachable
674 now. */
675 if (!early)
676 {
677 FOR_EACH_DEFINED_FUNCTION (node)
678 {
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);
683 }
684 }
685
686 return TODO_remove_functions;
687 }
688
689 const pass_data pass_data_ipa_chkp_versioning =
690 {
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 */
700 };
701
702 const pass_data pass_data_ipa_chkp_early_produce_thunks =
703 {
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 */
713 };
714
715 const pass_data pass_data_ipa_chkp_produce_thunks =
716 {
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 */
726 };
727
728 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
729 {
730 public:
731 pass_ipa_chkp_versioning (gcc::context *ctxt)
732 : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
733 {}
734
735 /* opt_pass methods: */
736 virtual opt_pass * clone ()
737 {
738 return new pass_ipa_chkp_versioning (m_ctxt);
739 }
740
741 virtual bool gate (function *)
742 {
743 return flag_check_pointer_bounds;
744 }
745
746 virtual unsigned int execute (function *)
747 {
748 return chkp_versioning ();
749 }
750
751 }; // class pass_ipa_chkp_versioning
752
753 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
754 {
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)
758 {}
759
760 /* opt_pass methods: */
761 virtual opt_pass * clone ()
762 {
763 return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
764 }
765
766 virtual bool gate (function *)
767 {
768 return flag_check_pointer_bounds;
769 }
770
771 virtual unsigned int execute (function *)
772 {
773 return chkp_produce_thunks (true);
774 }
775
776 }; // class pass_chkp_produce_thunks
777
778 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
779 {
780 public:
781 pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
782 : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
783 {}
784
785 /* opt_pass methods: */
786 virtual opt_pass * clone ()
787 {
788 return new pass_ipa_chkp_produce_thunks (m_ctxt);
789 }
790
791 virtual bool gate (function *)
792 {
793 return flag_check_pointer_bounds;
794 }
795
796 virtual unsigned int execute (function *)
797 {
798 return chkp_produce_thunks (false);
799 }
800
801 }; // class pass_chkp_produce_thunks
802
803 simple_ipa_opt_pass *
804 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
805 {
806 return new pass_ipa_chkp_versioning (ctxt);
807 }
808
809 simple_ipa_opt_pass *
810 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
811 {
812 return new pass_ipa_chkp_early_produce_thunks (ctxt);
813 }
814
815 simple_ipa_opt_pass *
816 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
817 {
818 return new pass_ipa_chkp_produce_thunks (ctxt);
819 }