[PATCH 03/12] genoutput: write each output template out once

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

genoutput gives every pattern that needs one its own output_N definition,
whether or not an identical one has already been written.  Iterators are
what make that expensive: one define_insn expanded over a mode iterator
produces a pattern per mode, and where the template does not mention the
mode, every one of those patterns gets the same definition.

Two patterns produce identical definitions exactly when their
templates agree and come from the same place in the machine description,
since the location is what print_md_ptr_loc turns into the #line.  Key on
both, and have the second pattern name the first rather than repeat it.

On aarch64 the output_N definitions drop from 7990 to 3850.  The
multi-alternative tables account for most of that, 6305 to 2524; the
functions go from 1685 to 1326.  insn-output.cc goes from 7966037 bytes
in 125441 lines to 6777272 in 97657, and compiles in 18% less time,
with peak memory 424MB against 498MB.

Keying on the location as well as the text means the #line in a shared
definition still names the pattern it came from, so debug information and
any host compiler diagnostic about the template are unchanged.

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

gcc/ChangeLog:

        * genoutput.cc (data): Add output_code.
        (output_codes): New variable.
        (process_template): Reuse an identical definition emitted earlier,
        and record output_code.  Check every pattern against its template
        even when the definition is reused.
        (output_insn_data): Use output_code.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/genoutput.cc | 103 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 76 insertions(+), 27 deletions(-)

diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index 115b9bbc21a..f0141869fc4 100644
--- a/gcc/genoutput.cc
+++ b/gcc/genoutput.cc
@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "errors.h"
 #include "read-md.h"
 #include "gensupport.h"
+#include "hash-map.h"
 #include "hash-table.h"
 
 /* No instruction can have more operands than this.  Sorry for this
@@ -154,6 +155,7 @@ public:
   const char *template_code;
   file_location loc;
   int code_number;
+  int output_code;		/* Which output_* to use; see process_template.  */
   int n_generator_args;		/* Number of arguments passed to generator */
   int n_operands;		/* Number of operands this insn recognizes */
   int n_dups;			/* Number times match_dup appears in pattern */
@@ -351,10 +353,8 @@ output_insn_data (void)
 	  }
 	  break;
 	case INSN_OUTPUT_FORMAT_MULTI:
-	  printf ("output_%d, ", d->code_number);
-	  break;
 	case INSN_OUTPUT_FORMAT_FUNCTION:
-	  printf ("output_%d, ", d->code_number);
+	  printf ("output_%d, ", d->output_code);
 	  break;
 	default:
 	  gcc_unreachable ();
@@ -648,25 +648,60 @@ place_operands (class data *d)
    It is either the assembler code template, a list of assembler code
    templates, or C code to generate the assembler code template.  */
 
