]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/read-rtl.c
[Ada] Replace low-level membership tests with high-level routines
[thirdparty/gcc.git] / gcc / read-rtl.c
index 046286dbf8ae60bb63ab7deba92b94370d1ecfc1..3b5d999760314b2927df85a7d9ee48516de17dd7 100644 (file)
@@ -1,5 +1,5 @@
 /* RTL reader for GCC.
-   Copyright (C) 1987-2014 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -17,7 +17,13 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+/* This file is compiled twice: once for the generator programs
+   once for the compiler.  */
+#ifdef GENERATOR_FILE
 #include "bconfig.h"
+#else
+#include "config.h"
+#endif
 
 /* Disable rtl checking; it conflicts with the iterator handling.  */
 #undef ENABLE_RTL_CHECKING
@@ -27,10 +33,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "rtl.h"
 #include "obstack.h"
-#include "hashtab.h"
 #include "read-md.h"
 #include "gensupport.h"
 
+#ifndef GENERATOR_FILE
+#include "function.h"
+#include "memmodel.h"
+#include "emit-rtl.h"
+#endif
+
 /* One element in a singly-linked list of (integer, string) pairs.  */
 struct map_value {
   struct map_value *next;
@@ -55,21 +66,26 @@ struct mapping {
   struct map_value *current_value;
 };
 
-/* Vector definitions for the above.  */
-typedef struct mapping *mapping_ptr;
-
 /* A structure for abstracting the common parts of iterators.  */
 struct iterator_group {
   /* Tables of "mapping" structures, one for attributes and one for
      iterators.  */
   htab_t attrs, iterators;
 
+  /* The C++ type of the iterator, such as "machine_mode" for modes.  */
+  const char *type;
+
   /* Treat the given string as the name of a standard mode, etc., and
      return its integer value.  */
   int (*find_builtin) (const char *);
 
-  /* Make the given pointer use the given iterator value.  */
-  void (*apply_iterator) (void *, int);
+  /* Make the given rtx use the iterator value given by the third argument.
+     If the iterator applies to operands, the second argument gives the
+     operand index, otherwise it is ignored.  */
+  void (*apply_iterator) (rtx, unsigned int, int);
+
+  /* Return the C token for the given standard mode, code, etc.  */
+  const char *(*get_c_token) (int);
 };
 
 /* Records one use of an iterator.  */
@@ -77,29 +93,32 @@ struct iterator_use {
   /* The iterator itself.  */
   struct mapping *iterator;
 
-  /* The location of the use, as passed to the apply_iterator callback.  */
-  void *ptr;
+  /* The location of the use, as passed to the apply_iterator callback.
+     The index is the number of the operand that used the iterator
+     if applicable, otherwise it is ignored.  */
+  rtx x;
+  unsigned int index;
 };
 
-/* Vector definitions for the above.  */
-typedef struct iterator_use iterator_use;
-
 /* Records one use of an attribute (the "<[iterator:]attribute>" syntax)
    in a non-string rtx field.  */
 struct attribute_use {
   /* The group that describes the use site.  */
   struct iterator_group *group;
 
+  /* The location at which the use occurs.  */
+  file_location loc;
+
   /* The name of the attribute, possibly with an "iterator:" prefix.  */
   const char *value;
 
-  /* The location of the use, as passed to GROUP's apply_iterator callback.  */
-  void *ptr;
+  /* The location of the use, as passed to GROUP's apply_iterator callback.
+     The index is the number of the operand that used the iterator
+     if applicable, otherwise it is ignored.  */
+  rtx x;
+  unsigned int index;
 };
 
-/* Vector definitions for the above.  */
-typedef struct attribute_use attribute_use;
-
 /* This struct is used to link subst_attr named ATTR_NAME with
    corresponding define_subst named ITER_NAME.  */
 struct subst_attr_to_iter_mapping
@@ -116,15 +135,16 @@ htab_t subst_attr_to_iter_map = NULL;
 const char *current_iterator_name;
 
 static void validate_const_int (const char *);
-static rtx read_rtx_code (const char *);
-static rtx read_nested_rtx (void);
-static rtx read_rtx_variadic (rtx);
+static void one_time_initialization (void);
+
+/* Global singleton.  */
+rtx_reader *rtx_reader_ptr = NULL;
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes, ints, substs;
 
 /* All iterators used in the current rtx.  */
-static vec<mapping_ptr> current_iterators;
+static vec<mapping *> current_iterators;
 
 /* The list of all iterator uses in the current rtx.  */
 static vec<iterator_use> iterator_uses;
@@ -147,9 +167,50 @@ find_mode (const char *name)
 }
 
 static void
-apply_mode_iterator (void *loc, int mode)
+apply_mode_iterator (rtx x, unsigned int, int mode)
 {
-  PUT_MODE ((rtx) loc, (enum machine_mode) mode);
+  PUT_MODE (x, (machine_mode) mode);
+}
+
+static const char *
+get_mode_token (int mode)
+{
+  return concat ("E_", GET_MODE_NAME (mode), "mode", NULL);
+}
+
+/* In compact dumps, the code of insns is prefixed with "c", giving "cinsn",
+   "cnote" etc, and CODE_LABEL is special-cased as "clabel".  */
+
+struct compact_insn_name {
+  RTX_CODE code;
+  const char *name;
+};
+
+static const compact_insn_name compact_insn_names[] = {
+  { DEBUG_INSN, "cdebug_insn" },
+  { INSN, "cinsn" },
+  { JUMP_INSN, "cjump_insn" },
+  { CALL_INSN, "ccall_insn" },
+  { JUMP_TABLE_DATA, "cjump_table_data" },
+  { BARRIER, "cbarrier" },
+  { CODE_LABEL, "clabel" },
+  { NOTE, "cnote" }
+};
+
+/* Return the rtx code for NAME, or UNKNOWN if NAME isn't a valid rtx code.  */
+
+static rtx_code
+maybe_find_code (const char *name)
+{
+  for (int i = 0; i < NUM_RTX_CODE; i++)
+    if (strcmp (GET_RTX_NAME (i), name) == 0)
+      return (rtx_code) i;
+
+  for (int i = 0; i < (signed)ARRAY_SIZE (compact_insn_names); i++)
+    if (strcmp (compact_insn_names[i].name, name) == 0)
+      return compact_insn_names[i].code;
+
+  return UNKNOWN;
 }
 
 /* Implementations of the iterator_group callbacks for codes.  */
@@ -157,19 +218,25 @@ apply_mode_iterator (void *loc, int mode)
 static int
 find_code (const char *name)
 {
-  int i;
-
-  for (i = 0; i < NUM_RTX_CODE; i++)
-    if (strcmp (GET_RTX_NAME (i), name) == 0)
-      return i;
-
-  fatal_with_file_and_line ("unknown rtx code `%s'", name);
+  rtx_code code = maybe_find_code (name);
+  if (code == UNKNOWN)
+    fatal_with_file_and_line ("unknown rtx code `%s'", name);
+  return code;
 }
 
 static void
-apply_code_iterator (void *loc, int code)
+apply_code_iterator (rtx x, unsigned int, int code)
 {
-  PUT_CODE ((rtx) loc, (enum rtx_code) code);
+  PUT_CODE (x, (enum rtx_code) code);
+}
+
+static const char *
+get_code_token (int code)
+{
+  char *name = xstrdup (GET_RTX_NAME (code));
+  for (int i = 0; name[i]; ++i)
+    name[i] = TOUPPER (name[i]);
+  return name;
 }
 
 /* Implementations of the iterator_group callbacks for ints.  */
@@ -186,31 +253,48 @@ find_int (const char *name)
 }
 
 static void
