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] Caller instrumentation with -finstrument-calls


Hi Andrew,

On Friday 28 June 2013 09:50:31 Andrew Pinski wrote:
> On Fri, Jun 28, 2013 at 5:51 AM,  <Paul_Woegerer@mentor.com> wrote:
> > Hi,
> > 
> > The patch below provides caller instrumentation for GCC.
> > 
> > The following new options have been added:
> >     -finstrument-calls
> >     -finstrument-calls-exclude-function-list=SYM,SYM,...
> >     -finstrument-calls-exclude-file-list=FILE,FILE,...
> > 
> > These new options behave and appear similar to the existing function
> > instrumentation options (-finstrument-functions*). I have also added
> > attribute no_instrument_calls to specify which functions should be
> > excluded from within the source code. Calls to functions that have
> > attribute no_instrument_function are also excluded.
> > 
> > The effect of the instrumentation causes all calls inside a function
> > 
> > to get instrumented using the following hooks:
> >     void __cyg_profile_call_before (void *fn);
> >     void __cyg_profile_call_after  (void *fn);
> 
> Can you not use cyg as the prefix rather use gcc or gnu.  cyg prefix
> for -finstrument-functions is a historical accident as it stands for
> cygnus but that company no longer exists and we should not be using a
> company specific prefix inside of GCC anymore.

Ha, funny. Originally I had the hooks with __gnu_profile_call_* but
then I changed them to be consistent with the existing __cyg_profile_*
hooks.

Anyway, here is the updated patch:


>From 43a1c2fb43e406f8f547dbcde19a60a8c56423a4 Mon Sep 17 00:00:00 2001
From: Paul Woegerer <paul_woegerer@mentor.com>
Date: Mon, 1 Jul 2013 09:15:21 +0200
Subject: [PATCH] Caller instrumentation with -finstrument-calls.

2013-07-01  Paul Woegerer  <paul_woegerer@mentor.com>

	Caller instrumentation with -finstrument-calls.
	* gcc/builtins.def: Add call-hooks __gnu_profile_call_before and
	__gnu_profile_call_after.
	* gcc/libfuncs.h (enum libfunc_index): Likewise.
	* gcc/optabs.c (init_optabs): Likewise.
	* gcc/c-family/c-common.c (no_instrument_calls): Add attribute.
	(handle_no_instrument_calls_attribute): New.
	* gcc/common.opt (finstrument-calls): New option.
	(finstrument-calls-exclude-function-list): Likewise.
	(finstrument-calls-exclude-file-list): Likewise.
	* gcc/opts.c (common_handle_option): Handle new options.
	* gcc/tree.h (tree_function_decl): Add field tree_function_decl.
	* gcc/c/c-decl.c (merge_decls): Handle tree_function_decl field.
	* gcc/cp/decl.c (duplicate_decls): Likewise.
	* gcc/function.c (expand_function_start): Likewise.
	* gcc/ipa.c: Likewise.
	* gcc/java/jcf-parse.c: Likewise.
	* gcc/tree-streamer-in.c: Likewise.
	* gcc/tree-streamer-out.c: Likewise.
	(finstrument-calls-exclude-function-list): Likewise.
	(finstrument-calls-exclude-file-list): Likewise.
	* gcc/gimplify.c (flag_instrument_calls_exclude_p): New.
	(addr_expr_for_call_instrumentation): New.
	(maybe_add_profile_call): New.
	(gimplify_call_expr): Add call-hooks insertion.
	(gimplify_modify_expr): Likewise.
	* gcc/doc/invoke.texi: Added documentation for
	-finstrument-calls-exclude-function-list and
	-finstrument-calls-exclude-file-list and
	-finstrument-calls.
	* gcc/testsuite/g++.dg/other/instrument_calls-1.C  Added
	 regression test for -finstrument-calls.
	* gcc/testsuite/g++.dg/other/instrument_calls-2.C: Likewise.
	* gcc/testsuite/g++.dg/other/instrument_calls-3.C: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-1.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-2.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-3.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-4.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-5.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-6.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-7.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-8.c: Likewise.
	* gcc/testsuite/gcc.dg/instrument_calls-9.c: Likewise.

diff --git a/gcc/builtins.def b/gcc/builtins.def
index 9b55b1f..0c2a6b2 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -795,6 +795,11 @@ DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_ENTER, "__cyg_profile_func_enter", BUILT_IN_N
 DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_EXIT, "__cyg_profile_func_exit", BUILT_IN_NORMAL, BT_FN_VOID_PTR_PTR, BT_LAST,
 	     false, false, false, ATTR_NULL, true, true)
 
