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]

[plugins] [patch] Initial implementation of GCC plugin support


Hi,

This patch for the plugins branch contains the initial implementation
of GCC plugin support based on the APIs described in the following
wiki page:

http://gcc.gnu.org/wiki/GCC_PluginAPI

Besides the proposed APIs, this patch also includes the support for
inserting new passes provided by plugins. I will modify the wiki page
later to describe this pass management support. Another thing that's
noticeably different from the APIs in the wiki is the GCC option for
specifying plugin arguments. In the original design, the options are
like

-fplugin=/path/to/NAME.so -fNAME-arg1=value -fNAME-arg2=value

During our implementation, I found the above options are hard (if not
impossible) to describe in opt file and would require major changes in
GCC option parsing code. So I changed the plugin argument options to
the following: (Please let me know what you think.)

-fplugin=/path/to/NAME.so -fplugin-arg-NAME-<key1>[=<value1>]
-fplugin-arg-NAME-<key2>[=<value2>]

This patch was bootstrapped and tested on i686-linux-gnu.

For those of you who prefer a web-based GUI interface for code review,
I also put the patch in the Rietveld Code Review Tool at

http://codereview.appspot.com/20041

(Please look at Patch Set 2).

Thanks,

Le-chun


2009-02-20  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.
        * cp/decl.c (finish_function): Call invoke_plugin_callbacks.
        * cp/parser.c (cp_parser_type_specifier): Call invoke_plugin_callbacks.
        * c.opt: Add -fplugin= and -fplugin-arg-.
        * gcc-plugin.h: New public header file for plugins to include.
        * c-opts.c (c_common_handle_option): Handle OPT_fplugin_ and
        OPT_fplugin_arg_.
        * plugin.c: New source file.
        * plugin.h: New internal header file.
        * Makefile.in: Add libs needed for plugin support. Also add plugin.o.
        * passes.c (register_one_dump_file): Make it external.
        * c-parser.c (c_parser_declspecs): Call invoke_plugin_callbacks.
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 144307)
+++ gcc/tree-pass.h	(working copy)
@@ -523,6 +523,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 *);
 
 /* Set to true if the pass is called the first time during compilation of the
    current function.  Note that using this information in the optimization
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 144307)
+++ gcc/toplev.c	(working copy)
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3.  
 #include "tree-mudflap.h"
 #include "tree-pass.h"
 #include "gimple.h"
+#include "plugin.h"
 
 #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
@@ -962,6 +963,7 @@ compile_file (void)
   init_final (main_input_filename);
   coverage_init (aux_base_name);
   statistics_init ();
+  initialize_plugins ();
 
   timevar_push (TV_PARSE);
 
@@ -2193,6 +2195,9 @@ do_compile (void)
 	compile_file ();
 
       finalize ();
+
+      /* Invoke registered plugin callbacks if any.  */
+      invoke_plugin_callbacks (PLUGIN_FINISH_UNIT, NULL);
     }
 
   /* Stop timing and print the times.  */
