OSDN Git Service

2009-12-01 Grigori Fursin <grigori.fursin@inria.fr>
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 1 Dec 2009 19:12:29 +0000 (19:12 +0000)
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 1 Dec 2009 19:12:29 +0000 (19:12 +0000)
            Joern Rennecke  <amylaar@spamcop.net>

        * cgraphunit.c (plugin.h): Include.
        (ipa_passes): Invoke PLUGIN_ALL_IPA_PASSES_START /
        PLUGIN_ALL_IPA_PASSES_END at start / end of processing.
        * gcc-plugin.h (highlev-plugin-common.h, hashtab.h): Include.
        (enum plugin_event): Define by including plugin.def.
        Last enumerator is now called PLUGIN_EVENT_FIRST_DYNAMIC.
        (plugin_event_name): Change type to const char **.
        (get_event_last, get_named_event_id, unregister_callback): Declare.
        (register_callback): Change type of event argument to int.
        (highlev-plugin-common.h): New file.
        * Makefile.in (GCC_PLUGIN_H): Add highlev-plugin-common.h and
        $(HASHTAB_H)
        (tree-optimize.o passes.o): Depend on $(PLUGIN_H).
        (PLUGIN_HEADERS): Add opts.h, $(PARAMS_H) and plugin.def.
        (s-header-vars): New rule.
        (install-plugin): Depend on s-header-vars.  Install b-header-vars.
        * params.c (get_num_compiler_params): New function.
        * params.h (get_num_compiler_params): Declare.
        * passes.c (plugin.h): Include.
        (make_pass_instance): Invoke PLUGIN_NEW_PASS.
        (do_per_function_toporder, pass_init_dump_file): No longer static.
        (pass_fini_dump_file): Likewise.
        (execute_one_pass): Likewise.  Invoke PLUGIN_OVERRIDE_GATE and
        PLUGIN_PASS_EXECUTION.
        (execute_ipa_pass_list): Invoke PLUGIN_EARLY_GIMPLE_PASSES_START and
        PLUGIN_EARLY_GIMPLE_PASSES_END.
        * plugin.c (plugin_event_name_init): New array, defined by
        including plugin.def.
        (FMT_FOR_PLUGIN_EVENT): Update.
        (plugin_event_name): Change type to const char ** and initialize
        to plugin_event_name_init.
        (event_tab, event_last, event_horizon): New variable.
        (get_event_last): New function.
        (plugin_callbacks_init): New array.
        (plugin_callbacks: Change type to struct callback_info **.
        Initialize to plugin_callbacks_init.
        (htab_event_eq, get_named_event_id, unregister_callback): New function.
        (invoke_plugin_va_callbacks): Likewise.
        (register_callback): Change type of event argument to int.
        Handle new events.  Allow dynamic events.
        (invoke_plugin_callbacks): Likewise.  Return success status.
        (plugins_active_p): Allow dynamic callbacks.
        * plugin.def: New file.
        * plugin.h (invoke_plugin_callbacks): Update prototype.
        (invoke_plugin_va_callbacks): Declare.
        * tree-optimize.c (plugin.h): Include.
        (tree_rest_of_compilation): Invoke PLUGIN_ALL_PASSES_START and
        PLUGIN_ALL_PASSES_END.
        * tree-pass.h (execute_one_pass, pass_init_dump_file): Declare.
        (pass_fini_dump_file, do_per_function_toporder): Likewise.
        * doc/plugin.texi: Document new event types.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@154877 138bc75d-0d04-0410-961f-82ee72b054a4

14 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cgraphunit.c
gcc/doc/plugins.texi
gcc/gcc-plugin.h
gcc/highlev-plugin-common.h [new file with mode: 0644]
gcc/params.c
gcc/params.h
gcc/passes.c
gcc/plugin.c
gcc/plugin.def [new file with mode: 0644]
gcc/plugin.h
gcc/tree-optimize.c
gcc/tree-pass.h

index 3b15962..1b82233 100644 (file)
@@ -1,3 +1,58 @@
+2009-12-01  Grigori Fursin  <grigori.fursin@inria.fr>
+           Joern Rennecke  <amylaar@spamcop.net>
+
+       * cgraphunit.c (plugin.h): Include.
+       (ipa_passes): Invoke PLUGIN_ALL_IPA_PASSES_START /
+       PLUGIN_ALL_IPA_PASSES_END at start / end of processing.
+       * gcc-plugin.h (highlev-plugin-common.h, hashtab.h): Include.
+       (enum plugin_event): Define by including plugin.def.
+       Last enumerator is now called PLUGIN_EVENT_FIRST_DYNAMIC.
+       (plugin_event_name): Change type to const char **.
+       (get_event_last, get_named_event_id, unregister_callback): Declare.
+       (register_callback): Change type of event argument to int.
+       (highlev-plugin-common.h): New file.
+       * Makefile.in (GCC_PLUGIN_H): Add highlev-plugin-common.h and
+       $(HASHTAB_H)
+       (tree-optimize.o passes.o): Depend on $(PLUGIN_H).
+       (PLUGIN_HEADERS): Add opts.h, $(PARAMS_H) and plugin.def.
+       (s-header-vars): New rule.
+       (install-plugin): Depend on s-header-vars.  Install b-header-vars.
+       * params.c (get_num_compiler_params): New function.
+       * params.h (get_num_compiler_params): Declare.
+       * passes.c (plugin.h): Include.
+       (make_pass_instance): Invoke PLUGIN_NEW_PASS.
+       (do_per_function_toporder, pass_init_dump_file): No longer static.
+       (pass_fini_dump_file): Likewise.
+       (execute_one_pass): Likewise.  Invoke PLUGIN_OVERRIDE_GATE and
+       PLUGIN_PASS_EXECUTION.
+       (execute_ipa_pass_list): Invoke PLUGIN_EARLY_GIMPLE_PASSES_START and
+       PLUGIN_EARLY_GIMPLE_PASSES_END.
+       * plugin.c (plugin_event_name_init): New array, defined by
+       including plugin.def.
+       (FMT_FOR_PLUGIN_EVENT): Update.
+       (plugin_event_name): Change type to const char ** and initialize
+       to plugin_event_name_init.
+       (event_tab, event_last, event_horizon): New variable.
+       (get_event_last): New function.
+       (plugin_callbacks_init): New array.
+       (plugin_callbacks: Change type to struct callback_info **.
+       Initialize to plugin_callbacks_init.
+       (htab_event_eq, get_named_event_id, unregister_callback): New function.
+       (invoke_plugin_va_callbacks): Likewise.
+       (register_callback): Change type of event argument to int.
+       Handle new events.  Allow dynamic events.
+       (invoke_plugin_callbacks): Likewise.  Return success status.
+       (plugins_active_p): Allow dynamic callbacks.
+       * plugin.def: New file.
+       * plugin.h (invoke_plugin_callbacks): Update prototype.
+       (invoke_plugin_va_callbacks): Declare.
+       * tree-optimize.c (plugin.h): Include.
+       (tree_rest_of_compilation): Invoke PLUGIN_ALL_PASSES_START and
+       PLUGIN_ALL_PASSES_END.
+       * tree-pass.h (execute_one_pass, pass_init_dump_file): Declare.
+       (pass_fini_dump_file, do_per_function_toporder): Likewise.
+       * doc/plugin.texi: Document new event types.
+
 2009-12-01  Martin Jambor  <mjambor@suse.cz>
 
        PR tree-optimization/42237
index ece9f74..9379a20 100644 (file)
@@ -943,7 +943,8 @@ TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
 IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H)
 GSTAB_H = gstab.h stab.def
 BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h
-GCC_PLUGIN_H = gcc-plugin.h $(CONFIG_H) $(SYSTEM_H)
+GCC_PLUGIN_H = gcc-plugin.h highlev-plugin-common.h $(CONFIG_H) $(SYSTEM_H) \
+               $(HASHTAB_H)
 PLUGIN_H = plugin.h $(GCC_PLUGIN_H)
 PLUGIN_VERSION_H = plugin-version.h configargs.h
 
@@ -2503,8 +2504,9 @@ tree-ssa-reassoc.o : tree-ssa-reassoc.c $(TREE_FLOW_H) $(CONFIG_H) \
    langhooks.h alloc-pool.h pointer-set.h $(CFGLOOP_H)
 tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) hard-reg-set.h $(EXPR_H) $(GGC_H) output.h \
