diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 1c3b2c1a43b..0558cdfc8e6 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -10909,10 +10909,12 @@ A port might need to generate this pattern for a variable
 ways of doing this.  The first is to build the rtx for the pattern
 directly from C++ code; this is a valid technique and avoids any risk
 of combinatorial explosion.  The second is to prefix the instruction
-name with the special character @samp{@@}.  This tells GCC to generate
-the four additional functions below, where @var{name} is the name of
-the instruction without the @samp{@@} and without the @samp{<@dots{}>}
-placeholders.
+name with the special character @samp{@@}, which tells GCC to generate
+the four additional functions below.  In each case, @var{name} is the
+name of the instruction without the leading @samp{@@} character,
+without the @samp{<@dots{}>} placeholders, and with any underscore
+before a @samp{<@dots{}>} placeholder removed if keeping it would
+lead to a double or trailing underscore.
 
 @table @samp
 @item insn_code maybe_code_for_@var{name} (@var{i1}, @var{i2}, @dots{})
diff --git a/gcc/gencodes.c b/gcc/gencodes.c
index 05635e4da26..891f465df04 100644
--- a/gcc/gencodes.c
+++ b/gcc/gencodes.c
@@ -46,29 +46,6 @@ gen_insn (md_rtx_info *info)
     }
 }
 
-/* Declare the maybe_code_for_* function for ONAME, and provide
-   an inline definition of the assserting code_for_* wrapper.  */
-
-static void
-handle_overloaded_code_for (overloaded_name *oname)
-{
-  printf ("\nextern insn_code maybe_code_for_%s (", oname->name);
-  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
-  printf (");\n");
-
-  printf ("inline insn_code\ncode_for_%s (", oname->name);
-  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
-  printf (")\n{\n  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"
-	  "  gcc_assert (code != CODE_FOR_nothing);\n"
-	  "  return code;\n"
-	  "}\n");
-}
-
 int
 main (int argc, const char **argv)
 {
@@ -108,13 +85,8 @@ enum insn_code {\n\
 
   printf ("\n};\n\
 \n\
-const unsigned int NUM_INSN_CODES = %d;\n", get_num_insn_codes ());
-
-  for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
-       oname; oname = oname->next)
-    handle_overloaded_code_for (oname);
-
-  printf ("\n#endif /* GCC_INSN_CODES_H */\n");
+const unsigned int NUM_INSN_CODES = %d;\n\
+#endif /* GCC_INSN_CODES_H */\n", get_num_insn_codes ());
 
   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
     return FATAL_EXIT_CODE;
diff --git a/gcc/genemit.c b/gcc/genemit.c
index 92270302119..675cf04ff4b 100644
--- a/gcc/genemit.c
+++ b/gcc/genemit.c
@@ -761,7 +761,7 @@ print_overload_arguments (overloaded_name *oname)
     printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
 }
 
-/* Print code to test whether INSTANCE should be chosne, given that
+/* Print code to test whether INSTANCE should be chosen, given that
    argument N of the overload is available as "arg<N>".  */
 
 static void
diff --git a/gcc/genflags.c b/gcc/genflags.c
index ce8377778e7..6186d6433d9 100644
--- a/gcc/genflags.c
+++ b/gcc/genflags.c
@@ -197,37 +197,6 @@ gen_insn (md_rtx_info *info)
   obstack_grow (&obstack, &insn, sizeof (rtx));
 }
 
-/* Declare the maybe_gen_* function for ONAME, and provide
-   an inline definition of the assserting gen_* wrapper.  */
-
-static void
-emit_overloaded_gen_proto (overloaded_name *oname)
-{
-  unsigned int num_ops = num_operands (oname->first_instance->insn);
-
-  printf ("\nextern rtx maybe_gen_%s (", oname->name);
-  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
-  for (unsigned int i = 0; i < num_ops; ++i)
-    printf (", rtx");
-  printf (");\n");
-
-  printf ("inline rtx\ngen_%s (", oname->name);
-  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
-  for (unsigned int i = 0; i < num_ops; ++i)
-    printf (", rtx x%d", i);
-  printf (")\n{\n  rtx res = maybe_gen_%s (", oname->name);
-  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
-    printf ("%sarg%d", i == 0 ? "" : ", ", i);
-  for (unsigned int i = 0; i < num_ops; ++i)
-    printf (", x%d", i);
-  printf (");\n"
-	  "  gcc_assert (res);\n"
-	  "  return res;\n"
-	  "}\n");
-}
-
 int
 main (int argc, const char **argv)
 {
@@ -273,10 +242,6 @@ main (int argc, const char **argv)
   for (insn_ptr = insns; *insn_ptr; insn_ptr++)
     gen_proto (*insn_ptr);
 
-  for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
-       oname; oname = oname->next)
-    emit_overloaded_gen_proto (oname);
-
   puts ("\n#endif /* GCC_INSN_FLAGS_H */");
 
   if (have_error || ferror (stdout) || fflush (stdout) || fclose (stdout))
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 65a38d214bb..79835cc5d88 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -104,6 +104,63 @@ open_outfile (const char *file_name)
   return f;
 }
 
