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)
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.