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

Reply via email to