...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_woege...@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_woege...@mentor.com> >> Date: Mon, 1 Jul 2013 09:15:21 +0200 >> Subject: [PATCH] Caller instrumentation with -finstrument-calls. >> >> 2013-07-01 Paul Woegerer <paul_woege...@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, SW Development Engineer Sourcery Analyzer <http://go.mentor.com/sourceryanalyzer> Mentor Graphics, Embedded Software Division