https://gcc.gnu.org/PR54179
https://inbox.sourceware.org/gcc-patches/de0f7bdc-d236-4f5b-9504-d5bfb215d023@gmail.com/

From 366eeb9d3b5e861291be112d66940d98e9dc2693 Mon Sep 17 00:00:00 2001
From: Robin Dapp <rdapp.gcc@gmail.com>
Date: Fri, 27 Oct 2023 21:04:25 +0200
Subject: [PATCH 14/14] genemit: Split insn-emit.cc into ten files.

After working with Sam off-list (thanks) I managed to get hppa to
build.  Initially it looked as if hppa just had a very small number of
instruction patterns so we wouldn't generate all 10 output files.
However, the actual issue (which we will only hit with a low
pattern count) was with counting all the patterns vs only counting
the patterns that will be output.  A wrong pattern count lead to
prematurely stopping to write output files.

With that corrected, hppa "just works" until I hit linker errors
due to relocations - most likely unrelated:

bin/ld: unwind-dw2-fde-dip_s.o(.data.rel.ro+0): cannot handle
R_PARISC_FPTR64 for __pthread_key_create@@GLIBC_2.34

Attached is v3 that has been bootstrapped and tested on x86 and power10,
aarch64 bootstrap was ok, testsuite is still running.  A riscv build and
testsuite run was successful as well.

Regards
 Robin

>From 248744c328440bff9cc339d2bf622852cbaac343 Mon Sep 17 00:00:00 2001
From: Robin Dapp <rdapp@ventanamicro.com>
Date: Thu, 12 Oct 2023 11:23:26 +0200
Subject: [PATCH v3] genemit: Split insn-emit.cc into several partitions.

On riscv insn-emit.cc has grown to over 1.2 mio lines of code and
compiling it takes considerable time.
Therefore, this patch adjust genemit to create several partitions
(insn-emit-1.cc to insn-emit-n.cc).  The available patterns are
written to the given files in a sequential fashion.

Similar to match.pd a configure option --with-emitinsn-partitions=num
is introduced that makes the number of partition configurable.

gcc/ChangeLog:

	PR bootstrap/84402
	PR target/111600

	* Makefile.in: Handle split insn-emit.cc.
	* configure: Regenerate.
	* configure.ac: Add --with-insnemit-partitions.
	* genemit.cc (output_peephole2_scratches): Print to file instead
	of stdout.
	(print_code): Ditto.
	(gen_rtx_scratch): Ditto.
	(gen_exp): Ditto.
	(gen_emit_seq): Ditto.
	(emit_c_code): Ditto.
	(gen_insn): Ditto.
	(gen_expand): Ditto.
	(gen_split): Ditto.
	(output_add_clobbers): Ditto.
	(output_added_clobbers_hard_reg_p): Ditto.
	(print_overload_arguments): Ditto.
	(print_overload_test): Ditto.
	(handle_overloaded_code_for): Ditto.
	(handle_overloaded_gen): Ditto.
	(print_header): New function.
	(handle_arg): New function.
	(main): Split output into 10 files.
	* gensupport.cc (count_patterns): New function.
	* gensupport.h (count_patterns): Define.
	* read-md.cc (md_reader::print_md_ptr_loc): Add file argument.
	* read-md.h (class md_reader): Change definition.
---
 gcc/Makefile.in   |  36 ++-
 gcc/configure     |  24 +-
 gcc/configure.ac  |  13 ++
 gcc/genemit.cc    | 542 +++++++++++++++++++++++++---------------------
 gcc/gensupport.cc |  55 +++++
 gcc/gensupport.h  |   1 +
 gcc/read-md.cc    |   4 +-
 gcc/read-md.h     |   2 +-
 8 files changed, 422 insertions(+), 255 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2c16b14ad0f3..b0c118e6d189 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -232,6 +232,13 @@ GIMPLE_MATCH_PD_SEQ_O = $(patsubst %, gimple-match-%.o, $(MATCH_SPLITS_SEQ))
 GENERIC_MATCH_PD_SEQ_SRC = $(patsubst %, generic-match-%.cc, $(MATCH_SPLITS_SEQ))
 GENERIC_MATCH_PD_SEQ_O = $(patsubst %, generic-match-%.o, $(MATCH_SPLITS_SEQ))
 
+# The number of splits to be made for the insn-emit files.
+NUM_INSNEMIT_SPLITS = @DEFAULT_INSNEMIT_PARTITIONS@
+INSNEMIT_SPLITS_SEQ = $(wordlist 1,$(NUM_INSNEMIT_SPLITS),$(one_to_9999))
+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))
+
 # 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
@@ -1331,7 +1338,7 @@ OBJS = \
 	insn-attrtab.o \
 	insn-automata.o \
 	insn-dfatab.o \
-	insn-emit.o \
+	$(INSNEMIT_SEQ_O) \
 	insn-extract.o \
 	insn-latencytab.o \
 	insn-modes.o \
@@ -1817,7 +1824,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 insn-emit.cc insn-extract.cc insn-peep.cc \
+ insn-output.cc insn-recog.cc $(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) \
@@ -2434,11 +2442,11 @@ $(common_out_object_file): $(common_out_file)
 # and compile them.
 
 .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \
-  insn-emit.cc insn-recog.cc 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) gimple-match-auto.h generic-match-auto.h \
-  insn-target-def.h
+  $(INSNEMIT_SEQ_SRC) insn-recog.cc 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) \
+  gimple-match-auto.h generic-match-auto.h insn-target-def.h
 
 # Dependencies for the md file.  The first time through, we just assume
 # the md file itself and the generated dependency file (in order to get
@@ -2461,7 +2469,7 @@ s-mddeps: $(md_file) $(MD_INCLUDES) build/genmddeps$(build_exeext)
 simple_rtl_generated_h	= insn-attr.h insn-attr-common.h insn-codes.h \
 			  insn-config.h insn-flags.h insn-target-def.h
 
-simple_rtl_generated_c	= insn-automata.cc insn-emit.cc \
+simple_rtl_generated_c	= insn-automata.cc \
 			  insn-extract.cc insn-output.cc \
 			  insn-peep.cc insn-recog.cc
 
@@ -2490,8 +2498,20 @@ $(simple_generated_c:insn-%.cc=s-%): s-%: build/gen%$(build_exeext)
 	$(SHELL) $(srcdir)/../move-if-change tmp-$*.cc insn-$*.cc
 	$(STAMP) s-$*
 
