<[email protected]> writes:
> From: Kyrylo Tkachov <[email protected]>
>
> Let genattrtab write multiple attribute outputs, following genemit and
> genrecog. Reuse --with-insnemit-partitions and make -A repeatable. Register
> the -A, -D, and -L outputs through the common gensupport machinery. This
> gives
> all output roles one validation, open, selection, and close lifecycle. Also
> distribute the fixed delay and length functions. Keep DFA and latency
> functions in their existing single files.
>
> choose_output places each function in the shortest partition so far, which
> only balances well if the large functions are placed early. Attribute
> functions differ in size by two orders of magnitude, so an arbitrary order
> lets a late large function land on an already full partition. Sort the
> functions by the amount of text write_attr_get will produce, largest first.
> For a derived attribute that amount is the length of its lookup table, and
> otherwise the number of case labels that survive find_most_used.
>
> 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
> the delay and latency outputs are byte-identical to the previous generator.
> The attribute output holds the same lines at the same total size, reordered,
> because the sort applies at any partition count.
>
> On AArch64 with eight partitions the sorted order reduces the spread between
> the largest and smallest partition from 5.9x to 2.3x. The largest partition
> is then within 0.1% of the size that no assignment can beat, since one
> attribute function alone accounts for that much of the total. The largest
> attribute part is about 83% smaller than the original single source, and the
> slowest attribute object compiles about 76% faster. Native AArch64 and
> RISC-V cross all-gcc builds pass.
>
> Bootstrapped on aarch64-none-linux-gnu. Ok for trunk?
>
> 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.
> (output_files): New variable.
> (dfa_file_name, latency_file_name): Retain output names.
> (make_automaton_attrs): Write to the first attribute partition.
> (handle_arg): Register repeatable attribute outputs.
> (attr_output_size, cmp_attr_output_size): New functions.
> (main): Register fixed outputs and use the common output helpers.
> Distribute attribute, delay, and length functions, largest first.
> * 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]>
> [...]
> @@ -5500,9 +5527,22 @@ 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);
> - dfa_file = open_outfile (dfa_file_name);
> - latency_file = open_outfile (latency_file_name);
> + if (output_files.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");
> +
I think it'd be worth adding a note here to say that the DFA and latency
files must be added after the attribute files (for make_automaton_attrs,
although the comment doesn't need to say that).
OK with that change, thanks.
Richard
> + unsigned int dfa_index
> + = add_generator_output (output_files, dfa_file_name, false);
> + unsigned int latency_index
> + = add_generator_output (output_files, latency_file_name, false);
> + open_generator_outputs (output_files);
> + dfa_file = output_files[dfa_index].file;
> + latency_file = output_files[latency_index].file;
> + for (generator_output &output : output_files)
> + write_header (output.file);
>
> obstack_init (hash_obstack);
> obstack_init (temp_obstack);
> @@ -5619,50 +5659,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. */
>
> + auto_vec<class attr_desc *> to_write;
> for (i = 0; i < MAX_ATTRS_INDEX; i++)
> for (attr = attrs[i]; attr; attr = attr->next)
> - {
> - FILE *outf;
> + if (!attr->is_special && !attr->is_const)
> + to_write.safe_push (attr);
>
> - 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;
> + /* Give choose_output the largest functions first. It assigns each one to
> + the shortest output so far, and feeding it an arbitrary order lets a
> + late large function land on an already full partition. Attribute
> + functions differ in size by two orders of magnitude, so that happens
> + easily. */
> + to_write.qsort (cmp_attr_output_size);
>
> - if (! attr->is_special && ! attr->is_const)
> - write_attr_get (outf, attr);
> - }
> + for (class attr_desc *a : to_write)
> + {
> + FILE *outf;
> +
> + if (startswith (a->name, "*internal_dfa_insn_code"))
> + outf = dfa_file;
> + else if (startswith (a->name, "*insn_default_latency"))
> + outf = latency_file;
> + else
> + outf = choose_output (output_files);
> +
> + write_attr_get (outf, a);
> + }
>
> /* 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_output (output_files), "delay");
> if (have_annul_true)
> - write_eligible_delay (attr_file, "annul_true");
> + write_eligible_delay (choose_output (output_files), "annul_true");
> else
> - write_dummy_eligible_delay (attr_file, "annul_true");
> + write_dummy_eligible_delay (choose_output (output_files), "annul_true");
> if (have_annul_false)
> - write_eligible_delay (attr_file, "annul_false");
> + write_eligible_delay (choose_output (output_files), "annul_false");
> else
> - write_dummy_eligible_delay (attr_file, "annul_false");
> + write_dummy_eligible_delay (choose_output (output_files), "annul_false");
>
> /* Write out constant delay slot info. */
> - write_const_num_delay_slots (attr_file);
> -
> - write_length_unit_log (attr_file);
> + write_const_num_delay_slots (choose_output (output_files));
>
> - if (fclose (attr_file) != 0)
> - fatal ("cannot close file %s: %s", attr_file_name, 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));
> + write_length_unit_log (choose_output (output_files));
>
> - return SUCCESS_EXIT_CODE;
> + return (close_generator_outputs (output_files)
> + ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
> }
> -