+DEF_BUILTIN (BUILT_IN_PROFILE_CALL_BEFORE, "__gnu_profile_call_before", BUILT_IN_NORMAL, BT_FN_VOID_PTR, BT_LAST,
+	     false, false, false, ATTR_NULL, true, true)
+DEF_BUILTIN (BUILT_IN_PROFILE_CALL_AFTER, "__gnu_profile_call_after", BUILT_IN_NORMAL, BT_FN_VOID_PTR, BT_LAST,
+	     false, false, false, ATTR_NULL, true, true)
+
 /* TLS thread pointer related builtins.  */
 DEF_BUILTIN (BUILT_IN_THREAD_POINTER, "__builtin_thread_pointer",
 	     BUILT_IN_NORMAL, BT_FN_PTR, BT_LAST,
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 8f7f5e5..f3ad003 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -343,6 +343,8 @@ static tree handle_tls_model_attribute (tree *, tree, tree, int,
 					bool *);
 static tree handle_no_instrument_function_attribute (tree *, tree,
 						     tree, int, bool *);
+static tree handle_no_instrument_calls_attribute (tree *, tree,
+						     tree, int, bool *);
 static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
 static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_limit_stack_attribute (tree *, tree, tree, int,
@@ -658,6 +660,9 @@ const struct attribute_spec c_common_attribute_table[] =
   { "no_instrument_function", 0, 0, true,  false, false,
 			      handle_no_instrument_function_attribute,
 			      false },
+  { "no_instrument_calls", 0, 0, true,  false, false,
+			      handle_no_instrument_calls_attribute,
+			      false },
   { "malloc",                 0, 0, true,  false, false,
 			      handle_malloc_attribute, false },
   { "returns_twice",          0, 0, true,  false, false,
@@ -7891,6 +7896,35 @@ handle_no_instrument_function_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Handle a "no_instrument_calls" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_no_instrument_calls_attribute (tree *node, tree name,
+					 tree ARG_UNUSED (args),
+					 int ARG_UNUSED (flags),
+					 bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"%qE attribute applies only to functions", name);
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"can%'t set %qE attribute after definition", name);
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
+
+  return NULL_TREE;
+}
+
 /* Handle a "malloc" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 8170a80..4657e48 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -2287,6 +2287,8 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+	  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (newdecl)
+	    |= DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
 	  DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
diff --git a/gcc/common.opt b/gcc/common.opt
index 4c7933e..90cb06d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -93,7 +93,7 @@ int flag_gen_aux_info = 0
 Variable
 int flag_shlib
 
-; These two are really VEC(char_p,heap) *.
+; These four are really VEC(char_p,heap) *.
 
 Variable
 void *flag_instrument_functions_exclude_functions
@@ -101,6 +101,12 @@ void *flag_instrument_functions_exclude_functions
 Variable
 void *flag_instrument_functions_exclude_files
 
+Variable
+void *flag_instrument_calls_exclude_functions
+
+Variable
+void *flag_instrument_calls_exclude_files
+
 ; Generic structs (e.g. templates not explicitly specialized)
 ; may not have a compilation unit associated with them, and so
 ; may need to be treated differently from ordinary structs.
@@ -1364,6 +1370,18 @@ finstrument-functions-exclude-file-list=
 Common RejectNegative Joined
 -finstrument-functions-exclude-file-list=filename,...  Do not instrument functions listed in files
 
+finstrument-calls
+Common Report Var(flag_instrument_calls_before_after)
+Instrument call entry and exit with profiling calls
+
+finstrument-calls-exclude-function-list=
+Common RejectNegative Joined
+-finstrument-calls-exclude-function-list=name,...  Do not instrument calls from listed functions
+
+finstrument-calls-exclude-file-list=
+Common RejectNegative Joined
+-finstrument-calls-exclude-file-list=filename,...  Do not instrument calls from functions listed in files
+
 fipa-cp
 Common Report Var(flag_ipa_cp) Optimization
 Perform Interprocedural constant propagation
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 047fd77..9a02012 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1971,6 +1971,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 	{
 	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
 	    |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+	  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (newdecl)
+	    |= DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (olddecl);
 	  DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
 	  TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
 	  TREE_NOTHROW (newdecl) |= TREE_NOTHROW (olddecl);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 1496d30..6589a41 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -1015,6 +1015,9 @@ See S/390 and zSeries Options.
 -finhibit-size-directive  -finstrument-functions @gol
 -finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol
 -finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{} @gol
+-finstrument-calls @gol
+-finstrument-calls-exclude-function-list=@var{sym},@var{sym},@dots{} @gol
+-finstrument-calls-exclude-file-list=@var{file},@var{file},@dots{} @gol
 -fno-common  -fno-ident @gol
 -fpcc-struct-return  -fpic  -fPIC -fpie -fPIE @gol
 -fno-jump-tables @gol
@@ -20706,6 +20709,45 @@ of the function name, it is considered to be a match.  For C99 and C++
 extended identifiers, the function name must be given in UTF-8, not
 using universal character names.
 
+@item -finstrument-calls
+@opindex finstrument-calls
+Generate instrumentation calls immediately before and after each
+function call. The following profiling functions will be called with
+the address of the function that is called between them. Use
+@code{__builtin_return_address(0)} inside the profiling functions to
+get the addresses from where they are called.
+
+@smallexample
+void __gnu_profile_call_before (void *fn);
+void __gnu_profile_call_after  (void *fn);
+@end smallexample
+
+A function may be given attribute @code{no_instrument_calls}, in which
+case the instrumentation is omitted (no calls within that function will
+be instrumented). 
+
+In addition, calls to functions which have been given attribute
+@code{no_instrument_function} (or selected via
+@code{-finstrument-functions-exclude} options) are also excluded from
+instrumentation.
+
+@item -finstrument-calls-exclude-file-list=@var{file},@var{file},@dots{}
+@opindex finstrument-calls-exclude-file-list
+
+Set the list of functions that are excluded from instrumentation (see
+the description of @code{-finstrument-calls}).  If the file that
+contains a function definition matches with one of @var{file}, then
+the calls in that function are not instrumented.  The match is done on
+substrings as for @code{-finstrument-functions-exclude-file-list}.
+
+@item -finstrument-calls-exclude-function-list=@var{sym},@var{sym},@dots{}
+@opindex finstrument-calls-exclude-function-list
+
+This is similar to @code{-finstrument-calls-exclude-file-list},
+but this option sets the list of function names to be excluded from
+instrumentation.  The function name to be matched in the same way as for
+@code{-finstrument-functions-exclude-function-list}
+
 @item -fstack-check
 @opindex fstack-check
 Generate code to verify that you do not go beyond the boundary of the
diff --git a/gcc/function.c b/gcc/function.c
index 3e33fc7..7290d76 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4728,7 +4728,8 @@ expand_function_start (tree subr)
 
   crtl->profile
     = (profile_flag
-       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr)
+       && ! DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (subr));
 
   crtl->limit_stack
     = (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index e2ae893..8401278 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -89,6 +89,8 @@ static struct gimplify_omp_ctx *gimplify_omp_ctxp;
 
 /* Forward declaration.  */
 static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, bool);
