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

Richard Biener richard.guenther@gmail.com
Tue Jun 2 08:40:00 GMT 2015


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.

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...).

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 Gcc-patches mailing list