OSDN Git Service

2009-04-14 Diego Novillo <dnovillo@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / plugin.c
1 /* Support for GCC plugin mechanism.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19
20 /* This file contains the support for GCC plugin mechanism based on the
21    APIs described in doc/plugin.texi.  */
22
23 #include "config.h"
24 #include "system.h"
25
26 /* If plugin support is not enabled, do not try to execute any code
27    that may reference libdl.  The generic code is still compiled in to
28    avoid including to many conditional compilation paths in the rest
29    of the compiler.  */
30 #ifdef ENABLE_PLUGIN
31 #include <dlfcn.h>
32 #endif
33
34 #include "coretypes.h"
35 #include "toplev.h"
36 #include "tree.h"
37 #include "tree-pass.h"
38 #include "intl.h"
39 #include "plugin.h"
40 #include "timevar.h"
41
42 /* Event names as strings.  Keep in sync with enum plugin_event.  */
43 const char *plugin_event_name[] =
44 {
45   "PLUGIN_PASS_MANAGER_SETUP",
46   "PLUGIN_FINISH_TYPE",
47   "PLUGIN_FINISH_UNIT",
48   "PLUGIN_CXX_CP_PRE_GENERICIZE",
49   "PLUGIN_FINISH",
50   "PLUGIN_EVENT_LAST"
51 };
52
53 /* Object that keeps track of the plugin name and its arguments
54    when parsing the command-line options -fplugin=/path/to/NAME.so and
55    -fplugin-arg-NAME-<key>[=<value>].  */
56 struct plugin_name_args
57 {
58   char *base_name;
59   const char *full_name;
60   int argc;
61   struct plugin_argument *argv;
62 };
63
64 /* Hash table for the plugin_name_args objects created during command-line
65    parsing.  */
66 static htab_t plugin_name_args_tab = NULL;
67
68 /* List node for keeping track of plugin-registered callback.  */
69 struct callback_info
70 {
71   const char *plugin_name;   /* Name of plugin that registers the callback.  */
72   plugin_callback_func func; /* Callback to be called.  */
73   void *user_data;           /* plugin-specified data.  */
74   struct callback_info *next;
75 };
76
77 /* An array of lists of 'callback_info' objects indexed by the event id.  */
78 static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
79
80 /* List node for an inserted pass instance. We need to keep track of all
81    the newly-added pass instances (with 'added_pass_nodes' defined below)
82    so that we can register their dump files after pass-positioning is finished.
83    Registering dumping files needs to be post-processed or the
84    static_pass_number of the opt_pass object would be modified and mess up
85    the dump file names of future pass instances to be added.  */
86 struct pass_list_node
87 {
88   struct opt_pass *pass;
89   struct pass_list_node *next;
90 };
91
92 static struct pass_list_node *added_pass_nodes = NULL;
93 static struct pass_list_node *prev_added_pass_node;
94
95 #ifdef ENABLE_PLUGIN
96 /* Each plugin should define an initialization function with exactly
97    this name.  */
98 static const char *str_plugin_init_func_name = "plugin_init";
99 #endif
100
101 /* Helper function for the hash table that compares the base_name of the
102    existing entry (S1) with the given string (S2).  */
103
104 static int
105 htab_str_eq (const void *s1, const void *s2)
106 {
107   const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
108   return !strcmp (plugin->base_name, (const char *) s2);
109 }
110
111
112 /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
113    return NAME.  */
114
115 static char *
116 get_plugin_base_name (const char *full_name)
117 {
118   /* First get the base name part of the full-path name, i.e. NAME.so.  */
119   char *base_name = xstrdup (lbasename (full_name));
120
121   /* Then get rid of '.so' part of the name.  */
122   strip_off_ending (base_name, strlen (base_name));
123
124   return base_name;
125 }
126
127
128 /* Create a plugin_name_args object for the give plugin and insert it to
129    the hash table. This function is called when -fplugin=/path/to/NAME.so
130    option is processed.  */
131
132 void
133 add_new_plugin (const char* plugin_name)
134 {
135   struct plugin_name_args *plugin;
136   void **slot;
137   char *base_name = get_plugin_base_name (plugin_name);
138
139   /* If this is the first -fplugin= option we encounter, create 
140      'plugin_name_args_tab' hash table.  */
141   if (!plugin_name_args_tab)
142     plugin_name_args_tab = htab_create (10, htab_hash_string, htab_str_eq,
143                                         NULL);
144
145   slot = htab_find_slot (plugin_name_args_tab, base_name, INSERT);
146
147   /* If the same plugin (name) has been specified earlier, either emit an
148      error or a warning message depending on if they have identical full
149      (path) names.  */
150   if (*slot)
151     {
152       plugin = (struct plugin_name_args *) *slot;
153       if (strcmp (plugin->full_name, plugin_name))
154         error ("Plugin %s was specified with different paths:\n%s\n%s",
155                plugin->base_name, plugin->full_name, plugin_name);
156       return;
157     }
158
159   plugin = XCNEW (struct plugin_name_args);
160   plugin->base_name = base_name;
161   plugin->full_name = plugin_name;
162
163   *slot = plugin;
164 }
165
166
167 /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
168    'plugin_argument' object for the parsed key-value pair. ARG is
169    the <name>-<key>[=<value>] part of the option.  */
170
171 void
172 parse_plugin_arg_opt (const char *arg)
173 {
174   size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
175   const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
176   char *name, *key, *value;
177   void **slot;
178   bool name_parsed = false, key_parsed = false;
179
180   /* Iterate over the ARG string and identify the starting character position
181      of 'name', 'key', and 'value' and their lengths.  */
182   for (ptr = arg; *ptr; ++ptr)
183     {
184       /* Only the first '-' encountered is considered a separator between
185          'name' and 'key'. All the subsequent '-'s are considered part of
186          'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
187          the plugin name is 'foo' and the key is 'bar-primary-key'.  */
188       if (*ptr == '-' && !name_parsed)
189         {
190           name_len = len;
191           len = 0;
192           key_start = ptr + 1;
193           name_parsed = true;
194           continue;
195         }
196       else if (*ptr == '=')
197         {
198           if (key_parsed)
199             {
200               error ("Malformed option -fplugin-arg-%s (multiple '=' signs)",
201                      arg);
202               return;
203             }
204           key_len = len;
205           len = 0;
206           value_start = ptr + 1;
207           key_parsed = true;
208           continue;
209         }
210       else
211         ++len;
212     }
213
214   if (!key_start)
215     {
216       error ("Malformed option -fplugin-arg-%s (missing -<key>[=<value>])",
217              arg);
218       return;
219     }
220
221   /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
222      Otherwise, it is the VALUE_LEN.  */
223   if (!value_start)
224     key_len = len;
225   else
226     value_len = len;
227
228   name = XNEWVEC (char, name_len + 1);
229   strncpy (name, name_start, name_len);
230   name[name_len] = '\0';
231
232   /* Check if the named plugin has already been specified earlier in the
233      command-line.  */
234   if (plugin_name_args_tab
235       && ((slot = htab_find_slot (plugin_name_args_tab, name, NO_INSERT))
236           != NULL))
237     {
238       struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
239
240       key = XNEWVEC (char, key_len + 1);
241       strncpy (key, key_start, key_len);
242       key[key_len] = '\0';
243       if (value_start)
244         {
245           value = XNEWVEC (char, value_len + 1);
246           strncpy (value, value_start, value_len);
247           value[value_len] = '\0';
248         }
249       else
250         value = NULL;
251
252       /* Create a plugin_argument object for the parsed key-value pair.
253          If there are already arguments for this plugin, we will need to
254          adjust the argument array size by creating a new array and deleting
255          the old one. If the performance ever becomes an issue, we can
256          change the code by pre-allocating a larger array first.  */
257       if (plugin->argc > 0)
258         {
259           struct plugin_argument *args = XNEWVEC (struct plugin_argument,
260                                                   plugin->argc + 1);
261           memcpy (args, plugin->argv,
262                   sizeof (struct plugin_argument) * plugin->argc);
263           XDELETEVEC (plugin->argv);
264           plugin->argv = args;
265           ++plugin->argc;
266         }
267       else
268         {
269           gcc_assert (plugin->argv == NULL);
270           plugin->argv = XNEWVEC (struct plugin_argument, 1);
271           plugin->argc = 1;
272         }
273
274       plugin->argv[plugin->argc - 1].key = key;
275       plugin->argv[plugin->argc - 1].value = value;
276     }
277   else
278     error ("Plugin %s should be specified before -fplugin-arg-%s "
279            "in the command line", name, arg);
280
281   /* We don't need the plugin's name anymore. Just release it.  */
282   XDELETEVEC (name);
283 }
284
285
286 /* Insert the plugin pass at the proper position. Return true if the pass 
287    is successfully added.
288
289    PLUGIN_PASS_INFO - new pass to be inserted
290    PASS_LIST        - root of the pass list to insert the new pass to  */
291
292 static bool
293 position_pass (struct plugin_pass *plugin_pass_info,
294                struct opt_pass **pass_list)
295 {
296   struct opt_pass *pass = *pass_list, *prev_pass = NULL;
297   bool success = false;
298
299   for ( ; pass; prev_pass = pass, pass = pass->next)
300     {
301       /* Check if the current pass is of the same type as the new pass and
302          matches the name and the instance number of the reference pass.  */
303       if (pass->type == plugin_pass_info->pass->type
304           && pass->name
305           && !strcmp (pass->name, plugin_pass_info->reference_pass_name)
306           && ((plugin_pass_info->ref_pass_instance_number == 0)
307               || (plugin_pass_info->ref_pass_instance_number ==
308                   pass->static_pass_number)
309               || (plugin_pass_info->ref_pass_instance_number == 1
310                   && pass->todo_flags_start & TODO_mark_first_instance)))
311         {
312           struct opt_pass *new_pass = plugin_pass_info->pass;
313           struct pass_list_node *new_pass_node;
314
315           /* The following code (if-statement) is adopted from next_pass_1.  */
316           if (new_pass->static_pass_number)
317             {
318               new_pass = XNEW (struct opt_pass);
319               memcpy (new_pass, plugin_pass_info->pass, sizeof (*new_pass));
320               new_pass->next = NULL;
321
322               new_pass->todo_flags_start &= ~TODO_mark_first_instance;
323
324               plugin_pass_info->pass->static_pass_number -= 1;
325               new_pass->static_pass_number =
326                   -plugin_pass_info->pass->static_pass_number;
327             }
328           else
329             {
330               new_pass->todo_flags_start |= TODO_mark_first_instance;
331               new_pass->static_pass_number = -1;
332             }
333
334           /* Insert the new pass instance based on the positioning op.  */
335           switch (plugin_pass_info->pos_op)
336             {
337               case PASS_POS_INSERT_AFTER:
338                 new_pass->next = pass->next;
339                 pass->next = new_pass;
340                 break;
341               case PASS_POS_INSERT_BEFORE:
342                 new_pass->next = pass;
343                 if (prev_pass)
344                   prev_pass->next = new_pass;
345                 else
346                   *pass_list = new_pass;
347                 break;
348               case PASS_POS_REPLACE:
349                 new_pass->next = pass->next;
350                 if (prev_pass)
351                   prev_pass->next = new_pass;
352                 else
353                   *pass_list = new_pass;
354                 new_pass->sub = pass->sub;
355                 new_pass->tv_id = pass->tv_id;
356                 pass = new_pass;
357                 break;
358               default:
359                 error ("Invalid pass positioning operation");
360                 return false;
361             }
362
363           /* Save the newly added pass (instance) in the added_pass_nodes
364              list so that we can register its dump file later. Note that
365              we cannot register the dump file now because doing so will modify
366              the static_pass_number of the opt_pass object and therefore
367              mess up the dump file name of future instances.  */
368           new_pass_node = XCNEW (struct pass_list_node);
369           new_pass_node->pass = new_pass;
370           if (!added_pass_nodes)
371             added_pass_nodes = new_pass_node;
372           else
373             prev_added_pass_node->next = new_pass_node;
374           prev_added_pass_node = new_pass_node;
375
376           success = true;
377         }
378
379       if (pass->sub && position_pass (plugin_pass_info, &pass->sub))
380         success = true;
381     }
382
383   return success;
384 }
385
386
387 /* Hook into the pass lists (trees) a new pass registered by a plugin.
388
389    PLUGIN_NAME - display name for the plugin
390    PASS_INFO   - plugin pass information that specifies the opt_pass object,
391                  reference pass, instance number, and how to position
392                  the pass  */
393
394 static void
395 register_pass (const char *plugin_name, struct plugin_pass *pass_info)
396 {
397   if (!pass_info->pass)
398     {
399       error ("No pass specified when registering a new pass in plugin %s",
400              plugin_name);
401       return;
402     }
403
404   if (!pass_info->reference_pass_name)
405     {
406       error ("No reference pass specified for positioning the pass "
407              " from plugin %s", plugin_name);
408       return;
409     }
410
411   /* Try to insert the new pass to the pass lists. We need to check all
412      three lists as the reference pass could be in one (or all) of them.  */
413   if (!position_pass (pass_info, &all_lowering_passes)
414       && !position_pass (pass_info, &all_ipa_passes)
415       && !position_pass (pass_info, &all_passes))
416     error ("Failed to position pass %s registered by plugin %s. "
417            "Cannot find the (specified instance of) reference pass %s",
418            pass_info->pass->name, plugin_name, pass_info->reference_pass_name);
419   else
420     {
421       /* OK, we have successfully inserted the new pass. We need to register
422          the dump files for the newly added pass and its duplicates (if any).
423          Because the registration of plugin passes happens after the
424          command-line options are parsed, the options that specify single
425          pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
426          plugin passes. Therefore we currently can only enable dumping of
427          new plugin passes when the 'dump-all' flags (e.g. -fdump-tree-all)
428          are specified. While doing so, we also delete the pass_list_node
429          objects created during pass positioning.  */
430       while (added_pass_nodes)
431         {
432           struct pass_list_node *next_node = added_pass_nodes->next;
433           enum tree_dump_index tdi;
434           register_one_dump_file (added_pass_nodes->pass);
435           if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
436               || added_pass_nodes->pass->type == IPA_PASS)
437             tdi = TDI_ipa_all;
438           else if (added_pass_nodes->pass->type == GIMPLE_PASS)
439             tdi = TDI_tree_all;
440           else
441             tdi = TDI_rtl_all;
442           /* Check if dump-all flag is specified.  */
443           if (get_dump_file_info (tdi)->state)
444             get_dump_file_info (added_pass_nodes->pass->static_pass_number)
445                 ->state = get_dump_file_info (tdi)->state;
446           XDELETE (added_pass_nodes);
447           added_pass_nodes = next_node;
448         }
449     }
450 }
451
452
453 /* Called from the plugin's initialization code. Register a single callback.
454    This function can be called multiple times.
455
456    PLUGIN_NAME - display name for this plugin
457    EVENT       - which event the callback is for
458    CALLBACK    - the callback to be called at the event
459    USER_DATA   - plugin-provided data   */
460
461 void
462 register_callback (const char *plugin_name,
463                    enum plugin_event event,
464                    plugin_callback_func callback,
465                    void *user_data)
466 {
467   switch (event)
468     {
469       case PLUGIN_PASS_MANAGER_SETUP:
470         register_pass (plugin_name, (struct plugin_pass *) user_data);
471         break;
472       case PLUGIN_FINISH_TYPE:
473       case PLUGIN_FINISH_UNIT:
474       case PLUGIN_CXX_CP_PRE_GENERICIZE:
475       case PLUGIN_FINISH:
476         {
477           struct callback_info *new_callback;
478           if (!callback)
479             {
480               error ("Plugin %s registered a null callback function "
481                      "for event %s", plugin_name, plugin_event_name[event]);
482               return;
483             }
484           new_callback = XNEW (struct callback_info);
485           new_callback->plugin_name = plugin_name;
486           new_callback->func = callback;
487           new_callback->user_data = user_data;
488           new_callback->next = plugin_callbacks[event];
489           plugin_callbacks[event] = new_callback;
490         }
491         break;
492       case PLUGIN_EVENT_LAST:
493       default:
494         error ("Unkown callback event registered by plugin %s",
495                plugin_name);
496     }
497 }
498
499
500 /* Called from inside GCC.  Invoke all plug-in callbacks registered with
501    the specified event.
502
503    EVENT    - the event identifier
504    GCC_DATA - event-specific data provided by the compiler  */
505
506 void
507 invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
508 {
509   timevar_push (TV_PLUGIN_RUN);
510
511   switch (event)
512     {
513       case PLUGIN_FINISH_TYPE:
514       case PLUGIN_FINISH_UNIT:
515       case PLUGIN_CXX_CP_PRE_GENERICIZE:
516       case PLUGIN_FINISH:
517         {
518           /* Iterate over every callback registered with this event and
519              call it.  */
520           struct callback_info *callback = plugin_callbacks[event];
521           for ( ; callback; callback = callback->next)
522             (*callback->func) (gcc_data, callback->user_data);
523         }
524         break;
525
526       case PLUGIN_PASS_MANAGER_SETUP:
527       case PLUGIN_EVENT_LAST:
528       default:
529         gcc_assert (false);
530     }
531
532   timevar_pop (TV_PLUGIN_RUN);
533 }
534
535 #ifdef ENABLE_PLUGIN
536 /* We need a union to cast dlsym return value to a function pointer
537    as ISO C forbids assignment between function pointer and 'void *'.
538    Use explicit union instead of __extension__(<union_cast>) for
539    portability.  */
540 #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
541 #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
542 #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
543
544 /* Routine to dlopen and initialize one plugin. This function is passed to
545    (and called by) the hash table traverse routine. Return 1 for the
546    htab_traverse to continue scan, 0 to stop.
547
548    SLOT - slot of the hash table element
549    INFO - auxiliary pointer handed to hash table traverse routine
550           (unused in this function)  */
551
552 static int
553 init_one_plugin (void **slot, void * ARG_UNUSED (info))
554 {
555   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
556   void *dl_handle;
557   plugin_init_func plugin_init;
558   char *err;
559   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
560
561   dl_handle = dlopen (plugin->full_name, RTLD_NOW);
562   if (!dl_handle)
563     {
564       error ("Cannot load plugin %s\n%s", plugin->full_name, dlerror ());
565       return 1;
566     }
567
568   /* Clear any existing error.  */
569   dlerror ();
570
571   PTR_UNION_AS_VOID_PTR (plugin_init_union) =
572       dlsym (dl_handle, str_plugin_init_func_name);
573   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
574
575   if ((err = dlerror ()) != NULL)
576     {
577       error ("Cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
578              plugin->full_name, err);
579       return 1;
580     }
581
582   /* Call the plugin-provided initialization routine with the arguments.  */
583   if ((*plugin_init) (plugin->base_name, plugin->argc, plugin->argv))
584     {
585       error ("Fail to initialize plugin %s", plugin->full_name);
586       return 1;
587     }
588
589   /* We can now delete the plugin_name_args object as it will no longer
590      be used. Note that base_name and argv fields (both of which were also
591      dynamically allocated) are not freed as they could still be used by
592      the plugin code.  */
593   XDELETE (plugin);
594
595   return 1;
596 }
597 #endif  /* ENABLE_PLUGIN  */
598
599 /* Main plugin initialization function.  Called from compile_file() in
600    toplev.c.  */
601
602 void
603 initialize_plugins (void)
604 {
605   /* If no plugin was specified in the command-line, simply return.  */
606   if (!plugin_name_args_tab)
607     return;
608
609   timevar_push (TV_PLUGIN_INIT);
610  
611 #ifdef ENABLE_PLUGIN
612   /* Traverse and initialize each plugin specified in the command-line.  */
613   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
614 #endif
615
616   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
617   htab_delete (plugin_name_args_tab);
618   plugin_name_args_tab = NULL;
619
620   timevar_pop (TV_PLUGIN_INIT);
621 }
622
623
624 /* Return true if plugins have been loaded.  */
625
626 bool
627 plugins_active_p (void)
628 {
629   enum plugin_event event;
630
631   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
632     if (plugin_callbacks[event])
633       return true;
634
635   return false;
636 }
637
638
639 /* Dump to FILE the names and associated events for all the active
640    plugins.  */
641
642 void
643 dump_active_plugins (FILE *file)
644 {
645   enum plugin_event event;
646
647   if (!plugins_active_p ())
648     return;
649
650   fprintf (stderr, "Event\t\tPlugins\n");
651   for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
652     if (plugin_callbacks[event])
653       {
654         struct callback_info *ci;
655
656         fprintf (file, "%s\t", plugin_event_name[event]);
657
658         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
659           fprintf (file, "%s ", ci->plugin_name);
660
661         fprintf (file, "\n");
662       }
663 }
664
665
666 /* Dump active plugins to stderr.  */
667
668 void
669 debug_active_plugins (void)
670 {
671   dump_active_plugins (stderr);
672 }