Fwd: RFA: plugin events for ICI

Joern Rennecke amylaar@spamcop.net
Tue Dec 1 17:25:00 GMT 2009


Quoting Diego Novillo <dnovillo@google.com>:
>> +the gate test - the gate status - stored as an integer.
>
> I can't parse this.

New text:

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.

>> +When your plugin is loaded, yt the moment you can inspect the various
>> +pass lists to determine what passes are available.
>
> I'm not sure what you are trying to say here.  Did you meant 'at'
> instead of 'yt'?  Still, this is hard to parse.

Yes, less is more here:

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.

>> +/* Number of event ids / names registered so far.  */
>> +
>> +extern int event_last;
>
> Why is this a global?  I'd rather have it as a static variable
> that is updated every time an event is registered.

Changed to file static + query function.

I am currently testing the attached patch locally & on gcc14.
-------------- next part --------------
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.

diff -drupN --exclude .svn gcc/gcc/cgraphunit.c gcc-ici-4/gcc/cgraphunit.c
--- gcc/gcc/cgraphunit.c	2009-11-29 17:42:48.662772536 +0000
+++ gcc-ici-4/gcc/cgraphunit.c	2009-12-01 13:54:02.833653857 +0000
@@ -135,6 +135,7 @@ along with GCC; see the file COPYING3.  
 #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 -drupN --exclude .svn gcc/gcc/doc/plugins.texi gcc-ici-4/gcc/doc/plugins.texi
--- gcc/gcc/doc/plugins.texi	2009-11-29 17:42:32.565901921 +0000
+++ gcc-ici-4/gcc/doc/plugins.texi	2009-12-01 16:31:15.979654130 +0000
@@ -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
 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 -drupN --exclude .svn gcc/gcc/gcc-plugin.h gcc-ici-4/gcc/gcc-plugin.h
--- gcc/gcc/gcc-plugin.h	2009-11-08 21:11:04.273376423 +0000
+++ gcc-ici-4/gcc/gcc-plugin.h	2009-12-01 17:01:11.379653175 +0000
@@ -26,29 +26,19 @@ along with GCC; see the file COPYING3.  
 
 #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) (vo
    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 -drupN --exclude .svn gcc/gcc/highlev-plugin-common.h gcc-ici-4/gcc/highlev-plugin-common.h
