[PATCH 15/16] gcc: Use libgas and libld within the driver

Trevor Saunders tbsaunde@tbsaunde.org
Tue Jun 2 11:07:00 GMT 2015


On Tue, Jun 02, 2015 at 10:31:53AM +0200, Richard Biener wrote:
> On Mon, Jun 1, 2015 at 11:04 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> > This patch adds the ability for gcc to be configured with:
> >   --with-embedded-as
> >   --with-embedded-ld
> > If so, invocations of "as" and "ld" are detected in the gcc driver, and
> > specialcased by invoking these in-process as shared libraries.  This is
> > intended for use by libgccjit, when the driver itself is in-process
> > within libgccjit, eliminating fork/exec and dynamic-library resolution.
> >
> > Doing so dramatically speeds up jit.dg/test-benchmark.c.
> >
> > The patch generalizes the named items support within timevar.c, so that
> > as well as having bucket of named "jit client items" we also have
> > buckets for "as" and for "ld" so that they can account for time spent
> > within them.
> >
> > One remaining hack here, appending CFLAGS-gcc.o with a hardcoded include
> > path, but I didn't want that to hold up posting what I've got so far.
> 
> Hum, so why not go further and embed as into cc1/cc1plus, etc.?  That is,
> make the as invocation parts of the driver accessible to the compiler
> in some way.

It certainly seems like something worth looking into, but I certainly
wouldn't want to hold binutils changes up on that.

> This way we can eventually add a more efficient way of funneling the compiler
> assembler output to libas (well, I suppose you at least use -pipe...).

yeah, and eventually maybe dump a whole bunch of text formating code.  I
wonder how much faster just doing this makes things though.

Trev