-apply_int_iterator (void *loc, int value)
+apply_int_iterator (rtx x, unsigned int index, int value)
+{
+  if (GET_CODE (x) == SUBREG)
+    SUBREG_BYTE (x) = value;
+  else
+    XINT (x, index) = value;
+}
+
+static const char *
+get_int_token (int value)
 {
-  *(int *)loc = value;
+  char buffer[HOST_BITS_PER_INT + 1];
+  sprintf (buffer, "%d", value);
+  return xstrdup (buffer);
 }
 
+#ifdef GENERATOR_FILE
+
 /* This routine adds attribute or does nothing depending on VALUE.  When
    VALUE is 1, it does nothing - the first duplicate of original
    template is kept untouched when it's subjected to a define_subst.
-   When VALUE isn't 1, the routine modifies RTL-template LOC, adding
+   When VALUE isn't 1, the routine modifies RTL-template RT, adding
    attribute, named exactly as define_subst, which later will be
    applied.  If such attribute has already been added, then no the
    routine has no effect.  */
 static void
-apply_subst_iterator (void *loc, int value)
+apply_subst_iterator (rtx rt, unsigned int, int value)
 {
-  rtx rt = (rtx)loc;
   rtx new_attr;
   rtvec attrs_vec, new_attrs_vec;
   int i;
-  if (value == 1)
+  /* define_split has no attributes.  */
+  if (value == 1 || GET_CODE (rt) == DEFINE_SPLIT)
     return;
   gcc_assert (GET_CODE (rt) == DEFINE_INSN
+             || GET_CODE (rt) == DEFINE_INSN_AND_SPLIT
+             || GET_CODE (rt) == DEFINE_INSN_AND_REWRITE
              || GET_CODE (rt) == DEFINE_EXPAND);
 
-  attrs_vec = XVEC (rt, 4);
+  int attrs = (GET_CODE (rt) == DEFINE_INSN_AND_SPLIT ? 7
+              : GET_CODE (rt) == DEFINE_INSN_AND_REWRITE ? 6 : 4);
+  attrs_vec = XVEC (rt, attrs);
 
   /* If we've already added attribute 'current_iterator_name', then we
      have nothing to do now.  */
@@ -242,7 +326,7 @@ apply_subst_iterator (void *loc, int value)
              GET_NUM_ELEM (attrs_vec) * sizeof (rtx));
       new_attrs_vec->elem[GET_NUM_ELEM (attrs_vec)] = new_attr;
     }
-  XVEC (rt, 4) = new_attrs_vec;
+  XVEC (rt, attrs) = new_attrs_vec;
 }
 
 /* Map subst-attribute ATTR to subst iterator ITER.  */
@@ -262,6 +346,8 @@ bind_subst_iter_and_attr (const char *iter, const char *attr)
   *slot = value;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
 /* Return name of a subst-iterator, corresponding to subst-attribute ATTR.  */
 
 static char*
@@ -277,10 +363,11 @@ find_subst_iter_by_attr (const char *attr)
 }
 
 /* Map attribute string P to its current value.  Return null if the attribute
-   isn't known.  */
+   isn't known.  If ITERATOR_OUT is nonnull, store the associated iterator
+   there.  Report any errors against location LOC.  */
 
 static struct map_value *
-map_attr_string (const char *p)
+map_attr_string (file_location loc, const char *p, mapping **iterator_out = 0)
 {
   const char *attr;
   struct mapping *iterator;
@@ -288,6 +375,8 @@ map_attr_string (const char *p)
   struct mapping *m;
   struct map_value *v;
   int iterator_name_len;
+  struct map_value *res = NULL;
+  struct mapping *prev = NULL;
 
   /* Peel off any "iterator:" prefix.  Set ATTR to the start of the
      attribute name.  */
@@ -329,45 +418,59 @@ map_attr_string (const char *p)
             iterator value.  */
          for (v = m->values; v; v = v->next)
            if (v->number == iterator->current_value->number)
-             return v;
+             {
+               if (res && strcmp (v->string, res->string) != 0)
+                 {
+                   error_at (loc, "ambiguous attribute '%s'; could be"
+                             " '%s' (via '%s:%s') or '%s' (via '%s:%s')",
+                             attr, res->string, prev->name, attr,
+                             v->string, iterator->name, attr);
+                   return v;
+                 }
+               if (iterator_out)
+                 *iterator_out = iterator;
+               prev = iterator;
+               res = v;
+             }
        }
     }
-  return NULL;
+  return res;
 }
 
 /* Apply the current iterator values to STRING.  Return the new string
    if any changes were needed, otherwise return STRING itself.  */
 
-static const char *
-apply_iterator_to_string (const char *string)
+const char *
+md_reader::apply_iterator_to_string (const char *string)
 {
   char *base, *copy, *p, *start, *end;
   struct map_value *v;
 
-  if (string == 0)
+  if (string == 0 || string[0] == 0)
     return string;
 
+  file_location loc = get_md_ptr_loc (string)->loc;
   base = p = copy = ASTRDUP (string);
   while ((start = strchr (p, '<')) && (end = strchr (start, '>')))
     {
       p = start + 1;
 
       *end = 0;
-      v = map_attr_string (p);
+      v = map_attr_string (loc, p);
       *end = '>';
       if (v == 0)
        continue;
 
       /* Add everything between the last copied byte and the '<',
         then add in the attribute value.  */
-      obstack_grow (&string_obstack, base, start - base);
-      obstack_grow (&string_obstack, v->string, strlen (v->string));
+      obstack_grow (&m_string_obstack, base, start - base);
+      obstack_grow (&m_string_obstack, v->string, strlen (v->string));
       base = end + 1;
     }
   if (base != copy)
     {
-      obstack_grow (&string_obstack, base, strlen (base) + 1);
-      copy = XOBFINISH (&string_obstack, char *);
+      obstack_grow (&m_string_obstack, base, strlen (base) + 1);
+      copy = XOBFINISH (&m_string_obstack, char *);
       copy_md_ptr_loc (copy, string);
       return copy;
     }
@@ -377,8 +480,8 @@ apply_iterator_to_string (const char *string)
 /* Return a deep copy of X, substituting the current iterator
    values into any strings.  */
 
-static rtx
-copy_rtx_for_iterators (rtx original)
+rtx
+md_reader::copy_rtx_for_iterators (rtx original)
 {
   const char *format_ptr, *p;
   int i, j;
@@ -428,6 +531,8 @@ copy_rtx_for_iterators (rtx original)
   return x;
 }
 
+#ifdef GENERATOR_FILE
+
 /* Return a condition that must satisfy both ORIGINAL and EXTRA.  If ORIGINAL
    has the form "&& ..." (as used in define_insn_and_splits), assume that
    EXTRA is already satisfied.  Empty strings are treated like "true".  */
@@ -437,7 +542,7 @@ add_condition_to_string (const char *original, const char *extra)
 {
   if (original != 0 && original[0] == '&' && original[1] == '&')
     return original;
-  return join_c_conditions (original, extra);
+  return rtx_reader_ptr->join_c_conditions (original, extra);
 }
 
 /* Like add_condition, but applied to all conditions in rtx X.  */
@@ -461,6 +566,7 @@ add_condition_to_rtx (rtx x, const char *extra)
       break;
 
     case DEFINE_INSN_AND_SPLIT:
+    case DEFINE_INSN_AND_REWRITE:
       XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
       XSTR (x, 4) = add_condition_to_string (XSTR (x, 4), extra);
       break;
@@ -481,10 +587,10 @@ apply_attribute_uses (void)
 
   FOR_EACH_VEC_ELT (attribute_uses, i, ause)
     {
-      v = map_attr_string (ause->value);
+      v = map_attr_string (ause->loc, ause->value);
       if (!v)
        fatal_with_file_and_line ("unknown iterator value `%s'", ause->value);
-      ause->group->apply_iterator (ause->ptr,
+      ause->group->apply_iterator (ause->x, ause->index,
                                   ause->group->find_builtin (v->string));
     }
 }
@@ -503,11 +609,185 @@ add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED)
   return 1;
 }
 
