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----- > >