> 
> Richard.
> 
> > gcc/ChangeLog:
> >         * configure.ac: Add --with-embedded-as and --with-embedded-ld.
> >         * gcc.c: Include libgas.h and libld.h.
> >         (class ctimershim): New.
> >         (ctimershim::impl_push): New.
> >         (ctimershim::impl_pop): New.
> >         (run_embedded_as): New.
> >         (run_embedded_ld): New.
> >         (enum known_command): New.
> >         (get_known_command): New.
> >         (tv_id_for_known_command): New.
> >         (maybe_run_embedded_command): New.
> >         (execute): Invoke get_known_command and
> >         maybe_run_embedded_command, potentially avoiding the need to call
> >         into pex.
> >         * timevar.c (timer::named_items::print): Add "name" param rather
> >         than hardcoding "Client items".
> >         (timer::timer): Initialize "m_has_named_items"; replace
> >         "m_jit_client_items" with "m_named_items" array.
> >         (timer::~timer): Likewise.
> >         (timer::push_client_item): Rename to...
> >         (timer::push_named_item): ...this and add "dict" param,
> >         generalizing to support an array of dicts of named items.
> >         (timer::pop_client_item): Rename to...
> >         (timer::pop_named_item): ...this, generalizing to support
> >         an array of dicts of named items.
> >         (timer::print): Print JIT client items first (if any), then
> >         GCC timevar items, then embedded as items (if any), then embedded
> >         ld items (if any).
> >         * timevar.def (TV_DRIVER_EMBEDDED_AS): New.
> >         (TV_DRIVER_EMBEDDED_LD): New.
> >         * timevar.h (timer::item_dict): New enum.
> >         (timer::push_client_item): Rename to...
> >         (timer::push_named_item): ...this, adding "dict" param.
> >         (timer::pop_client_item): Rename to...
> >         (timer::pop_named_item):  ...this, adding "dict" param.
> >         (timer::get_item_dict): New.
> >         (timer::m_jit_client_items): Drop this field in favor of...
> >         (timer::m_named_items): ...this array.
> >         (timer::m_has_named_items): New.
> >
> > gcc/jit/ChangeLog:
> >         * Make-lang.in (LIBGCCJIT_FILENAME): Add EXTRA_GCC_LIBS to link.
> >         * libgccjit.c (gcc_jit_timer_push): Replace call to
> >         timer->push_client_item with timer->push_named_item.
> >         (gcc_jit_timer_pop): Likewise for pop.
> >         * notes.txt: Indicate that as/ld could be embedded.
> > ---
> >  gcc/Makefile.in      |   3 +
> >  gcc/configure.ac     |  25 ++++++
> >  gcc/gcc.c            | 214 ++++++++++++++++++++++++++++++++++++++++++++++++---
> >  gcc/jit/Make-lang.in |   2 +-
> >  gcc/jit/libgccjit.c  |   5 +-
> >  gcc/jit/notes.txt    |   4 +-
> >  gcc/timevar.c        |  56 ++++++++++----
> >  gcc/timevar.def      |   2 +
> >  gcc/timevar.h        |  33 +++++++-
> >  9 files changed, 308 insertions(+), 36 deletions(-)
> >
> > diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> > index 2388975..9061933 100644
> > --- a/gcc/Makefile.in
> > +++ b/gcc/Makefile.in
> > @@ -1993,6 +1993,9 @@ DRIVER_DEFINES = \
> >
> >  CFLAGS-gcc.o += $(DRIVER_DEFINES)
> >
> > +# FIXME
> > +CFLAGS-gcc.o += -I/home/david/coding/gcc-python/binutils-gdb-libraries/install/include
> > +
> >  specs.h : s-specs ; @true
> >  s-specs : Makefile
> >         lsf="$(lang_specs_files)"; for f in $$lsf; do \
> > diff --git a/gcc/configure.ac b/gcc/configure.ac
> > index 810725c..6f50908 100644
> > --- a/gcc/configure.ac
> > +++ b/gcc/configure.ac
> > @@ -1114,6 +1114,31 @@ LIBS=
> >  AC_SEARCH_LIBS(kstat_open, kstat)
> >  EXTRA_GCC_LIBS="$LIBS"
> >  LIBS="$save_LIBS"
> > +
> > +# Support embedding libgas in the driver
> > +
> > +AC_ARG_WITH([embedded-as],
> > + [AS_HELP_STRING([--with-embedded-as],
> > +               [use libgas to embed the assembler in-process])],
> > + [AC_CHECK_LIB([gas], [gas_main],
> > +   [EXTRA_GCC_LIBS+=" -lgas $LDFLAGS";
> > +    AC_DEFINE(HAVE_LIBGAS, 1,
> > +       [Define if libgas is installed.])
> > +   ],
> > +   [AC_MSG_ERROR(["libgas not found"])])])
> > +
> > +# Support embedding libld in the driver
> > +
> > +AC_ARG_WITH([embedded-ld],
> > + [AS_HELP_STRING([--with-embedded-ld],
> > +                [use libld to embed the linker in-process])],
> > + [AC_CHECK_LIB([ld], [ld_main],
> > +               [EXTRA_GCC_LIBS+=" -lld $LDFLAGS";
> > +                AC_DEFINE(HAVE_LIBLD, 1,
> > +                [Define if libld is installed.])
> > +               ],
> > +               [AC_MSG_ERROR(["libld not found"])])])
> > +
> >  AC_SUBST(EXTRA_GCC_LIBS)
> >
> >  # Some systems put ldexp and frexp in libm instead of libc; assume
> > diff --git a/gcc/gcc.c b/gcc/gcc.c
> > index 93f41ec..ed92c7d 100644
> > --- a/gcc/gcc.c
> > +++ b/gcc/gcc.c
> > @@ -45,6 +45,14 @@ compilation is specified by a string called a "spec".  */
> >  #include "filenames.h"
> >  #include "timevar.h"
> >
> > +#ifdef HAVE_LIBGAS
> > +#include "libgas.h"
> > +#endif
> > +
> > +#ifdef HAVE_LIBLD
> > +#include "libld.h"
> > +#endif
> > +
> >  /* Singleton instance of "driver" class.  */
> >  static driver *g_driver;
> >
> > @@ -2807,6 +2815,190 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
> >               require_machine_suffix, os_multilib);
> >  }
> >
> > +
> > +/* An implementation of the ctimer hooks C API, forwarding to
> > +   our C++ "timer" class, for a particular timer::item_dict.  */
> > +class ctimershim : public ctimer
> > +{
> > + public:
> > +  ctimershim (timer *t,
> > +             enum timer::item_dict dict)
> > +    : m_timer (t),
> > +      m_dict (dict)
> > +  {
> > +    this->push = impl_push;
> > +    this->pop = impl_pop;
> > +  }
> > +
> > + private:
> > +  static void impl_push (ctimer *that, const char *item_name);
> > +  static void impl_pop (ctimer *that);
> > +
> > + private:
> > +   timer *m_timer;
> > +   enum timer::item_dict m_dict;
> > +};
> > +
> > +/* Implement CTIMER_PUSH in terms of pushing a named item
> > +   within the given item_dict.  */
> > +void
> > +ctimershim::impl_push (ctimer *that, const char *item_name)
> > +{
> > +  ctimershim *this_ = static_cast <ctimershim *> (that);
> > +  gcc_assert (this_->m_timer);
> > +  this_->m_timer->push_named_item (this_->m_dict, item_name);
> > +}
> > +
> > +/* Implement CTIMER_POP in terms of popping the item
> > +   from the given item_dict.  */
> > +void
> > +ctimershim::impl_pop (ctimer *that)
> > +{
> > +  ctimershim *this_ = static_cast <ctimershim *> (that);
> > +  gcc_assert (this_->m_timer);
> > +  this_->m_timer->pop_named_item (this_->m_dict);
> > +}
> > +
> > +#ifdef HAVE_LIBGAS
> > +
> > +/* Invoke gas_main, passing in the driver's timer
> > +   so that the gas code can record timing information into it.  */
> > +
> > +static int run_embedded_as (int argc, const char **argv)
> > +{
> > +  gcc_assert (g_driver);
> > +  timer *driver_timer = g_driver->get_timer ();
> > +  auto_timevar tv (driver_timer, TV_DRIVER_EMBEDDED_AS);
> > +  if (0)
> > +    {
> > +      fprintf (stderr, "run_embedded_as: %i args\n", argc);
> > +      for (int i = 0; i < argc; i++)
> > +       fprintf (stderr, "  argv[%i]: %s\n", i, argv[i]);
> > +    }
> > +
> > +  ctimershim ct (driver_timer, timer::ITEM_DICT_EMBEDDED_AS);
> > +  return gas_main (argc,
> > +                   argv,
> > +                   0, /* "standalone" */
> > +                  driver_timer ? &ct : NULL); /* "timer" */
> > +}
> > +
> > +#endif /* #ifdef HAVE_LIBGAS */
> > +
> > +#ifdef HAVE_LIBLD
> > +
> > +/* Invoke ld_main, passing in the driver's timer
> > +   so that the linker code can record timing information into it.  */
> > +
> > +static int run_embedded_ld (int argc, const char **argv)
> > +{
> > +  gcc_assert (g_driver);
> > +  timer *driver_timer = g_driver->get_timer ();
> > +  auto_timevar tv (driver_timer, TV_DRIVER_EMBEDDED_LD);
> > +  if (0)
> > +    {
> > +      fprintf (stderr, "run_embedded_ld: %i args\n", argc);
> > +      for (int i = 0; i < argc; i++)
> > +       fprintf (stderr, "  argv[%i]: %s\n", i, argv[i]);
> > +    }
> > +
> > +  ctimershim ct (driver_timer, timer::ITEM_DICT_EMBEDDED_LD);
> > +  return ld_main (argc,
> > +                  argv,
> > +                  0, /* "standalone" */
> > +                  driver_timer ? &ct : NULL); /* struct ctimer *  */
> > +}
> > +
> > +#endif /* #ifdef HAVE_LIBLD */
> > +
> > +/* The result of get_known_command.  */
> > +
> > +enum known_command
> > +{
> > +  KNOWN_COMMAND_AS,
> > +  KNOWN_COMMAND_COLLECT2,
> > +  KNOWN_COMMAND_LD,
> > +  KNOWN_COMMAND_OTHER, /* not a known command, or a pipeline.  */
> > +  NUM_KNOWN_COMMANDS
> > +};
> > +
> > +/* Do we have an invocation of a single, known command, with no pipes?
> > +   We can use this for selecting a timevar_id_t for the pex invocation,
> > +   and potentially for running the command in-process.  */
> > +
> > +static enum known_command
> > +get_known_command (int n_commands, const char *argv0)
> > +{
> > +  if (n_commands == 1)
> > +    {
> > +      if (0 == strcmp (argv0, "as"))
> > +       return KNOWN_COMMAND_AS;
> > +      else if (0 == strcmp (argv0, "collect2"))
> > +       return KNOWN_COMMAND_COLLECT2;
> > +      else if (0 == strcmp (argv0, "ld"))
> > +       return KNOWN_COMMAND_LD;
> > +    }
> > +  return KNOWN_COMMAND_OTHER;
> > +}
> > +
> > +/* If we're timing things, and we have a single command in the
> > +   pipeline, bill the time to that command.  Given that we
> > +   need a timevar for each one, we only split out a few important
> > +   commands. */
> > +
> > +const timevar_id_t tv_id_for_known_command[NUM_KNOWN_COMMANDS] = {
> > +  TV_DRIVER_EXECUTE_AS,
> > +  TV_DRIVER_EXECUTE_COLLECT2,
> > +  TV_DRIVER_EXECUTE_LD,
> > +  TV_DRIVER_EXECUTE_OTHER
> > +};
> > +
> > +/* Optimization: if we have a single, known command, and we're linked
> > +   against an embedded copy of it, call it directly in-process, avoiding
> > +   the overhead of fork/exec/dynamic link.
> > +
> > +   Return true if an embedded command was run, writing the result to
> > +   *RESULT_OUT.
> > +   Return false if no embedded command was available, leading *result_out
> > +   untouched.  */
> > +
> > +static bool
> > +maybe_run_embedded_command (enum known_command known_command,
> > +                           int *result_out ATTRIBUTE_UNUSED)
> > +{
> > +#if defined (HAVE_LIBGAS) || defined (HAVE_LIBLD)
> > +  int argc = argbuf.length ();
> > +  const char **argv = argbuf.address ();
> > +#endif
> > +
> > +  switch (known_command)
> > +    {
> > +    case KNOWN_COMMAND_AS:
> > +#ifdef HAVE_LIBGAS
> > +      *result_out = run_embedded_as (argc, argv);
> > +      return true;
> > +#else
> > +      return false;
> > +#endif
> > +
> > +    case KNOWN_COMMAND_COLLECT2:
> > +      return false;
> > +
> > +    case KNOWN_COMMAND_LD:
> > +#ifdef HAVE_LIBLD
> > +      *result_out = run_embedded_ld (argc, argv);
> > +      return true;
> > +#else
> > +      return false;
> > +#endif
> > +
> > +    default:
> > +      gcc_unreachable ();
> > +    case KNOWN_COMMAND_OTHER:
> > +      return false;
> > +    }
> > +}
> > +
> >  /* Execute the command specified by the arguments on the current line of spec.
> >     When using pipes, this includes several piped-together commands
> >     with `|' between them.
> > @@ -2845,23 +3037,23 @@ execute (void)
> >      if (strcmp (arg, "|") == 0)
> >        n_commands++;
> >
> > +  /* Determine if we're dealing with a single embeddable command.  */
> > +  enum known_command known_command = get_known_command (n_commands,
> > +                                                       argbuf[0]);
> > +
> > +  /* Optimization: potentially avoid fork/exec by calling the command
> > +     as a function in-process.  */
> > +  int result;
> > +  if (maybe_run_embedded_command (known_command, &result))
> > +    return result;
> > +
> >    /* If we're timing things, and we have a single command in the
> >       pipeline, bill the time to that command.  Given that we
> >       need a timevar for each one, we only split out a few important
> >       commands. */
> > -  timevar_id_t tv_id;
> > -  tv_id = TV_DRIVER_EXECUTE_OTHER;
> >    gcc_assert (g_driver);
> >    timer *driver_timer = g_driver->get_timer ();
> > -  if (driver_timer && n_commands == 1)
> > -    {
> > -      if (0 == strcmp (argbuf[0], "as"))
> > -       tv_id = TV_DRIVER_EXECUTE_AS;
> > -      else if (0 == strcmp (argbuf[0], "collect2"))
> > -       tv_id = TV_DRIVER_EXECUTE_COLLECT2;
> > -      else if (0 == strcmp (argbuf[0], "ld"))
> > -       tv_id = TV_DRIVER_EXECUTE_LD;
> > -    }
> > +  timevar_id_t tv_id = tv_id_for_known_command[known_command];
> >    auto_timevar tv (driver_timer, tv_id);
> >
> >    /* Get storage for each command.  */
> > diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
> > index 9cff752..a7efe2e 100644
> > --- a/gcc/jit/Make-lang.in
> > +++ b/gcc/jit/Make-lang.in
> > @@ -84,7 +84,7 @@ $(LIBGCCJIT_FILENAME): $(jit_OBJS) \
> >         +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
> >              $(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
> >              $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) \
> > -            $(EXTRA_GCC_OBJS) \
> > +            $(EXTRA_GCC_OBJS) $(EXTRA_GCC_LIBS) \
> >              -Wl,--version-script=$(srcdir)/jit/libgccjit.map \
> >              -Wl,-soname,$(LIBGCCJIT_SONAME)
> >
> > diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
> > index 2a67ef7..8eee2da 100644
> > --- a/gcc/jit/libgccjit.c
> > +++ b/gcc/jit/libgccjit.c
> > @@ -2431,7 +2431,8 @@ gcc_jit_timer_push (gcc_jit_timer *timer,
> >  {
> >    RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
> >    RETURN_IF_FAIL (item_name, NULL, NULL, "NULL item_name");
> > -  timer->push_client_item (item_name);
> > +  timer->push_named_item (timer::ITEM_DICT_JIT_CLIENT_CODE,
> > +                         item_name);
> >  }
> >
> >  /* Pop the top item from the timing stack.  */
> > @@ -2441,7 +2442,7 @@ gcc_jit_timer_pop (gcc_jit_timer *timer)
> >  {
> >    RETURN_IF_FAIL (timer, NULL, NULL, "NULL timer");
> >    /* FIXME: mismatching item? */
> > -  timer->pop_client_item ();
> > +  timer->pop_named_item (timer::ITEM_DICT_JIT_CLIENT_CODE);
> >  }
> >
> >  /* Print timing information to the given stream about activity since
> > diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
> > index 36e05cb..4469145 100644
> > --- a/gcc/jit/notes.txt
> > +++ b/gcc/jit/notes.txt
> > @@ -81,8 +81,8 @@ Client Code   . Generated .            libgccjit.so
> >                .           .      --> Convert assembler to DSO, via embedded
> >                .           .          copy of driver:
> >                .           .           driver::main ()
> > -              .           .             invocation of "as"
> > -              .           .             invocation of "ld"
> > +              .           .             in-process libgas, or out-of-process invocation of "as"
> > +              .           .             in-process libld, or out-of-process invocation of "ld"
> >                .           .           driver::finalize ()
> >                .           .      <----
> >                .           .      │   .               .
> > diff --git a/gcc/timevar.c b/gcc/timevar.c
> > index 9bc62e6..28db5b4 100644
> > --- a/gcc/timevar.c
> > +++ b/gcc/timevar.c
> > @@ -134,7 +134,7 @@ class timer::named_items
> >
> >    void push (const char *item_name);
> >    void pop ();
> > -  void print (FILE *fp, const timevar_time_def *total);
> > +  void print (FILE *fp, const char *name, const timevar_time_def *total);
> >
> >   private:
> >    /* Which timer instance does this relate to?  */
> > @@ -197,11 +197,13 @@ timer::named_items::pop ()
> >  /* Print the given client item.  Helper function for timer::print.  */
> >
> >  void
> > -timer::named_items::print (FILE *fp, const timevar_time_def *total)
> > +timer::named_items::print (FILE *fp,
> > +                          const char *name,
> > +                          const timevar_time_def *total)
> >  {
> >    unsigned int i;
> >    const char *item_name;
> > -  fprintf (fp, "Client items:\n");
> > +  fprintf (fp, "%s:\n", name);
> >    FOR_EACH_VEC_ELT (m_names, i, item_name)
> >      {
> >        timer::timevar_def *def = m_hash_map.get (item_name);
> > @@ -260,11 +262,14 @@ timer::timer () :
> >    m_stack (NULL),
> >    m_unused_stack_instances (NULL),
> >    m_start_time (),
> > -  m_jit_client_items (NULL)
> > +  m_has_named_items (false)
> >  {
> >    /* Zero all elapsed times.  */
> >    memset (m_timevars, 0, sizeof (m_timevars));
> >
> > +  /* There are no named_timers yet.  */
> > +  memset (m_named_items, 0, sizeof (m_named_items));
> > +
> >    /* Initialize the names of timing variables.  */
> >  #define DEFTIMEVAR(identifier__, name__) \
> >    m_timevars[identifier__].name = name__;
> > @@ -298,7 +303,8 @@ timer::~timer ()
> >        free (iter);
> >      }
> >
> > -  delete m_jit_client_items;
> > +  for (int i = 0; i < NUM_ITEM_DICTS; i++)
> > +    delete m_named_items[i];
> >  }
> >
> >  /* Initialize timing variables.  */
> > @@ -544,24 +550,32 @@ timer::cond_stop (timevar_id_t timevar)
> >  /* Push the named item onto the timing stack.  */
> >
> >  void
> > -timer::push_client_item (const char *item_name)
> > +timer::push_named_item (enum item_dict dict,
> > +                       const char *item_name)
> >  {
> > +  gcc_assert (dict < NUM_ITEM_DICTS);
> >    gcc_assert (item_name);
> > -
> >    /* Lazily create the named_items instance.  */
> > -  if (!m_jit_client_items)
> > -    m_jit_client_items = new named_items (this);
> > +  named_items **item_dict = &m_named_items[dict];
> > +  if (!*item_dict)
> > +    *item_dict = new named_items (this);
> > +  (*item_dict)->push (item_name);
> >
> > -  m_jit_client_items->push (item_name);
> > +  m_has_named_items = true;
> >  }
> >
> >  /* Pop the top-most client item from the timing stack.  */
> >
> >  void
> > -timer::pop_client_item ()
> > +timer::pop_named_item (enum item_dict dict)
> >  {
> > -  gcc_assert (m_jit_client_items);
> > -  m_jit_client_items->pop ();
> > +  gcc_assert (dict < NUM_ITEM_DICTS);
> > +  named_items *item_dict = m_named_items[dict];
> > +
> > +  /* If this fails, we have a pop from something that was never pushed to.  */
> > +  gcc_assert (item_dict);
> > +
> > +  item_dict->pop ();
> >  }
> >
> >  /* Validate that phase times are consistent.  */
> > @@ -687,7 +701,11 @@ timer::print (FILE *fp)
> >    m_start_time = now;
> >
> >    fputs ("\nExecution times (seconds)\n", fp);
> > -  if (m_jit_client_items)
> > +  if (m_named_items[ITEM_DICT_JIT_CLIENT_CODE])
> > +    m_named_items[ITEM_DICT_JIT_CLIENT_CODE]->print (fp,
> > +                                                    "Client items",
> > +                                                    total);
> > +  if (m_has_named_items)
> >      fputs ("GCC items:\n", fp);
> >    for (id = 0; id < (unsigned int) TIMEVAR_LAST; ++id)
> >      {
> > @@ -713,8 +731,14 @@ timer::print (FILE *fp)
> >
> >        print_row (fp, total, tv);
> >      }
> > -  if (m_jit_client_items)
> > -    m_jit_client_items->print (fp, total);
> > +  if (m_named_items[ITEM_DICT_EMBEDDED_AS])
> > +    m_named_items[ITEM_DICT_EMBEDDED_AS]->print (fp,
> > +                                                "Embedded 'as'",
> > +                                                total);
> > +  if (m_named_items[ITEM_DICT_EMBEDDED_LD])
> > +    m_named_items[ITEM_DICT_EMBEDDED_LD]->print (fp,
> > +                                                "Embedded 'ld'",
> > +                                                total);
> >
> >    /* Print total time.  */
> >    fputs (" TOTAL                 :", fp);
> > diff --git a/gcc/timevar.def b/gcc/timevar.def
> > index ce9236d..2360b30 100644
> > --- a/gcc/timevar.def
> > +++ b/gcc/timevar.def
> > @@ -292,8 +292,10 @@ DEFTIMEVAR (TV_DRIVER_SETUP          , "driver: setup")
> >  DEFTIMEVAR (TV_DRIVER_SPEC          , "driver: do spec on infiles")
> >  DEFTIMEVAR (TV_DRIVER_LINK          , "driver: run linker")
> >  DEFTIMEVAR (TV_DRIVER_EXECUTE_AS     , "driver: executing \"as\"")
> > +DEFTIMEVAR (TV_DRIVER_EMBEDDED_AS    , "driver: embedded assembler")
> >  DEFTIMEVAR (TV_DRIVER_EXECUTE_COLLECT2, "driver: executing \"collect2\"")
> >  DEFTIMEVAR (TV_DRIVER_EXECUTE_LD     , "driver: executing \"ld\"")
> > +DEFTIMEVAR (TV_DRIVER_EMBEDDED_LD    , "driver: embedded linker")
> >  DEFTIMEVAR (TV_DRIVER_EXECUTE_OTHER  , "driver: executing subprocess")
> >  DEFTIMEVAR (TV_LINK                 , "link JIT code")
> >  DEFTIMEVAR (TV_LOAD                 , "load JIT result")
> > diff --git a/gcc/timevar.h b/gcc/timevar.h
> > index d46dc88..a0133d2 100644
> > --- a/gcc/timevar.h
> > +++ b/gcc/timevar.h
> > @@ -105,6 +105,16 @@ extern void timevar_cond_stop (timevar_id_t, bool);
> >  class timer
> >  {
> >   public:
> > +  /* Support for multiple collections of named timing items.  */
> > +  enum item_dict
> > +  {
> > +    ITEM_DICT_JIT_CLIENT_CODE,
> > +    ITEM_DICT_EMBEDDED_AS,
> > +    ITEM_DICT_EMBEDDED_LD,
> > +    NUM_ITEM_DICTS
> > +  };
> > +
> > + public:
> >    timer ();
> >    ~timer ();
> >
> > @@ -115,12 +125,20 @@ class timer
> >    bool cond_start (timevar_id_t tv);
> >    void cond_stop (timevar_id_t tv);
> >
> > -  void push_client_item (const char *item_name);
> > -  void pop_client_item ();
> > +  void push_named_item (enum item_dict dict,
> > +                       const char *item_name);
> > +  void pop_named_item (enum item_dict dict);
> >
> >    void print (FILE *fp);
> >
> >   private:
> > +  /* A class for managing a collection of named timing items, for use
> > +     e.g. by libgccjit for timing client code.  This class is declared
> > +     inside timevar.c to avoid everything using timevar.h
> > +     from needing vec and hash_map.  */
> > +  class named_items;
> > +
> > + private:
> >    /* Private member functions.  */
> >    void validate_phases (FILE *fp) const;
> >
> > @@ -131,6 +149,8 @@ class timer
> >                          const timevar_time_def *total,
> >                          const timevar_def *tv);
> >
> > +  named_items *get_item_dict (enum item_dict dict);
> > +
> >   private:
> >
> >    /* Private type: a timing variable.  */
> > @@ -193,10 +213,15 @@ class timer
> >       element.  */
> >    timevar_time_def m_start_time;
> >
> > -  /* If non-NULL, for use when timing libgccjit's client code.  */
> > -  named_items *m_jit_client_items;
> > +  /* Array of named_items, which are created on demand, and hence
> > +     may each be NULL/non-NULL.  */
> > +  named_items *m_named_items[NUM_ITEM_DICTS];
> >
> >    friend class named_items;
> > +
> > +  /* Do we have any named items?  Affects the output of the "print"
> > +     method.  */
> > +  bool m_has_named_items;
> >  };
> >
> >  /* Provided for backward compatibility.  */
> > --
> > 1.8.5.3
> >



More information about the Binutils mailing list