Function entry/exit profiling instrumentation:

* expr.h (profile_function_entry_libfunc, profile_function_exit_libfunc):
Declare new variables.
* optabs.c: Define them here.
(init_optabs): Initialize them.
* tree.h (struct tree_decl): New flag no_instrument_function_entry_exit.
(DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT): New accessor macro.
* c-decl.c (duplicate_decls): Merge it.
* c-common.c (enum attrs): New value A_NO_INSTRUMENT_FUNCTION.
(init_attributes): Use it for "no_instrument_function".
(decl_attributes): Handle it, for functions that have not yet been compiled.
Set decl flag.
* flags.h (flag_instrument_function_entry_exit): Declare new variable.
* toplev.c (flag_instrument_function_entry_exit): Define it here.
(f_options): New option "instrument-functions".
* function.h (struct function): New field instrument_entry_exit.
* function.c (current_function_instrument_entry_exit): New variable.
(push_function_context_to, pop_function_context_from): Save and restore.
(expand_function_start): Set current_ variable, maybe emit return label and
entry profile call.
(expand_function_end): Maybe emit exit profile call.
Testsuite:
* gcc.c-torture/special/eeprof-1.c: New test, for -finstrument-functions.
* gcc.c-torture/special/special.exp: Run it.

From-SVN: r21495
This commit is contained in:
Ken Raeburn 1998-07-30 10:38:22 +00:00 committed by Ken Raeburn
parent 6bcf8e5a04
commit 07417085a1
15 changed files with 239 additions and 5 deletions

View File

@ -1,3 +1,31 @@
Thu Jul 30 13:08:07 1998 Ken Raeburn <raeburn@cygnus.com>
Function entry/exit profiling instrumentation:
* expr.h (profile_function_entry_libfunc,
profile_function_exit_libfunc): Declare new variables.
* optabs.c: Define them here.
(init_optabs): Initialize them.
* tree.h (struct tree_decl): New flag
no_instrument_function_entry_exit.
(DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT): New accessor macro.
* c-decl.c (duplicate_decls): Merge it.
* c-common.c (enum attrs): New value A_NO_INSTRUMENT_FUNCTION.
(init_attributes): Use it for "no_instrument_function".
(decl_attributes): Handle it, for functions that have not yet been
compiled. Set decl flag.
* flags.h (flag_instrument_function_entry_exit): Declare new
variable.
* toplev.c (flag_instrument_function_entry_exit): Define it here.
(f_options): New option "instrument-functions".
* function.h (struct function): New field instrument_entry_exit.
* function.c (current_function_instrument_entry_exit): New
variable.
(push_function_context_to, pop_function_context_from): Save and
restore.
(expand_function_start): Set current_ variable, maybe emit return
label and entry profile call.
(expand_function_end): Maybe emit exit profile call.
Thu Jul 30 00:58:34 1998 Jeffrey A Law (law@cygnus.com)
* i386.md (movqi): When optimizing a load of (const_int 1) into a

View File

@ -50,6 +50,7 @@ extern struct obstack permanent_obstack;
int skip_evaluation;
enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
A_NO_INSTRUMENT_FUNCTION,
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
@ -382,6 +383,7 @@ init_attributes ()
add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
add_attribute (A_WEAK, "weak", 0, 0, 1);
add_attribute (A_ALIAS, "alias", 1, 1, 1);
add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
}
/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
@ -856,6 +858,23 @@ decl_attributes (node, attributes, prefix_attributes)
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
case A_NO_INSTRUMENT_FUNCTION:
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
"`%s' attribute applies only to functions",
IDENTIFIER_POINTER (name));
}
else if (DECL_INITIAL (decl))
{
error_with_decl (decl,
"can't set `%s' attribute after definition",
IDENTIFIER_POINTER (name));
}
else
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
break;
}
}
}

View File

@ -1931,6 +1931,9 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
{
DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
|= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
}
pop_obstacks ();

View File

@ -532,6 +532,10 @@ extern rtx chkr_set_right_libfunc;
extern rtx chkr_copy_bitmap_libfunc;
extern rtx chkr_check_exec_libfunc;
extern rtx chkr_check_str_libfunc;
/* For instrument-functions. */
extern rtx profile_function_entry_libfunc;
extern rtx profile_function_exit_libfunc;
typedef rtx (*rtxfun) PROTO ((rtx));

