Re: [PATCH 02/12] genoutput: emit insn_data and operand_data compactly
Andrea Pinski <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcD8wK+v4ZGycOQ2jazj86Aue0dxiPVnRjG90+i8JTo=VA@mail.gmail.com> |
On Wed, Aug 19, 2026 at 2:21 AM Kyrylo Tkachov <[email protected]> wrote: > > > > > On 13 Aug 2026, at 20:33, Andrea Pinski <[email protected]> wrote: > > > > 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. > > Thanks, done so in the attached respin. Ok but give some folks a week to reply if they have any other comments on it. > Kyrill > > > > >> * 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) > >> >