Re: [PATCH 02/12] genoutput: emit insn_data and operand_data compactly
Andrea Pinski <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcB-cmPFvROtQaqf6by_5xYfWDdBmAcmBB7t9e+nwZZ6ww@mail.gmail.com> |
On Thu, Aug 13, 2026 at 6:27 AM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > insn_data[] is 65% of insn-output.cc. Every one of its rows carried its > own HAVE_DESIGNATED_UNION_INITIALIZERS conditional, and both tables put > one field on each line. On aarch64 that is 85621 preprocessor lines > (1.48MB) and 1.04MB of indentation in a 11.37MB file. > > Give the output union constexpr constructors, one per member, and emit > one table row per line. The constructors pick the union member from the > argument's type, so genoutput just writes the value. A row > > /* .../aarch64-simd.md:9549 */ > { > "*aarch64_simd_ld1rv4bf", > #if HAVE_DESIGNATED_UNION_INITIALIZERS > { .single = > #else > { > #endif > "ld1r\t{%0.4h}, %1", > #if HAVE_DESIGNATED_UNION_INITIALIZERS > }, > #else > 0, 0 }, > #endif > { 0 }, > &operand_data[6252], > 2, > 2, > 0, > 1, > 1 > }, > > becomes > > /* .../aarch64-simd.md:9549 */ > { "*aarch64_simd_ld1rv4bf", "ld1r\t{%0.4h}, %1", { 0 }, \ > &operand_data[6252], 2, 2, 0, 1, 1 }, > > Designated initialisers for unions are a GNU extension in C++; they are > not standard before C++20. Constexpr constructors say the same thing in > C++14, which GCC has required of the host compiler since GCC 15, so > HAVE_DESIGNATED_UNION_INITIALIZERS goes away entirely. Hosts without the > extension no longer fall back to a three-pointer struct, which is a third > larger than the union. > > insn-output.cc shrinks from 11.37MB/670505 lines to 7.57MB/125441 lines > on aarch64, and by a similar fraction on riscv64 (39.12MB), x86_64 > (8.53MB), i686 (8.00MB) and avr (1.94MB). > Compile time is unchanged, which is expected: the file's cost is its 1685 output_* function > bodies, not its source text. Peak memory drops from 498MB to 461MB. > > insn-output.o keeps an identical .rodata and identical text, data and > bss sizes, and gains no dynamic initialiser, so the tables are still > built entirely at compile time. The preprocessed, whitespace-normalised > token streams of the two tables are also identical before and after on > all five targets above. > > Bootstrapped on aarch64-none-linux-gnu. > Ok for trunk? > > gcc/ChangeLog: > > * system.h (HAVE_DESIGNATED_UNION_INITIALIZERS): Remove. I suspect you want to poison HAVE_DESIGNATED_UNION_INITIALIZERS too. Just in case someone still has `#if HAVE_DESIGNATED_UNION_INITIALIZERS` somewhere. > * recog.h (insn_data_d::insn_output_u): New union, replacing the > anonymous one and its non-designated fallback. Add a constructor > per member. > * genoutput.cc (output_operand_data): Emit one row per line. > (output_insn_data): Likewise, and initialise the output member > directly rather than through a designated initialiser. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/genoutput.cc | 83 ++++++++++++++---------------------------------- > gcc/recog.h | 20 ++++++------ > gcc/system.h | 9 ------ > 3 files changed, 34 insertions(+), 78 deletions(-) > > diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc > index d2e2507f25e..115b9bbc21a 100644 > --- a/gcc/genoutput.cc > +++ b/gcc/genoutput.cc > @@ -253,29 +253,19 @@ output_operand_data (void) > > for (d = odata; d; d = d->next) > { > - struct pred_data *pred; > + struct pred_data *pred = NULL; > > - printf (" {\n"); > - > - printf (" %s,\n", > - d->predicate && d->predicate[0] ? d->predicate : "0"); > - > - printf (" \"%s\",\n", d->constraint ? d->constraint : ""); > - > - printf (" E_%smode,\n", GET_MODE_NAME (d->mode)); > - > - printf (" %d,\n", d->strict_low); > - > - printf (" %d,\n", d->constraint == NULL ? 1 : 0); > - > - printf (" %d,\n", d->eliminable); > - > - pred = NULL; > if (d->predicate) > pred = lookup_predicate (d->predicate); > - printf (" %d\n", pred && pred->codes[MEM]); > > - printf (" },\n"); > + printf (" { %s, \"%s\", E_%smode, %d, %d, %d, %d },\n", > + d->predicate && d->predicate[0] ? d->predicate : "0", > + d->constraint ? d->constraint : "", > + GET_MODE_NAME (d->mode), > + d->strict_low, > + d->constraint == NULL ? 1 : 0, > + d->eliminable, > + pred && pred->codes[MEM]); > } > printf ("};\n\n\n"); > } > @@ -303,11 +293,11 @@ output_insn_data (void) > for (d = idata; d; d = d->next) > { > printf (" /* %s:%d */\n", d->loc.filename, d->loc.lineno); > - printf (" {\n"); > + printf (" { "); > > if (d->name) > { > - printf (" \"%s\",\n", d->name); > + printf ("\"%s\", ", d->name); > name_offset = 0; > last_name = d->name; > next_name = 0; > @@ -326,32 +316,23 @@ output_insn_data (void) > name_offset++; > if (next_name && (last_name == 0 > || name_offset > next_name_offset / 2)) > - printf (" \"%s-%d\",\n", next_name, > + printf ("\"%s-%d\", ", next_name, > next_name_offset - name_offset); > else > - printf (" \"%s+%d\",\n", last_name, name_offset); > + printf ("\"%s+%d\", ", last_name, name_offset); > } > > switch (d->output_format) > { > case INSN_OUTPUT_FORMAT_NONE: > - printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); > - printf (" { 0 },\n"); > - printf ("#else\n"); > - printf (" { 0, 0, 0 },\n"); > - printf ("#endif\n"); > + printf ("{}, "); > break; > case INSN_OUTPUT_FORMAT_SINGLE: > { > const char *p = d->template_code; > char prev = 0; > > - printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); > - printf (" { .single =\n"); > - printf ("#else\n"); > - printf (" {\n"); > - printf ("#endif\n"); > - printf (" \""); > + printf ("\""); > while (*p) > { > if (IS_VSPACE (*p) && prev != '\\') > @@ -366,45 +347,27 @@ output_insn_data (void) > prev = *p; > ++p; > } > - printf ("\",\n"); > - printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); > - printf (" },\n"); > - printf ("#else\n"); > - printf (" 0, 0 },\n"); > - printf ("#endif\n"); > + printf ("\", "); > } > break; > case INSN_OUTPUT_FORMAT_MULTI: > - printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); > - printf (" { .multi = output_%d },\n", d->code_number); > - printf ("#else\n"); > - printf (" { 0, output_%d, 0 },\n", d->code_number); > - printf ("#endif\n"); > + printf ("output_%d, ", d->code_number); > break; > case INSN_OUTPUT_FORMAT_FUNCTION: > - printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); > - printf (" { .function = output_%d },\n", d->code_number); > - printf ("#else\n"); > - printf (" { 0, 0, output_%d },\n", d->code_number); > - printf ("#endif\n"); > + printf ("output_%d, ", d->code_number); > break; > default: > gcc_unreachable (); > } > > if (d->name && d->name[0] != '*') > - printf (" { (insn_gen_fn::stored_funcptr) gen_%s },\n", d->name); > + printf ("{ (insn_gen_fn::stored_funcptr) gen_%s }, ", d->name); > else > - printf (" { 0 },\n"); > - > - printf (" &operand_data[%d],\n", d->operand_number); > - printf (" %d,\n", d->n_generator_args); > - printf (" %d,\n", d->n_operands); > - printf (" %d,\n", d->n_dups); > - printf (" %d,\n", d->n_alternatives); > - printf (" %d\n", d->output_format); > + printf ("{ 0 }, "); > > - printf (" },\n"); > + printf ("&operand_data[%d], %d, %d, %d, %d, %d },\n", > + d->operand_number, d->n_generator_args, d->n_operands, > + d->n_dups, d->n_alternatives, d->output_format); > } > printf ("};\n\n\n"); > } > diff --git a/gcc/recog.h b/gcc/recog.h > index d7c816a6097..34c7d17d902 100644 > --- a/gcc/recog.h > +++ b/gcc/recog.h > @@ -526,19 +526,21 @@ struct insn_operand_data > struct insn_data_d > { > const char *const name; > -#if HAVE_DESIGNATED_UNION_INITIALIZERS > - union { > - const char *single; > - const char *const *multi; > - insn_output_fn function; > - } output; > -#else > - struct { > + > + /* How to print the insn. OUTPUT_FORMAT says which member is live. The > + constructors let genoutput write the member's value directly, and pick > + the member from its type. */ > + union insn_output_u > + { > const char *single; > const char *const *multi; > insn_output_fn function; > + > + constexpr insn_output_u () : single (nullptr) {} > + constexpr insn_output_u (const char *s) : single (s) {} > + constexpr insn_output_u (const char *const *m) : multi (m) {} > + constexpr insn_output_u (insn_output_fn f) : function (f) {} > } output; > -#endif > const insn_gen_fn genfun; > const struct insn_operand_data *const operand; > > diff --git a/gcc/system.h b/gcc/system.h > index 08fefd6f054..eacc8675a5f 100644 > --- a/gcc/system.h > +++ b/gcc/system.h > @@ -616,15 +616,6 @@ extern int vsnprintf (char *, size_t, const char *, va_list); > #endif > #endif > > -#if !defined(HAVE_DESIGNATED_UNION_INITIALIZERS) > -#ifdef __cplusplus > -#define HAVE_DESIGNATED_UNION_INITIALIZERS (GCC_VERSION >= 4007) > -#else > -#define HAVE_DESIGNATED_UNION_INITIALIZERS \ > - ((GCC_VERSION >= 2007) || (__STDC_VERSION__ >= 199901L)) > -#endif > -#endif > - > #if HAVE_SYS_STAT_H > # include <sys/stat.h> > #endif > -- > 2.50.1 (Apple Git-155) >