commit: 1a1d956946479e114de07f5e2118d2d329e940c4 Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Sun Aug 3 09:06:16 2025 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Sun Aug 3 09:06:16 2025 +0000 URL: https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=1a1d9569
14.3.0: backport more build speed improvements Signed-off-by: Sam James <sam <AT> gentoo.org> ...ut-Accelerate-the-place_operands-function.patch | 247 ++++ ...nemit-Distribute-evenly-to-files-PR111600.patch | 190 +++ ...g-Split-into-separate-partitions-PR111600.patch | 1369 ++++++++++++++++++++ 14.3.0/gentoo/README.history | 6 + 4 files changed, 1812 insertions(+) diff --git a/14.3.0/gentoo/80_all_genoutput-Accelerate-the-place_operands-function.patch b/14.3.0/gentoo/80_all_genoutput-Accelerate-the-place_operands-function.patch new file mode 100644 index 0000000..006eb02 --- /dev/null +++ b/14.3.0/gentoo/80_all_genoutput-Accelerate-the-place_operands-function.patch @@ -0,0 +1,247 @@ +From c7b82a73d8ee92ce47734170978c22d2140ddae0 Mon Sep 17 00:00:00 2001 +Message-ID: <c7b82a73d8ee92ce47734170978c22d2140ddae0.1754211915.git....@gentoo.org> +From: Xianmiao Qu <[email protected]> +Date: Wed, 22 May 2024 15:25:16 +0800 +Subject: [PATCH 1/3] genoutput: Accelerate the place_operands function + +With the increase in the number of modes and patterns for some +backend architectures, the place_operands function becomes a +bottleneck int the speed of genoutput, and may even become a +bottleneck int the overall speed of building the GCC project. +This patch aims to accelerate the place_operands function, +the optimizations it includes are: +1. Use a hash table to store operand information, + improving the lookup time for the first operand. +2. Move mode comparison to the beginning to avoid the scenarios of most strcmp. + +I tested the speed improvements for the following backends, + Improvement Ratio +x86_64 197.9% +aarch64 954.5% +riscv 2578.6% +If the build machine is slow, then this improvement can save a lot of time. + +I tested the genoutput output for x86_64/aarch64/riscv backends, +and there was no difference compared to before the optimization, +so this shouldn't introduce any functional issues. + +gcc/ + * genoutput.cc (struct operand_data): Add member 'eq_next' to + point to the next member with the same hash value in the + hash table. + (compare_operands): Move the comparison of the mode to the very + beginning to accelerate the comparison of the two operands. + (struct operand_data_hasher): New, a class that takes into account + the necessary elements for comparing the equality of two operands + in its hash value. + (operand_data_hasher::hash): New. + (operand_data_hasher::equal): New. + (operand_datas): New, hash table of konwn pattern operands. + (place_operands): Use a hash table instead of traversing the array + to find the same operand. + (main): Add initialization of the hash table 'operand_datas'. + +(cherry picked from commit ca7936f7764116a39d785bb087584805072a3461) +--- + gcc/genoutput.cc | 111 +++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 88 insertions(+), 23 deletions(-) + +diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc +index efd81766bb5b..16fd811b5dd5 100644 +--- a/gcc/genoutput.cc ++++ b/gcc/genoutput.cc +@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see + #include "errors.h" + #include "read-md.h" + #include "gensupport.h" ++#include "hash-table.h" + + /* No instruction can have more operands than this. Sorry for this + arbitrary limit, but what machine will have an instruction with +@@ -112,6 +113,8 @@ static int next_operand_number = 1; + struct operand_data + { + struct operand_data *next; ++ /* Point to the next member with the same hash value in the hash table. */ ++ struct operand_data *eq_next; + int index; + const char *predicate; + const char *constraint; +@@ -127,7 +130,7 @@ struct operand_data + + static struct operand_data null_operand = + { +- 0, 0, "", "", E_VOIDmode, 0, 0, 0, 0, 0 ++ 0, 0, 0, "", "", E_VOIDmode, 0, 0, 0, 0, 0 + }; + + static struct operand_data *odata = &null_operand; +@@ -174,8 +177,8 @@ static void output_operand_data (void); + static void output_insn_data (void); + static void output_get_insn_name (void); + static void scan_operands (class data *, rtx, int, int); +-static int compare_operands (struct operand_data *, +- struct operand_data *); ++static int compare_operands (const struct operand_data *, ++ const struct operand_data *); + static void place_operands (class data *); + static void process_template (class data *, const char *); + static void validate_insn_alternatives (class data *); +@@ -528,10 +531,18 @@ scan_operands (class data *d, rtx part, int this_address_p, + /* Compare two operands for content equality. */ + + static int +-compare_operands (struct operand_data *d0, struct operand_data *d1) ++compare_operands (const struct operand_data *d0, ++ const struct operand_data *d1) + { + const char *p0, *p1; + ++ /* On one hand, comparing strings for predicate and constraint ++ is time-consuming, and on the other hand, the probability of ++ different modes is relatively high. Therefore, checking the mode ++ first can speed up the execution of the program. */ ++ if (d0->mode != d1->mode) ++ return 0; ++ + p0 = d0->predicate; + if (!p0) + p0 = ""; +@@ -550,9 +561,6 @@ compare_operands (struct operand_data *d0, struct operand_data *d1) + if (strcmp (p0, p1) != 0) + return 0; + +- if (d0->mode != d1->mode) +- return 0; +- + if (d0->strict_low != d1->strict_low) + return 0; + +@@ -562,6 +570,46 @@ compare_operands (struct operand_data *d0, struct operand_data *d1) + return 1; + } + ++/* This is a class that takes into account the necessary elements for ++ comparing the equality of two operands in its hash value. */ ++struct operand_data_hasher : nofree_ptr_hash <operand_data> ++{ ++ static inline hashval_t hash (const operand_data *); ++ static inline bool equal (const operand_data *, const operand_data *); ++}; ++ ++hashval_t ++operand_data_hasher::hash (const operand_data * op_info) ++{ ++ inchash::hash h; ++ const char *pred, *cons; ++ ++ pred = op_info->predicate; ++ if (!pred) ++ pred = ""; ++ h.add (pred, strlen (pred) + 1); ++ ++ cons = op_info->constraint; ++ if (!cons) ++ cons = ""; ++ h.add (cons, strlen (cons) + 1); ++ ++ h.add_object (op_info->mode); ++ h.add_object (op_info->strict_low); ++ h.add_object (op_info->eliminable); ++ return h.end (); ++} ++ ++bool ++operand_data_hasher::equal (const operand_data * op_info1, ++ const operand_data * op_info2) ++{ ++ return compare_operands (op_info1, op_info2); ++} ++ ++/* Hashtable of konwn pattern operands. */ ++static hash_table<operand_data_hasher> *operand_datas; ++ + /* Scan the list of operands we've already committed to output and either + find a subsequence that is the same, or allocate a new one at the end. */ + +@@ -569,6 +617,7 @@ static void + place_operands (class data *d) + { + struct operand_data *od, *od2; ++ struct operand_data **slot; + int i; + + if (d->n_operands == 0) +@@ -577,23 +626,24 @@ place_operands (class data *d) + return; + } + ++ od = operand_datas->find (&d->operand[0]); + /* Brute force substring search. */ +- for (od = odata, i = 0; od; od = od->next, i = 0) +- if (compare_operands (od, &d->operand[0])) +- { +- od2 = od->next; +- i = 1; +- while (1) +- { +- if (i == d->n_operands) +- goto full_match; +- if (od2 == NULL) +- goto partial_match; +- if (! compare_operands (od2, &d->operand[i])) +- break; +- ++i, od2 = od2->next; +- } +- } ++ for (; od; od = od->eq_next) ++ { ++ od2 = od->next; ++ i = 1; ++ while (1) ++ { ++ if (i == d->n_operands) ++ goto full_match; ++ if (od2 == NULL) ++ goto partial_match; ++ if (! compare_operands (od2, &d->operand[i])) ++ break; ++ ++i, od2 = od2->next; ++ } ++ } ++ i = 0; + + /* Either partial match at the end of the list, or no match. In either + case, we tack on what operands are remaining to the end of the list. */ +@@ -605,6 +655,20 @@ place_operands (class data *d) + *odata_end = od2; + odata_end = &od2->next; + od2->index = next_operand_number++; ++ /* Insert the operand_data variable OD2 into the hash table. ++ If a variable with the same hash value already exists in ++ the hash table, insert the element at the end of the ++ linked list connected through the eq_next member. */ ++ slot = operand_datas->find_slot (od2, INSERT); ++ if (*slot) ++ { ++ struct operand_data *last = (struct operand_data *) *slot; ++ while (last->eq_next) ++ last = last->eq_next; ++ last->eq_next = od2; ++ } ++ else ++ *slot = od2; + } + *odata_end = NULL; + return; +@@ -1049,6 +1113,7 @@ main (int argc, const char **argv) + progname = "genoutput"; + + init_insn_for_nothing (); ++ operand_datas = new hash_table<operand_data_hasher> (1024); + + if (!init_rtx_reader_args (argc, argv)) + return (FATAL_EXIT_CODE); +-- +2.50.1 + diff --git a/14.3.0/gentoo/81_all_genemit-Distribute-evenly-to-files-PR111600.patch b/14.3.0/gentoo/81_all_genemit-Distribute-evenly-to-files-PR111600.patch new file mode 100644 index 0000000..b82f525 --- /dev/null +++ b/14.3.0/gentoo/81_all_genemit-Distribute-evenly-to-files-PR111600.patch @@ -0,0 +1,190 @@ +From a3a4e67e334de5512bca14341c26edba66f0b659 Mon Sep 17 00:00:00 2001 +Message-ID: <a3a4e67e334de5512bca14341c26edba66f0b659.1754211915.git....@gentoo.org> +In-Reply-To: <c7b82a73d8ee92ce47734170978c22d2140ddae0.1754211915.git....@gentoo.org> +References: <c7b82a73d8ee92ce47734170978c22d2140ddae0.1754211915.git....@gentoo.org> +From: Robin Dapp <[email protected]> +Date: Thu, 21 Nov 2024 15:34:37 +0100 +Subject: [PATCH 2/3] genemit: Distribute evenly to files [PR111600] + +currently we distribute insn patterns in genemit, partitioning them +by the number of patterns per file. The first 100 into file 1, the +next 100 into file 2, and so on. Depending on the patterns this +can lead to files of very uneven sizes. + +Similar to the genmatch split, this patch introduces a dynamic +choose_output () which considers the size of the output files +and selects the shortest one for the next pattern. + +gcc/ChangeLog: + + PR target/111600 + + * genemit.cc (handle_arg): Use files instead of filenames. + (main): Ditto. + * gensupport.cc (SIZED_BASED_CHUNKS): Define. + (choose_output): New function. + * gensupport.h (choose_output): Declare. + +(cherry picked from commit 2e6b3308af6ddf87925321ddd2d387bfd352e410) +--- + gcc/genemit.cc | 54 +++++++++++++++-------------------------------- + gcc/gensupport.cc | 33 +++++++++++++++++++++++++++++ + gcc/gensupport.h | 1 + + 3 files changed, 51 insertions(+), 37 deletions(-) + +diff --git a/gcc/genemit.cc b/gcc/genemit.cc +index 98d0477424b0..bbbd4b12f454 100644 +--- a/gcc/genemit.cc ++++ b/gcc/genemit.cc +@@ -897,14 +897,15 @@ from the machine description file `md'. */\n\n"); + fprintf (file, "#include \"target.h\"\n\n"); + } + +-auto_vec<const char *, 10> output_files; ++auto_vec<FILE *, 10> output_files; + + static bool + handle_arg (const char *arg) + { + if (arg[1] == 'O') + { +- output_files.safe_push (&arg[2]); ++ FILE *file = fopen (&arg[2], "w"); ++ output_files.safe_push (file); + return true; + } + return false; +@@ -925,47 +926,21 @@ main (int argc, const char **argv) + /* Assign sequential codes to all entries in the machine description + in parallel with the tables in insn-output.cc. */ + +- int npatterns = count_patterns (); + md_rtx_info info; + +- bool to_stdout = false; +- int npatterns_per_file = npatterns; +- if (!output_files.is_empty ()) +- npatterns_per_file = npatterns / output_files.length () + 1; +- else +- to_stdout = true; +- +- gcc_assert (npatterns_per_file > 1); ++ if (output_files.is_empty ()) ++ output_files.safe_push (stdout); + +- /* Reverse so we can pop the first-added element. */ +- output_files.reverse (); ++ for (auto f : output_files) ++ print_header (f); + +- int count = 0; + FILE *file = NULL; ++ unsigned file_idx; + + /* Read the machine description. */ + while (read_md_rtx (&info)) + { +- if (count == 0 || count == npatterns_per_file) +- { +- bool is_last = !to_stdout && output_files.is_empty (); +- if (file && !is_last) +- if (fclose (file) != 0) +- return FATAL_EXIT_CODE; +- +- if (!output_files.is_empty ()) +- { +- const char *const filename = output_files.pop (); +- file = fopen (filename, "w"); +- } +- else if (to_stdout) +- file = stdout; +- else +- break; +- +- print_header (file); +- count = 0; +- } ++ file = choose_output (output_files, file_idx); + + switch (GET_CODE (info.def)) + { +@@ -991,10 +966,10 @@ main (int argc, const char **argv) + default: + break; + } +- +- count++; + } + ++ file = choose_output (output_files, file_idx); ++ + /* Write out the routines to add CLOBBERs to a pattern and say whether they + clobber a hard reg. */ + output_add_clobbers (&info, file); +@@ -1007,5 +982,10 @@ main (int argc, const char **argv) + handle_overloaded_gen (oname, file); + } + +- return (fclose (file) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); ++ int ret = SUCCESS_EXIT_CODE; ++ for (FILE *f : output_files) ++ if (fclose (f) != 0) ++ ret = FATAL_EXIT_CODE; ++ ++ return ret; + } +diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc +index 3a02132c8761..e0adf0c1bc54 100644 +--- a/gcc/gensupport.cc ++++ b/gcc/gensupport.cc +@@ -3913,3 +3913,36 @@ 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. */ ++ ++#define SIZED_BASED_CHUNKS 1 ++ ++FILE * ++choose_output (const vec<FILE *> &parts, unsigned &idx) ++{ ++ 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++) ++ { ++ FILE *part = parts[i]; ++ long len = ftell (part); ++ if (!shortest || min > len) ++ { ++ shortest = part; ++ min = len; ++ idx = i; ++ } ++ } ++ return shortest; ++#else ++ static int current_file; ++ idx = current_file++ % parts.length (); ++ return parts[idx]; ++#endif ++} +diff --git a/gcc/gensupport.h b/gcc/gensupport.h +index b7a1da34518c..781c9e9ffcea 100644 +--- a/gcc/gensupport.h ++++ b/gcc/gensupport.h +@@ -231,5 +231,6 @@ extern file_location get_file_location (rtx); + extern const char *get_emit_function (rtx); + extern bool needs_barrier_p (rtx); + extern bool find_optab (optab_pattern *, const char *); ++extern FILE *choose_output (const vec<FILE *> &, unsigned &); + + #endif /* GCC_GENSUPPORT_H */ +-- +2.50.1 + diff --git a/14.3.0/gentoo/82_all_genrecog-Split-into-separate-partitions-PR111600.patch b/14.3.0/gentoo/82_all_genrecog-Split-into-separate-partitions-PR111600.patch new file mode 100644 index 0000000..197e50b --- /dev/null +++ b/14.3.0/gentoo/82_all_genrecog-Split-into-separate-partitions-PR111600.patch @@ -0,0 +1,1369 @@ +From 6ba975a1d3feec09cd430514c1457bb74485c64c Mon Sep 17 00:00:00 2001 +Message-ID: <6ba975a1d3feec09cd430514c1457bb74485c64c.1754211915.git....@gentoo.org> +In-Reply-To: <c7b82a73d8ee92ce47734170978c22d2140ddae0.1754211915.git....@gentoo.org> +References: <c7b82a73d8ee92ce47734170978c22d2140ddae0.1754211915.git....@gentoo.org> +From: Robin Dapp <[email protected]> +Date: Tue, 26 Nov 2024 14:44:17 +0100 +Subject: [PATCH 3/3] genrecog: Split into separate partitions [PR111600] + +Hi, + +this patch makes genrecog split its output into separate files (10 by +default) in the same vein genemit does. The changes are mostly +mechanical again, changing printfs and puts to fprintf. +As insn-recog.cc relies on being able to call other recog functions a +header insn-recog.h is introduced that pre declares all of those. + +For simplicity the number of files is determined by (re-using) +--with-insnemit-partitions. Naming suggestions welcome :) + +Bootstrapped and regtested on x86 and power10, regtested on riscv. +aarch64 bootstrap is currently blocked because of the +"maybe uninitialized" issue discussed on IRC. + +Regards + Robin + +gcc/ChangeLog: + +* Makefile.in: Add insn-recog split. + * configure.ac: Document that the number of insnemit partitions is + used for insn-recog as well. + * genconditions.cc (write_one_condition): Use fprintf. + * genpreds.cc (write_predicate_expr): Ditto. + (write_init_reg_class_start_regs): Ditto. + * genrecog.cc (write_header): Add header file to includes. + (printf_indent): Use fprintf. + (change_state): Ditto. + (print_code): Ditto. + (print_host_wide_int): Ditto. + (print_parameter_value): Ditto. + (print_test_rtx): Ditto. + (print_nonbool_test): Ditto. + (print_label_value): Ditto. + (print_test): Ditto. + (print_decision): Ditto. + (print_state): Ditto. + (print_subroutine_call): Ditto. + (print_acceptance): Ditto. + (print_subroutine_start): Ditto. + (print_pattern): Ditto. + (print_subroutine): Ditto. + (print_subroutine_group): Ditto. + (handle_arg): Add -O and -H for output and header file handling. + (main): Use callback. + * gentarget-def.cc (def_target_insn): Use fprintf. + * read-md.cc (md_reader::print_c_condition): Ditto. + * read-md.h (class md_reader): Ditto. +--- + gcc/Makefile.in | 29 ++- + gcc/configure.ac | 4 +- + gcc/genconditions.cc | 4 +- + gcc/genpreds.cc | 4 +- + gcc/genrecog.cc | 552 +++++++++++++++++++++++++------------------ + gcc/gentarget-def.cc | 2 +- + gcc/read-md.cc | 4 +- + gcc/read-md.h | 2 +- + 8 files changed, 358 insertions(+), 243 deletions(-) + +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 3ff59f0b0f19..7cd605b81769 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -243,6 +243,12 @@ INSNEMIT_SEQ_SRC = $(patsubst %, insn-emit-%.cc, $(INSNEMIT_SPLITS_SEQ)) + INSNEMIT_SEQ_TMP = $(patsubst %, tmp-emit-%.cc, $(INSNEMIT_SPLITS_SEQ)) + INSNEMIT_SEQ_O = $(patsubst %, insn-emit-%.o, $(INSNEMIT_SPLITS_SEQ)) + ++# Re-use the split number for insn-recog as well. ++INSNRECOG_SPLITS_SEQ = $(wordlist 1,$(NUM_INSNEMIT_SPLITS),$(one_to_9999)) ++INSNRECOG_SEQ_SRC = $(patsubst %, insn-recog-%.cc, $(INSNRECOG_SPLITS_SEQ)) ++INSNRECOG_SEQ_TMP = $(patsubst %, tmp-recog-%.cc, $(INSNRECOG_SPLITS_SEQ)) ++INSNRECOG_SEQ_O = $(patsubst %, insn-recog-%.o, $(INSNRECOG_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 +@@ -1378,7 +1384,7 @@ OBJS = \ + insn-output.o \ + insn-peep.o \ + insn-preds.o \ +- insn-recog.o \ ++ $(INSNRECOG_SEQ_O) \ + insn-enums.o \ + ggc-page.o \ + adjust-alignment.o \ +@@ -1877,8 +1883,8 @@ TREECHECKING = @TREECHECKING@ + FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext) + + MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ +- insn-output.cc insn-recog.cc $(INSNEMIT_SEQ_SRC) \ +- insn-extract.cc insn-peep.cc \ ++ 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 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) \ +@@ -2516,7 +2522,8 @@ $(common_out_object_file): $(common_out_file) + # and compile them. + + .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ +- $(INSNEMIT_SEQ_SRC) insn-recog.cc insn-extract.cc insn-output.cc \ ++ $(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-dfatab.cc insn-latencytab.cc insn-preds.cc \ + $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \ +@@ -2545,7 +2552,7 @@ simple_rtl_generated_h = insn-attr.h insn-attr-common.h insn-codes.h \ + + simple_rtl_generated_c = insn-automata.cc \ + insn-extract.cc insn-output.cc \ +- insn-peep.cc insn-recog.cc ++ insn-peep.cc + + simple_generated_h = $(simple_rtl_generated_h) insn-constants.h + +@@ -2583,6 +2590,18 @@ s-tmp-emit: build/genemit$(build_exeext) $(MD_DEPS) insn-conditions.md + insn-emit-$(id).cc;) + $(STAMP) s-tmp-emit + ++# Same for genrecog. ++$(INSNRECOG_SEQ_SRC): s-tmp-recog; @true ++insn-recog.h: s-tmp-recog; @true ++s-tmp-recog: build/genrecog$(build_exeext) $(MD_DEPS) insn-conditions.md ++ $(RUN_GEN) build/genrecog$(build_exeext) $(md_file) insn-conditions.md \ ++ -Hinsn-recog.h \ ++ $(addprefix -O,${INSNRECOG_SEQ_TMP}) ++ $(foreach id, $(INSNRECOG_SPLITS_SEQ), \ ++ $(SHELL) $(srcdir)/../move-if-change tmp-recog-$(id).cc \ ++ insn-recog-$(id).cc;) ++ $(STAMP) s-tmp-recog ++ + # gencheck doesn't read the machine description, and the file produced + # doesn't use the insn-* convention. + +diff --git a/gcc/configure.ac b/gcc/configure.ac +index 151e234a2f91..46f89f137452 100644 +--- a/gcc/configure.ac ++++ b/gcc/configure.ac +@@ -910,10 +910,10 @@ fi + + AC_SUBST(DEFAULT_MATCHPD_PARTITIONS) + +-# Specify the number of splits of insn-emit.cc to generate. ++# Specify the number of splits of insn-emit.cc and insn-recog.cc to generate. + AC_ARG_WITH(insnemit-partitions, + [AS_HELP_STRING([--with-insnemit-partitions=num], +-[Set the number of partitions of insn-emit.cc for genemit to create. [default=10]])], ++[Set the number of partitions of insn-emit.cc for genemit and genrecog to create. [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/genconditions.cc b/gcc/genconditions.cc +index 13963dc3ff46..9da460893d52 100644 +--- a/gcc/genconditions.cc ++++ b/gcc/genconditions.cc +@@ -141,9 +141,9 @@ write_one_condition (void **slot, void * ARG_UNUSED (dummy)) + } + + fputs ("\",\n __builtin_constant_p ", stdout); +- rtx_reader_ptr->print_c_condition (test->expr); ++ rtx_reader_ptr->print_c_condition (stdout, test->expr); + fputs ("\n ? (int) ", stdout); +- rtx_reader_ptr->print_c_condition (test->expr); ++ rtx_reader_ptr->print_c_condition (stdout, test->expr); + fputs ("\n : -1 },\n", stdout); + return 1; + } +diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc +index 55d149e8a404..b8f3bf279d97 100644 +--- a/gcc/genpreds.cc ++++ b/gcc/genpreds.cc +@@ -538,7 +538,7 @@ write_predicate_expr (rtx exp) + break; + + case MATCH_TEST: +- rtx_reader_ptr->print_c_condition (XSTR (exp, 0)); ++ rtx_reader_ptr->print_c_condition (stdout, XSTR (exp, 0)); + break; + + default: +@@ -1344,7 +1344,7 @@ write_init_reg_class_start_regs () + for (unsigned int i = 0; i < register_filters.length (); ++i) + { + printf (" if ("); +- rtx_reader_ptr->print_c_condition (register_filters[i]); ++ rtx_reader_ptr->print_c_condition (stdout, register_filters[i]); + printf (")\n" + " SET_HARD_REG_BIT (%s[%d], regno);\n", + "this_target_constraints->register_filters", i); +diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc +index ba09ec3b6005..7f7ca728bbe0 100644 +--- a/gcc/genrecog.cc ++++ b/gcc/genrecog.cc +@@ -4255,9 +4255,9 @@ match_pattern (state *s, md_rtx_info *info, rtx pattern, + /* Begin the output file. */ + + static void +-write_header (void) ++write_header (FILE *f, const char *header_filename) + { +- puts ("\ ++ fprintf (f, "%s", "\ + /* Generated automatically by the program `genrecog' from the target\n\ + machine description file. */\n\ + \n\ +@@ -4281,10 +4281,12 @@ write_header (void) + #include \"diagnostic-core.h\"\n\ + #include \"reload.h\"\n\ + #include \"regs.h\"\n\ +-#include \"tm-constrs.h\"\n\ +-\n"); ++#include \"tm-constrs.h\"\n"); + +- puts ("\n\ ++ fprintf (f, "#include \"%s\"\n", header_filename); ++ fprintf (f, "%s", "\n"); ++ ++ fprintf (f, "%s", "\n\ + /* `recog' contains a decision tree that recognizes whether the rtx\n\ + X0 is a valid instruction.\n\ + \n\ +@@ -4293,19 +4295,19 @@ write_header (void) + pattern that matched. This is the same as the order in the machine\n\ + description of the entry that matched. This number can be used as an\n\ + index into `insn_data' and other tables.\n"); +- puts ("\ ++ fprintf (f, "%s", "\ + The third parameter to recog is an optional pointer to an int. If\n\ + present, recog will accept a pattern if it matches except for missing\n\ + CLOBBER expressions at the end. In that case, the value pointed to by\n\ + the optional pointer will be set to the number of CLOBBERs that need\n\ + to be added (it should be initialized to zero by the caller). If it"); +- puts ("\ ++ fprintf (f, "%s", "\ + is set nonzero, the caller should allocate a PARALLEL of the\n\ + appropriate size, copy the initial entries, and call add_clobbers\n\ + (found in insn-emit.cc) to fill in the CLOBBERs.\n\ + "); + +- puts ("\n\ ++ fprintf (f, "%s", "\n\ + The function split_insns returns 0 if the rtl could not\n\ + be split or the split rtl as an INSN list if it can be.\n\ + \n\ +@@ -4463,13 +4465,13 @@ test_position_available_p (output_state *os, const rtx_test &test) + + /* Like printf, but print INDENT spaces at the beginning. */ + +-static void ATTRIBUTE_PRINTF_2 +-printf_indent (unsigned int indent, const char *format, ...) ++static void ATTRIBUTE_PRINTF_3 ++printf_indent (FILE *f, unsigned int indent, const char *format, ...) + { + va_list ap; + va_start (ap, format); +- printf ("%*s", indent, ""); +- vprintf (format, ap); ++ fprintf (f, "%*s", indent, ""); ++ vfprintf (f, format, ap); + va_end (ap); + } + +@@ -4478,7 +4480,7 @@ printf_indent (unsigned int indent, const char *format, ...) + OS with the new state. */ + + static void +-change_state (output_state *os, position *pos, unsigned int indent) ++change_state (FILE *f, output_state *os, position *pos, unsigned int indent) + { + unsigned int var = os->id_to_var[pos->id]; + gcc_assert (var < os->var_to_id.length () && os->var_to_id[var] == pos->id); +@@ -4487,19 +4489,19 @@ change_state (output_state *os, position *pos, unsigned int indent) + switch (pos->type) + { + case POS_PEEP2_INSN: +- printf_indent (indent, "x%d = PATTERN (peep2_next_insn (%d));\n", ++ printf_indent (f, indent, "x%d = PATTERN (peep2_next_insn (%d));\n", + var, pos->arg); + break; + + case POS_XEXP: +- change_state (os, pos->base, indent); +- printf_indent (indent, "x%d = XEXP (x%d, %d);\n", ++ change_state (f, os, pos->base, indent); ++ printf_indent (f, indent, "x%d = XEXP (x%d, %d);\n", + var, os->id_to_var[pos->base->id], pos->arg); + break; + + case POS_XVECEXP0: +- change_state (os, pos->base, indent); +- printf_indent (indent, "x%d = XVECEXP (x%d, 0, %d);\n", ++ change_state (f, os, pos->base, indent); ++ printf_indent (f, indent, "x%d = XVECEXP (x%d, 0, %d);\n", + var, os->id_to_var[pos->base->id], pos->arg); + break; + } +@@ -4510,11 +4512,11 @@ change_state (output_state *os, position *pos, unsigned int indent) + the name. */ + + static void +-print_code (enum rtx_code code) ++print_code (FILE *f, enum rtx_code code) + { + const char *p; + for (p = GET_RTX_NAME (code); *p; p++) +- putchar (TOUPPER (*p)); ++ fprintf (f, "%c", TOUPPER (*p)); + } + + /* Emit a uint64_t as an integer constant expression. We need to take +@@ -4522,22 +4524,22 @@ print_code (enum rtx_code code) + warnings in the resulting code. */ + + static void +-print_host_wide_int (uint64_t val) ++print_host_wide_int (FILE *f, uint64_t val) + { + uint64_t min = uint64_t (1) << (HOST_BITS_PER_WIDE_INT - 1); + if (val == min) +- printf ("(" HOST_WIDE_INT_PRINT_DEC_C " - 1)", val + 1); ++ fprintf (f, "(" HOST_WIDE_INT_PRINT_DEC_C " - 1)", val + 1); + else +- printf (HOST_WIDE_INT_PRINT_DEC_C, val); ++ fprintf (f, HOST_WIDE_INT_PRINT_DEC_C, val); + } + + /* Print the C expression for actual parameter PARAM. */ + + static void +-print_parameter_value (const parameter ¶m) ++print_parameter_value (FILE *f, const parameter ¶m) + { + if (param.is_param) +- printf ("i%d", (int) param.value + 1); ++ fprintf (f, "i%d", (int) param.value + 1); + else + switch (param.type) + { +@@ -4546,23 +4548,23 @@ print_parameter_value (const parameter ¶m) + break; + + case parameter::CODE: +- print_code ((enum rtx_code) param.value); ++ print_code (f, (enum rtx_code) param.value); + break; + + case parameter::MODE: +- printf ("E_%smode", GET_MODE_NAME ((machine_mode) param.value)); ++ fprintf (f, "E_%smode", GET_MODE_NAME ((machine_mode) param.value)); + break; + + case parameter::INT: +- printf ("%d", (int) param.value); ++ fprintf (f, "%d", (int) param.value); + break; + + case parameter::UINT: +- printf ("%u", (unsigned int) param.value); ++ fprintf (f, "%u", (unsigned int) param.value); + break; + + case parameter::WIDE_INT: +- print_host_wide_int (param.value); ++ print_host_wide_int (f, param.value); + break; + } + } +@@ -4570,90 +4572,90 @@ print_parameter_value (const parameter ¶m) + /* Print the C expression for the rtx tested by TEST. */ + + static void +-print_test_rtx (output_state *os, const rtx_test &test) ++print_test_rtx (FILE *f, output_state *os, const rtx_test &test) + { + if (test.pos_operand >= 0) +- printf ("operands[%d]", test.pos_operand); ++ fprintf (f, "operands[%d]", test.pos_operand); + else +- printf ("x%d", os->id_to_var[test.pos->id]); ++ fprintf (f, "x%d", os->id_to_var[test.pos->id]); + } + + /* Print the C expression for non-boolean test TEST. */ + + static void +-print_nonbool_test (output_state *os, const rtx_test &test) ++print_nonbool_test (FILE *f, output_state *os, const rtx_test &test) + { + switch (test.kind) + { + case rtx_test::CODE: +- printf ("GET_CODE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "GET_CODE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::MODE: +- printf ("GET_MODE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "GET_MODE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::VECLEN: +- printf ("XVECLEN ("); +- print_test_rtx (os, test); +- printf (", 0)"); ++ fprintf (f, "XVECLEN ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", 0)"); + break; + + case rtx_test::INT_FIELD: +- printf ("XINT ("); +- print_test_rtx (os, test); +- printf (", %d)", test.u.opno); ++ fprintf (f, "XINT ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", %d)", test.u.opno); + break; + + case rtx_test::REGNO_FIELD: +- printf ("REGNO ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "REGNO ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::SUBREG_FIELD: +- printf ("SUBREG_BYTE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "SUBREG_BYTE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::WIDE_INT_FIELD: +- printf ("XWINT ("); +- print_test_rtx (os, test); +- printf (", %d)", test.u.opno); ++ fprintf (f, "XWINT ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", %d)", test.u.opno); + break; + + case rtx_test::PATTERN: + { + pattern_routine *routine = test.u.pattern->routine; +- printf ("pattern%d (", routine->pattern_id); ++ fprintf (f, "pattern%d (", routine->pattern_id); + const char *sep = ""; + if (test.pos) + { +- print_test_rtx (os, test); ++ print_test_rtx (f, os, test); + sep = ", "; + } + if (routine->insn_p) + { +- printf ("%sinsn", sep); ++ fprintf (f, "%sinsn", sep); + sep = ", "; + } + if (routine->pnum_clobbers_p) + { +- printf ("%spnum_clobbers", sep); ++ fprintf (f, "%spnum_clobbers", sep); + sep = ", "; + } + for (unsigned int i = 0; i < test.u.pattern->params.length (); ++i) + { +- fputs (sep, stdout); +- print_parameter_value (test.u.pattern->params[i]); ++ fprintf (f, "%s\n", sep); ++ print_parameter_value (f, test.u.pattern->params[i]); + sep = ", "; + } +- printf (")"); ++ fprintf (f, ")"); + break; + } + +@@ -4674,10 +4676,11 @@ print_nonbool_test (output_state *os, const rtx_test &test) + decision performs TEST. Print the C code for the label. */ + + static void +-print_label_value (const rtx_test &test, bool is_param, uint64_t value) ++print_label_value (FILE *f, const rtx_test &test, bool is_param, ++ uint64_t value) + { +- print_parameter_value (parameter (transition_parameter_type (test.kind), +- is_param, value)); ++ print_parameter_value (f, parameter (transition_parameter_type (test.kind), ++ is_param, value)); + } + + /* If IS_PARAM, print code to compare TEST with the C variable i<VALUE+1>. +@@ -4685,7 +4688,7 @@ print_label_value (const rtx_test &test, bool is_param, uint64_t value) + Test for inequality if INVERT_P, otherwise test for equality. */ + + static void +-print_test (output_state *os, const rtx_test &test, bool is_param, ++print_test (FILE *f, output_state *os, const rtx_test &test, bool is_param, + uint64_t value, bool invert_p) + { + switch (test.kind) +@@ -4698,71 +4701,71 @@ print_test (output_state *os, const rtx_test &test, bool is_param, + case rtx_test::INT_FIELD: + case rtx_test::WIDE_INT_FIELD: + case rtx_test::PATTERN: +- print_nonbool_test (os, test); +- printf (" %s ", invert_p ? "!=" : "=="); +- print_label_value (test, is_param, value); ++ print_nonbool_test (f, os, test); ++ fprintf (f, " %s ", invert_p ? "!=" : "=="); ++ print_label_value (f, test, is_param, value); + break; + + case rtx_test::SUBREG_FIELD: +- printf ("%s (", invert_p ? "maybe_ne" : "known_eq"); +- print_nonbool_test (os, test); +- printf (", "); +- print_label_value (test, is_param, value); +- printf (")"); ++ fprintf (f, "%s (", invert_p ? "maybe_ne" : "known_eq"); ++ print_nonbool_test (f, os, test); ++ fprintf (f, ", "); ++ print_label_value (f, test, is_param, value); ++ fprintf (f, ")"); + break; + + case rtx_test::SAVED_CONST_INT: + gcc_assert (!is_param && value == 1); +- print_test_rtx (os, test); +- printf (" %s const_int_rtx[MAX_SAVED_CONST_INT + ", +- invert_p ? "!=" : "=="); +- print_parameter_value (parameter (parameter::INT, +- test.u.integer.is_param, +- test.u.integer.value)); +- printf ("]"); ++ print_test_rtx (f, os, test); ++ fprintf (f, " %s const_int_rtx[MAX_SAVED_CONST_INT + ", ++ invert_p ? "!=" : "=="); ++ print_parameter_value (f, parameter (parameter::INT, ++ test.u.integer.is_param, ++ test.u.integer.value)); ++ fprintf (f, "]"); + break; + + case rtx_test::PEEP2_COUNT: + gcc_assert (!is_param && value == 1); +- printf ("peep2_current_count %s %d", invert_p ? "<" : ">=", +- test.u.min_len); ++ fprintf (f, "peep2_current_count %s %d", invert_p ? "<" : ">=", ++ test.u.min_len); + break; + + case rtx_test::VECLEN_GE: + gcc_assert (!is_param && value == 1); +- printf ("XVECLEN ("); +- print_test_rtx (os, test); +- printf (", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len); ++ fprintf (f, "XVECLEN ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len); + break; + + case rtx_test::PREDICATE: + gcc_assert (!is_param && value == 1); +- printf ("%s%s (", invert_p ? "!" : "", test.u.predicate.data->name); +- print_test_rtx (os, test); +- printf (", "); +- print_parameter_value (parameter (parameter::MODE, +- test.u.predicate.mode_is_param, +- test.u.predicate.mode)); +- printf (")"); ++ fprintf (f, "%s%s (", invert_p ? "!" : "", test.u.predicate.data->name); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", "); ++ print_parameter_value (f, parameter (parameter::MODE, ++ test.u.predicate.mode_is_param, ++ test.u.predicate.mode)); ++ fprintf (f, ")"); + break; + + case rtx_test::DUPLICATE: + gcc_assert (!is_param && value == 1); +- printf ("%srtx_equal_p (", invert_p ? "!" : ""); +- print_test_rtx (os, test); +- printf (", operands[%d])", test.u.opno); ++ fprintf (f, "%srtx_equal_p (", invert_p ? "!" : ""); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", operands[%d])", test.u.opno); + break; + + case rtx_test::HAVE_NUM_CLOBBERS: + gcc_assert (!is_param && value == 1); +- printf ("pnum_clobbers %s NULL", invert_p ? "==" : "!="); ++ fprintf (f, "pnum_clobbers %s NULL", invert_p ? "==" : "!="); + break; + + case rtx_test::C_TEST: + gcc_assert (!is_param && value == 1); + if (invert_p) +- printf ("!"); +- rtx_reader_ptr->print_c_condition (test.u.string); ++ fprintf (f, "!"); ++ rtx_reader_ptr->print_c_condition (f, test.u.string); + break; + + case rtx_test::ACCEPT: +@@ -4771,7 +4774,7 @@ print_test (output_state *os, const rtx_test &test, bool is_param, + } + } + +-static exit_state print_decision (output_state *, decision *, ++static exit_state print_decision (FILE *f, output_state *, decision *, + unsigned int, bool); + + /* Print code to perform S, indent each line by INDENT spaces. +@@ -4779,14 +4782,15 @@ static exit_state print_decision (output_state *, decision *, + if the state fails then the entire routine fails. */ + + static exit_state +-print_state (output_state *os, state *s, unsigned int indent, bool is_final) ++print_state (FILE *f, output_state *os, state *s, unsigned int indent, ++ bool is_final) + { + exit_state es = ES_FALLTHROUGH; + for (decision *d = s->first; d; d = d->next) +- es = print_decision (os, d, indent, is_final && !d->next); ++ es = print_decision (f, os, d, indent, is_final && !d->next); + if (es != ES_RETURNED && is_final) + { +- printf_indent (indent, "return %s;\n", get_failure_return (os->type)); ++ printf_indent (f, indent, "return %s;\n", get_failure_return (os->type)); + es = ES_RETURNED; + } + return es; +@@ -4797,7 +4801,7 @@ print_state (output_state *os, state *s, unsigned int indent, bool is_final) + match. */ + + static const char * +-print_subroutine_call (const acceptance_type &acceptance) ++print_subroutine_call (FILE *f, const acceptance_type &acceptance) + { + switch (acceptance.type) + { +@@ -4805,17 +4809,17 @@ print_subroutine_call (const acceptance_type &acceptance) + gcc_unreachable (); + + case RECOG: +- printf ("recog_%d (x1, insn, pnum_clobbers)", +- acceptance.u.subroutine_id); ++ fprintf (f, "recog_%d (x1, insn, pnum_clobbers)", ++ acceptance.u.subroutine_id); + return ">= 0"; + + case SPLIT: +- printf ("split_%d (x1, insn)", acceptance.u.subroutine_id); ++ fprintf (f, "split_%d (x1, insn)", acceptance.u.subroutine_id); + return "!= NULL_RTX"; + + case PEEPHOLE2: +- printf ("peephole2_%d (x1, insn, pmatch_len_)", +- acceptance.u.subroutine_id); ++ fprintf (f, "peephole2_%d (x1, insn, pmatch_len_)", ++ acceptance.u.subroutine_id); + return "!= NULL_RTX"; + } + gcc_unreachable (); +@@ -4825,63 +4829,65 @@ print_subroutine_call (const acceptance_type &acceptance) + INDENT and IS_FINAL are as for print_state. */ + + static exit_state +-print_acceptance (const acceptance_type &acceptance, unsigned int indent, +- bool is_final) ++print_acceptance (FILE *f, const acceptance_type &acceptance, ++ unsigned int indent, bool is_final) + { + if (acceptance.partial_p) + { + /* Defer the rest of the match to a subroutine. */ + if (is_final) + { +- printf_indent (indent, "return "); +- print_subroutine_call (acceptance); +- printf (";\n"); ++ printf_indent (f, indent, "return "); ++ print_subroutine_call (f, acceptance); ++ fprintf (f, ";\n"); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = "); +- const char *res_test = print_subroutine_call (acceptance); +- printf (";\n"); +- printf_indent (indent, "if (res %s)\n", res_test); +- printf_indent (indent + 2, "return res;\n"); ++ printf_indent (f, indent, "res = "); ++ const char *res_test = print_subroutine_call (f, acceptance); ++ fprintf (f, ";\n"); ++ printf_indent (f, indent, "if (res %s)\n", res_test); ++ printf_indent (f, indent + 2, "return res;\n"); + return ES_FALLTHROUGH; + } + } + switch (acceptance.type) + { + case SUBPATTERN: +- printf_indent (indent, "return %d;\n", acceptance.u.full.code); ++ printf_indent (f, indent, "return %d;\n", acceptance.u.full.code); + return ES_RETURNED; + + case RECOG: + if (acceptance.u.full.u.num_clobbers != 0) +- printf_indent (indent, "*pnum_clobbers = %d;\n", ++ printf_indent (f, indent, "*pnum_clobbers = %d;\n", + acceptance.u.full.u.num_clobbers); +- printf_indent (indent, "return %d; /* %s */\n", acceptance.u.full.code, ++ printf_indent (f, indent, "return %d; /* %s */\n", acceptance.u.full.code, + get_insn_name (acceptance.u.full.code)); + return ES_RETURNED; + + case SPLIT: +- printf_indent (indent, "return gen_split_%d (insn, operands);\n", ++ printf_indent (f, indent, "return gen_split_%d (insn, operands);\n", + acceptance.u.full.code); + return ES_RETURNED; + + case PEEPHOLE2: +- printf_indent (indent, "*pmatch_len_ = %d;\n", ++ printf_indent (f, indent, "*pmatch_len_ = %d;\n", + acceptance.u.full.u.match_len); + if (is_final) + { +- printf_indent (indent, "return gen_peephole2_%d (insn, operands);\n", ++ printf_indent (f, indent, ++ "return gen_peephole2_%d (insn, operands);\n", + acceptance.u.full.code); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = gen_peephole2_%d (insn, operands);\n", ++ printf_indent (f, ++ indent, "res = gen_peephole2_%d (insn, operands);\n", + acceptance.u.full.code); +- printf_indent (indent, "if (res != NULL_RTX)\n"); +- printf_indent (indent + 2, "return res;\n"); ++ printf_indent (f, indent, "if (res != NULL_RTX)\n"); ++ printf_indent (f, indent + 2, "return res;\n"); + return ES_FALLTHROUGH; + } + } +@@ -4891,7 +4897,7 @@ print_acceptance (const acceptance_type &acceptance, unsigned int indent, + /* Print code to perform D. INDENT and IS_FINAL are as for print_state. */ + + static exit_state +-print_decision (output_state *os, decision *d, unsigned int indent, ++print_decision (FILE *f, output_state *os, decision *d, unsigned int indent, + bool is_final) + { + uint64_t label; +@@ -4900,7 +4906,7 @@ print_decision (output_state *os, decision *d, unsigned int indent, + /* Make sure the rtx under test is available either in operands[] or + in an xN variable. */ + if (d->test.pos && d->test.pos_operand < 0) +- change_state (os, d->test.pos, indent); ++ change_state (f, os, d->test.pos, indent); + + /* Look for cases where a pattern routine P1 calls another pattern routine + P2 and where P1 returns X + BASE whenever P2 returns X. If IS_FINAL +@@ -4924,32 +4930,32 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + if (is_final && base == 0) + { +- printf_indent (indent, "return "); +- print_nonbool_test (os, d->test); +- printf ("; /* [-1, %d] */\n", count - 1); ++ printf_indent (f, indent, "return "); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, "; /* [-1, %d] */\n", count - 1); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = "); +- print_nonbool_test (os, d->test); +- printf (";\n"); +- printf_indent (indent, "if (res >= 0)\n"); +- printf_indent (indent + 2, "return res"); ++ printf_indent (f, indent, "res = "); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, ";\n"); ++ printf_indent (f, indent, "if (res >= 0)\n"); ++ printf_indent (f, indent + 2, "return res"); + if (base != 0) +- printf (" + %d", base); +- printf ("; /* [%d, %d] */\n", base, base + count - 1); ++ fprintf (f, " + %d", base); ++ fprintf (f, "; /* [%d, %d] */\n", base, base + count - 1); + return ES_FALLTHROUGH; + } + } + else if (d->test.kind == rtx_test::ACCEPT) +- return print_acceptance (d->test.u.acceptance, indent, is_final); ++ return print_acceptance (f, d->test.u.acceptance, indent, is_final); + else if (d->test.kind == rtx_test::SET_OP) + { +- printf_indent (indent, "operands[%d] = ", d->test.u.opno); +- print_test_rtx (os, d->test); +- printf (";\n"); +- return print_state (os, d->singleton ()->to, indent, is_final); ++ printf_indent (f, indent, "operands[%d] = ", d->test.u.opno); ++ print_test_rtx (f, os, d->test); ++ fprintf (f, ";\n"); ++ return print_state (f, os, d->singleton ()->to, indent, is_final); + } + /* Handle decisions with a single transition and a single transition + label. */ +@@ -4957,13 +4963,13 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + transition *trans = d->singleton (); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent, "/* OPTIONAL IF */\n"); ++ printf_indent (f, indent, "/* OPTIONAL IF */\n"); + + /* Print the condition associated with TRANS. Invert it if IS_FINAL, + so that we return immediately on failure and fall through on + success. */ +- printf_indent (indent, "if ("); +- print_test (os, d->test, trans->is_param, label, is_final); ++ printf_indent (f, indent, "if ("); ++ print_test (f, os, d->test, trans->is_param, label, is_final); + + /* Look for following states that would be handled by this code + on recursion. If they don't need any preparatory statements, +@@ -4979,13 +4985,13 @@ print_decision (output_state *os, decision *d, unsigned int indent, + || !test_position_available_p (os, d->test)) + break; + trans = d->first; +- printf ("\n"); ++ fprintf (f, "\n"); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent + 4, "/* OPTIONAL IF */\n"); +- printf_indent (indent + 4, "%s ", is_final ? "||" : "&&"); +- print_test (os, d->test, trans->is_param, label, is_final); ++ printf_indent (f, indent + 4, "/* OPTIONAL IF */\n"); ++ printf_indent (f, indent + 4, "%s ", is_final ? "||" : "&&"); ++ print_test (f, os, d->test, trans->is_param, label, is_final); + } +- printf (")\n"); ++ fprintf (f, ")\n"); + + /* Print the conditional code with INDENT + 2 and the fallthrough + code with indent INDENT. */ +@@ -4994,9 +5000,9 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + /* We inverted the condition above, so return failure in the + "if" body and fall through to the target of the transition. */ +- printf_indent (indent + 2, "return %s;\n", ++ printf_indent (f, indent + 2, "return %s;\n", + get_failure_return (os->type)); +- return print_state (os, to, indent, is_final); ++ return print_state (f, os, to, indent, is_final); + } + else if (to->singleton () + && to->first->test.kind == rtx_test::ACCEPT +@@ -5004,7 +5010,7 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + /* The target of the transition is a simple "return" statement. + It doesn't need any braces and doesn't fall through. */ +- if (print_acceptance (to->first->test.u.acceptance, ++ if (print_acceptance (f, to->first->test.u.acceptance, + indent + 2, true) != ES_RETURNED) + gcc_unreachable (); + return ES_FALLTHROUGH; +@@ -5018,9 +5024,9 @@ print_decision (output_state *os, decision *d, unsigned int indent, + auto_vec <bool, 32> old_seen; + old_seen.safe_splice (os->seen_vars); + +- printf_indent (indent + 2, "{\n"); +- print_state (os, trans->to, indent + 4, is_final); +- printf_indent (indent + 2, "}\n"); ++ printf_indent (f, indent + 2, "{\n"); ++ print_state (f, os, trans->to, indent + 4, is_final); ++ printf_indent (f, indent + 2, "}\n"); + + os->seen_vars.truncate (0); + os->seen_vars.splice (old_seen); +@@ -5030,48 +5036,48 @@ print_decision (output_state *os, decision *d, unsigned int indent, + else + { + /* Output the decision as a switch statement. */ +- printf_indent (indent, "switch ("); +- print_nonbool_test (os, d->test); +- printf (")\n"); ++ printf_indent (f, indent, "switch ("); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, ")\n"); + + /* Each case statement starts with the same set of valid variables. + These are also the only variables will be valid on fallthrough. */ + auto_vec <bool, 32> old_seen; + old_seen.safe_splice (os->seen_vars); + +- printf_indent (indent + 2, "{\n"); ++ printf_indent (f, indent + 2, "{\n"); + for (transition *trans = d->first; trans; trans = trans->next) + { + gcc_assert (!trans->is_param); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent + 2, "/* OPTIONAL CASE */\n"); ++ printf_indent (f, indent + 2, "/* OPTIONAL CASE */\n"); + for (int_set::iterator j = trans->labels.begin (); + j != trans->labels.end (); ++j) + { +- printf_indent (indent + 2, "case "); +- print_label_value (d->test, trans->is_param, *j); +- printf (":\n"); ++ printf_indent (f, indent + 2, "case "); ++ print_label_value (f, d->test, trans->is_param, *j); ++ fprintf (f, ":\n"); + } +- if (print_state (os, trans->to, indent + 4, is_final)) ++ if (print_state (f, os, trans->to, indent + 4, is_final)) + { + /* The state can fall through. Add an explicit break. */ + gcc_assert (!is_final); +- printf_indent (indent + 4, "break;\n"); ++ printf_indent (f, indent + 4, "break;\n"); + } +- printf ("\n"); ++ fprintf (f, "\n"); + + /* Restore the original set of valid variables. */ + os->seen_vars.truncate (0); + os->seen_vars.splice (old_seen); + } + /* Add a default case. */ +- printf_indent (indent + 2, "default:\n"); ++ printf_indent (f, indent + 2, "default:\n"); + if (is_final) +- printf_indent (indent + 4, "return %s;\n", ++ printf_indent (f, indent + 4, "return %s;\n", + get_failure_return (os->type)); + else +- printf_indent (indent + 4, "break;\n"); +- printf_indent (indent + 2, "}\n"); ++ printf_indent (f, indent + 4, "break;\n"); ++ printf_indent (f, indent + 2, "}\n"); + return is_final ? ES_RETURNED : ES_FALLTHROUGH; + } + } +@@ -5114,10 +5120,10 @@ assign_position_vars (output_state *os, state *s) + only ROOT's variable has a valid value. */ + + static void +-print_subroutine_start (output_state *os, state *s, position *root) ++print_subroutine_start (FILE *f, output_state *os, state *s, position *root) + { +- printf ("{\n rtx * const operands ATTRIBUTE_UNUSED" +- " = &recog_data.operand[0];\n"); ++ fprintf (f, "{\n rtx * const operands ATTRIBUTE_UNUSED" ++ " = &recog_data.operand[0];\n"); + os->var_to_id.truncate (0); + os->seen_vars.truncate (0); + if (root) +@@ -5140,9 +5146,9 @@ print_subroutine_start (output_state *os, state *s, position *root) + { + for (unsigned int i = 2; i < num_vars; ++i) + /* Print 8 rtx variables to a line. */ +- printf ("%s x%d", ++ fprintf (f, "%s x%d", + i == 2 ? " rtx" : (i - 2) % 8 == 0 ? ";\n rtx" : ",", i); +- printf (";\n"); ++ fprintf (f, ";\n"); + } + + /* Say that x1 is valid and the rest aren't. */ +@@ -5150,22 +5156,26 @@ print_subroutine_start (output_state *os, state *s, position *root) + os->seen_vars[1] = true; + } + if (os->type == SUBPATTERN || os->type == RECOG) +- printf (" int res ATTRIBUTE_UNUSED;\n"); ++ fprintf (f, " int res ATTRIBUTE_UNUSED;\n"); + else +- printf (" rtx_insn *res ATTRIBUTE_UNUSED;\n"); ++ fprintf (f, " rtx_insn *res ATTRIBUTE_UNUSED;\n"); + } + + /* Output the definition of pattern routine ROUTINE. */ + + static void +-print_pattern (output_state *os, pattern_routine *routine) ++print_pattern (FILE *f, output_state *os, pattern_routine *routine, ++ bool in_header = false) + { +- printf ("\nstatic int\npattern%d (", routine->pattern_id); ++ if (!in_header) ++ fprintf (f, "\nint\npattern%d (", routine->pattern_id); ++ else ++ fprintf (f, "\nextern int\npattern%d (", routine->pattern_id); + const char *sep = ""; + /* Add the top-level rtx parameter, if any. */ + if (routine->pos) + { +- printf ("%srtx x1", sep); ++ fprintf (f, "%srtx x1", sep); + sep = ", "; + } + /* Add the optional parameters. */ +@@ -5173,26 +5183,34 @@ print_pattern (output_state *os, pattern_routine *routine) + { + /* We can't easily tell whether a C condition actually reads INSN, + so add an ATTRIBUTE_UNUSED just in case. */ +- printf ("%srtx_insn *insn ATTRIBUTE_UNUSED", sep); ++ fprintf (f, "%srtx_insn *insn ATTRIBUTE_UNUSED", sep); + sep = ", "; + } + if (routine->pnum_clobbers_p) + { +- printf ("%sint *pnum_clobbers", sep); ++ fprintf (f, "%sint *pnum_clobbers", sep); + sep = ", "; + } + /* Add the "i" parameters. */ + for (unsigned int i = 0; i < routine->param_types.length (); ++i) + { +- printf ("%s%s i%d", sep, +- parameter_type_string (routine->param_types[i]), i + 1); ++ fprintf (f, "%s%s i%d", sep, ++ parameter_type_string (routine->param_types[i]), i + 1); + sep = ", "; + } +- printf (")\n"); ++ ++ if (!in_header) ++ fprintf (f, ")\n"); ++ else ++ { ++ fprintf (f, ");\n"); ++ return; ++ } ++ + os->type = SUBPATTERN; +- print_subroutine_start (os, routine->s, routine->pos); +- print_state (os, routine->s, 2, true); +- printf ("}\n"); ++ print_subroutine_start (f, os, routine->s, routine->pos); ++ print_state (f, os, routine->s, 2, true); ++ fprintf (f, "}\n"); + } + + /* Output a routine of type TYPE that implements S. PROC_ID is the +@@ -5200,9 +5218,26 @@ print_pattern (output_state *os, pattern_routine *routine) + routine. */ + + static void +-print_subroutine (output_state *os, state *s, int proc_id) +-{ +- printf ("\n"); ++print_subroutine (FILE *f, output_state *os, state *s, int proc_id, ++ bool in_header = false) ++{ ++ fprintf (f, "\n"); ++ const char *specifier_ext = "extern"; ++ const char *specifier_default = ""; ++ const char *specifier; ++ if (!in_header) ++ specifier = specifier_default; ++ else ++ specifier = specifier_ext; ++ ++ const char *end; ++ const char *end_default = ""; ++ const char *end_header = ";"; ++ if (!in_header) ++ end = end_default; ++ else ++ end = end_header; ++ + switch (os->type) + { + case SUBPATTERN: +@@ -5210,46 +5245,54 @@ print_subroutine (output_state *os, state *s, int proc_id) + + case RECOG: + if (proc_id) +- printf ("static int\nrecog_%d", proc_id); ++ fprintf (f, "%s int\nrecog_%d", specifier, proc_id); + else +- printf ("int\nrecog"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED,\n" +- "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" +- "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s int\nrecog", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED,\n" ++ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" ++ "\tint *pnum_clobbers ATTRIBUTE_UNUSED)%s\n", end); + break; + + case SPLIT: + if (proc_id) +- printf ("static rtx_insn *\nsplit_%d", proc_id); ++ fprintf (f, "%s rtx_insn *\nsplit_%d", specifier, proc_id); + else +- printf ("rtx_insn *\nsplit_insns"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s rtx_insn *\nsplit_insns", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED, " ++ "rtx_insn *insn ATTRIBUTE_UNUSED)%s\n", end); + break; + + case PEEPHOLE2: + if (proc_id) +- printf ("static rtx_insn *\npeephole2_%d", proc_id); ++ fprintf (f, "%s rtx_insn *\npeephole2_%d", specifier, proc_id); + else +- printf ("rtx_insn *\npeephole2_insns"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED,\n" +- "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" +- "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s rtx_insn *\npeephole2_insns", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED,\n" ++ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" ++ "\tint *pmatch_len_ ATTRIBUTE_UNUSED)%s\n", end); + break; + } +- print_subroutine_start (os, s, &root_pos); ++ ++ if (in_header) ++ return; ++ ++ print_subroutine_start (f, os, s, &root_pos); + if (proc_id == 0) + { +- printf (" recog_data.insn = NULL;\n"); ++ fprintf (f, " recog_data.insn = NULL;\n"); + } +- print_state (os, s, 2, true); +- printf ("}\n"); ++ print_state (f, os, s, 2, true); ++ fprintf (f, "}\n"); + } + + /* Print out a routine of type TYPE that performs ROOT. */ + + static void +-print_subroutine_group (output_state *os, routine_type type, state *root) ++print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os, ++ routine_type type, state *root) + { ++ FILE *f; ++ unsigned idx; + os->type = type; + if (use_subroutines_p) + { +@@ -5261,11 +5304,20 @@ print_subroutine_group (output_state *os, routine_type type, state *root) + /* Output the subroutines (but not ROOT itself). */ + 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) +- print_subroutine (os, s, i + 1); ++ { ++ f = choose_output (vec, idx); ++ print_subroutine (f, os, s, i + 1); ++ } + } + /* Output the main routine. */ +- print_subroutine (os, root, 0); ++ f = choose_output (vec, idx); ++ print_subroutine (f, os, root, 0); + } + + /* Return the rtx pattern for the list of rtxes in a define_peephole2. */ +@@ -5336,6 +5388,29 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr) + return true; + } + ++auto_vec<FILE *, 10> output_files; ++char header_name[255]; ++FILE *header = NULL; ++ ++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); ++ return true; ++ } ++ if (arg[1] == 'H') ++ { ++ snprintf (header_name, 255, "%s", &arg[2]); ++ header = fopen (header_name, "w"); ++ return true; ++ } ++ return false; ++} ++ + int + main (int argc, const char **argv) + { +@@ -5343,10 +5418,17 @@ main (int argc, const char **argv) + + progname = "genrecog"; + +- if (!init_rtx_reader_args (argc, argv)) ++ if (!init_rtx_reader_args_cb (argc, argv, handle_arg)) + return (FATAL_EXIT_CODE); + +- write_header (); ++ if (output_files.is_empty ()) ++ output_files.safe_push (stdout); ++ ++ for (auto f : output_files) ++ write_header (f, header_name); ++ ++ FILE *file = NULL; ++ unsigned file_idx; + + /* Read the machine description. */ + +@@ -5354,6 +5436,7 @@ 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; +@@ -5387,8 +5470,8 @@ main (int argc, const char **argv) + + /* Declare the gen_split routine that we'll call if the + pattern matches. The definition comes from insn-emit.cc. */ +- printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n", +- info.index); ++ fprintf (header, "extern rtx_insn *gen_split_%d " ++ "(rtx_insn *, rtx *);\n", info.index); + break; + + case DEFINE_PEEPHOLE2: +@@ -5399,8 +5482,8 @@ main (int argc, const char **argv) + + /* Declare the gen_peephole2 routine that we'll call if the + pattern matches. The definition comes from insn-emit.cc. */ +- printf ("extern rtx_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n", +- info.index); ++ fprintf (header, "extern rtx_insn *gen_peephole2_%d " ++ "(rtx_insn *, rtx *);\n", info.index); + break; + + default: +@@ -5411,7 +5494,8 @@ main (int argc, const char **argv) + if (have_error) + return FATAL_EXIT_CODE; + +- puts ("\n\n"); ++ for (auto f : output_files) ++ fprintf (f, "%s", "\n\n"); + + /* Optimize each routine in turn. */ + optimize_subroutine_group ("recog", &insn_root); +@@ -5433,15 +5517,27 @@ main (int argc, const char **argv) + /* Print out the routines that we just created. */ + unsigned int i; + pattern_routine *routine; ++ + FOR_EACH_VEC_ELT (patterns, i, routine) +- print_pattern (&os, routine); ++ 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 out the matching routines. */ +- print_subroutine_group (&os, RECOG, &insn_root); +- print_subroutine_group (&os, SPLIT, &split_root); +- print_subroutine_group (&os, PEEPHOLE2, &peephole2_root); ++ print_subroutine_group (output_files, header, &os, RECOG, &insn_root); ++ print_subroutine_group (output_files, header, &os, SPLIT, &split_root); ++ print_subroutine_group (output_files, header, &os, PEEPHOLE2, &peephole2_root); ++ ++ fclose (header); + +- fflush (stdout); +- return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); ++ int ret = SUCCESS_EXIT_CODE; ++ for (FILE *f : output_files) ++ if (fclose (f) != 0) ++ ret = FATAL_EXIT_CODE; ++ return ret; + } +diff --git a/gcc/gentarget-def.cc b/gcc/gentarget-def.cc +index 061b1e7247c1..3a462560cc1b 100644 +--- a/gcc/gentarget-def.cc ++++ b/gcc/gentarget-def.cc +@@ -191,7 +191,7 @@ def_target_insn (const char *name, const char *prototype) + printf ("target_have_%s (void)\n", name); + printf ("{\n"); + printf (" return "); +- rtx_reader_ptr->print_c_condition (test); ++ rtx_reader_ptr->print_c_condition (stdout, test); + printf (";\n"); + printf ("}\n"); + } +diff --git a/gcc/read-md.cc b/gcc/read-md.cc +index 93d1ea437812..aeb1cced00d0 100644 +--- a/gcc/read-md.cc ++++ b/gcc/read-md.cc +@@ -192,9 +192,9 @@ md_reader::fprint_c_condition (FILE *outf, const char *cond) + /* Special fprint_c_condition for writing to STDOUT. */ + + void +-md_reader::print_c_condition (const char *cond) ++md_reader::print_c_condition (FILE *outf, const char *cond) + { +- fprint_c_condition (stdout, cond); ++ fprint_c_condition (outf, cond); + } + + /* A vfprintf-like function for reporting an error against line LINENO +diff --git a/gcc/read-md.h b/gcc/read-md.h +index 9703551a8fd4..2c04f536e7d1 100644 +--- a/gcc/read-md.h ++++ b/gcc/read-md.h +@@ -205,7 +205,7 @@ class md_reader + + const char *join_c_conditions (const char *cond1, const char *cond2); + void fprint_c_condition (FILE *outf, const char *cond); +- void print_c_condition (const char *cond); ++ void print_c_condition (FILE *outf, const char *cond); + + /* Defined in read-rtl.cc. */ + const char *apply_iterator_to_string (const char *string); +-- +2.50.1 + diff --git a/14.3.0/gentoo/README.history b/14.3.0/gentoo/README.history index 3c130be..85297d1 100644 --- a/14.3.0/gentoo/README.history +++ b/14.3.0/gentoo/README.history @@ -1,3 +1,9 @@ + 4 3 August 2025 + + + 80_all_genoutput-Accelerate-the-place_operands-function.patch + + 81_all_genemit-Distribute-evenly-to-files-PR111600.patch + + 82_all_genrecog-Split-into-separate-partitions-PR111600.patch + 3 2 August 2025 - 80_all-libsanitizer-Fix-build-with-glibc-2.42.patch