+static bool flag_instrument_calls_exclude_p (tree fndecl);
+static bool flag_instrument_functions_exclude_p (tree fndecl);
 
 /* Mark X addressable.  Unlike the langhook we expect X to be in gimple
    form and we don't do any syntax checking.  */
@@ -1153,6 +1155,63 @@ build_stack_save_restore (gimple *save, gimple *restore)
 			 1, tmp_var);
 }
 
+/* Returns the function decl that corresponds the function called in
+   CALL_EXPR if call instrumentation is enabled.  */
+
+static tree
+addr_expr_for_call_instrumentation (tree call_expr)
+{
+  tree addr_expr = NULL_TREE;
+
+  if (!gimplify_ctxp->into_ssa && flag_instrument_calls_before_after
+      && !DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (current_function_decl)
+      && !flag_instrument_calls_exclude_p (current_function_decl))
+    {
+      tree fndecl = get_callee_fndecl (call_expr);
+      if (fndecl)
+        {
+	  if (!DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
+	      && !flag_instrument_functions_exclude_p (fndecl))
+	    {
+	      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+		      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_APPLY
+		      && call_expr_nargs (call_expr) > 0)
+		  addr_expr = CALL_EXPR_ARG (call_expr, 0);
+	      else if (!DECL_IS_BUILTIN (fndecl))
+		  addr_expr = build_fold_addr_expr (fndecl);
+	    }
+        }
+      else
+	  addr_expr = CALL_EXPR_FN (call_expr);
+    }
+
+  if (addr_expr)
+    {
+      if (TREE_CODE (addr_expr) == OBJ_TYPE_REF)
+	addr_expr = OBJ_TYPE_REF_EXPR (addr_expr);
+      else if (!is_gimple_val (addr_expr))
+	addr_expr = NULL_TREE;
+    }
+
+  return addr_expr;
+}
+
+/* Prepare call to PROFILE_CALL_* builtin (specified by CODE) for
+   function with decl FNDECL and add it to the sequence of GIMPLE
+   statements in PRE_P.  */
+
+static void
+maybe_add_profile_call (tree addr_expr, enum built_in_function code,
+			gimple_seq *pre_p)
+{
+  if (addr_expr)
+    {
+      tree x = builtin_decl_implicit (code);
+      gimple call = gimple_build_call (x, 1, addr_expr);
+      gimplify_seq_add_stmt (pre_p, call);
+    }
+}
+
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
 
 static enum gimplify_status