+/* Declare the maybe_code_for_* function for ONAME, and provide
+   an inline definition of the assserting code_for_* wrapper.  */
+
+static void
+handle_overloaded_code_for (FILE *file, overloaded_name *oname)
+{
+  fprintf (file, "\nextern insn_code maybe_code_for_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
+  fprintf (file, ");\n");
+
+  fprintf (file, "inline insn_code\ncode_for_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
+  fprintf (file, ")\n{\n  insn_code code = maybe_code_for_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
+  fprintf (file,
+	   ");\n"
+	   "  gcc_assert (code != CODE_FOR_nothing);\n"
+	   "  return code;\n"
+	   "}\n");
+}
+
+/* Declare the maybe_gen_* function for ONAME, and provide
+   an inline definition of the assserting gen_* wrapper.  */
+
+static void
+handle_overloaded_gen (FILE *file, overloaded_name *oname)
+{
+  pattern_stats stats;
+  get_pattern_stats (&stats, XVEC (oname->first_instance->insn, 1));
+
+  fprintf (file, "\nextern rtx maybe_gen_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%s%s", i == 0 ? "" : ", ", oname->arg_types[i]);
+  for (int i = 0; i < stats.num_generator_args; ++i)
+    fprintf (file, ", rtx");
+  fprintf (file, ");\n");
+
+  fprintf (file, "inline rtx\ngen_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i);
+  for (int i = 0; i < stats.num_generator_args; ++i)
+    fprintf (file, ", rtx x%d", i);
+  fprintf (file, ")\n{\n  rtx res = maybe_gen_%s (", oname->name);
+  for (unsigned int i = 0; i < oname->arg_types.length (); ++i)
+    fprintf (file, "%sarg%d", i == 0 ? "" : ", ", i);
+  for (int i = 0; i < stats.num_generator_args; ++i)
+    fprintf (file, ", x%d", i);
+  fprintf (file,
+	   ");\n"
+	   "  gcc_assert (res);\n"
+	   "  return res;\n"
+	   "}\n");
+}
+
 int
 main (int argc, const char **argv)
 {
@@ -220,7 +277,16 @@ main (int argc, const char **argv)
 	   "optab_to_code (optab op)\n"
 	   "{\n"
 	   "  return optab_to_code_[op];\n"
-	   "}\n"
+	   "}\n");
+
+  for (overloaded_name *oname = rtx_reader_ptr->get_overloads ();
+       oname; oname = oname->next)
+    {
+      handle_overloaded_code_for (h_file, oname);
+      handle_overloaded_gen (h_file, oname);
+    }
+
+  fprintf (h_file,
 	   "#endif\n"
 	   "\n"
 	   "extern const struct convert_optab_libcall_d convlib_def[NUM_CONVLIB_OPTABS];\n"
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index 9fece1fa09b..723c3e174b5 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -651,6 +651,7 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
   char *base = copy, *start, *end;
   overloaded_name tmp_oname;
   tmp_oname.arg_types.create (current_iterators.length ());
+  bool pending_underscore_p = false;
   while ((start = strchr (base, '<')) && (end = strchr (start, '>')))
     {
       *end = 0;
@@ -659,11 +660,28 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
 	fatal_with_file_and_line ("unknown iterator `%s'", start + 1);
       *end = '>';
 
-      /* Add the text between either the last '>' or the start of the string
-	 and this '<'.  */
+      /* Remove a trailing underscore, so that we don't end a name
+	 with "_" or turn "_<...>_" into "__".  */
+      if (start != base && start[-1] == '_')
+	{
+	  start -= 1;
+	  pending_underscore_p = true;
+	}
+
+      /* Add the text between either the last '>' or the start of
+	 the string and this '<'.  */
       obstack_grow (&m_string_obstack, base, start - base);
       base = end + 1;
 
+      /* If there's a character we need to keep after the '>', check
+	 whether we should prefix it with a previously-dropped '_'.  */
+      if (base[0] != 0 && base[0] != '<')
+	{
+	  if (pending_underscore_p && base[0] != '_')
+	    obstack_1grow (&m_string_obstack, '_');
+	  pending_underscore_p = false;
+	}
+
       /* Record an argument for ITERATOR.  */
       iterators->safe_push (iterator);
       tmp_oname.arg_types.safe_push (iterator->group->type);
@@ -671,6 +689,10 @@ md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
   if (base == copy)
     fatal_with_file_and_line ("no iterator attributes in name `%s'", name);
 
+  size_t length = obstack_object_size (&m_string_obstack);
+  if (length == 0)
+    fatal_with_file_and_line ("`%s' only contains iterator attributes", name);
+
   /* Get the completed name.  */
   obstack_grow (&m_string_obstack, base, strlen (base) + 1);
   char *new_name = XOBFINISH (&m_string_obstack, char *);
