cgraphunit.c (plugin.h): Include.

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.

Co-Authored-By: Joern Rennecke <amylaar@spamcop.net>

From-SVN: r154877
This commit is contained in:
Grigori Fursin 2009-12-01 20:12:29 +01:00 committed by Joern Rennecke
parent d0d565e1b0
commit 090fa0ab61
14 changed files with 509 additions and 71 deletions

View 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

View 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

View 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);
}

View 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

View 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 */

View File

@ -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 */

View 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;
}

View 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);

View 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);

View 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;
}

94
gcc/plugin.def Normal file
View File

@ -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. */

View 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 *);

View 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. */

View 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 */