@@ -2684,15 +2743,22 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
      gimplify_modify_expr.  */
   if (!want_value)
     {
+      tree addr_expr = addr_expr_for_call_instrumentation (*expr_p);
+      gimple_stmt_iterator gsi;
+
+      maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_BEFORE, pre_p);
+
       /* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
 	 have to do is replicate it as a GIMPLE_CALL tuple.  */
-      gimple_stmt_iterator gsi;
       call = gimple_build_call_from_tree (*expr_p);
       gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
       notice_special_calls (call);
       gimplify_seq_add_stmt (pre_p, call);
       gsi = gsi_last (*pre_p);
       fold_stmt (&gsi);
+
+      maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_AFTER, pre_p);
+
       *expr_p = NULL_TREE;
     }
   else
@@ -4793,6 +4859,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
   gimple assign;
   location_t loc = EXPR_LOCATION (*expr_p);
   gimple_stmt_iterator gsi;
+  tree addr_expr = NULL_TREE;
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
 	      || TREE_CODE (*expr_p) == INIT_EXPR);
@@ -4922,9 +4989,13 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   if (TREE_CODE (*from_p) == CALL_EXPR)
     {
+      tree fnptrtype;
+
+      addr_expr = addr_expr_for_call_instrumentation (*from_p);
+
       /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
 	 instead of a GIMPLE_ASSIGN.  */
-      tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
+      fnptrtype = TREE_TYPE (CALL_EXPR_FN (*from_p));
       CALL_EXPR_FN (*from_p) = TREE_OPERAND (CALL_EXPR_FN (*from_p), 0);
       STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
       assign = gimple_build_call_from_tree (*from_p);
@@ -4945,7 +5016,9 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       gcc_assert (TREE_CODE (*to_p) == SSA_NAME);
     }
 
+  maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_BEFORE, pre_p);
   gimplify_seq_add_stmt (pre_p, assign);
+  maybe_add_profile_call (addr_expr, BUILT_IN_PROFILE_CALL_AFTER, pre_p);
   gsi = gsi_last (*pre_p);
   fold_stmt (&gsi);
 
@@ -8284,6 +8357,42 @@ flag_instrument_functions_exclude_p (tree fndecl)
   return false;
 }
 
