This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [plugins] RFA: Merge plugins into mainline [4/5 - configury]


On Tue, Apr 14, 2009 at 03:11, Paolo Bonzini <bonzini@gnu.org> wrote:

> This further change is pretty trivial, so I'll preapprove a variant of
> the patch that drops changes in the toplevel.

Thanks.  As we agreed on IRC, I moved the changes from
<toplev>/configure.ac to gcc/configure.ac.  This simplifies the
patch in that there are no changes needed in <toplev>.

With this, I now have enough approval to commit the main patch.
The changes to the testsuite are still waiting for approval.

This is the patch I will be committing to mainline.  Tested on
i686, x86_64 and darwin/i386.


Thanks.  Diego.

2009-04-14  Diego Novillo  <dnovillo@google.com>
	    Le-Chun Wu  <lcwu@google.com>

       * configure.ac: Add --enable-plugin support.
       Define ENABLE_PLUGIN and PLUGINLIBS when specified.
       * Makefile.in (PLUGIN_H): Define.
       Export ENABLE_PLUGIN and GMPINC to site.exp.
       Add PLUGINLIBS to link command.
       Add/modify dependencies for plugin.o and files including plugin.h.
       (plugin.o): New.
       * config.in: Regenerate.

       * opts.c (common_handle_option): Handle OPT_fplugin_ and
       OPT_fplugin_arg_.

2009-04-14  Le-Chun Wu  <lcwu@google.com>

       * tree-pass.h (register_one_dump_file): Add a prototype for
       register_one_dump_file.
       * toplev.c (compile_file): Call initialize_plugins.
       (do_compile): Call invoke_plugin_callbacks.
       (toplev_main): Call invoke_plugin_callbacks.
       * common.opt: Add -fplugin= and -fplugin-arg-.
       * gcc-plugin.h: New public header file for plugins to include.
       * plugin.c: New source file.
       * plugin.h: New internal header file.
       * passes.c (register_one_dump_file): Make it external.

       * c-parser.c (c_parser_declspecs): Call invoke_plugin_callbacks.

2009-04-14  Diego Novillo  <dnovillo@google.com>

       * doc/plugins.texi: New.
       * doc/gccint.texi: Add reference to Plugins chapter.
       * doc/invoke.texi: Document -fplugin and -fplugin-arg
       * diagnostic.c (diagnostic_report_diagnostic): Warn about
       loaded plugins, if any.
       * timevar.def (TV_PLUGIN_INIT): Define.
       (TV_PLUGIN_RUN): Define.
       * plugin.c: Include timevar.h
       (plugins_active_p): New.
       (dump_active_plugins): New.
       (debug_active_plugins): New.

cp/ChangeLog

2009-04-14  Le-Chun Wu  <lcwu@google.com>

       * Make-lang.in: Modify dependencies of files including plugin.h.

2009-04-14  Le-Chun Wu  <lcwu@google.com>

       * decl.c (finish_function): Call invoke_plugin_callbacks.
       * parser.c (cp_parser_type_specifier): Call invoke_plugin_callbacks.

Index: doc/plugins.texi
===================================================================
--- doc/plugins.texi	(revision 0)
+++ doc/plugins.texi	(revision 0)
@@ -0,0 +1,137 @@
+@c Copyright (c) 2009 Free Software Foundation, Inc.
+@c Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Plugins
+@chapter Plugins
+@cindex Plugins
+
+@section Loading Plugins
+
+Plugins are supported on platforms that support @option{-ld
+-rdynamic}.  They are loaded by the compiler using @code{dlopen}
+and invoked at pre-determined locations in the compilation
+process.
+
+Plugins are loaded with
+
+@option{-fplugin=/path/to/NAME.so} @option{-fplugin-arg-NAME-<key1>[=<value1>]}
+
+The plugin arguments are parsed by GCC and passed to respective
+plugins as key-value pairs. Multiple plugins can be invoked by
+specifying multiple @option{-fplugin} arguments.
+
+
+@section Plugin API
+
+Plugins are activated by the compiler at specific events as defined in
+@file{gcc-plugin.h}.  For each event of interest, the plugin should
+call @code{register_callback} specifying the name of the event and
+address of the callback function that will handle that event.
+
+@subsection Plugin initialization
+
+Every plugin should export a function called @code{plugin_init} that
+is called right after the plugin is loaded. This function is
+responsible for registering all the callbacks required by the plugin
+and do any other required initialization.
+
+This function is called from @code{compile_file} right before invoking
+the parser.  The arguments to @code{plugin_init} are:
+
+@itemize @bullet
+@item @code{plugin_name}: Name of the plugin.
+@item @code{argc}: Number of arguments specified with
@option{-fplugin-arg-...}.
+@item @code{argv}: Array of @code{argc} key-value pairs.
+@end itemize
+
+If initialization fails, @code{plugin_init} must return a non-zero
+value.  Otherwise, it should return 0.
+
+@subsection Plugin callbacks
+
+Callback functions have the following prototype:
+
+@smallexample
+/* The prototype for a plugin callback function.
+     gcc_data  - event-specific data provided by GCC
+     user_data - plugin-specific data provided by the plug-in.  */
+typedef void (*plugin_callback_func)(void *gcc_data, void *user_data);
+@end smallexample
+
+Callbacks can be invoked at the following pre-determined events:
+
+
+@smallexample
+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_EVENT_LAST             /* Dummy event used for indexing callback
+                                   array.  */
+@};
+@end smallexample
+
+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{plugin_callback_func callback}: The function that handles
@code{event}.
+@item @code{void *user_data}: Pointer to plugin-specific data.
+@end itemize
+
+
+@section Interacting with the pass manager
+
+There needs to be a way to add/reorder/remove passes dynamically. This
+is useful for both analysis plugins (plugging in after a certain pass
+such as CFG or an IPA pass) and optimization plugins.
+
+Basic support for inserting new passes or replacing existing passes is
+provided. A plugin registers a new pass with GCC by calling
+@code{register_callback} with the @code{PLUGIN_PASS_MANAGER_SETUP}
+event and a pointer to a @code{struct plugin_pass} object defined as follows
+
+@smallexample
+enum pass_positioning_ops
+@{
+  PASS_POS_INSERT_AFTER,  // Insert after the reference pass.
+  PASS_POS_INSERT_BEFORE, // Insert before the reference pass.
+  PASS_POS_REPLACE        // Replace the reference pass.
+@};
+
+struct plugin_pass
+@{
+  struct opt_pass *pass;            /* New pass provided by the plugin.  */
+  const char *reference_pass_name;  /* Name of the reference pass for hooking
+                                       up the new pass.  */
+  int ref_pass_instance_number;     /* Insert the pass at the specified
+                                       instance number of the
reference pass.  */
+                                    /* Do it for every instance if it is 0.  */
+  enum pass_positioning_ops pos_op; /* how to insert the new pass.  */
+@};
+
+
+/* Sample plugin code that registers a new pass.  */
+int
+plugin_init (const char *plugin_name, int argc, struct plugin_argument *argv)
+@{
+  struct plugin_pass pass_info;
+
+  ...
+
+  /* Code to fill in the pass_info object with new pass information.  */
+
+  ...
+
+  /* Register the new pass.  */
+  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
+
+  ...
+@}
+@end smallexample
Index: doc/gccint.texi
===================================================================
--- doc/gccint.texi	(revision 146056)
+++ doc/gccint.texi	(working copy)
@@ -122,6 +122,7 @@ Additional tutorial information is linke
 * Collect2::        How @code{collect2} works; how it finds @code{ld}.
 * Header Dirs::     Understanding the standard header file directories.
 * Type Information:: GCC's memory management; generating type information.