+/* Return a hash value for overloaded_name UNCAST_ONAME.  There shouldn't
+   be many instances of two overloaded_names having the same name but
+   different arguments, so hashing on the name should be good enough in
+   practice.  */
+
+static hashval_t
+overloaded_name_hash (const void *uncast_oname)
+{
+  const overloaded_name *oname = (const overloaded_name *) uncast_oname;
+  return htab_hash_string (oname->name);
+}
+
+/* Return true if two overloaded_names are similar enough to share
+   the same generated functions.  */
+
+static int
+overloaded_name_eq_p (const void *uncast_oname1, const void *uncast_oname2)
+{
+  const overloaded_name *oname1 = (const overloaded_name *) uncast_oname1;
+  const overloaded_name *oname2 = (const overloaded_name *) uncast_oname2;
+  if (strcmp (oname1->name, oname2->name) != 0
+      || oname1->arg_types.length () != oname2->arg_types.length ())
+    return 0;
+
+  for (unsigned int i = 0; i < oname1->arg_types.length (); ++i)
+    if (strcmp (oname1->arg_types[i], oname2->arg_types[i]) != 0)
+      return 0;
+
+  return 1;
+}
+
+/* Return true if X has an instruction name in XSTR (X, 0).  */
+
+static bool
+named_rtx_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case DEFINE_EXPAND:
+    case DEFINE_INSN:
+    case DEFINE_INSN_AND_SPLIT:
+    case DEFINE_INSN_AND_REWRITE:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Check whether ORIGINAL is a named pattern whose name starts with '@'.
+   If so, return the associated overloaded_name and add the iterator for
+   each argument to ITERATORS.  Return null otherwise.  */
+
+overloaded_name *
+md_reader::handle_overloaded_name (rtx original, vec<mapping *> *iterators)
+{
+  /* Check for the leading '@'.  */
+  if (!named_rtx_p (original) || XSTR (original, 0)[0] != '@')
+    return NULL;
+
+  /* Remove the '@', so that no other code needs to worry about it.  */
+  const char *name = XSTR (original, 0);
+  file_location loc = get_md_ptr_loc (name)->loc;
+  copy_md_ptr_loc (name + 1, name);
+  name += 1;
+  XSTR (original, 0) = name;
+
+  /* Build a copy of the name without the '<...>' attribute strings.
+     Add the iterator associated with each such attribute string to ITERATORS
+     and add an associated argument to TMP_ONAME.  */
+  char *copy = ASTRDUP (name);
+  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;
+      mapping *iterator;
+      if (!map_attr_string (loc, start + 1, &iterator))
+       fatal_with_file_and_line ("unknown iterator `%s'", start + 1);
+      *end = '>';
+
+      /* 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);
+    }
+  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 *);
+  tmp_oname.name = new_name;
+
+  if (!m_overloads_htab)
+    m_overloads_htab = htab_create (31, overloaded_name_hash,
+                                   overloaded_name_eq_p, NULL);
+
+  /* See whether another pattern had the same overload name and list
+     of argument types.  Create a new permanent one if not.  */
+  void **slot = htab_find_slot (m_overloads_htab, &tmp_oname, INSERT);
+  overloaded_name *oname = (overloaded_name *) *slot;
+  if (!oname)
+    {
+      *slot = oname = new overloaded_name;
+      oname->name = tmp_oname.name;
+      oname->arg_types = tmp_oname.arg_types;
+      oname->next = NULL;
+      oname->first_instance = NULL;
+      oname->next_instance_ptr = &oname->first_instance;
+
+      *m_next_overload_ptr = oname;
+      m_next_overload_ptr = &oname->next;
+    }
+  else
+    {
+      obstack_free (&m_string_obstack, new_name);
+      tmp_oname.arg_types.release ();
+    }
+
+  return oname;
+}
+
+/* Add an instance of ONAME for instruction pattern X.  ITERATORS[I]
+   gives the iterator associated with argument I of ONAME.  */
+
+static void
+add_overload_instance (overloaded_name *oname, vec<mapping *> iterators, rtx x)
+{
+  /* Create the instance.  */
+  overloaded_instance *instance = new overloaded_instance;
+  instance->next = NULL;
+  instance->arg_values.create (oname->arg_types.length ());
+  for (unsigned int i = 0; i < iterators.length (); ++i)
+    {
+      int value = iterators[i]->current_value->number;
+      const char *name = iterators[i]->group->get_c_token (value);
+      instance->arg_values.quick_push (name);
+    }
+  instance->name = XSTR (x, 0);
+  instance->insn = x;
+
+  /* Chain it onto the end of ONAME's list.  */
+  *oname->next_instance_ptr = instance;
+  oname->next_instance_ptr = &instance->next;
+}
+
 /* Expand all iterators in the current rtx, which is given as ORIGINAL.
    Build a list of expanded rtxes in the EXPR_LIST pointed to by QUEUE.  */
 
 static void
