Patchwork Caller instrumentation with -finstrument-calls

login
register
mail settings
Submitter Paul_Woegerer@mentor.com
Date July 1, 2013, 8:22 a.m.
Message ID <1869484.hXzanm2aKp@atv-pwoegere-l3.atv.mentorg.com>
Download mbox | patch
Permalink /patch/256031/
State New
Headers show

Comments

Paul_Woegerer@mentor.com - July 1, 2013, 8:22 a.m.
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.
Paul_Woegerer@mentor.com - July 10, 2013, 2:43 p.m.
Ping,

The updated patch that I have sent here:
http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00007.html
is still pending review/acceptance.

Could someone please have a look.

Many Thanks,
Paul

On Monday 01 July 2013 10:22:02 Woegerer, Paul wrote:
> 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.  */
>
Paul_Woegerer@mentor.com - Aug. 5, 2013, 2:16 p.m.
...just about time for another ping on GCC caller instrumentation:

http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00007.html

Thanks,
Paul

On 07/10/2013 04:43 PM, wrote:
> Ping,
>
> The updated patch that I have sent here:
> http://gcc.gnu.org/ml/gcc-patches/2013-07/msg00007.html
> is still pending review/acceptance.
>
> Could someone please have a look.
>
> Many Thanks,
> Paul
>
> On Monday 01 July 2013 10:22:02 Woegerer, Paul wrote:
>> 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.  */
>>
Jan Hubicka - Nov. 11, 2013, 2:38 p.m.
Hi,
I apologize for long time for the review.

> > 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 },

So you are adding no_instrument_calls in addition to no_instrument_function and moreover you add
command line option to disable/enable this per line basis.  I see this follow the pre-existing
functio ninstrumentatio ncode, but can't we just make this part of the function instrumentation
instead of adding three new knobs for this? (i.e. have just -finstrument-calls that will be controlled
same way as function instrumentation).

> > 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);

You do not need to introduce new DECL flag for this.  We used to do this in dark ages before
we had attributes in place, but this time we usually just look up the given attribute.

> > +@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

I would expect this to be useful i.e. for dynamic callgraph construction.
In this case I would expect to have two parameters (calling function
and called function) instead of just one (calling function, right?)
> > 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))

Here you can just use lookup_attribute ("no_instrument", attributes) != NULL
instead of DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT.
> > @@ -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

Note that adding instrumentation at gimplification time will make you to miss calls produced later
(i.e. by libcalls, or EH exapnsion or GOMP) and it will also make you to record calls that got inlined.
I suppose this is intended behaviour, what is the main use case for this code?

> > +
> > +      name = lang_hooks.decl_printable_name (fndecl, 0);

The printable names get uninformative for C++ (i.e. all ctors/dtors are called the same way).
I would think of favour of dropping those knobs in favour of functio nattributes...
> > 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");

I do not think we need libcalls for this, since the conversio happens on expansion time.
It seems that the function_entry/function_exit was not removed when the code was upgraded.
So please rmeove those, too.

The patch seems reasonable to me with the changes above. Afte removal of the DECL bits
it should become quite small and localized, so it seems the maintenance costs of the
code should not be too big.  Do you have FSF copyright assignment?

Honza

Patch

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.  */