Hi Sean,

It's great that you updated the wiki page with the latest and more
detailed API design.

We (at Google) also started to look at the GCC plugin support a couple
of weeks ago. We had a quick prototype implemented based on the
original APIs that Taras put together in the old wiki. (I can send out
the patch later for people's reference.) The updated APIs in general
look good to me. I do have some comments based on our experience with
the initial prototyping:

>>
>> void register_callbacks(int nregistrations, struct plugin_registration 
>> *registrations);
>>

Instead of passing in an array of plugin_registration objects with a
single register_callbacks call, it's probably better to have the
plugin call a sequence of register_callback with the necessary
information, as shown in the following example:

void plugin_register_callback (const char *plugin_name, enum
plugin_event event, plugin_callback_func  callback, void *user_data);

/* In plugin code */
void
plugin_init()
{
  ...
  register_callback (plugin_name, PLUGIN_FINISH_STRUCT, handle_struct, NULL);
  register_callback (plugin_name, PLUGIN_FINISH_UNIT,
handle_end_of_compilation_unit, NULL);
  ...
}

In the function body of register_callback, GCC can then create the
plugin_registration objects and chain them together based on the event
type. Because GCC will need to maintain a list of plugin_registration
objects for each event anyway, we might as well let it create (and
destroy if necessary) the objects instead of leaving the task to the
plugins.

Note that in my example an additional parameter, plugin_name, is added
in register_callback. We found it useful to have the name around when
emitting error messages if something goes wrong during the callback
registration process.

>>
>> -fplugin=/path/to/plugin.so;arg1=value;arg2=value;...
>>

I am not sure if it is GCC's responsibility to understand key-value
(or any other types of) arguments to plugins. I think GCC should
simply take a string (which, of course, can be something like
"arg1=value arg2=value") and pass it (unparsed) to the plugin. It is
plugin's job to parse/process the given arguments (whatever way it
likes). So the prototype of the plugin_init would look like this:

void plugin_init (const char *plugin_name, const char *plugin_arg);

In our current prototype, we implemented the originally proposed flag
"-fplugin-arg=", which is associated with the plugin specified in the
most recently parsed "-fplugin" flag. If a "-fplugin-arg" flag is used
in the command-line without any preceding "-fplugin", an error message
is emitted. Having the plugin name and its arguments concatenated as
currently proposed is also fine, but I would prefer a simple string
(like below) to a series of key-value pairs.

-fplugin=/path/to/plugin.so;"arguments"

(Note that the double quotes may not needed if the "arguments" doesn't
contain characters such as spaces.)

>>
>> Pass Manager
>>

We think it would be quite daunting (and probably open up a can of
worms) to allow plugins to re-order passes. So to get things moving
quickly, in our initial prototype we only support insertion of a new
pass and replacing an existing pass. When registering a new pass with
GCC, the plugin uses the normal register_callback call with the
PLUGIN_PASS_MANAGER_SETUP event. However, instead of registering a
callback function, it passes in a plugin_pass object (see below) that
specifies the opt_pass object of the new pass, the name of the
reference pass, the static instance number of the reference pass, and
whether to insert before/after or replacing the reference pass.

enum pass_positioning_ops
{
  PASS_POS_INSERT_AFTER,
  PASS_POS_INSERT_BEFORE,
  PASS_POS_REPLACE
};

struct plugin_pass
{
  struct opt_pass *pass;
  const char *reference_pass_name;
  /* Insert the pass at the specified instance of the reference pass.
     If it's 0, do that for every instance.  */
  int ref_pass_instance_number;
  enum pass_positioning_ops pos_op;
};

/* In plugin code */
void
plugin_init()
{
  ...
  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &pass_info);
  ...
}