-apply_iterators (rtx original, rtx *queue)
+apply_iterators (rtx original, vec<rtx> *queue)
 {
   unsigned int i;
   const char *condition;
@@ -520,8 +800,11 @@ apply_iterators (rtx original, rtx *queue)
     {
       /* Raise an error if any attributes were used.  */
       apply_attribute_uses ();
-      XEXP (*queue, 0) = original;
-      XEXP (*queue, 1) = NULL_RTX;
+
+      if (named_rtx_p (original) && XSTR (original, 0)[0] == '@')
+       fatal_with_file_and_line ("'@' used without iterators");
+
+      queue->safe_push (original);
       return;
     }
 
@@ -542,6 +825,11 @@ apply_iterators (rtx original, rtx *queue)
   htab_traverse (substs.iterators, add_current_iterators, NULL);
   gcc_assert (!current_iterators.is_empty ());
 
+  /* Check whether this is a '@' overloaded pattern.  */
+  auto_vec<mapping *, 16> iterators;
+  overloaded_name *oname
+    = rtx_reader_ptr->handle_overloaded_name (original, &iterators);
+
   for (;;)
     {
       /* Apply the current iterator values.  Accumulate a condition to
@@ -552,11 +840,12 @@ apply_iterators (rtx original, rtx *queue)
          if (iuse->iterator->group == &substs)
            continue;
          v = iuse->iterator->current_value;
-         iuse->iterator->group->apply_iterator (iuse->ptr, v->number);
-         condition = join_c_conditions (condition, v->string);
+         iuse->iterator->group->apply_iterator (iuse->x, iuse->index,
+                                                v->number);
+         condition = rtx_reader_ptr->join_c_conditions (condition, v->string);
        }
       apply_attribute_uses ();
-      x = copy_rtx_for_iterators (original);
+      x = rtx_reader_ptr->copy_rtx_for_iterators (original);
       add_condition_to_rtx (x, condition);
 
       /* We apply subst iterator after RTL-template is copied, as during
@@ -567,14 +856,19 @@ apply_iterators (rtx original, rtx *queue)
          v = iuse->iterator->current_value;
          if (iuse->iterator->group == &substs)
            {
-             iuse->ptr = x;
+             iuse->x = x;
+             iuse->index = 0;
              current_iterator_name = iuse->iterator->name;
-             iuse->iterator->group->apply_iterator (iuse->ptr, v->number);
+             iuse->iterator->group->apply_iterator (iuse->x, iuse->index,
+                                                    v->number);
            }
        }
+
+      if (oname)
+       add_overload_instance (oname, iterators, x);
+
       /* Add the new rtx to the end of the queue.  */
-      XEXP (*queue, 0) = x;
-      XEXP (*queue, 1) = NULL_RTX;
+      queue->safe_push (x);
 
       /* Lexicographically increment the iterator value sequence.
         That is, cycle through iterator values, starting from the right,
@@ -591,12 +885,9 @@ apply_iterators (rtx original, rtx *queue)
            break;
          iterator->current_value = iterator->values;
        }
-
-      /* At least one more rtx to go.  Allocate room for it.  */
-      XEXP (*queue, 1) = rtx_alloc (EXPR_LIST);
-      queue = &XEXP (*queue, 1);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 /* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
    of the mapping and GROUP is the group to which it belongs.  */
@@ -652,26 +943,36 @@ initialize_iterators (void)
   modes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
   modes.iterators = htab_create (13, leading_string_hash,
                                 leading_string_eq_p, 0);
+  modes.type = "machine_mode";
   modes.find_builtin = find_mode;
   modes.apply_iterator = apply_mode_iterator;
+  modes.get_c_token = get_mode_token;
 
   codes.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
   codes.iterators = htab_create (13, leading_string_hash,
                                 leading_string_eq_p, 0);
+  codes.type = "rtx_code";
   codes.find_builtin = find_code;
   codes.apply_iterator = apply_code_iterator;
+  codes.get_c_token = get_code_token;
 
   ints.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
   ints.iterators = htab_create (13, leading_string_hash,
                                 leading_string_eq_p, 0);
+  ints.type = "int";
   ints.find_builtin = find_int;
   ints.apply_iterator = apply_int_iterator;
+  ints.get_c_token = get_int_token;
 
   substs.attrs = htab_create (13, leading_string_hash, leading_string_eq_p, 0);
   substs.iterators = htab_create (13, leading_string_hash,
                                 leading_string_eq_p, 0);
+  substs.type = "int";
   substs.find_builtin = find_int; /* We don't use it, anyway.  */
+#ifdef GENERATOR_FILE
   substs.apply_iterator = apply_subst_iterator;
+#endif
+  substs.get_c_token = get_int_token;
 
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
@@ -704,7 +1005,7 @@ initialize_iterators (void)
 \f
 /* Provide a version of a function to read a long long if the system does
    not provide one.  */
-#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ)
+#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !HAVE_DECL_ATOLL && !defined(HAVE_ATOQ)
 HOST_WIDE_INT atoll (const char *);
 
 HOST_WIDE_INT
@@ -727,7 +1028,7 @@ atoll (const char *p)
       if (new_wide < tmp_wide)
        {
          /* Return INT_MAX equiv on overflow.  */
-         tmp_wide = (~(unsigned HOST_WIDE_INT) 0) >> 1;
+         tmp_wide = HOST_WIDE_INT_M1U >> 1;
          break;
        }
       tmp_wide = new_wide;
@@ -740,6 +1041,8 @@ atoll (const char *p)
 }
 #endif
 \f
+
+#ifdef GENERATOR_FILE
 /* Process a define_conditions directive, starting with the optional
    space after the "define_conditions".  The directive looks like this:
 
@@ -753,14 +1056,12 @@ atoll (const char *p)
    generated by (the program generated by) genconditions.c, and
    slipped in at the beginning of the sequence of MD files read by
    most of the other generators.  */
-static void
-read_conditions (void)
+void
+md_reader::read_conditions ()
 {
   int c;
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   while ( (c = read_skip_spaces ()) != ']')
     {
@@ -775,18 +1076,15 @@ read_conditions (void)
       validate_const_int (name.string);
       value = atoi (name.string);
 
-      c = read_skip_spaces ();
-      if (c != '"')
-       fatal_expected_char ('"', c);
+      require_char_ws ('"');
       expr = read_quoted_string ();
 
-      c = read_skip_spaces ();
-      if (c != ')')
-       fatal_expected_char (')', c);
+      require_char_ws (')');
 
       add_c_test (expr, value);
     }
 }
+#endif /* #ifdef GENERATOR_FILE */
 
 static void
 validate_const_int (const char *string)
@@ -834,33 +1132,37 @@ validate_const_wide_int (const char *string)
     fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
 }
 
-/* Record that PTR uses iterator ITERATOR.  */
+/* Record that X uses iterator ITERATOR.  If the use is in an operand
+   of X, INDEX is the index of that operand, otherwise it is ignored.  */
 
 static void
-record_iterator_use (struct mapping *iterator, void *ptr)
+record_iterator_use (struct mapping *iterator, rtx x, unsigned int index)
 {
-  struct iterator_use iuse = {iterator, ptr};
+  struct iterator_use iuse = {iterator, x, index};
   iterator_uses.safe_push (iuse);
 }
 
-/* Record that PTR uses attribute VALUE, which must match a built-in
-   value from group GROUP.  */
+/* Record that X uses attribute VALUE at location LOC, where VALUE must
+   match a built-in value from group GROUP.  If the use is in an operand
+   of X, INDEX is the index of that operand, otherwise it is ignored.  */
 
 static void
-record_attribute_use (struct iterator_group *group, void *ptr,
-                     const char *value)
+record_attribute_use (struct iterator_group *group, file_location loc, rtx x,
+                     unsigned int index, const char *value)
 {
-  struct attribute_use ause = {group, value, ptr};
+  struct attribute_use ause = {group, loc, value, x, index};
   attribute_uses.safe_push (ause);
 }
 
 /* Interpret NAME as either a built-in value, iterator or attribute
-   for group GROUP.  PTR is the value to pass to GROUP's apply_iterator
-   callback.  */
-
-static void
-record_potential_iterator_use (struct iterator_group *group, void *ptr,
-                              const char *name)
+   for group GROUP.  X and INDEX are the values to pass to GROUP's
+   apply_iterator callback.  LOC is the location of the use.  */
+
+void
+md_reader::record_potential_iterator_use (struct iterator_group *group,
+                                         file_location loc,
+                                         rtx x, unsigned int index,
+                                         const char *name)
 {
   struct mapping *m;
   size_t len;
@@ -870,19 +1172,22 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
     {
       /* Copy the attribute string into permanent storage, without the
         angle brackets around it.  */
-      obstack_grow0 (&string_obstack, name + 1, len - 2);
-      record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *));
+      obstack_grow0 (&m_string_obstack, name + 1, len - 2);
+      record_attribute_use (group, loc, x, index,
+                           XOBFINISH (&m_string_obstack, char *));
     }
   else
     {
       m = (struct mapping *) htab_find (group->iterators, &name);
       if (m != 0)
-       record_iterator_use (m, ptr);
+       record_iterator_use (m, x, index);
       else
-       group->apply_iterator (ptr, group->find_builtin (name));
+       group->apply_iterator (x, index, group->find_builtin (name));
     }
 }
 
+#ifdef GENERATOR_FILE
+
 /* Finish reading a declaration of the form:
 
        (define... <name> [<value1> ... <valuen>])
@@ -893,8 +1198,8 @@ record_potential_iterator_use (struct iterator_group *group, void *ptr,
    Represent the declaration as a "mapping" structure; add it to TABLE
    (which belongs to GROUP) and return it.  */
 
-static struct mapping *
-read_mapping (struct iterator_group *group, htab_t table)
+struct mapping *
+md_reader::read_mapping (struct iterator_group *group, htab_t table)
 {
   struct md_name name;
   struct mapping *m;
@@ -906,9 +1211,7 @@ read_mapping (struct iterator_group *group, htab_t table)
   read_name (&name);
   m = add_mapping (group, table, name.string);
 
-  c = read_skip_spaces ();
-  if (c != '[')
-    fatal_expected_char ('[', c);
+  require_char_ws ('[');
 
   /* Read each value.  */
   end_ptr = &m->values;
@@ -928,9 +1231,7 @@ read_mapping (struct iterator_group *group, htab_t table)
          /* A "(name string)" pair.  */
          read_name (&name);
          string = read_string (false);
-         c = read_skip_spaces ();
-         if (c != ')')
-           fatal_expected_char (')', c);
+         require_char_ws (')');
        }
       number = group->find_builtin (name.string);
       end_ptr = add_map_value (end_ptr, number, string);
