https://gcc.gnu.org/g:de7711bf18144e6cdae5f78b94d385472f38f51d
commit r17-4261-gde7711bf18144e6cdae5f78b94d385472f38f51d Author: Kyrylo Tkachov <[email protected]> Date: Tue Aug 4 21:25:49 2026 +0200 gensupport: Centralize machine-generator output management genemit and genrecog use the same size-based output selection, but each generator owns its file names, opens files during option parsing, and closes them separately. Adding more partitioned generators would copy this logic. Put the common output record and lifecycle helpers in gensupport. The helpers validate names, delay file opening until option parsing is complete, select only partition outputs by current size, and close every output with a useful diagnostic. Fixed outputs, such as headers, use the same record but do not participate in selection. Convert genemit and genrecog to the common interface. Also remove the unused output index and disabled round-robin code from choose_output, and remove a genrecog selection whose result is discarded. Diagnose missing or repeated genrecog -H options, remove its fixed header-name limit, and stop printing parsed output options to standard output. Robin Dapp added the shared choose_output helper for PR111600, following the size-based policy that Tamar Christina used in genmatch. The AArch64 all-gcc build and self-tests pass. The 20 normal emit and recog partition files come out unchanged, and so do the one-output files. Duplicate name, cross-role alias, missing option, open failure, and close failure tests pass. Bootstrapped on aarch64-none-linux-gnu. gcc/ChangeLog: * gensupport.h (generator_output): New structure. (add_generator_output, open_generator_outputs): Declare. (close_generator_outputs): Likewise. (choose_output): Accept generator_output records. Remove the output index parameter. * gensupport.cc (add_generator_output): New function. (open_generator_outputs, close_generator_outputs): Likewise. (choose_output): Select only partition records. Remove the output index and disabled round-robin implementation. (SIZED_BASED_CHUNKS): Remove. * genemit.cc (output_files): Use generator_output records. (handle_arg): Register output names. (main): Use the common open, selection, and close helpers. * genrecog.cc (print_subroutine_group): Accept generator_output records. (header_name): Change to a pointer. (header): Remove global variable. (output_files): Use generator_output records. (handle_arg): Register output names and validate -H. (main): Validate and register the header output. Use the common open, selection, and close helpers. Remove an unused output selection. Suggested-by: Tamar Christina <[email protected]> Signed-off-by: Kyrylo Tkachov <[email protected]> Diff: --- gcc/genemit.cc | 27 ++++++++----------- gcc/genrecog.cc | 64 +++++++++++++++++++-------------------------- gcc/gensupport.cc | 78 +++++++++++++++++++++++++++++++++++++++++-------------- gcc/gensupport.h | 16 +++++++++++- 4 files changed, 111 insertions(+), 74 deletions(-) diff --git a/gcc/genemit.cc b/gcc/genemit.cc index 9c881aa2baee..c40f7fc7fb1a 100644 --- a/gcc/genemit.cc +++ b/gcc/genemit.cc @@ -877,15 +877,14 @@ from the machine description file `md'. */\n\n"); fprintf (file, "#include \"target.h\"\n\n"); } -auto_vec<FILE *, 10> output_files; +auto_vec<generator_output, 10> output_files; static bool handle_arg (const char *arg) { if (arg[1] == 'O') { - FILE *file = fopen (&arg[2], "w"); - output_files.safe_push (file); + add_generator_output (output_files, &arg[2], true); return true; } return false; @@ -909,13 +908,13 @@ main (int argc, const char **argv) md_rtx_info info; if (output_files.is_empty ()) - output_files.safe_push (stdout); + add_generator_output (output_files, NULL, true); + open_generator_outputs (output_files); - for (auto f : output_files) - print_header (f); + for (const generator_output &output : output_files) + print_header (output.file); FILE *file = NULL; - unsigned file_idx; /* Read the machine description. */ while (read_md_rtx (&info)) @@ -940,7 +939,7 @@ main (int argc, const char **argv) for (auto &info : queue) { - file = choose_output (output_files, file_idx); + file = choose_output (output_files); fprintf (file, "/* %s:%d */\n", info.loc.filename, info.loc.lineno); switch (GET_CODE (info.def)) @@ -963,7 +962,7 @@ main (int argc, const char **argv) } } - file = choose_output (output_files, file_idx); + file = choose_output (output_files); /* Write out the routines to add CLOBBERs to a pattern and say whether they clobber a hard reg. */ @@ -976,15 +975,11 @@ main (int argc, const char **argv) for (overloaded_name *oname = rtx_reader_ptr->get_overloads (); oname; oname = oname->next) { - file = choose_output (output_files, file_idx); + file = choose_output (output_files); handle_overloaded_code_for (oname, file); handle_overloaded_gen (oname, file); } - int ret = SUCCESS_EXIT_CODE; - for (FILE *f : output_files) - if (fclose (f) != 0) - ret = FATAL_EXIT_CODE; - - return ret; + return (close_generator_outputs (output_files) + ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE); } diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc index 04fc23300185..2adf29be705e 100644 --- a/gcc/genrecog.cc +++ b/gcc/genrecog.cc @@ -5340,11 +5340,10 @@ print_subroutine (FILE *f, output_state *os, state *s, int proc_id, /* Print out a routine of type TYPE that performs ROOT. */ static void -print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os, +print_subroutine_group (const vec<generator_output> &outputs, FILE *header, + output_state *os, routine_type type, state *root) { - FILE *f; - unsigned idx; os->type = type; if (use_subroutines_p) { @@ -5357,19 +5356,14 @@ print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os, unsigned int i; state *s; - FILE *f = header; FOR_EACH_VEC_ELT (subroutines, i, s) print_subroutine (header, os, s, i + 1, true); FOR_EACH_VEC_ELT (subroutines, i, s) - { - f = choose_output (vec, idx); - print_subroutine (f, os, s, i + 1); - } + print_subroutine (choose_output (outputs), os, s, i + 1); } /* Output the main routine. */ - f = choose_output (vec, idx); - print_subroutine (f, os, root, 0); + print_subroutine (choose_output (outputs), os, root, 0); } /* Return the rtx pattern for the list of rtxes in a define_peephole2. */ @@ -5440,24 +5434,22 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr) return true; } -auto_vec<FILE *, 10> output_files; -char header_name[255]; -FILE *header = NULL; +auto_vec<generator_output, 10> output_files; +const char *header_name; static bool handle_arg (const char *arg) { - printf ("%s\n", arg); if (arg[1] == 'O') { - FILE *file = fopen (&arg[2], "w"); - output_files.safe_push (file); + add_generator_output (output_files, &arg[2], true); return true; } if (arg[1] == 'H') { - snprintf (header_name, 255, "%s", &arg[2]); - header = fopen (header_name, "w"); + if (header_name) + fatal ("option -H specified more than once"); + header_name = &arg[2]; return true; } return false; @@ -5473,14 +5465,18 @@ main (int argc, const char **argv) if (!init_rtx_reader_args_cb (argc, argv, handle_arg)) return (FATAL_EXIT_CODE); + if (!header_name) + fatal ("no -H output file specified"); if (output_files.is_empty ()) - output_files.safe_push (stdout); - - for (auto f : output_files) - write_header (f, header_name); + add_generator_output (output_files, NULL, true); + unsigned int header_index + = add_generator_output (output_files, header_name, false); + open_generator_outputs (output_files); + FILE *header = output_files[header_index].file; - FILE *file = NULL; - unsigned file_idx; + for (const generator_output &output : output_files) + if (output.partition_p) + write_header (output.file, header_name); /* Read the machine description. */ @@ -5488,7 +5484,6 @@ main (int argc, const char **argv) while (read_md_rtx (&info)) { rtx def = info.def; - file = choose_output (output_files, file_idx); acceptance_type acceptance; acceptance.partial_p = false; @@ -5546,8 +5541,9 @@ main (int argc, const char **argv) if (have_error) return FATAL_EXIT_CODE; - for (auto f : output_files) - fprintf (f, "%s", "\n\n"); + for (const generator_output &output : output_files) + if (output.partition_p) + fprintf (output.file, "%s", "\n\n"); /* Optimize each routine in turn. */ optimize_subroutine_group ("recog", &insn_root); @@ -5574,10 +5570,7 @@ main (int argc, const char **argv) print_pattern (header, &os, routine, true); FOR_EACH_VEC_ELT (patterns, i, routine) - { - file = choose_output (output_files, file_idx); - print_pattern (file, &os, routine); - } + print_pattern (choose_output (output_files), &os, routine); } /* Print out the matching routines. */ @@ -5588,11 +5581,6 @@ main (int argc, const char **argv) /* Every test has been printed, so the set of conditions is complete. */ print_md_conditions (header); - fclose (header); - - int ret = SUCCESS_EXIT_CODE; - for (FILE *f : output_files) - if (fclose (f) != 0) - ret = FATAL_EXIT_CODE; - return ret; + return (close_generator_outputs (output_files) + ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE); } diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index 5fcc30d340eb..0bacafc848b1 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -3935,35 +3935,75 @@ find_optab (optab_pattern *p, const char *name) return false; } -/* Find the file to write into next. We try to evenly distribute the contents - over the different files. */ +/* Add output NAME to OUTPUTS. A null NAME means standard output. + PARTITION_P is true if the output participates in size-based selection. + Return its index. */ -#define SIZED_BASED_CHUNKS 1 +unsigned int +add_generator_output (vec<generator_output> &outputs, const char *name, + bool partition_p) +{ + gcc_assert (name || outputs.is_empty ()); + if (name) + for (const generator_output &output : outputs) + if (output.name && canonical_filename_eq (name, output.name)) + fatal ("output file %s specified more than once", name); + + generator_output output = { name, name ? NULL : stdout, partition_p }; + unsigned int index = outputs.length (); + outputs.safe_push (output); + return index; +} + +/* Open each named file in OUTPUTS. */ + +void +open_generator_outputs (vec<generator_output> &outputs) +{ + for (generator_output &output : outputs) + if (!output.file) + { + output.file = fopen (output.name, "w"); + if (!output.file) + fatal ("cannot open file %s: %s", output.name, xstrerror (errno)); + } +} + +/* Return the shortest partition file in OUTPUTS. */ FILE * -choose_output (const vec<FILE *> &parts, unsigned &idx) +choose_output (const vec<generator_output> &outputs) { - if (parts.length () == 0) - gcc_unreachable (); -#ifdef SIZED_BASED_CHUNKS FILE *shortest = NULL; long min = 0; - idx = 0; - for (unsigned i = 0; i < parts.length (); i++) + for (const generator_output &output : outputs) { - FILE *part = parts[i]; - long len = ftell (part); + if (!output.partition_p) + continue; + long len = ftell (output.file); if (!shortest || min > len) { - shortest = part; + shortest = output.file; min = len; - idx = i; - } + } } + if (!shortest) + gcc_unreachable (); return shortest; -#else - static int current_file; - idx = current_file++ % parts.length (); - return parts[idx]; -#endif +} + +/* Close all files in OUTPUTS. Return true if every close succeeds. */ + +bool +close_generator_outputs (const vec<generator_output> &outputs) +{ + bool ok = true; + for (const generator_output &output : outputs) + if (fclose (output.file) != 0) + { + error ("cannot close output %s: %s", + output.name ? output.name : "<stdout>", xstrerror (errno)); + ok = false; + } + return ok; } diff --git a/gcc/gensupport.h b/gcc/gensupport.h index 86dd11034365..880505355b28 100644 --- a/gcc/gensupport.h +++ b/gcc/gensupport.h @@ -232,6 +232,20 @@ extern void compute_test_codes (rtx, file_location, char *); extern file_location get_file_location (rtx); extern const char *get_emit_function (rtx); extern bool find_optab (optab_pattern *, const char *); -extern FILE *choose_output (const vec<FILE *> &, unsigned &); + +/* An output file produced by a machine-description generator. Partition + files participate in size-based output selection. */ +struct generator_output +{ + const char *name; + FILE *file; + bool partition_p; +}; + +extern unsigned int add_generator_output (vec<generator_output> &, + const char *, bool); +extern void open_generator_outputs (vec<generator_output> &); +extern FILE *choose_output (const vec<generator_output> &); +extern bool close_generator_outputs (const vec<generator_output> &); #endif /* GCC_GENSUPPORT_H */
