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