From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26471 invoked by alias); 2 Jun 2015 12:12:48 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 26440 invoked by uid 89); 2 Jun 2015 12:12:47 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.8 required=5.0 tests=AWL,BAYES_99,BAYES_999,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-oi0-f44.google.com Received: from mail-oi0-f44.google.com (HELO mail-oi0-f44.google.com) (209.85.218.44) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 02 Jun 2015 12:12:44 +0000 Received: by oiww2 with SMTP id w2so123797637oiw.0 for ; Tue, 02 Jun 2015 05:12:42 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.182.135.202 with SMTP id pu10mr22453622obb.52.1433247161912; Tue, 02 Jun 2015 05:12:41 -0700 (PDT) Received: by 10.76.115.167 with HTTP; Tue, 2 Jun 2015 05:12:41 -0700 (PDT) In-Reply-To: <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> <20150602105849.GA15500@tsaunders-iceball.corp.tor1.mozilla.com> Date: Tue, 02 Jun 2015 12:12:00 -0000 Message-ID: Subject: Re: [PATCH 15/16] gcc: Use libgas and libld within the driver From: Richard Biener To: Trevor Saunders Cc: David Malcolm , GCC Patches , Binutils Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-SW-Source: 2015-06/txt/msg00048.txt.bz2 On Tue, Jun 2, 2015 at 1:06 PM, Trevor Saunders wro= te: > On Tue, Jun 02, 2015 at 10:31:53AM +0200, Richard Biener wrote: >> On Mon, Jun 1, 2015 at 11:04 PM, David Malcolm wro= te: >> > 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 inclu= de >> > 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 com= piler >> 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. No idea. Eventually just hooking up to libopcodes and feeding simple stmts as binary blobs could work, keeping the textual interchange for the rest... Richard. > 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 c= all >> > into pex. >> > * timevar.c (timer::named_items::print): Add "name" param rath= er >> > 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 embed= ded >> > 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 lin= k. >> > * 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 =3D \ >> > >> > CFLAGS-gcc.o +=3D $(DRIVER_DEFINES) >> > >> > +# FIXME >> > +CFLAGS-gcc.o +=3D -I/home/david/coding/gcc-python/binutils-gdb-librar= ies/install/include >> > + >> > specs.h : s-specs ; @true >> > s-specs : Makefile >> > lsf=3D"$(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=3D >> > AC_SEARCH_LIBS(kstat_open, kstat) >> > EXTRA_GCC_LIBS=3D"$LIBS" >> > LIBS=3D"$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+=3D" -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+=3D" -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 *ppre= fix, 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 =3D impl_push; >> > + this->pop =3D 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_ =3D 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_ =3D 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 =3D 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 =3D 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 =3D 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 =3D 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 invocatio= n, >> > + and potentially for running the command in-process. */ >> > + >> > +static enum known_command >> > +get_known_command (int n_commands, const char *argv0) >> > +{ >> > + if (n_commands =3D=3D 1) >> > + { >> > + if (0 =3D=3D strcmp (argv0, "as")) >> > + return KNOWN_COMMAND_AS; >> > + else if (0 =3D=3D strcmp (argv0, "collect2")) >> > + return KNOWN_COMMAND_COLLECT2; >> > + else if (0 =3D=3D 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] =3D { >> > + 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, avoid= ing >> > + 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 =3D argbuf.length (); >> > + const char **argv =3D argbuf.address (); >> > +#endif >> > + >> > + switch (known_command) >> > + { >> > + case KNOWN_COMMAND_AS: >> > +#ifdef HAVE_LIBGAS >> > + *result_out =3D 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 =3D 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, "|") =3D=3D 0) >> > n_commands++; >> > >> > + /* Determine if we're dealing with a single embeddable command. */ >> > + enum known_command known_command =3D 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 =3D TV_DRIVER_EXECUTE_OTHER; >> > gcc_assert (g_driver); >> > timer *driver_timer =3D g_driver->get_timer (); >> > - if (driver_timer && n_commands =3D=3D 1) >> > - { >> > - if (0 =3D=3D strcmp (argbuf[0], "as")) >> > - tv_id =3D TV_DRIVER_EXECUTE_AS; >> > - else if (0 =3D=3D strcmp (argbuf[0], "collect2")) >> > - tv_id =3D TV_DRIVER_EXECUTE_COLLECT2; >> > - else if (0 =3D=3D strcmp (argbuf[0], "ld")) >> > - tv_id =3D TV_DRIVER_EXECUTE_LD; >> > - } >> > + timevar_id_t tv_id =3D 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=3D$(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 em= bedded >> > . . 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-p= rocess invocation of "ld" >> > . . driver::finalize () >> > . . <---- >> > . . =E2=94=82 . . >> > 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 *tot= al); >> > >> > 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 =3D 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 =3D name__; >> > @@ -298,7 +303,8 @@ timer::~timer () >> > free (iter); >> > } >> > >> > - delete m_jit_client_items; >> > + for (int i =3D 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 =3D new named_items (this); >> > + named_items **item_dict =3D &m_named_items[dict]; >> > + if (!*item_dict) >> > + *item_dict =3D new named_items (this); >> > + (*item_dict)->push (item_name); >> > >> > - m_jit_client_items->push (item_name); >> > + m_has_named_items =3D 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 =3D m_named_items[dict]; >> > + >> > + /* If this fails, we have a pop from something that was never pushe= d 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 =3D 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 =3D 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: s= etup") >> > 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 >> >