+* Plugins::         Extending the compiler with plugins.

 * Funding::         How to help assure funding for free software.
 * GNU Project::     The GNU Project and GNU/Linux.
@@ -157,6 +158,7 @@ Additional tutorial information is linke
 @include collect2.texi
 @include headerdirs.texi
 @include gty.texi
+@include plugins.texi

 @include funding.texi
 @include gnu.texi
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 146056)
+++ doc/invoke.texi	(working copy)
@@ -163,7 +163,7 @@ in the following sections.
 @xref{Overall Options,,Options Controlling the Kind of Output}.
 @gccoptlist{-c  -S  -E  -o @var{file}  -combine  -pipe  -pass-exit-codes  @gol
 -x @var{language}  -v  -###
--help@r{[}=@var{class}@r{[},@dots{}@r{]]}  --target-help  @gol
---version -wrapper@@@var{file}}
+--version -wrapper@@@var{file} -fplugin=@var{file}
-fplugin-arg-@var{name}=@var{arg}}

 @item C Language Options
 @xref{C Dialect Options,,Options Controlling C Dialect}.
@@ -1298,6 +1298,19 @@ gcc -c t.c -wrapper gdb,--args
 This will invoke all subprograms of gcc under "gdb --args",
 thus cc1 invocation will be "gdb --args cc1 ...".

+@item -fplugin=@var{name}.so
+Load the plugin code in file @var{name}.so, assumed to be a
+shared object to be dlopen'd by the compiler.  The base name of
+the shared object file is used to identify the plugin for the
+purposes of argument parsing (See
+@option{-fplugin-arg-@var{name}-@var{key}=@var{value}} below).
+Each plugin should define the callback functions specified in the
+Plugins API.
+
+@item -fplugin-arg-@var{name}-@var{key}=@var{value}
+Define an argument called @var{key} with a value of @var{value}
+for the plugin called @var{name}.
+
 @include @value{srcdir}/../libiberty/at-file.texi
 @end table

Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 146056)
+++ tree-pass.h	(working copy)
@@ -529,6 +529,7 @@ extern void execute_pass_list (struct op
 extern void execute_ipa_pass_list (struct opt_pass *);
 extern void print_current_pass (FILE *);
 extern void debug_pass (void);
+extern void register_one_dump_file (struct opt_pass *);
 extern bool function_called_by_processed_nodes_p (void);

 /* Set to true if the pass is called the first time during compilation of the
Index: diagnostic.c
===================================================================
--- diagnostic.c	(revision 146056)
+++ diagnostic.c	(working copy)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "opts.h"
+#include "plugin.h"

 #define pedantic_warning_kind() (flag_pedantic_errors ? DK_ERROR : DK_WARNING)
 #define permissive_error_kind() (flag_permissive ? DK_WARNING : DK_ERROR)
@@ -371,6 +372,17 @@ diagnostic_report_diagnostic (diagnostic

   context->lock++;

+  if ((diagnostic->kind == DK_ERROR
+       || diagnostic->kind == DK_WARNING
+       || diagnostic->kind == DK_ICE)
+      && plugins_active_p ())
+    {
+      fnotice (stderr, "*** WARNING *** there are active plugins, do
not report"
+	       " this as a bug unless you can reproduce it without enabling"
+	       " any plugins.\n");
+      dump_active_plugins (stderr);
+    }
+
   if (diagnostic->kind == DK_ICE)
     {
 #ifndef ENABLE_CHECKING
Index: toplev.c
===================================================================
--- toplev.c	(revision 146056)
+++ toplev.c	(working copy)
@@ -85,6 +85,7 @@ along with GCC; see the file COPYING3.
 #include "tree-pass.h"
 #include "gimple.h"
 #include "tree-ssa-alias.h"
+#include "plugin.h"

 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -968,6 +969,7 @@ compile_file (void)
   init_final (main_input_filename);
   coverage_init (aux_base_name);
   statistics_init ();
+  initialize_plugins ();

   timevar_push (TV_PARSE);

@@ -2241,6 +2243,9 @@ do_compile (void)
 	compile_file ();

       finalize ();
+
+      /* Invoke registered plugin callbacks.  */
+      invoke_plugin_callbacks (PLUGIN_FINISH_UNIT, NULL);
     }

   /* Stop timing and print the times.  */
@@ -2275,6 +2280,9 @@ toplev_main (unsigned int argc, const ch
   if (warningcount || errorcount)
     print_ignored_options ();

+  /* Invoke registered plugin callbacks if any.  */
+  invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
+
   if (errorcount || sorrycount)
     return (FATAL_EXIT_CODE);

Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 146056)
+++ cp/decl.c	(working copy)
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.
 #include "timevar.h"
 #include "tree-flow.h"
 #include "pointer-set.h"