-   $(DIAGNOSTIC_H) $(BASIC_BLOCK_H) $(FLAGS_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
-   $(TREE_DUMP_H) $(TOPLEV_H) $(FUNCTION_H) langhooks.h $(FLAGS_H) $(CGRAPH_H) \
+   $(DIAGNOSTIC_H) $(BASIC_BLOCK_H) $(FLAGS_H) $(TIMEVAR_H) $(TM_H) \
+   coretypes.h $(TREE_DUMP_H) $(TOPLEV_H) $(FUNCTION_H) langhooks.h \
+   $(FLAGS_H) $(CGRAPH_H) $(PLUGIN_H) \
    $(TREE_INLINE_H) tree-mudflap.h $(GGC_H) graph.h $(CGRAPH_H) \
    $(TREE_PASS_H) $(CFGLOOP_H) $(EXCEPT_H)
 
@@ -2725,7 +2727,8 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    langhooks.h insn-flags.h $(CFGLAYOUT_H) $(REAL_H) $(CFGLOOP_H) \
    hosthooks.h $(CGRAPH_H) $(COVERAGE_H) $(TREE_PASS_H) $(TREE_DUMP_H) \
    $(GGC_H) $(INTEGRATE_H) $(CPPLIB_H) opts.h $(TREE_FLOW_H) $(TREE_INLINE_H) \
-   gt-passes.h $(DF_H) $(PREDICT_H) $(LTO_HEADER_H) $(LTO_SECTION_OUT_H)
+   gt-passes.h $(DF_H) $(PREDICT_H) $(LTO_HEADER_H) $(LTO_SECTION_OUT_H) \
+   $(PLUGIN_H)
 
 plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TOPLEV_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H) $(GGC_H)
@@ -4264,7 +4267,7 @@ installdirs:
 
 PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
   $(TOPLEV_H) $(BASIC_BLOCK_H) $(GIMPLE_H) $(TREE_PASS_H) $(GCC_PLUGIN_H) \
