This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH, Pointer Bounds Checker 14/x] Passes [2/n] IPA passes


On 10 Oct 13:14, Jeff Law wrote:
> On 10/08/14 12:55, Ilya Enkovich wrote:
> >Hi,
> >
> >This patch introduces two IPA passes used by Pointer Bounds Checker.  One pass creates clones for instrumentation.  The other one transforms unneeded functions into thunks.
> >
> >Thanks,
> >Ilya
> >--
> 2014-10-08  Ilya Enkovich  <ilya.enkovich@intel.com>
> 
> 	* ipa-chkp.c: New.
> 	* ipa-chkp.h: New.
> 	* Makefile.in (OBJS): Add ipa-chkp.o.
> 
> 
> >+    when linker reolution files are used.  Linker has no info about
> s/reolution/???
> 
> 
> >+    connection between original and instrumented function and
> >+    therefore we may wrongly decide (due to difference in assember
> s/assember/assembler/
> 
> 
> >+
> >+  /* We want called_as_built_in recall instrumented calls
> >+     to instrumented built-in functions.
> Sorry, I simply can't parse that sentence...  Can you rewrite/revise
> it to be clearer?
> 
> 
> 
> 
> >+
> >+  /* If function type has attribute with arg indexes then
> >+     we have to copy it fixing attribute ops.  Map for
> >+     fixing is in indexes array.  */
> >+  attrs = TYPE_ATTRIBUTES (type);
> >+  if (lookup_attribute ("nonnull", attrs)
> >+      || lookup_attribute ("format", attrs)
> >+      || lookup_attribute ("format_arg", attrs))
> So you need to adjust the indices in those attributes so that they
> refer to the right argument.  I get that.  My concern is how do we
> keep the list of attributes that must be fixed up-to-date.
> 
> I can easily see someone adding a new argument attribute and folks
> forgetting to update this code.
> 
> Seems to me we need to document the attribute code with a reference
> back to these ipa-chkp bits.  It's not foolproof, but it's better
> than depending on my memory to catch this stuff during reviews.
> 
> OK with the nits above fixed and a suitable comment that folks
> adding new attributes with parameter indices are likely to see to
> refer them back to the index adjustment code in ipa-chkp.c.
> 
> Thanks,
> Jeff
> 

Thanks for review!  Below is a fixed verison.  I added references to ipa-chkp into attributes tables descriptions.

Ilya
--
2014-10-13  Ilya Enkovich  <ilya.enkovich@intel.com>

	* ipa-chkp.c: New.
	* ipa-chkp.h: New.
	* Makefile.in (OBJS): Add ipa-chkp.o.
	* c-family/c-common.c (c_common_attribute_table): Fix documentation.
	(c_common_format_attribute_table): Likewsie.


diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3113a9f..d8c8488 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1253,6 +1253,7 @@ OBJS = \
 	incpath.o \
 	init-regs.o \
 	internal-fn.o \
+	ipa-chkp.o \
 	ipa-cp.o \
 	ipa-devirt.o \
 	ipa-split.o \
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 94b766f..cf35ec5 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -617,7 +617,12 @@ const struct c_common_resword c_common_reswords[] =
 const unsigned int num_c_common_reswords =
   sizeof c_common_reswords / sizeof (struct c_common_resword);
 
-/* Table of machine-independent attributes common to all C-like languages.  */
+/* Table of machine-independent attributes common to all C-like languages.
+
+   All attributes referencing arguments should be additionally processed
+   in chkp_copy_function_type_adding_bounds for correct instrumentation
+   by Pointer Bounds Checker.
+   Current list of processed common attributes: nonnull.  */
 const struct attribute_spec c_common_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
@@ -794,8 +799,12 @@ const struct attribute_spec c_common_attribute_table[] =
 };
 
 /* Give the specifications for the format attributes, used by C and all
-   descendants.  */
+   descendants.
 
+   All attributes referencing arguments should be additionally processed
+   in chkp_copy_function_type_adding_bounds for correct instrumentation
+   by Pointer Bounds Checker.
+   Current list of processed format attributes: format, format_arg.  */
 const struct attribute_spec c_common_format_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
