commit: ee2008a6cbb19d604b2cfa4e9c1eeb08e2488cf0 Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Wed Nov 27 17:42:31 2024 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Wed Nov 27 17:42:31 2024 +0000 URL: https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=ee2008a6
15.0.0: pull in genrecog split patch I will see about backporting these (downstream) once they're all merged, at least to 14. Bug: https://gcc.gnu.org/PR111600 Signed-off-by: Sam James <sam <AT> gentoo.org> ...0-genrecog-Split-into-separate-partitions.patch | 1369 ++++++++++++++++++++ 1 file changed, 1369 insertions(+) diff --git a/15.0.0/gentoo/72_all_PR111600-genrecog-Split-into-separate-partitions.patch b/15.0.0/gentoo/72_all_PR111600-genrecog-Split-into-separate-partitions.patch new file mode 100644 index 0000000..07486e4 --- /dev/null +++ b/15.0.0/gentoo/72_all_PR111600-genrecog-Split-into-separate-partitions.patch @@ -0,0 +1,1369 @@ +From 1135970eb38c8f90db20c12cb4222e3a5214557e Mon Sep 17 00:00:00 2001 +Message-ID: <1135970eb38c8f90db20c12cb4222e3a5214557e.1732630692.git....@gentoo.org> +From: Robin Dapp <rdapp....@gmail.com> +Date: Tue, 26 Nov 2024 14:44:17 +0100 +Subject: [PATCH] genrecog: Split into separate partitions [PR111600]. + +Hi, + +this patch makes genrecog split its output into separate files (10 by +default) in the same vein genemit does. The changes are mostly +mechanical again, changing printfs and puts to fprintf. +As insn-recog.cc relies on being able to call other recog functions a +header insn-recog.h is introduced that pre declares all of those. + +For simplicity the number of files is determined by (re-using) +--with-insnemit-partitions. Naming suggestions welcome :) + +Bootstrapped and regtested on x86 and power10, regtested on riscv. +aarch64 bootstrap is currently blocked because of the +"maybe uninitialized" issue discussed on IRC. + +Regards + Robin + +gcc/ChangeLog: + +* Makefile.in: Add insn-recog split. + * configure.ac: Document that the number of insnemit partitions is + used for insn-recog as well. + * genconditions.cc (write_one_condition): Use fprintf. + * genpreds.cc (write_predicate_expr): Ditto. + (write_init_reg_class_start_regs): Ditto. + * genrecog.cc (write_header): Add header file to includes. + (printf_indent): Use fprintf. + (change_state): Ditto. + (print_code): Ditto. + (print_host_wide_int): Ditto. + (print_parameter_value): Ditto. + (print_test_rtx): Ditto. + (print_nonbool_test): Ditto. + (print_label_value): Ditto. + (print_test): Ditto. + (print_decision): Ditto. + (print_state): Ditto. + (print_subroutine_call): Ditto. + (print_acceptance): Ditto. + (print_subroutine_start): Ditto. + (print_pattern): Ditto. + (print_subroutine): Ditto. + (print_subroutine_group): Ditto. + (handle_arg): Add -O and -H for output and header file handling. + (main): Use callback. + * gentarget-def.cc (def_target_insn): Use fprintf. + * read-md.cc (md_reader::print_c_condition): Ditto. + * read-md.h (class md_reader): Ditto. +--- + gcc/Makefile.in | 29 ++- + gcc/configure.ac | 4 +- + gcc/genconditions.cc | 4 +- + gcc/genpreds.cc | 4 +- + gcc/genrecog.cc | 552 +++++++++++++++++++++++++------------------ + gcc/gentarget-def.cc | 2 +- + gcc/read-md.cc | 4 +- + gcc/read-md.h | 2 +- + 8 files changed, 358 insertions(+), 243 deletions(-) + +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index ead8d2eb094c..d301bef47003 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -239,6 +239,12 @@ INSNEMIT_SEQ_SRC = $(patsubst %, insn-emit-%.cc, $(INSNEMIT_SPLITS_SEQ)) + INSNEMIT_SEQ_TMP = $(patsubst %, tmp-emit-%.cc, $(INSNEMIT_SPLITS_SEQ)) + INSNEMIT_SEQ_O = $(patsubst %, insn-emit-%.o, $(INSNEMIT_SPLITS_SEQ)) + ++# Re-use the split number for insn-recog as well. ++INSNRECOG_SPLITS_SEQ = $(wordlist 1,$(NUM_INSNEMIT_SPLITS),$(one_to_9999)) ++INSNRECOG_SEQ_SRC = $(patsubst %, insn-recog-%.cc, $(INSNRECOG_SPLITS_SEQ)) ++INSNRECOG_SEQ_TMP = $(patsubst %, tmp-recog-%.cc, $(INSNRECOG_SPLITS_SEQ)) ++INSNRECOG_SEQ_O = $(patsubst %, insn-recog-%.o, $(INSNRECOG_SPLITS_SEQ)) ++ + # These files are to have specific diagnostics suppressed, or are not to + # be subject to -Werror: + # flex output may yield harmless "no previous prototype" warnings +@@ -1385,7 +1391,7 @@ OBJS = \ + insn-output.o \ + insn-peep.o \ + insn-preds.o \ +- insn-recog.o \ ++ $(INSNRECOG_SEQ_O) \ + insn-enums.o \ + ggc-page.o \ + adjust-alignment.o \ +@@ -1903,8 +1909,8 @@ TREECHECKING = @TREECHECKING@ + FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext) + + MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ +- insn-output.cc insn-recog.cc $(INSNEMIT_SEQ_SRC) \ +- insn-extract.cc insn-peep.cc \ ++ insn-output.cc $(INSNRECOG_SEQ_SRC) insn-recog.h \ ++ $(INSNEMIT_SEQ_SRC) insn-extract.cc insn-peep.cc \ + insn-attr.h insn-attr-common.h insn-attrtab.cc insn-dfatab.cc \ + insn-latencytab.cc insn-opinit.cc insn-opinit.h insn-preds.cc insn-constants.h \ + tm-preds.h tm-constrs.h checksum-options $(GIMPLE_MATCH_PD_SEQ_SRC) \ +@@ -2671,7 +2677,8 @@ $(common_out_object_file): $(common_out_file) + # and compile them. + + .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \ +- $(INSNEMIT_SEQ_SRC) insn-recog.cc insn-extract.cc insn-output.cc \ ++ $(INSNEMIT_SEQ_SRC) insn-recog.h $(INSNRECOG_SEQ_SRC) \ ++ insn-extract.cc insn-output.cc \ + insn-peep.cc insn-attr.h insn-attr-common.h insn-attrtab.cc \ + insn-dfatab.cc insn-latencytab.cc insn-preds.cc \ + $(GIMPLE_MATCH_PD_SEQ_SRC) $(GENERIC_MATCH_PD_SEQ_SRC) \ +@@ -2700,7 +2707,7 @@ simple_rtl_generated_h = insn-attr.h insn-attr-common.h insn-codes.h \ + + simple_rtl_generated_c = insn-automata.cc \ + insn-extract.cc insn-output.cc \ +- insn-peep.cc insn-recog.cc ++ insn-peep.cc + + simple_generated_h = $(simple_rtl_generated_h) insn-constants.h + +@@ -2738,6 +2745,18 @@ s-tmp-emit: build/genemit$(build_exeext) $(MD_DEPS) insn-conditions.md + insn-emit-$(id).cc;) + $(STAMP) s-tmp-emit + ++# Same for genrecog. ++$(INSNRECOG_SEQ_SRC): s-tmp-recog; @true ++insn-recog.h: s-tmp-recog; @true ++s-tmp-recog: build/genrecog$(build_exeext) $(MD_DEPS) insn-conditions.md ++ $(RUN_GEN) build/genrecog$(build_exeext) $(md_file) insn-conditions.md \ ++ -Hinsn-recog.h \ ++ $(addprefix -O,${INSNRECOG_SEQ_TMP}) ++ $(foreach id, $(INSNRECOG_SPLITS_SEQ), \ ++ $(SHELL) $(srcdir)/../move-if-change tmp-recog-$(id).cc \ ++ insn-recog-$(id).cc;) ++ $(STAMP) s-tmp-recog ++ + # gencheck doesn't read the machine description, and the file produced + # doesn't use the insn-* convention. + +diff --git a/gcc/configure.ac b/gcc/configure.ac +index c546432b2775..a0d9038ea595 100644 +--- a/gcc/configure.ac ++++ b/gcc/configure.ac +@@ -913,10 +913,10 @@ fi + + AC_SUBST(DEFAULT_MATCHPD_PARTITIONS) + +-# Specify the number of splits of insn-emit.cc to generate. ++# Specify the number of splits of insn-emit.cc and insn-recog.cc to generate. + AC_ARG_WITH(insnemit-partitions, + [AS_HELP_STRING([--with-insnemit-partitions=num], +-[Set the number of partitions of insn-emit.cc for genemit to create. [default=10]])], ++[Set the number of partitions of insn-emit.cc for genemit and genrecog to create. [default=10]])], + [DEFAULT_INSNEMIT_PARTITIONS="$with_insnemit_partitions"], [DEFAULT_INSNEMIT_PARTITIONS=10]) + if (test $DEFAULT_INSNEMIT_PARTITIONS -lt 1); then + AC_MSG_ERROR(m4_normalize([ +diff --git a/gcc/genconditions.cc b/gcc/genconditions.cc +index 13963dc3ff46..9da460893d52 100644 +--- a/gcc/genconditions.cc ++++ b/gcc/genconditions.cc +@@ -141,9 +141,9 @@ write_one_condition (void **slot, void * ARG_UNUSED (dummy)) + } + + fputs ("\",\n __builtin_constant_p ", stdout); +- rtx_reader_ptr->print_c_condition (test->expr); ++ rtx_reader_ptr->print_c_condition (stdout, test->expr); + fputs ("\n ? (int) ", stdout); +- rtx_reader_ptr->print_c_condition (test->expr); ++ rtx_reader_ptr->print_c_condition (stdout, test->expr); + fputs ("\n : -1 },\n", stdout); + return 1; + } +diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc +index 55d149e8a404..b8f3bf279d97 100644 +--- a/gcc/genpreds.cc ++++ b/gcc/genpreds.cc +@@ -538,7 +538,7 @@ write_predicate_expr (rtx exp) + break; + + case MATCH_TEST: +- rtx_reader_ptr->print_c_condition (XSTR (exp, 0)); ++ rtx_reader_ptr->print_c_condition (stdout, XSTR (exp, 0)); + break; + + default: +@@ -1344,7 +1344,7 @@ write_init_reg_class_start_regs () + for (unsigned int i = 0; i < register_filters.length (); ++i) + { + printf (" if ("); +- rtx_reader_ptr->print_c_condition (register_filters[i]); ++ rtx_reader_ptr->print_c_condition (stdout, register_filters[i]); + printf (")\n" + " SET_HARD_REG_BIT (%s[%d], regno);\n", + "this_target_constraints->register_filters", i); +diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc +index ba09ec3b6005..7f7ca728bbe0 100644 +--- a/gcc/genrecog.cc ++++ b/gcc/genrecog.cc +@@ -4255,9 +4255,9 @@ match_pattern (state *s, md_rtx_info *info, rtx pattern, + /* Begin the output file. */ + + static void +-write_header (void) ++write_header (FILE *f, const char *header_filename) + { +- puts ("\ ++ fprintf (f, "%s", "\ + /* Generated automatically by the program `genrecog' from the target\n\ + machine description file. */\n\ + \n\ +@@ -4281,10 +4281,12 @@ write_header (void) + #include \"diagnostic-core.h\"\n\ + #include \"reload.h\"\n\ + #include \"regs.h\"\n\ +-#include \"tm-constrs.h\"\n\ +-\n"); ++#include \"tm-constrs.h\"\n"); + +- puts ("\n\ ++ fprintf (f, "#include \"%s\"\n", header_filename); ++ fprintf (f, "%s", "\n"); ++ ++ fprintf (f, "%s", "\n\ + /* `recog' contains a decision tree that recognizes whether the rtx\n\ + X0 is a valid instruction.\n\ + \n\ +@@ -4293,19 +4295,19 @@ write_header (void) + pattern that matched. This is the same as the order in the machine\n\ + description of the entry that matched. This number can be used as an\n\ + index into `insn_data' and other tables.\n"); +- puts ("\ ++ fprintf (f, "%s", "\ + The third parameter to recog is an optional pointer to an int. If\n\ + present, recog will accept a pattern if it matches except for missing\n\ + CLOBBER expressions at the end. In that case, the value pointed to by\n\ + the optional pointer will be set to the number of CLOBBERs that need\n\ + to be added (it should be initialized to zero by the caller). If it"); +- puts ("\ ++ fprintf (f, "%s", "\ + is set nonzero, the caller should allocate a PARALLEL of the\n\ + appropriate size, copy the initial entries, and call add_clobbers\n\ + (found in insn-emit.cc) to fill in the CLOBBERs.\n\ + "); + +- puts ("\n\ ++ fprintf (f, "%s", "\n\ + The function split_insns returns 0 if the rtl could not\n\ + be split or the split rtl as an INSN list if it can be.\n\ + \n\ +@@ -4463,13 +4465,13 @@ test_position_available_p (output_state *os, const rtx_test &test) + + /* Like printf, but print INDENT spaces at the beginning. */ + +-static void ATTRIBUTE_PRINTF_2 +-printf_indent (unsigned int indent, const char *format, ...) ++static void ATTRIBUTE_PRINTF_3 ++printf_indent (FILE *f, unsigned int indent, const char *format, ...) + { + va_list ap; + va_start (ap, format); +- printf ("%*s", indent, ""); +- vprintf (format, ap); ++ fprintf (f, "%*s", indent, ""); ++ vfprintf (f, format, ap); + va_end (ap); + } + +@@ -4478,7 +4480,7 @@ printf_indent (unsigned int indent, const char *format, ...) + OS with the new state. */ + + static void +-change_state (output_state *os, position *pos, unsigned int indent) ++change_state (FILE *f, output_state *os, position *pos, unsigned int indent) + { + unsigned int var = os->id_to_var[pos->id]; + gcc_assert (var < os->var_to_id.length () && os->var_to_id[var] == pos->id); +@@ -4487,19 +4489,19 @@ change_state (output_state *os, position *pos, unsigned int indent) + switch (pos->type) + { + case POS_PEEP2_INSN: +- printf_indent (indent, "x%d = PATTERN (peep2_next_insn (%d));\n", ++ printf_indent (f, indent, "x%d = PATTERN (peep2_next_insn (%d));\n", + var, pos->arg); + break; + + case POS_XEXP: +- change_state (os, pos->base, indent); +- printf_indent (indent, "x%d = XEXP (x%d, %d);\n", ++ change_state (f, os, pos->base, indent); ++ printf_indent (f, indent, "x%d = XEXP (x%d, %d);\n", + var, os->id_to_var[pos->base->id], pos->arg); + break; + + case POS_XVECEXP0: +- change_state (os, pos->base, indent); +- printf_indent (indent, "x%d = XVECEXP (x%d, 0, %d);\n", ++ change_state (f, os, pos->base, indent); ++ printf_indent (f, indent, "x%d = XVECEXP (x%d, 0, %d);\n", + var, os->id_to_var[pos->base->id], pos->arg); + break; + } +@@ -4510,11 +4512,11 @@ change_state (output_state *os, position *pos, unsigned int indent) + the name. */ + + static void +-print_code (enum rtx_code code) ++print_code (FILE *f, enum rtx_code code) + { + const char *p; + for (p = GET_RTX_NAME (code); *p; p++) +- putchar (TOUPPER (*p)); ++ fprintf (f, "%c", TOUPPER (*p)); + } + + /* Emit a uint64_t as an integer constant expression. We need to take +@@ -4522,22 +4524,22 @@ print_code (enum rtx_code code) + warnings in the resulting code. */ + + static void +-print_host_wide_int (uint64_t val) ++print_host_wide_int (FILE *f, uint64_t val) + { + uint64_t min = uint64_t (1) << (HOST_BITS_PER_WIDE_INT - 1); + if (val == min) +- printf ("(" HOST_WIDE_INT_PRINT_DEC_C " - 1)", val + 1); ++ fprintf (f, "(" HOST_WIDE_INT_PRINT_DEC_C " - 1)", val + 1); + else +- printf (HOST_WIDE_INT_PRINT_DEC_C, val); ++ fprintf (f, HOST_WIDE_INT_PRINT_DEC_C, val); + } + + /* Print the C expression for actual parameter PARAM. */ + + static void +-print_parameter_value (const parameter ¶m) ++print_parameter_value (FILE *f, const parameter ¶m) + { + if (param.is_param) +- printf ("i%d", (int) param.value + 1); ++ fprintf (f, "i%d", (int) param.value + 1); + else + switch (param.type) + { +@@ -4546,23 +4548,23 @@ print_parameter_value (const parameter ¶m) + break; + + case parameter::CODE: +- print_code ((enum rtx_code) param.value); ++ print_code (f, (enum rtx_code) param.value); + break; + + case parameter::MODE: +- printf ("E_%smode", GET_MODE_NAME ((machine_mode) param.value)); ++ fprintf (f, "E_%smode", GET_MODE_NAME ((machine_mode) param.value)); + break; + + case parameter::INT: +- printf ("%d", (int) param.value); ++ fprintf (f, "%d", (int) param.value); + break; + + case parameter::UINT: +- printf ("%u", (unsigned int) param.value); ++ fprintf (f, "%u", (unsigned int) param.value); + break; + + case parameter::WIDE_INT: +- print_host_wide_int (param.value); ++ print_host_wide_int (f, param.value); + break; + } + } +@@ -4570,90 +4572,90 @@ print_parameter_value (const parameter ¶m) + /* Print the C expression for the rtx tested by TEST. */ + + static void +-print_test_rtx (output_state *os, const rtx_test &test) ++print_test_rtx (FILE *f, output_state *os, const rtx_test &test) + { + if (test.pos_operand >= 0) +- printf ("operands[%d]", test.pos_operand); ++ fprintf (f, "operands[%d]", test.pos_operand); + else +- printf ("x%d", os->id_to_var[test.pos->id]); ++ fprintf (f, "x%d", os->id_to_var[test.pos->id]); + } + + /* Print the C expression for non-boolean test TEST. */ + + static void +-print_nonbool_test (output_state *os, const rtx_test &test) ++print_nonbool_test (FILE *f, output_state *os, const rtx_test &test) + { + switch (test.kind) + { + case rtx_test::CODE: +- printf ("GET_CODE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "GET_CODE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::MODE: +- printf ("GET_MODE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "GET_MODE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::VECLEN: +- printf ("XVECLEN ("); +- print_test_rtx (os, test); +- printf (", 0)"); ++ fprintf (f, "XVECLEN ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", 0)"); + break; + + case rtx_test::INT_FIELD: +- printf ("XINT ("); +- print_test_rtx (os, test); +- printf (", %d)", test.u.opno); ++ fprintf (f, "XINT ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", %d)", test.u.opno); + break; + + case rtx_test::REGNO_FIELD: +- printf ("REGNO ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "REGNO ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::SUBREG_FIELD: +- printf ("SUBREG_BYTE ("); +- print_test_rtx (os, test); +- printf (")"); ++ fprintf (f, "SUBREG_BYTE ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ")"); + break; + + case rtx_test::WIDE_INT_FIELD: +- printf ("XWINT ("); +- print_test_rtx (os, test); +- printf (", %d)", test.u.opno); ++ fprintf (f, "XWINT ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", %d)", test.u.opno); + break; + + case rtx_test::PATTERN: + { + pattern_routine *routine = test.u.pattern->routine; +- printf ("pattern%d (", routine->pattern_id); ++ fprintf (f, "pattern%d (", routine->pattern_id); + const char *sep = ""; + if (test.pos) + { +- print_test_rtx (os, test); ++ print_test_rtx (f, os, test); + sep = ", "; + } + if (routine->insn_p) + { +- printf ("%sinsn", sep); ++ fprintf (f, "%sinsn", sep); + sep = ", "; + } + if (routine->pnum_clobbers_p) + { +- printf ("%spnum_clobbers", sep); ++ fprintf (f, "%spnum_clobbers", sep); + sep = ", "; + } + for (unsigned int i = 0; i < test.u.pattern->params.length (); ++i) + { +- fputs (sep, stdout); +- print_parameter_value (test.u.pattern->params[i]); ++ fprintf (f, "%s\n", sep); ++ print_parameter_value (f, test.u.pattern->params[i]); + sep = ", "; + } +- printf (")"); ++ fprintf (f, ")"); + break; + } + +@@ -4674,10 +4676,11 @@ print_nonbool_test (output_state *os, const rtx_test &test) + decision performs TEST. Print the C code for the label. */ + + static void +-print_label_value (const rtx_test &test, bool is_param, uint64_t value) ++print_label_value (FILE *f, const rtx_test &test, bool is_param, ++ uint64_t value) + { +- print_parameter_value (parameter (transition_parameter_type (test.kind), +- is_param, value)); ++ print_parameter_value (f, parameter (transition_parameter_type (test.kind), ++ is_param, value)); + } + + /* If IS_PARAM, print code to compare TEST with the C variable i<VALUE+1>. +@@ -4685,7 +4688,7 @@ print_label_value (const rtx_test &test, bool is_param, uint64_t value) + Test for inequality if INVERT_P, otherwise test for equality. */ + + static void +-print_test (output_state *os, const rtx_test &test, bool is_param, ++print_test (FILE *f, output_state *os, const rtx_test &test, bool is_param, + uint64_t value, bool invert_p) + { + switch (test.kind) +@@ -4698,71 +4701,71 @@ print_test (output_state *os, const rtx_test &test, bool is_param, + case rtx_test::INT_FIELD: + case rtx_test::WIDE_INT_FIELD: + case rtx_test::PATTERN: +- print_nonbool_test (os, test); +- printf (" %s ", invert_p ? "!=" : "=="); +- print_label_value (test, is_param, value); ++ print_nonbool_test (f, os, test); ++ fprintf (f, " %s ", invert_p ? "!=" : "=="); ++ print_label_value (f, test, is_param, value); + break; + + case rtx_test::SUBREG_FIELD: +- printf ("%s (", invert_p ? "maybe_ne" : "known_eq"); +- print_nonbool_test (os, test); +- printf (", "); +- print_label_value (test, is_param, value); +- printf (")"); ++ fprintf (f, "%s (", invert_p ? "maybe_ne" : "known_eq"); ++ print_nonbool_test (f, os, test); ++ fprintf (f, ", "); ++ print_label_value (f, test, is_param, value); ++ fprintf (f, ")"); + break; + + case rtx_test::SAVED_CONST_INT: + gcc_assert (!is_param && value == 1); +- print_test_rtx (os, test); +- printf (" %s const_int_rtx[MAX_SAVED_CONST_INT + ", +- invert_p ? "!=" : "=="); +- print_parameter_value (parameter (parameter::INT, +- test.u.integer.is_param, +- test.u.integer.value)); +- printf ("]"); ++ print_test_rtx (f, os, test); ++ fprintf (f, " %s const_int_rtx[MAX_SAVED_CONST_INT + ", ++ invert_p ? "!=" : "=="); ++ print_parameter_value (f, parameter (parameter::INT, ++ test.u.integer.is_param, ++ test.u.integer.value)); ++ fprintf (f, "]"); + break; + + case rtx_test::PEEP2_COUNT: + gcc_assert (!is_param && value == 1); +- printf ("peep2_current_count %s %d", invert_p ? "<" : ">=", +- test.u.min_len); ++ fprintf (f, "peep2_current_count %s %d", invert_p ? "<" : ">=", ++ test.u.min_len); + break; + + case rtx_test::VECLEN_GE: + gcc_assert (!is_param && value == 1); +- printf ("XVECLEN ("); +- print_test_rtx (os, test); +- printf (", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len); ++ fprintf (f, "XVECLEN ("); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", 0) %s %d", invert_p ? "<" : ">=", test.u.min_len); + break; + + case rtx_test::PREDICATE: + gcc_assert (!is_param && value == 1); +- printf ("%s%s (", invert_p ? "!" : "", test.u.predicate.data->name); +- print_test_rtx (os, test); +- printf (", "); +- print_parameter_value (parameter (parameter::MODE, +- test.u.predicate.mode_is_param, +- test.u.predicate.mode)); +- printf (")"); ++ fprintf (f, "%s%s (", invert_p ? "!" : "", test.u.predicate.data->name); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", "); ++ print_parameter_value (f, parameter (parameter::MODE, ++ test.u.predicate.mode_is_param, ++ test.u.predicate.mode)); ++ fprintf (f, ")"); + break; + + case rtx_test::DUPLICATE: + gcc_assert (!is_param && value == 1); +- printf ("%srtx_equal_p (", invert_p ? "!" : ""); +- print_test_rtx (os, test); +- printf (", operands[%d])", test.u.opno); ++ fprintf (f, "%srtx_equal_p (", invert_p ? "!" : ""); ++ print_test_rtx (f, os, test); ++ fprintf (f, ", operands[%d])", test.u.opno); + break; + + case rtx_test::HAVE_NUM_CLOBBERS: + gcc_assert (!is_param && value == 1); +- printf ("pnum_clobbers %s NULL", invert_p ? "==" : "!="); ++ fprintf (f, "pnum_clobbers %s NULL", invert_p ? "==" : "!="); + break; + + case rtx_test::C_TEST: + gcc_assert (!is_param && value == 1); + if (invert_p) +- printf ("!"); +- rtx_reader_ptr->print_c_condition (test.u.string); ++ fprintf (f, "!"); ++ rtx_reader_ptr->print_c_condition (f, test.u.string); + break; + + case rtx_test::ACCEPT: +@@ -4771,7 +4774,7 @@ print_test (output_state *os, const rtx_test &test, bool is_param, + } + } + +-static exit_state print_decision (output_state *, decision *, ++static exit_state print_decision (FILE *f, output_state *, decision *, + unsigned int, bool); + + /* Print code to perform S, indent each line by INDENT spaces. +@@ -4779,14 +4782,15 @@ static exit_state print_decision (output_state *, decision *, + if the state fails then the entire routine fails. */ + + static exit_state +-print_state (output_state *os, state *s, unsigned int indent, bool is_final) ++print_state (FILE *f, output_state *os, state *s, unsigned int indent, ++ bool is_final) + { + exit_state es = ES_FALLTHROUGH; + for (decision *d = s->first; d; d = d->next) +- es = print_decision (os, d, indent, is_final && !d->next); ++ es = print_decision (f, os, d, indent, is_final && !d->next); + if (es != ES_RETURNED && is_final) + { +- printf_indent (indent, "return %s;\n", get_failure_return (os->type)); ++ printf_indent (f, indent, "return %s;\n", get_failure_return (os->type)); + es = ES_RETURNED; + } + return es; +@@ -4797,7 +4801,7 @@ print_state (output_state *os, state *s, unsigned int indent, bool is_final) + match. */ + + static const char * +-print_subroutine_call (const acceptance_type &acceptance) ++print_subroutine_call (FILE *f, const acceptance_type &acceptance) + { + switch (acceptance.type) + { +@@ -4805,17 +4809,17 @@ print_subroutine_call (const acceptance_type &acceptance) + gcc_unreachable (); + + case RECOG: +- printf ("recog_%d (x1, insn, pnum_clobbers)", +- acceptance.u.subroutine_id); ++ fprintf (f, "recog_%d (x1, insn, pnum_clobbers)", ++ acceptance.u.subroutine_id); + return ">= 0"; + + case SPLIT: +- printf ("split_%d (x1, insn)", acceptance.u.subroutine_id); ++ fprintf (f, "split_%d (x1, insn)", acceptance.u.subroutine_id); + return "!= NULL_RTX"; + + case PEEPHOLE2: +- printf ("peephole2_%d (x1, insn, pmatch_len_)", +- acceptance.u.subroutine_id); ++ fprintf (f, "peephole2_%d (x1, insn, pmatch_len_)", ++ acceptance.u.subroutine_id); + return "!= NULL_RTX"; + } + gcc_unreachable (); +@@ -4825,63 +4829,65 @@ print_subroutine_call (const acceptance_type &acceptance) + INDENT and IS_FINAL are as for print_state. */ + + static exit_state +-print_acceptance (const acceptance_type &acceptance, unsigned int indent, +- bool is_final) ++print_acceptance (FILE *f, const acceptance_type &acceptance, ++ unsigned int indent, bool is_final) + { + if (acceptance.partial_p) + { + /* Defer the rest of the match to a subroutine. */ + if (is_final) + { +- printf_indent (indent, "return "); +- print_subroutine_call (acceptance); +- printf (";\n"); ++ printf_indent (f, indent, "return "); ++ print_subroutine_call (f, acceptance); ++ fprintf (f, ";\n"); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = "); +- const char *res_test = print_subroutine_call (acceptance); +- printf (";\n"); +- printf_indent (indent, "if (res %s)\n", res_test); +- printf_indent (indent + 2, "return res;\n"); ++ printf_indent (f, indent, "res = "); ++ const char *res_test = print_subroutine_call (f, acceptance); ++ fprintf (f, ";\n"); ++ printf_indent (f, indent, "if (res %s)\n", res_test); ++ printf_indent (f, indent + 2, "return res;\n"); + return ES_FALLTHROUGH; + } + } + switch (acceptance.type) + { + case SUBPATTERN: +- printf_indent (indent, "return %d;\n", acceptance.u.full.code); ++ printf_indent (f, indent, "return %d;\n", acceptance.u.full.code); + return ES_RETURNED; + + case RECOG: + if (acceptance.u.full.u.num_clobbers != 0) +- printf_indent (indent, "*pnum_clobbers = %d;\n", ++ printf_indent (f, indent, "*pnum_clobbers = %d;\n", + acceptance.u.full.u.num_clobbers); +- printf_indent (indent, "return %d; /* %s */\n", acceptance.u.full.code, ++ printf_indent (f, indent, "return %d; /* %s */\n", acceptance.u.full.code, + get_insn_name (acceptance.u.full.code)); + return ES_RETURNED; + + case SPLIT: +- printf_indent (indent, "return gen_split_%d (insn, operands);\n", ++ printf_indent (f, indent, "return gen_split_%d (insn, operands);\n", + acceptance.u.full.code); + return ES_RETURNED; + + case PEEPHOLE2: +- printf_indent (indent, "*pmatch_len_ = %d;\n", ++ printf_indent (f, indent, "*pmatch_len_ = %d;\n", + acceptance.u.full.u.match_len); + if (is_final) + { +- printf_indent (indent, "return gen_peephole2_%d (insn, operands);\n", ++ printf_indent (f, indent, ++ "return gen_peephole2_%d (insn, operands);\n", + acceptance.u.full.code); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = gen_peephole2_%d (insn, operands);\n", ++ printf_indent (f, ++ indent, "res = gen_peephole2_%d (insn, operands);\n", + acceptance.u.full.code); +- printf_indent (indent, "if (res != NULL_RTX)\n"); +- printf_indent (indent + 2, "return res;\n"); ++ printf_indent (f, indent, "if (res != NULL_RTX)\n"); ++ printf_indent (f, indent + 2, "return res;\n"); + return ES_FALLTHROUGH; + } + } +@@ -4891,7 +4897,7 @@ print_acceptance (const acceptance_type &acceptance, unsigned int indent, + /* Print code to perform D. INDENT and IS_FINAL are as for print_state. */ + + static exit_state +-print_decision (output_state *os, decision *d, unsigned int indent, ++print_decision (FILE *f, output_state *os, decision *d, unsigned int indent, + bool is_final) + { + uint64_t label; +@@ -4900,7 +4906,7 @@ print_decision (output_state *os, decision *d, unsigned int indent, + /* Make sure the rtx under test is available either in operands[] or + in an xN variable. */ + if (d->test.pos && d->test.pos_operand < 0) +- change_state (os, d->test.pos, indent); ++ change_state (f, os, d->test.pos, indent); + + /* Look for cases where a pattern routine P1 calls another pattern routine + P2 and where P1 returns X + BASE whenever P2 returns X. If IS_FINAL +@@ -4924,32 +4930,32 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + if (is_final && base == 0) + { +- printf_indent (indent, "return "); +- print_nonbool_test (os, d->test); +- printf ("; /* [-1, %d] */\n", count - 1); ++ printf_indent (f, indent, "return "); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, "; /* [-1, %d] */\n", count - 1); + return ES_RETURNED; + } + else + { +- printf_indent (indent, "res = "); +- print_nonbool_test (os, d->test); +- printf (";\n"); +- printf_indent (indent, "if (res >= 0)\n"); +- printf_indent (indent + 2, "return res"); ++ printf_indent (f, indent, "res = "); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, ";\n"); ++ printf_indent (f, indent, "if (res >= 0)\n"); ++ printf_indent (f, indent + 2, "return res"); + if (base != 0) +- printf (" + %d", base); +- printf ("; /* [%d, %d] */\n", base, base + count - 1); ++ fprintf (f, " + %d", base); ++ fprintf (f, "; /* [%d, %d] */\n", base, base + count - 1); + return ES_FALLTHROUGH; + } + } + else if (d->test.kind == rtx_test::ACCEPT) +- return print_acceptance (d->test.u.acceptance, indent, is_final); ++ return print_acceptance (f, d->test.u.acceptance, indent, is_final); + else if (d->test.kind == rtx_test::SET_OP) + { +- printf_indent (indent, "operands[%d] = ", d->test.u.opno); +- print_test_rtx (os, d->test); +- printf (";\n"); +- return print_state (os, d->singleton ()->to, indent, is_final); ++ printf_indent (f, indent, "operands[%d] = ", d->test.u.opno); ++ print_test_rtx (f, os, d->test); ++ fprintf (f, ";\n"); ++ return print_state (f, os, d->singleton ()->to, indent, is_final); + } + /* Handle decisions with a single transition and a single transition + label. */ +@@ -4957,13 +4963,13 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + transition *trans = d->singleton (); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent, "/* OPTIONAL IF */\n"); ++ printf_indent (f, indent, "/* OPTIONAL IF */\n"); + + /* Print the condition associated with TRANS. Invert it if IS_FINAL, + so that we return immediately on failure and fall through on + success. */ +- printf_indent (indent, "if ("); +- print_test (os, d->test, trans->is_param, label, is_final); ++ printf_indent (f, indent, "if ("); ++ print_test (f, os, d->test, trans->is_param, label, is_final); + + /* Look for following states that would be handled by this code + on recursion. If they don't need any preparatory statements, +@@ -4979,13 +4985,13 @@ print_decision (output_state *os, decision *d, unsigned int indent, + || !test_position_available_p (os, d->test)) + break; + trans = d->first; +- printf ("\n"); ++ fprintf (f, "\n"); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent + 4, "/* OPTIONAL IF */\n"); +- printf_indent (indent + 4, "%s ", is_final ? "||" : "&&"); +- print_test (os, d->test, trans->is_param, label, is_final); ++ printf_indent (f, indent + 4, "/* OPTIONAL IF */\n"); ++ printf_indent (f, indent + 4, "%s ", is_final ? "||" : "&&"); ++ print_test (f, os, d->test, trans->is_param, label, is_final); + } +- printf (")\n"); ++ fprintf (f, ")\n"); + + /* Print the conditional code with INDENT + 2 and the fallthrough + code with indent INDENT. */ +@@ -4994,9 +5000,9 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + /* We inverted the condition above, so return failure in the + "if" body and fall through to the target of the transition. */ +- printf_indent (indent + 2, "return %s;\n", ++ printf_indent (f, indent + 2, "return %s;\n", + get_failure_return (os->type)); +- return print_state (os, to, indent, is_final); ++ return print_state (f, os, to, indent, is_final); + } + else if (to->singleton () + && to->first->test.kind == rtx_test::ACCEPT +@@ -5004,7 +5010,7 @@ print_decision (output_state *os, decision *d, unsigned int indent, + { + /* The target of the transition is a simple "return" statement. + It doesn't need any braces and doesn't fall through. */ +- if (print_acceptance (to->first->test.u.acceptance, ++ if (print_acceptance (f, to->first->test.u.acceptance, + indent + 2, true) != ES_RETURNED) + gcc_unreachable (); + return ES_FALLTHROUGH; +@@ -5018,9 +5024,9 @@ print_decision (output_state *os, decision *d, unsigned int indent, + auto_vec <bool, 32> old_seen; + old_seen.safe_splice (os->seen_vars); + +- printf_indent (indent + 2, "{\n"); +- print_state (os, trans->to, indent + 4, is_final); +- printf_indent (indent + 2, "}\n"); ++ printf_indent (f, indent + 2, "{\n"); ++ print_state (f, os, trans->to, indent + 4, is_final); ++ printf_indent (f, indent + 2, "}\n"); + + os->seen_vars.truncate (0); + os->seen_vars.splice (old_seen); +@@ -5030,48 +5036,48 @@ print_decision (output_state *os, decision *d, unsigned int indent, + else + { + /* Output the decision as a switch statement. */ +- printf_indent (indent, "switch ("); +- print_nonbool_test (os, d->test); +- printf (")\n"); ++ printf_indent (f, indent, "switch ("); ++ print_nonbool_test (f, os, d->test); ++ fprintf (f, ")\n"); + + /* Each case statement starts with the same set of valid variables. + These are also the only variables will be valid on fallthrough. */ + auto_vec <bool, 32> old_seen; + old_seen.safe_splice (os->seen_vars); + +- printf_indent (indent + 2, "{\n"); ++ printf_indent (f, indent + 2, "{\n"); + for (transition *trans = d->first; trans; trans = trans->next) + { + gcc_assert (!trans->is_param); + if (mark_optional_transitions_p && trans->optional) +- printf_indent (indent + 2, "/* OPTIONAL CASE */\n"); ++ printf_indent (f, indent + 2, "/* OPTIONAL CASE */\n"); + for (int_set::iterator j = trans->labels.begin (); + j != trans->labels.end (); ++j) + { +- printf_indent (indent + 2, "case "); +- print_label_value (d->test, trans->is_param, *j); +- printf (":\n"); ++ printf_indent (f, indent + 2, "case "); ++ print_label_value (f, d->test, trans->is_param, *j); ++ fprintf (f, ":\n"); + } +- if (print_state (os, trans->to, indent + 4, is_final)) ++ if (print_state (f, os, trans->to, indent + 4, is_final)) + { + /* The state can fall through. Add an explicit break. */ + gcc_assert (!is_final); +- printf_indent (indent + 4, "break;\n"); ++ printf_indent (f, indent + 4, "break;\n"); + } +- printf ("\n"); ++ fprintf (f, "\n"); + + /* Restore the original set of valid variables. */ + os->seen_vars.truncate (0); + os->seen_vars.splice (old_seen); + } + /* Add a default case. */ +- printf_indent (indent + 2, "default:\n"); ++ printf_indent (f, indent + 2, "default:\n"); + if (is_final) +- printf_indent (indent + 4, "return %s;\n", ++ printf_indent (f, indent + 4, "return %s;\n", + get_failure_return (os->type)); + else +- printf_indent (indent + 4, "break;\n"); +- printf_indent (indent + 2, "}\n"); ++ printf_indent (f, indent + 4, "break;\n"); ++ printf_indent (f, indent + 2, "}\n"); + return is_final ? ES_RETURNED : ES_FALLTHROUGH; + } + } +@@ -5114,10 +5120,10 @@ assign_position_vars (output_state *os, state *s) + only ROOT's variable has a valid value. */ + + static void +-print_subroutine_start (output_state *os, state *s, position *root) ++print_subroutine_start (FILE *f, output_state *os, state *s, position *root) + { +- printf ("{\n rtx * const operands ATTRIBUTE_UNUSED" +- " = &recog_data.operand[0];\n"); ++ fprintf (f, "{\n rtx * const operands ATTRIBUTE_UNUSED" ++ " = &recog_data.operand[0];\n"); + os->var_to_id.truncate (0); + os->seen_vars.truncate (0); + if (root) +@@ -5140,9 +5146,9 @@ print_subroutine_start (output_state *os, state *s, position *root) + { + for (unsigned int i = 2; i < num_vars; ++i) + /* Print 8 rtx variables to a line. */ +- printf ("%s x%d", ++ fprintf (f, "%s x%d", + i == 2 ? " rtx" : (i - 2) % 8 == 0 ? ";\n rtx" : ",", i); +- printf (";\n"); ++ fprintf (f, ";\n"); + } + + /* Say that x1 is valid and the rest aren't. */ +@@ -5150,22 +5156,26 @@ print_subroutine_start (output_state *os, state *s, position *root) + os->seen_vars[1] = true; + } + if (os->type == SUBPATTERN || os->type == RECOG) +- printf (" int res ATTRIBUTE_UNUSED;\n"); ++ fprintf (f, " int res ATTRIBUTE_UNUSED;\n"); + else +- printf (" rtx_insn *res ATTRIBUTE_UNUSED;\n"); ++ fprintf (f, " rtx_insn *res ATTRIBUTE_UNUSED;\n"); + } + + /* Output the definition of pattern routine ROUTINE. */ + + static void +-print_pattern (output_state *os, pattern_routine *routine) ++print_pattern (FILE *f, output_state *os, pattern_routine *routine, ++ bool in_header = false) + { +- printf ("\nstatic int\npattern%d (", routine->pattern_id); ++ if (!in_header) ++ fprintf (f, "\nint\npattern%d (", routine->pattern_id); ++ else ++ fprintf (f, "\nextern int\npattern%d (", routine->pattern_id); + const char *sep = ""; + /* Add the top-level rtx parameter, if any. */ + if (routine->pos) + { +- printf ("%srtx x1", sep); ++ fprintf (f, "%srtx x1", sep); + sep = ", "; + } + /* Add the optional parameters. */ +@@ -5173,26 +5183,34 @@ print_pattern (output_state *os, pattern_routine *routine) + { + /* We can't easily tell whether a C condition actually reads INSN, + so add an ATTRIBUTE_UNUSED just in case. */ +- printf ("%srtx_insn *insn ATTRIBUTE_UNUSED", sep); ++ fprintf (f, "%srtx_insn *insn ATTRIBUTE_UNUSED", sep); + sep = ", "; + } + if (routine->pnum_clobbers_p) + { +- printf ("%sint *pnum_clobbers", sep); ++ fprintf (f, "%sint *pnum_clobbers", sep); + sep = ", "; + } + /* Add the "i" parameters. */ + for (unsigned int i = 0; i < routine->param_types.length (); ++i) + { +- printf ("%s%s i%d", sep, +- parameter_type_string (routine->param_types[i]), i + 1); ++ fprintf (f, "%s%s i%d", sep, ++ parameter_type_string (routine->param_types[i]), i + 1); + sep = ", "; + } +- printf (")\n"); ++ ++ if (!in_header) ++ fprintf (f, ")\n"); ++ else ++ { ++ fprintf (f, ");\n"); ++ return; ++ } ++ + os->type = SUBPATTERN; +- print_subroutine_start (os, routine->s, routine->pos); +- print_state (os, routine->s, 2, true); +- printf ("}\n"); ++ print_subroutine_start (f, os, routine->s, routine->pos); ++ print_state (f, os, routine->s, 2, true); ++ fprintf (f, "}\n"); + } + + /* Output a routine of type TYPE that implements S. PROC_ID is the +@@ -5200,9 +5218,26 @@ print_pattern (output_state *os, pattern_routine *routine) + routine. */ + + static void +-print_subroutine (output_state *os, state *s, int proc_id) +-{ +- printf ("\n"); ++print_subroutine (FILE *f, output_state *os, state *s, int proc_id, ++ bool in_header = false) ++{ ++ fprintf (f, "\n"); ++ const char *specifier_ext = "extern"; ++ const char *specifier_default = ""; ++ const char *specifier; ++ if (!in_header) ++ specifier = specifier_default; ++ else ++ specifier = specifier_ext; ++ ++ const char *end; ++ const char *end_default = ""; ++ const char *end_header = ";"; ++ if (!in_header) ++ end = end_default; ++ else ++ end = end_header; ++ + switch (os->type) + { + case SUBPATTERN: +@@ -5210,46 +5245,54 @@ print_subroutine (output_state *os, state *s, int proc_id) + + case RECOG: + if (proc_id) +- printf ("static int\nrecog_%d", proc_id); ++ fprintf (f, "%s int\nrecog_%d", specifier, proc_id); + else +- printf ("int\nrecog"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED,\n" +- "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" +- "\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s int\nrecog", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED,\n" ++ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" ++ "\tint *pnum_clobbers ATTRIBUTE_UNUSED)%s\n", end); + break; + + case SPLIT: + if (proc_id) +- printf ("static rtx_insn *\nsplit_%d", proc_id); ++ fprintf (f, "%s rtx_insn *\nsplit_%d", specifier, proc_id); + else +- printf ("rtx_insn *\nsplit_insns"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s rtx_insn *\nsplit_insns", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED, " ++ "rtx_insn *insn ATTRIBUTE_UNUSED)%s\n", end); + break; + + case PEEPHOLE2: + if (proc_id) +- printf ("static rtx_insn *\npeephole2_%d", proc_id); ++ fprintf (f, "%s rtx_insn *\npeephole2_%d", specifier, proc_id); + else +- printf ("rtx_insn *\npeephole2_insns"); +- printf (" (rtx x1 ATTRIBUTE_UNUSED,\n" +- "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" +- "\tint *pmatch_len_ ATTRIBUTE_UNUSED)\n"); ++ fprintf (f, "%s rtx_insn *\npeephole2_insns", specifier); ++ fprintf (f, " (rtx x1 ATTRIBUTE_UNUSED,\n" ++ "\trtx_insn *insn ATTRIBUTE_UNUSED,\n" ++ "\tint *pmatch_len_ ATTRIBUTE_UNUSED)%s\n", end); + break; + } +- print_subroutine_start (os, s, &root_pos); ++ ++ if (in_header) ++ return; ++ ++ print_subroutine_start (f, os, s, &root_pos); + if (proc_id == 0) + { +- printf (" recog_data.insn = NULL;\n"); ++ fprintf (f, " recog_data.insn = NULL;\n"); + } +- print_state (os, s, 2, true); +- printf ("}\n"); ++ print_state (f, os, s, 2, true); ++ fprintf (f, "}\n"); + } + + /* Print out a routine of type TYPE that performs ROOT. */ + + static void +-print_subroutine_group (output_state *os, routine_type type, state *root) ++print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os, ++ routine_type type, state *root) + { ++ FILE *f; ++ unsigned idx; + os->type = type; + if (use_subroutines_p) + { +@@ -5261,11 +5304,20 @@ print_subroutine_group (output_state *os, routine_type type, state *root) + /* Output the subroutines (but not ROOT itself). */ + unsigned int i; + state *s; ++ ++ FILE *f = header; ++ FOR_EACH_VEC_ELT (subroutines, i, s) ++ print_subroutine (header, os, s, i + 1, true); ++ + FOR_EACH_VEC_ELT (subroutines, i, s) +- print_subroutine (os, s, i + 1); ++ { ++ f = choose_output (vec, idx); ++ print_subroutine (f, os, s, i + 1); ++ } + } + /* Output the main routine. */ +- print_subroutine (os, root, 0); ++ f = choose_output (vec, idx); ++ print_subroutine (f, os, root, 0); + } + + /* Return the rtx pattern for the list of rtxes in a define_peephole2. */ +@@ -5336,6 +5388,29 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr) + return true; + } + ++auto_vec<FILE *, 10> output_files; ++char header_name[255]; ++FILE *header = NULL; ++ ++static bool ++handle_arg (const char *arg) ++{ ++ printf ("%s\n", arg); ++ if (arg[1] == 'O') ++ { ++ FILE *file = fopen (&arg[2], "w"); ++ output_files.safe_push (file); ++ return true; ++ } ++ if (arg[1] == 'H') ++ { ++ snprintf (header_name, 255, "%s", &arg[2]); ++ header = fopen (header_name, "w"); ++ return true; ++ } ++ return false; ++} ++ + int + main (int argc, const char **argv) + { +@@ -5343,10 +5418,17 @@ main (int argc, const char **argv) + + progname = "genrecog"; + +- if (!init_rtx_reader_args (argc, argv)) ++ if (!init_rtx_reader_args_cb (argc, argv, handle_arg)) + return (FATAL_EXIT_CODE); + +- write_header (); ++ if (output_files.is_empty ()) ++ output_files.safe_push (stdout); ++ ++ for (auto f : output_files) ++ write_header (f, header_name); ++ ++ FILE *file = NULL; ++ unsigned file_idx; + + /* Read the machine description. */ + +@@ -5354,6 +5436,7 @@ main (int argc, const char **argv) + while (read_md_rtx (&info)) + { + rtx def = info.def; ++ file = choose_output (output_files, file_idx); + + acceptance_type acceptance; + acceptance.partial_p = false; +@@ -5387,8 +5470,8 @@ main (int argc, const char **argv) + + /* Declare the gen_split routine that we'll call if the + pattern matches. The definition comes from insn-emit.cc. */ +- printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n", +- info.index); ++ fprintf (header, "extern rtx_insn *gen_split_%d " ++ "(rtx_insn *, rtx *);\n", info.index); + break; + + case DEFINE_PEEPHOLE2: +@@ -5399,8 +5482,8 @@ main (int argc, const char **argv) + + /* Declare the gen_peephole2 routine that we'll call if the + pattern matches. The definition comes from insn-emit.cc. */ +- printf ("extern rtx_insn *gen_peephole2_%d (rtx_insn *, rtx *);\n", +- info.index); ++ fprintf (header, "extern rtx_insn *gen_peephole2_%d " ++ "(rtx_insn *, rtx *);\n", info.index); + break; + + default: +@@ -5411,7 +5494,8 @@ main (int argc, const char **argv) + if (have_error) + return FATAL_EXIT_CODE; + +- puts ("\n\n"); ++ for (auto f : output_files) ++ fprintf (f, "%s", "\n\n"); + + /* Optimize each routine in turn. */ + optimize_subroutine_group ("recog", &insn_root); +@@ -5433,15 +5517,27 @@ main (int argc, const char **argv) + /* Print out the routines that we just created. */ + unsigned int i; + pattern_routine *routine; ++ + FOR_EACH_VEC_ELT (patterns, i, routine) +- print_pattern (&os, routine); ++ print_pattern (header, &os, routine, true); ++ ++ FOR_EACH_VEC_ELT (patterns, i, routine) ++ { ++ file = choose_output (output_files, file_idx); ++ print_pattern (file, &os, routine); ++ } + } + + /* Print out the matching routines. */ +- print_subroutine_group (&os, RECOG, &insn_root); +- print_subroutine_group (&os, SPLIT, &split_root); +- print_subroutine_group (&os, PEEPHOLE2, &peephole2_root); ++ print_subroutine_group (output_files, header, &os, RECOG, &insn_root); ++ print_subroutine_group (output_files, header, &os, SPLIT, &split_root); ++ print_subroutine_group (output_files, header, &os, PEEPHOLE2, &peephole2_root); ++ ++ fclose (header); + +- fflush (stdout); +- return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); ++ int ret = SUCCESS_EXIT_CODE; ++ for (FILE *f : output_files) ++ if (fclose (f) != 0) ++ ret = FATAL_EXIT_CODE; ++ return ret; + } +diff --git a/gcc/gentarget-def.cc b/gcc/gentarget-def.cc +index 061b1e7247c1..3a462560cc1b 100644 +--- a/gcc/gentarget-def.cc ++++ b/gcc/gentarget-def.cc +@@ -191,7 +191,7 @@ def_target_insn (const char *name, const char *prototype) + printf ("target_have_%s (void)\n", name); + printf ("{\n"); + printf (" return "); +- rtx_reader_ptr->print_c_condition (test); ++ rtx_reader_ptr->print_c_condition (stdout, test); + printf (";\n"); + printf ("}\n"); + } +diff --git a/gcc/read-md.cc b/gcc/read-md.cc +index 93d1ea437812..aeb1cced00d0 100644 +--- a/gcc/read-md.cc ++++ b/gcc/read-md.cc +@@ -192,9 +192,9 @@ md_reader::fprint_c_condition (FILE *outf, const char *cond) + /* Special fprint_c_condition for writing to STDOUT. */ + + void +-md_reader::print_c_condition (const char *cond) ++md_reader::print_c_condition (FILE *outf, const char *cond) + { +- fprint_c_condition (stdout, cond); ++ fprint_c_condition (outf, cond); + } + + /* A vfprintf-like function for reporting an error against line LINENO +diff --git a/gcc/read-md.h b/gcc/read-md.h +index e613c42b7241..b42add391ed8 100644 +--- a/gcc/read-md.h ++++ b/gcc/read-md.h +@@ -205,7 +205,7 @@ class md_reader + + const char *join_c_conditions (const char *cond1, const char *cond2); + void fprint_c_condition (FILE *outf, const char *cond); +- void print_c_condition (const char *cond); ++ void print_c_condition (FILE *outf, const char *cond); + + /* Defined in read-rtl.cc. */ + const char *apply_iterator_to_string (const char *string); + +base-commit: a22dfe208d94105a6e587a3b25e8fe8d62444d8a +-- +2.47.1 +