bmake(1): complete update to version 20141111
[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 = copy_node (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             }
554           else
555             {
556               tree_function_versioning (fndecl, new_decl, NULL, false,
557                                         NULL, false, NULL, NULL);
558               clone->lowered = true;
559             }
560         }
561
562       /* New params are inserted after versioning because it
563          actually copies args list from the original decl.  */
564       chkp_add_bounds_params_to_function (new_decl);
565
566       /* Remember builtin fndecl.  */
567       if (DECL_BUILT_IN_CLASS (clone->decl) == BUILT_IN_NORMAL
568           && fndecl == builtin_decl_explicit (DECL_FUNCTION_CODE (fndecl)))
569         {
570           gcc_assert (!builtin_decl_explicit (DECL_FUNCTION_CODE (clone->decl)));
571           set_builtin_decl (DECL_FUNCTION_CODE (clone->decl),
572                             clone->decl, false);
573         }
574
575       /* Clones have the same comdat group as originals.  */
576       if (node->same_comdat_group
577           || DECL_ONE_ONLY (node->decl))
578         clone->add_to_same_comdat_group (node);
579
580       if (gimple_has_body_p (fndecl))
581         symtab->call_cgraph_insertion_hooks (clone);
582
583       /* Clone all aliases.  */
584       for (i = 0; node->iterate_direct_aliases (i, ref); i++)
585         {
586           struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
587           struct cgraph_node *chkp_alias
588             = chkp_maybe_create_clone (alias->decl);
589           chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
590         }
591
592       /* Clone all thunks.  */
593       for (e = node->callers; e; e = e->next_caller)
594         if (e->caller->thunk.thunk_p
595             && !e->caller->thunk.add_pointer_bounds_args)
596           {
597             struct cgraph_node *thunk
598               = chkp_maybe_create_clone (e->caller->decl);
599             /* Redirect thunk clone edge to the node clone.  */
600             thunk->callees->redirect_callee (clone);
601           }
602
603       /* For aliases and thunks we should make sure target is cloned
604          to have proper references and edges.  */
605       if (node->thunk.thunk_p)
606         chkp_maybe_create_clone (node->callees->callee->decl);
607       else if (node->alias)
608         {
609           struct cgraph_node *target;
610
611           ref = node->ref_list.first_reference ();
612           if (ref)
613             chkp_maybe_create_clone (ref->referred->decl);
614
615           if (node->alias_target)
616             {
617               if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
618                 {
619                   target = chkp_maybe_create_clone (node->alias_target);
620                   clone->alias_target = target->decl;
621                 }
622               else
623                 clone->alias_target = node->alias_target;
624             }
625         }
626
627       /* Add IPA reference.  It's main role is to keep instrumented
628          version reachable while original node is reachable.  */
629       ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
630     }
631
632   return clone;
633 }
634
635 /* Create clone for all functions to be instrumented.  */
636
637 static unsigned int
638 chkp_versioning (void)
639 {
640   struct cgraph_node *node;
641   const char *reason;
642
643   bitmap_obstack_initialize (NULL);
644
645   FOR_EACH_DEFINED_FUNCTION (node)
646     {
647       if (!node->instrumentation_clone
648           && !node->instrumented_version
649           && !node->alias
650           && !node->thunk.thunk_p
651           && (!DECL_BUILT_IN (node->decl)
652               || (DECL_BUILT_IN_CLASS (node->decl) == BUILT_IN_NORMAL
653                   && DECL_FUNCTION_CODE (node->decl) < BEGIN_CHKP_BUILTINS)))
654         {
655           if (chkp_instrumentable_p (node->decl))
656             chkp_maybe_create_clone (node->decl);
657           else if ((reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl),
658                                              node->decl)))
659             {
660               if (warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wchkp,
661                               "function cannot be instrumented"))
662                 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
663             }
664         }
665     }
666
667   /* Mark all aliases and thunks of functions with no instrumented
668      version as legacy function.  */
669   FOR_EACH_DEFINED_FUNCTION (node)
670     {
671       if (!node->instrumentation_clone
672           && !node->instrumented_version
673           && (node->alias || node->thunk.thunk_p)
674           && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
675         DECL_ATTRIBUTES (node->decl)
676           = tree_cons (get_identifier ("bnd_legacy"), NULL,
677                        DECL_ATTRIBUTES (node->decl));
678     }
679
680   bitmap_obstack_release (NULL);
681
682   return 0;
683 }
684
685 /* In this pass we remove bodies of functions having
686    instrumented version.  Functions with removed bodies
687    become a special kind of thunks to provide a connection
688    between calls to the original version and instrumented
689    function.  */
690
691 static unsigned int
692 chkp_produce_thunks (bool early)
693 {
694   struct cgraph_node *node;
695
696   FOR_EACH_DEFINED_FUNCTION (node)
697     {
698       if (!node->instrumentation_clone
699           && node->instrumented_version
700           && gimple_has_body_p (node->decl)
701           && gimple_has_body_p (node->instrumented_version->decl)
702           && (!lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))
703               || !early))
704         {
705           node->release_body ();
706           node->remove_callees ();
707           node->remove_all_references ();
708
709           node->thunk.thunk_p = true;
710           node->thunk.add_pointer_bounds_args = true;
711           node->create_edge (node->instrumented_version, NULL,
712                              0, CGRAPH_FREQ_BASE);
713           node->create_reference (node->instrumented_version,
714                                IPA_REF_CHKP, NULL);
715         }
716     }
717
718   /* Mark instrumentation clones created for aliases and thunks
719      as insttrumented so they could be removed as unreachable
720      now.  */
721   if (!early)
722     {
723       FOR_EACH_DEFINED_FUNCTION (node)
724       {
725         if (node->instrumentation_clone
726             && (node->alias || node->thunk.thunk_p)
727             && !chkp_function_instrumented_p (node->decl))
728           chkp_function_mark_instrumented (node->decl);
729       }
730     }
731
732   return TODO_remove_functions;
733 }
734
735 const pass_data pass_data_ipa_chkp_versioning =
736 {
737   SIMPLE_IPA_PASS, /* type */
738   "chkp_versioning", /* name */
739   OPTGROUP_NONE, /* optinfo_flags */
740   TV_NONE, /* tv_id */
741   0, /* properties_required */
742   0, /* properties_provided */
743   0, /* properties_destroyed */
744   0, /* todo_flags_start */
745   0 /* todo_flags_finish */
746 };
747
748 const pass_data pass_data_ipa_chkp_early_produce_thunks =
749 {
750   SIMPLE_IPA_PASS, /* type */
751   "chkp_ecleanup", /* name */
752   OPTGROUP_NONE, /* optinfo_flags */
753   TV_NONE, /* tv_id */
754   0, /* properties_required */
755   0, /* properties_provided */
756   0, /* properties_destroyed */
757   0, /* todo_flags_start */
758   0 /* todo_flags_finish */
759 };
760
761 const pass_data pass_data_ipa_chkp_produce_thunks =
762 {
763   SIMPLE_IPA_PASS, /* type */
764   "chkp_cleanup", /* name */
765   OPTGROUP_NONE, /* optinfo_flags */
766   TV_NONE, /* tv_id */
767   0, /* properties_required */
768   0, /* properties_provided */
769   0, /* properties_destroyed */
770   0, /* todo_flags_start */
771   0 /* todo_flags_finish */
772 };
773
774 class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
775 {
776 public:
777   pass_ipa_chkp_versioning (gcc::context *ctxt)
778     : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
779   {}
780
781   /* opt_pass methods: */
782   virtual opt_pass * clone ()
783     {
784       return new pass_ipa_chkp_versioning (m_ctxt);
785     }
786
787   virtual bool gate (function *)
788     {
789       return flag_check_pointer_bounds;
790     }
791
792   virtual unsigned int execute (function *)
793     {
794       return chkp_versioning ();
795     }
796
797 }; // class pass_ipa_chkp_versioning
798
799 class pass_ipa_chkp_early_produce_thunks : public simple_ipa_opt_pass
800 {
801 public:
802   pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
803     : simple_ipa_opt_pass (pass_data_ipa_chkp_early_produce_thunks, ctxt)
804   {}
805
806   /* opt_pass methods: */
807   virtual opt_pass * clone ()
808     {
809       return new pass_ipa_chkp_early_produce_thunks (m_ctxt);
810     }
811
812   virtual bool gate (function *)
813     {
814       return flag_check_pointer_bounds;
815     }
816
817   virtual unsigned int execute (function *)
818     {
819       return chkp_produce_thunks (true);
820     }
821
822 }; // class pass_chkp_produce_thunks
823
824 class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
825 {
826 public:
827   pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
828     : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
829   {}
830
831   /* opt_pass methods: */
832   virtual opt_pass * clone ()
833     {
834       return new pass_ipa_chkp_produce_thunks (m_ctxt);
835     }
836
837   virtual bool gate (function *)
838     {
839       return flag_check_pointer_bounds;
840     }
841
842   virtual unsigned int execute (function *)
843     {
844       return chkp_produce_thunks (false);
845     }
846
847 }; // class pass_chkp_produce_thunks
848
849 simple_ipa_opt_pass *
850 make_pass_ipa_chkp_versioning (gcc::context *ctxt)
851 {
852   return new pass_ipa_chkp_versioning (ctxt);
853 }
854
855 simple_ipa_opt_pass *
856 make_pass_ipa_chkp_early_produce_thunks (gcc::context *ctxt)
857 {
858   return new pass_ipa_chkp_early_produce_thunks (ctxt);
859 }
860
861 simple_ipa_opt_pass *
862 make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
863 {
864   return new pass_ipa_chkp_produce_thunks (ctxt);
865 }