+#include "plugin.h"

 static tree grokparms (tree parmlist, tree *);
 static const char *redeclaration_error_message (tree, tree);
@@ -12354,6 +12355,7 @@ finish_function (int flags)
   if (!processing_template_decl)
     {
       struct language_function *f = DECL_SAVED_FUNCTION_DATA (fndecl);
+      invoke_plugin_callbacks (PLUGIN_CXX_CP_PRE_GENERICIZE, fndecl);
       cp_genericize (fndecl);
       /* Clear out the bits we don't need.  */
       f->x_current_class_ptr = NULL;
Index: cp/Make-lang.in
===================================================================
--- cp/Make-lang.in	(revision 146056)
+++ cp/Make-lang.in	(working copy)
@@ -240,7 +240,7 @@ cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H)
 cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h \
   output.h $(EXPR_H) except.h toplev.h $(HASHTAB_H) $(RTL_H) \
   cp/operators.def $(TM_P_H) $(TREE_INLINE_H) $(DIAGNOSTIC_H) $(C_PRAGMA_H) \
-  debug.h gt-cp-decl.h $(TIMEVAR_H) $(TREE_FLOW_H) $(TARGET_H)
+  debug.h gt-cp-decl.h $(TIMEVAR_H) $(TREE_FLOW_H) $(TARGET_H) $(PLUGIN_H)
 cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) cp/decl.h $(EXPR_H) \
   output.h except.h toplev.h $(RTL_H) $(C_COMMON_H) gt-cp-decl2.h $(CGRAPH_H) \
   $(C_PRAGMA_H) $(TREE_DUMP_H) intl.h $(TARGET_H) $(GIMPLE_H)
@@ -292,7 +292,7 @@ cp/optimize.o: cp/optimize.c $(CXX_TREE_
 cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h $(REAL_H) \
   gt-cp-mangle.h $(TARGET_H) $(TM_P_H)
 cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) gt-cp-parser.h \
-  output.h $(TARGET_H)
+  output.h $(TARGET_H) $(PLUGIN_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) toplev.h $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h

Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 146056)
+++ cp/parser.c	(working copy)
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.
 #include "target.h"
 #include "cgraph.h"
 #include "c-common.h"
+#include "plugin.h"

 
 /* The lexer.  */
@@ -13890,6 +13891,8 @@ cp_parser_type_specifier_seq (cp_parser*
 	  break;
 	}

+      invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, type_specifier);
+
       seen_type_specifier = true;
       /* The standard says that a condition can be:

Index: opts.c
===================================================================
--- opts.c	(revision 146056)
+++ opts.c	(working copy)
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.
 #include "tree-pass.h"
 #include "dbgcnt.h"
 #include "debug.h"
+#include "plugin.h"

 /* Value of the -G xx switch, and whether it was passed or not.  */
 unsigned HOST_WIDE_INT g_switch_value;
@@ -1766,6 +1767,22 @@ common_handle_option (size_t scode, cons
       flag_peel_loops_set = true;
       break;

+    case OPT_fplugin_:
+#ifdef ENABLE_PLUGIN
+      add_new_plugin (arg);
+#else
+      error ("Plugin support is disabled.  Configure with --enable-plugin.");
+#endif
+      break;
+
+    case OPT_fplugin_arg_:
+#ifdef ENABLE_PLUGIN
+      parse_plugin_arg_opt (arg);
+#else
+      error ("Plugin support is disabled.  Configure with --enable-plugin.");
+#endif
+      break;
+
     case OPT_fprofile_arcs:
       profile_arc_flag_set = true;
       break;
Index: timevar.def
===================================================================
--- timevar.def	(revision 146056)
+++ timevar.def	(working copy)
@@ -195,6 +195,8 @@ DEFTIMEVAR (TV_FINAL                 , "
 DEFTIMEVAR (TV_SYMOUT                , "symout")
 DEFTIMEVAR (TV_VAR_TRACKING          , "variable tracking")
 DEFTIMEVAR (TV_TREE_IFCOMBINE        , "tree if-combine")
+DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
+DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")

 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_REST_OF_COMPILATION   , "rest of compilation")
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 146056)
+++ c-decl.c	(working copy)
@@ -63,6 +63,7 @@ along with GCC; see the file COPYING3.
 #include "langhooks-def.h"
 #include "pointer-set.h"
 #include "gimple.h"
+#include "plugin.h"

 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -7261,6 +7262,9 @@ struct c_declspecs *
 declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
 {
   tree type = spec.spec;
+
+  invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, type);
+
   specs->non_sc_seen_p = true;
   specs->declspecs_seen_p = true;
   specs->type_seen_p = true;
Index: configure.ac
===================================================================
--- configure.ac	(revision 146056)
+++ configure.ac	(working copy)
@@ -3949,6 +3949,74 @@ if test "x${CLOOGLIBS}" != "x" ; then
    AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.])
 fi

