On Thu, 2026-01-08 at 18:54 -0800, Andrew Pinski wrote:
> On Fri, Nov 14, 2025 at 10:33 AM David Malcolm <[email protected]>
> wrote:
> > 
> > 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.
> 
> The only complaint I have is ...
> 
> > ---
> >  gcc/channels.h                                | 43 ++++++++++++++
> >  gcc/context.cc                                |  7 ++-
> >  gcc/context.h                                 | 12 ++++
> >  gcc/passes.cc                                 | 12 ++++
> >  gcc/testsuite/gcc.dg/plugin/plugin.exp        |  1 +
> >  .../plugin/progress_notifications_plugin.cc   | 51
> > ++++++++++++++++
> >  gcc/topics/pass-events.h                      | 59
> > +++++++++++++++++++
> >  7 files changed, 184 insertions(+), 1 deletion(-)
> >  create mode 100644 gcc/channels.h
> >  create mode 100644
> > gcc/testsuite/gcc.dg/plugin/progress_notifications_plugin.cc
> >  create mode 100644 gcc/topics/pass-events.h
> > 
> > diff --git a/gcc/channels.h b/gcc/channels.h
> > new file mode 100644
> > index 0000000000000..433a1e7fcf62a
> > --- /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 f31acc11460eb..cbd7f2bda48e0 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 2220e517d0c50..e881d565676d1 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 a33c8d924a52d..440852f12fabf 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;
> You have this but then ...
> 
> > +
> >    unsigned int todo_after = 0;
> > 
> >    bool gate_status;
> > 
> > +  if (auto channel = g->get_channels
> > ().pass_events_channel.get_if_active ())
> > +    channel->publish (gcc::topics::pass_events::before_pass {pass,
> > cfun});
> 
> You write out the fully qualified name here. Should it just be
> pass_events::before_pass ?

Good catch; thanks.  I fixed that and have pushed the series to trunk.


> Also maybe we should be able to do:
> ```
> if (auto channel = pass_events_channel_if_active (g))
> ```
> Which is slightly easier to write. Obviously it will be a wrapper for
> `g->get_channels ().pass_events_channel.get_if_active ()`.

Adding this requires a header that includes the topics, the channels,
and the global context, so I decided not to bother.

I verified the bootstrap, regression tests, and some light manually
testing, and have pushed the series as r16-6663-gb34dad6d185a2d through
r16-6666-gf68343c2543ab6.

Thanks
Dave


> 
> Thanks,
> Andrew
> 
> > +
> >    /* 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 (gcc::topics::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 38991e8e6191a..b2812db5890ab 100644
> > --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
> > @@ -201,6 +201,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 0000000000000..e1fe2a54820f0
> > --- /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 0000000000000..2b072f65bc154
> > --- /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 */
> > --
> > 2.26.3
> > 
> 

Reply via email to