-  $(GGC_H) $(TREE_DUMP_H) $(PRETTY_PRINT_H) \
+  $(GGC_H) $(TREE_DUMP_H) $(PRETTY_PRINT_H) opts.h $(PARAMS_H) plugin.def \
   $(tm_file_list) $(tm_include_list) $(tm_p_file_list) $(tm_p_include_list) \
   $(host_xm_file_list) $(host_xm_include_list) $(xm_include_list) \
   intl.h $(PLUGIN_VERSION_H) $(DIAGNOSTIC_H) $(C_COMMON_H) $(C_PRETTY_PRINT_H) \
@@ -4273,8 +4276,15 @@ PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
   $(C_PRAGMA_H)  $(CPPLIB_H)  $(FUNCTION_H) \
   cppdefault.h flags.h $(MD5_H) params.def params.h prefix.h tree-inline.h
 
+# generate the 'build fragment' b-header-vars
+s-header-vars: Makefile
+       rm -f tmp-header-vars
+       $(foreach header_var,$(shell sed < Makefile -e 's/^\([A-Z0-9_]*_H\)[      ]*=.*/\1/p' -e d),echo $(header_var)=$(shell echo $($(header_var):$(srcdir)/%=.../%) | sed -e 's~\.\.\./config/~config/~' -e 's~\.\.\..*/~~') >> tmp-header-vars;) \
+       $(SHELL) $(srcdir)/../move-if-change tmp-header-vars b-header-vars
+       $(STAMP) s-header-vars
+
 # Install the headers needed to build a plugin.
-install-plugin: installdirs lang.install-plugin
+install-plugin: installdirs lang.install-plugin s-header-vars
 # We keep the directory structure for files in config and .def files. All
 # other files are flattened to a single directory.
        $(mkinstalldirs) $(DESTDIR)$(plugin_includedir)
@@ -4298,6 +4308,7 @@ install-plugin: installdirs lang.install-plugin
          $(mkinstalldirs) $(DESTDIR)$$dir; \
          $(INSTALL_DATA) $$path $(DESTDIR)$$dest; \
        done
+       $(INSTALL_DATA) b-header-vars $(DESTDIR)$(plugin_includedir)/b-header-vars
 
 # Install the compiler executables built during cross compilation.
 install-common: native lang.install-common installdirs
index e382543..51ead06 100644 (file)
@@ -135,6 +135,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "output.h"
 #include "coverage.h"
+#include "plugin.h"
 
 static void cgraph_expand_all_functions (void);
 static void cgraph_mark_functions_to_output (void);
@@ -1712,6 +1713,8 @@ ipa_passes (void)
   gimple_register_cfg_hooks ();
   bitmap_obstack_initialize (NULL);
 
+  invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_START, NULL);
+
   if (!in_lto_p)
     execute_ipa_pass_list (all_small_ipa_passes);
 
@@ -1730,7 +1733,8 @@ ipa_passes (void)
       current_function_decl = NULL;
       cgraph_process_new_functions ();
 
-      execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
+      execute_ipa_summary_passes
+       ((struct ipa_opt_pass_d *) all_regular_ipa_passes);
     }
   execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes);
 
@@ -1739,6 +1743,7 @@ ipa_passes (void)
 
   if (!flag_ltrans)
     execute_ipa_pass_list (all_regular_ipa_passes);
+  invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL);
 
   bitmap_obstack_release (NULL);
 }
index eb1008e..8aac0f7 100644 (file)
@@ -156,18 +156,42 @@ enum plugin_event
   PLUGIN_ATTRIBUTES,            /* Called during attribute registration */
   PLUGIN_START_UNIT,            /* Called before processing a translation unit.  */
   PLUGIN_PRAGMAS,              /* Called during pragma registration. */
-  PLUGIN_EVENT_LAST             /* Dummy event used for indexing callback
+  /* Called before first pass from all_passes.  */
+  PLUGIN_ALL_PASSES_START,
+  /* Called after last pass from all_passes.  */
+  PLUGIN_ALL_PASSES_END,
+  /* Called before first ipa pass.  */
+  PLUGIN_ALL_IPA_PASSES_START,
+  /* Called after last ipa pass.  */
+  PLUGIN_ALL_IPA_PASSES_END,
+  /* Allows to override pass gate decision for current_pass.  */
+  PLUGIN_OVERRIDE_GATE,
+  /* Called before executing a pass.  */
+  PLUGIN_PASS_EXECUTION,
+  /* Called before executing subpasses of a GIMPLE_PASS in
+     execute_ipa_pass_list.  */
+  PLUGIN_EARLY_GIMPLE_PASSES_START,
+  /* Called after executing subpasses of a GIMPLE_PASS in
+     execute_ipa_pass_list.  */
+  PLUGIN_EARLY_GIMPLE_PASSES_END,
+  /* Called when a pass is first instantiated.  */
+  PLUGIN_NEW_PASS,
+
+  PLUGIN_EVENT_FIRST_DYNAMIC    /* Dummy event used for indexing callback
                                    array.  */
 @};
 @end smallexample
 
+In addition, plugins can also look up the enumerator of a named event,
+and / or generate new events dynamically, by calling the function
+@code{get_named_event_id}.
 
 To register a callback, the plugin calls @code{register_callback} with
 the arguments:
 
 @itemize
 @item @code{char *name}: Plugin name.
