public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-1065] Introduce -finstrument-functions-once
@ 2022-06-13 11:35 Eric Botcazou
0 siblings, 0 replies; only message in thread
From: Eric Botcazou @ 2022-06-13 11:35 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:3b598848f6fdbf7e76eaf2beec1ce94fc3a14b9b
commit r13-1065-g3b598848f6fdbf7e76eaf2beec1ce94fc3a14b9b
Author: Eric Botcazou <ebotcazou@adacore.com>
Date: Mon Jun 13 13:32:53 2022 +0200
Introduce -finstrument-functions-once
The goal is to make it possible to use it in (large) production binaries
to do function-level coverage, so the overhead must be minimum and, in
particular, there is no protection against data races so the "once"
moniker is imprecise.
gcc/
* common.opt (finstrument-functions): Set explicit value.
(-finstrument-functions-once): New option.
* doc/invoke.texi (Program Instrumentation Options): Document it.
* gimplify.cc (build_instrumentation_call): New static function.
(gimplify_function_tree): Call it to emit the instrumentation calls
if -finstrument-functions[-once] is specified.
gcc/testsuite/
* gcc.dg/instrument-4.c: New test.
Diff:
---
gcc/common.opt | 6 +-
gcc/doc/invoke.texi | 18 ++++-
gcc/gimplify.cc | 137 +++++++++++++++++++++++++++---------
gcc/testsuite/gcc.dg/instrument-4.c | 7 ++
4 files changed, 133 insertions(+), 35 deletions(-)
diff --git a/gcc/common.opt b/gcc/common.opt
index 7ca0cceed82..8e961f16b0e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1890,9 +1890,13 @@ EnumValue
Enum(cf_protection_level) String(none) Value(CF_NONE)
finstrument-functions
-Common Var(flag_instrument_function_entry_exit)
+Common Var(flag_instrument_function_entry_exit,1)
Instrument function entry and exit with profiling calls.
+finstrument-functions-once
+Common Var(flag_instrument_function_entry_exit,2)
+Instrument function entry and exit with profiling calls invoked once.
+
finstrument-functions-exclude-function-list=
Common RejectNegative Joined
-finstrument-functions-exclude-function-list=name,... Do not instrument listed functions.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 174bc09e5cf..b6c0305f198 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -618,7 +618,7 @@ Objective-C and Objective-C++ Dialects}.
-fno-stack-limit -fsplit-stack @gol
-fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} @gol
-fvtv-counts -fvtv-debug @gol
--finstrument-functions @gol
+-finstrument-functions -finstrument-functions-once @gol
-finstrument-functions-exclude-function-list=@var{sym},@var{sym},@dots{} @gol
-finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{}} @gol
-fprofile-prefix-map=@var{old}=@var{new}
@@ -16395,6 +16395,22 @@ cannot safely be called (perhaps signal handlers, if the profiling
routines generate output or allocate memory).
@xref{Common Function Attributes}.
+@item -finstrument-functions-once
+@opindex -finstrument-functions-once
+This is similar to @option{-finstrument-functions}, but the profiling
+functions are called only once per instrumented function, i.e. the first
+profiling function is called after the first entry into the instrumented
+function and the second profiling function is called before the exit
+corresponding to this first entry.
+
+The definition of @code{once} for the purpose of this option is a little
+vague because the implementation is not protected against data races.
+As a result, the implementation only guarantees that the profiling
+functions are called at @emph{least} once per process and at @emph{most}
+once per thread, but the calls are always paired, that is to say, if a
+thread calls the first function, then it will call the second function,
+unless it never reaches the exit of the instrumented function.
+
@item -finstrument-functions-exclude-file-list=@var{file},@var{file},@dots{}
@opindex finstrument-functions-exclude-file-list
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index cd1796643d7..04990ad91a6 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -16586,6 +16586,51 @@ flag_instrument_functions_exclude_p (tree fndecl)
return false;
}
+/* Build a call to the instrumentation function FNCODE and add it to SEQ.
+ If COND_VAR is not NULL, it is a boolean variable guarding the call to
+ the instrumentation function. IF STMT is not NULL, it is a statement
+ to be executed just before the call to the instrumentation function. */
+
+static void
+build_instrumentation_call (gimple_seq *seq, enum built_in_function fncode,
+ tree cond_var, gimple *stmt)
+{
+ /* The instrumentation hooks aren't going to call the instrumented
+ function and the address they receive is expected to be matchable
+ against symbol addresses. Make sure we don't create a trampoline,
+ in case the current function is nested. */
+ tree this_fn_addr = build_fold_addr_expr (current_function_decl);
+ TREE_NO_TRAMPOLINE (this_fn_addr) = 1;
+
+ tree label_true, label_false;
+ if (cond_var)
+ {
+ label_true = create_artificial_label (UNKNOWN_LOCATION);
+ label_false = create_artificial_label (UNKNOWN_LOCATION);
+ gcond *cond = gimple_build_cond (EQ_EXPR, cond_var, boolean_false_node,
+ label_true, label_false);
+ gimplify_seq_add_stmt (seq, cond);
+ gimplify_seq_add_stmt (seq, gimple_build_label (label_true));
+ gimplify_seq_add_stmt (seq, gimple_build_predict (PRED_COLD_LABEL,
+ NOT_TAKEN));
+ }
+
+ if (stmt)
+ gimplify_seq_add_stmt (seq, stmt);
+
+ tree x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
+ gcall *call = gimple_build_call (x, 1, integer_zero_node);
+ tree tmp_var = create_tmp_var (ptr_type_node, "return_addr");
+ gimple_call_set_lhs (call, tmp_var);
+ gimplify_seq_add_stmt (seq, call);
+ x = builtin_decl_implicit (fncode);
+ call = gimple_build_call (x, 2, this_fn_addr, tmp_var);
+ gimplify_seq_add_stmt (seq, call);
+
+ if (cond_var)
+ gimplify_seq_add_stmt (seq, gimple_build_label (label_false));
+}
+
/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL
node for the function we want to gimplify.
@@ -16636,40 +16681,66 @@ gimplify_function_tree (tree fndecl)
&& DECL_DISREGARD_INLINE_LIMITS (fndecl))
&& !flag_instrument_functions_exclude_p (fndecl))
{
- tree x;
- gbind *new_bind;
- gimple *tf;
- gimple_seq cleanup = NULL, body = NULL;
- tree tmp_var, this_fn_addr;
- gcall *call;
-
- /* The instrumentation hooks aren't going to call the instrumented
- function and the address they receive is expected to be matchable
- against symbol addresses. Make sure we don't create a trampoline,
- in case the current function is nested. */
- this_fn_addr = build_fold_addr_expr (current_function_decl);
- TREE_NO_TRAMPOLINE (this_fn_addr) = 1;
-
- x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
- call = gimple_build_call (x, 1, integer_zero_node);
- tmp_var = create_tmp_var (ptr_type_node, "return_addr");
- gimple_call_set_lhs (call, tmp_var);
- gimplify_seq_add_stmt (&cleanup, call);
- x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_EXIT);
- call = gimple_build_call (x, 2, this_fn_addr, tmp_var);
- gimplify_seq_add_stmt (&cleanup, call);
- tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY);
-
- x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
- call = gimple_build_call (x, 1, integer_zero_node);
- tmp_var = create_tmp_var (ptr_type_node, "return_addr");
- gimple_call_set_lhs (call, tmp_var);
- gimplify_seq_add_stmt (&body, call);
- x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_ENTER);
- call = gimple_build_call (x, 2, this_fn_addr, tmp_var);
- gimplify_seq_add_stmt (&body, call);
+ gimple_seq body = NULL, cleanup = NULL;
+ gassign *assign;
+ tree cond_var;
+
+ /* If -finstrument-functions-once is specified, generate:
+
+ static volatile bool C.0 = false;
+ bool tmp_called;
+
+ tmp_called = C.0;
+ if (!tmp_called)
+ {
+ C.0 = true;
+ [call profiling enter function]
+ }
+
+ without specific protection for data races. */
+ if (flag_instrument_function_entry_exit > 1)
+ {
+ tree first_var
+ = build_decl (DECL_SOURCE_LOCATION (current_function_decl),
+ VAR_DECL,
+ create_tmp_var_name ("C"),
+ boolean_type_node);
+ DECL_ARTIFICIAL (first_var) = 1;
+ DECL_IGNORED_P (first_var) = 1;
+ TREE_STATIC (first_var) = 1;
+ TREE_THIS_VOLATILE (first_var) = 1;
+ TREE_USED (first_var) = 1;
+ DECL_INITIAL (first_var) = boolean_false_node;
+ varpool_node::add (first_var);
+
+ cond_var = create_tmp_var (boolean_type_node, "tmp_called");
+ assign = gimple_build_assign (cond_var, first_var);
+ gimplify_seq_add_stmt (&body, assign);
+
+ assign = gimple_build_assign (first_var, boolean_true_node);
+ }
+
+ else
+ {
+ cond_var = NULL_TREE;
+ assign = NULL;
+ }
+
+ build_instrumentation_call (&body, BUILT_IN_PROFILE_FUNC_ENTER,
+ cond_var, assign);
+
+ /* If -finstrument-functions-once is specified, generate:
+
+ if (!tmp_called)
+ [call profiling exit function]
+
+ without specific protection for data races. */
+ build_instrumentation_call (&cleanup, BUILT_IN_PROFILE_FUNC_EXIT,
+ cond_var, NULL);
+
+ gimple *tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY);
gimplify_seq_add_stmt (&body, tf);
- new_bind = gimple_build_bind (NULL, body, NULL);
+ gbind *new_bind = gimple_build_bind (NULL, body, NULL);
/* Replace the current function body with the body
wrapped in the try/finally TF. */
diff --git a/gcc/testsuite/gcc.dg/instrument-4.c b/gcc/testsuite/gcc.dg/instrument-4.c
new file mode 100644
index 00000000000..c19e8bf3971
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/instrument-4.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-options "-finstrument-functions-once" } */
+
+void fn () { }
+
+/* { dg-final { scan-assembler "__cyg_profile_func_enter" } } */
+/* { dg-final { scan-assembler "__cyg_profile_func_exit" } } */
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-06-13 11:35 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-13 11:35 [gcc r13-1065] Introduce -finstrument-functions-once Eric Botcazou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).