70e629b318b17b9b2772f1030140223a7fbf3b02
[dragonfly.git] / contrib / gcc-5.0 / 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 #define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_"
104
105 /* Return 1 calls to FNDECL should be replaced with
106    a call to wrapper function.  */
107 static bool
108 chkp_wrap_function (tree fndecl)
109 {
110   if (!flag_chkp_use_wrappers)
111     return false;
112
113   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
114     {
115       switch (DECL_FUNCTION_CODE (fndecl))
116         {
117         case BUILT_IN_STRLEN:
118         case BUILT_IN_STRCPY:
119         case BUILT_IN_STRNCPY:
120         case BUILT_IN_STPCPY:
121         case BUILT_IN_STPNCPY:
122         case BUILT_IN_STRCAT:
123         case BUILT_IN_STRNCAT:
124         case BUILT_IN_MEMCPY:
125         case BUILT_IN_MEMPCPY:
126         case BUILT_IN_MEMSET:
127         case BUILT_IN_MEMMOVE:
128         case BUILT_IN_BZERO:
129         case BUILT_IN_MALLOC:
130         case BUILT_IN_CALLOC:
131         case BUILT_IN_REALLOC:
132           return 1;
133
134         default:
135           return 0;
136         }
137     }
138
139   return false;
140 }
141
142 /* Build a clone of FNDECL with a modified name.  */
143
144 static tree
145 chkp_build_instrumented_fndecl (tree fndecl)
146 {
147   tree new_decl = copy_node (fndecl);
148   tree new_name;
149   std::string s;
150
151   /* called_as_built_in checks DECL_NAME to identify calls to
152      builtins.  We want instrumented calls to builtins to be
153      recognized by called_as_built_in.  Therefore use original
154      DECL_NAME for cloning with no prefixes.  */
155   s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
156   s += ".chkp";
157   DECL_NAME (new_decl) = get_identifier (s.c_str ());
158
159   /* References to the original and to the instrumented version
160      should look the same in the output assembly.  And we cannot
161      use the same assembler name for the instrumented version
162      because it conflicts with decl merging algorithms in LTO.
163      Achieve the result by using transparent alias name for the
164      instrumented version.  */
165   if (chkp_wrap_function(fndecl))
166     {
167       s = CHKP_WRAPPER_SYMBOL_PREFIX;
168       s += IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
169       new_name = get_identifier (s.c_str ());
170     }
171   else
172     {
173       s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
174       s += ".chkp";
175       new_name = get_identifier (s.c_str ());
176       IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
177       TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
178     }
179   SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
180
181   /* For functions with body versioning will make a copy of arguments.
182      For functions with no body we need to do it here.  */
183   if (!gimple_has_body_p (fndecl))
184     DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
185
186   /* We are going to modify attributes list and therefore should
187      make own copy.  */
188   DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
189
190   /* Change builtin function code.  */
191   if (DECL_BUILT_IN (new_decl))
192     {
193       gcc_assert (DECL_BUILT_IN_CLASS (new_decl) == BUILT_IN_NORMAL);
194       gcc_assert (DECL_FUNCTION_CODE (new_decl) < BEGIN_CHKP_BUILTINS);
195       DECL_FUNCTION_CODE (new_decl)
196         = (enum built_in_function)(DECL_FUNCTION_CODE (new_decl)
197                                    + BEGIN_CHKP_BUILTINS + 1);
198     }
199
200   return new_decl;
201 }
202
203
204 /* Fix operands of attribute from ATTRS list named ATTR_NAME.
205    Integer operands are replaced with values according to
206    INDEXES map having LEN elements.  For operands out of len
207    we just add DELTA.  */
208
209 static void
210 chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
211                            unsigned *indexes, int len, int delta)
212 {
213   tree attr = lookup_attribute (attr_name, attrs);
214   tree op;
215
216   if (!attr)
217     return;
218
219   TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
220   for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
221     {
222       int idx;
223
224       if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
225         continue;
226
227       idx = TREE_INT_CST_LOW (TREE_VALUE (op));
228
229       /* If idx exceeds indexes length then we just
230          keep it at the same distance from the last
231          known arg.  */
232       if (idx > len)
233         idx += delta;
234       else
235         idx = indexes[idx - 1] + 1;
236       TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
237     }
238 }
239
240 /* Make a copy of function type ORIG_TYPE adding pointer
241    bounds as additional arguments.  */
242
243 tree
244 chkp_copy_function_type_adding_bounds (tree orig_type)
245 {
246   tree type;
247   tree arg_type, attrs, t;
248   unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
249   unsigned *indexes = XALLOCAVEC (unsigned, len);
250   unsigned idx = 0, new_idx = 0;
251
252   for (arg_type = TYPE_ARG_TYPES (orig_type);
253        arg_type;
254        arg_type = TREE_CHAIN (arg_type))
255     if (TREE_VALUE (arg_type) == void_type_node)
256       continue;
257     else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
258              || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
259                                    TREE_VALUE (arg_type), true)
260              || chkp_type_has_pointer (TREE_VALUE (arg_type)))
261       break;
262
263   /* We may use original type if there are no bounds passed.  */
264   if (!arg_type)
265     return orig_type;
266
267   type = build_distinct_type_copy (orig_type);
268   TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
269
270   for (arg_type = TYPE_ARG_TYPES (type);
271        arg_type;
272        arg_type = TREE_CHAIN (arg_type))
273     {
274       indexes[idx++] = new_idx++;
275
276       /* pass_by_reference returns 1 for void type,
277          so check for it first.  */
278       if (TREE_VALUE (arg_type) == void_type_node)
279         continue;
280       else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
281                || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
282                                      TREE_VALUE (arg_type), true))
283         {
284           tree new_type = build_tree_list (NULL_TREE,
285                                            pointer_bounds_type_node);
286           TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
287           TREE_CHAIN (arg_type) = new_type;
288
289           arg_type = TREE_CHAIN (arg_type);
290           new_idx++;
291         }
292       else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
293         {
294           bitmap slots = BITMAP_ALLOC (NULL);
295           bitmap_iterator bi;
296           unsigned bnd_no;
297
298           chkp_find_bound_slots (TREE_VALUE (arg_type), slots);
299
300           EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
301             {
302               tree new_type = build_tree_list (NULL_TREE,
303                                                pointer_bounds_type_node);
304               TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
305               TREE_CHAIN (arg_type) = new_type;
306
307               arg_type = TREE_CHAIN (arg_type);
308               new_idx++;
309             }
310           BITMAP_FREE (slots);
311         }
312     }
313
314   /* If function type has attribute with arg indexes then
315      we have to copy it fixing attribute ops.  Map for
316      fixing is in indexes array.  */
317   attrs = TYPE_ATTRIBUTES (type);
318   if (lookup_attribute ("nonnull", attrs)
319       || lookup_attribute ("format", attrs)
320       || lookup_attribute ("format_arg", attrs))
321     {
322       int delta = new_idx - len;
323       attrs = copy_list (TYPE_ATTRIBUTES (type));
324       chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
325       chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
326       chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
327       TYPE_ATTRIBUTES (type) = attrs;
328     }
329
330   t = TYPE_MAIN_VARIANT (orig_type);
331   if (orig_type != t)
332     {
333       TYPE_MAIN_VARIANT (type) = t;
334       TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
335       TYPE_NEXT_VARIANT (t) = type;
336     }
337   else
338     {
339       TYPE_MAIN_VARIANT (type) = type;
340       TYPE_NEXT_VARIANT (type) = NULL;
341     }
342
343
344   return type;
345 }
346
347 /* For given function FNDECL add bounds arguments to arguments
348    list.  */
349
350 static void
351 chkp_add_bounds_params_to_function (tree fndecl)
352 {
353   tree arg;
354
355   for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
356     if (BOUNDED_P (arg))
357       {
358         std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
359         tree new_arg;
360
361         if (DECL_NAME (arg))
362           new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
363         else
364           {
365             char uid[25];
366             snprintf (uid, 25, "D.%u", DECL_UID (arg));
367             new_name += uid;
368           }
369
370         new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
371                               get_identifier (new_name.c_str ()),
372                               pointer_bounds_type_node);
373         DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
374         DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
375         DECL_ARTIFICIAL (new_arg) = 1;
376         DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
377         DECL_CHAIN (arg) = new_arg;
378
379         arg = DECL_CHAIN (arg);
380
381       }
382     else if (chkp_type_has_pointer (TREE_TYPE (arg)))
383       {
384         tree orig_arg = arg;
385         bitmap slots = BITMAP_ALLOC (NULL);
386         bitmap_iterator bi;
387         unsigned bnd_no;
388
389         chkp_find_bound_slots (TREE_TYPE (arg), slots);
390
391         EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
392           {
393             std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
394             tree new_arg;
395             char offs[25];
396
397             if (DECL_NAME (orig_arg))
398               new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
399             else
400               {
401                 snprintf (offs, 25, "D.%u", DECL_UID (arg));
402                 new_name += offs;
403               }
404             snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
405
406             new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
407                                   PARM_DECL,
408                                   get_identifier (new_name.c_str ()),
409                                   pointer_bounds_type_node);
410             DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
411             DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
412             DECL_ARTIFICIAL (new_arg) = 1;
413             DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
414             DECL_CHAIN (arg) = new_arg;
415
416             arg = DECL_CHAIN (arg);
417           }
418         BITMAP_FREE (slots);
419       }
420
421   TREE_TYPE (fndecl) =
422     chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
423 }
424
425 /* Return an instrumentation clone for builtin function
426    FNDECL.  Create one if needed.  */
427
428 tree
429 chkp_maybe_clone_builtin_fndecl (tree fndecl)
430 {
431   tree clone;
432   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
433
434   gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
435               && fcode < BEGIN_CHKP_BUILTINS);
436
437   fcode = (enum built_in_function) (fcode + BEGIN_CHKP_BUILTINS + 1);
438   clone = builtin_decl_explicit (fcode);
439   if (clone)
440     return clone;
441
442   clone = chkp_build_instrumented_fndecl (fndecl);
443   chkp_add_bounds_params_to_function (clone);
444
445   gcc_assert (DECL_FUNCTION_CODE (clone) == fcode);
446
447   set_builtin_decl (fcode, clone, false);
448
449   return clone;
450 }
451
452 /* Return 1 if function FNDECL should be instrumented.  */
453
454 bool
455 chkp_instrumentable_p (tree fndecl)
456 {
457   struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
458   return (!lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
459           && (!flag_chkp_instrument_marked_only
460               || lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl)))
461           && (!fn || !copy_forbidden (fn, fndecl)));
462 }
463
464 /* Return clone created for instrumentation of NODE or NULL.  */
465
466 cgraph_node *
467 chkp_maybe_create_clone (tree fndecl)
468 {
469   cgraph_node *node = cgraph_node::get_create (fndecl);
470   cgraph_node *clone = node->instrumented_version;
471
472   gcc_assert (!node->instrumentation_clone);
473
474   if (DECL_BUILT_IN (fndecl)
475       && (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
476           || DECL_FUNCTION_CODE (fndecl) >= BEGIN_CHKP_BUILTINS))
477     return NULL;
478
479   clone = node->instrumented_version;
480
481   /* Some instrumented builtin function calls may be optimized and
482      cgraph nodes may be removed as unreachable.  Later optimizations
483      may generate new calls to removed functions and in this case
484      we have to recreate cgraph node.  FUNCTION_DECL for instrumented
485      builtin still exists and should be reused in such case.  */
486   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
487       && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl))
488       && !clone)
489     {
490       enum built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
491       tree new_decl;
492
493       fncode = (enum built_in_function) (fncode + BEGIN_CHKP_BUILTINS + 1);
494       new_decl = builtin_decl_explicit (fncode);
495
496       /* We've actually already created an instrumented clone once.
497          Restore it.  */
498       if (new_decl)
499         {
500           clone = cgraph_node::get (new_decl);
501
502           if (!clone)
503             {
504               gcc_assert (!gimple_has_body_p (fndecl));
505               clone = cgraph_node::get_create (new_decl);
506               clone->externally_visible = node->externally_visible;
507               clone->local = node->local;
508               clone->address_taken = node->address_taken;
509               clone->thunk = node->thunk;
510               clone->alias = node->alias;
511               clone->weakref = node->weakref;
512               clone->cpp_implicit_alias = node->cpp_implicit_alias;
513               clone->orig_decl = fndecl;
514               clone->instrumentation_clone = true;
515             }
516
517           clone->instrumented_version = node;
518           node->instrumented_version = clone;
519         }
520     }
521
522   if (!clone)
523     {
524       tree new_decl = chkp_build_instrumented_fndecl (fndecl);
525       struct cgraph_edge *e;
526       struct ipa_ref *ref;
527       int i;
528
529       clone = node->create_version_clone (new_decl, vNULL, NULL);
530       clone->externally_visible = node->externally_visible;
531       clone->local = node->local;
532       clone->address_taken = node->address_taken;
533       clone->thunk = node->thunk;
534       clone->alias = node->alias;
535       clone->weakref = node->weakref;
536       clone->cpp_implicit_alias = node->cpp_implicit_alias;
537       clone->instrumented_version = node;
538       clone->orig_decl = fndecl;
539       clone->instrumentation_clone = true;
540       node->instrumented_version = clone;
541
542       if (gimple_has_body_p (fndecl))
543         {
544           /* If function will not be instrumented, then it's instrumented
545              version is a thunk for the original.  */
546           if (!chkp_instrumentable_p (fndecl))
547             {
548               clone->remove_callees ();
549               clone->remove_all_references ();
550               clone->thunk.thunk_p = true;
551               clone->thunk.add_pointer_bounds_args = true;
552               clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
553               /* Thunk shouldn't be a cdtor.  */
554               DECL_STATIC_CONSTRUCTOR (clone->decl) = 0;
555               DECL_STATIC_DESTRUCTOR (clone->decl) = 0;
556             }
557           else
558             {
559               tree_function_versioning (fndecl, new_decl, NULL, false,
560                                         NULL, false, NULL, NULL);
561               clone->lowered = true;
562             }
563         }
564
565       /* New params are inserted after versioning because it
566          actually copies args list from the original decl.  */
567       chkp_add_bounds_params_to_function (new_decl);
568
569       /* Remember builtin fndecl.  */
570       if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
571           && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
572         {
573           gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
574           set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
575                             clone->decl, false);
576         }
577
578       /* Clones have the same comdat group as originals.  */
579       if (node->same_comdat_group
580           || (DECL_ONE_ONLY (node->decl)
581               && !DECL_EXTERNAL (node->decl)))
582         clone->add_to_same_comdat_group (node);
583
584       if (gimple_has_body_p (fndecl))
585         symtab->call_cgraph_insertion_hooks (clone);
586
587       /* Clone all aliases.  */
588       for (i = 0; node->iterate_direct_aliases (i, ref); i++)
589         {
590           struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
591           struct cgraph_node *chkp_alias
592             = chkp_maybe_create_clone (alias->decl);
593           chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
594         }
595
596       /* Clone all thunks.  */
597       for (e = node->callers; e; e = e->next_caller)
598         if (e->caller->thunk.thunk_p
599             && !e->caller->thunk.add_pointer_bounds_args
600             && !e->caller->instrumentation_clone)
601           {
602             struct cgraph_node *thunk
603               = chkp_maybe_create_clone (e->caller->decl);
604             /* Redirect thunk clone edge to the node clone.  */
605             thunk->callees->redirect_callee (clone);
606           }
607
608       /* For aliases and thunks we should make sure target is cloned
609          to have proper references and edges.  */
610       if (node->thunk.thunk_p)
611         chkp_maybe_create_clone (node->callees->callee->decl);
612       else if (node->alias)
613         {
614           struct cgraph_node *target;
615
616           ref = node->ref_list.first_reference ();
617           if (ref)
618             chkp_maybe_create_clone (ref->referred->decl);
619
620           if (node->alias_target)
621             {
622               if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
623                 {
624                   target = chkp_maybe_create_clone (node->alias_target);
625                   clone->alias_target = target->decl;
626                 }
627               else
628                 clone->alias_target = node->alias_target;
629             }
630         }
631
632       /* Add IPA reference.  It's main role is to keep instrumented
633          version reachable while original node is reachable.  */
634       ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
635     }
636
637   return clone;
638 }
639
640 /* Create clone for all functions to be instrumented.  */
641
642 static unsigned int
643 chkp_versioning (void)
644 {
645   struct cgraph_node *node;
646   const char *reason;
647
648   bitmap_obstack_initialize (NULL);
649
650   FOR_EACH_DEFINED_FUNCTION (node)
651     {
652       if (!node->instrumentation_clone
653           && !node->instrumented_version
654           && !node->alias
655           && !node->thunk.thunk_p
656           && (!DECL_BUILT_IN (node->decl)
657               || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
658                   && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
659         {
660           if (chkp_instrumentable_p (node->decl))
661             chkp_maybe_create_clone (node->decl);
662           else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
663                                              node->decl)))
664             {
665               if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
666                               "function cannot be instrumented"))
667                 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
668             }
669         }
670     }
671
672   /* Mark all aliases and thunks of functions with no instrumented
673      version as legacy function.  */
674   FOR_EACH_DEFINED_FUNCTION (node)
675     {
676       if (!node->instrumentation_clone
677           && !node->instrumented_version
678           && (node->alias || node->thunk.thunk_p)
679           && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
680         DECL_ATTRIBUTES (node->decl)
681           = tree_cons (get_identifier ("bnd_legacy"), NULL,
682                        DECL_ATTRIBUTES (node->decl));
683     }
684
685   bitmap_obstack_release (NULL);
686
687   return 0;
688 }
689
690 /* In this pass we remove bodies of functions having
691    instrumented version.  Functions with removed bodies
692    become a special kind of thunks to provide a connection
693    between calls to the original version and instrumented
694    function.  */
695
696 static unsigned int
697 chkp_produce_thunks (bool early)
698 {
699   struct cgraph_node *node;
700
701   FOR_EACH_DEFINED_FUNCTION (node)
702     {
703       if (!node->instrumentation_clone
704           && node->instrumented_version
705           && gimple_has_body_p (node->decl)
706           && gimple_has_body_p (node->instrumented_version->decl)
707           && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
708               || !early))
709         {
710           node->release_body ();
711           node->remove_callees ();
712           node->remove_all_references ();
713
714           node->thunk.thunk_p = true;
715           node->thunk.add_pointer_bounds_args = true;
716           node->create_edge (node->instrumented_version, NULL,
717                              0, CGRAPH_FREQ_BASE);
718           node->create_reference (node->instrumented_version,
719                                IPA_REF_CHKP, NULL);
720           /* Thunk shouldn't be a cdtor.  */
721           DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
722           DECL_STATIC_DESTRUCTOR (node->decl) = 0;
723         }
724     }
725
726   /* Mark instrumentation clones created for aliases and thunks
727      as insttrumented so they could be removed as unreachable
728      now.  */
729   if (!early)
730     {
731       FOR_EACH_DEFINED_FUNCTION (node)
732       {
733         if (node->instrumentation_clone
734             && (node->alias || node->thunk.thunk_p)
735             && !chkp_function_instrumented_p (node->decl))
736           chkp_function_mark_instrumented (node->decl);
737       }
738     }
739
740   return TODO_remove_functions;
741 }
742
743 const pass_data pass_data_ipa_chkp_versioning =
744 {
745   SIMPLE_IPA_PASS, /* type */
746   "chkp_versioning", /* name */
747   OPTGROUP_NONE, /* optinfo_flags */
748   TV_NONE, /* tv_id */
749   0, /* properties_required */
750   0, /* properties_provided */
751   0, /* properties_destroyed */
752   0, /* todo_flags_start */
753   0 /* todo_flags_finish */
754 };
755
756 const pass_data pass_data_ipa_chkp_early_produce_thunks =
757 {
758   SIMPLE_IPA_PASS, /* type */
759   "chkp_ecleanup", /* name */
760   OPTGROUP_NONE, /* optinfo_flags */
761   TV_NONE, /* tv_id */
762   0, /* properties_required */
763   0, /* properties_provided */
764   0, /* properties_destroyed */
765   0, /* todo_flags_start */
766   0 /* todo_flags_finish */
767 };
768
769 const pass_data pass_data_ipa_chkp_produce_thunks =
770 {
771   SIMPLE_IPA_PASS, /* type */
772   "chkp_cleanup", /* name */
773   OPTGROUP_NONE, /* optinfo_flags */
774   TV_NONE, /* tv_id */
775   0, /* properties_required */
776   0, /* properties_provided */
777   0, /* properties_destroyed */
778   0, /* todo_flags_start */
779   0 /* todo_flags_finish */
780 };
781
782 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
783 {
784 public:
785   pass_ipa_chkp_versioning (gcc::context *ctxt)
786     : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
787   {}
788
789   /* opt_pass methods: */
790   virtual opt_pass * clone ()
791     {
792       return new pass_ipa_chkp_versioning (m_ctxt);
793     }
794
795   virtual bool gate (function *)
796     {
797       return flag_check_pointer_bounds;
798     }
799
800   virtual unsigned int execute (function *)
801     {
802       return chkp_versioning ();
803     }
804
805 }; // class pass_ipa_chkp_versioning
806
807 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
808 {
809 public:
810   pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
811     : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
812   {}
813
814   /* opt_pass methods: */
815   virtual opt_pass * clone ()
816     {
817       return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
818     }
819
820   virtual bool gate (function *)
821     {
822       return flag_check_pointer_bounds;
823     }
824
825   virtual unsigned int execute (function *)
826     {
827       return chkp_produce_thunks (true);
828     }
829
830 }; // class pass_chkp_produce_thunks
831
832 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
833 {
834 public:
835   pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
836     : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
837   {}
838
839   /* opt_pass methods: */
840   virtual opt_pass * clone ()
841     {
842       return new pass_ipa_chkp_produce_thunks (m_ctxt);
843     }
844
845   virtual bool gate (function *)
846     {
847       return flag_check_pointer_bounds;
848     }
849
850   virtual unsigned int execute (function *)
851     {
852       return chkp_produce_thunks (false);
853     }
854
855 }; // class pass_chkp_produce_thunks
856
857 simple_ipa_opt_pass *
858 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
859 {
860   return new pass_ipa_chkp_versioning (ctxt);
861 }
862
863 simple_ipa_opt_pass *
864 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
865 {
866   return new pass_ipa_chkp_early_produce_thunks (ctxt);
867 }
868
869 simple_ipa_opt_pass *
870 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
871 {
872   return new pass_ipa_chkp_produce_thunks (ctxt);
873 }