This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 15/16] gcc: Use libgas and libld within the driver
- From: Trevor Saunders <tbsaunde at tbsaunde dot org>
- To: Richard Biener <richard dot guenther at gmail dot com>
- Cc: David Malcolm <dmalcolm at redhat dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>, Binutils <binutils at sourceware dot org>
- Date: Tue, 2 Jun 2015 07:06:57 -0400
- Subject: Re: [PATCH 15/16] gcc: Use libgas and libld within the driver
- Authentication-results: sourceware.org; auth=none
- References: <1433192664-50156-1-git-send-email-dmalcolm at redhat dot com> <1433192664-50156-16-git-send-email-dmalcolm at redhat dot com> <CAFiYyc2Puh05oTYfM1aJf0KFjqoMbbXTQBeQ2H3gNoQ+JTMPOg at mail dot gmail dot com>
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
> >