From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 57073 invoked by alias); 2 Jun 2015 11:07:24 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 57054 invoked by uid 89); 2 Jun 2015 11:07:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.1 required=5.0 tests=AWL,BAYES_99,BAYES_999,KAM_LAZY_DOMAIN_SECURITY,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: paperclip.tbsaunde.org Received: from tbsaunde.org (HELO paperclip.tbsaunde.org) (66.228.47.254) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 02 Jun 2015 11:07:11 +0000 Received: from tsaunders-iceball.corp.tor1.mozilla.com (unknown [23.233.68.71]) by paperclip.tbsaunde.org (Postfix) with ESMTPSA id B1750C072; Tue, 2 Jun 2015 11:07:08 +0000 (UTC) Date: Tue, 02 Jun 2015 11:08:00 -0000 From: Trevor Saunders To: Richard Biener Cc: David Malcolm , GCC Patches , Binutils Subject: Re: [PATCH 15/16] gcc: Use libgas and libld within the driver Message-ID: <20150602105849.GA15500@tsaunders-iceball.corp.tor1.mozilla.com> References: <1433192664-50156-1-git-send-email-dmalcolm@redhat.com> <1433192664-50156-16-git-send-email-dmalcolm@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: User-Agent: Mutt/1.5.23 (2014-03-12) X-SW-Source: 2015-06/txt/msg00181.txt.bz2 On Tue, Jun 02, 2015 at 10:31:53AM +0200, Richard Biener wrote: > On Mon, Jun 1, 2015 at 11:04 PM, David Malcolm 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 (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 (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 > >