@@ -946,7 +1247,7 @@ read_mapping (struct iterator_group *group, htab_t table)
    define_subst ATTR_NAME should be applied.  This attribute is set and
    defined implicitly and automatically.  */
 static void
-add_define_attr_for_define_subst (const char *attr_name, rtx *queue)
+add_define_attr_for_define_subst (const char *attr_name, vec<rtx> *queue)
 {
   rtx const_str, return_rtx;
 
@@ -961,14 +1262,13 @@ add_define_attr_for_define_subst (const char *attr_name, rtx *queue)
   XSTR (return_rtx, 1) = xstrdup ("no,yes");
   XEXP (return_rtx, 2) = const_str;
 
-  XEXP (*queue, 0) = return_rtx;
-  XEXP (*queue, 1) = NULL_RTX;
+  queue->safe_push (return_rtx);
 }
 
 /* This routine generates DEFINE_SUBST_ATTR expression with operands
    ATTR_OPERANDS and places it to QUEUE.  */
 static void
-add_define_subst_attr (const char **attr_operands, rtx *queue)
+add_define_subst_attr (const char **attr_operands, vec<rtx> *queue)
 {
   rtx return_rtx;
   int i;
@@ -979,8 +1279,7 @@ add_define_subst_attr (const char **attr_operands, rtx *queue)
   for (i = 0; i < 4; i++)
     XSTR (return_rtx, i) = xstrdup (attr_operands[i]);
 
-  XEXP (*queue, 0) = return_rtx;
-  XEXP (*queue, 1) = NULL_RTX;
+  queue->safe_push (return_rtx);
 }
 
 /* Read define_subst_attribute construction.  It has next form:
@@ -993,18 +1292,17 @@ add_define_subst_attr (const char **attr_operands, rtx *queue)
 
 static void
 read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
-                   rtx *queue)
+                   vec<rtx> *queue)
 {
   struct mapping *m;
   struct map_value **end_ptr;
   const char *attr_operands[4];
-  rtx * queue_elem = queue;
   int i;
 
   for (i = 0; i < 4; i++)
-    attr_operands[i] = read_string (false);
+    attr_operands[i] = rtx_reader_ptr->read_string (false);
 
-  add_define_subst_attr (attr_operands, queue_elem);
+  add_define_subst_attr (attr_operands, queue);
 
   bind_subst_iter_and_attr (attr_operands[1], attr_operands[0]);
 
@@ -1014,19 +1312,15 @@ read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
       m = add_mapping (&substs, subst_iters_table, attr_operands[1]);
       end_ptr = &m->values;
       end_ptr = add_map_value (end_ptr, 1, "");
-      end_ptr = add_map_value (end_ptr, 2, "");
-
-      /* Add element to the queue.  */
-      XEXP (*queue, 1) = rtx_alloc (EXPR_LIST);
-      queue_elem = &XEXP (*queue, 1);
+      add_map_value (end_ptr, 2, "");
 
-      add_define_attr_for_define_subst (attr_operands[1], queue_elem);
+      add_define_attr_for_define_subst (attr_operands[1], queue);
     }
 
   m = add_mapping (&substs, subst_attrs_table, attr_operands[0]);
   end_ptr = &m->values;
   end_ptr = add_map_value (end_ptr, 1, attr_operands[2]);
-  end_ptr = add_map_value (end_ptr, 2, attr_operands[3]);
+  add_map_value (end_ptr, 2, attr_operands[3]);
 }
 
 /* Check newly-created code iterator ITERATOR to see whether every code has the
@@ -1042,7 +1336,37 @@ check_code_iterator (struct mapping *iterator)
   for (v = iterator->values->next; v != 0; v = v->next)
     if (strcmp (GET_RTX_FORMAT (bellwether), GET_RTX_FORMAT (v->number)) != 0)
       fatal_with_file_and_line ("code iterator `%s' combines "
-                               "different rtx formats", iterator->name);
+                               "`%s' and `%s', which have different "
+                               "rtx formats", iterator->name,
+                               GET_RTX_NAME (bellwether),
+                               GET_RTX_NAME (v->number));
+}
+
+/* Check that all values of attribute ATTR are rtx codes that have a
+   consistent format.  Return a representative code.  */
+
+static rtx_code
+check_code_attribute (mapping *attr)
+{
+  rtx_code bellwether = UNKNOWN;
+  for (map_value *v = attr->values; v != 0; v = v->next)
+    {
+      rtx_code code = maybe_find_code (v->string);
+      if (code == UNKNOWN)
+       fatal_with_file_and_line ("code attribute `%s' contains "
+                                 "unrecognized rtx code `%s'",
+                                 attr->name, v->string);
+      if (bellwether == UNKNOWN)
+       bellwether = code;
+      else if (strcmp (GET_RTX_FORMAT (bellwether),
+                      GET_RTX_FORMAT (code)) != 0)
+       fatal_with_file_and_line ("code attribute `%s' combines "
+                                 "`%s' and `%s', which have different "
+                                 "rtx formats", attr->name,
+                                 GET_RTX_NAME (bellwether),
+                                 GET_RTX_NAME (code));
+    }
+  return bellwether;
 }
 
 /* Read an rtx-related declaration from the MD file, given that it
@@ -1051,17 +1375,8 @@ check_code_iterator (struct mapping *iterator)
    store the list of rtxes as an EXPR_LIST in *X.  */
 
 bool
-read_rtx (const char *rtx_name, rtx *x)
+rtx_reader::read_rtx (const char *rtx_name, vec<rtx> *rtxen)
 {
-  static rtx queue_head;
-
-  /* Do one-time initialization.  */
-  if (queue_head == 0)
-    {
-      initialize_iterators ();
-      queue_head = rtx_alloc (EXPR_LIST);
-    }
-
   /* Handle various rtx-related declarations that aren't themselves
      encoded as rtxes.  */
   if (strcmp (rtx_name, "define_conditions") == 0)
@@ -1101,40 +1416,179 @@ read_rtx (const char *rtx_name, rtx *x)
     }
   if (strcmp (rtx_name, "define_subst_attr") == 0)
     {
-      read_subst_mapping (substs.iterators, substs.attrs, &queue_head);
-      *x = queue_head;
+      read_subst_mapping (substs.iterators, substs.attrs, rtxen);
 
       /* READ_SUBST_MAPPING could generate a new DEFINE_ATTR.  Return
         TRUE to process it.  */
       return true;
     }
 
-  apply_iterators (read_rtx_code (rtx_name), &queue_head);
+  apply_iterators (rtx_reader_ptr->read_rtx_code (rtx_name), rtxen);
   iterator_uses.truncate (0);
   attribute_uses.truncate (0);
 