--- gcc/gcc/highlev-plugin-common.h	1970-01-01 01:00:00.000000000 +0100
+++ gcc-ici-4/gcc/highlev-plugin-common.h	2009-12-01 13:49:26.129669583 +0000
@@ -0,0 +1,33 @@
+/* Interface for high-level plugins in GCC - Parts common between GCC,
+   ICI and high-level plugins.
+
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   Contributed by INRIA.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef HIGHLEV_PLUGIN_COMMON_H
+#define HIGHLEV_PLUGIN_COMMON_H
+
+/* Return codes for invoke_plugin_callbacks / call_plugin_event .  */
+#define PLUGEVT_SUCCESS         0
+#define PLUGEVT_NO_EVENTS       1
+#define PLUGEVT_NO_SUCH_EVENT   2
+#define PLUGEVT_NO_CALLBACK     3
+
+#endif /* HIGHLEV_PLUGIN_COMMON_H */
diff -drupN --exclude .svn gcc/gcc/Makefile.in gcc-ici-4/gcc/Makefile.in
--- gcc/gcc/Makefile.in	2009-11-29 17:42:49.155526086 +0000
+++ gcc-ici-4/gcc/Makefile.in	2009-12-01 14:08:00.428897667 +0000
@@ -943,7 +943,8 @@ TREE_VECTORIZER_H = tree-vectorizer.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 
    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
    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) $
   $(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
 	  $(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 -drupN --exclude .svn gcc/gcc/params.c gcc-ici-4/gcc/params.c
--- gcc/gcc/params.c	2009-11-04 14:49:32.468125810 +0000
+++ gcc-ici-4/gcc/params.c	2009-12-01 16:44:30.849653237 +0000
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  
 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 v
   /* 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 -drupN --exclude .svn gcc/gcc/params.h gcc-ici-4/gcc/params.h
--- gcc/gcc/params.h	2009-11-29 17:42:48.652772589 +0000
+++ gcc-ici-4/gcc/params.h	2009-12-01 16:44:50.248653402 +0000
@@ -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 -drupN --exclude .svn gcc/gcc/passes.c gcc-ici-4/gcc/passes.c
--- gcc/gcc/passes.c	2009-11-29 17:42:49.163525359 +0000
+++ gcc-ici-4/gcc/passes.c	2009-12-01 16:43:31.059530137 +0000
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  
 #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.  
 #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 *pas
     {
       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 
 
 /* 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 *pa
 }
 
 /* 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 *
       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 -drupN --exclude .svn gcc/gcc/plugin.c gcc-ici-4/gcc/plugin.c
--- gcc/gcc/plugin.c	2009-11-29 17:42:49.053525413 +0000
+++ gcc-ici-4/gcc/plugin.c	2009-12-01 16:49:06.384654230 +0000
@@ -44,28 +44,30 @@ along with GCC; see the file COPYING3.  
 #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, 
   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, 
 
 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_na
 	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_na
       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_na
           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_eve
       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 plu
     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 -drupN --exclude .svn gcc/gcc/plugin.def gcc-ici-4/gcc/plugin.def
--- gcc/gcc/plugin.def	1970-01-01 01:00:00.000000000 +0100
+++ gcc-ici-4/gcc/plugin.def	2009-12-01 13:45:58.662653796 +0000
@@ -0,0 +1,94 @@
+/* This file contains the definitions for plugin events in GCC.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* To hook into pass manager.  */
+DEFEVENT (PLUGIN_PASS_MANAGER_SETUP)
+
+/* After finishing parsing a type.  */
+DEFEVENT (PLUGIN_FINISH_TYPE)
+
+/* Useful for summary processing.  */
+DEFEVENT (PLUGIN_FINISH_UNIT)
+
+/* Allows to see low level AST in C++ FE.  */
+DEFEVENT (PLUGIN_CXX_CP_PRE_GENERICIZE)
+
+/* Called before GCC exits.  */
+DEFEVENT (PLUGIN_FINISH)
+
+/* Information about the plugin. */
+DEFEVENT (PLUGIN_INFO)
+
+/* Called at start of GCC Garbage Collection. */
+DEFEVENT (PLUGIN_GGC_START)
+
+/* Extend the GGC marking. */
+DEFEVENT (PLUGIN_GGC_MARKING)
+
+/* Called at end of GGC. */
+DEFEVENT (PLUGIN_GGC_END)
+
+/* Register an extra GGC root table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_ROOTS)
+
+/* Register an extra GGC cache table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_CACHES)
+
+/* Called during attribute registration.  */
+DEFEVENT (PLUGIN_ATTRIBUTES)
+
+/* Called before processing a translation unit.  */
+DEFEVENT (PLUGIN_START_UNIT)
+
+/* Called during pragma registration.  */
+DEFEVENT (PLUGIN_PRAGMAS)
+
+/* Called before first pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_START)
+
+/* Called after last pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_END)
+
+/* Called before first ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_START)
+
+/* Called after last ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_END)
+
+/* Allows to override pass gate decision for current_pass.  */
+DEFEVENT (PLUGIN_OVERRIDE_GATE)
+
+/* Called before executing a pass.  */
+DEFEVENT (PLUGIN_PASS_EXECUTION)
+
+/* Called before executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_START)
+
+/* Called after executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_END)
+
+/* Called when a pass is first instantiated.  */
+DEFEVENT (PLUGIN_NEW_PASS)
+
+/* After the hard-coded events above, plugins can dynamically allocate events
+   at run time.
+   PLUGIN_EVENT_FIRST_DYNAMIC only appears as last enum element.  */
diff -drupN --exclude .svn gcc/gcc/plugin.h gcc-ici-4/gcc/plugin.h
--- gcc/gcc/plugin.h	2009-11-04 14:49:32.602125905 +0000
+++ gcc-ici-4/gcc/plugin.h	2009-12-01 13:41:08.259654594 +0000
@@ -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 -drupN --exclude .svn gcc/gcc/tree-optimize.c gcc-ici-4/gcc/tree-optimize.c
--- gcc/gcc/tree-optimize.c	2009-11-29 17:42:49.047772795 +0000
+++ gcc-ici-4/gcc/tree-optimize.c	2009-12-01 13:57:08.926528800 +0000
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  
 #include "graph.h"
 #include "cfgloop.h"
 #include "except.h"
+#include "plugin.h"
 
 
 /* Gate: execute, or not, all of the non-trivial optimizations.  */
@@ -405,8 +406,15 @@ tree_rest_of_compilation (tree fndecl)
   execute_all_ipa_transforms ();
 
   /* Perform all tree transforms and optimizations.  */
+
+  /* Signal the start of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL);
+
   execute_pass_list (all_passes);
 
+  /* Signal the end of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL);
+
   bitmap_obstack_release (&reg_obstack);
 
   /* Release the default bitmap obstack.  */
diff -drupN --exclude .svn gcc/gcc/tree-pass.h gcc-ici-4/gcc/tree-pass.h
--- gcc/gcc/tree-pass.h	2009-11-29 17:42:48.639772819 +0000
+++ gcc-ici-4/gcc/tree-pass.h	2009-12-01 13:13:57.689528409 +0000
@@ -565,12 +565,16 @@ extern struct opt_pass *all_passes, *all
 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);
@@ -590,4 +594,7 @@ extern void register_pass (struct regist
    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 */
-------------- next part --------------
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.

diff -drupN --exclude .svn gcc/gcc/cgraphunit.c gcc-ici-4/gcc/cgraphunit.c
--- gcc/gcc/cgraphunit.c	2009-11-29 17:42:48.662772536 +0000
+++ gcc-ici-4/gcc/cgraphunit.c	2009-12-01 13:54:02.833653857 +0000
@@ -135,6 +135,7 @@ along with GCC; see the file COPYING3.  
 #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 -drupN --exclude .svn gcc/gcc/doc/plugins.texi gcc-ici-4/gcc/doc/plugins.texi
--- gcc/gcc/doc/plugins.texi	2009-11-29 17:42:32.565901921 +0000
+++ gcc-ici-4/gcc/doc/plugins.texi	2009-12-01 16:31:15.979654130 +0000
@@ -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
 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 -drupN --exclude .svn gcc/gcc/gcc-plugin.h gcc-ici-4/gcc/gcc-plugin.h
--- gcc/gcc/gcc-plugin.h	2009-11-08 21:11:04.273376423 +0000
+++ gcc-ici-4/gcc/gcc-plugin.h	2009-12-01 17:01:11.379653175 +0000
@@ -26,29 +26,19 @@ along with GCC; see the file COPYING3.  
 
 #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) (vo
    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 -drupN --exclude .svn gcc/gcc/highlev-plugin-common.h gcc-ici-4/gcc/highlev-plugin-common.h
--- gcc/gcc/highlev-plugin-common.h	1970-01-01 01:00:00.000000000 +0100
+++ gcc-ici-4/gcc/highlev-plugin-common.h	2009-12-01 13:49:26.129669583 +0000
@@ -0,0 +1,33 @@
+/* Interface for high-level plugins in GCC - Parts common between GCC,
+   ICI and high-level plugins.
+
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+   Contributed by INRIA.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef HIGHLEV_PLUGIN_COMMON_H
+#define HIGHLEV_PLUGIN_COMMON_H
+
+/* Return codes for invoke_plugin_callbacks / call_plugin_event .  */
+#define PLUGEVT_SUCCESS         0
+#define PLUGEVT_NO_EVENTS       1
+#define PLUGEVT_NO_SUCH_EVENT   2
+#define PLUGEVT_NO_CALLBACK     3
+
+#endif /* HIGHLEV_PLUGIN_COMMON_H */
diff -drupN --exclude .svn gcc/gcc/Makefile.in gcc-ici-4/gcc/Makefile.in
--- gcc/gcc/Makefile.in	2009-11-29 17:42:49.155526086 +0000
+++ gcc-ici-4/gcc/Makefile.in	2009-12-01 14:08:00.428897667 +0000
@@ -943,7 +943,8 @@ TREE_VECTORIZER_H = tree-vectorizer.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 
    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
    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) $
   $(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
 	  $(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 -drupN --exclude .svn gcc/gcc/params.c gcc-ici-4/gcc/params.c
--- gcc/gcc/params.c	2009-11-04 14:49:32.468125810 +0000
+++ gcc-ici-4/gcc/params.c	2009-12-01 16:44:30.849653237 +0000
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3.  
 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 v
   /* 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 -drupN --exclude .svn gcc/gcc/params.h gcc-ici-4/gcc/params.h
--- gcc/gcc/params.h	2009-11-29 17:42:48.652772589 +0000
+++ gcc-ici-4/gcc/params.h	2009-12-01 16:44:50.248653402 +0000
@@ -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 -drupN --exclude .svn gcc/gcc/passes.c gcc-ici-4/gcc/passes.c
--- gcc/gcc/passes.c	2009-11-29 17:42:49.163525359 +0000
+++ gcc-ici-4/gcc/passes.c	2009-12-01 16:43:31.059530137 +0000
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.  
 #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.  
 #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 *pas
     {
       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 
 
 /* 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 *pa
 }
 
 /* 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 *
       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 -drupN --exclude .svn gcc/gcc/plugin.c gcc-ici-4/gcc/plugin.c
--- gcc/gcc/plugin.c	2009-11-29 17:42:49.053525413 +0000
+++ gcc-ici-4/gcc/plugin.c	2009-12-01 16:49:06.384654230 +0000
@@ -44,28 +44,30 @@ along with GCC; see the file COPYING3.  
 #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, 
   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, 
 
 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_na
 	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_na
       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_na
           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_eve
       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 plu
     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 -drupN --exclude .svn gcc/gcc/plugin.def gcc-ici-4/gcc/plugin.def
--- gcc/gcc/plugin.def	1970-01-01 01:00:00.000000000 +0100
+++ gcc-ici-4/gcc/plugin.def	2009-12-01 13:45:58.662653796 +0000
@@ -0,0 +1,94 @@
+/* This file contains the definitions for plugin events in GCC.
+   Copyright (C) 2009 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* To hook into pass manager.  */
+DEFEVENT (PLUGIN_PASS_MANAGER_SETUP)
+
+/* After finishing parsing a type.  */
+DEFEVENT (PLUGIN_FINISH_TYPE)
+
+/* Useful for summary processing.  */
+DEFEVENT (PLUGIN_FINISH_UNIT)
+
+/* Allows to see low level AST in C++ FE.  */
+DEFEVENT (PLUGIN_CXX_CP_PRE_GENERICIZE)
+
+/* Called before GCC exits.  */
+DEFEVENT (PLUGIN_FINISH)
+
+/* Information about the plugin. */
+DEFEVENT (PLUGIN_INFO)
+
+/* Called at start of GCC Garbage Collection. */
+DEFEVENT (PLUGIN_GGC_START)
+
+/* Extend the GGC marking. */
+DEFEVENT (PLUGIN_GGC_MARKING)
+
+/* Called at end of GGC. */
+DEFEVENT (PLUGIN_GGC_END)
+
+/* Register an extra GGC root table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_ROOTS)
+
+/* Register an extra GGC cache table. */
+DEFEVENT (PLUGIN_REGISTER_GGC_CACHES)
+
+/* Called during attribute registration.  */
+DEFEVENT (PLUGIN_ATTRIBUTES)
+
+/* Called before processing a translation unit.  */
+DEFEVENT (PLUGIN_START_UNIT)
+
+/* Called during pragma registration.  */
+DEFEVENT (PLUGIN_PRAGMAS)
+
+/* Called before first pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_START)
+
+/* Called after last pass from all_passes.  */
+DEFEVENT (PLUGIN_ALL_PASSES_END)
+
+/* Called before first ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_START)
+
+/* Called after last ipa pass.  */
+DEFEVENT (PLUGIN_ALL_IPA_PASSES_END)
+
+/* Allows to override pass gate decision for current_pass.  */
+DEFEVENT (PLUGIN_OVERRIDE_GATE)
+
+/* Called before executing a pass.  */
+DEFEVENT (PLUGIN_PASS_EXECUTION)
+
+/* Called before executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_START)
+
+/* Called after executing subpasses of a GIMPLE_PASS in
+   execute_ipa_pass_list.  */
+DEFEVENT (PLUGIN_EARLY_GIMPLE_PASSES_END)
+
+/* Called when a pass is first instantiated.  */
+DEFEVENT (PLUGIN_NEW_PASS)
+
+/* After the hard-coded events above, plugins can dynamically allocate events
+   at run time.
+   PLUGIN_EVENT_FIRST_DYNAMIC only appears as last enum element.  */
diff -drupN --exclude .svn gcc/gcc/plugin.h gcc-ici-4/gcc/plugin.h
--- gcc/gcc/plugin.h	2009-11-04 14:49:32.602125905 +0000
+++ gcc-ici-4/gcc/plugin.h	2009-12-01 13:41:08.259654594 +0000
@@ -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 -drupN --exclude .svn gcc/gcc/tree-optimize.c gcc-ici-4/gcc/tree-optimize.c
--- gcc/gcc/tree-optimize.c	2009-11-29 17:42:49.047772795 +0000
+++ gcc-ici-4/gcc/tree-optimize.c	2009-12-01 13:57:08.926528800 +0000
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  
 #include "graph.h"
 #include "cfgloop.h"
 #include "except.h"
+#include "plugin.h"
 
 
 /* Gate: execute, or not, all of the non-trivial optimizations.  */
@@ -405,8 +406,15 @@ tree_rest_of_compilation (tree fndecl)
   execute_all_ipa_transforms ();
 
   /* Perform all tree transforms and optimizations.  */
+
+  /* Signal the start of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL);
+
   execute_pass_list (all_passes);
 
+  /* Signal the end of passes.  */
+  invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL);
+
   bitmap_obstack_release (&reg_obstack);
 
   /* Release the default bitmap obstack.  */
diff -drupN --exclude .svn gcc/gcc/tree-pass.h gcc-ici-4/gcc/tree-pass.h
--- gcc/gcc/tree-pass.h	2009-11-29 17:42:48.639772819 +0000
+++ gcc-ici-4/gcc/tree-pass.h	2009-12-01 13:13:57.689528409 +0000
@@ -565,12 +565,16 @@ extern struct opt_pass *all_passes, *all
 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);
@@ -590,4 +594,7 @@ extern void register_pass (struct regist
    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 */


More information about the Gcc-patches mailing list