View File

@ -1286,8 +1286,9 @@ carefully.
The keyword @code{__attribute__} allows you to specify special
attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. Eight attributes,
@code{noreturn}, @code{const}, @code{format}, @code{section},
attribute specification inside double parentheses. Nine attributes,
@code{noreturn}, @code{const}, @code{format},
@code{no_instrument_function}, @code{section},
@code{constructor}, @code{destructor}, @code{unused} and @code{weak} are
currently defined for functions. Other attributes, including
@code{section} are supported for variables declarations (@pxref{Variable
@ -1447,6 +1448,12 @@ operands are a call to one of your own function. The compiler always
treats @code{gettext}, @code{dgettext}, and @code{dcgettext} in this
manner.
@item no_instrument_function
@cindex @code{no_instrument_function} function attribute
If @samp{-finstrument-functions} is given, profiling function calls will
be generated at entry and exit of most user-compiled functions.
Functions with this attribute will not be so instrumented.
@item section ("section-name")
@cindex @code{section} function attribute
Normally, the compiler places the code it generates in the @code{text} section.

View File

@ -444,6 +444,9 @@ extern int flag_stack_check;
/* Do the full regmove optimization pass. */
extern int flag_regmove;
/* Instrument functions with calls at entry and exit, for profiling. */
extern int flag_instrument_function_entry_exit;
/* Other basic status info about current function. */

View File

@ -217,6 +217,10 @@ rtx current_function_internal_arg_pointer;
/* Language-specific reason why the current function cannot be made inline. */
char *current_function_cannot_inline;
/* Nonzero if instrumentation calls for function entry and exit should be
generated. */
int current_function_instrument_entry_exit;
/* The FUNCTION_DECL for an inline function currently being expanded. */
tree inline_function_decl;
@ -539,6 +543,7 @@ push_function_context_to (context)
p->fixup_var_refs_queue = 0;
p->epilogue_delay_list = current_function_epilogue_delay_list;
p->args_info = current_function_args_info;
p->instrument_entry_exit = current_function_instrument_entry_exit;
save_tree_status (p, context);
save_storage_status (p);
@ -621,6 +626,7 @@ pop_function_context_from (context)
current_function_epilogue_delay_list = p->epilogue_delay_list;
reg_renumber = 0;
current_function_args_info = p->args_info;
current_function_instrument_entry_exit = p->instrument_entry_exit;
restore_tree_status (p, context);
restore_storage_status (p);
@ -5458,6 +5464,10 @@ expand_function_start (subr, parms_have_cleanups)
valid operands of arithmetic insns. */
init_recog_no_volatile ();
current_function_instrument_entry_exit
= (flag_instrument_function_entry_exit
&& ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
/* If function gets a static chain arg, store it in the stack frame.
Do this first, so it gets the first stack slot offset. */
if (current_function_needs_context)
@ -5484,6 +5494,7 @@ expand_function_start (subr, parms_have_cleanups)
or if it returns a structure, or if it has parm cleanups. */
#ifdef HAVE_return
if (cleanup_label == 0 && HAVE_return
&& ! current_function_instrument_entry_exit
&& ! current_function_returns_pcc_struct
&& ! (current_function_returns_struct && ! optimize))
return_label = 0;
@ -5532,7 +5543,7 @@ expand_function_start (subr, parms_have_cleanups)
else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
/* If return mode is void, this decl rtl should not be used. */
DECL_RTL (DECL_RESULT (subr)) = 0;
else if (parms_have_cleanups)
else if (parms_have_cleanups || current_function_instrument_entry_exit)
{
/* If function will end with cleanup code for parms,
compute the return values into a pseudo reg,
@ -5650,6 +5661,21 @@ expand_function_start (subr, parms_have_cleanups)
}
}
if (current_function_instrument_entry_exit)
{
rtx fun = DECL_RTL (current_function_decl);
if (GET_CODE (fun) == MEM)
fun = XEXP (fun, 0);
else
abort ();
emit_library_call (profile_function_entry_libfunc, 0, VOIDmode, 2,
fun, Pmode,
expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
0,
hard_frame_pointer_rtx),
Pmode);
}
/* After the display initializations is where the tail-recursion label
should go, if we end up needing one. Ensure we have a NOTE here
since some things (like trampolines) get placed before this. */
@ -5863,6 +5889,21 @@ expand_function_end (filename, line, end_bindings)
}
}
if (current_function_instrument_entry_exit)
{
rtx fun = DECL_RTL (current_function_decl);
if (GET_CODE (fun) == MEM)
fun = XEXP (fun, 0);
else
abort ();
emit_library_call (profile_function_exit_libfunc, 0, VOIDmode, 2,
fun, Pmode,
expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
0,
hard_frame_pointer_rtx),
Pmode);
}
/* If we had calls to alloca, and this machine needs
an accurate stack pointer to exit the function,
insert some code to save and restore the stack pointer. */

View File

@ -113,6 +113,7 @@ struct function
int temp_slot_level;
int target_temp_slot_level;
int var_temp_slot_level;
int instrument_entry_exit;
/* This slot is initialized as 0 and is added to
during the nested function. */
struct var_refs_queue *fixup_var_refs_queue;

View File

@ -5907,6 +5907,41 @@ prefix_foo (int a)
@end example
This option is designed to be used with @samp{-fcheck-memory-usage}.
@item -finstrument-functions
Generate instrumentation calls for entry and exit to functions. Just
after function entry and just before function exit, the following
profiling functions will be called with the address of the current
function and its call site. (On some platforms,
@code{__builtin_return_address} does not work beyond the current
function, so the call site information may not be available to the
profiling functions otherwise.)
@example
void __cyg_profile_func_enter (void *this_fn, void *call_site);
void __cyg_profile_func_exit (void *this_fn, void *call_site);
@end example
The first argument is the address of the start of the current function,
which may be looked up exactly in the symbol table.
This instrumentation is also done for functions expanded inline in other
functions. The profiling calls will indicate where, conceptually, the
inline function is entered and exited. This means that addressable
versions of such functions must be available. If all your uses of a
function are expanded inline, this may mean an additional expansion of
code size. If you use @samp{extern inline} in your C code, an
addressable version of such functions must be provided. (This is
normally the case anyways, but if you get lucky and the optimizer always
expands the functions inline, you might have gotten away without
providing static copies.)
A function may be given the attribute @code{no_instrument_function}, in
which case this instrumentation will not be done. This can be used, for
example, for the profiling functions listed above, high-priority
interrupt routines, and any functions from which the profiling functions
cannot safely be called (perhaps signal handlers, if the profiling
routines generate output or allocate memory).
@item -fstack-check
Generate code to verify that you do not go beyond the boundary of the
stack. You should specify this flag if you are running in an

View File

@ -214,6 +214,9 @@ rtx chkr_copy_bitmap_libfunc;
rtx chkr_check_exec_libfunc;
rtx chkr_check_str_libfunc;
rtx profile_function_entry_libfunc;
rtx profile_function_exit_libfunc;
/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
gives the gen_function to make a branch to test that condition. */
@ -4391,6 +4394,12 @@ init_optabs ()
chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_exec");
chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_str");
/* For function entry/exit instrumentation. */
profile_function_entry_libfunc
= gen_rtx_SYMBOL_REF (VOIDmode, "__cyg_profile_func_enter");
profile_function_exit_libfunc
= gen_rtx_SYMBOL_REF (VOIDmode, "__cyg_profile_func_exit");
#ifdef HAVE_conditional_trap
init_traps ();
#endif

View File

@ -1,3 +1,9 @@
1998-07-30 Ken Raeburn <raeburn@cygnus.com>
* gcc.c-torture/special/eeprof-1.c: New test, for
-finstrument-functions.
* gcc.c-torture/special/special.exp: Run it.
Wed Jul 29 00:17:18 1998 Jeffrey A Law (law@cygnus.com)
* gcc.c-torture/compile/980729-1.c: New test.

View File

@ -0,0 +1,67 @@
#define ASSERT(X) if (!(X)) abort ();
#define NOCHK __attribute__ ((no_instrument_function))
int entry_calls, exit_calls;
void (*last_fn_entered)();
void (*last_fn_exited)();
int main () NOCHK;
void foo ()
{
ASSERT (last_fn_entered == foo);
}
static void foo2 ()
{
ASSERT (entry_calls == 1 && exit_calls == 0);
ASSERT (last_fn_entered == foo2);
foo ();
ASSERT (entry_calls == 2 && exit_calls == 1);
ASSERT (last_fn_entered == foo);
ASSERT (last_fn_exited == foo);
}
void nfoo (void) NOCHK;
void nfoo ()
{
ASSERT (entry_calls == 2 && exit_calls == 2);
ASSERT (last_fn_entered == foo);
ASSERT (last_fn_exited == foo2);
foo ();
ASSERT (entry_calls == 3 && exit_calls == 3);
ASSERT (last_fn_entered == foo);
ASSERT (last_fn_exited == foo);
}
int main ()
{
ASSERT (entry_calls == 0 && exit_calls == 0);
foo2 ();
ASSERT (entry_calls == 2 && exit_calls == 2);
ASSERT (last_fn_entered == foo);
ASSERT (last_fn_exited == foo2);
nfoo ();
ASSERT (entry_calls == 3 && exit_calls == 3);
ASSERT (last_fn_entered == foo);
return 0;
}
void __cyg_profile_func_enter (void (*fn)(), void (*parent)()) NOCHK;
void __cyg_profile_func_exit (void (*fn)(), void (*parent)()) NOCHK;
void __cyg_profile_func_enter (void (*fn)(), void (*parent)())
{
entry_calls++;
last_fn_entered = fn;
}
void __cyg_profile_func_exit (void (*fn)(), void (*parent)())
{
exit_calls++;
last_fn_exited = fn;
}

View File

@ -98,3 +98,5 @@ c-torture 960224-1.c "-E -ansi -pedantic-errors"
# 960224-2
#c-torture 960224-2.c "-E -ansi -pedantic-errors"
c-torture-execute $srcdir/$subdir/eeprof-1.c "-finstrument-functions"

View File

@ -723,6 +723,9 @@ int flag_strict_aliasing = 0;
extern int flag_dump_unnumbered;
/* Instrument functions with calls at entry and exit, for profiling. */
int flag_instrument_function_entry_exit = 0;
/* Table of supported debugging formats. */
static struct
@ -908,7 +911,9 @@ lang_independent_options f_options[] =
"Generate code to check every memory access" },
{"prefix-function-name", &flag_prefix_function_name, 1,
"Add a prefix to all function names" },
{"dump-unnumbered", &flag_dump_unnumbered, 1}
{"dump-unnumbered", &flag_dump_unnumbered, 1},
{"instrument-functions", &flag_instrument_function_entry_exit, 1,
"Instrument function entry/exit with profiling calls"},
};
#define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0]))