-  *x = queue_head;
   return true;
 }
 
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Do one-time initialization.  */
+
+static void
+one_time_initialization (void)
+{
+  static bool initialized = false;
+
+  if (!initialized)
+    {
+      initialize_iterators ();
+      initialized = true;
+    }
+}
+
+/* Consume characters until encountering a character in TERMINATOR_CHARS,
+   consuming the terminator character if CONSUME_TERMINATOR is true.
+   Return all characters before the terminator as an allocated buffer.  */
+
+char *
+rtx_reader::read_until (const char *terminator_chars, bool consume_terminator)
+{
+  int ch = read_skip_spaces ();
+  unread_char (ch);
+  auto_vec<char> buf;
+  while (1)
+    {
+      ch = read_char ();
+      if (strchr (terminator_chars, ch))
+       {
+         if (!consume_terminator)
+           unread_char (ch);
+         break;
+       }
+      buf.safe_push (ch);
+    }
+  buf.safe_push ('\0');
+  return xstrdup (buf.address ());
+}
+
+/* Subroutine of read_rtx_code, for parsing zero or more flags.  */
+
+static void
+read_flags (rtx return_rtx)
+{
+  while (1)
+    {
+      int ch = read_char ();
+      if (ch != '/')
+       {
+         unread_char (ch);
+         break;
+       }
+
+      int flag_char = read_char ();
+      switch (flag_char)
+       {
+         case 's':
+           RTX_FLAG (return_rtx, in_struct) = 1;
+           break;
+         case 'v':
+           RTX_FLAG (return_rtx, volatil) = 1;
+           break;
+         case 'u':
+           RTX_FLAG (return_rtx, unchanging) = 1;
+           break;
+         case 'f':
+           RTX_FLAG (return_rtx, frame_related) = 1;
+           break;
+         case 'j':
+           RTX_FLAG (return_rtx, jump) = 1;
+           break;
+         case 'c':
+           RTX_FLAG (return_rtx, call) = 1;
+           break;
+         case 'i':
+           RTX_FLAG (return_rtx, return_val) = 1;
+           break;
+         default:
+           fatal_with_file_and_line ("unrecognized flag: `%c'", flag_char);
+       }
+    }
+}
+
+/* Return the numeric value n for GET_REG_NOTE_NAME (n) for STRING,
+   or fail if STRING isn't recognized.  */
+
+static int
+parse_reg_note_name (const char *string)
+{
+  for (int i = 0; i < REG_NOTE_MAX; i++)
+    if (strcmp (string, GET_REG_NOTE_NAME (i)) == 0)
+      return i;
+  fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
+}
+
+/* Allocate an rtx for code NAME.  If NAME is a code iterator or code
+   attribute, record its use for later and use one of its possible
+   values as an interim rtx code.  */
+
+rtx
+rtx_reader::rtx_alloc_for_name (const char *name)
+{
+#ifdef GENERATOR_FILE
+  size_t len = strlen (name);
+  if (name[0] == '<' && name[len - 1] == '>')
+    {
+      /* Copy the attribute string into permanent storage, without the
+        angle brackets around it.  */
+      obstack *strings = get_string_obstack ();
+      obstack_grow0 (strings, name + 1, len - 2);
+      char *deferred_name = XOBFINISH (strings, char *);
+
+      /* Find the name of the attribute.  */
+      const char *attr = strchr (deferred_name, ':');
+      if (!attr)
+       attr = deferred_name;
+
+      /* Find the attribute itself.  */
+      mapping *m = (mapping *) htab_find (codes.attrs, &attr);
+      if (!m)
+       fatal_with_file_and_line ("unknown code attribute `%s'", attr);
+
+      /* Pick the first possible code for now, and record the attribute
+        use for later.  */
+      rtx x = rtx_alloc (check_code_attribute (m));
+      record_attribute_use (&codes, get_current_location (),
+                           x, 0, deferred_name);
+      return x;
+    }
+
+  mapping *iterator = (mapping *) htab_find (codes.iterators, &name);
+  if (iterator != 0)
+    {
+      /* Pick the first possible code for now, and record the iterator
+        use for later.  */
+      rtx x = rtx_alloc (rtx_code (iterator->values->number));
+      record_iterator_use (iterator, x, 0);
+      return x;
+    }
+#endif
+
+  return rtx_alloc (rtx_code (codes.find_builtin (name)));
+}
+
 /* Subroutine of read_rtx and read_nested_rtx.  CODE_NAME is the name of
    either an rtx code or a code iterator.  Parse the rest of the rtx and
    return it.  */
 
-static rtx
-read_rtx_code (const char *code_name)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
-  int i;
   RTX_CODE code;
-  struct mapping *iterator, *m;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
   int c;
-  HOST_WIDE_INT tmp_wide;
-  char *str;
-  char *start, *end, *ptr;
-  char tmpstr[256];
+  long reuse_id = -1;
 
   /* Linked list structure for making RTXs: */
   struct rtx_list
@@ -1143,212 +1597,85 @@ read_rtx_code (const char *code_name)
       rtx value;               /* Value of this node.  */
     };
 
-  /* If this code is an iterator, build the rtx using the iterator's
-     first value.  */
-  iterator = (struct mapping *) htab_find (codes.iterators, &code_name);
-  if (iterator != 0)
-    code = (enum rtx_code) iterator->values->number;
-  else
-    code = (enum rtx_code) codes.find_builtin (code_name);
+  /* Handle reuse_rtx ids e.g. "(0|scratch:DI)".  */
+  if (ISDIGIT (code_name[0]))
+    {
+      reuse_id = atoi (code_name);
+      while (char ch = *code_name++)
+       if (ch == '|')
+         break;
+    }
+
+  /* Handle "reuse_rtx".  */
+  if (strcmp (code_name, "reuse_rtx") == 0)
+    {
+      read_name (&name);
+      unsigned idx = atoi (name.string);
+      /* Look it up by ID.  */
+      gcc_assert (idx < m_reuse_rtx_by_id.length ());
+      return_rtx = m_reuse_rtx_by_id[idx];
+      return return_rtx;
+    }
 
   /* If we end up with an insn expression then we free this space below.  */
-  return_rtx = rtx_alloc (code);
+  return_rtx = rtx_alloc_for_name (code_name);
+  code = GET_CODE (return_rtx);
   format_ptr = GET_RTX_FORMAT (code);
   memset (return_rtx, 0, RTX_CODE_SIZE (code));
   PUT_CODE (return_rtx, code);
 
-  if (iterator)
-    record_iterator_use (iterator, return_rtx);
-
-  /* If what follows is `: mode ', read it and
-     store the mode in the rtx.  */
-
-  i = read_skip_spaces ();
-  if (i == ':')
+  if (reuse_id != -1)
     {
-      read_name (&name);
-      record_potential_iterator_use (&modes, return_rtx, name.string);
+      /* Store away for later reuse.  */
+      m_reuse_rtx_by_id.safe_grow_cleared (reuse_id + 1);
+      m_reuse_rtx_by_id[reuse_id] = return_rtx;
     }
-  else
-    unread_char (i);
 
-  for (i = 0; format_ptr[i] != 0; i++)
-    switch (format_ptr[i])
-      {
-       /* 0 means a field for internal use only.
-          Don't expect it to be present in the input.  */
-      case '0':
-       if (code == REG)
-         ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
-       break;
+  /* Check for flags. */
+  read_flags (return_rtx);
 
-      case 'e':
-      case 'u':
-       XEXP (return_rtx, i) = read_nested_rtx ();
-       break;
-
-      case 'V':
-       /* 'V' is an optional vector: if a closeparen follows,
-          just store NULL for this element.  */
-       c = read_skip_spaces ();
-       unread_char (c);
-       if (c == ')')
-         {
-           XVEC (return_rtx, i) = 0;
-           break;
-         }
-       /* Now process the vector.  */
-
-      case 'E':
+  /* Read REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+  if ((GET_CODE (return_rtx) == EXPR_LIST
+       || GET_CODE (return_rtx) == INSN_LIST
+       || GET_CODE (return_rtx) == INT_LIST)
+      && !m_in_call_function_usage)
+    {
+      char ch = read_char ();
+      if (ch == ':')
        {
-         /* Obstack to store scratch vector in.  */
-         struct obstack vector_stack;
-         int list_counter = 0;
-         rtvec return_vec = NULL_RTVEC;
-
-         c = read_skip_spaces ();
-         if (c != '[')
-           fatal_expected_char ('[', c);
-
-         /* Add expressions to a list, while keeping a count.  */
-         obstack_init (&vector_stack);
-         while ((c = read_skip_spaces ()) && c != ']')
-           {
-             if (c == EOF)
-               fatal_expected_char (']', c);
-             unread_char (c);
-             list_counter++;
-             obstack_ptr_grow (&vector_stack, read_nested_rtx ());
-           }
-         if (list_counter > 0)
-           {
-             return_vec = rtvec_alloc (list_counter);
-             memcpy (&return_vec->elem[0], obstack_finish (&vector_stack),
-                     list_counter * sizeof (rtx));
-           }
-         else if (format_ptr[i] == 'E')
-           fatal_with_file_and_line ("vector must have at least one element");
-         XVEC (return_rtx, i) = return_vec;
-         obstack_free (&vector_stack, NULL);
-         /* close bracket gotten */
+         read_name (&name);
+         PUT_MODE_RAW (return_rtx,
+                       (machine_mode)parse_reg_note_name (name.string));
        }
