summaryrefslogtreecommitdiff
path: root/gcc/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/plugin.c')
-rw-r--r--gcc/plugin.c190
1 files changed, 161 insertions, 29 deletions
diff --git a/gcc/plugin.c b/gcc/plugin.c
index 750f537a222..673ad07ffc5 100644
--- a/gcc/plugin.c
+++ b/gcc/plugin.c
@@ -44,30 +44,32 @@ along with GCC; see the file COPYING3. If not see
#include "plugin-version.h"
#endif
+#define GCC_PLUGIN_STRINGIFY0(X) #X
+#define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
+
/* Event names as strings. Keep in sync with enum plugin_event. */
-const char *plugin_event_name[] =
+static const char *plugin_event_name_init[] =
{
- "PLUGIN_PASS_MANAGER_SETUP",
- "PLUGIN_FINISH_TYPE",
- "PLUGIN_FINISH_UNIT",
- "PLUGIN_CXX_CP_PRE_GENERICIZE",
- "PLUGIN_FINISH",
- "PLUGIN_INFO",
- "PLUGIN_GGC_START",
- "PLUGIN_GGC_MARKING",
- "PLUGIN_GGC_END",
- "PLUGIN_REGISTER_GGC_ROOTS",
- "PLUGIN_REGISTER_GGC_CACHES",
- "PLUGIN_ATTRIBUTES",
- "PLUGIN_START_UNIT",
- "PLUGIN_PRAGMAS",
- "PLUGIN_EVENT_LAST"
+# define DEFEVENT(NAME) GCC_PLUGIN_STRINGIFY1 (NAME),
+# include "plugin.def"
+# undef DEFEVENT
};
/* a printf format large enough for the largest event above */
#define FMT_FOR_PLUGIN_EVENT "%-26s"
/* A printf format large enough for the largest event above. */
-#define FMT_FOR_PLUGIN_EVENT "%-26s"
+#define FMT_FOR_PLUGIN_EVENT "%-32s"
+
+const char **plugin_event_name = plugin_event_name_init;
+
+/* A hash table to map event names to the position of the names in the
+ plugin_event_name table. */
+static htab_t event_tab;
+
+/* Keep track of the limit of allocated events and space ready for
+ allocating events. */
+static int event_last = PLUGIN_EVENT_FIRST_DYNAMIC;
+static int event_horizon = PLUGIN_EVENT_FIRST_DYNAMIC;
/* Hash table for the plugin_name_args objects created during command-line
parsing. */
@@ -83,7 +85,8 @@ struct callback_info
};
/* An array of lists of 'callback_info' objects indexed by the event id. */
-static struct callback_info *plugin_callbacks[PLUGIN_EVENT_LAST] = { NULL };
+static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_FIRST_DYNAMIC];
+static struct callback_info **plugin_callbacks = plugin_callbacks_init;
#ifdef ENABLE_PLUGIN
@@ -292,6 +295,71 @@ register_plugin_info (const char* name, struct plugin_info *info)
plugin->help = info->help;
}
+/* Helper function for the event hash table that compares the name of an
+ existing entry (E1) with the given string (S2). */
+
+static int
+htab_event_eq (const void *e1, const void *s2)
+{
+ const char *s1= *(const char * const *) e1;
+ return !strcmp (s1, (const char *) s2);
+}
+
+/* Look up the event id for NAME. If the name is not found, return -1
+ if INSERT is NO_INSERT. */
+
+int
+get_named_event_id (const char *name, enum insert_option insert)
+{
+ void **slot;
+
+ if (!event_tab)
+ {
+ int i;
+
+ event_tab = htab_create (150, htab_hash_string, htab_event_eq, NULL);
+ for (i = 0; i < PLUGIN_EVENT_FIRST_DYNAMIC; i++)
+ {
+ slot = htab_find_slot (event_tab, plugin_event_name[i], INSERT);
+ gcc_assert (*slot == HTAB_EMPTY_ENTRY);
+ *slot = &plugin_event_name[i];
+ }
+ }
+ slot = htab_find_slot (event_tab, name, insert);
+ if (slot == NULL)
+ return -1;
+ if (*slot != HTAB_EMPTY_ENTRY)
+ return (const char **) *slot - &plugin_event_name[0];
+
+ if (event_last >= event_horizon)
+ {
+ event_horizon = event_last * 2;
+ if (plugin_event_name == plugin_event_name_init)
+ {
+ plugin_event_name = XNEWVEC (const char *, event_horizon);
+ memcpy (plugin_event_name, plugin_event_name_init,
+ sizeof plugin_event_name_init);
+ plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon);
+ memcpy (plugin_callbacks, plugin_callbacks_init,
+ sizeof plugin_callbacks_init);
+ }
+ else
+ {
+ plugin_event_name
+ = XRESIZEVEC (const char *, plugin_event_name, event_horizon);
+ plugin_callbacks = XRESIZEVEC (struct callback_info *,
+ plugin_callbacks, event_horizon);
+ }
+ /* All the pointers in the hash table will need to be updated. */
+ htab_delete (event_tab);
+ event_tab = NULL;
+ }
+ else
+ *slot = &plugin_event_name[event_last];
+ plugin_event_name[event_last] = name;
+ return event_last++;
+}
+
/* Called from the plugin's initialization code. Register a single callback.
This function can be called multiple times.
@@ -302,7 +370,7 @@ register_plugin_info (const char* name, struct plugin_info *info)
void
register_callback (const char *plugin_name,
- enum plugin_event event,
+ int event,
plugin_callback_func callback,
void *user_data)
{
@@ -324,6 +392,15 @@ register_callback (const char *plugin_name,
gcc_assert (!callback);
ggc_register_cache_tab ((const struct ggc_cache_tab*) user_data);
break;
+ case PLUGIN_EVENT_FIRST_DYNAMIC:
+ default:
+ if (event < PLUGIN_EVENT_FIRST_DYNAMIC || event >= event_last)
+ {
+ error ("Unknown callback event registered by plugin %s",
+ plugin_name);
+ return;
+ }
+ /* Fall through. */
case PLUGIN_FINISH_TYPE:
case PLUGIN_START_UNIT:
case PLUGIN_FINISH_UNIT:
@@ -334,6 +411,15 @@ register_callback (const char *plugin_name,
case PLUGIN_ATTRIBUTES:
case PLUGIN_PRAGMAS:
case PLUGIN_FINISH:
+ case PLUGIN_ALL_PASSES_START:
+ case PLUGIN_ALL_PASSES_END:
+ case PLUGIN_ALL_IPA_PASSES_START:
+ case PLUGIN_ALL_IPA_PASSES_END:
+ case PLUGIN_OVERRIDE_GATE:
+ case PLUGIN_PASS_EXECUTION:
+ case PLUGIN_EARLY_GIMPLE_PASSES_START:
+ case PLUGIN_EARLY_GIMPLE_PASSES_END:
+ case PLUGIN_NEW_PASS:
{
struct callback_info *new_callback;
if (!callback)
@@ -350,27 +436,52 @@ register_callback (const char *plugin_name,
plugin_callbacks[event] = new_callback;
}
break;
- case PLUGIN_EVENT_LAST:
- default:
- error ("Unknown callback event registered by plugin %s",
- plugin_name);
}
}
+/* Remove a callback for EVENT which has been registered with for a plugin
+ PLUGIN_NAME. Return PLUGEVT_SUCCESS if a matching callback was
+ found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching
+ callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid. */
+int
+unregister_callback (const char *plugin_name, int event)
+{
+ struct callback_info *callback, **cbp;
+
+ if (event >= event_last)
+ return PLUGEVT_NO_SUCH_EVENT;
+
+ for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next)
+ if (strcmp (callback->plugin_name, plugin_name) == 0)
+ {
+ *cbp = callback->next;
+ return PLUGEVT_SUCCESS;
+ }
+ return PLUGEVT_NO_CALLBACK;
+}
/* Called from inside GCC. Invoke all plug-in callbacks registered with
the specified event.
+ Return PLUGEVT_SUCCESS if at least one callback was called,
+ PLUGEVT_NO_CALLBACK if there was no callback.
EVENT - the event identifier
GCC_DATA - event-specific data provided by the compiler */
-void
-invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
+int
+invoke_plugin_callbacks (int event, void *gcc_data)
{
+ int retval = PLUGEVT_SUCCESS;
+
timevar_push (TV_PLUGIN_RUN);
switch (event)
{
+ case PLUGIN_EVENT_FIRST_DYNAMIC:
+ default:
+ gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC);
+ gcc_assert (event < event_last);
+ /* Fall through. */
case PLUGIN_FINISH_TYPE:
case PLUGIN_START_UNIT:
case PLUGIN_FINISH_UNIT:
@@ -381,24 +492,35 @@ invoke_plugin_callbacks (enum plugin_event event, void *gcc_data)
case PLUGIN_GGC_START:
case PLUGIN_GGC_MARKING:
case PLUGIN_GGC_END:
+ case PLUGIN_ALL_PASSES_START:
+ case PLUGIN_ALL_PASSES_END:
+ case PLUGIN_ALL_IPA_PASSES_START:
+ case PLUGIN_ALL_IPA_PASSES_END:
+ case PLUGIN_OVERRIDE_GATE:
+ case PLUGIN_PASS_EXECUTION:
+ case PLUGIN_EARLY_GIMPLE_PASSES_START:
+ case PLUGIN_EARLY_GIMPLE_PASSES_END:
+ case PLUGIN_NEW_PASS:
{
/* Iterate over every callback registered with this event and
call it. */
struct callback_info *callback = plugin_callbacks[event];
+
+ if (!callback)
+ retval = PLUGEVT_NO_CALLBACK;
for ( ; callback; callback = callback->next)
(*callback->func) (gcc_data, callback->user_data);
}
break;
case PLUGIN_PASS_MANAGER_SETUP:
- case PLUGIN_EVENT_LAST:
case PLUGIN_REGISTER_GGC_ROOTS:
case PLUGIN_REGISTER_GGC_CACHES:
- default:
gcc_assert (false);
}
timevar_pop (TV_PLUGIN_RUN);
+ return retval;
}
#ifdef ENABLE_PLUGIN
@@ -623,7 +745,7 @@ plugins_active_p (void)
{
int event;
- for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+ for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
if (plugin_callbacks[event])
return true;
@@ -643,7 +765,7 @@ dump_active_plugins (FILE *file)
return;
fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
- for (event = PLUGIN_PASS_MANAGER_SETUP; event < PLUGIN_EVENT_LAST; event++)
+ for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
if (plugin_callbacks[event])
{
struct callback_info *ci;
@@ -688,3 +810,13 @@ plugin_default_version_check (struct plugin_gcc_version *gcc_version,
return false;
return true;
}
+
+/* Return the current value of event_last, so that plugins which provide
+ additional functionality for events for the benefit of high-level plugins
+ know how many valid entries plugin_event_name holds. */
+
+int
+get_event_last (void)
+{
+ return event_last;
+}