+# Check for plugin support
+AC_ARG_ENABLE(plugin,
+[  --enable-plugin         enable plugin support],
+enable_plugin=$enableval,
+enable_plugin=yes; default_plugin=yes)
+
+pluginlibs=
+if test x"$enable_plugin" = x"yes"; then
+  # Check that the host supports -rdynamic and -ldl
+  have_rdynamic=no
+  have_dl=no
+  saved_LDFLAGS="$LDFLAGS"
+  saved_LIBS="$LIBS"
+  LIBS=
+
+  # Check -rdynamic
+  LDFLAGS="$LDFLAGS -rdynamic"
+  AC_MSG_CHECKING([for -rdynamic])
+  AC_TRY_LINK([],[return 0;],
+    [AC_MSG_RESULT([yes]); have_rdynamic=yes],
+    [AC_MSG_RESULT([no])])
+  if test x"$have_rdynamic" = x"yes" ; then
+    pluginlibs="-rdynamic"
+  fi
+
+  # Check -ldl
+  LDFLAGS="$LDFLAGS -ldl"
+  AC_MSG_CHECKING([for -ldl])
+  AC_TRY_LINK(
+    [#include <dlfcn.h>],
+    [volatile int f = 0; if (f) dlopen ("dummy", 0);],
+    [AC_MSG_RESULT([yes]); have_dl=yes],
+    [AC_MSG_RESULT([no])])
+  if test x"$have_dl" = x"yes"; then
+    pluginlibs="$pluginlibs -ldl"
+  fi
+
+  # Check that we can build shared objects with -fPIC -shared
+  LDFLAGS="$LDFLAGS -fPIC -shared"
+  AC_MSG_CHECKING([for -fPIC -shared])
+  AC_TRY_LINK(
+    [extern int X;],[return X == 0;],
+    [AC_MSG_RESULT([yes]); have_pic_shared=yes],
+    [AC_MSG_RESULT([no]); have_pic_shared=no])
+  if test x"$have_pic_shared" != x"yes"; then
+    pluginlibs=
+    enable_plugin=no
+  fi
+
+  # If plugin support had been requested but not available, fail.
+  if test x"$enable_plugin" = x"no" ; then
+    if test x"$default_plugin" != x"yes"; then
+      AC_MSG_ERROR([
+Building GCC with plugin support requires a host that supports
+-fPIC, -shared, -ldl and -rdynamic.])
+    fi
+  fi
+
+  LDFLAGS="$saved_LDFLAGS"
+  LIBS="$saved_LIBS"
+fi
+
+AC_SUBST(pluginlibs)
+AC_SUBST(enable_plugin)
+if test x"$enable_plugin" = x"yes"; then
+  AC_DEFINE(ENABLE_PLUGIN, 1, [Define to enable plugin support.])
+fi
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)

Index: gcc-plugin.h
===================================================================
--- gcc-plugin.h	(revision 0)
+++ gcc-plugin.h	(revision 0)
@@ -0,0 +1,98 @@
+/* Public header file for plugins to include.
+   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/>.  */
+
+#ifndef GCC_PLUGIN_H
+#define GCC_PLUGIN_H
+
+/* Event names.  Keep in sync with plugin_event_name[].  */
+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_EVENT_LAST             /* Dummy event used for indexing callback
+                                   array.  */
+};
+
+extern const char *plugin_event_name[];
+
+struct plugin_argument
+{
+  char *key;    /* key of the argument.  */
+  char *value;  /* value is optional and can be NULL.  */
+};
+
+enum pass_positioning_ops
+{
+  PASS_POS_INSERT_AFTER,  /* Insert after the reference pass.  */
+  PASS_POS_INSERT_BEFORE, /* Insert before the reference pass.  */
+  PASS_POS_REPLACE        /* Replace the reference pass.  */
+};
+
+struct plugin_pass
+{
+  struct opt_pass *pass;            /* New pass provided by the plugin.  */
+  const char *reference_pass_name;  /* Name of the reference pass for hooking
+                                       up the new pass.  */
+  int ref_pass_instance_number;     /* Insert the pass at the specified
+                                       instance number of the reference pass.
+                                       Do it for every instance if it is 0.  */
+  enum pass_positioning_ops pos_op; /* how to insert the new pass.  */
+};
+
+/* Function type for the plugin initialization routine. Each plugin module
+   should define this as an externally-visible function with name
+   "plugin_init."
+
+   PLUGIN_NAME - name of the plugin (useful for error reporting)
+   ARGC        - the size of the ARGV array
+   ARGV        - an array of key-value argument pair
+
+   Returns 0 if initialization finishes successfully.  */
+
+typedef int (*plugin_init_func) (const char *plugin_name,
+                                 int argc, struct plugin_argument *argv);
+
+/* Declaration for "plugin_init" function so that it doesn't need to be
+   duplicated in every plugin.  */
+extern int plugin_init (const char *, int, struct plugin_argument *);
+
+/* Function type for a plugin callback routine.
+
+   GCC_DATA  - event-specific data provided by GCC
+   USER_DATA - plugin-specific data provided by the plugin  */
+
+typedef void (*plugin_callback_func) (void *gcc_data, void *user_data);
+
+/* Called from the plugin's initialization code. Register a single callback.
+   This function can be called multiple times.
+
+   PLUGIN_NAME - display name for this plugin
+   EVENT       - which event the callback is for
+   CALLBACK    - the callback to be called at the event
+   USER_DATA   - plugin-provided data   */
+
+extern void register_callback (const char *plugin_name,
+                               enum plugin_event event,
+                               plugin_callback_func callback,
+                               void *user_data);
+
+#endif /* GCC_PLUGIN_H */
Index: common.opt
===================================================================
--- common.opt	(revision 146056)
+++ common.opt	(working copy)
@@ -854,6 +854,14 @@ fpie
 Common Report Var(flag_pie,1) VarExists
 Generate position-independent code for executables if possible (small mode)

+fplugin=
+Common Joined RejectNegative
+Specify a plugin to load
+
+fplugin-arg-
+Common Joined RejectNegative
+-fplugin-arg-<name>-<key>[=<value>] Specify argument <key>=<value>
for plugin <name>
+
 fpredictive-commoning
 Common Report Var(flag_predictive_commoning) Optimization
 Run predictive commoning optimization.