-       break;
-
-      case 'S':
-      case 'T':
-      case 's':
-       {
-         char *stringbuf;
-         int star_if_braced;
-
-         c = read_skip_spaces ();
-         unread_char (c);
-         if (c == ')')
-           {
-             /* 'S' fields are optional and should be NULL if no string
-                was given.  Also allow normal 's' and 'T' strings to be
-                omitted, treating them in the same way as empty strings.  */
-             XSTR (return_rtx, i) = (format_ptr[i] == 'S' ? NULL : "");
-             break;
-           }
-
-         /* The output template slot of a DEFINE_INSN,
-            DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically
-            gets a star inserted as its first character, if it is
-            written with a brace block instead of a string constant.  */
-         star_if_braced = (format_ptr[i] == 'T');
-
-         stringbuf = read_string (star_if_braced);
-
-         /* For insn patterns, we want to provide a default name
-            based on the file and line, like "*foo.md:12", if the
-            given name is blank.  These are only for define_insn and
-            define_insn_and_split, to aid debugging.  */
-         if (*stringbuf == '\0'
-             && i == 0
-             && (GET_CODE (return_rtx) == DEFINE_INSN
-                 || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
-           {
-             char line_name[20];
-             const char *fn = (read_md_filename ? read_md_filename : "rtx");
-             const char *slash;
-             for (slash = fn; *slash; slash ++)
-               if (*slash == '/' || *slash == '\\' || *slash == ':')
-                 fn = slash + 1;
-             obstack_1grow (&string_obstack, '*');
-             obstack_grow (&string_obstack, fn, strlen (fn));
-             sprintf (line_name, ":%d", read_md_lineno);
-             obstack_grow (&string_obstack, line_name, strlen (line_name)+1);
-             stringbuf = XOBFINISH (&string_obstack, char *);
-           }
+      else
+       unread_char (ch);
+    }
 
-         /* Find attr-names in the string.  */
-         ptr = &tmpstr[0];
-         end = stringbuf;
-         while ((start = strchr (end, '<')) && (end  = strchr (start, '>')))
-           {
-             if ((end - start - 1 > 0)
-                 && (end - start - 1 < (int)sizeof (tmpstr)))
-               {
-                 strncpy (tmpstr, start+1, end-start-1);
-                 tmpstr[end-start-1] = 0;
-                 end++;
-               }
-             else
-               break;
-             m = (struct mapping *) htab_find (substs.attrs, &ptr);
-             if (m != 0)
-               {
-                 /* Here we should find linked subst-iter.  */
-                 str = find_subst_iter_by_attr (ptr);
-                 if (str)
-                   m = (struct mapping *) htab_find (substs.iterators, &str);
-                 else
-                   m = 0;
-               }
-             if (m != 0)
-               record_iterator_use (m, return_rtx);
-           }
+  /* If what follows is `: mode ', read it and
+     store the mode in the rtx.  */
 
-         if (star_if_braced)
-           XTMPL (return_rtx, i) = stringbuf;
-         else
-           XSTR (return_rtx, i) = stringbuf;
-       }
-       break;
+  c = read_skip_spaces ();
+  if (c == ':')
+    {
+      file_location loc = read_name (&name);
+      record_potential_iterator_use (&modes, loc, return_rtx, 0, name.string);
+    }
+  else
+    unread_char (c);
 
-      case 'w':
-       read_name (&name);
-       validate_const_int (name.string);
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-       tmp_wide = atoi (name.string);
-#else
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-       tmp_wide = atol (name.string);
-#else
-       /* Prefer atoll over atoq, since the former is in the ISO C99 standard.
-          But prefer not to use our hand-rolled function above either.  */
-#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
-       tmp_wide = atoll (name.string);
-#else
-       tmp_wide = atoq (name.string);
-#endif
-#endif
-#endif
-       XWINT (return_rtx, i) = tmp_wide;
-       break;
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
 
-      case 'i':
-      case 'n':
-       /* Can be an iterator or an integer constant.  */
-       read_name (&name);
-       record_potential_iterator_use (&ints, &XINT (return_rtx, i),
-                                      name.string);
-       break;
+  /* Use the format_ptr to parse the various operands of this rtx.  */
+  for (int idx = 0; format_ptr[idx] != 0; idx++)
+    return_rtx = read_rtx_operand (return_rtx, idx);
 
-      default:
-       gcc_unreachable ();
-      }
+  /* Handle any additional information that after the regular fields
+     (e.g. when parsing function dumps).  */
+  handle_any_trailing_information (return_rtx);
 
   if (CONST_WIDE_INT_P (return_rtx))
     {
@@ -1410,18 +1737,271 @@ read_rtx_code (const char *code_name)
   return return_rtx;
 }
 
