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.
        * 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