summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorraeburn <raeburn@138bc75d-0d04-0410-961f-82ee72b054a4>1998-07-30 10:38:22 +0000
committerraeburn <raeburn@138bc75d-0d04-0410-961f-82ee72b054a4>1998-07-30 10:38:22 +0000
commitabd28ceff13aab2bf6e6116b9918ac1b4e8fa9a0 (patch)
tree026e48c190a03450b58622639d6f3e00ed5ec047
parent081dca2bcf8a8c05f930de68972eafe6d2cd3bee (diff)
downloadgcc-abd28ceff13aab2bf6e6116b9918ac1b4e8fa9a0.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@21495 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog28
-rw-r--r--gcc/c-common.c19
-rw-r--r--gcc/c-decl.c3
-rw-r--r--gcc/expr.h4
-rw-r--r--gcc/extend.texi11
-rw-r--r--gcc/flags.h3
-rw-r--r--gcc/function.c43
-rw-r--r--gcc/function.h1
-rw-r--r--gcc/invoke.texi35
-rw-r--r--gcc/optabs.c9
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/special/eeprof-1.c67
-rw-r--r--gcc/testsuite/gcc.c-torture/special/special.exp2
-rw-r--r--gcc/toplev.c7
-rw-r--r--gcc/tree.h6
15 files changed, 239 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8ae4b2a1fd5..88fb4937ce5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 245fedb97be..8405a41a2c9 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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;
}
}
}
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 3af985d732d..a4b87860e66 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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 ();
diff --git a/gcc/expr.h b/gcc/expr.h
index a53a036a15a..9e43741f26e 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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));
diff --git a/gcc/extend.texi b/gcc/extend.texi
index 736f4220c5a..0fb01f444f5 100644
--- a/gcc/extend.texi
+++ b/gcc/extend.texi
@@ -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.
diff --git a/gcc/flags.h b/gcc/flags.h
index 37c1bd96a91..cfb4ee628c9 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -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. */
diff --git a/gcc/function.c b/gcc/function.c
index cf9542bfe9b..5bd012fc135 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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. */
diff --git a/gcc/function.h b/gcc/function.h
index f9b9a9a924b..06e90dc88aa 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -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;
diff --git a/gcc/invoke.texi b/gcc/invoke.texi
index 3b3ad4313db..67c7392258f 100644
--- a/gcc/invoke.texi
+++ b/gcc/invoke.texi
@@ -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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 4b31fe0d106..95c963ee040 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4b718f2a8fa..aced868b959 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/gcc.c-torture/special/eeprof-1.c b/gcc/testsuite/gcc.c-torture/special/eeprof-1.c
new file mode 100644
index 00000000000..6dad7ec5a73
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/special/eeprof-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.c-torture/special/special.exp b/gcc/testsuite/gcc.c-torture/special/special.exp
index 374fe40c765..ac215a39f5b 100644
--- a/gcc/testsuite/gcc.c-torture/special/special.exp
+++ b/gcc/testsuite/gcc.c-torture/special/special.exp
@@ -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"
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 266a209f9bf..9ab6435ab30 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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]))
diff --git a/gcc/tree.h b/gcc/tree.h
index 703c94e7aef..401e5ee4b92 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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.