mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-08 20:37:19 +08:00
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:
parent
6bcf8e5a04
commit
07417085a1
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 ();
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
67
gcc/testsuite/gcc.c-torture/special/eeprof-1.c
Normal file
67
gcc/testsuite/gcc.c-torture/special/eeprof-1.c
Normal 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;
|
||||
}
|
@ -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"
|
||||
|
@ -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]))
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user