+/* Return whether we should exclude FNDECL from call instrumentation.  */
+
+static bool
+flag_instrument_calls_exclude_p (tree fndecl)
+{
+  vec<char_p> *v;
+
+  v = (vec<char_p> *) flag_instrument_calls_exclude_functions;
+  if (v && v->length () > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = lang_hooks.decl_printable_name (fndecl, 0);
+      FOR_EACH_VEC_ELT (*v, i, s)
+	if (strstr (name, s) != NULL)
+	  return true;
+    }
+
+  v = (vec<char_p> *) flag_instrument_calls_exclude_files;
+  if (v && v->length () > 0)
+    {
+      const char *name;
+      int i;
+      char *s;
+
+      name = DECL_SOURCE_FILE (fndecl);
+      FOR_EACH_VEC_ELT (*v, i, s)
+	if (strstr (name, s) != NULL)
+	  return true;
+    }
+
+  return false;
+}
+
 /* Entry point to the gimplification pass.  FNDECL is the FUNCTION_DECL
    node for the function we want to gimplify.
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 7c0d495..b62b301 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -1429,6 +1429,7 @@ cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final)
   TREE_USED (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
   DECL_SAVED_TREE (decl) = body;
   if (!targetm.have_ctors_dtors && final)
     {
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index fbd4e00..5ead4a6 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -1715,6 +1715,7 @@ java_emit_static_constructor (void)
       TREE_USED (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
       DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
+      DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (decl) = 1;
       DECL_SAVED_TREE (decl) = body;
       DECL_UNINLINABLE (decl) = 1;
 
diff --git a/gcc/libfuncs.h b/gcc/libfuncs.h
index 04a4dc2..4c7faa4 100644
--- a/gcc/libfuncs.h
+++ b/gcc/libfuncs.h
@@ -40,6 +40,9 @@ enum libfunc_index
   LTI_profile_function_entry,
   LTI_profile_function_exit,
 
+  LTI_profile_call_before,
+  LTI_profile_call_after,
+
   LTI_synchronize,
 
   LTI_gcov_flush,
@@ -98,6 +101,9 @@ extern struct target_libfuncs *this_target_libfuncs;
 #define profile_function_entry_libfunc	(libfunc_table[LTI_profile_function_entry])
 #define profile_function_exit_libfunc	(libfunc_table[LTI_profile_function_exit])
 
+#define profile_call_before_libfunc	(libfunc_table[LTI_profile_call_before])
+#define profile_call_after_libfunc	(libfunc_table[LTI_profile_call_after])
+
 #define synchronize_libfunc	(libfunc_table[LTI_synchronize])
 
 #define gcov_flush_libfunc	(libfunc_table[LTI_gcov_flush])
diff --git a/gcc/optabs.c b/gcc/optabs.c
index a3051ad..04d149c 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -6202,6 +6202,12 @@ init_optabs (void)
   profile_function_exit_libfunc
     = init_one_libfunc ("__cyg_profile_func_exit");
 
+  /* For call before/after instrumentation.  */
+  profile_call_before_libfunc
+    = init_one_libfunc ("__gnu_profile_call_before");
+  profile_call_after_libfunc
+    = init_one_libfunc ("__gnu_profile_call_after");
+
   gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
 
   /* Allow the target to add more libcalls or rename some, etc.  */