+# genemit splits its output into different files and doesn't write to
+# stdout. (but rather to tmp-emit-01.cc..tmp-emit-10.cc)
+$(INSNEMIT_SEQ_SRC): s-tmp-emit; @true
+s-tmp-emit: build/genemit$(build_exeext) $(MD_DEPS) insn-conditions.md
+	$(RUN_GEN) build/genemit$(build_exeext) $(md_file) insn-conditions.md \
+	  $(addprefix -O,${INSNEMIT_SEQ_TMP})
+	$(foreach id, $(INSNEMIT_SPLITS_SEQ), \
+	  $(SHELL) $(srcdir)/../move-if-change tmp-emit-$(id).cc \
+	  insn-emit-$(id).cc;)
+	$(STAMP) s-tmp-emit
+
 # gencheck doesn't read the machine description, and the file produced
 # doesn't use the insn-* convention.
+
 tree-check.h: s-check ; @true
 s-check : build/gencheck$(build_exeext)
 	$(RUN_GEN) build/gencheck$(build_exeext) > tmp-check.h
diff --git a/gcc/configure b/gcc/configure
index 61c18a13ab7b..9a8d7ab8b8fa 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -838,6 +838,7 @@ enable_gcov
 enable_shared
 enable_fixed_point
 enable_decimal_float
+DEFAULT_INSNEMIT_PARTITIONS
 DEFAULT_MATCHPD_PARTITIONS
 with_float
 with_cpu
@@ -967,6 +968,7 @@ enable_multilib
 enable_multiarch
 with_stack_clash_protection_guard_size
 with_matchpd_partitions
+with_insnemit_partitions
 enable___cxa_atexit
 enable_decimal_float
 enable_fixed_point
@@ -1837,6 +1839,9 @@ Optional Packages:
   --with-matchpd-partitions=num
                           Set the number of partitions to make for gimple and
                           generic when splitting match.pd. [default=10]
+  --with-insnemit-partitions=num
+                          Set the number of partitions of insn-emit.cc for
+                          genemit to create. [default=10]
   --with-dwarf2           force the default debug format to be DWARF 2 (or
                           later)
   --with-specs=SPECS      add SPECS to driver command-line processing
@@ -7915,6 +7920,21 @@ fi
 
 
 
+# Specify the number of splits of insn-emit.cc to generate.
+
+# Check whether --with-insnemit-partitions was given.
+if test "${with_insnemit_partitions+set}" = set; then :
+  withval=$with_insnemit_partitions; DEFAULT_INSNEMIT_PARTITIONS="$with_insnemit_partitions"
+else
+  DEFAULT_INSNEMIT_PARTITIONS=10
+fi
+
+if (test $DEFAULT_INSNEMIT_PARTITIONS -lt 1); then
+  as_fn_error $? "Invalid value $DEFAULT_INSNEMIT_PARTITIONS for --with-insnemit-partitions. Cannot be negative." "$LINENO" 5
+fi
+
+
+
 # Enable __cxa_atexit for C++.
 # Check whether --enable-__cxa_atexit was given.
 if test "${enable___cxa_atexit+set}" = set; then :
@@ -19868,7 +19888,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19871 "configure"
+#line 19891 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -19974,7 +19994,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19977 "configure"
+#line 19997 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index c15b65367419..66b9eaa99e08 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -934,6 +934,19 @@ fi
 
 AC_SUBST(DEFAULT_MATCHPD_PARTITIONS)
 
+# Specify the number of splits of insn-emit.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]])],
+[DEFAULT_INSNEMIT_PARTITIONS="$with_insnemit_partitions"], [DEFAULT_INSNEMIT_PARTITIONS=10])
+if (test $DEFAULT_INSNEMIT_PARTITIONS -lt 1); then
+  AC_MSG_ERROR(m4_normalize([
+		Invalid value $DEFAULT_INSNEMIT_PARTITIONS for --with-insnemit-partitions. \
+		Cannot be negative.]))
+fi
+
+AC_SUBST(DEFAULT_INSNEMIT_PARTITIONS)
+
 # Enable __cxa_atexit for C++.
 AC_ARG_ENABLE(__cxa_atexit,
 [AS_HELP_STRING([--enable-__cxa_atexit], [enable __cxa_atexit for C++])],
diff --git a/gcc/genemit.cc b/gcc/genemit.cc
index 33c9ec05d6fc..18c95e3f6412 100644
--- a/gcc/genemit.cc
+++ b/gcc/genemit.cc
@@ -49,29 +49,29 @@ struct clobber_ent
   struct clobber_ent *next;
 };
 
-static void output_peephole2_scratches	(rtx);
+static void output_peephole2_scratches	(rtx, FILE*);
 
 /* True for <X>_optab if that optab isn't allowed to fail.  */
 static bool nofail_optabs[NUM_OPTABS];
 
 static void
-print_code (RTX_CODE code)
+print_code (RTX_CODE code, FILE *file)
 {
   const char *p1;
   for (p1 = GET_RTX_NAME (code); *p1; p1++)
-    putchar (TOUPPER (*p1));
+    fprintf (file, "%c", TOUPPER (*p1));
 }
 
 static void
