Import pre-release gcc-5.0 to new vendor branch
[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
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 }