@@ -2227,6 +2232,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: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 144307)
+++ gcc/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);
@@ -12283,6 +12284,8 @@ finish_function (int flags)
   if (!processing_template_decl)
     {
       struct language_function *f = DECL_SAVED_FUNCTION_DATA (fndecl);
+      /* Invoke registered plugin callbacks if any.  */
+      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: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 144307)
+++ gcc/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.  */
@@ -10998,6 +10999,8 @@ cp_parser_type_specifier (cp_parser* par
       cp_parser_parse_tentatively (parser);
       /* Look for the class-specifier.  */
       type_spec = cp_parser_class_specifier (parser);
+      /* Invoke registered plugin callbacks if any.  */
+      invoke_plugin_callbacks (PLUGIN_FINISH_STRUCT, type_spec);
       /* If that worked, we're done.  */
       if (cp_parser_parse_definitely (parser))
 	{
Index: gcc/c.opt
===================================================================
--- gcc/c.opt	(revision 144307)
+++ gcc/c.opt	(working copy)
@@ -708,6 +708,14 @@ fpermissive
 C++ ObjC++
 Downgrade conformance errors to warnings
 
+fplugin=
+C++ C Joined RejectNegative
+Specify a plugin to load
+
+fplugin-arg-
+C++ C Joined RejectNegative
+-fplugin-arg-<name>-<key>[=<value>] Specify argument <key>=<value> for plugin <name>
+
 fpreprocessed
 C ObjC C++ ObjC++
 Treat the input file as already preprocessed
Index: gcc/gcc-plugin.h
===================================================================
--- gcc/gcc-plugin.h	(revision 0)
+++ gcc/gcc-plugin.h	(revision 0)
@@ -0,0 +1,91 @@
+/* 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
+
+enum plugin_event
+{
+  PLUGIN_PASS_MANAGER_SETUP,    /* To hook into pass manager.  */
+  PLUGIN_FINISH_STRUCT,
+  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.  */
+};
+
+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);
+
+/* 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: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c	(revision 144307)
+++ gcc/c-opts.c	(working copy)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  
 #include "mkdeps.h"
 #include "target.h"
 #include "tm_p.h"
+#include "plugin.h"
 
 #ifndef DOLLARS_IN_IDENTIFIERS
 # define DOLLARS_IN_IDENTIFIERS true
@@ -742,6 +743,14 @@ c_common_handle_option (size_t scode, co
       flag_permissive = value;
       break;
 
+    case OPT_fplugin_:
+      add_new_plugin (arg);
+      break;
+
+    case OPT_fplugin_arg_:
+      parse_plugin_arg_opt (arg);
+      break;
+
     case OPT_fpreprocessed:
       cpp_opts->preprocessed = value;
       break;
Index: gcc/plugin.c
===================================================================
--- gcc/plugin.c	(revision 0)
+++ gcc/plugin.c	(revision 0)
@@ -0,0 +1,582 @@
+/* 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 the following wiki page:
+
+   http://gcc.gnu.org/wiki/GCC_PluginAPI  */
+
+#include <dlfcn.h>
+#include <string.h>
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "errors.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin.h"
+
+/* 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;
+
+/* Each plugin should define an initialization function with exactly
+   this name.  */
+static const char *str_plugin_init_func_name = "plugin_init";
+
+
+/* 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, e.g. /pass/to/NAME.so, return NAME.  */
+
+static char *
+get_plugin_base_name (const char *full_name)
+{
+  const char *name_start = full_name;
+  const char *ptr;
+  char *base_name;
+  size_t name_len = 0;
+  bool in_name_extension = false;
+
+  for (ptr = full_name; *ptr; ++ptr)
+    {
+      if (*ptr == '/')
+        {
+          name_start = ptr + 1;
+          name_len = 0;
+          in_name_extension = false;
+          continue;
+        }
+      else if (*ptr == '.')
+        {
+          in_name_extension = true;
+          continue;
+        }
+
+      if (!in_name_extension)
+        ++name_len;
+    }
+
+  base_name = XNEWVEC (char, name_len + 1);
+  strncpy (base_name, name_start, name_len);
+  base_name[name_len] = '\0';
+
+  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 (G_("Plugin %s was specified with different paths:\n%s\n%s"),
+               plugin->base_name, plugin->full_name, plugin_name);
+      else
+        warning (0, G_("Plugin %s was specified multiple times"), 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;
+
+  /* Iterate over the ARG string and identify the starting character position
+     of 'name', 'key', and 'value' and their lengths.  */
+  for (ptr = arg; *ptr; ++ptr)
+    {
+      if (*ptr == '-')
+        {
+          name_len = len;
+          len = 0;
+          key_start = ptr + 1;
+          continue;
+        }
+      else if (*ptr == '=')
+        {
+          key_len = len;
+          len = 0;
+          value_start = ptr + 1;
+          continue;
+        }
+      else
+        ++len;
+    }
+
+  if (!key_start)
+    {
+      error (G_("Misformed 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 (G_("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 matches the name and the instance number
+         of the reference pass.  */
+      if (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 (G_("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 (G_("No pass specified when registering a new pass in plugin %s"),
+             plugin_name);
+      return;
+    }
+
+  if (!pass_info->reference_pass_name)
+    {
+      error (G_("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 (G_("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_STRUCT:
+      case PLUGIN_FINISH_UNIT:
+      case PLUGIN_CXX_CP_PRE_GENERICIZE:
+      case PLUGIN_FINISH:
+        {
+          struct callback_info *new_callback;
+          if (!callback)
+            {
+              error (G_("Plugin %s registered a null callback function"),
+                     plugin_name);
+              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 (G_("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)
+{
+  switch (event)
+    {
+      case PLUGIN_FINISH_STRUCT:
+      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);
+    }
+}
+
+/* We need the following macro to cast a 'void *' pointer to a function
+   pointer to avoid compiler warnings in bootstrap as ISO C forbids
+   assignment between function pointer and 'void *'.  */
+#define POINTER_CAST(TOTYPE, X) ((__extension__(union {void * _q; TOTYPE _nq;})(X))._nq)
+
+/* Routine to dlopen and initialize one plugin. This function is passed to
+   (and called by) the hash table traverse routine.  */
+
+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;
+
+  dl_handle = dlopen (plugin->full_name, RTLD_LAZY);
+  if (!dl_handle)
+    {
+      error (G_("Cannot load plugin %s\n%s"), plugin->full_name, dlerror());
+      return 1;
+    }
+
+  /* Clear any existing error.  */
+  dlerror();
+
+  plugin_init = POINTER_CAST (plugin_init_func,
+                              dlsym (dl_handle, str_plugin_init_func_name));
+  if ((err = dlerror()) != NULL)
+    {
+      error (G_("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 (G_("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;
+}
+
+/* Main plugin initialization function. Called from compiler_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;
+ 
+  /* Traverse and initialize each plugin specified in the command-line.  */
+  htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
+
+  /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
+  htab_delete (plugin_name_args_tab);
+  plugin_name_args_tab = NULL;
+}
Index: gcc/plugin.h
===================================================================
--- gcc/plugin.h	(revision 0)
+++ gcc/plugin.h	(revision 0)
@@ -0,0 +1,34 @@
+/* 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"
+
+/* Called when -fplugin=/path/to/NAME.so option is parsed.  */
+extern void add_new_plugin (const char* plugin_name);
+/* Parse the -fplugin-arg-<name>-<key>[=<value>] option.  */
+extern void parse_plugin_arg_opt (const char *arg);
+/* Invoke all plug-in callbacks registered with the specified event.  */
+extern void invoke_plugin_callbacks (enum plugin_event event, void *gcc_data);
+/* Main plugin initialization function.  */
+extern void initialize_plugins (void);
+
+#endif /* PLUGIN_H */
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 144307)
+++ gcc/Makefile.in	(working copy)
@@ -287,6 +287,9 @@ PPLINC = @PPLINC@
 CLOOGLIBS = @CLOOGLIBS@
 CLOOGINC = @CLOOGINC@
 
+# Libs needed for plugin support
+PLUGINLIBS = -rdynamic -ldl
+
 CPPLIB = ../libcpp/libcpp.a
 CPPINC = -I$(srcdir)/../libcpp/include
 
@@ -914,7 +917,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@
 
@@ -1156,6 +1159,7 @@ OBJS-common = \
 	opts.o \
 	params.o \
 	passes.o \
+	plugin.o \
 	pointer-set.o \
 	postreload-gcse.o \
 	postreload.o \
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 144307)
+++ gcc/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: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 144307)
+++ gcc/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.  */
@@ -1544,6 +1545,8 @@ c_parser_declspecs (c_parser *parser, st
 	  attrs_ok = true;
 	  seen_type = true;
 	  t = c_parser_struct_or_union_specifier (parser);
+          /* Invoke registered plugin callbacks if any.  */
+          invoke_plugin_callbacks (PLUGIN_FINISH_STRUCT, t.spec);
 	  declspecs_add_type (specs, t);
 	  break;
 	case RID_TYPEOF:

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