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)
>

Reply via email to