From c9036234fbf4b8b9c2b26ea3ba46e3bacd6d46fa Mon Sep 17 00:00:00 2001 From: amylaar Date: Tue, 1 Dec 2009 19:12:29 +0000 Subject: [PATCH] 2009-12-01 Grigori Fursin Joern Rennecke * 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 --- gcc/ChangeLog | 55 +++++++++++ gcc/Makefile.in | 23 +++-- gcc/cgraphunit.c | 7 +- gcc/doc/plugins.texi | 63 +++++++++++- gcc/gcc-plugin.h | 36 ++++--- gcc/highlev-plugin-common.h | 33 +++++++ gcc/params.c | 10 +- gcc/params.h | 3 + gcc/passes.c | 49 +++++++--- gcc/plugin.c | 190 ++++++++++++++++++++++++++++++------ gcc/plugin.def | 94 ++++++++++++++++++ gcc/plugin.h | 2 +- gcc/tree-optimize.c | 8 ++ gcc/tree-pass.h | 7 ++ 14 files changed, 509 insertions(+), 71 deletions(-) create mode 100644 gcc/highlev-plugin-common.h create mode 100644 gcc/plugin.def diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3b15962e71fa..1b822330ca5b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,58 @@ +2009-12-01 Grigori Fursin + Joern Rennecke + + * 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 PR tree-optimization/42237 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ece9f7427025..9379a206304d 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 e3825433d87e..51ead06bc4a2 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 eb1008e8f2cd..8aac0f7b65c1 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 2e36f4862629..ec12265417de 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 000000000000..7af2d0a3f9c5 --- /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 +. */ + +#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 d7179c085fcc..04eff112055f 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 e0bb4fa7e9bd..833fc3bb2f14 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 57b55c08fc99..818adde18e0b 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 c43e0c844a13..84c9f4434dc8 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 000000000000..b4e541e3c174 --- /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 +. */ + + +/* 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 b610b23ed93e..1e1dd594937c 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 23b7046c60d4..42e7d10b1282 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 (®_obstack); /* Release the default bitmap obstack. */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 473176c21c9b..b997eb126ece 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 */ -- 2.39.5