Ping.
Thanks,
Kyrill
> On 23 Jul 2026, at 15:20, Kyrylo Tkachov <[email protected]> wrote:
>
> From: Kyrylo Tkachov <[email protected]>
>
> insn-attrtab.cc contains many independent get_attr_* functions. Several have
> large switches over every instruction code, making the single source one of
> the slowest objects in each bootstrap stage.
>
> Let genattrtab write multiple attribute outputs, following genemit and
> genrecog. Reuse --with-insnemit-partitions and make -A repeatable. Record
> and
> validate every output name before opening files, rejecting duplicates and
> resolvable aliases across -A, -D, and -L. Place each attribute function in
> the shortest output, along with the fixed delay and length functions. Keep
> DFA and latency
> functions in their existing single files.
>
> The functions refer to one another through insn-attr.h and
> insn-attr-common.h, so generated headers do not change. With one -A option
> all
> three outputs are byte-identical to the previous generator. Close diagnostics
> retain the affected filename.
>
> With the default AArch64 partition count, the largest attribute part is about
> 85% smaller and compiles about 67% faster than the original source.
>
> Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-linux.
> Ok for trunk?
> Thanks,
> Kyrill
>
> gcc/ChangeLog:
>
> * Makefile.in (INSNATTRTAB_SPLITS_SEQ, INSNATTRTAB_SEQ_SRC)
> (INSNATTRTAB_SEQ_TMP, INSNATTRTAB_SEQ_O): New variables.
> (OBJS): Replace insn-attrtab.o with $(INSNATTRTAB_SEQ_O).
> (MOSTLYCLEANFILES): Add $(INSNATTRTAB_SEQ_SRC), retaining the legacy
> unnumbered source for cleanup.
> (.PRECIOUS): Use $(INSNATTRTAB_SEQ_SRC).
> (s-attrtab): Generate and move numbered attribute files. Stop when a
> move fails.
> * configure.ac (--with-insnemit-partitions): Document all generators
> which use the option.
> * configure: Regenerate.
> * genattrtab.cc (attr_file_name, attr_file): Remove.
> (attr_files, attr_file_names): New variables.
> (dfa_file_name, latency_file_name): Retain output names.
> (choose_attr_output, check_output_name): New functions.
> (make_automaton_attrs): Write to the first attribute file.
> (handle_arg): Record and validate repeatable output names.
> (main): Open outputs after complete validation. Distribute attribute,
> delay, and length functions. Diagnose close failures.
> * final.cc (length_unit_log): Update comment for partitioned output.
> * config/arc/arc-protos.h (regno_clobbered_p): Likewise.
> * config/ia64/ia64.cc (bundling): Likewise.
> * config/ia64/t-ia64 (insn-attrtab.o-warn): Replace with per-partition
> warning variables.
> * config/sh/sh.h (code_for_indirect_jump_scratch): Update comment for
> partitioned output.
>
> contrib/ChangeLog:
>
> * filter-clang-warnings.py (skip_warning): Match numbered attribute
> files.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
> contrib/filter-clang-warnings.py | 2 +-
> gcc/Makefile.in | 32 +++++++---
> gcc/config/arc/arc-protos.h | 3 +-
> gcc/config/ia64/ia64.cc | 4 +-
> gcc/config/ia64/t-ia64 | 3 +-
> gcc/config/sh/sh.h | 5 +-
> gcc/configure | 11 ++--
> gcc/configure.ac | 7 ++-
> gcc/final.cc | 2 +-
> gcc/genattrtab.cc | 105 ++++++++++++++++++++++---------
> 10 files changed, 121 insertions(+), 53 deletions(-)
>
> diff --git a/contrib/filter-clang-warnings.py
> b/contrib/filter-clang-warnings.py
> index 8eec366b4bc..6b01b559b6e 100755
> --- a/contrib/filter-clang-warnings.py
> +++ b/contrib/filter-clang-warnings.py
> @@ -56,7 +56,7 @@ def skip_warning(filename, message):
> 'ipa-strub.cc': ['-Wunused-but-set-variable'],
> 'insn-modes.cc': ['-Wshift-count-overflow'],
> 'insn-emit.cc': ['-Wtautological-compare'],
> - 'insn-attrtab.cc': ['-Wparentheses-equality'],
> + 'insn-attrtab': ['-Wparentheses-equality'],
> 'omp-builtins.def': ['-Wc++11-narrowing'],
> 'wide-int.h': ['-Wnontrivial-memcall'],
> 'i386.md': ['-Wparentheses-equality', '-Wtautological-compare',
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 42c8e8f9062..fd20812703b 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -247,6 +247,14 @@ INSNOPINIT_SEQ_SRC = $(patsubst %, insn-opinit-%.cc,
> $(INSNOPINIT_SPLITS_SEQ))
> INSNOPINIT_SEQ_TMP = $(patsubst %, tmp-opinit-%.cc, $(INSNOPINIT_SPLITS_SEQ))
> INSNOPINIT_SEQ_O = $(patsubst %, insn-opinit-%.o, $(INSNOPINIT_SPLITS_SEQ))
>
> +# Re-use the split number for insn-attrtab as well.
> +INSNATTRTAB_SPLITS_SEQ = $(INSNEMIT_SPLITS_SEQ)
> +INSNATTRTAB_SEQ_SRC = $(patsubst %, insn-attrtab-%.cc, \
> + $(INSNATTRTAB_SPLITS_SEQ))
> +INSNATTRTAB_SEQ_TMP = $(patsubst %, tmp-attrtab-%.cc, \
> + $(INSNATTRTAB_SPLITS_SEQ))
> +INSNATTRTAB_SEQ_O = $(patsubst %, insn-attrtab-%.o,
> $(INSNATTRTAB_SPLITS_SEQ))
> +
> # These files are to have specific diagnostics suppressed, or are not to
> # be subject to -Werror:
> # flex output may yield harmless "no previous prototype" warnings
> @@ -1409,7 +1417,7 @@ OBJS = \
> $(GIMPLE_MATCH_PD_SEQ_O) \
> gimple-match-exports.o \
> $(GENERIC_MATCH_PD_SEQ_O) \
> - insn-attrtab.o \
> + $(INSNATTRTAB_SEQ_O) \
> insn-automata.o \
> insn-dfatab.o \
> $(INSNEMIT_SEQ_O) \
> @@ -1990,9 +1998,9 @@
> FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)
> MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
> insn-output.cc $(INSNRECOG_SEQ_SRC) insn-recog.h \
> $(INSNEMIT_SEQ_SRC) insn-extract.cc insn-peep.cc \
> - insn-attr.h insn-attr-common.h insn-attrtab.cc insn-dfatab.cc \
> - insn-latencytab.cc $(INSNOPINIT_SEQ_SRC) insn-opinit.cc insn-opinit.h \
> - insn-preds.cc \
> + insn-attr.h insn-attr-common.h $(INSNATTRTAB_SEQ_SRC) insn-attrtab.cc \
> + insn-dfatab.cc insn-latencytab.cc $(INSNOPINIT_SEQ_SRC) insn-opinit.cc \
> + insn-opinit.h insn-preds.cc \
> insn-constants.h \
> tm-preds.h tm-constrs.h checksum-options $(GIMPLE_MATCH_PD_SEQ_SRC) \
> $(GENERIC_MATCH_PD_SEQ_SRC) gimple-match-auto.h generic-match-auto.h \
> @@ -2768,7 +2776,7 @@ $(common_out_object_file): $(common_out_file)
> .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \
> $(INSNEMIT_SEQ_SRC) insn-recog.h $(INSNRECOG_SEQ_SRC) \
> insn-extract.cc insn-output.cc \
> - insn-peep.cc insn-attr.h insn-attr-common.h insn-attrtab.cc \
> + insn-peep.cc insn-attr.h insn-attr-common.h $(INSNATTRTAB_SEQ_SRC) \
> insn-dfatab.cc insn-latencytab.cc insn-preds.cc \
> $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \
> gimple-match-auto.h generic-match-auto.h insn-target-def.h
> @@ -2855,13 +2863,19 @@ s-check : build/gencheck$(build_exeext)
> $(SHELL) $(srcdir)/../move-if-change tmp-check.h tree-check.h
> $(STAMP) s-check
>
> -# genattrtab produces three files: tmp-{attrtab.cc,dfatab.cc,latencytab.cc}
> -insn-attrtab.cc insn-dfatab.cc insn-latencytab.cc: s-attrtab ; @true
> +# genattrtab splits the attribute functions like genemit and additionally
> +# produces tmp-dfatab.cc and tmp-latencytab.cc.
> +$(INSNATTRTAB_SEQ_SRC): s-attrtab ; @true
> +insn-dfatab.cc insn-latencytab.cc: s-attrtab ; @true
> s-attrtab : $(MD_DEPS) build/genattrtab$(build_exeext) \
> insn-conditions.md
> $(RUN_GEN) build/genattrtab$(build_exeext) $(md_file) insn-conditions.md \
> - -Atmp-attrtab.cc -Dtmp-dfatab.cc -Ltmp-latencytab.cc
> - $(SHELL) $(srcdir)/../move-if-change tmp-attrtab.cc insn-attrtab.cc
> + $(addprefix -A,${INSNATTRTAB_SEQ_TMP}) \
> + -Dtmp-dfatab.cc -Ltmp-latencytab.cc
> + for id in $(INSNATTRTAB_SPLITS_SEQ); do \
> + $(SHELL) $(srcdir)/../move-if-change tmp-attrtab-$$id.cc \
> + insn-attrtab-$$id.cc || exit 1; \
> + done
> $(SHELL) $(srcdir)/../move-if-change tmp-dfatab.cc insn-dfatab.cc
> $(SHELL) $(srcdir)/../move-if-change tmp-latencytab.cc insn-latencytab.cc
> $(STAMP) s-attrtab
> diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h
> index fc36d52ead0..380f2c39777 100644
> --- a/gcc/config/arc/arc-protos.h
> +++ b/gcc/config/arc/arc-protos.h
> @@ -93,7 +93,8 @@ extern bool arc_text_label (rtx_insn *insn);
> extern bool arc_short_comparison_p (rtx, int);
> extern bool arc_epilogue_uses (int regno);
> extern bool arc_eh_uses (int regno);
> -/* insn-attrtab.cc doesn't include reload.h, which declares
> regno_clobbered_p. */
> +/* Generated attribute code does not include reload.h, which declares
> + regno_clobbered_p. */
> extern int regno_clobbered_p (unsigned int, rtx_insn *, machine_mode, int);
> extern bool arc_legitimize_reload_address (rtx *, machine_mode, int, int);
> extern void arc_secondary_reload_conv (rtx, rtx, rtx, bool);
> diff --git a/gcc/config/ia64/ia64.cc b/gcc/config/ia64/ia64.cc
> index b06158ba7bc..292c6b3d939 100644
> --- a/gcc/config/ia64/ia64.cc
> +++ b/gcc/config/ia64/ia64.cc
> @@ -9286,8 +9286,8 @@ bundling (FILE *dump, int verbose, rtx_insn
> *prev_head_insn, rtx_insn *tail)
> curr_state = curr_state->next)
> if (verbose >= 2 && dump)
> {
> - /* This structure is taken from generated code of the
> - pipeline hazard recognizer (see file insn-attrtab.cc).
> + /* This structure is taken from the generated pipeline hazard
> + recognizer code.
> Please don't forget to change the structure if a new
> automaton is added to .md file. */
> struct DFA_chip
> diff --git a/gcc/config/ia64/t-ia64 b/gcc/config/ia64/t-ia64
> index 4c37dd89fba..2bf590d89df 100644
> --- a/gcc/config/ia64/t-ia64
> +++ b/gcc/config/ia64/t-ia64
> @@ -22,7 +22,8 @@ ia64-c.o: $(srcdir)/config/ia64/ia64-c.cc $(CONFIG_H)
> $(SYSTEM_H) \
> $(srcdir)/config/ia64/ia64-c.cc
>
> # genattrtab generates very long string literals.
> -insn-attrtab.o-warn = -Wno-error
> +$(foreach id, $(INSNATTRTAB_SPLITS_SEQ), \
> + $(eval insn-attrtab-$(id).o-warn = -Wno-error))
>
> ia64.o: $(srcdir)/config/ia64/ia64.cc debug.h $(PARAMS_H) sel-sched.h
> reload.h \
> $(OPTS_H) dumpfile.h $(HASH_TABLE_H)
> diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
> index 9b2ed6a33db..f3973e7fcab 100644
> --- a/gcc/config/sh/sh.h
> +++ b/gcc/config/sh/sh.h
> @@ -24,8 +24,9 @@ along with GCC; see the file COPYING3. If not see
>
> #include "config/vxworks-dummy.h"
>
> -/* Unfortunately, insn-attrtab.cc doesn't include insn-codes.h. We can't
> - include it here, because bconfig.h is also included by gencodes.cc . */
> +/* Unfortunately, generated attribute code does not include insn-codes.h.
> + We can't include it here, because bconfig.h is also included by
> + gencodes.cc . */
> /* ??? No longer true. */
> extern int code_for_indirect_jump_scratch;
>
> diff --git a/gcc/configure b/gcc/configure
> index b1f31b61725..846426e5908 100755
> --- a/gcc/configure
> +++ b/gcc/configure
> @@ -1882,8 +1882,8 @@ Optional Packages:
> Set the number of partitions to make for gimple and
> generic when splitting match.pd. [default=10]
> --with-insnemit-partitions=num
> - Set the number of insn-emit, insn-recog and
> - insn-opinit partitions to generate. [default=10]
> + Set the number of partitions used by genemit,
> + genrecog, genopinit and genattrtab. [default=10]
> --with-dwarf2 force the default debug format to be DWARF 2 (or
> later)
> --with-specs=SPECS add SPECS to driver command-line processing
> @@ -7907,7 +7907,8 @@ fi
>
>
>
> -# Specify the number of output files used by the insn generators.
> +# Specify the number of output partitions used by the machine-description
> +# generators.
>
> # Check whether --with-insnemit-partitions was given.
> if test "${with_insnemit_partitions+set}" = set; then :
> @@ -21921,7 +21922,7 @@ else
> lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> lt_status=$lt_dlunknown
> cat > conftest.$ac_ext <<_LT_EOF
> -#line 21924 "configure"
> +#line 21925 "configure"
> #include "confdefs.h"
>
> #if HAVE_DLFCN_H
> @@ -22027,7 +22028,7 @@ else
> lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
> lt_status=$lt_dlunknown
> cat > conftest.$ac_ext <<_LT_EOF
> -#line 22030 "configure"
> +#line 22031 "configure"
> #include "confdefs.h"
>
> #if HAVE_DLFCN_H
> diff --git a/gcc/configure.ac b/gcc/configure.ac
> index 9e767a7fc5f..e332c6382ab 100644
> --- a/gcc/configure.ac
> +++ b/gcc/configure.ac
> @@ -902,11 +902,12 @@ fi
>
> AC_SUBST(DEFAULT_MATCHPD_PARTITIONS)
>
> -# Specify the number of output files used by the insn generators.
> +# Specify the number of output partitions used by the machine-description
> +# generators.
> AC_ARG_WITH(insnemit-partitions,
> [AS_HELP_STRING([--with-insnemit-partitions=num],
> -[Set the number of insn-emit, insn-recog and insn-opinit partitions to
> -generate. [default=10]])],
> +[Set the number of partitions used by genemit, genrecog, genopinit and
> +genattrtab. [default=10]])],
> [DEFAULT_INSNEMIT_PARTITIONS="$with_insnemit_partitions"],
> [DEFAULT_INSNEMIT_PARTITIONS=10])
> if (test $DEFAULT_INSNEMIT_PARTITIONS -lt 1); then
> AC_MSG_ERROR(m4_normalize([
> diff --git a/gcc/final.cc b/gcc/final.cc
> index 0152be59fc8..e2761d056ea 100644
> --- a/gcc/final.cc
> +++ b/gcc/final.cc
> @@ -142,7 +142,7 @@ static int override_discriminator;
> /* Whether to force emission of a line note before the next insn. */
> static bool force_source_line = false;
>
> -extern const int length_unit_log; /* This is defined in insn-attrtab.cc. */
> +extern const int length_unit_log; /* Defined in generated attribute code. */
>
> /* Nonzero while outputting an `asm' with operands.
> This means that inconsistencies are the user's fault, so don't die.
> diff --git a/gcc/genattrtab.cc b/gcc/genattrtab.cc
> index a2cf08d5305..3e22e828488 100644
> --- a/gcc/genattrtab.cc
> +++ b/gcc/genattrtab.cc
> @@ -305,16 +305,41 @@ static rtx min_fn (rtx);
> functions and tables. This made insn-attrtab.cc _the_ bottle-neck in
> a parallel build, and even made it impossible to build GCC on machines
> with relatively small RAM space (PR other/29442). Therefore, the
> - attribute functions/tables are now written out to three separate
> - files: all "*insn_default_latency" functions go to LATENCY_FILE_NAME,
> - all "*internal_dfa_insn_code" functions go to DFA_FILE_NAME, and the
> - rest goes to ATTR_FILE_NAME. */
> + attribute functions/tables are now written out to separate files: all
> + "*insn_default_latency" functions go to LATENCY_FILE, all
> + "*internal_dfa_insn_code" functions go to DFA_FILE, and the rest is
> + distributed across ATTR_FILES the way genemit and genrecog distribute
> + their output. */
>
> -static const char *attr_file_name = NULL;
> -static const char *dfa_file_name = NULL;
> -static const char *latency_file_name = NULL;
> +/* The files to distribute the attribute functions across. */
> +static auto_vec<FILE *, 10> attr_files;
> +static auto_vec<const char *, 10> attr_file_names;
>
> -static FILE *attr_file, *dfa_file, *latency_file;
> +static FILE *dfa_file, *latency_file;
> +static const char *dfa_file_name, *latency_file_name;
> +
> +/* Return the shortest attribute output file. */
> +
> +static FILE *
> +choose_attr_output ()
> +{
> + unsigned file_idx;
> + return choose_output (attr_files, file_idx);
> +}
> +
> +/* Reject NAME if another output already uses it. */
> +
> +static void
> +check_output_name (const char *name)
> +{
> + for (const char *attr_name : attr_file_names)
> + if (canonical_filename_eq (name, attr_name))
> + fatal ("output file %s specified more than once", name);
> + if ((dfa_file_name && canonical_filename_eq (name, dfa_file_name))
> + || (latency_file_name
> + && canonical_filename_eq (name, latency_file_name)))
> + fatal ("output file %s specified more than once", name);
> +}
>
> /* Hash table for sharing RTL and strings. */
>
> @@ -4981,6 +5006,9 @@ make_automaton_attrs (void)
> tune_attr = find_tune_attr (all_insn_reservs->condexp);
> if (tune_attr != NULL)
> {
> + /* The function pointers and init_sched_attrs go to the first
> + attribute file. */
> + FILE *attr_file = attr_files[0];
> rtx *condexps = XNEWVEC (rtx, n_insn_reservs * 3);
> struct attr_value *val;
> bool first = true;
> @@ -5223,12 +5251,19 @@ handle_arg (const char *arg)
> switch (arg[1])
> {
> case 'A':
> - attr_file_name = &arg[2];
> + check_output_name (&arg[2]);
> + attr_file_names.safe_push (&arg[2]);
> return true;
> case 'D':
> + if (dfa_file_name)
> + fatal ("option -D specified more than once");
> + check_output_name (&arg[2]);
> dfa_file_name = &arg[2];
> return true;
> case 'L':
> + if (latency_file_name)
> + fatal ("option -L specified more than once");
> + check_output_name (&arg[2]);
> latency_file_name = &arg[2];
> return true;
> default:
> @@ -5248,7 +5283,15 @@ main (int argc, const char **argv)
> if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
> return FATAL_EXIT_CODE;
>
> - attr_file = open_outfile (attr_file_name);
> + if (attr_file_names.is_empty ())
> + fatal ("no -A output file specified");
> + if (!dfa_file_name)
> + fatal ("no -D output file specified");
> + if (!latency_file_name)
> + fatal ("no -L output file specified");
> +
> + for (const char *name : attr_file_names)
> + attr_files.safe_push (open_outfile (name));
> dfa_file = open_outfile (dfa_file_name);
> latency_file = open_outfile (latency_file_name);
>
> @@ -5363,50 +5406,56 @@ main (int argc, const char **argv)
> /* Perform any possible optimizations to speed up compilation. */
> optimize_attrs (num_insn_codes);
>
> - /* Now write out all the `gen_attr_...' routines. Do these before the
> - special routines so that they get defined before they are used. */
> + /* Now write out all the `get_attr_...' routines. The DFA and latency
> + routines go to their own files; the rest are distributed across the
> + attribute files. They only refer to each other through the extern
> + declarations in insn-attr.h and insn-attr-common.h. */
>
> for (i = 0; i < MAX_ATTRS_INDEX; i++)
> for (attr = attrs[i]; attr; attr = attr->next)
> {
> - FILE *outf;
> + FILE *outf;
> +
> + if (attr->is_special || attr->is_const)
> + continue;
>
> - if (startswith(attr->name, "*internal_dfa_insn_code"))
> + if (startswith (attr->name, "*internal_dfa_insn_code"))
> outf = dfa_file;
> else if (startswith (attr->name, "*insn_default_latency"))
> outf = latency_file;
> else
> - outf = attr_file;
> + outf = choose_attr_output ();
>
> - if (! attr->is_special && ! attr->is_const)
> - write_attr_get (outf, attr);
> + write_attr_get (outf, attr);
> }
>
> /* Write out delay eligibility information, if DEFINE_DELAY present.
> (The function to compute the number of delay slots will be written
> below.) */
> - write_eligible_delay (attr_file, "delay");
> + write_eligible_delay (choose_attr_output (), "delay");
> if (have_annul_true)
> - write_eligible_delay (attr_file, "annul_true");
> + write_eligible_delay (choose_attr_output (), "annul_true");
> else
> - write_dummy_eligible_delay (attr_file, "annul_true");
> + write_dummy_eligible_delay (choose_attr_output (), "annul_true");
> if (have_annul_false)
> - write_eligible_delay (attr_file, "annul_false");
> + write_eligible_delay (choose_attr_output (), "annul_false");
> else
> - write_dummy_eligible_delay (attr_file, "annul_false");
> + write_dummy_eligible_delay (choose_attr_output (), "annul_false");
>
> /* Write out constant delay slot info. */
> - write_const_num_delay_slots (attr_file);
> + write_const_num_delay_slots (choose_attr_output ());
>
> - write_length_unit_log (attr_file);
> + write_length_unit_log (choose_attr_output ());
>
> - if (fclose (attr_file) != 0)
> - fatal ("cannot close file %s: %s", attr_file_name, xstrerror (errno));
> + for (unsigned int i = 0; i < attr_files.length (); ++i)
> + if (fclose (attr_files[i]) != 0)
> + fatal ("cannot close file %s: %s", attr_file_names[i],
> + xstrerror (errno));
> if (fclose (dfa_file) != 0)
> fatal ("cannot close file %s: %s", dfa_file_name, xstrerror (errno));
> if (fclose (latency_file) != 0)
> - fatal ("cannot close file %s: %s", latency_file_name, xstrerror (errno));
> + fatal ("cannot close file %s: %s", latency_file_name,
> + xstrerror (errno));
>
> return SUCCESS_EXIT_CODE;
> }
> -
> --
> 2.50.1 (Apple Git-155)
>