https://gcc.gnu.org/g:d0b42b0016cdbe3e0ca86be8a888b305c96a8df0

commit r17-4033-gd0b42b0016cdbe3e0ca86be8a888b305c96a8df0
Author: Kyrylo Tkachov <[email protected]>
Date:   Fri Aug 7 10:27:51 2026 +0200

    genoutput: emit insn_data and operand_data compactly
    
    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++, and 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.  Poison the macro rather than only deleting it, so
    that anything left testing it fails to build instead of silently taking the
    absent branch.
    
    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 a byte-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 and poison.
            * 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]>

Diff:
---
 gcc/genoutput.cc | 83 ++++++++++++++++----------------------------------------
 gcc/recog.h      | 20 ++++++++------
 gcc/system.h     | 12 ++------
 3 files changed, 36 insertions(+), 79 deletions(-)

diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index d2e2507f25e7..115b9bbc21ab 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 d7c816a6097d..34c7d17d9020 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 08fefd6f0549..9a4a99a0528f 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
@@ -1126,7 +1117,8 @@ extern void fancy_abort (const char *, int, const char *)
    LIBGCC2_FLOAT_WORDS_BIG_ENDIAN
 
 /* Miscellaneous macros that are no longer used.  */
- #pragma GCC poison USE_MAPPED_LOCATION GET_ENVIRONMENT
+ #pragma GCC poison USE_MAPPED_LOCATION GET_ENVIRONMENT \
+  HAVE_DESIGNATED_UNION_INITIALIZERS
 
 /* Libiberty macros that are no longer used in GCC.  */
 #undef ANSI_PROTOTYPES

Reply via email to