-@item @code{enum plugin_event event}: The event code.
+@item @code{int event}: The event code.
 @item @code{plugin_callback_func callback}: The function that handles @code{event}.
 @item @code{void *user_data}: Pointer to plugin-specific data.
 @end itemize
@@ -337,6 +361,41 @@ It is suggested to pass @code{"GCCPLUGIN"} (or a short name identifying
 your plugin) as the ``space'' argument of your pragma. 
 
 
+@section Recording information about pass execution
+
+The event PLUGIN_PASS_EXECUTION passes the pointer to the executed pass
+(the same as current_pass) as @code{gcc_data} to the callback.  You can also
+inspect cfun to find out about which function this pass is executed for.
+Note that this event will only be invoked if the gate check (if
+applicable, modified by PLUGIN_OVERRIDE_GATE) succeeds.
+You can use other hooks, like @code{PLUGIN_ALL_PASSES_START},
+@code{PLUGIN_ALL_PASSES_END}, @code{PLUGIN_ALL_IPA_PASSES_START},
+@code{PLUGIN_ALL_IPA_PASSES_END}, @code{PLUGIN_EARLY_GIMPLE_PASSES_START},
+and/or @code{PLUGIN_EARLY_GIMPLE_PASSES_END} to manipulate global state
+in your plugin(s) in order to get context for the pass execution.
+
+
+@section Controlling which passes are being run
+
+After the original gate function for a pass is called, its result
+- the gate status - is stored as an integer.
+Then the event @code{PLUGIN_OVERRIDE_GATE} is invoked, with a pointer
+to the gate status in the @code{gcc_data} parameter to the callback function.
+A nonzero value of the gate status means that the pass is to be executed.
+You can both read and write the gate status via the passed pointer.
+
+
+@section Keeping track of available passes
+
+When your plugin is loaded, you can inspect the various
+pass lists to determine what passes are available.  However, other
+plugins might add new passes.  Also, future changes to GCC might cause
+generic passes to be added after plugin loading.
+When a pass is first added to one of the pass lists, the event
+@code{PLUGIN_NEW_PASS} is invoked, with the callback parameter
+@code{gcc_data} pointing to the new pass.
+
+
 @section Building GCC plugins
 
 If plugins are enabled, GCC installs the headers needed to build a
index 2e36f48..ec12265 100644 (file)
@@ -26,29 +26,19 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "config.h"
 #include "system.h"
+#include "highlev-plugin-common.h"
+#include "hashtab.h"
 
-/* Event names.  Keep in sync with plugin_event_name[].  */
+/* Event names.  */
 enum plugin_event
 {
-  PLUGIN_PASS_MANAGER_SETUP,    /* To hook into pass manager.  */
-  PLUGIN_FINISH_TYPE,           /* After finishing parsing a type.  */
-  PLUGIN_FINISH_UNIT,           /* Useful for summary processing.  */
-  PLUGIN_CXX_CP_PRE_GENERICIZE, /* Allows to see low level AST in C++ FE.  */
-  PLUGIN_FINISH,                /* Called before GCC exits.  */
-  PLUGIN_INFO,                  /* Information about the plugin. */
-  PLUGIN_GGC_START,            /* Called at start of GCC Garbage Collection. */
-  PLUGIN_GGC_MARKING,          /* Extend the GGC marking. */
-  PLUGIN_GGC_END,              /* Called at end of GGC. */
-  PLUGIN_REGISTER_GGC_ROOTS,   /* Register an extra GGC root table. */
-  PLUGIN_REGISTER_GGC_CACHES,  /* Register an extra GGC cache table. */
-  PLUGIN_ATTRIBUTES,            /* Called during attribute registration.  */
-  PLUGIN_START_UNIT,            /* Called before processing a translation unit.  */
-  PLUGIN_PRAGMAS,              /* Called during pragma registration.  */
-  PLUGIN_EVENT_LAST             /* Dummy event used for indexing callback
-                                   array.  */
+# define DEFEVENT(NAME) NAME,
+# include "plugin.def"
+# undef DEFEVENT
+  PLUGIN_EVENT_FIRST_DYNAMIC
 };
 
-extern const char *plugin_event_name[];
+extern const char **plugin_event_name;
 
 struct plugin_argument
 {
@@ -127,14 +117,22 @@ typedef void (*plugin_callback_func) (void *gcc_data, void *user_data);
    USER_DATA   - plugin-provided data.
 */
 
+/* Number of event ids / names registered so far.  */
+
+extern int get_event_last (void);
+
+int get_named_event_id (const char *name, enum insert_option insert);
+
 /* This is also called without a callback routine for the
    PLUGIN_PASS_MANAGER_SETUP, PLUGIN_INFO, PLUGIN_REGISTER_GGC_ROOTS and
    PLUGIN_REGISTER_GGC_CACHES pseudo-events, with a specific user_data.
   */
 
 extern void register_callback (const char *plugin_name,
-                               enum plugin_event event,
+                              int event,
                                plugin_callback_func callback,
                                void *user_data);
 
+extern int unregister_callback (const char *plugin_name, int event);
+
 #endif /* GCC_PLUGIN_H */
diff --git a/gcc/highlev-plugin-common.h b/gcc/highlev-plugin-common.h
new file mode 100644 (file)
index 0000000..7af2d0a
--- /dev/null
@@ -0,0 +1,33 @@
+/* Interface for high-level plugins in GCC - Parts common between GCC,
+   ICI and high-level plugins.
+
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   Contributed by INRIA.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef HIGHLEV_PLUGIN_COMMON_H
+#define HIGHLEV_PLUGIN_COMMON_H
+
+/* Return codes for invoke_plugin_callbacks / call_plugin_event .  */
+#define PLUGEVT_SUCCESS         0
+#define PLUGEVT_NO_EVENTS       1
+#define PLUGEVT_NO_SUCH_EVENT   2
+#define PLUGEVT_NO_CALLBACK     3
+
+#endif /* HIGHLEV_PLUGIN_COMMON_H */
index d7179c0..04eff11 100644 (file)
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  If not see
 param_info *compiler_params;
 
 /* The number of entries in the table.  */
-
 static size_t num_compiler_params;
 
 /* Add the N PARAMS to the current list of compiler parameters.  */
@@ -85,3 +84,12 @@ set_param_value (const char *name, int value)
   /* If we didn't find this parameter, issue an error message.  */
   error ("invalid parameter %qs", name);
 }