+/* The output_* definitions emitted so far, keyed by the template that
+   produced them together with the .md location that template came from.
+   Two patterns agreeing on both get byte-identical definitions, down to the
+   #line, so the second can name the first rather than repeat it.  */
+
+static hash_map<nofree_string_hash, int> output_codes;
+
 static void
 process_template (class data *d, const char *template_code)
 {
   const char *cp;
   int i;
 
+  d->output_code = d->code_number;
+
+  /* A template that needs a definition of its own may already have had one
+     emitted for an earlier pattern.  Every pattern is still checked against
+     its template below, since the checks read the pattern rather than the
+     template alone.  Only the definition is emitted once.  */
+  bool emit = true;
+  if (template_code[0] == '*' || template_code[0] == '@')
+    {
+      const md_reader::ptr_loc *loc
+	= rtx_reader_ptr->get_md_ptr_loc (template_code);
+      char *key = xasprintf ("%s:%d\n%s", loc ? loc->loc.filename : "",
+			     loc ? loc->loc.lineno : 0, template_code);
+      bool existed;
+      int &prev = output_codes.get_or_insert (key, &existed);
+      if (existed)
+	{
+	  free (key);
+	  d->output_code = prev;
+	  emit = false;
+	}
+      else
+	prev = d->code_number;
+    }
+
   /* Templates starting with * contain straight code to be run.  */
   if (template_code[0] == '*')
     {
       d->template_code = 0;
       d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
 
-      puts ("\nstatic const char *");
-      printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n",
-	      d->code_number);
-      puts ("{");
-      rtx_reader_ptr->print_md_ptr_loc (template_code);
-      puts (template_code + 1);
-      puts ("}");
+      if (emit)
+	{
+	  puts ("\nstatic const char *");
+	  printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n",
+		  d->code_number);
+	  puts ("{");
+	  rtx_reader_ptr->print_md_ptr_loc (template_code);
+	  puts (template_code + 1);
+	  puts ("}");
+	}
     }
 
   /* If the assembler code template starts with a @ it is a newline-separated
@@ -688,17 +723,21 @@ process_template (class data *d, const char *template_code)
       if (found_star)
 	{
 	  d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
-	  puts ("\nstatic const char *");
-	  printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, "
-		  "rtx_insn *insn ATTRIBUTE_UNUSED)\n", d->code_number);
-	  puts ("{");
-	  puts ("  switch (which_alternative)\n    {");
+	  if (emit)
+	    {
+	      puts ("\nstatic const char *");
+	      printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, "
+		      "rtx_insn *insn ATTRIBUTE_UNUSED)\n", d->code_number);
+	      puts ("{");
+	      puts ("  switch (which_alternative)\n    {");
+	    }
 	}
       else
 	{
 	  d->output_format = INSN_OUTPUT_FORMAT_MULTI;
-	  printf ("\nstatic const char * const output_%d[] = {\n",
-		  d->code_number);
+	  if (emit)
+	    printf ("\nstatic const char * const output_%d[] = {\n",
+		    d->code_number);
 	}
 
       for (i = 0, cp = &template_code[1]; *cp; )
@@ -711,16 +750,18 @@ process_template (class data *d, const char *template_code)
 	  bp = cp;
 	  if (found_star)
 	    {
-	      printf ("    case %d:", i);
+	      if (emit)
+		printf ("    case %d:", i);
 	      if (*cp == '*')
 		{
-		  printf ("\n      ");
+		  if (emit)
+		    printf ("\n      ");
 		  cp++;
 		}
-	      else
+	      else if (emit)
 		printf (" return \"");
 	    }
-	  else
+	  else if (emit)
 	    printf ("  \"");
 
 	  for (ep = sp = cp; !IS_VSPACE (*ep) && *ep != '\0'; ++ep)
@@ -739,8 +780,11 @@ process_template (class data *d, const char *template_code)
 		{
 		  if (*p == '\\' && p + 1 < sp)
 		    {
-		      putchar (*p);
-		      putchar (*(p+1));
+		      if (emit)
+			{
+			  putchar (*p);
+			  putchar (*(p+1));
+			}
 		      p += 2;
 		      continue;
 		    }
@@ -754,7 +798,8 @@ process_template (class data *d, const char *template_code)
 		  else if (*p == '<' || *p == '>')
 		    last_bracket = p;
 
-		  putchar (*p);
+		  if (emit)
+		    putchar (*p);
 		  p += 1;
 		}
 
@@ -767,7 +812,7 @@ process_template (class data *d, const char *template_code)
 			    "error in iterator syntax in %s", cp);
 		}
 	    }
-	  else
+	  else if (emit)
 	    {
 	      while (cp < sp)
 		putchar (*(cp++));
@@ -775,7 +820,9 @@ process_template (class data *d, const char *template_code)
 
 	  cp = sp;
 
-	  if (!found_star)
+	  if (!emit)
+	    ;
+	  else if (!found_star)
 	    puts ("\",");
 	  else if (*bp != '*')
 	    puts ("\";");
@@ -796,7 +843,9 @@ process_template (class data *d, const char *template_code)
 	error_at (d->loc, "wrong number of alternatives in the output"
 		  " template");
 
-      if (found_star)
+      if (!emit)
+	;
+      else if (found_star)
 	puts ("      default: gcc_unreachable ();\n    }\n}");
       else
 	printf ("};\n");
-- 
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.