View File

@ -1201,6 +1201,10 @@ struct tree_type
multiple translation units should be merged. */
#define DECL_ONE_ONLY(NODE) (DECL_CHECK (NODE)->decl.transparent_union)
/* Used in FUNCTION_DECLs to indicate that function entry and exit should
be instrumented with calls to support routines. */
#define DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(NODE) ((NODE)->decl.no_instrument_function_entry_exit)
/* Additional flags for language-specific uses. */
#define DECL_LANG_FLAG_0(NODE) (DECL_CHECK (NODE)->decl.lang_flag_0)
#define DECL_LANG_FLAG_1(NODE) (DECL_CHECK (NODE)->decl.lang_flag_1)
@ -1245,7 +1249,6 @@ struct tree_decl
unsigned static_dtor_flag : 1;
unsigned artificial_flag : 1;
unsigned weak_flag : 1;
/* room for no more */
unsigned lang_flag_0 : 1;
unsigned lang_flag_1 : 1;
@ -1257,6 +1260,7 @@ struct tree_decl
unsigned lang_flag_7 : 1;
unsigned non_addr_const_p : 1;
unsigned no_instrument_function_entry_exit : 1;
/* For a FUNCTION_DECL, if inline, this is the size of frame needed.
If built-in, this is the code for which built-in function.