+
+/* Return the current value of num_compiler_params, for the benefit of
+   plugins that use parameters as features.  */
+
+size_t
+get_num_compiler_params (void)
+{
+  return num_compiler_params;
+}
index e0bb4fa..833fc3b 100644 (file)
@@ -65,6 +65,9 @@ typedef struct param_info
 
 extern param_info *compiler_params;
 
+/* Returns the number of entries in the table, for the use by plugins.  */
+extern size_t get_num_compiler_params (void);
+
 /* Add the N PARAMS to the current list of compiler parameters.  */
 
 extern void add_params (const param_info params[], size_t n);
index 57b55c0..818adde 100644 (file)
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "predict.h"
 #include "lto-streamer.h"
+#include "plugin.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -104,7 +105,8 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 /* This is used for debugging.  It allows the current pass to printed
-   from anywhere in compilation.  */
+   from anywhere in compilation.
+   The variable current_pass is also used for statistics and plugins.  */
 struct opt_pass *current_pass;
 
 /* Call from anywhere to find out what pass this is.  Useful for
@@ -479,6 +481,8 @@ make_pass_instance (struct opt_pass *pass, bool track_duplicates)
     {
       pass->todo_flags_start |= TODO_mark_first_instance;
       pass->static_pass_number = -1;
+
+      invoke_plugin_callbacks (PLUGIN_NEW_PASS, pass);
     }
   return pass;
 }
@@ -1090,9 +1094,9 @@ static GTY ((length ("nnodes"))) struct cgraph_node **order;
 
 /* If we are in IPA mode (i.e., current_function_decl is NULL), call
    function CALLBACK for every function in the call graph.  Otherwise,
-   call CALLBACK on the current function.  */
-
-static void
+   call CALLBACK on the current function.
+   This function is global so that plugins can use it.  */
+void
 do_per_function_toporder (void (*callback) (void *data), void *data)
 {
   int i;
@@ -1317,8 +1321,9 @@ verify_curr_properties (void *data)
 #endif
 
 /* Initialize pass dump file.  */
+/* This is non-static so that the plugins can use it.  */
 
-static bool
+bool
 pass_init_dump_file (struct opt_pass *pass)
 {
   /* If a dump file name is present, open it if enabled.  */
@@ -1347,8 +1352,9 @@ pass_init_dump_file (struct opt_pass *pass)
 }
 
 /* Flush PASS dump file.  */
+/* This is non-static so that plugins can use it.  */
 
-static void
+void
 pass_fini_dump_file (struct opt_pass *pass)
 {
   /* Flush and close dump file.  */
@@ -1476,12 +1482,14 @@ execute_all_ipa_transforms (void)
 
 /* Execute PASS. */
 
-static bool
+bool
 execute_one_pass (struct opt_pass *pass)
 {
   bool initializing_dump;
   unsigned int todo_after = 0;
 
+  bool gate_status;
+
   /* IPA passes are executed on whole program, so cfun should be NULL.
      Other passes need function context set.  */
   if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
@@ -1491,9 +1499,22 @@ execute_one_pass (struct opt_pass *pass)
 
   current_pass = pass;
 
-  /* See if we're supposed to run this pass.  */
-  if (pass->gate && !pass->gate ())
-    return false;
+  /* Check whether gate check should be avoided.
+     User controls the value of the gate through the parameter "gate_status". */
+  gate_status = (pass->gate == NULL) ? true : pass->gate();
+
+  /* Override gate with plugin.  */
+  invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
+
+  if (!gate_status)
+    {
+      current_pass = NULL;
+      return false;
+    }
+
+  /* Pass execution event trigger: useful to identify passes being
+     executed.  */
+  invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
 
   if (!quiet_flag && !cfun)
     fprintf (stderr, " <%s>", pass->name ? pass->name : "");
@@ -1756,8 +1777,12 @@ execute_ipa_pass_list (struct opt_pass *pass)
       if (execute_one_pass (pass) && pass->sub)
        {
          if (pass->sub->type == GIMPLE_PASS)
-           do_per_function_toporder ((void (*)(void *))execute_pass_list,
-                                     pass->sub);
+           {
+             invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
+             do_per_function_toporder ((void (*)(void *))execute_pass_list,
+                                       pass->sub);
+             invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
+           }
          else if (pass->sub->type == SIMPLE_IPA_PASS
                   || pass->sub->type == IPA_PASS)
            execute_ipa_pass_list (pass->sub);
index c43e0c8..84c9f44 100644 (file)
@@ -44,28 +44,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "plugin-version.h"
 #endif
 
+#define GCC_PLUGIN_STRINGIFY0(X) #X
+#define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
+
 /* Event names as strings.  Keep in sync with enum plugin_event.  */
-const char *plugin_event_name[] =
+static const char *plugin_event_name_init[] =
 {
-  "PLUGIN_PASS_MANAGER_SETUP",
-  "PLUGIN_FINISH_TYPE",
-  "PLUGIN_FINISH_UNIT",
-  "PLUGIN_CXX_CP_PRE_GENERICIZE",
-  "PLUGIN_FINISH",
-  "PLUGIN_INFO",
-  "PLUGIN_GGC_START",
-  "PLUGIN_GGC_MARKING",
-  "PLUGIN_GGC_END",
-  "PLUGIN_REGISTER_GGC_ROOTS",
-  "PLUGIN_REGISTER_GGC_CACHES",
-  "PLUGIN_ATTRIBUTES",
-  "PLUGIN_START_UNIT",
-  "PLUGIN_PRAGMAS",
-  "PLUGIN_EVENT_LAST"
+# define DEFEVENT(NAME) GCC_PLUGIN_STRINGIFY1 (NAME),
+# include "plugin.def"
+# undef DEFEVENT
 };
 
 /* A printf format large enough for the largest event above.  */
-#define FMT_FOR_PLUGIN_EVENT "%-26s"
+#define FMT_FOR_PLUGIN_EVENT "%-32s"
+
+const char **plugin_event_name = plugin_event_name_init;
+
+/* A hash table to map event names to the position of the names in the
+   plugin_event_name table.  */
+static htab_t event_tab;
+
+/* Keep track of the limit of allocated events and space ready for
+   allocating events.  */
+static int event_last = PLUGIN_EVENT_FIRST_DYNAMIC;
+static int event_horizon = PLUGIN_EVENT_FIRST_DYNAMIC;
 
 /* Hash table for the plugin_name_args objects created during command-line
    parsing.  */
@@ -81,7 +83,8 @@ struct callback_info
 };
 
 /* An array of lists of 'callback_info' objects indexed by the event id.  */
-static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
+static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_FIRST_DYNAMIC];
+static struct callback_info **plugin_callbacks = plugin_callbacks_init;
 
 
 #ifdef ENABLE_PLUGIN
@@ -290,6 +293,71 @@ register_plugin_info (const char* name, struct plugin_info *info)
   plugin->help = info->help;
 }
 
+/* Helper function for the event hash table that compares the name of an
+   existing entry (E1) with the given string (S2).  */
+
+static int
+htab_event_eq (const void *e1, const void *s2)
+{
+  const char *s1= *(const char * const *) e1;
+  return !strcmp (s1, (const char *) s2);
+}
+
+/* Look up the event id for NAME.  If the name is not found, return -1
+   if INSERT is NO_INSERT.  */
+
+int
+get_named_event_id (const char *name, enum insert_option insert)
+{
+  void **slot;
+
+  if (!event_tab)
+    {
+      int i;
+
+      event_tab = htab_create (150, htab_hash_string, htab_event_eq, NULL);
+      for (i = 0; i < PLUGIN_EVENT_FIRST_DYNAMIC; i++)
+       {
+         slot = htab_find_slot (event_tab, plugin_event_name[i], INSERT);
+         gcc_assert (*slot == HTAB_EMPTY_ENTRY);
+         *slot = &plugin_event_name[i];
+       }
+    }
+  slot = htab_find_slot (event_tab, name, insert);
+  if (slot == NULL)
+    return -1;
+  if (*slot != HTAB_EMPTY_ENTRY)
+    return (const char **) *slot - &plugin_event_name[0];
+
+  if (event_last >= event_horizon)
+    {
+      event_horizon = event_last * 2;
+      if (plugin_event_name == plugin_event_name_init)
+       {
+         plugin_event_name = XNEWVEC (const char *, event_horizon);
+         memcpy (plugin_event_name, plugin_event_name_init,
+                 sizeof plugin_event_name_init);
+         plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon);
+         memcpy (plugin_callbacks, plugin_callbacks_init,
+                 sizeof plugin_callbacks_init);
+       }
+      else
+       {
+         plugin_event_name
+           = XRESIZEVEC (const char *, plugin_event_name, event_horizon);
+         plugin_callbacks = XRESIZEVEC (struct callback_info *,
+                                        plugin_callbacks, event_horizon);
+       }
+      /* All the pointers in the hash table will need to be updated.  */
+      htab_delete (event_tab);
+      event_tab = NULL;
+    }
+  else
+    *slot = &plugin_event_name[event_last];
+  plugin_event_name[event_last] = name;
+  return event_last++;
+}
+
 /* Called from the plugin's initialization code. Register a single callback.
    This function can be called multiple times.
 
@@ -300,7 +368,7 @@ register_plugin_info (const char* name, struct plugin_info *info)
 
 void
 register_callback (const char *plugin_name,
-                   enum plugin_event event,
+                  int event,
                    plugin_callback_func callback,
                    void *user_data)
 {
@@ -322,6 +390,15 @@ register_callback (const char *plugin_name,
        gcc_assert (!callback);
         ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data);
        break;
+      case PLUGIN_EVENT_FIRST_DYNAMIC:
+      default:
+       if (event < PLUGIN_EVENT_FIRST_DYNAMIC || event >= event_last)
+         {
+           error ("Unknown callback event registered by plugin %s",
+                  plugin_name);
+           return;
+         }
+      /* Fall through.  */
       case PLUGIN_FINISH_TYPE:
       case PLUGIN_START_UNIT:
       case PLUGIN_FINISH_UNIT:
@@ -332,6 +409,15 @@ register_callback (const char *plugin_name,
       case PLUGIN_ATTRIBUTES:
       case PLUGIN_PRAGMAS:
       case PLUGIN_FINISH:
+      case PLUGIN_ALL_PASSES_START:
+      case PLUGIN_ALL_PASSES_END:
+      case PLUGIN_ALL_IPA_PASSES_START:
+      case PLUGIN_ALL_IPA_PASSES_END:
+      case PLUGIN_OVERRIDE_GATE:
+      case PLUGIN_PASS_EXECUTION:
+      case PLUGIN_EARLY_GIMPLE_PASSES_START:
+      case PLUGIN_EARLY_GIMPLE_PASSES_END:
+      case PLUGIN_NEW_PASS:
         {
           struct callback_info *new_callback;
           if (!callback)
@@ -348,27 +434,52 @@ register_callback (const char *plugin_name,
           plugin_callbacks[event] = new_callback;
         }
         break;
-      case PLUGIN_EVENT_LAST:
-      default:
-        error ("Unknown callback event registered by plugin %s",
-               plugin_name);
     }
 }
 
+/* Remove a callback for EVENT which has been registered with for a plugin
+   PLUGIN_NAME.  Return PLUGEVT_SUCCESS if a matching callback was
+   found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching
+   callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid.  */
+int
+unregister_callback (const char *plugin_name, int event)
+{
+  struct callback_info *callback, **cbp;
+
+  if (event >= event_last)
+    return PLUGEVT_NO_SUCH_EVENT;
+
+  for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next)
+    if (strcmp (callback->plugin_name, plugin_name) == 0)
+      {
+       *cbp = callback->next;
+       return PLUGEVT_SUCCESS;
+      }
+  return PLUGEVT_NO_CALLBACK;
+}
 
 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
    the specified event.
