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);

Reply via email to