Index: plugin.c
===================================================================
--- plugin.c	(revision 0)
+++ plugin.c	(revision 0)
@@ -0,0 +1,672 @@
+/* Support for GCC plugin mechanism.
+   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/>.  */
+
+/* This file contains the support for GCC plugin mechanism based on the
+   APIs described in doc/plugin.texi.  */
+
+#include "config.h"
+#include "system.h"
+
+/* If plugin support is not enabled, do not try to execute any code
+   that may reference libdl.  The generic code is still compiled in to
+   avoid including to many conditional compilation paths in the rest
+   of the compiler.  */
+#ifdef ENABLE_PLUGIN
+#include <dlfcn.h>
+#endif
+
+#include "coretypes.h"
+#include "toplev.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin.h"
+#include "timevar.h"
+
+/* Event names as strings.  Keep in sync with enum plugin_event.  */
+const char *plugin_event_name[] =
+{
+  "PLUGIN_PASS_MANAGER_SETUP",
+  "PLUGIN_FINISH_TYPE",
+  "PLUGIN_FINISH_UNIT",
+  "PLUGIN_CXX_CP_PRE_GENERICIZE",
+  "PLUGIN_FINISH",
+  "PLUGIN_EVENT_LAST"
+};
+
+/* Object that keeps track of the plugin name and its arguments
+   when parsing the command-line options -fplugin=/path/to/NAME.so and
+   -fplugin-arg-NAME-<key>[=<value>].  */
+struct plugin_name_args
+{
+  char *base_name;
+  const char *full_name;
+  int argc;
+  struct plugin_argument *argv;
+};
+
+/* Hash table for the plugin_name_args objects created during command-line
+   parsing.  */
+static htab_t plugin_name_args_tab = NULL;
+
+/* List node for keeping track of plugin-registered callback.  */
+struct callback_info
+{
+  const char *plugin_name;   /* Name of plugin that registers the callback.  */
+  plugin_callback_func func; /* Callback to be called.  */
+  void *user_data;           /* plugin-specified data.  */
+  struct callback_info *next;
+};
+
+/* An array of lists of 'callback_info' objects indexed by the event id.  */
+static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
+
+/* List node for an inserted pass instance. We need to keep track of all
+   the newly-added pass instances (with 'added_pass_nodes' defined below)
+   so that we can register their dump files after pass-positioning is finished.
+   Registering dumping files needs to be post-processed or the
+   static_pass_number of the opt_pass object would be modified and mess up
+   the dump file names of future pass instances to be added.  */
+struct pass_list_node
+{
+  struct opt_pass *pass;
+  struct pass_list_node *next;
+};
+
+static struct pass_list_node *added_pass_nodes = NULL;
+static struct pass_list_node *prev_added_pass_node;
+
+#ifdef ENABLE_PLUGIN
+/* Each plugin should define an initialization function with exactly
+   this name.  */
+static const char *str_plugin_init_func_name = "plugin_init";
+#endif
+
+/* Helper function for the hash table that compares the base_name of the
+   existing entry (S1) with the given string (S2).  */
+
+static int
+htab_str_eq (const void *s1, const void *s2)
+{
+  const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
+  return !strcmp (plugin->base_name, (const char *) s2);
+}
+
+
+/* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
+   return NAME.  */
+
+static char *
+get_plugin_base_name (const char *full_name)
+{
+  /* First get the base name part of the full-path name, i.e. NAME.so.  */
+  char *base_name = xstrdup (lbasename (full_name));
+
+  /* Then get rid of '.so' part of the name.  */
+  strip_off_ending (base_name, strlen (base_name));
+
+  return base_name;
+}
+
+
+/* Create a plugin_name_args object for the give plugin and insert it to
+   the hash table. This function is called when -fplugin=/path/to/NAME.so
+   option is processed.  */
+
+void
+add_new_plugin (const char* plugin_name)
+{
+  struct plugin_name_args *plugin;
+  void **slot;
+  char *base_name = get_plugin_base_name (plugin_name);
+
+  /* If this is the first -fplugin= option we encounter, create
+     'plugin_name_args_tab' hash table.  */
+  if (!plugin_name_args_tab)
+    plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
+                                        NULL);
+
+  slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
+
+  /* If the same plugin (name) has been specified earlier, either emit an
+     error or a warning message depending on if they have identical full
+     (path) names.  */
+  if (*slot)
+    {
+      plugin = (struct plugin_name_args *) *slot;
+      if (strcmp (plugin->full_name, plugin_name))
+        error ("Plugin %s was specified with different paths:\n%s\n%s",
+               plugin->base_name, plugin->full_name, plugin_name);
+      return;
+    }
+
+  plugin = XCNEW (struct plugin_name_args);
+  plugin->base_name = base_name;
+  plugin->full_name = plugin_name;
+
+  *slot = plugin;
+}
+
+
+/* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
+   'plugin_argument' object for the parsed key-value pair. ARG is
+   the <name>-<key>[=<value>] part of the option.  */
+
+void
+parse_plugin_arg_opt (const char *arg)
+{
+  size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
+  const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
+  char *name, *key, *value;
+  void **slot;
+  bool name_parsed = false, key_parsed = false;
+
+  /* Iterate over the ARG string and identify the starting character position
+     of 'name', 'key', and 'value' and their lengths.  */
+  for (ptr = arg; *ptr; ++ptr)
+    {
+      /* Only the first '-' encountered is considered a separator between
+         'name' and 'key'. All the subsequent '-'s are considered part of
+         'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
+         the plugin name is 'foo' and the key is 'bar-primary-key'.  */
+      if (*ptr == '-' && !name_parsed)
+        {
+          name_len = len;
+          len = 0;
+          key_start = ptr + 1;
+          name_parsed = true;
+          continue;
+        }
+      else if (*ptr == '=')
+        {
+          if (key_parsed)
+            {
+              error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
+		     arg);
+              return;
+            }
+          key_len = len;
+          len = 0;
+          value_start = ptr + 1;
+          key_parsed = true;
+          continue;
+        }
+      else
+        ++len;
+    }
+
+  if (!key_start)
+    {
+      error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
+             arg);
+      return;
+    }
+
+  /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
+     Otherwise, it is the VALUE_LEN.  */
+  if (!value_start)
+    key_len = len;
+  else
+    value_len = len;
+
+  name = XNEWVEC (char, name_len + 1);
+  strncpy (name, name_start, name_len);
+  name[name_len] = '\0';
+
+  /* Check if the named plugin has already been specified earlier in the
+     command-line.  */
+  if (plugin_name_args_tab
+      && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
+          != NULL))
+    {
+      struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
+
+      key = XNEWVEC (char, key_len + 1);
+      strncpy (key, key_start, key_len);
+      key[key_len] = '\0';
+      if (value_start)
+        {
+          value = XNEWVEC (char, value_len + 1);
+          strncpy (value, value_start, value_len);
+          value[value_len] = '\0';
+        }
+      else
+        value = NULL;
+
+      /* Create a plugin_argument object for the parsed key-value pair.
+         If there are already arguments for this plugin, we will need to
+         adjust the argument array size by creating a new array and deleting
+         the old one. If the performance ever becomes an issue, we can
+         change the code by pre-allocating a larger array first.  */
+      if (plugin->argc > 0)
+        {
+          struct plugin_argument *args = XNEWVEC (struct plugin_argument,
+                                                  plugin->argc + 1);
+          memcpy (args, plugin->argv,
+                  sizeof (struct plugin_argument) * plugin->argc);
+          XDELETEVEC (plugin->argv);
+          plugin->argv = args;
+          ++plugin->argc;
+        }
+      else
+        {
+          gcc_assert (plugin->argv == NULL);
+          plugin->argv = XNEWVEC (struct plugin_argument, 1);
+          plugin->argc = 1;
+        }
+
+      plugin->argv[plugin->argc - 1].key = key;
+      plugin->argv[plugin->argc - 1].value = value;
+    }
+  else
+    error ("Plugin %s should be specified before -fplugin-arg-%s "
+           "in the command line", name, arg);
+
+  /* We don't need the plugin's name anymore. Just release it.  */
+  XDELETEVEC (name);
+}
+
+
+/* Insert the plugin pass at the proper position. Return true if the pass
+   is successfully added.
+
+   PLUGIN_PASS_INFO - new pass to be inserted
+   PASS_LIST        - root of the pass list to insert the new pass to  */
+
+static bool
+position_pass (struct plugin_pass *plugin_pass_info,
+               struct opt_pass **pass_list)
+{
+  struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+  bool success = false;
+
+  for ( ; pass; prev_pass = pass, pass = pass->next)
+    {
+      /* Check if the current pass is of the same type as the new pass and
+         matches the name and the instance number of the reference pass.  */
+      if (pass->type == plugin_pass_info->pass->type
+          && pass->name
+          && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
+          && ((plugin_pass_info->ref_pass_instance_number == 0)
+              || (plugin_pass_info->ref_pass_instance_number ==
+                  pass->static_pass_number)
+              || (plugin_pass_info->ref_pass_instance_number == 1
+                  && pass->todo_flags_start & TODO_mark_first_instance)))
+        {
+          struct opt_pass *new_pass = plugin_pass_info->pass;
+          struct pass_list_node *new_pass_node;
+
+          /* The following code (if-statement) is adopted from next_pass_1.  */
+          if (new_pass->static_pass_number)
+            {
+              new_pass = XNEW (struct opt_pass);
+              memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
+              new_pass->next = NULL;
+
+              new_pass->todo_flags_start &= ~TODO_mark_first_instance;
+
+              plugin_pass_info->pass->static_pass_number -= 1;
+              new_pass->static_pass_number =
+                  -plugin_pass_info->pass->static_pass_number;
+            }
+          else
+            {
+              new_pass->todo_flags_start |= TODO_mark_first_instance;
+              new_pass->static_pass_number = -1;
+            }
+
+          /* Insert the new pass instance based on the positioning op.  */
+          switch (plugin_pass_info->pos_op)
+            {
+              case PASS_POS_INSERT_AFTER:
+                new_pass->next = pass->next;
+                pass->next = new_pass;
+                break;
+              case PASS_POS_INSERT_BEFORE:
+                new_pass->next = pass;
+                if (prev_pass)
+                  prev_pass->next = new_pass;
+                else
+                  *pass_list = new_pass;
+                break;
+              case PASS_POS_REPLACE:
+                new_pass->next = pass->next;
+                if (prev_pass)
+                  prev_pass->next = new_pass;
+                else
+                  *pass_list = new_pass;
+                new_pass->sub = pass->sub;
+                new_pass->tv_id = pass->tv_id;
+                pass = new_pass;
+                break;
+              default:
+                error ("Invalid pass positioning operation");
+                return false;
+            }
+
+          /* Save the newly added pass (instance) in the added_pass_nodes
+             list so that we can register its dump file later. Note that
+             we cannot register the dump file now because doing so will modify
+             the static_pass_number of the opt_pass object and therefore
+             mess up the dump file name of future instances.  */
+          new_pass_node = XCNEW (struct pass_list_node);
+          new_pass_node->pass = new_pass;
+          if (!added_pass_nodes)
+            added_pass_nodes = new_pass_node;
+          else
+            prev_added_pass_node->next = new_pass_node;
+          prev_added_pass_node = new_pass_node;
+
+          success = true;
+        }
+
+      if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
+        success = true;
+    }
+
+  return success;
+}
+
+
+/* Hook into the pass lists (trees) a new pass registered by a plugin.
+
+   PLUGIN_NAME - display name for the plugin
+   PASS_INFO   - plugin pass information that specifies the opt_pass object,
+                 reference pass, instance number, and how to position
+                 the pass  */
+
+static void
+register_pass (const char *plugin_name, struct plugin_pass *pass_info)
+{
+  if (!pass_info->pass)
+    {
+      error ("No pass specified when registering a new pass in plugin %s",
+             plugin_name);
+      return;
+    }
+
+  if (!pass_info->reference_pass_name)
+    {
+      error ("No reference pass specified for positioning the pass "
+             " from plugin %s", plugin_name);
+      return;
+    }
+
+  /* Try to insert the new pass to the pass lists. We need to check all
+     three lists as the reference pass could be in one (or all) of them.  */
+  if (!position_pass (pass_info, &all_lowering_passes)
+      && !position_pass (pass_info, &all_ipa_passes)
+      && !position_pass (pass_info, &all_passes))
+    error ("Failed to position pass %s registered by plugin %s. "
+           "Cannot find the (specified instance of) reference pass %s",
+           pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
+  else
+    {
+      /* OK, we have successfully inserted the new pass. We need to register
+         the dump files for the newly added pass and its duplicates (if any).
+         Because the registration of plugin passes happens after the
+         command-line options are parsed, the options that specify single
+         pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
+         plugin passes. Therefore we currently can only enable dumping of
+         new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
+         are specified. While doing so, we also delete the pass_list_node
+         objects created during pass positioning.  */
+      while (added_pass_nodes)
+        {
+          struct pass_list_node *next_node = added_pass_nodes->next;
+          enum tree_dump_index tdi;
+          register_one_dump_file (added_pass_nodes->pass);
+          if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
+              || added_pass_nodes->pass->type == IPA_PASS)
+            tdi = TDI_ipa_all;
+          else if (added_pass_nodes->pass->type == GIMPLE_PASS)
+            tdi = TDI_tree_all;
+          else
+            tdi = TDI_rtl_all;
+          /* Check if dump-all flag is specified.  */
+          if (get_dump_file_info (tdi)->state)
+            get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+                ->state = get_dump_file_info (tdi)->state;
+          XDELETE (added_pass_nodes);
+          added_pass_nodes = next_node;
+        }
+    }
+}
+
+
+/* Called from the plugin's initialization code. Register a single callback.
+   This function can be called multiple times.
+
+   PLUGIN_NAME - display name for this plugin
+   EVENT       - which event the callback is for
+   CALLBACK    - the callback to be called at the event
+   USER_DATA   - plugin-provided data   */
+
+void
+register_callback (const char *plugin_name,
+                   enum plugin_event event,
+                   plugin_callback_func callback,
+                   void *user_data)
+{
+  switch (event)
+    {
+      case PLUGIN_PASS_MANAGER_SETUP:
+        register_pass (plugin_name, (struct plugin_pass *) user_data);
+        break;
+      case PLUGIN_FINISH_TYPE:
+      case PLUGIN_FINISH_UNIT:
+      case PLUGIN_CXX_CP_PRE_GENERICIZE:
+      case PLUGIN_FINISH:
+        {
+          struct callback_info *new_callback;
+          if (!callback)
+            {
+              error ("Plugin %s registered a null callback function "
+		     "for event %s", plugin_name, plugin_event_name[event]);
+              return;
+            }
+          new_callback = XNEW (struct callback_info);
+          new_callback->plugin_name = plugin_name;
+          new_callback->func = callback;
+          new_callback->user_data = user_data;
+          new_callback->next = plugin_callbacks[event];
+          plugin_callbacks[event] = new_callback;
+        }
+        break;
+      case PLUGIN_EVENT_LAST:
+      default:
+        error ("Unkown callback event registered by plugin %s",
+               plugin_name);
+    }
+}
+
+
+/* Called from inside GCC.  Invoke all plug-in callbacks registered with
+   the specified event.
+
+   EVENT    - the event identifier
+   GCC_DATA - event-specific data provided by the compiler  */
+
+void
+invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
+{
+  timevar_push (TV_PLUGIN_RUN);
+
+  switch (event)
+    {
+      case PLUGIN_FINISH_TYPE:
+      case PLUGIN_FINISH_UNIT:
+      case PLUGIN_CXX_CP_PRE_GENERICIZE:
+      case PLUGIN_FINISH:
+        {
+          /* Iterate over every callback registered with this event and
+             call it.  */
+          struct callback_info *callback = plugin_callbacks[event];
+          for ( ; callback; callback = callback->next)
+            (*callback->func) (gcc_data, callback->user_data);
+        }
+        break;
+
+      case PLUGIN_PASS_MANAGER_SETUP:
+      case PLUGIN_EVENT_LAST:
+      default:
+        gcc_assert (false);
+    }
+
+  timevar_pop (TV_PLUGIN_RUN);
+}
+
+#ifdef ENABLE_PLUGIN
+/* We need a union to cast dlsym return value to a function pointer
+   as ISO C forbids assignment between function pointer and 'void *'.
+   Use explicit union instead of __extension__(<union_cast>) for
+   portability.  */
+#define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
+#define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
+#define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
+
+/* Routine to dlopen and initialize one plugin. This function is passed to
+   (and called by) the hash table traverse routine. Return 1 for the
+   htab_traverse to continue scan, 0 to stop.
+
+   SLOT - slot of the hash table element
+   INFO - auxiliary pointer handed to hash table traverse routine
+          (unused in this function)  */
+
+static int
+init_one_plugin (void **slot, void * ARG_UNUSED (info))
+{
+  struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
+  void *dl_handle;
+  plugin_init_func plugin_init;
+  char *err;
+  PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
+
+  dl_handle = dlopen (plugin->full_name, RTLD_NOW);
+  if (!dl_handle)
+    {
+      error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
+      return 1;
+    }
+
+  /* Clear any existing error.  */
+  dlerror ();
+
+  PTR_UNION_AS_VOID_PTR (plugin_init_union) =
+      dlsym (dl_handle, str_plugin_init_func_name);
+  plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
+
+  if ((err = dlerror ()) != NULL)
+    {
+      error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
+             plugin->full_name, err);
+      return 1;
+    }
+
+  /* Call the plugin-provided initialization routine with the arguments.  */
+  if ((*plugin_init) (plugin->base_name, plugin->argc, plugin->argv))
+    {
+      error ("Fail to initialize plugin %s", plugin->full_name);
+      return 1;
+    }
+
+  /* We can now delete the plugin_name_args object as it will no longer
+     be used. Note that base_name and argv fields (both of which were also
+     dynamically allocated) are not freed as they could still be used by
+     the plugin code.  */
+  XDELETE (plugin);
+
+  return 1;
+}
+#endif	/* ENABLE_PLUGIN  */
+
+/* Main plugin initialization function.  Called from compile_file() in
+   toplev.c.  */
+
+void
+initialize_plugins (void)
+{
+  /* If no plugin was specified in the command-line, simply return.  */
+  if (!plugin_name_args_tab)
+    return;
+
+  timevar_push (TV_PLUGIN_INIT);
+
+#ifdef ENABLE_PLUGIN
+  /* Traverse and initialize each plugin specified in the command-line.  */
+  htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
+#endif
+
+  /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
+  htab_delete (plugin_name_args_tab);
+  plugin_name_args_tab = NULL;
+
+  timevar_pop (TV_PLUGIN_INIT);
+}
+
+
+/* Return true if plugins have been loaded.  */
+
+bool
+plugins_active_p (void)
+{
+  enum plugin_event event;
+
+  for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+    if (plugin_callbacks[event])
+      return true;
+
+  return false;
+}
+
+
+/* Dump to FILE the names and associated events for all the active
+   plugins.  */
+
+void
+dump_active_plugins (FILE *file)
+{
+  enum plugin_event event;
+
+  if (!plugins_active_p ())
+    return;
+
+  fprintf (stderr, "Event\t\tPlugins\n");
+  for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+    if (plugin_callbacks[event])
+      {
+	struct callback_info *ci;
+
+	fprintf (file, "%s\t", plugin_event_name[event]);
+
+	for (ci = plugin_callbacks[event]; ci; ci = ci->next)
+	  fprintf (file, "%s ", ci->plugin_name);
+
+	fprintf (file, "\n");
+      }
+}
+
+
+/* Dump active plugins to stderr.  */
+
+void
+debug_active_plugins (void)
+{
+  dump_active_plugins (stderr);
+}
Index: plugin.h
===================================================================
--- plugin.h	(revision 0)
+++ plugin.h	(revision 0)
@@ -0,0 +1,33 @@
+/* Header file for internal GCC plugin mechanism.
+   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/>.  */
+
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include "gcc-plugin.h"
+
+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 void initialize_plugins (void);
+extern bool plugins_active_p (void);
+extern void dump_active_plugins (FILE *);
+extern void debug_active_plugins (void);
+
+#endif /* PLUGIN_H */
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 146056)
+++ Makefile.in	(working copy)
@@ -283,6 +283,9 @@ PPLINC = @PPLINC@
 CLOOGLIBS = @CLOOGLIBS@
 CLOOGINC = @CLOOGINC@

