commit:     dee36e2a3bc87096002eb97f0bd6847122bb40b1
Author:     Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Sun Aug  3 09:03:36 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Aug  3 09:03:36 2025 +0000
URL:        https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=dee36e2a

13.3.0: backport more build speed improvements

We already have a bunch so what's a few more?

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 | 1360 ++++++++++++++++++++
 13.3.0/gentoo/README.history                       |    6 +
 4 files changed, 1803 insertions(+)

diff --git 
a/13.3.0/gentoo/94_all_genoutput-Accelerate-the-place_operands-function.patch 
b/13.3.0/gentoo/94_all_genoutput-Accelerate-the-place_operands-function.patch
new file mode 100644
index 0000000..7663658
--- /dev/null
+++ 
b/13.3.0/gentoo/94_all_genoutput-Accelerate-the-place_operands-function.patch
@@ -0,0 +1,247 @@
+From 6b737d8e61fb341317c2cad4dbd68a9eb156c1d4 Mon Sep 17 00:00:00 2001
+Message-ID: 
<6b737d8e61fb341317c2cad4dbd68a9eb156c1d4.1754207024.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 163e8dfef4ca..b8d41d428028 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;
+@@ -173,8 +176,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 *);
+@@ -527,10 +530,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 = "";
+@@ -549,9 +560,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;
+ 
+@@ -561,6 +569,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.  */
+ 
+@@ -568,6 +616,7 @@ static void
+ place_operands (class data *d)
+ {
+   struct operand_data *od, *od2;
++  struct operand_data **slot;
+   int i;
+ 
+   if (d->n_operands == 0)
+@@ -576,23 +625,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.  */
+@@ -604,6 +654,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;
+@@ -1007,6 +1071,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/13.3.0/gentoo/95_all_genemit-Distribute-evenly-to-files-PR111600.patch 
b/13.3.0/gentoo/95_all_genemit-Distribute-evenly-to-files-PR111600.patch
new file mode 100644
index 0000000..34f1730
--- /dev/null
+++ b/13.3.0/gentoo/95_all_genemit-Distribute-evenly-to-files-PR111600.patch
@@ -0,0 +1,190 @@
+From 1c8da06e0460625beb85da920481248d0cac4325 Mon Sep 17 00:00:00 2001
+Message-ID: 
<1c8da06e0460625beb85da920481248d0cac4325.1754207024.git....@gentoo.org>
+In-Reply-To: 
<6b737d8e61fb341317c2cad4dbd68a9eb156c1d4.1754207024.git....@gentoo.org>
+References: 
<6b737d8e61fb341317c2cad4dbd68a9eb156c1d4.1754207024.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 18c95e3f6412..7da969920303 100644
+--- a/gcc/genemit.cc
++++ b/gcc/genemit.cc
+@@ -896,14 +896,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;
+@@ -924,47 +925,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))
+       {
+@@ -990,10 +965,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);
+@@ -1006,5 +981,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 f941f76a739f..895d544e0721 100644
+--- a/gcc/gensupport.cc
++++ b/gcc/gensupport.cc
+@@ -3369,3 +3369,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 510ba19405e4..fb0506aba559 100644
+--- a/gcc/gensupport.h
++++ b/gcc/gensupport.h
+@@ -225,5 +225,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/13.3.0/gentoo/96_all_genrecog-Split-into-separate-partitions-PR111600.patch 
b/13.3.0/gentoo/96_all_genrecog-Split-into-separate-partitions-PR111600.patch
new file mode 100644
index 0000000..5834925
--- /dev/null
+++ 
b/13.3.0/gentoo/96_all_genrecog-Split-into-separate-partitions-PR111600.patch
@@ -0,0 +1,1360 @@
+From e90ec925b65660ab853120d77b699dc17c8a9814 Mon Sep 17 00:00:00 2001
+Message-ID: 
<e90ec925b65660ab853120d77b699dc17c8a9814.1754207024.git....@gentoo.org>
+In-Reply-To: 
<6b737d8e61fb341317c2cad4dbd68a9eb156c1d4.1754207024.git....@gentoo.org>
+References: 
<6b737d8e61fb341317c2cad4dbd68a9eb156c1d4.1754207024.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      |   2 +-
+ gcc/genrecog.cc      | 552 +++++++++++++++++++++++++------------------
+ gcc/gentarget-def.cc |   2 +-
+ gcc/read-md.cc       |   4 +-
+ gcc/read-md.h        |   2 +-
+ 8 files changed, 357 insertions(+), 242 deletions(-)
+
+diff --git a/gcc/Makefile.in b/gcc/Makefile.in
+index 41abe03f7948..8b197a1e3f4a 100644
+--- a/gcc/Makefile.in
++++ b/gcc/Makefile.in
+@@ -239,6 +239,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
+@@ -1350,7 +1356,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 \
+@@ -1829,8 +1835,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) \
+@@ -2447,7 +2453,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) \
+@@ -2476,7 +2483,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
+ 
+@@ -2514,6 +2521,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 1a89f3058f73..12f7d9814889 100644
+--- a/gcc/configure.ac
++++ b/gcc/configure.ac
+@@ -949,10 +949,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 28655fa44706..caa1783ccc65 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 bdd65ef7d7a1..bc01b0fd7a91 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:
+diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc
+index 6dd375da5e35..17358652b99b 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 &param)
++print_parameter_value (FILE *f, const parameter &param)
+ {
+   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 &param)
+       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 &param)
+ /* 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 35f9a3142c86..79e53f724ad2 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 46ab9065e3e4..cf726cdfc4bd 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 2adcb58478fe..bd4d99ec3bdb 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/13.3.0/gentoo/README.history b/13.3.0/gentoo/README.history
index 3424374..575c188 100644
--- a/13.3.0/gentoo/README.history
+++ b/13.3.0/gentoo/README.history
@@ -1,3 +1,9 @@
+8      3 August 2025
+
+       + 94_all_genoutput-Accelerate-the-place_operands-function.patch
+       + 95_all_genemit-Distribute-evenly-to-files-PR111600.patch
+       + 96_all_genrecog-Split-into-separate-partitions-PR111600.patch
+
 7      2 August 2025
 
        - 94_all-libsanitizer-Fix-build-with-glibc-2.42.patch

Reply via email to