-gen_rtx_scratch (rtx x, enum rtx_code subroutine_type)
+gen_rtx_scratch (rtx x, enum rtx_code subroutine_type, FILE *file)
 {
   if (subroutine_type == DEFINE_PEEPHOLE2)
     {
-      printf ("operand%d", XINT (x, 0));
+      fprintf (file, "operand%d", XINT (x, 0));
     }
   else
     {
-      printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
+      fprintf (file, "gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
     }
 }
 
@@ -79,7 +79,8 @@ gen_rtx_scratch (rtx x, enum rtx_code subroutine_type)
    substituting any operand references appearing within.  */
 
 static void
-gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
+gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info,
+	 FILE *file)
 {
   RTX_CODE code;
   int i;
@@ -89,7 +90,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
 
   if (x == 0)
     {
-      printf ("NULL_RTX");
+      fprintf (file, "NULL_RTX");
       return;
     }
 
@@ -103,67 +104,67 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
 	{
 	  if (used[XINT (x, 0)])
 	    {
-	      printf ("copy_rtx (operand%d)", XINT (x, 0));
+	      fprintf (file, "copy_rtx (operand%d)", XINT (x, 0));
 	      return;
 	    }
 	  used[XINT (x, 0)] = 1;
 	}
-      printf ("operand%d", XINT (x, 0));
+      fprintf (file, "operand%d", XINT (x, 0));
       return;
 
     case MATCH_OP_DUP:
-      printf ("gen_rtx_fmt_");
+      fprintf (file, "gen_rtx_fmt_");
       for (i = 0; i < XVECLEN (x, 1); i++)
-	printf ("e");
-      printf (" (GET_CODE (operand%d), ", XINT (x, 0));
+	fprintf (file, "e");
+      fprintf (file, " (GET_CODE (operand%d), ", XINT (x, 0));
       if (GET_MODE (x) == VOIDmode)
-	printf ("GET_MODE (operand%d)", XINT (x, 0));
+	fprintf (file, "GET_MODE (operand%d)", XINT (x, 0));
       else
-	printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
+	fprintf (file, "%smode", GET_MODE_NAME (GET_MODE (x)));
       for (i = 0; i < XVECLEN (x, 1); i++)
 	{
-	  printf (",\n\t\t");
-	  gen_exp (XVECEXP (x, 1, i), subroutine_type, used, info);
+	  fprintf (file, ",\n\t\t");
+	  gen_exp (XVECEXP (x, 1, i), subroutine_type, used, info, file);
 	}
-      printf (")");
+      fprintf (file, ")");
       return;
 
     case MATCH_OPERATOR:
-      printf ("gen_rtx_fmt_");
+      fprintf (file, "gen_rtx_fmt_");
       for (i = 0; i < XVECLEN (x, 2); i++)
-	printf ("e");
-      printf (" (GET_CODE (operand%d)", XINT (x, 0));
-      printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
+	fprintf (file, "e");
+      fprintf (file, " (GET_CODE (operand%d)", XINT (x, 0));
+      fprintf (file, ", %smode", GET_MODE_NAME (GET_MODE (x)));
       for (i = 0; i < XVECLEN (x, 2); i++)
 	{
-	  printf (",\n\t\t");
-	  gen_exp (XVECEXP (x, 2, i), subroutine_type, used, info);
+	  fprintf (file, ",\n\t\t");
+	  gen_exp (XVECEXP (x, 2, i), subroutine_type, used, info, file);
 	}
-      printf (")");
+      fprintf (file, ")");
       return;
 
     case MATCH_PARALLEL:
     case MATCH_PAR_DUP:
-      printf ("operand%d", XINT (x, 0));
+      fprintf (file, "operand%d", XINT (x, 0));
       return;
 
     case MATCH_SCRATCH:
-      gen_rtx_scratch (x, subroutine_type);
+      gen_rtx_scratch (x, subroutine_type, file);
       return;
 
     case PC:
-      printf ("pc_rtx");
+      fprintf (file, "pc_rtx");
       return;
     case RETURN:
-      printf ("ret_rtx");
+      fprintf (file, "ret_rtx");
       return;
     case SIMPLE_RETURN:
-      printf ("simple_return_rtx");
+      fprintf (file, "simple_return_rtx");
       return;
     case CLOBBER:
       if (REG_P (XEXP (x, 0)))
 	{
-	  printf ("gen_hard_reg_clobber (%smode, %i)",
+	  fprintf (file, "gen_hard_reg_clobber (%smode, %i)",
 		  GET_MODE_NAME (GET_MODE (XEXP (x, 0))),
 		  REGNO (XEXP (x, 0)));
 	  return;
@@ -172,22 +173,22 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
 
     case CONST_INT:
       if (INTVAL (x) == 0)
-	printf ("const0_rtx");
+	fprintf (file, "const0_rtx");
       else if (INTVAL (x) == 1)
-	printf ("const1_rtx");
+	fprintf (file, "const1_rtx");
       else if (INTVAL (x) == -1)
-	printf ("constm1_rtx");
+	fprintf (file, "constm1_rtx");
       else if (-MAX_SAVED_CONST_INT <= INTVAL (x)
 	       && INTVAL (x) <= MAX_SAVED_CONST_INT)
-	printf ("const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+	fprintf (file, "const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
 		(int) INTVAL (x));
       else if (INTVAL (x) == STORE_FLAG_VALUE)
-	printf ("const_true_rtx");
+	fprintf (file, "const_true_rtx");
       else
 	{
-	  printf ("GEN_INT (");
-	  printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));
-	  printf (")");
+	  fprintf (file, "GEN_INT (");
+	  fprintf (file, HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));
+	  fprintf (file, ")");
 	}
       return;
 
@@ -195,7 +196,7 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
       /* Handle `const_double_zero' rtx.  */
       if (CONST_DOUBLE_REAL_VALUE (x)->cl == rvc_zero)
 	{
-	  printf ("CONST_DOUBLE_ATOF (\"0\", %smode)",
+	  fprintf (file, "CONST_DOUBLE_ATOF (\"0\", %smode)",
 		  GET_MODE_NAME (GET_MODE (x)));
 	  return;
 	}
@@ -210,12 +211,12 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
       break;
     }
 
-  printf ("gen_rtx_");
-  print_code (code);
-  printf (" (");
+  fprintf (file, "gen_rtx_");
+  print_code (code, file);
+  fprintf (file, " (");
   if (!always_void_p (code))
     {
-      printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
+      fprintf (file, "%smode", GET_MODE_NAME (GET_MODE (x)));
       sep = ",\n\t";
     }
 
@@ -225,41 +226,41 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
     {
       if (fmt[i] == '0')
 	break;
-      fputs (sep, stdout);
+      fputs (sep, file);
       switch (fmt[i])
 	{
 	case 'e': case 'u':
-	  gen_exp (XEXP (x, i), subroutine_type, used, info);
+	  gen_exp (XEXP (x, i), subroutine_type, used, info, file);
 	  break;
 
 	case 'i':
-	  printf ("%u", XINT (x, i));
+	  fprintf (file, "%u", XINT (x, i));
 	  break;
 
 	case 'r':
-	  printf ("%u", REGNO (x));
+	  fprintf (file, "%u", REGNO (x));
 	  break;
 
 	case 'p':
 	  /* We don't have a way of parsing polynomial offsets yet,
 	     and hopefully never will.  */
-	  printf ("%d", SUBREG_BYTE (x).to_constant ());
+	  fprintf (file, "%d", SUBREG_BYTE (x).to_constant ());
 	  break;
 
 	case 's':
-	  printf ("\"%s\"", XSTR (x, i));
+	  fprintf (file, "\"%s\"", XSTR (x, i));
 	  break;
 
 	case 'E':
 	  {
 	    int j;
-	    printf ("gen_rtvec (%d", XVECLEN (x, i));
+	    fprintf (file, "gen_rtvec (%d", XVECLEN (x, i));
 	    for (j = 0; j < XVECLEN (x, i); j++)
 	      {
-		printf (",\n\t\t");
-		gen_exp (XVECEXP (x, i, j), subroutine_type, used, info);
+		fprintf (file, ",\n\t\t");
+		gen_exp (XVECEXP (x, i, j), subroutine_type, used, info, file);
 	      }
-	    printf (")");
+	    fprintf (file, ")");
 	    break;
 	  }
 
@@ -268,14 +269,14 @@ gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info)
 	}
       sep = ",\n\t";
     }