+   Return PLUGEVT_SUCCESS if at least one callback was called,
+   PLUGEVT_NO_CALLBACK if there was no callback.
 
    EVENT    - the event identifier
    GCC_DATA - event-specific data provided by the compiler  */
 
-void
-invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
+int
+invoke_plugin_callbacks (int event, void *gcc_data)
 {
+  int retval = PLUGEVT_SUCCESS;
+
   timevar_push (TV_PLUGIN_RUN);
 
   switch (event)
     {
+      case PLUGIN_EVENT_FIRST_DYNAMIC:
+      default:
+       gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC);
+       gcc_assert (event < event_last);
+      /* Fall through.  */
       case PLUGIN_FINISH_TYPE:
       case PLUGIN_START_UNIT:
       case PLUGIN_FINISH_UNIT:
@@ -379,24 +490,35 @@ invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
       case PLUGIN_GGC_START:
       case PLUGIN_GGC_MARKING:
       case PLUGIN_GGC_END:
+      case PLUGIN_ALL_PASSES_START:
+      case PLUGIN_ALL_PASSES_END:
+      case PLUGIN_ALL_IPA_PASSES_START:
+      case PLUGIN_ALL_IPA_PASSES_END:
+      case PLUGIN_OVERRIDE_GATE:
+      case PLUGIN_PASS_EXECUTION:
+      case PLUGIN_EARLY_GIMPLE_PASSES_START:
+      case PLUGIN_EARLY_GIMPLE_PASSES_END:
+      case PLUGIN_NEW_PASS:
         {
           /* Iterate over every callback registered with this event and
              call it.  */
           struct callback_info *callback = plugin_callbacks[event];
+
+         if (!callback)
+           retval = PLUGEVT_NO_CALLBACK;
           for ( ; callback; callback = callback->next)
             (*callback->func) (gcc_data, callback->user_data);
         }
         break;
 
       case PLUGIN_PASS_MANAGER_SETUP:
-      case PLUGIN_EVENT_LAST:
       case PLUGIN_REGISTER_GGC_ROOTS:
       case PLUGIN_REGISTER_GGC_CACHES:
-      default:
         gcc_assert (false);
     }
 
   timevar_pop (TV_PLUGIN_RUN);
+  return retval;
 }
 
 #ifdef ENABLE_PLUGIN