diff --git a/gcc/opts.c b/gcc/opts.c
index 6856c3c..14bb78d 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1540,6 +1540,16 @@ common_handle_option (struct gcc_options *opts,
 	(&opts->x_flag_instrument_functions_exclude_files, arg);
       break;
 
+    case OPT_finstrument_calls_exclude_function_list_:
+      add_comma_separated_to_vector
+	(&opts->x_flag_instrument_calls_exclude_functions, arg);
+      break;
+
+    case OPT_finstrument_calls_exclude_file_list_:
+      add_comma_separated_to_vector
+	(&opts->x_flag_instrument_calls_exclude_files, arg);
+      break;
+
     case OPT_fmessage_length_:
       pp_set_line_maximum_length (dc->printer, value);
       diagnostic_set_caret_max_width (dc, value);
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-1.C b/gcc/testsuite/g++.dg/other/instrument_calls-1.C
new file mode 100644
index 0000000..68e00c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-1.C
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+class Base
+{
+public:
+	virtual void foo();
+};
+
+void fn_caller( Base* b ) { b->foo(); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-2.C b/gcc/testsuite/g++.dg/other/instrument_calls-2.C
new file mode 100644
index 0000000..0a295e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-2.C
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
+
+class Base
+{
+public:
+	virtual void foo();
+	virtual void bar();
+	virtual void foobar(int i);
+	virtual void barfoo(int i);
+};
+
+typedef void (Base::*BaseMemFn)(int i);
+void fn_caller( Base& obj, BaseMemFn memfnptr ) { CALL_MEMBER_FN(obj, memfnptr)(42); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/g++.dg/other/instrument_calls-3.C b/gcc/testsuite/g++.dg/other/instrument_calls-3.C
new file mode 100644
index 0000000..e96280a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/instrument_calls-3.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+class Base
+{
+public:
+	int bar();
+};
+
+int fn_caller( Base& b )
+{
+   b.bar();
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
+
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-1.c b/gcc/testsuite/gcc.dg/instrument_calls-1.c
new file mode 100644
index 0000000..c406448
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-2.c b/gcc/testsuite/gcc.dg/instrument_calls-2.c
new file mode 100644
index 0000000..8be35be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls -finstrument-calls-exclude-function-list=fn_caller" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-3.c b/gcc/testsuite/gcc.dg/instrument_calls-3.c
new file mode 100644
index 0000000..ad14987
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-3.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls -finstrument-calls-exclude-file-list=instrument_calls-3" } */
+
+void fn () { }
+void fn_caller () { fn (); }
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-4.c b/gcc/testsuite/gcc.dg/instrument_calls-4.c
new file mode 100644
index 0000000..ef95a89
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-4.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+#include <stdio.h>
+void fn_caller () { puts (""); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-5.c b/gcc/testsuite/gcc.dg/instrument_calls-5.c
new file mode 100644
index 0000000..be567d7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-5.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+int fn (int i) { }
+int fn_caller (int i)
+{
+    return fn (i);
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-6.c b/gcc/testsuite/gcc.dg/instrument_calls-6.c
new file mode 100644
index 0000000..38a2605
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-6.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn_caller ()
+{
+    void fn () { }
+    fn ();
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-7.c b/gcc/testsuite/gcc.dg/instrument_calls-7.c
new file mode 100644
index 0000000..e6d9503
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-7.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void *p_fn[3];
+int fn_caller (int i, char *fmt, ...)
+{
+    void *arg = __builtin_apply_args();
+    void *ret = __builtin_apply(p_fn[i], arg, 0xff);
+    __builtin_return(ret);
+}
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-8.c b/gcc/testsuite/gcc.dg/instrument_calls-8.c
new file mode 100644
index 0000000..57d021b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-8.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+void fn_caller ( void (*p_fn)() ) { p_fn (); }
+
+/* { dg-final { scan-assembler "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler "__gnu_profile_call_after" } } */
diff --git a/gcc/testsuite/gcc.dg/instrument_calls-9.c b/gcc/testsuite/gcc.dg/instrument_calls-9.c
new file mode 100644
index 0000000..ec67040
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument_calls-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-calls" } */
+
+__attribute__((no_instrument_function)) void fn ();
+
+void fn_caller ()
+{
+    fn ();
+}
+
+/* { dg-final { scan-assembler-not "__gnu_profile_call_before" } } */
+/* { dg-final { scan-assembler-not "__gnu_profile_call_after" } } */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 00f78a1..967b1e7 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -305,6 +305,8 @@ unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr)
     			= (unsigned) bp_unpack_value (bp, 1);
+  DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (expr)
+			= (unsigned) bp_unpack_value (bp, 1);
   DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1);
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index fa50ef5..f71fea6 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -271,6 +271,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
   bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1);
   bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1);
   bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1);
+  bp_pack_value (bp, DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER (expr), 1);
   bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1);
   bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1);
   bp_pack_value (bp, DECL_PURE_P (expr), 1);
diff --git a/gcc/tree.h b/gcc/tree.h
index b444517..456e41e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3375,6 +3375,11 @@ struct GTY(())
 #define DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(NODE) \
   (FUNCTION_DECL_CHECK (NODE)->function_decl.no_instrument_function_entry_exit)
 
+/* Used in FUNCTION_DECLs to indicate that function calls in that function should
+   be instrumented with calls to support routines before and after each function call.  */
+#define DECL_NO_INSTRUMENT_CALLS_BEFORE_AFTER(NODE) \
+  (FUNCTION_DECL_CHECK (NODE)->function_decl.no_instrument_calls_before_after)
+
 /* Used in FUNCTION_DECLs to indicate that limit-stack-* should be
    disabled in this function.  */
 #define DECL_NO_LIMIT_STACK(NODE) \
@@ -3512,6 +3517,7 @@ struct GTY(()) tree_function_decl {
   unsigned no_inline_warning_flag : 1;
 
   unsigned no_instrument_function_entry_exit : 1;
+  unsigned no_instrument_calls_before_after : 1;
   unsigned no_limit_stack : 1;
   unsigned disregard_inline_limits : 1;
   unsigned pure_flag : 1;
@@ -3519,7 +3525,7 @@ struct GTY(()) tree_function_decl {
   unsigned has_debug_args_flag : 1;
   unsigned tm_clone_flag : 1;
   unsigned versioned_function : 1;
-  /* No bits left.  */
+  /* -1 bit left */
 };
 
 /* The source language of the translation-unit.  */
-- 
1.8.1.4



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