[PATCH 10/12] gensupport: Centralize machine-generator output management

<[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Kyrylo Tkachov <[email protected]>

genemit and genrecog use the same size-based output selection, but each
generator owns its file names, opens files during option parsing, and closes
them separately.  Adding more partitioned generators would copy this logic.

Put the common output record and lifecycle helpers in gensupport.  The helpers
validate names, delay file opening until option parsing is complete, select
only partition outputs by current size, and close every output with a useful
diagnostic.  Fixed outputs, such as headers, use the same record but do not
participate in selection.

Convert genemit and genrecog to the common interface.  Also remove the unused
output index and disabled round-robin code from choose_output, and remove a
genrecog selection whose result is discarded.  Diagnose missing or repeated
genrecog -H options, remove its fixed header-name limit, and stop printing
parsed output options to standard output.

Robin added the shared choose_output helper for PR111600, following the
size-based policy that Tamar used in genmatch.

The 20 normal emit and recog partition files are identical before and after
this change.  One-output files also match.  Duplicate name, cross-role alias,
missing option, open failure, and close failure tests pass.

Bootstrapped on aarch64-none-linux-gnu.  Ok for trunk?

gcc/ChangeLog:

	* gensupport.h (generator_output): New structure.
	(add_generator_output, open_generator_outputs): Declare.
	(close_generator_outputs): Likewise.
	(choose_output): Accept generator_output records.  Remove the output
	index parameter.
	* gensupport.cc (add_generator_output): New function.
	(open_generator_outputs, close_generator_outputs): Likewise.
	(choose_output): Select only partition records.  Remove the output index
	and disabled round-robin implementation.
	* genemit.cc (output_files): Use generator_output records.
	(handle_arg): Register output names.
	(main): Use the common open, selection, and close helpers.
	* genrecog.cc (print_subroutine_group): Accept generator_output records.
	(header_name): Change to a pointer.
	(header): Remove global variable.
	(output_files): Use generator_output records.
	(handle_arg): Register output names and validate -H.
	(main): Validate and register the header output.  Use the common open,
	selection, and close helpers.  Remove an unused output selection.

Suggested-by: Tamar Christina <[email protected]>
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/genemit.cc    | 27 +++++++---------
 gcc/genrecog.cc   | 64 +++++++++++++++----------------------
 gcc/gensupport.cc | 80 ++++++++++++++++++++++++++++++++++++-----------
 gcc/gensupport.h  | 16 +++++++++-
 4 files changed, 113 insertions(+), 74 deletions(-)

diff --git a/gcc/genemit.cc b/gcc/genemit.cc
index 9c881aa2bae..c40f7fc7fb1 100644
--- a/gcc/genemit.cc
+++ b/gcc/genemit.cc
@@ -877,15 +877,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;
@@ -909,13 +908,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))
@@ -940,7 +939,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))
@@ -963,7 +962,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.  */
@@ -976,15 +975,11 @@ main (int argc, const char **argv)
   for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
        oname; oname = oname->next)
     {
-      file = choose_output (output_files, file_idx);
+      file = choose_output (output_files);
       handle_overloaded_code_for (oname, file);
       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 04fc2330018..2adf29be705 100644
--- a/gcc/genrecog.cc
+++ b/gcc/genrecog.cc
@@ -5340,11 +5340,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)
     {
@@ -5357,19 +5356,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.  */
@@ -5440,24 +5434,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;
@@ -5473,14 +5465,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.  */
 
@@ -5488,7 +5484,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;
@@ -5546,8 +5541,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);
@@ -5574,10 +5570,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.  */
@@ -5588,11 +5581,6 @@ main (int argc, const char **argv)
   /* Every test has been printed, so the set of conditions is complete.  */
   print_md_conditions (header);
 
-  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 */
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.