-  printf (")");
+  fprintf (file, ")");
 }
 
 /* Output code to emit the instruction patterns in VEC, with each element
    becoming a separate instruction.  USED is as for gen_exp.  */
 
 static void
-gen_emit_seq (rtvec vec, char *used, md_rtx_info *info)
+gen_emit_seq (rtvec vec, char *used, md_rtx_info *info, FILE *file)
 {
   for (int i = 0, len = GET_NUM_ELEM (vec); i < len; ++i)
     {
@@ -283,17 +284,17 @@ gen_emit_seq (rtvec vec, char *used, md_rtx_info *info)
       rtx next = RTVEC_ELT (vec, i);
       if (const char *name = get_emit_function (next))
 	{
-	  printf ("  %s (", name);
-	  gen_exp (next, DEFINE_EXPAND, used, info);
-	  printf (");\n");
+	  fprintf (file, "  %s (", name);
+	  gen_exp (next, DEFINE_EXPAND, used, info, file);
+	  fprintf (file, ");\n");
 	  if (!last_p && needs_barrier_p (next))
-	    printf ("  emit_barrier ();");
+	    fprintf (file, "  emit_barrier ();");
 	}
       else
 	{
-	  printf ("  emit (");
-	  gen_exp (next, DEFINE_EXPAND, used, info);
-	  printf (", %s);\n", last_p ? "false" : "true");
+	  fprintf (file, "  emit (");
+	  gen_exp (next, DEFINE_EXPAND, used, info, file);
+	  fprintf (file, ", %s);\n", last_p ? "false" : "true");
 	}
     }
 }
@@ -303,27 +304,27 @@ gen_emit_seq (rtvec vec, char *used, md_rtx_info *info)
    for use in error messages.  */
 
 static void
-emit_c_code (const char *code, bool can_fail_p, const char *name)
+emit_c_code (const char *code, bool can_fail_p, const char *name, FILE *file)
 {
   if (can_fail_p)
-    printf ("#define FAIL return (end_sequence (), _val)\n");
+    fprintf (file, "#define FAIL return (end_sequence (), _val)\n");
   else
-    printf ("#define FAIL _Pragma (\"GCC error \\\"%s cannot FAIL\\\"\")"
+    fprintf (file, "#define FAIL _Pragma (\"GCC error \\\"%s cannot FAIL\\\"\")"
 	    " (void)0\n", name);
-  printf ("#define DONE return (_val = get_insns (), "
+  fprintf (file, "#define DONE return (_val = get_insns (), "
 	  "end_sequence (), _val)\n");
 
-  rtx_reader_ptr->print_md_ptr_loc (code);
-  printf ("%s\n", code);
+  rtx_reader_ptr->print_md_ptr_loc (code, file);
+  fprintf (file, "%s\n", code);
 
-  printf ("#undef DONE\n");
-  printf ("#undef FAIL\n");
+  fprintf (file, "#undef DONE\n");
+  fprintf (file, "#undef FAIL\n");
 }
 
 /* Generate the `gen_...' function for a DEFINE_INSN.  */
 
 static void
-gen_insn (md_rtx_info *info)
+gen_insn (md_rtx_info *info, FILE *file)
 {
   struct pattern_stats stats;
   int i;
@@ -409,7 +410,7 @@ gen_insn (md_rtx_info *info)
   if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
     return;
 
-  printf ("/* %s:%d */\n", info->loc.filename, info->loc.lineno);
+  fprintf (file, "/* %s:%d */\n", info->loc.filename, info->loc.lineno);
 
   /* Find out how many operands this function has.  */
   get_pattern_stats (&stats, XVEC (insn, 1));
@@ -417,17 +418,17 @@ gen_insn (md_rtx_info *info)
     fatal_at (info->loc, "match_dup operand number has no match_operand");
 
   /* Output the function name and argument declarations.  */
-  printf ("rtx\ngen_%s (", XSTR (insn, 0));
+  fprintf (file, "rtx\ngen_%s (", XSTR (insn, 0));
   if (stats.num_generator_args)
     for (i = 0; i < stats.num_generator_args; i++)
       if (i)
-	printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i);
+	fprintf (file, ",\n\trtx operand%d ATTRIBUTE_UNUSED", i);
       else
-	printf ("rtx operand%d ATTRIBUTE_UNUSED", i);
+	fprintf (file, "rtx operand%d ATTRIBUTE_UNUSED", i);
   else
-    printf ("void");
-  printf (")\n");
-  printf ("{\n");
+    fprintf (file, "void");
+  fprintf (file, ")\n");
+  fprintf (file, "{\n");
 
   /* Output code to construct and return the rtl for the instruction body.  */
 
@@ -436,16 +437,16 @@ gen_insn (md_rtx_info *info)
   char *used = (XVECLEN (insn, 1) == 1
 		? NULL
 		: XCNEWVEC (char, stats.num_generator_args));
-  printf ("  return ");
-  gen_exp (pattern, DEFINE_INSN, used, info);
-  printf (";\n}\n\n");
+  fprintf (file, "  return ");
+  gen_exp (pattern, DEFINE_INSN, used, info, file);
+  fprintf (file, ";\n}\n\n");
   XDELETEVEC (used);
 }
 
 /* Generate the `gen_...' function for a DEFINE_EXPAND.  */
 
 static void
-gen_expand (md_rtx_info *info)
+gen_expand (md_rtx_info *info, FILE *file)
 {
   struct pattern_stats stats;
   int i;
@@ -466,17 +467,17 @@ gen_expand (md_rtx_info *info)
 			 "numbers above all other operands", XSTR (expand, 0));
 
   /* Output the function name and argument declarations.  */
-  printf ("rtx\ngen_%s (", XSTR (expand, 0));
+  fprintf (file, "rtx\ngen_%s (", XSTR (expand, 0));
   if (stats.num_generator_args)
     for (i = 0; i < stats.num_generator_args; i++)
       if (i)
-	printf (",\n\trtx operand%d", i);
+	fprintf (file, ",\n\trtx operand%d", i);
       else
-	printf ("rtx operand%d", i);
+	fprintf (file, "rtx operand%d", i);
   else
-    printf ("void");
-  printf (")\n");
-  printf ("{\n");
+    fprintf (file, "void");
+  fprintf (file, ")\n");
+  fprintf (file, "{\n");
 
   /* If we don't have any C code to write, only one insn is being written,
      and no MATCH_DUPs are present, we can just return the desired insn
@@ -485,18 +486,18 @@ gen_expand (md_rtx_info *info)
       && stats.max_opno >= stats.max_dup_opno
       && XVECLEN (expand, 1) == 1)
     {
-      printf ("  return ");
-      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL, info);
-      printf (";\n}\n\n");
+      fprintf (file, "  return ");
+      gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL, info, file);
+      fprintf (file, ";\n}\n\n");
       return;
     }
 
   /* For each operand referred to only with MATCH_DUPs,
      make a local variable.  */
   for (i = stats.num_generator_args; i <= stats.max_dup_opno; i++)
-    printf ("  rtx operand%d;\n", i);
-  printf ("  rtx_insn *_val = 0;\n");
-  printf ("  start_sequence ();\n");
+    fprintf (file, "  rtx operand%d;\n", i);
+  fprintf (file, "  rtx_insn *_val = 0;\n");
+  fprintf (file, "  start_sequence ();\n");
 
   /* The fourth operand of DEFINE_EXPAND is some code to be executed
      before the actual construction.
@@ -506,13 +507,13 @@ gen_expand (md_rtx_info *info)
      So copy the operand values there before executing it.  */
   if (XSTR (expand, 3) && *XSTR (expand, 3))
     {
-      printf ("  {\n");
+      fprintf (file, "  {\n");
       if (stats.num_operand_vars > 0)
-	printf ("    rtx operands[%d];\n", stats.num_operand_vars);
+	fprintf (file, "    rtx operands[%d];\n", stats.num_operand_vars);
 
       /* Output code to copy the arguments into `operands'.  */
       for (i = 0; i < stats.num_generator_args; i++)
-	printf ("    operands[%d] = operand%d;\n", i, i);
+	fprintf (file, "    operands[%d] = operand%d;\n", i, i);
 
       /* Output the special code to be executed before the sequence
 	 is generated.  */
@@ -524,7 +525,7 @@ gen_expand (md_rtx_info *info)
 	  if (nofail_optabs[p.op])
 	    can_fail_p = false;
 	}
-      emit_c_code (XSTR (expand, 3), can_fail_p, XSTR (expand, 0));
+      emit_c_code (XSTR (expand, 3), can_fail_p, XSTR (expand, 0), file);
 
       /* Output code to copy the arguments back out of `operands'
 	 (unless we aren't going to use them at all).  */
@@ -532,29 +533,29 @@ gen_expand (md_rtx_info *info)
 	{
 	  for (i = 0; i <= MAX (stats.max_opno, stats.max_dup_opno); i++)
 	    {
-	      printf ("    operand%d = operands[%d];\n", i, i);
-	      printf ("    (void) operand%d;\n", i);
+	      fprintf (file, "    operand%d = operands[%d];\n", i, i);
+	      fprintf (file, "    (void) operand%d;\n", i);
 	    }
 	}
-      printf ("  }\n");
+      fprintf (file, "  }\n");
     }
 
   used = XCNEWVEC (char, stats.num_operand_vars);