+# Libs and linker option needed for plugin support
+PLUGINLIBS = @pluginlibs@
+
 CPPLIB = ../libcpp/libcpp.a
 CPPINC = -I$(srcdir)/../libcpp/include

@@ -872,6 +875,7 @@ EBIMAP_H = ebitmap.h sbitmap.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
+PLUGIN_H = plugin.h gcc-plugin.h

 #
 # Now figure out from those variables how to compile and link.
@@ -906,7 +910,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
 # How to link with both our special library facilities
 # and the system's installed libraries.
 LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER)
-BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS)
+BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS)
 # Any system libraries needed just for GNAT.
 SYSLIBS = @GNAT_LIBEXC@

@@ -1148,6 +1152,7 @@ OBJS-common = \
 	opts.o \
 	params.o \
 	passes.o \
+	plugin.o \
 	pointer-set.o \
 	postreload-gcse.o \
 	postreload.o \
@@ -1800,7 +1805,7 @@ c-errors.o: c-errors.c $(CONFIG_H) $(SYS
 c-parser.o : c-parser.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
     $(GGC_H) $(TIMEVAR_H) $(C_TREE_H) $(INPUT_H) $(FLAGS_H)
$(TOPLEV_H) output.h \
     $(CPPLIB_H) gt-c-parser.h $(RTL_H) langhooks.h $(C_COMMON_H)
$(C_PRAGMA_H) \
-    vec.h $(TARGET_H) $(CGRAPH_H)
+    vec.h $(TARGET_H) $(CGRAPH_H) $(PLUGIN_H)

 srcextra: gcc.srcextra lang.srcextra

@@ -2422,11 +2427,12 @@ fold-const.o : fold-const.c $(CONFIG_H)
    $(GIMPLE_H)
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) version.h $(TM_P_H) $(FLAGS_H) $(INPUT_H) $(TOPLEV_H) intl.h \
-   $(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h
+   $(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h \
+   $(PLUGIN_H)
 opts.o : opts.c opts.h options.h $(TOPLEV_H) $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TREE_H) $(TM_H) langhooks.h $(GGC_H) $(EXPR_H) $(RTL_H) \
    output.h $(DIAGNOSTIC_H) $(TM_P_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
-   $(FLAGS_H) $(PARAMS_H) tree-pass.h $(DBGCNT_H) debug.h varray.h
+   $(FLAGS_H) $(PARAMS_H) tree-pass.h $(DBGCNT_H) debug.h varray.h $(PLUGIN_H)
 opts-common.o : opts-common.c opts.h $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h intl.h
 targhooks.o : targhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
@@ -2443,7 +2449,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM
    langhooks.h insn-flags.h $(CFGLAYOUT_H) $(CFGLOOP_H) hosthooks.h \
    $(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) $(INTEGRATE_H) \
    opts.h params.def tree-mudflap.h $(REAL_H) tree-pass.h $(GIMPLE_H) \
-   tree-ssa-alias.h
+   tree-ssa-alias.h $(PLUGIN_H)
 	$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \
 	  -DTARGET_NAME=\"$(target_noncanonical)\" \
 	  -c $(srcdir)/toplev.c $(OUTPUT_OPTION)
@@ -2459,6 +2465,9 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM
    $(GGC_H) $(INTEGRATE_H) $(CPPLIB_H) opts.h $(TREE_FLOW_H) $(TREE_INLINE_H) \
    gt-passes.h $(DF_H) $(PREDICT_H)

+plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   errors.h $(TOPLEV_H) $(TREE_H) tree-pass.h intl.h
+
 main.o : main.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TOPLEV_H)

 host-default.o : host-default.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -4247,6 +4256,10 @@ site.exp: ./config.status Makefile
 	@echo "set TEST_GCC_EXEC_PREFIX \"$(libdir)/gcc/\"" >> ./tmp0
 	@echo "set TESTING_IN_BUILD_TREE 1" >> ./tmp0
 	@echo "set HAVE_LIBSTDCXX_V3 1" >> ./tmp0
+	@if test "@enable_plugin@" = "yes" ; then \
+	  echo "set ENABLE_PLUGIN 1" >> ./tmp0; \
+	  echo "set GMPINC \"$(GMPINC)\"" >> ./tmp0; \
+	fi
 # If newlib has been configured, we need to pass -B to gcc so it can find
 # newlib's crt0.o if it exists.  This will cause a "path prefix not used"
 # message if it doesn't, but the testsuite is supposed to ignore the message -
Index: passes.c
===================================================================
--- passes.c	(revision 146056)
+++ passes.c	(working copy)
@@ -368,7 +368,7 @@ get_pass_for_id (int id)
    to do this depth first, and independent of whether the pass is
    enabled or not.  */

-static void
+void
 register_one_dump_file (struct opt_pass *pass)
 {
   char *dot_name, *flag_name, *glob_name;
Index: c-parser.c
===================================================================
--- c-parser.c	(revision 146056)
+++ c-parser.c	(working copy)
@@ -57,6 +57,7 @@ along with GCC; see the file COPYING3.
 #include "vec.h"
 #include "target.h"
 #include "cgraph.h"
+#include "plugin.h"

 
 /* Initialization routine for this file.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]