new file mode 100644
index 0000000..d5c9502
--- /dev/null
+++ b/gcc/ipa-chkp.c
@@ -0,0 +1,623 @@
+/* Pointer Bounds Checker IPA passes.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "stringpool.h"
+#include "bitmap.h"
+#include "gimple-expr.h"
+#include "function.h"
+#include "tree-chkp.h"
+#include <string>
+
+/*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
+
+    In instrumented code each pointer is provided with bounds.  For input
+    pointer parameters it means we also have bounds passed.  For calls it
+    means we have additional bounds arguments for pointer arguments.
+
+    To have all IPA optimizations working correctly we have to express
+    dataflow between passed and received bounds explicitly via additional
+    entries in function declaration arguments list and in function type.
+    Since we may have both instrumented and not instrumented code at the
+    same time, we cannot replace all original functions with their
+    instrumented variants.  Therefore we create clones (versions) instead.
+
+    Instrumentation clones creation is a separate IPA pass which is a part
+    of early local passes.  Clones are created after SSA is built (because
+    instrumentation pass works on SSA) and before any transformations
+    which may change pointer flow and therefore lead to incorrect code
+    instrumentation (possibly causing false bounds check failures).
+
+    Instrumentation clones have pointer bounds arguments added right after
+    pointer arguments.  Clones have assembler name of the original
+    function with suffix added.  New assembler name is in transparent
+    alias chain with the original name.  Thus we expect all calls to the
+    original and instrumented functions look similar in assembler.
+
+    During instrumentation versioning pass we create instrumented versions
+    of all function with body and also for all their aliases and thunks.
+    Clones for functions with no body are created on demand (usually
+    during call instrumentation).
+
+    Original and instrumented function nodes are connected with IPA
+    reference IPA_REF_CHKP.  It is mostly done to have reachability
+    analysis working correctly.  We may have no references to the
+    instrumented function in the code but it still should be counted
+    as reachable if the original function is reachable.
+
+    When original function bodies are not needed anymore we release
+    them and transform functions into a special kind of thunks.  Each
+    thunk has a call edge to the instrumented version.  These thunks
+    help to keep externally visible instrumented functions visible
+    when linker resolution files are used.  Linker has no info about
+    connection between original and instrumented function and
+    therefore we may wrongly decide (due to difference in assembler
+    names) that instrumented function version is local and can be
+    removed.  */
+
+#define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_"
+
+/* Build a clone of FNDECL with a modified name.  */
+
+static tree
+chkp_build_instrumented_fndecl (tree fndecl)
+{
+  tree new_decl = copy_node (fndecl);
+  tree new_name;
+  std::string s;
+
+  /* called_as_built_in checks DECL_NAME to identify calls to
+     builtins.  We want instrumented calls to builtins to be
+     recognized by called_as_built_in.  Therefore use original
+     DECL_NAME for cloning with no prefixes.  */
+  s = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+  s += ".chkp";
+  DECL_NAME (new_decl) = get_identifier (s.c_str ());
+
+  /* References to the original and to the instrumented version
+     should look the same in the output assembly.  And we cannot
+     use the same assembler name for the instrumented version
+     because it conflicts with decl merging algorithms in LTO.
+     Achieve the result by using transparent alias name for the
+     instrumented version.  */
+  s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
+  s += ".chkp";
+  new_name = get_identifier (s.c_str ());
+  IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1;
+  TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl);
+  SET_DECL_ASSEMBLER_NAME (new_decl, new_name);
+
+  /* For functions with body versioning will make a copy of arguments.
+     For functions with no body we need to do it here.  */
+  if (!gimple_has_body_p (fndecl))
+    DECL_ARGUMENTS (new_decl) = copy_list (DECL_ARGUMENTS (fndecl));
+
+  /* We are going to modify attributes list and therefore should
+     make own copy.  */
+  DECL_ATTRIBUTES (new_decl) = copy_list (DECL_ATTRIBUTES (fndecl));
+
+  return new_decl;
+}
+
+
+/* Fix operands of attribute from ATTRS list named ATTR_NAME.
+   Integer operands are replaced with values according to
+   INDEXES map having LEN elements.  For operands out of len
+   we just add DELTA.  */
+
+static void
+chkp_map_attr_arg_indexes (tree attrs, const char *attr_name,
+			   unsigned *indexes, int len, int delta)
+{
+  tree attr = lookup_attribute (attr_name, attrs);
+  tree op;
+
+  if (!attr)
+    return;
+
+  TREE_VALUE (attr) = copy_list (TREE_VALUE (attr));
+  for (op = TREE_VALUE (attr); op; op = TREE_CHAIN (op))
+    {
+      int idx;
+
+      if (TREE_CODE (TREE_VALUE (op)) != INTEGER_CST)
+	continue;
+
+      idx = TREE_INT_CST_LOW (TREE_VALUE (op));
+
+      /* If idx exceeds indexes length then we just
+	 keep it at the same distance from the last
+	 known arg.  */
+      if (idx > len)
+	idx += delta;
+      else
+	idx = indexes[idx - 1] + 1;
+      TREE_VALUE (op) = build_int_cst (TREE_TYPE (TREE_VALUE (op)), idx);
+    }
+}
+
+/* Make a copy of function type ORIG_TYPE adding pointer
+   bounds as additional arguments.  */
+
+tree
+chkp_copy_function_type_adding_bounds (tree orig_type)
+{
+  tree type;
+  tree arg_type, attrs, t;
+  unsigned len = list_length (TYPE_ARG_TYPES (orig_type));
+  unsigned *indexes = XALLOCAVEC (unsigned, len);
+  unsigned idx = 0, new_idx = 0;
+
+  for (arg_type = TYPE_ARG_TYPES (orig_type);
+       arg_type;
+       arg_type = TREE_CHAIN (arg_type))
+    if (TREE_VALUE (arg_type) == void_type_node)
+      continue;
+    else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
+	     || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
+				   TREE_VALUE (arg_type), true)
+	     || chkp_type_has_pointer (TREE_VALUE (arg_type)))
+      break;
+
+  /* We may use original type if there are no bounds passed.  */
+  if (!arg_type)
+    return orig_type;
+
+  type = copy_node (orig_type);
+  TYPE_ARG_TYPES (type) = copy_list (TYPE_ARG_TYPES (type));
+
+  for (arg_type = TYPE_ARG_TYPES (type);
+       arg_type;
+       arg_type = TREE_CHAIN (arg_type))
+    {
+      indexes[idx++] = new_idx++;
+
+      /* pass_by_reference returns 1 for void type,
+	 so check for it first.  */
+      if (TREE_VALUE (arg_type) == void_type_node)
+	continue;
+      else if (BOUNDED_TYPE_P (TREE_VALUE (arg_type))
+	       || pass_by_reference (NULL, TYPE_MODE (TREE_VALUE (arg_type)),
+				     TREE_VALUE (arg_type), true))
+	{
+	  tree new_type = build_tree_list (NULL_TREE,
+					   pointer_bounds_type_node);
+	  TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
+	  TREE_CHAIN (arg_type) = new_type;
+
+	  arg_type = TREE_CHAIN (arg_type);
+	  new_idx++;
+	}
+      else if (chkp_type_has_pointer (TREE_VALUE (arg_type)))
+	{
+	  bitmap slots = chkp_find_bound_slots (TREE_VALUE (arg_type));
+	  bitmap_iterator bi;
+	  unsigned bnd_no;
+
+	  EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
+	    {
+	      tree new_type = build_tree_list (NULL_TREE,
+					       pointer_bounds_type_node);
+	      TREE_CHAIN (new_type) = TREE_CHAIN (arg_type);
+	      TREE_CHAIN (arg_type) = new_type;
+
+	      arg_type = TREE_CHAIN (arg_type);
+	      new_idx++;
+	    }
+	  BITMAP_FREE (slots);
+	}
+    }
+
+  /* If function type has attribute with arg indexes then
+     we have to copy it fixing attribute ops.  Map for
+     fixing is in indexes array.  */
+  attrs = TYPE_ATTRIBUTES (type);
+  if (lookup_attribute ("nonnull", attrs)
+      || lookup_attribute ("format", attrs)
+      || lookup_attribute ("format_arg", attrs))
+    {
+      int delta = new_idx - len;
+      attrs = copy_list (TYPE_ATTRIBUTES (type));
+      chkp_map_attr_arg_indexes (attrs, "nonnull", indexes, len, delta);
+      chkp_map_attr_arg_indexes (attrs, "format", indexes, len, delta);
+      chkp_map_attr_arg_indexes (attrs, "format_arg", indexes, len, delta);
+      TYPE_ATTRIBUTES (type) = attrs;
+    }
+
+  t = TYPE_MAIN_VARIANT (orig_type);
+  if (orig_type != t)
+    {
+      TYPE_MAIN_VARIANT (type) = t;
+      TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (t);
+      TYPE_NEXT_VARIANT (t) = type;
+    }
+  else
+    {
+      TYPE_MAIN_VARIANT (type) = type;
+      TYPE_NEXT_VARIANT (type) = NULL;
+    }
+
+
+  return type;
+}
+
+/* For given function FNDECL add bounds arguments to arguments
+   list.  */
+
+static void
+chkp_add_bounds_params_to_function (tree fndecl)
+{
+  tree arg;
+
+  for (arg = DECL_ARGUMENTS (fndecl); arg; arg = DECL_CHAIN (arg))
+    if (BOUNDED_P (arg))
+      {
+	std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
+	tree new_arg;
+
+	if (DECL_NAME (arg))
+	  new_name += IDENTIFIER_POINTER (DECL_NAME (arg));
+	else
+	  {
+	    char uid[25];
+	    snprintf (uid, 25, "D.%u", DECL_UID (arg));
+	    new_name += uid;
+	  }
+
+	new_arg = build_decl (DECL_SOURCE_LOCATION (arg), PARM_DECL,
+			      get_identifier (new_name.c_str ()),
+			      pointer_bounds_type_node);
+	DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
+	DECL_CONTEXT (new_arg) = DECL_CONTEXT (arg);
+	DECL_ARTIFICIAL (new_arg) = 1;
+	DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
+	DECL_CHAIN (arg) = new_arg;
+
+	arg = DECL_CHAIN (arg);
+
+      }
+    else if (chkp_type_has_pointer (TREE_TYPE (arg)))
+      {
+	tree orig_arg = arg;
+	bitmap slots = chkp_find_bound_slots (TREE_TYPE (arg));
+	bitmap_iterator bi;
+	unsigned bnd_no;
+
+	EXECUTE_IF_SET_IN_BITMAP (slots, 0, bnd_no, bi)
+	  {
+	    std::string new_name = CHKP_BOUNDS_OF_SYMBOL_PREFIX;
+	    tree new_arg;
+	    char offs[25];
+
+	    if (DECL_NAME (orig_arg))
+	      new_name += IDENTIFIER_POINTER (DECL_NAME (orig_arg));
+	    else
+	      {
+		snprintf (offs, 25, "D.%u", DECL_UID (arg));
+		new_name += offs;
+	      }
+	    snprintf (offs, 25, "__%u", bnd_no * POINTER_SIZE / BITS_PER_UNIT);
+
+	    new_arg = build_decl (DECL_SOURCE_LOCATION (orig_arg),
+				  PARM_DECL,
+				  get_identifier (new_name.c_str ()),
+				  pointer_bounds_type_node);
+	    DECL_ARG_TYPE (new_arg) = pointer_bounds_type_node;
+	    DECL_CONTEXT (new_arg) = DECL_CONTEXT (orig_arg);
+	    DECL_ARTIFICIAL (new_arg) = 1;
+	    DECL_CHAIN (new_arg) = DECL_CHAIN (arg);
+	    DECL_CHAIN (arg) = new_arg;
+
+	    arg = DECL_CHAIN (arg);
+	  }
+	BITMAP_FREE (slots);
+      }
+
+  TREE_TYPE (fndecl) =
+    chkp_copy_function_type_adding_bounds (TREE_TYPE (fndecl));
+}
+
+/* Return clone created for instrumentation of NODE or NULL.  */
+
+cgraph_node *
+chkp_maybe_create_clone (tree fndecl)
+{
+  cgraph_node *node = cgraph_node::get_create (fndecl);
+  cgraph_node *clone = node->instrumented_version;
+
+  gcc_assert (!node->instrumentation_clone);
+
+  if (!clone)
+    {
+      tree new_decl = chkp_build_instrumented_fndecl (fndecl);
+      struct cgraph_edge *e;
+      struct ipa_ref *ref;
+      int i;
+
+      clone = node->create_version_clone (new_decl, vNULL, NULL);
+      clone->externally_visible = node->externally_visible;
+      clone->local = node->local;
+      clone->address_taken = node->address_taken;
+      clone->thunk = node->thunk;
+      clone->alias = node->alias;
+      clone->weakref = node->weakref;
+      clone->cpp_implicit_alias = node->cpp_implicit_alias;
+      clone->instrumented_version = node;
+      clone->orig_decl = fndecl;
+      clone->instrumentation_clone = true;
+      node->instrumented_version = clone;
+
+      if (gimple_has_body_p (fndecl))
+	{
+	  /* If function will not be instrumented, then it's instrumented
+	     version is a thunk for the original.  */
+	  if (lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (fndecl))
+	      || (flag_chkp_instrument_marked_only
+		  && !lookup_attribute ("bnd_instrument", DECL_ATTRIBUTES (fndecl))))
+	    {
+	      clone->thunk.thunk_p = true;
+	      clone->thunk.add_pointer_bounds_args = true;
+	      clone->create_edge (node, NULL, 0, CGRAPH_FREQ_BASE);
+	    }
+	  else
+	    {
+	      tree_function_versioning (fndecl, new_decl, NULL, false,
+					NULL, false, NULL, NULL);
+	      clone->lowered = true;
+	    }
+	}
+
+      /* New params are inserted after versioning because it
+	 actually copies args list from the original decl.  */
+      chkp_add_bounds_params_to_function (new_decl);
+
+      /* Clones have the same comdat group as originals.  */
+      if (node->same_comdat_group
+	  || DECL_ONE_ONLY (node->decl))
+	clone->add_to_same_comdat_group (node);
+
+      if (gimple_has_body_p (fndecl))
+	symtab->call_cgraph_insertion_hooks (clone);
+
+      /* Clone all aliases.  */
+      for (i = 0; node->iterate_referring (i, ref); i++)
+	if (ref->use == IPA_REF_ALIAS)
+	  {
+	    struct cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
+	    struct cgraph_node *chkp_alias
+	      = chkp_maybe_create_clone (alias->decl);
+	    chkp_alias->create_reference (clone, IPA_REF_ALIAS, NULL);
+	  }
+
+      /* Clone all thunks.  */
+      for (e = node->callers; e; e = e->next_caller)
+	if (e->caller->thunk.thunk_p)
+	  {
+	    struct cgraph_node *thunk
+	      = chkp_maybe_create_clone (e->caller->decl);
+	    /* Redirect thunk clone edge to the node clone.  */
+	    thunk->callees->redirect_callee (clone);
+	  }
+
+      /* For aliases and thunks we should make sure target is cloned
+	 to have proper references and edges.  */
+      if (node->thunk.thunk_p)
+	chkp_maybe_create_clone (node->callees->callee->decl);
+      else if (node->alias)
+	{
+	  struct cgraph_node *target;
+
+	  ref = node->ref_list.first_reference ();
+	  if (ref)
+	    chkp_maybe_create_clone (ref->referred->decl);
+
+	  if (node->alias_target)
+	    {
+	      if (TREE_CODE (node->alias_target) == FUNCTION_DECL)
+		{
+		  target = chkp_maybe_create_clone (node->alias_target);
+		  clone->alias_target = target->decl;
+		}
+	      else
+		clone->alias_target = node->alias_target;
+	    }
+	}
+
+      /* Add IPA reference.  It's main role is to keep instrumented
+	 version reachable while original node is reachable.  */
+      ref = node->create_reference (clone, IPA_REF_CHKP, NULL);
+    }
+
+  return clone;
+}
+
+/* Create clone for all functions to be instrumented.  */
+
+static unsigned int
+chkp_versioning (void)
+{
+  struct cgraph_node *node;
+
+  FOR_EACH_DEFINED_FUNCTION (node)
+    {
+      if (!node->instrumentation_clone
+	  && !node->instrumented_version
+	  && !node->alias
+	  && !node->thunk.thunk_p
+	  && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl))
+	  && (!flag_chkp_instrument_marked_only
+	      || lookup_attribute ("bnd_instrument",
+				   DECL_ATTRIBUTES (node->decl)))
+	  /* No builtins instrumentation for now.  */
+	  && DECL_BUILT_IN_CLASS (node->decl) == NOT_BUILT_IN)
+	chkp_maybe_create_clone (node->decl);
+    }
+
+  /* Mark all aliases and thunks of functions with no instrumented
+     version as legacy function.  */
+  FOR_EACH_DEFINED_FUNCTION (node)
+    {
+      if (!node->instrumentation_clone
+	  && !node->instrumented_version
+	  && (node->alias || node->thunk.thunk_p)
+	  && !lookup_attribute ("bnd_legacy", DECL_ATTRIBUTES (node->decl)))
+	DECL_ATTRIBUTES (node->decl)
+	  = tree_cons (get_identifier ("bnd_legacy"), NULL,
+		       DECL_ATTRIBUTES (node->decl));
+    }
+
+  return 0;
+}
+
+/* In this pass we remove bodies of functions having
+   instrumented version.  Functions with removed bodies
+   become a special kind of thunks to provide a connection
+   between calls to the original version and instrumented
+   function.  */
+
+static unsigned int
+chkp_produce_thunks (void)
+{
+  struct cgraph_node *node;
+
+  FOR_EACH_DEFINED_FUNCTION (node)
+    {
+      if (!node->instrumentation_clone
+	  && node->instrumented_version
+	  && gimple_has_body_p (node->decl)
+	  && gimple_has_body_p (node->instrumented_version->decl))
+	{
+	  node->release_body ();
+	  node->remove_callees ();
+	  node->remove_all_references ();
+
+	  node->thunk.thunk_p = true;
+	  node->thunk.add_pointer_bounds_args = true;
+	  node->create_edge (node->instrumented_version, NULL,
+			     0, CGRAPH_FREQ_BASE);
+	  node->create_reference (node->instrumented_version,
+			       IPA_REF_CHKP, NULL);
+	}
+    }
+
+  /* Mark instrumentation clones created for aliases and thunks
+     as insttrumented so they could be removed as unreachable
+     now.  */
+  FOR_EACH_DEFINED_FUNCTION (node)
+    {
+      if (node->instrumentation_clone
+	  && (node->alias || node->thunk.thunk_p)
+	  && !chkp_function_instrumented_p (node->decl))
+	chkp_function_mark_instrumented (node->decl);
+    }
+
+  symtab->remove_unreachable_nodes (true, dump_file);
+
+  return 0;
+}
+
+const pass_data pass_data_ipa_chkp_versioning =
+{
+  SIMPLE_IPA_PASS, /* type */
+  "chkp_versioning", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0 /* todo_flags_finish */
+};
+
+const pass_data pass_data_ipa_chkp_produce_thunks =
+{
+  SIMPLE_IPA_PASS, /* type */
+  "chkp_cleanup", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0 /* todo_flags_finish */
+};
+
+class pass_ipa_chkp_versioning : public simple_ipa_opt_pass
+{
+public:
+  pass_ipa_chkp_versioning (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_ipa_chkp_versioning, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual opt_pass * clone ()
+    {
+      return new pass_ipa_chkp_versioning (m_ctxt);
+    }
+
+  virtual bool gate (function *)
+    {
+      return flag_check_pointer_bounds;
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return chkp_versioning ();
+    }
+
+}; // class pass_ipa_chkp_versioning
+
+class pass_ipa_chkp_produce_thunks : public simple_ipa_opt_pass
+{
+public:
+  pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
+    : simple_ipa_opt_pass (pass_data_ipa_chkp_produce_thunks, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual opt_pass * clone ()
+    {
+      return new pass_ipa_chkp_produce_thunks (m_ctxt);
+    }
+
+  virtual unsigned int execute (function *)
+    {
+      return chkp_produce_thunks ();
+    }
+
+}; // class pass_chkp_produce_thunks
+
+simple_ipa_opt_pass *
+make_pass_ipa_chkp_versioning (gcc::context *ctxt)
+{
+  return new pass_ipa_chkp_versioning (ctxt);
+}
+
+simple_ipa_opt_pass *
+make_pass_ipa_chkp_produce_thunks (gcc::context *ctxt)
+{
+  return new pass_ipa_chkp_produce_thunks (ctxt);
+}
diff --git a/gcc/ipa-chkp.h b/gcc/ipa-chkp.h
new file mode 100644
index 0000000..9c92c04
--- /dev/null
+++ b/gcc/ipa-chkp.h
@@ -0,0 +1,29 @@
+/* Declaration of interface functions of Pointer Bounds Checker.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_IPA_CHKP_H
+#define GCC_IPA_CHKP_H
+
+#include "tree.h"
+#include "cgraph.h"
+
+extern tree chkp_copy_function_type_adding_bounds (tree orig_type);
+extern cgraph_node *chkp_maybe_create_clone (tree fndecl);
+
+#endif /* GCC_IPA_CHKP_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]