From patchwork Tue Sep 17 07:41:15 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul_Woegerer@mentor.com X-Patchwork-Id: 275389 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AA2232C00CE for ; Tue, 17 Sep 2013 17:42:06 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=CBbCWSndvW9A3ZRzNTKVg1fyOaZrb/PsA3EHDiJln+edaQtWJoKVe 3TxdGekGW0cnXfzYab3LFCtsH34CR63NE7q4NAY8FPJQuVZw/ICL9WrRa5K/oq6D WydNJhQFGUS927Cg2YTRC5q1cIrkOYvV3nzCJva5j0yj24f4tkmMlk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=3uNo/DQ2UoEK5AGmsBZnYJIBzwM=; b=GpM36jP9re8MxKWQB2BC iDyjTaXfbWtJw1aTidCkXN1euD77Xe3Qtvb6UCW7f8uDNTjjm6otnZICJlpWoamb SxsDaIP6DNkkpyRb4FU122HWYaVdpZo5VFdblsch+mCqpnB/6Qz2KAy/Gf5tHzr0 rQuTjRBkQiXujOFPvULkkJE= Received: (qmail 16140 invoked by alias); 17 Sep 2013 07:41:48 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 16043 invoked by uid 89); 17 Sep 2013 07:41:48 -0000 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 17 Sep 2013 07:41:48 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, KHOP_THREADED, RDNS_NONE, SPF_HELO_FAIL autolearn=no version=3.3.2 X-HELO: relay1.mentorg.com Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1VLpuo-0001bG-RZ from Paul_Woegerer@mentor.com ; Tue, 17 Sep 2013 00:41:42 -0700 Received: from NA1-MAIL.mgc.mentorg.com ([147.34.98.181]) by svr-orw-fem-01.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Tue, 17 Sep 2013 00:41:42 -0700 Received: from atv-pwoegere-l3.atv.mentorg.com.com ([172.30.72.69]) by NA1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 17 Sep 2013 00:41:41 -0700 From: Paul Woegerer To: jh@suse.cz Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Caller instrumentation with -finstrument-calls. Date: Tue, 17 Sep 2013 09:41:15 +0200 Message-Id: <1379403675-2866-2-git-send-email-paul_woegerer@mentor.com> In-Reply-To: <1379403675-2866-1-git-send-email-paul_woegerer@mentor.com> References: <1379403675-2866-1-git-send-email-paul_woegerer@mentor.com> 2013-07-01 Paul Woegerer 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-core.h (tree_decl_with_vis): Add bitfield no_instrument_calls_before_after. * gcc/tree.h: Macro for no_instrument_calls_before_after access. * 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. Signed-off-by: Paul Woegerer --- gcc/builtins.def | 5 ++ gcc/c-family/c-common.c | 34 +++++++ gcc/c/c-decl.c | 2 + gcc/common.opt | 20 ++++- gcc/cp/decl.c | 2 + gcc/doc/invoke.texi | 42 +++++++++ gcc/function.c | 3 +- gcc/gimplify.c | 113 +++++++++++++++++++++++- gcc/ipa.c | 1 + gcc/java/jcf-parse.c | 1 + gcc/libfuncs.h | 6 ++ gcc/optabs.c | 6 ++ gcc/opts.c | 10 +++ gcc/testsuite/g++.dg/other/instrument_calls-1.C | 14 +++ gcc/testsuite/g++.dg/other/instrument_calls-2.C | 20 +++++ gcc/testsuite/g++.dg/other/instrument_calls-3.C | 17 ++++ gcc/testsuite/gcc.dg/instrument_calls-1.c | 8 ++ gcc/testsuite/gcc.dg/instrument_calls-2.c | 8 ++ gcc/testsuite/gcc.dg/instrument_calls-3.c | 8 ++ gcc/testsuite/gcc.dg/instrument_calls-4.c | 8 ++ gcc/testsuite/gcc.dg/instrument_calls-5.c | 11 +++ gcc/testsuite/gcc.dg/instrument_calls-6.c | 11 +++ gcc/testsuite/gcc.dg/instrument_calls-7.c | 13 +++ gcc/testsuite/gcc.dg/instrument_calls-8.c | 7 ++ gcc/testsuite/gcc.dg/instrument_calls-9.c | 12 +++ gcc/tree-core.h | 4 +- gcc/tree-streamer-in.c | 2 + gcc/tree-streamer-out.c | 1 + gcc/tree.h | 6 ++ 29 files changed, 390 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-1.C create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-2.C create mode 100644 gcc/testsuite/g++.dg/other/instrument_calls-3.C create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-1.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-2.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-3.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-4.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-5.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-6.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-7.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-8.c create mode 100644 gcc/testsuite/gcc.dg/instrument_calls-9.c diff --git a/gcc/builtins.def b/gcc/builtins.def index 8ccf3ae..fc60cc7 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -805,6 +805,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 62aa9fc..d145283 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, @@ -660,6 +662,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, @@ -7920,6 +7925,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 f7ae648..e65f29c 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 fae9763..da4b176 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. @@ -1368,6 +1374,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 6e026b2..c6e5327 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1977,6 +1977,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 caca744..0cccbf2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1026,6 +1026,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 @@ -20976,6 +20979,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 c7d259c..a03a69d 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4757,7 +4757,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 1589db4..7047490 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -91,6 +91,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. */ @@ -1157,6 +1159,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 @@ -2690,15 +2749,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 @@ -4800,6 +4866,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); @@ -4929,9 +4996,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); @@ -4952,7 +5023,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); @@ -8447,6 +8520,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 *v; + + v = (vec *) 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 *) 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 91d63eb..a3da75b 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -1299,6 +1299,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 1d0659e..31c91b9 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -6207,6 +6207,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 6b6652d..1df54ae 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1605,6 +1605,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 +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-core.h b/gcc/tree-core.h index b1bc56a..8a2a464 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1309,7 +1309,9 @@ struct GTY(()) tree_decl_with_vis { unsigned cxx_destructor : 1; /* Belong to FUNCTION_DECL exclusively. */ unsigned final : 1; - /* 11 unused bits. */ + /* Belong to FUNCTION_DECL exclusively. */ + unsigned no_instrument_calls_before_after : 1; + /* 10 unused bits. */ }; struct GTY(()) tree_var_decl { diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index c36d4f6..be74fb2 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -308,6 +308,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 942ba1e..549b26c 100644 --- a/gcc/tree-streamer-out.c +++ b/gcc/tree-streamer-out.c @@ -276,6 +276,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 a263a2c..25f8c14 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2543,6 +2543,12 @@ extern vec **decl_debug_args_insert (tree); #define DECL_FINAL_P(NODE)\ (FUNCTION_DECL_CHECK (NODE)->decl_with_vis.final) +/* Used in FUNCTION_DECL 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)->decl_with_vis.no_instrument_calls_before_after) + /* The source language of the translation-unit. */ #define TRANSLATION_UNIT_LANGUAGE(NODE) \ (TRANSLATION_UNIT_DECL_CHECK (NODE)->translation_unit_decl.language)