+/* Subroutine of read_rtx_code.  Parse operand IDX within RETURN_RTX,
+   based on the corresponding format character within GET_RTX_FORMAT
+   for the GET_CODE (RETURN_RTX), and return RETURN_RTX.
+   This is a virtual function, so that function_reader can override
+   some parsing, and potentially return a different rtx.  */
+
+rtx
+rtx_reader::read_rtx_operand (rtx return_rtx, int idx)
+{
+  RTX_CODE code = GET_CODE (return_rtx);
+  const char *format_ptr = GET_RTX_FORMAT (code);
+  int c;
+  struct md_name name;
+
+  switch (format_ptr[idx])
+    {
+      /* 0 means a field for internal use only.
+        Don't expect it to be present in the input.  */
+    case '0':
+      if (code == REG)
+       ORIGINAL_REGNO (return_rtx) = REGNO (return_rtx);
+      break;
+
+    case 'e':
+      XEXP (return_rtx, idx) = read_nested_rtx ();
+      break;
+
+    case 'u':
+      XEXP (return_rtx, idx) = read_nested_rtx ();
+      break;
+
+    case 'V':
+      /* 'V' is an optional vector: if a closeparen follows,
+        just store NULL for this element.  */
+      c = read_skip_spaces ();
+      unread_char (c);
+      if (c == ')')
+       {
+         XVEC (return_rtx, idx) = 0;
+         break;
+       }
+      /* Now process the vector.  */
+      /* FALLTHRU */
+
+    case 'E':
+      {
+       /* Obstack to store scratch vector in.  */
+       struct obstack vector_stack;
+       int list_counter = 0;
+       rtvec return_vec = NULL_RTVEC;
+       rtx saved_rtx = NULL_RTX;
+
+       require_char_ws ('[');
+
+       /* Add expressions to a list, while keeping a count.  */
+       obstack_init (&vector_stack);
+       while ((c = read_skip_spaces ()) && c != ']')
+         {
+           if (c == EOF)
+             fatal_expected_char (']', c);
+           unread_char (c);
+
+           rtx value;
+           int repeat_count = 1;
+           if (c == 'r')
+             {
+               /* Process "repeated xN" directive.  */
+               read_name (&name);
+               if (strcmp (name.string, "repeated"))
+                 fatal_with_file_and_line ("invalid directive \"%s\"\n",
+                                           name.string);
+               read_name (&name);
+               if (!sscanf (name.string, "x%d", &repeat_count))
+                 fatal_with_file_and_line ("invalid repeat count \"%s\"\n",
+                                           name.string);
+
+               /* We already saw one of the instances.  */
+               repeat_count--;
+               value = saved_rtx;
+             }
+           else
+             value = read_nested_rtx ();
+
+           for (; repeat_count > 0; repeat_count--)
+             {
+               list_counter++;
+               obstack_ptr_grow (&vector_stack, value);
+             }
+           saved_rtx = value;
+         }
+       if (list_counter > 0)
+         {
+           return_vec = rtvec_alloc (list_counter);
+           memcpy (&return_vec->elem[0], obstack_finish (&vector_stack),
+                   list_counter * sizeof (rtx));
+         }
+       else if (format_ptr[idx] == 'E')
+         fatal_with_file_and_line ("vector must have at least one element");
+       XVEC (return_rtx, idx) = return_vec;
+       obstack_free (&vector_stack, NULL);
+       /* close bracket gotten */
+      }
+      break;
+
+    case 'S':
+    case 'T':
+    case 's':
+      {
+       char *stringbuf;
+       int star_if_braced;
+
+       c = read_skip_spaces ();
+       unread_char (c);
+       if (c == ')')
+         {
+           /* 'S' fields are optional and should be NULL if no string
+              was given.  Also allow normal 's' and 'T' strings to be
+              omitted, treating them in the same way as empty strings.  */
+           XSTR (return_rtx, idx) = (format_ptr[idx] == 'S' ? NULL : "");
+           break;
+         }
+
+       /* The output template slot of a DEFINE_INSN, DEFINE_INSN_AND_SPLIT,
+          DEFINE_INSN_AND_REWRITE or DEFINE_PEEPHOLE automatically
+          gets a star inserted as its first character, if it is
+          written with a brace block instead of a string constant.  */
+       star_if_braced = (format_ptr[idx] == 'T');
+
+       stringbuf = read_string (star_if_braced);
+       if (!stringbuf)
+         break;
+
+#ifdef GENERATOR_FILE
+       /* For insn patterns, we want to provide a default name
+          based on the file and line, like "*foo.md:12", if the
+          given name is blank.  These are only for define_insn and
+          define_insn_and_split, to aid debugging.  */
+       if (*stringbuf == '\0'
+           && idx == 0
+           && (GET_CODE (return_rtx) == DEFINE_INSN
+               || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT
+               || GET_CODE (return_rtx) == DEFINE_INSN_AND_REWRITE))
+         {
+           const char *old_stringbuf = stringbuf;
+           struct obstack *string_obstack = get_string_obstack ();
+           char line_name[20];
+           const char *read_md_filename = get_filename ();
+           const char *fn = (read_md_filename ? read_md_filename : "rtx");
+           const char *slash;
+           for (slash = fn; *slash; slash ++)
+             if (*slash == '/' || *slash == '\\' || *slash == ':')
+               fn = slash + 1;
+           obstack_1grow (string_obstack, '*');
+           obstack_grow (string_obstack, fn, strlen (fn));
+           sprintf (line_name, ":%d", get_lineno ());
+           obstack_grow (string_obstack, line_name, strlen (line_name)+1);
+           stringbuf = XOBFINISH (string_obstack, char *);
+           copy_md_ptr_loc (stringbuf, old_stringbuf);
+         }
+
+       /* Find attr-names in the string.  */
+       char *str;
+       char *start, *end, *ptr;
+       char tmpstr[256];
+       ptr = &tmpstr[0];
+       end = stringbuf;
+       while ((start = strchr (end, '<')) && (end  = strchr (start, '>')))
+         {
+           if ((end - start - 1 > 0)
+               && (end - start - 1 < (int)sizeof (tmpstr)))
+             {
+               strncpy (tmpstr, start+1, end-start-1);
+               tmpstr[end-start-1] = 0;
+               end++;
+             }
+           else
+             break;
+           struct mapping *m
+             = (struct mapping *) htab_find (substs.attrs, &ptr);
+           if (m != 0)
+             {
+               /* Here we should find linked subst-iter.  */
+               str = find_subst_iter_by_attr (ptr);
+               if (str)
+                 m = (struct mapping *) htab_find (substs.iterators, &str);
+               else
+                 m = 0;
+             }
+           if (m != 0)
+             record_iterator_use (m, return_rtx, 0);
+         }
+#endif /* #ifdef GENERATOR_FILE */
+
+       const char *string_ptr = finalize_string (stringbuf);
+
+       if (star_if_braced)
+         XTMPL (return_rtx, idx) = string_ptr;
+       else
+         XSTR (return_rtx, idx) = string_ptr;
+      }
+      break;
+
+    case 'w':
+      {
+       HOST_WIDE_INT tmp_wide;
+       read_name (&name);
+       validate_const_int (name.string);
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+       tmp_wide = atoi (name.string);
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+       tmp_wide = atol (name.string);
+#else
+       /* Prefer atoll over atoq, since the former is in the ISO C99 standard.
+          But prefer not to use our hand-rolled function above either.  */
+#if HAVE_DECL_ATOLL || !defined(HAVE_ATOQ)
+       tmp_wide = atoll (name.string);
+#else
+       tmp_wide = atoq (name.string);
+#endif
+#endif
+#endif
+       XWINT (return_rtx, idx) = tmp_wide;
+      }
+      break;
+
+    case 'i':
+    case 'n':
+    case 'p':
+      {
+       /* Can be an iterator or an integer constant.  */
+       file_location loc = read_name (&name);
+       record_potential_iterator_use (&ints, loc, return_rtx, idx,
+                                      name.string);
+       break;
+      }
+
+    case 'r':
+      read_name (&name);
+      validate_const_int (name.string);
+      set_regno_raw (return_rtx, atoi (name.string), 1);
+      REG_ATTRS (return_rtx) = NULL;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return return_rtx;
+}
+
 /* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (void)
+rtx
+rtx_reader::read_nested_rtx ()
 {
   struct md_name name;
-  int c;
   rtx return_rtx;
 
-  c = read_skip_spaces ();
-  if (c != '(')
-    fatal_expected_char ('(', c);
+  /* In compact dumps, trailing "(nil)" values can be omitted.
+     Handle such dumps.  */
+  if (peek_char () == ')')
+    return NULL_RTX;
+
+  require_char_ws ('(');
 
   read_name (&name);
   if (strcmp (name.string, "nil") == 0)
@@ -1429,9 +2009,9 @@ read_nested_rtx (void)
   else
     return_rtx = read_rtx_code (name.string);
 
-  c = read_skip_spaces ();
-  if (c != ')')
-    fatal_expected_char (')', c);
+  require_char_ws (')');
+
+  return_rtx = postprocess (return_rtx);
 
   return return_rtx;
 }
@@ -1442,8 +2022,8 @@ read_nested_rtx (void)
    When called, FORM is (thing x1 x2), and the file position
    is just past the leading parenthesis of x3.  Only works
    for THINGs which are dyadic expressions, e.g. AND, IOR.  */
-static rtx
-read_rtx_variadic (rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
@@ -1466,3 +2046,23 @@ read_rtx_variadic (rtx form)
   unread_char (c);
   return form;
 }
+
+/* Constructor for class rtx_reader.  */
+
+rtx_reader::rtx_reader (bool compact)
+: md_reader (compact),
+  m_in_call_function_usage (false)
+{
+  /* Set the global singleton pointer.  */
+  rtx_reader_ptr = this;
+
+  one_time_initialization ();
+}
+
+/* Destructor for class rtx_reader.  */
+
+rtx_reader::~rtx_reader ()
+{
+  /* Clear the global singleton pointer.  */
+  rtx_reader_ptr = NULL;
+}