+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
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
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)
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)
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) \
$(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)
$(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
#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);
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);
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);
if (!flag_ltrans)
execute_ipa_pass_list (all_regular_ipa_passes);
+ invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL);
bitmap_obstack_release (NULL);
}
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
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
#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
{
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 */
--- /dev/null
+/* 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 */
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. */
/* 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;
+}
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);
#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"
#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
{
pass->todo_flags_start |= TODO_mark_first_instance;
pass->static_pass_number = -1;
+
+ invoke_plugin_callbacks (PLUGIN_NEW_PASS, pass);
}
return pass;
}
/* 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;
#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. */
}
/* 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. */
/* 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)
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 : "");
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);
#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. */
};
/* 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
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.
void
register_callback (const char *plugin_name,
- enum plugin_event event,
+ int event,
plugin_callback_func callback,
void *user_data)
{
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:
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)
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:
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
{
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;
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;
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;
+}
--- /dev/null
+/* 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. */
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 *);
#include "graph.h"
#include "cfgloop.h"
#include "except.h"
+#include "plugin.h"
/* Gate: execute, or not, all of the non-trivial optimizations. */
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 (®_obstack);
/* Release the default bitmap obstack. */
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);
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 */