diff --git a/gcc/genemit.cc b/gcc/genemit.cc
index 6323aeb19fc..4cddaaa59b9 100644
--- a/gcc/genemit.cc
+++ b/gcc/genemit.cc
@@ -878,15 +878,14 @@ from the machine description file `md'.  */\n\n");
   fprintf (file, "#include \"target.h\"\n\n");
 }
 
-auto_vec<FILE *, 10> output_files;
+auto_vec<generator_output, 10> output_files;
 
 static bool
 handle_arg (const char *arg)
 {
   if (arg[1] == 'O')
     {
-      FILE *file = fopen (&arg[2], "w");
-      output_files.safe_push (file);
+      add_generator_output (output_files, &arg[2], true);
       return true;
     }
   return false;
@@ -910,13 +909,13 @@ main (int argc, const char **argv)
   md_rtx_info info;
 
   if (output_files.is_empty ())
-    output_files.safe_push (stdout);
+    add_generator_output (output_files, NULL, true);
+  open_generator_outputs (output_files);
 
-  for (auto f : output_files)
-    print_header (f);
+  for (const generator_output &output : output_files)
+    print_header (output.file);
 
   FILE *file = NULL;
-  unsigned file_idx;
 
   /* Read the machine description.  */
   while (read_md_rtx (&info))
@@ -941,7 +940,7 @@ main (int argc, const char **argv)
 
   for (auto &info : queue)
     {
-      file = choose_output (output_files, file_idx);
+      file = choose_output (output_files);
 
       fprintf (file, "/* %s:%d */\n", info.loc.filename, info.loc.lineno);
       switch (GET_CODE (info.def))
@@ -964,7 +963,7 @@ main (int argc, const char **argv)
 	}
     }
 
-  file = choose_output (output_files, file_idx);
+  file = choose_output (output_files);
 
   /* Write out the routines to add CLOBBERs to a pattern and say whether they
      clobber a hard reg.  */
@@ -978,10 +977,6 @@ main (int argc, const char **argv)
       handle_overloaded_gen (oname, file);
     }
 
-  int ret = SUCCESS_EXIT_CODE;
-  for (FILE *f : output_files)
-    if (fclose (f) != 0)
-      ret = FATAL_EXIT_CODE;
-
-  return ret;
+  return (close_generator_outputs (output_files)
+	  ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
 }
diff --git a/gcc/genrecog.cc b/gcc/genrecog.cc
index 663620224ab..ab9f3723e89 100644
--- a/gcc/genrecog.cc
+++ b/gcc/genrecog.cc
@@ -5288,11 +5288,10 @@ print_subroutine (FILE *f, output_state *os, state *s, int proc_id,
 /* Print out a routine of type TYPE that performs ROOT.  */
 
 static void
-print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os,
+print_subroutine_group (const vec<generator_output> &outputs, FILE *header,
+			output_state *os,
 			routine_type type, state *root)
 {
-  FILE *f;
-  unsigned idx;
   os->type = type;
   if (use_subroutines_p)
     {
@@ -5305,19 +5304,14 @@ print_subroutine_group (vec<FILE *> &vec, FILE *header, output_state *os,
       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)
-	{
-	  f = choose_output (vec, idx);
-	  print_subroutine (f, os, s, i + 1);
-	}
+	print_subroutine (choose_output (outputs), os, s, i + 1);
     }
   /* Output the main routine.  */
-  f = choose_output (vec, idx);
-  print_subroutine (f, os, root, 0);
+  print_subroutine (choose_output (outputs), os, root, 0);
 }
 
 /* Return the rtx pattern for the list of rtxes in a define_peephole2.  */
@@ -5388,24 +5382,22 @@ remove_clobbers (acceptance_type *acceptance_ptr, rtx *pattern_ptr)
   return true;
 }
 
-auto_vec<FILE *, 10> output_files;
-char header_name[255];
-FILE *header = NULL;
+auto_vec<generator_output, 10> output_files;
+const char *header_name;
 
 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);
+      add_generator_output (output_files, &arg[2], true);
       return true;
     }
   if (arg[1] == 'H')
     {
-      snprintf (header_name, 255, "%s", &arg[2]);
-      header = fopen (header_name, "w");
+      if (header_name)
+	fatal ("option -H specified more than once");
+      header_name = &arg[2];
       return true;
     }
   return false;
@@ -5421,14 +5413,18 @@ main (int argc, const char **argv)
   if (!init_rtx_reader_args_cb (argc, argv, handle_arg))
     return (FATAL_EXIT_CODE);
 
+  if (!header_name)
+    fatal ("no -H output file specified");
   if (output_files.is_empty ())
-    output_files.safe_push (stdout);
-
-  for (auto f : output_files)
-    write_header (f, header_name);
+    add_generator_output (output_files, NULL, true);
+  unsigned int header_index
+    = add_generator_output (output_files, header_name, false);
+  open_generator_outputs (output_files);
+  FILE *header = output_files[header_index].file;
 
-  FILE *file = NULL;
-  unsigned file_idx;
+  for (const generator_output &output : output_files)
+    if (output.partition_p)
+      write_header (output.file, header_name);
 
   /* Read the machine description.  */
 
@@ -5436,7 +5432,6 @@ 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;
@@ -5494,8 +5489,9 @@ main (int argc, const char **argv)
   if (have_error)
     return FATAL_EXIT_CODE;
 
-  for (auto f : output_files)
-    fprintf (f, "%s", "\n\n");
+  for (const generator_output &output : output_files)
+    if (output.partition_p)
+      fprintf (output.file, "%s", "\n\n");
 
   /* Optimize each routine in turn.  */
   optimize_subroutine_group ("recog", &insn_root);
@@ -5522,10 +5518,7 @@ main (int argc, const char **argv)
 	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_pattern (choose_output (output_files), &os, routine);
     }
 
   /* Print out the matching routines.  */
@@ -5533,11 +5526,6 @@ main (int argc, const char **argv)
   print_subroutine_group (output_files, header, &os, SPLIT, &split_root);
   print_subroutine_group (output_files, header, &os, PEEPHOLE2, &peephole2_root);
 
-  fclose (header);
-
-  int ret = SUCCESS_EXIT_CODE;
-  for (FILE *f : output_files)
-    if (fclose (f) != 0)
-      ret = FATAL_EXIT_CODE;
-  return ret;
+  return (close_generator_outputs (output_files)
+	  ? SUCCESS_EXIT_CODE : FATAL_EXIT_CODE);
 }
diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc
index 5fcc30d340e..9439ddd97d8 100644
--- a/gcc/gensupport.cc
+++ b/gcc/gensupport.cc
@@ -3935,35 +3935,77 @@ find_optab (optab_pattern *p, const char *name)
   return false;
 }
 
-/* Find the file to write into next.  We try to evenly distribute the contents
-   over the different files.  */
+/* Add output NAME to OUTPUTS.  A null NAME means standard output.
+   PARTITION_P is true if the output participates in size-based selection.
+   Return its index.  */
 
-#define SIZED_BASED_CHUNKS 1
+unsigned int
+add_generator_output (vec<generator_output> &outputs, const char *name,
+		      bool partition_p)
+{
+  gcc_assert (name || outputs.is_empty ());
+  if (name)
+    for (const generator_output &output : outputs)
+      if (output.name && canonical_filename_eq (name, output.name))
+	fatal ("output file %s specified more than once", name);
+
+  generator_output output = { name, name ? NULL : stdout, partition_p };
+  unsigned int index = outputs.length ();
+  outputs.safe_push (output);
+  return index;
+}
+
+/* Open each named file in OUTPUTS.  */
+
+void
+open_generator_outputs (vec<generator_output> &outputs)
+{
+  for (generator_output &output : outputs)
+    if (!output.file)
+      {
+	output.file = fopen (output.name, "w");
+	if (!output.file)
+	  fatal ("cannot open file %s: %s", output.name, xstrerror (errno));
+      }
+}
+
+/* Return the shortest partition file in OUTPUTS.  */
 
 FILE *
-choose_output (const vec<FILE *> &parts, unsigned &idx)
+choose_output (const vec<generator_output> &outputs)
 {
-  if (parts.length () == 0)
-    gcc_unreachable ();
-#ifdef SIZED_BASED_CHUNKS
   FILE *shortest = NULL;
   long min = 0;
-  idx = 0;
-  for (unsigned i = 0; i < parts.length (); i++)
+  for (const generator_output &output : outputs)
     {
-      FILE *part  = parts[i];
-      long len = ftell (part);
+      if (!output.partition_p)
+	continue;
+      long len = ftell (output.file);
       if (!shortest || min > len)
 	{
-	  shortest = part;
+	  shortest = output.file;
 	  min = len;
-	  idx = i;
-       }
+	}
     }
+  if (!shortest)
+    gcc_unreachable ();
   return shortest;
-#else
-  static int current_file;
-  idx = current_file++ % parts.length ();
-  return parts[idx];
-#endif
+}
+
+/* Close all files in OUTPUTS.  Return true if every close succeeds.  */
+
+bool
+close_generator_outputs (const vec<generator_output> &outputs)
+{
+  bool ok = true;
+  for (const generator_output &output : outputs)
+    {
+      if (fclose (output.file) != 0)
+	{
+	  error ("cannot close output %s: %s",
+		 output.name ? output.name : "<stdout>", xstrerror (errno));
+	  ok = false;
+	}
+    }
+  return ok;
 }
diff --git a/gcc/gensupport.h b/gcc/gensupport.h
index 86dd1103436..880505355b2 100644
--- a/gcc/gensupport.h
+++ b/gcc/gensupport.h
@@ -232,6 +232,20 @@ extern void compute_test_codes (rtx, file_location, char *);
 extern file_location get_file_location (rtx);
 extern const char *get_emit_function (rtx);
 extern bool find_optab (optab_pattern *, const char *);
-extern FILE *choose_output (const vec<FILE *> &, unsigned &);
+
+/* An output file produced by a machine-description generator.  Partition
+   files participate in size-based output selection.  */
+struct generator_output
+{
+  const char *name;
+  FILE *file;
+  bool partition_p;
+};
+
+extern unsigned int add_generator_output (vec<generator_output> &,
+					  const char *, bool);
+extern void open_generator_outputs (vec<generator_output> &);
+extern FILE *choose_output (const vec<generator_output> &);
+extern bool close_generator_outputs (const vec<generator_output> &);
 
 #endif /* GCC_GENSUPPORT_H */