When registering and positioning a new pass, GCC will search the
passes chained up in all_lowering_passes, all_ipa_passes, and
all_passes (similar to Mozilla dehydra's implementation) to find the
reference pass(es) with the matching name and instance number, and
then either insert the new pass or replace the reference pass.

One caveat with our current implementation is that because the
registration of new plugin passes happens after the command-line
options are parsed, we cannot specify single pass dumping for plugin
passes (e.g. -fdump-tree-newpass).  IR dumping of plugin passes is
enabled only when the dump-all flags (e.g. -fdump-tree-all) are
specified.

What do people think about this pass registration/positioning
interface that I described? (Again, I will send out our patch later so
that people can get a better idea if my description is not clear
enough.)

Le-chun Wu


On Mon, Feb 2, 2009 at 2:42 PM, Sean Callanan <spy...@cs.sunysb.edu> wrote:
> I updated the page http://gcc.gnu.org/wiki/GCC_PluginAPI.
>
> I cleaned up the formatting and added syntax coloring where appropriate.  I
> also changed the API to reflect the comments so far, making it easier to
> register many callbacks at once while preserving the ability to register
> callbacks dynamically as needed.
>
> I volunteer to maintain this page.  (That isn't to say no-one should edit
> it, just that I'll keep it neat and make threads if there are problems with
> the API.)
>
> Sean
>
> On Feb 2, 2009, at 2:15 PM, Benjamin Smedberg wrote:
>
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> On 1/31/09 10:06 PM, Sean Callanan wrote:
>>
>>> (1) register_callback is an unnecessary API.  It's already possible to
>>> use dlsym() to get a pointer to a symbol in a plug-in.  A plug-in could
>>> export a function symbol corresponding to each hook it is interested in;
>>> that way a plug-in would simply have things like
>>>
>>> void HOOK_PASS_MANAGER_SETUP(...)
>>
>> Mozilla currently uses only dlsym, and it's limiting. We have several
>> unrelated analysis scripts loaded throught the same binary plugin. The
>> binary plugin doesn't know in advance which passes the plugin wants to
>> see.
>> To implement this properly, we'd have to have which want to use the same
>> callback.
>>
>> It's possible for the plugin to implement every possible dlsym entry point
>> and then farm the calls out to each individual script pass internally, but
>> since GCC is already going to have to maintain a list of callbacks, it
>> seems
>> better to piggyback on the list GCC already maintains.
>>
>> I agree that the current callback proposal seems overly generic. Perhaps
>> registering specific hooks into the pass manager and other plugin targets
>> makes more sense?
>>
>> typedef (void pluginpasshook)(tree t, void *data);
>>
>> /* implemented in the pass manager */
>> register_plugin_event_after_pass(enum tree_pass, pluginpasshook fn, void*
>> data)
>>
>> Then, plugins would implement only a single entry point. GCC would inform
>> the plugin of the arguments passed to it, and the plugin would register
>> callbacks to perform its actual work.
>>
>> /* implemented in the plugin */
>> void gcc_plugin(const char *arguments);
>>
>>> instead of needing to register that callback.  Equivalently, a global
>>> data structure in the plug-in could map hook UIDs to function pointers,
>>> giving the same effect.  This latter approach would provide very elegant
>>> hook versioning.
>>
>> What kind of verisioning? I don't think that having a single compiled
>> plugin
>> work with multiple versions of GCC should be a goal.
>>
>>> (3) The -fplugin-arg argument is one way to do arguments.  We do it as
>>>
>>>  -ftree-plugin=/path/to/plugin.so:arg=value:arg=value:...
>>>
>>> We also have a magic argument called FILE that lets you load arguments
>>> from a file.
>>
>> I like this better than the current solution: with the current proposal
>> it's
>> hard to tell which -fplugin-arg is supposed to go with which -fplugin.
>>
>> I'm a little worried about the colon separator. Windows file paths may
>> legally have colons. Is there some separator character (semicolon?) which
>> is
>> not part of a path on any platform? Perhaps we shouldn't worry about it
>> since -rdynamic doesn't work on Windows anyway.
>>
>> - --BDS
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1.4.5 (Darwin)
>> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
>>
>> iD8DBQFJh0ZOSSwGp5sTYNkRAkn6AJ9e4zMwlZIrpdX7XUPDCfR0+56EYACfQW9f
>> vMxuuIrJyP6O4hjo9b+fVwo=
>> =OxHa
>> -----END PGP SIGNATURE-----
>
>

Reply via email to