-  gen_emit_seq (XVEC (expand, 1), used, info);
+  gen_emit_seq (XVEC (expand, 1), used, info, file);
   XDELETEVEC (used);
 
   /* Call `get_insns' to extract the list of all the
      insns emitted within this gen_... function.  */
 
-  printf ("  _val = get_insns ();\n");
-  printf ("  end_sequence ();\n");
-  printf ("  return _val;\n}\n\n");
+  fprintf (file, "  _val = get_insns ();\n");
+  fprintf (file, "  end_sequence ();\n");
+  fprintf (file, "  return _val;\n}\n\n");
 }
 
 /* Like gen_expand, but generates insns resulting from splitting SPLIT.  */
 
 static void
-gen_split (md_rtx_info *info)
+gen_split (md_rtx_info *info, FILE *file)
 {
   struct pattern_stats stats;
   int i;
@@ -580,62 +581,62 @@ gen_split (md_rtx_info *info)
   /* Output the prototype, function name and argument declarations.  */
   if (GET_CODE (split) == DEFINE_PEEPHOLE2)
     {
-      printf ("extern rtx_insn *gen_%s_%d (rtx_insn *, rtx *);\n",
+      fprintf (file, "extern rtx_insn *gen_%s_%d (rtx_insn *, rtx *);\n",
 	      name, info->index);
-      printf ("rtx_insn *\ngen_%s_%d (rtx_insn *curr_insn ATTRIBUTE_UNUSED,"
+      fprintf (file, "rtx_insn *\ngen_%s_%d (rtx_insn *curr_insn ATTRIBUTE_UNUSED,"
 	      " rtx *operands%s)\n",
 	      name, info->index, unused);
     }
   else
     {
-      printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n",
+      fprintf (file, "extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n",
 	      info->index);
-      printf ("rtx_insn *\ngen_split_%d "
+      fprintf (file, "rtx_insn *\ngen_split_%d "
 	      "(rtx_insn *curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n",
 	      info->index, unused);
     }
-  printf ("{\n");
+  fprintf (file, "{\n");
 
   /* Declare all local variables.  */
   for (i = 0; i < stats.num_operand_vars; i++)
-    printf ("  rtx operand%d;\n", i);
-  printf ("  rtx_insn *_val = NULL;\n");
+    fprintf (file, "  rtx operand%d;\n", i);
+  fprintf (file, "  rtx_insn *_val = NULL;\n");
 
   if (GET_CODE (split) == DEFINE_PEEPHOLE2)
-    output_peephole2_scratches (split);
+    output_peephole2_scratches (split, file);
 
   const char *fn = info->loc.filename;
   for (const char *p = fn; *p; p++)
     if (*p == '/')
       fn = p + 1;
 
-  printf ("  if (dump_file)\n");
-  printf ("    fprintf (dump_file, \"Splitting with gen_%s_%d (%s:%d)\\n\");\n",
+  fprintf (file, "  if (dump_file)\n");
+  fprintf (file, "    fprintf (dump_file, \"Splitting with gen_%s_%d (%s:%d)\\n\");\n",
 	  name, info->index, fn, info->loc.lineno);
 
-  printf ("  start_sequence ();\n");
+  fprintf (file, "  start_sequence ();\n");
 
   /* The fourth operand of DEFINE_SPLIT is some code to be executed
      before the actual construction.  */
 
   if (XSTR (split, 3))
-    emit_c_code (XSTR (split, 3), true, name);
+    emit_c_code (XSTR (split, 3), true, name, file);
 
   /* Output code to copy the arguments back out of `operands'  */
   for (i = 0; i < stats.num_operand_vars; i++)
     {
-      printf ("  operand%d = operands[%d];\n", i, i);
-      printf ("  (void) operand%d;\n", i);
+      fprintf (file, "  operand%d = operands[%d];\n", i, i);
+      fprintf (file, "  (void) operand%d;\n", i);
     }
 
-  gen_emit_seq (XVEC (split, 2), used, info);
+  gen_emit_seq (XVEC (split, 2), used, info, file);
 
   /* Call `get_insns' to make a list of all the
      insns emitted within this gen_... function.  */
 
-  printf ("  _val = get_insns ();\n");
-  printf ("  end_sequence ();\n");
-  printf ("  return _val;\n}\n\n");
+  fprintf (file, "  _val = get_insns ();\n");
+  fprintf (file, "  end_sequence ();\n");
+  fprintf (file, "  return _val;\n}\n\n");
 
   free (used);
 }
@@ -645,37 +646,37 @@ gen_split (md_rtx_info *info)
    the end of the vector.  */
 
 static void
-output_add_clobbers (md_rtx_info *info)
+output_add_clobbers (md_rtx_info *info, FILE *file)
 {
   struct clobber_pat *clobber;
   struct clobber_ent *ent;
   int i;
 
-  printf ("\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n");
-  printf ("{\n");
-  printf ("  switch (insn_code_number)\n");
-  printf ("    {\n");
+  fprintf (file, "\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n");
+  fprintf (file, "{\n");
+  fprintf (file, "  switch (insn_code_number)\n");
+  fprintf (file, "    {\n");
 
   for (clobber = clobber_list; clobber; clobber = clobber->next)
     {
       for (ent = clobber->insns; ent; ent = ent->next)
-	printf ("    case %d:\n", ent->code_number);
+	fprintf (file, "    case %d:\n", ent->code_number);
 
       for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
 	{
-	  printf ("      XVECEXP (pattern, 0, %d) = ", i);
+	  fprintf (file, "      XVECEXP (pattern, 0, %d) = ", i);
 	  gen_exp (XVECEXP (clobber->pattern, 1, i),
-		   GET_CODE (clobber->pattern), NULL, info);
-	  printf (";\n");
+		   GET_CODE (clobber->pattern), NULL, info, file);
+	  fprintf (file, ";\n");
 	}
 
-      printf ("      break;\n\n");
+      fprintf (file, "      break;\n\n");
     }
 
-  printf ("    default:\n");
-  printf ("      gcc_unreachable ();\n");
-  printf ("    }\n");
-  printf ("}\n");
+  fprintf (file, "    default:\n");
+  fprintf (file, "      gcc_unreachable ();\n");
+  fprintf (file, "    }\n");
+  fprintf (file, "}\n");
 }
 
 /* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code
@@ -684,16 +685,16 @@ output_add_clobbers (md_rtx_info *info)
    SCRATCH.  */
 
 static void
-output_added_clobbers_hard_reg_p (void)
+output_added_clobbers_hard_reg_p (FILE *file)
 {
   struct clobber_pat *clobber;
   struct clobber_ent *ent;
   int clobber_p, used;
 
-  printf ("\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n");
-  printf ("{\n");
-  printf ("  switch (insn_code_number)\n");
-  printf ("    {\n");
+  fprintf (file, "\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n");
+  fprintf (file, "{\n");
+  fprintf (file, "  switch (insn_code_number)\n");
+  fprintf (file, "    {\n");
 
   for (clobber_p = 0; clobber_p <= 1; clobber_p++)
     {
@@ -702,25 +703,25 @@ output_added_clobbers_hard_reg_p (void)
 	if (clobber->has_hard_reg == clobber_p)
 	  for (ent = clobber->insns; ent; ent = ent->next)
 	    {
-	      printf ("    case %d:\n", ent->code_number);
+	      fprintf (file, "    case %d:\n", ent->code_number);
 	      used++;
 	    }
 
       if (used)
-	printf ("      return %d;\n\n", clobber_p);
+	fprintf (file, "      return %d;\n\n", clobber_p);
     }
 
-  printf ("    default:\n");
-  printf ("      gcc_unreachable ();\n");
-  printf ("    }\n");
-  printf ("}\n");
+  fprintf (file, "    default:\n");
+  fprintf (file, "      gcc_unreachable ();\n");
+  fprintf (file, "    }\n");
+  fprintf (file, "}\n");
 }
 
 /* Generate code to invoke find_free_register () as needed for the
    scratch registers used by the peephole2 pattern in SPLIT.  */
 
 static void
-output_peephole2_scratches (rtx split)
+output_peephole2_scratches (rtx split, FILE *file)
 {
   int i;
   int insn_nr = 0;
@@ -745,12 +746,12 @@ output_peephole2_scratches (rtx split)
 
 	  if (first)
 	    {
-	      printf ("  HARD_REG_SET _regs_allocated;\n");
-	      printf ("  CLEAR_HARD_REG_SET (_regs_allocated);\n");
+	      fprintf (file, "  HARD_REG_SET _regs_allocated;\n");
+	      fprintf (file, "  CLEAR_HARD_REG_SET (_regs_allocated);\n");
 	      first = false;
 	    }
 
-	  printf ("  if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
+	  fprintf (file, "  if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\
     return NULL;\n",
 		  XINT (elt, 0),
 		  insn_nr, last_insn_nr,
@@ -766,50 +767,50 @@ output_peephole2_scratches (rtx split)
 /* Print "arg<N>" parameter declarations for each argument N of ONAME.  */
 
 static void
-print_overload_arguments (overloaded_name *oname)
+print_overload_arguments (overloaded_name *oname, FILE *file)
 {
   for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
+    fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
 }
 
 /* Print code to test whether INSTANCE should be chosen, given that
    argument N of the overload is available as "arg<N>".  */
 
 static void
-print_overload_test (overloaded_instance *instance)
+print_overload_test (overloaded_instance *instance, FILE *file)
 {
   for (unsigned int i = 0; i < instance->arg_values.length (); ++i)
-    printf ("%sarg%d == %s", i == 0 ? "  if (" : "\n      && ",
+    fprintf (file, "%sarg%d == %s", i == 0 ? "  if (" : "\n      && ",
 	    i, instance->arg_values[i]);
-  printf (")\n");
+  fprintf (file, ")\n");
 }
 
 /* Emit a maybe_code_for_* function for ONAME.  */
 
 static void
-handle_overloaded_code_for (overloaded_name *oname)
+handle_overloaded_code_for (overloaded_name *oname, FILE *file)
 {
   /* Print the function prototype.  */
-  printf ("\ninsn_code\nmaybe_code_for_%s (", oname->name);
-  print_overload_arguments (oname);
-  printf (")\n{\n");
+  fprintf (file, "\ninsn_code\nmaybe_code_for_%s (", oname->name);
+  print_overload_arguments (oname, file);
+  fprintf (file, ")\n{\n");
 
   /* Use a sequence of "if" statements for each instance.  */
   for (overloaded_instance *instance = oname->first_instance;
        instance; instance = instance->next)
     {
-      print_overload_test (instance);
-      printf ("    return CODE_FOR_%s;\n", instance->name);
+      print_overload_test (instance, file);
+      fprintf (file, "    return CODE_FOR_%s;\n", instance->name);
     }
 
   /* Return null if no match was found.  */
-  printf ("  return CODE_FOR_nothing;\n}\n");
+  fprintf (file, "  return CODE_FOR_nothing;\n}\n");
 }
 
 /* Emit a maybe_gen_* function for ONAME.  */
 
 static void
-handle_overloaded_gen (overloaded_name *oname)
+handle_overloaded_gen (overloaded_name *oname, FILE *file)
 {
   unsigned HOST_WIDE_INT seen = 0;
   /* All patterns must have the same number of operands.  */
@@ -826,25 +827,25 @@ handle_overloaded_gen (overloaded_name *oname)
       seen |= mask;
 
       /* Print the function prototype.  */
-      printf ("\nrtx\nmaybe_gen_%s (", oname->name);
-      print_overload_arguments (oname);
+      fprintf (file, "\nrtx\nmaybe_gen_%s (", oname->name);
+      print_overload_arguments (oname, file);
       for (int i = 0; i < stats.num_generator_args; ++i)
-	printf (", rtx x%d", i);
-      printf (")\n{\n");
+	fprintf (file, ", rtx x%d", i);
+      fprintf (file, ")\n{\n");
 
       /* Use maybe_code_for_*, instead of duplicating the selection
 	 logic here.  */
-      printf ("  insn_code code = maybe_code_for_%s (", oname->name);
+      fprintf (file, "  insn_code code = maybe_code_for_%s (", oname->name);
       for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-	printf ("%sarg%d", i == 0 ? "" : ", ", i);
-      printf (");\n"
+	fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
+      fprintf (file, ");\n"
 	      "  if (code != CODE_FOR_nothing)\n"
 	      "    {\n"
 	      "      gcc_assert (insn_data[code].n_generator_args == %d);\n"
 	      "      return GEN_FCN (code) (", stats.num_generator_args);
       for (int i = 0; i < stats.num_generator_args; ++i)
-	printf ("%sx%d", i == 0 ? "" : ", ", i);
-      printf (");\n"
+	fprintf (file, "%sx%d", i == 0 ? "" : ", ", i);
+      fprintf (file, ");\n"
 	      "    }\n"
 	      "  else\n"
 	      "    return NULL_RTX;\n"
@@ -852,12 +853,68 @@ handle_overloaded_gen (overloaded_name *oname)
     }
 }
 
+void
+print_header (FILE *file)
+{
+  fprintf (file, "/* Generated automatically by the program `genemit'\n\
+from the machine description file `md'.  */\n\n");
+
+  fprintf (file, "#define IN_TARGET_CODE 1\n");
+  fprintf (file, "#include \"config.h\"\n");
+  fprintf (file, "#include \"system.h\"\n");
+  fprintf (file, "#include \"coretypes.h\"\n");
+  fprintf (file, "#include \"backend.h\"\n");
+  fprintf (file, "#include \"predict.h\"\n");
+  fprintf (file, "#include \"tree.h\"\n");
+  fprintf (file, "#include \"rtl.h\"\n");
+  fprintf (file, "#include \"alias.h\"\n");
+  fprintf (file, "#include \"varasm.h\"\n");
+  fprintf (file, "#include \"stor-layout.h\"\n");
+  fprintf (file, "#include \"calls.h\"\n");
+  fprintf (file, "#include \"memmodel.h\"\n");
+  fprintf (file, "#include \"tm_p.h\"\n");
+  fprintf (file, "#include \"flags.h\"\n");
+  fprintf (file, "#include \"insn-config.h\"\n");
+  fprintf (file, "#include \"expmed.h\"\n");
+  fprintf (file, "#include \"dojump.h\"\n");
+  fprintf (file, "#include \"explow.h\"\n");
+  fprintf (file, "#include \"emit-rtl.h\"\n");
+  fprintf (file, "#include \"stmt.h\"\n");
+  fprintf (file, "#include \"expr.h\"\n");
+  fprintf (file, "#include \"insn-codes.h\"\n");
+  fprintf (file, "#include \"optabs.h\"\n");
+  fprintf (file, "#include \"dfp.h\"\n");
+  fprintf (file, "#include \"output.h\"\n");
+  fprintf (file, "#include \"recog.h\"\n");
+  fprintf (file, "#include \"df.h\"\n");
+  fprintf (file, "#include \"resource.h\"\n");
+  fprintf (file, "#include \"reload.h\"\n");
+  fprintf (file, "#include \"diagnostic-core.h\"\n");
+  fprintf (file, "#include \"regs.h\"\n");
+  fprintf (file, "#include \"tm-constrs.h\"\n");
+  fprintf (file, "#include \"ggc.h\"\n");
+  fprintf (file, "#include \"target.h\"\n\n");
+}
+
+auto_vec<const char *, 10> output_files;
+
+static bool
+handle_arg (const char *arg)
+{
+  if (arg[1] == 'O')
+    {
+      output_files.safe_push (&arg[2]);
+      return true;
+    }
+  return false;
+}
+
 int
 main (int argc, const char **argv)
 {
   progname = "genemit";
 
-  if (!init_rtx_reader_args (argc, argv))
+  if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
     return (FATAL_EXIT_CODE);
 
 #define DEF_INTERNAL_OPTAB_FN(NAME, FLAGS, OPTAB, TYPE) \
@@ -867,86 +924,87 @@ 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.  */
 
-  printf ("/* Generated automatically by the program `genemit'\n\
-from the machine description file `md'.  */\n\n");
+  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;
 
-  printf ("#define IN_TARGET_CODE 1\n");
-  printf ("#include \"config.h\"\n");
-  printf ("#include \"system.h\"\n");
-  printf ("#include \"coretypes.h\"\n");
-  printf ("#include \"backend.h\"\n");
-  printf ("#include \"predict.h\"\n");
-  printf ("#include \"tree.h\"\n");
-  printf ("#include \"rtl.h\"\n");
-  printf ("#include \"alias.h\"\n");
-  printf ("#include \"varasm.h\"\n");
-  printf ("#include \"stor-layout.h\"\n");
-  printf ("#include \"calls.h\"\n");
-  printf ("#include \"memmodel.h\"\n");
-  printf ("#include \"tm_p.h\"\n");
-  printf ("#include \"flags.h\"\n");
-  printf ("#include \"insn-config.h\"\n");
-  printf ("#include \"expmed.h\"\n");
-  printf ("#include \"dojump.h\"\n");
-  printf ("#include \"explow.h\"\n");
-  printf ("#include \"emit-rtl.h\"\n");
-  printf ("#include \"stmt.h\"\n");
-  printf ("#include \"expr.h\"\n");
-  printf ("#include \"insn-codes.h\"\n");
-  printf ("#include \"optabs.h\"\n");
-  printf ("#include \"dfp.h\"\n");
-  printf ("#include \"output.h\"\n");
-  printf ("#include \"recog.h\"\n");
-  printf ("#include \"df.h\"\n");
-  printf ("#include \"resource.h\"\n");
-  printf ("#include \"reload.h\"\n");
-  printf ("#include \"diagnostic-core.h\"\n");
-  printf ("#include \"regs.h\"\n");
-  printf ("#include \"tm-constrs.h\"\n");
-  printf ("#include \"ggc.h\"\n");
-  printf ("#include \"target.h\"\n\n");
+  gcc_assert (npatterns_per_file > 1);
 
-  /* Read the machine description.  */
+  /* Reverse so we can pop the first-added element.  */
+  output_files.reverse ();
 
-  md_rtx_info info;
+  int count = 0;
+  FILE *file = NULL;
+
+  /* Read the machine description.  */
   while (read_md_rtx (&info))
-    switch (GET_CODE (info.def))
-      {
-      case DEFINE_INSN:
-	gen_insn (&info);
-	break;
+    {
+      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;
 
-      case DEFINE_EXPAND:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_expand (&info);
-	break;
+	  if (!output_files.is_empty ())
+	    {
+	      const char *const filename = output_files.pop ();
+	      file = fopen (filename, "w");
+	    }
+	  else if (to_stdout)
+	    file = stdout;
+	  else
+	    break;
 
-      case DEFINE_SPLIT:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_split (&info);
-	break;
+	  print_header (file);
+	  count = 0;
+	}
 
-      case DEFINE_PEEPHOLE2:
-	printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno);
-	gen_split (&info);
-	break;
+      switch (GET_CODE (info.def))
+	{
+	case DEFINE_INSN:
+	  gen_insn (&info, file);
+	  break;
 
-      default:
-	break;
-      }
+	case DEFINE_EXPAND:
+	  fprintf (file, "/* %s:%d */\n", info.loc.filename, info.loc.lineno);
+	  gen_expand (&info, file);
+	  break;
+
+	case DEFINE_SPLIT:
+	  fprintf (file, "/* %s:%d */\n", info.loc.filename, info.loc.lineno);
+	  gen_split (&info, file);
+	  break;
+
+	case DEFINE_PEEPHOLE2:
+	  fprintf (file, "/* %s:%d */\n", info.loc.filename, info.loc.lineno);
+	  gen_split (&info, file);
+	  break;
+
+	default:
+	  break;
+	}
+
+      count++;
+    }
 
   /* Write out the routines to add CLOBBERs to a pattern and say whether they
      clobber a hard reg.  */
-  output_add_clobbers (&info);
-  output_added_clobbers_hard_reg_p ();
+  output_add_clobbers (&info, file);
+  output_added_clobbers_hard_reg_p (file);
 
   for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
        oname; oname = oname->next)
     {
-      handle_overloaded_code_for (oname);
-      handle_overloaded_gen (oname);
+      handle_overloaded_code_for (oname, file);
+      handle_overloaded_gen (oname, file);
     }
 
-  fflush (stdout);
-  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
+  return (fclose (file) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
 }
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index f9efc6eb7572..f941f76a739f 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -2631,6 +2631,61 @@ init_rtx_reader_args (int argc, const char **argv)
   return init_rtx_reader_args_cb (argc, argv, 0);
 }
 
+/* Count the number of patterns in all queues and return the count.  */
+int
+count_patterns ()
+{
+  int count = 0, truth = 1;
+  rtx def;
+  class queue_elem *cur = define_attr_queue;
+  while (cur)
+    {
+      def = cur->data;
+
+      truth = maybe_eval_c_test (get_c_test (def));
+      if (truth || !insn_elision)
+	count++;
+      cur = cur->next;
+    }
+
+  cur = define_pred_queue;
+  while (cur)
+    {
+      def = cur->data;
+
+      truth = maybe_eval_c_test (get_c_test (def));
+      if (truth || !insn_elision)
+	count++;
+      cur = cur->next;
+    }
+
+  cur = define_insn_queue;
+  truth = 1;
+  while (cur)
+    {
+      def = cur->data;
+
+      truth = maybe_eval_c_test (get_c_test (def));
+      if (truth || !insn_elision)
+	count++;
+      cur = cur->next;
+    }
+
+  cur = other_queue;
+  truth = 1;
+  while (cur)
+    {
+      def = cur->data;
+
+      truth = maybe_eval_c_test (get_c_test (def));
+      if (truth || !insn_elision)
+	count++;
+      cur = cur->next;
+    }
+
+  return count;
+}
+
 /* Try to read a single rtx from the file.  Return true on success,
    describing it in *INFO.  */
 
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index a1edfbd71908..510ba19405e4 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -129,6 +129,7 @@ extern rtx add_implicit_parallel (rtvec);
 extern rtx_reader *init_rtx_reader_args_cb (int, const char **,
 					    bool (*)(const char *));
 extern rtx_reader *init_rtx_reader_args (int, const char **);
+extern int count_patterns ();
 extern bool read_md_rtx (md_rtx_info *);
 extern unsigned int get_num_insn_codes ();
 
diff --git a/gcc/read-md.cc b/gcc/read-md.cc
index fd38818e3a3e..46ab9065e3e4 100644
--- a/gcc/read-md.cc
+++ b/gcc/read-md.cc
@@ -132,9 +132,9 @@ md_reader::fprint_md_ptr_loc (FILE *outf, const void *ptr)
 
 /* Special fprint_md_ptr_loc for writing to STDOUT.  */
 void
-md_reader::print_md_ptr_loc (const void *ptr)
+md_reader::print_md_ptr_loc (const void *ptr, FILE *file)
 {
-  fprint_md_ptr_loc (stdout, ptr);
+  fprint_md_ptr_loc (file, ptr);
 }
 
 /* Return a condition that satisfies both COND1 and COND2.  Either string
diff --git a/gcc/read-md.h b/gcc/read-md.h
index b309c9c3deb6..2adcb58478fe 100644
--- a/gcc/read-md.h
+++ b/gcc/read-md.h
@@ -194,7 +194,7 @@ class md_reader
   const struct ptr_loc *get_md_ptr_loc (const void *ptr);
   void copy_md_ptr_loc (const void *new_ptr, const void *old_ptr);
   void fprint_md_ptr_loc (FILE *outf, const void *ptr);
-  void print_md_ptr_loc (const void *ptr);
+  void print_md_ptr_loc (const void *ptr, FILE * = stdout);
 
   struct enum_type *lookup_enum_type (const char *name);
   void traverse_enum_types (htab_trav callback, void *info);
-- 
2.43.0

