Robin Dapp <rdapp....@gmail.com> writes:
> Hi, > > the attached v2 includes Tamar's suggestion of keeping the current > stdout behavior. When no output files are passed (via -O) the output > is written to stdout as before. > > Tamar also mentioned off-list that, similar to match.pd, it might make > sense to balance the partitions in a better way than a fixed number > of patterns threshold. That's a good idea but I'd rather do that > separately as the current approach already helps considerably. > > Attached v2 was bootstrapped and regtested on power10, aarch64 and > x86 are still running. > Stefan also tested v1 on s390 where the partitioning does not help > but also doesn't slow anything down. insn-emit.cc isn't very large > to begin with on s390. I tested v1 on x86/arm64, I'll do at least the same for v2. (I also backported it to 13 for my own purposes locally and everything seemed fine there.) I didn't notice any change on my x86 machine but it's already quite powerful and I didn't have a chance to try on anything weaker, so I wasn't too surprised. > > Regards > Robin > > From 34d05113a4e3c7e83a4731020307e26c1144af69 Mon Sep 17 00:00:00 2001 > From: Robin Dapp <rd...@ventanamicro.com> > Date: Thu, 12 Oct 2023 11:23:26 +0200 > Subject: [PATCH v2] 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). In order to do so it first counts > the number of available patterns, calculates the number of patterns per > file and starts a new file whenever that number is reached. > > 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 | 38 +++- > gcc/configure | 24 ++- > gcc/configure.ac | 13 ++ > gcc/genemit.cc | 536 +++++++++++++++++++++++++--------------------- > gcc/gensupport.cc | 36 ++++ > gcc/gensupport.h | 1 + > gcc/read-md.cc | 4 +- > gcc/read-md.h | 2 +- > 8 files changed, 399 insertions(+), 255 deletions(-) > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > index 9cc16268abf..ca0a616f768 100644 > --- a/gcc/Makefile.in > +++ b/gcc/Makefile.in > @@ -236,6 +236,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 > @@ -1354,7 +1361,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 \ > @@ -1852,7 +1859,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) \ > @@ -2481,11 +2489,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 > @@ -2508,7 +2516,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 > > @@ -2537,8 +2545,22 @@ $(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) > +s-tmp-emit: build/genemit$(build_exeext) insn-conditions.md > + $(RUN_GEN) build/genemit$(build_exeext) $(md_file) insn-conditions.md \ > + $(addprefix -O,${INSNEMIT_SEQ_TMP}) > + $(STAMP) s-tmp-emit > + > +$(INSNEMIT_SEQ_SRC): insn-emit-%.cc: s-insn-emit-%; @true > +$(INSNEMIT_SEQ_SRC:insn-emit-%.cc=s-insn-emit-%): s-insn-emit-%: s-tmp-emit > + $(SHELL) $(srcdir)/../move-if-change tmp-emit-$*.cc insn-emit-$*.cc > + $(STAMP) s-insn-emit-$* > + > # gencheck doesn't read the machine description, and the file produced > # doesn't use the insn-* convention. > + > +# --> s-check has prerequisite tree-check.h (though nothing to do) > 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 c43bde8174b..00672b18f72 100755 > --- a/gcc/configure > +++ b/gcc/configure > @@ -842,6 +842,7 @@ enable_gcov > enable_shared > enable_fixed_point > enable_decimal_float > +DEFAULT_INSNEMIT_PARTITIONS > DEFAULT_MATCHPD_PARTITIONS > with_float > with_cpu > @@ -971,6 +972,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 > @@ -1839,6 +1841,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 > @@ -7938,6 +7943,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 : > @@ -19923,7 +19943,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 19926 "configure" > +#line 19946 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > @@ -20029,7 +20049,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 20032 "configure" > +#line 20052 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > diff --git a/gcc/configure.ac b/gcc/configure.ac > index fb8e32f8ee5..bc0ef734e6c 100644 > --- a/gcc/configure.ac > +++ b/gcc/configure.ac > @@ -956,6 +956,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 1ce0564076d..8d8a3c4aa80 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,17 +685,17 @@ 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; > bool used; > > - printf ("\n\nbool\nadded_clobbers_hard_reg_p (int insn_code_number)\n"); > - printf ("{\n"); > - printf (" switch (insn_code_number)\n"); > - printf (" {\n"); > + fprintf (file, "\n\nbool\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++) > { > @@ -703,25 +704,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 = true; > } > > if (used) > - printf (" return %s;\n\n", clobber_p ? "true" : "false"); > + fprintf (file, " return %s;\n\n", clobber_p ? "true" : "false"); > } > > - 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; > @@ -746,12 +747,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, > @@ -767,50 +768,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. */ > @@ -827,25 +828,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" > @@ -853,12 +854,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) \ > @@ -868,86 +925,81 @@ 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; > > - 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"); > + int npatterns_per_file = npatterns; > + if (!output_files.is_empty ()) > + npatterns_per_file = npatterns / output_files.length () + 1; > > - /* Read the machine description. */ > + gcc_assert (npatterns_per_file > 1); > > - md_rtx_info info; > + /* Reverse so we can pop the first-added element. */ > + output_files.reverse (); > + > + 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) > + { > + if (file) > + 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 > + file = stdout; > > - 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 dd920d673b4..367ba1a30a4 100644 > --- a/gcc/gensupport.cc > +++ b/gcc/gensupport.cc > @@ -3131,6 +3131,42 @@ 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; > + class queue_elem *cur = define_attr_queue; > + while (cur != NULL) > + { > + count++; > + cur = cur->next; > + } > + > + cur = define_pred_queue; > + while (cur != NULL) > + { > + count++; > + cur = cur->next; > + } > + > + cur = define_insn_queue; > + while (cur != NULL) > + { > + count++; > + cur = cur->next; > + } > + > + cur = other_queue; > + while (cur != NULL) > + { > + 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 7925e22ed41..7396118714b 100644 > --- a/gcc/gensupport.h > +++ b/gcc/gensupport.h > @@ -130,6 +130,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 fd38818e3a3..46ab9065e3e 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 b309c9c3deb..2adcb58478f 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);