https://gcc.gnu.org/g:4a2e1c31159aab4bde1990589ccab0da2436dfad
commit r16-6664-g4a2e1c31159aab4bde1990589ccab0da2436dfad Author: David Malcolm <[email protected]> Date: Fri Jan 9 15:54:15 2026 -0500 Add publish/subscribe topics and channel: pass_events This patch adds a new "struct compiler_channels" to hold channels relating to the compiler that plugins (or diagnostic sinks) might want to subscribe to events for, accessed from the global gcc::context object, along with a new gcc/topics/ source subdirectory to hold strongly-typed publish/subscribe topics relating to the compiler. For now, there is just one: pass_events_channel, which, if there are any subscribers, issues notifications about passes starting/stopping on particular functions, using topics::pass_events, declared in topics/pass-events.h, but followup patches add more kinds of notification channel. A toy plugin in the testsuite shows how this could be used to build a progress notification UI for the compiler, and a followup patch uses the channel to (optionally) capture CFG information at each stage of optimization in machine-readable form into a SARIF sink. gcc/ChangeLog: * channels.h: New file. * context.cc: Define INCLUDE_LIST. Include "channels.h". (gcc::context::context): Create m_channels. (gcc::context::~context): Delete it. * context.h (struct compiler_channels): New forward decl. (gcc::context::get_channels): New accessor. (gcc::context::m_channels): New field. * passes.cc: Define INCLUDE_LIST. Include "topics/pass-events.h" and "channels.h". (execute_one_pass): If the global context's pass_events_channel has subscribers, publish before_pass and after_pass events to it. * topics/pass-events.h: New file. gcc/testsuite/ChangeLog: * gcc.dg/plugin/plugin.exp: Add progress_notifications_plugin.cc. * gcc.dg/plugin/progress_notifications_plugin.cc: New test plugin. Signed-off-by: David Malcolm <[email protected]> Diff: --- gcc/channels.h | 43 ++++++++++++++++ gcc/context.cc | 7 ++- gcc/context.h | 12 +++++ gcc/passes.cc | 12 +++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 1 + .../gcc.dg/plugin/progress_notifications_plugin.cc | 51 +++++++++++++++++++ gcc/topics/pass-events.h | 59 ++++++++++++++++++++++ 7 files changed, 184 insertions(+), 1 deletion(-) diff --git a/gcc/channels.h b/gcc/channels.h new file mode 100644 index 000000000000..433a1e7fcf62 --- /dev/null +++ b/gcc/channels.h @@ -0,0 +1,43 @@ +/* channels.h - Publish/Subscribe channels on compiler-specific topics. + Copyright (C) 2025 Free Software Foundation, Inc. + Contributed by David Malcolm <[email protected]>. + +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_CHANNELS_H +#define GCC_CHANNELS_H + +#include "pub-sub.h" + +namespace gcc { + +/* Forward decls of subscribers for the various topics we have + publish/subscribe channels for. */ +namespace topics { + namespace pass_events { struct subscriber; } +} // namespace gcc::topics + +/* Publish/subscribe channels on various compiler-specific topics. */ + +struct compiler_channels +{ + pub_sub::channel<topics::pass_events::subscriber> pass_events_channel; +}; + +} // namespace gcc + +#endif /* ! GCC_CHANNELS_H */ diff --git a/gcc/context.cc b/gcc/context.cc index 152ab586a7f2..053010883b71 100644 --- a/gcc/context.cc +++ b/gcc/context.cc @@ -17,6 +17,7 @@ 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/>. */ +#define INCLUDE_LIST #include "config.h" #include "system.h" #include "coretypes.h" @@ -24,12 +25,15 @@ along with GCC; see the file COPYING3. If not see #include "pass_manager.h" #include "dumpfile.h" #include "realmpfr.h" +#include "channels.h" /* The singleton holder of global state: */ gcc::context *g; gcc::context::context () - : m_passes (NULL), m_dumps (new gcc::dump_manager ()) +: m_passes (NULL), + m_dumps (new gcc::dump_manager ()), + m_channels (new gcc::compiler_channels ()) { have_offload = false; } @@ -38,6 +42,7 @@ gcc::context::~context () { delete m_passes; delete m_dumps; + delete m_channels; /* Release MPFR caches to avoid Valgrind leak reports. */ mpfr_free_cache (); diff --git a/gcc/context.h b/gcc/context.h index d5180ccdc587..0e54b9b8960a 100644 --- a/gcc/context.h +++ b/gcc/context.h @@ -24,6 +24,7 @@ namespace gcc { class pass_manager; class dump_manager; +struct compiler_channels; /* GCC's internal state can be divided into zero or more "parallel universe" of state; an instance of this class is one such @@ -51,6 +52,15 @@ public: dump_manager *get_dumps () {gcc_assert (m_dumps); return m_dumps; } + /* Publish/subscribe channels for events + on various compiler-specific topics. */ + compiler_channels & + get_channels () const + { + gcc_assert (m_channels); + return *m_channels; + } + private: /* Pass-management. */ pass_manager *m_passes; @@ -58,6 +68,8 @@ private: /* Dump files. */ dump_manager *m_dumps; + compiler_channels *m_channels; + }; // class context } // namespace gcc diff --git a/gcc/passes.cc b/gcc/passes.cc index cd8da8bb75f8..837f84e3d834 100644 --- a/gcc/passes.cc +++ b/gcc/passes.cc @@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see in the proper order, and counts the time used by each. Error messages and low-level interface to malloc also handled here. */ +#define INCLUDE_LIST #include "config.h" #include "system.h" #include "coretypes.h" @@ -63,6 +64,8 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" /* for fnotice */ #include "stringpool.h" #include "attribs.h" +#include "topics/pass-events.h" +#include "channels.h" /* Reserved TODOs */ #define TODO_verify_il (1u << 31) @@ -2575,10 +2578,15 @@ skip_pass (opt_pass *pass) bool execute_one_pass (opt_pass *pass) { + namespace pass_events = gcc::topics::pass_events; + unsigned int todo_after = 0; bool gate_status; + if (auto channel = g->get_channels ().pass_events_channel.get_if_active ()) + channel->publish (pass_events::before_pass {pass, cfun}); + /* IPA passes are executed on whole program, so cfun should be NULL. Other passes need function context set. */ if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) @@ -2741,6 +2749,10 @@ execute_one_pass (opt_pass *pass) if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) report_heap_memory_use (); + + if (auto channel = g->get_channels ().pass_events_channel.get_if_active ()) + channel->publish (pass_events::after_pass {pass, cfun}); + return true; } diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 55eac8628fc6..deef8e8570c2 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -200,6 +200,7 @@ set plugin_test_list [list \ cpython-plugin-test-PyList_Append.c \ cpython-plugin-test-PyList_New.c \ cpython-plugin-test-PyLong_FromLong.c } \ + { progress_notifications_plugin.cc } \ ] foreach plugin_test $plugin_test_list { diff --git a/gcc/testsuite/gcc.dg/plugin/progress_notifications_plugin.cc b/gcc/testsuite/gcc.dg/plugin/progress_notifications_plugin.cc new file mode 100644 index 000000000000..e1fe2a54820f --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/progress_notifications_plugin.cc @@ -0,0 +1,51 @@ +/* Toy implementation of progress notifications about the compiler, + using gcc::topics::pass_events. */ + +#define INCLUDE_LIST +#include "gcc-plugin.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree-pass.h" +#include "diagnostic-core.h" +#include "context.h" +#include "channels.h" +#include "topics/pass-events.h" + +int plugin_is_GPL_compatible; + +namespace pass_events = gcc::topics::pass_events; + +namespace { + +class notification_event_subscriber : public pass_events::subscriber +{ +public: + void on_message (const pass_events::before_pass &m) final override + { + if (m.fun) + inform (m.fun->function_start_locus, "starting pass %qs on %qD", + m.pass->name, m.fun->decl); + else + inform (UNKNOWN_LOCATION, "starting pass %qs", m.pass->name); + } + void on_message (const pass_events::after_pass &m) final override + { + if (m.fun) + inform (m.fun->function_end_locus, "finished pass %qs on %qD", + m.pass->name, m.fun->decl); + else + inform (UNKNOWN_LOCATION, "finished pass %qs", m.pass->name); + } +} my_event_subscriber; + +} // anonymous namespace + +int +plugin_init (struct plugin_name_args *, + struct plugin_gcc_version *) +{ + g->get_channels ().pass_events_channel.add_subscriber (my_event_subscriber); + + return 0; +} diff --git a/gcc/topics/pass-events.h b/gcc/topics/pass-events.h new file mode 100644 index 000000000000..2b072f65bc15 --- /dev/null +++ b/gcc/topics/pass-events.h @@ -0,0 +1,59 @@ +/* pass-events.h - pub/sub messages about GCC optimization passes. + Copyright (C) 2025 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_TOPICS_PASS_EVENTS_H +#define GCC_TOPICS_PASS_EVENTS_H + +#include "pub-sub.h" + +namespace gcc { +namespace topics { + +/* A topic for messages relating to GCC optimization passes. */ + +namespace pass_events { + +struct before_pass +{ + opt_pass *pass; + function *fun; +}; + +struct after_pass +{ + opt_pass *pass; + function *fun; +}; + +/* Abstract base class for a subscriber to messages about + GCC optimization passes. */ + +struct subscriber +{ + virtual ~subscriber () = default; + + virtual void on_message (const before_pass &) = 0; + virtual void on_message (const after_pass &) = 0; +}; + +} // namespace gcc::topics::pass_events +} // namespace gcc::topics +} // namespace gcc + +#endif /* ! GCC_TOPICS_PASS_EVENTS_H */
