summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2009-12-01 19:12:29 +0000
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2009-12-01 19:12:29 +0000
commitc9036234fbf4b8b9c2b26ea3ba46e3bacd6d46fa (patch)
tree5cb060dd65f054dc0a5dfd551c6f71e558fcdb9f
parent0ecda2ba70d65b613978d57e912b26617a6ee46d (diff)
downloadgcc-c9036234fbf4b8b9c2b26ea3ba46e3bacd6d46fa.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@154877 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog55
-rw-r--r--gcc/Makefile.in23
-rw-r--r--gcc/cgraphunit.c7
-rw-r--r--gcc/doc/plugins.texi63
-rw-r--r--gcc/gcc-plugin.h36
-rw-r--r--gcc/highlev-plugin-common.h33
-rw-r--r--gcc/params.c10
-rw-r--r--gcc/params.h3
-rw-r--r--gcc/passes.c49
-rw-r--r--gcc/plugin.c190
-rw-r--r--gcc/plugin.def94
-rw-r--r--gcc/plugin.h2
-rw-r--r--gcc/tree-optimize.c8
-rw-r--r--gcc/tree-pass.h7
14 files changed, 509 insertions, 71 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3b15962e71f..1b822330ca5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ece9f742702..9379a206304 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index e3825433d87..51ead06bc4a 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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);
}
diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi
index eb1008e8f2c..8aac0f7b65c 100644
--- a/gcc/doc/plugins.texi
+++ b/gcc/doc/plugins.texi
@@ -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
diff --git a/gcc/gcc-plugin.h b/gcc/gcc-plugin.h
index 2e36f486262..ec12265417d 100644
--- a/gcc/gcc-plugin.h
+++ b/gcc/gcc-plugin.h
@@ -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
index 00000000000..7af2d0a3f9c
--- /dev/null
+++ b/gcc/highlev-plugin-common.h
@@ -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 */
diff --git a/gcc/params.c b/gcc/params.c
index d7179c085fc..04eff112055 100644
--- a/gcc/params.c
+++ b/gcc/params.c
@@ -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;
+}
diff --git a/gcc/params.h b/gcc/params.h
index e0bb4fa7e9b..833fc3bb2f1 100644
--- a/gcc/params.h
+++ b/gcc/params.h
@@ -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);
diff --git a/gcc/passes.c b/gcc/passes.c
index 57b55c08fc9..818adde18e0 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -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);
diff --git a/gcc/plugin.c b/gcc/plugin.c
index c43e0c844a1..84c9f4434dc 100644
--- a/gcc/plugin.c
+++ b/gcc/plugin.c
@@ -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
index 00000000000..b4e541e3c17
--- /dev/null
+++ b/gcc/plugin.def
@@ -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. */
diff --git a/gcc/plugin.h b/gcc/plugin.h
index b610b23ed93..1e1dd594937 100644
--- a/gcc/plugin.h
+++ b/gcc/plugin.h
@@ -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 *);
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
index 23b7046c60d..42e7d10b128 100644
--- a/gcc/tree-optimize.c
+++ b/gcc/tree-optimize.c
@@ -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. */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 473176c21c9..b997eb126ec 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -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 */