@@ -621,7 +743,7 @@ plugins_active_p (void)
 {
   int event;
 
-  for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+  for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
     if (plugin_callbacks[event])
       return true;
 
@@ -641,7 +763,7 @@ dump_active_plugins (FILE *file)
     return;
 
   fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
-  for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+  for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
     if (plugin_callbacks[event])
       {
        struct callback_info *ci;
@@ -686,3 +808,13 @@ plugin_default_version_check (struct plugin_gcc_version *gcc_version,
     return false;
   return true;
 }
+
+/* Return the current value of event_last, so that plugins which provide
+   additional functionality for events for the benefit of high-level plugins
+   know how many valid entries plugin_event_name holds.  */
+
+int
+get_event_last (void)
+{
+  return event_last;
+}
diff --git a/gcc/plugin.def b/gcc/plugin.def
new file mode 100644 (file)
index 0000000..b4e541e
--- /dev/null
@@ -0,0 +1,94 @@
+/* This file contains the definitions for plugin events in GCC.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* To hook into pass manager.  */
+DEFEVENT (PLUGIN_PASS_MANAGER_SETUP)
+
+/* After finishing parsing a type.  */
+DEFEVENT (PLUGIN_FINISH_TYPE)
+
+/* Useful for summary processing.  */
+DEFEVENT (PLUGIN_FINISH_UNIT)
+
+/* Allows to see low level AST in C++ FE.  */
+DEFEVENT (PLUGIN_CXX_CP_PRE_GENERICIZE)
+
+/* Called before GCC exits.  */
+DEFEVENT (PLUGIN_FINISH)
+
+/* Information about the plugin. */
+DEFEVENT (PLUGIN_INFO)
+
+/* Called at start of GCC Garbage Collection. */
+DEFEVENT (PLUGIN_GGC_START)
+
+/* Extend the GGC marking. */
+DEFEVENT (PLUGIN_GGC_MARKING)
+
+/* Called at end of GGC. */
+DEFEVENT (PLUGIN_GGC_END)
+
+/* Register an extra GGC root table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_ROOTS)
+
+/* Register an extra GGC cache table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_CACHES)
+
+/* Called during attribute registration.  */
+DEFEVENT (PLUGIN_ATTRIBUTES)
+
+/* Called before processing a translation unit.  */
+DEFEVENT (PLUGIN_START_UNIT)
+
+/* Called during pragma registration.  */
+DEFEVENT (PLUGIN_PRAGMAS)
+
+/* Called before first pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_START)
+
+/* Called after last pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_END)
+
+/* Called before first ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_START)
+
+/* Called after last ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_END)
+
+/* Allows to override pass gate decision for current_pass.  */
+DEFEVENT (PLUGIN_OVERRIDE_GATE)
+
+/* Called before executing a pass.  */
+DEFEVENT (PLUGIN_PASS_EXECUTION)
+
+/* Called before executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_START)
+
+/* Called after executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_END)
+
+/* Called when a pass is first instantiated.  */
+DEFEVENT (PLUGIN_NEW_PASS)
+
+/* After the hard-coded events above, plugins can dynamically allocate events
+   at run time.
+   PLUGIN_EVENT_FIRST_DYNAMIC only appears as last enum element.  */
index b610b23..1e1dd59 100644 (file)
@@ -26,7 +26,7 @@ struct attribute_spec;
 
 extern void add_new_plugin (const char *);
 extern void parse_plugin_arg_opt (const char *);
-extern void invoke_plugin_callbacks (enum plugin_event, void *);
+extern int invoke_plugin_callbacks (int, void *);
 extern void initialize_plugins (void);
 extern bool plugins_active_p (void);
 extern void dump_active_plugins (FILE *);
index 23b7046..42e7d10 100644 (file)
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "graph.h"
 #include "cfgloop.h"
 #include "except.h"
+#include "plugin.h"
 
 
 /* Gate: execute, or not, all of the non-trivial optimizations.  */
@@ -405,8 +406,15 @@ tree_rest_of_compilation (tree fndecl)
   execute_all_ipa_transforms ();
 
   /* Perform all tree transforms and optimizations.  */
+
+  /* Signal the start of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL);
+
   execute_pass_list (all_passes);
 
+  /* Signal the end of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL);
+
   bitmap_obstack_release (&reg_obstack);
 
   /* Release the default bitmap obstack.  */
index 473176c..b997eb1 100644 (file)
@@ -566,12 +566,16 @@ extern struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
 extern struct opt_pass *current_pass;
 
 extern struct opt_pass * get_pass_for_id (int);
+extern bool execute_one_pass (struct opt_pass *);
 extern void execute_pass_list (struct opt_pass *);
 extern void execute_ipa_pass_list (struct opt_pass *);
 extern void execute_ipa_summary_passes (struct ipa_opt_pass_d *);
 extern void execute_all_ipa_transforms (void);
 extern void execute_all_ipa_stmt_fixups (struct cgraph_node *, gimple *);
+extern bool pass_init_dump_file (struct opt_pass *);
+extern void pass_fini_dump_file (struct opt_pass *);
 
+extern const char *get_current_pass_name (void);
 extern void print_current_pass (FILE *);
 extern void debug_pass (void);
 extern void ipa_write_summaries (void);
@@ -591,4 +595,7 @@ extern void register_pass (struct register_pass_info *);
    directly in jump threading, and avoid peeling them next time.  */
 extern bool first_pass_instance;
 
+/* Declare for plugins.  */
+extern void do_per_function_toporder (void (*) (void *), void *);
+
 #endif /* GCC_TREE_PASS_H */