OSDN Git Service

Function entry/exit profiling instrumentation:
authorraeburn <raeburn@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Jul 1998 10:38:22 +0000 (10:38 +0000)
committerraeburn <raeburn@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 30 Jul 1998 10:38:22 +0000 (10:38 +0000)
* 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

15 files changed:
gcc/ChangeLog
gcc/c-common.c
gcc/c-decl.c
gcc/expr.h
gcc/extend.texi
gcc/flags.h
gcc/function.c
gcc/function.h
gcc/invoke.texi
gcc/optabs.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/special/eeprof-1.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/special/special.exp
gcc/toplev.c
gcc/tree.h

index 8ae4b2a..88fb493 100644 (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
index 245fedb..8405a41 100644 (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);
 }
 \f
 /* 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;
        }
     }
 }
index 3af985d..a4b8786 100644 (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 ();
index a53a036..9e43741 100644 (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;
 \f
 typedef rtx (*rtxfun) PROTO ((rtx));
 
index 736f422..0fb01f4 100644 (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.
index 37c1bd9..cfb4ee6 100644 (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;
 \f
 /* Other basic status info about current function.  */
 
index cf9542b..5bd012f 100644 (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.  */
index f9b9a9a..06e90dc 100644 (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;
index 3b3ad43..67c7392 100644 (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
index 4b31fe0..95c963e 100644 (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
index 4b718f2..aced868 100644 (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.
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 (file)
index 0000000..6dad7ec
--- /dev/null
@@ -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;
+}
index 374fe40..ac215a3 100644 (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"
index 266a209..9ab6435 100644 (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]))
index 703c94e..401e5ee 100644 (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.