diff gcc/read-rtl.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/read-rtl.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/read-rtl.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,7 +1,5 @@
 /* RTL reader for GCC.
-   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2007, 2008, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2017 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -19,7 +17,13 @@
 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
@@ -29,10 +33,15 @@
 #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;
@@ -41,7 +50,7 @@
 };
 
 /* Maps an iterator or attribute name to a list of (integer, string) pairs.
-   The integers are mode or code values; the strings are either C conditions
+   The integers are iterator values; the strings are either C conditions
    or attribute values.  */
 struct mapping {
   /* The name of the iterator or attribute.  */
@@ -50,82 +59,89 @@
   /* The group (modes or codes) to which the iterator or attribute belongs.  */
   struct iterator_group *group;
 
-  /* Gives a unique number to the attribute or iterator.  Numbers are
-     allocated consecutively, starting at 0.  */
-  int index;
-
   /* The list of (integer, string) pairs.  */
   struct map_value *values;
+
+  /* For iterators, records the current value of the iterator.  */
+  struct map_value *current_value;
 };
 
-/* A structure for abstracting the common parts of code and mode iterators.  */
+/* A structure for abstracting the common parts of iterators.  */
 struct iterator_group {
-  /* Tables of "mapping" structures, one for attributes and one for iterators.  */
+  /* Tables of "mapping" structures, one for attributes and one for
+     iterators.  */
   htab_t attrs, iterators;
 
-  /* The number of "real" modes or codes (and by extension, the first
-     number available for use as an iterator placeholder).  */
-  int num_builtins;
-
-  /* Treat the given string as the name of a standard mode or code and
+  /* Treat the given string as the name of a standard mode, etc., and
      return its integer value.  */
   int (*find_builtin) (const char *);
 
-  /* Return true if the given rtx uses the given mode or code.  */
-  bool (*uses_iterator_p) (rtx, int);
-
-  /* Make the given rtx use the given mode or code.  */
-  void (*apply_iterator) (rtx, 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);
 };
 
-/* A structure used to pass data from read_rtx to apply_iterator_traverse
-   via htab_traverse.  */
-struct iterator_traverse_data {
-  /* Instruction queue.  */
-  rtx queue;
-  /* Attributes seen for modes.  */
-  struct map_value *mode_maps;
-  /* The last unknown attribute used as a mode.  */
-  const char *unknown_mode_attr;
+/* Records one use of an iterator.  */
+struct iterator_use {
+  /* The iterator itself.  */
+  struct mapping *iterator;
+
+  /* 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;
 };
 
-/* If CODE is the number of a code iterator, return a real rtx code that
-   has the same format.  Return CODE otherwise.  */
-#define BELLWETHER_CODE(CODE) \
-  ((CODE) < NUM_RTX_CODE ? CODE : bellwether_codes[CODE - NUM_RTX_CODE])
+/* 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 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.
+     The index is the number of the operand that used the iterator
+     if applicable, otherwise it is ignored.  */
+  rtx x;
+  unsigned int index;
+};
 
-static int find_mode (const char *);
-static bool uses_mode_iterator_p (rtx, int);
-static void apply_mode_iterator (rtx, int);
-static int find_code (const char *);
-static bool uses_code_iterator_p (rtx, int);
-static void apply_code_iterator (rtx, int);
-static const char *apply_iterator_to_string (const char *, struct mapping *, int);
-static rtx apply_iterator_to_rtx (rtx, struct mapping *, int,
-				  struct map_value *, const char **);
-static bool uses_iterator_p (rtx, struct mapping *);
-static const char *add_condition_to_string (const char *, const char *);
-static void add_condition_to_rtx (rtx, const char *);
-static int apply_iterator_traverse (void **, void *);
-static struct mapping *add_mapping (struct iterator_group *, htab_t t,
-				    const char *);
-static struct map_value **add_map_value (struct map_value **,
-					 int, const char *);
-static void initialize_iterators (void);
-static void read_conditions (void);
+/* This struct is used to link subst_attr named ATTR_NAME with
+   corresponding define_subst named ITER_NAME.  */
+struct subst_attr_to_iter_mapping
+{
+    char *attr_name;
+    char *iter_name;
+};
+
+/* Hash-table to store links between subst-attributes and
+   define_substs.  */
+htab_t subst_attr_to_iter_map = NULL;
+/* This global stores name of subst-iterator which is currently being
+   processed.  */
+const char *current_iterator_name;
+
 static void validate_const_int (const char *);
-static int find_iterator (struct iterator_group *, const char *);
-static struct mapping *read_mapping (struct iterator_group *, htab_t);
-static void check_code_iterator (struct mapping *);
-static rtx read_rtx_code (const char *, struct map_value **);
-static rtx read_nested_rtx (struct map_value **);
-static rtx read_rtx_variadic (struct map_value **, 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;
+static struct iterator_group modes, codes, ints, substs;
+
+/* All iterators used in the current rtx.  */
+static vec<mapping *> current_iterators;
 
-/* Index I is the value of BELLWETHER_CODE (I + NUM_RTX_CODE).  */
-static enum rtx_code *bellwether_codes;
+/* The list of all iterator uses in the current rtx.  */
+static vec<iterator_use> iterator_uses;
+
+/* The list of all attribute uses in the current rtx.  */
+static vec<attribute_use> attribute_uses;
 
 /* Implementations of the iterator_group callbacks for modes.  */
 
@@ -141,17 +157,30 @@
   fatal_with_file_and_line ("unknown mode `%s'", name);
 }
 
-static bool
-uses_mode_iterator_p (rtx x, int mode)
+static void
+apply_mode_iterator (rtx x, unsigned int, int mode)
 {
-  return (int) GET_MODE (x) == mode;
+  PUT_MODE (x, (machine_mode) mode);
 }
 
-static void
-apply_mode_iterator (rtx x, int mode)
-{
-  PUT_MODE (x, (enum machine_mode) mode);
-}
+/* 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" }
+};
 
 /* Implementations of the iterator_group callbacks for codes.  */
 
@@ -164,125 +193,190 @@
     if (strcmp (GET_RTX_NAME (i), name) == 0)
       return i;
 
+  for (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;
+
   fatal_with_file_and_line ("unknown rtx code `%s'", name);
 }
 
-static bool
-uses_code_iterator_p (rtx x, int code)
-{
-  return (int) GET_CODE (x) == code;
-}
-
 static void
-apply_code_iterator (rtx x, int code)
+apply_code_iterator (rtx x, unsigned int, int code)
 {
   PUT_CODE (x, (enum rtx_code) code);
 }
 
-/* Map a code or mode attribute string P to the underlying string for
-   ITERATOR and VALUE.  */
+/* Implementations of the iterator_group callbacks for ints.  */
+
+/* Since GCC does not construct a table of valid constants,
+   we have to accept any int as valid.  No cross-checking can
+   be done.  */
+
+static int
+find_int (const char *name)
+{
+  validate_const_int (name);
+  return atoi (name);
+}
+
+static void
+apply_int_iterator (rtx x, unsigned int index, int value)
+{
+  XINT (x, index) = value;
+}
+
+#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 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 (rtx rt, unsigned int, int value)
+{
+  rtx new_attr;
+  rtvec attrs_vec, new_attrs_vec;
+  int i;
+  if (value == 1)
+    return;
+  gcc_assert (GET_CODE (rt) == DEFINE_INSN
+	      || GET_CODE (rt) == DEFINE_EXPAND);
+
+  attrs_vec = XVEC (rt, 4);
+
+  /* If we've already added attribute 'current_iterator_name', then we
+     have nothing to do now.  */
+  if (attrs_vec)
+    {
+      for (i = 0; i < GET_NUM_ELEM (attrs_vec); i++)
+	{
+	  if (strcmp (XSTR (attrs_vec->elem[i], 0), current_iterator_name) == 0)
+	    return;
+	}
+    }
+
+  /* Add attribute with subst name - it serves as a mark for
+     define_subst which later would be applied to this pattern.  */
+  new_attr = rtx_alloc (SET_ATTR);
+  PUT_CODE (new_attr, SET_ATTR);
+  XSTR (new_attr, 0) = xstrdup (current_iterator_name);
+  XSTR (new_attr, 1) = xstrdup ("yes");
+
+  if (!attrs_vec)
+    {
+      new_attrs_vec = rtvec_alloc (1);
+      new_attrs_vec->elem[0] = new_attr;
+    }
+  else
+    {
+      new_attrs_vec = rtvec_alloc (GET_NUM_ELEM (attrs_vec) + 1);
+      memcpy (&new_attrs_vec->elem[0], &attrs_vec->elem[0],
+	      GET_NUM_ELEM (attrs_vec) * sizeof (rtx));
+      new_attrs_vec->elem[GET_NUM_ELEM (attrs_vec)] = new_attr;
+    }
+  XVEC (rt, 4) = new_attrs_vec;
+}
+
+/* Map subst-attribute ATTR to subst iterator ITER.  */
+
+static void
+bind_subst_iter_and_attr (const char *iter, const char *attr)
+{
+  struct subst_attr_to_iter_mapping *value;
+  void **slot;
+  if (!subst_attr_to_iter_map)
+    subst_attr_to_iter_map =
+      htab_create (1, leading_string_hash, leading_string_eq_p, 0);
+  value = XNEW (struct subst_attr_to_iter_mapping);
+  value->attr_name = xstrdup (attr);
+  value->iter_name = xstrdup (iter);
+  slot = htab_find_slot (subst_attr_to_iter_map, value, INSERT);
+  *slot = value;
+}
+
+#endif /* #ifdef GENERATOR_FILE */
+
+/* Return name of a subst-iterator, corresponding to subst-attribute ATTR.  */
+
+static char*
+find_subst_iter_by_attr (const char *attr)
+{
+  char *iter_name = NULL;
+  struct subst_attr_to_iter_mapping *value;
+  value = (struct subst_attr_to_iter_mapping*)
+    htab_find (subst_attr_to_iter_map, &attr);
+  if (value)
+    iter_name = value->iter_name;
+  return iter_name;
+}
+
+/* Map attribute string P to its current value.  Return null if the attribute
+   isn't known.  */
 
 static struct map_value *
-map_attr_string (const char *p, struct mapping *iterator, int value)
+map_attr_string (const char *p)
 {
   const char *attr;
+  struct mapping *iterator;
+  unsigned int i;
   struct mapping *m;
   struct map_value *v;
+  int iterator_name_len;
 
-  /* If there's a "iterator:" prefix, check whether the iterator name matches.
-     Set ATTR to the start of the attribute name.  */
+  /* Peel off any "iterator:" prefix.  Set ATTR to the start of the
+     attribute name.  */
   attr = strchr (p, ':');
   if (attr == 0)
-    attr = p;
+    {
+      iterator_name_len = -1;
+      attr = p;
+    }
   else
     {
-      if (strncmp (p, iterator->name, attr - p) != 0
-	  || iterator->name[attr - p] != 0)
-	return 0;
+      iterator_name_len = attr - p;
       attr++;
     }
 
-  /* Find the attribute specification.  */
-  m = (struct mapping *) htab_find (iterator->group->attrs, &attr);
-  if (m == 0)
-    return 0;
-
-  /* Find the attribute value for VALUE.  */
-  for (v = m->values; v != 0; v = v->next)
-    if (v->number == value)
-      break;
-
-  return v;
-}
-
-/* Given an attribute string used as a machine mode, return an index
-   to store in the machine mode to be translated by
-   apply_iterator_to_rtx.  */
+  FOR_EACH_VEC_ELT (current_iterators, i, iterator)
+    {
+      /* If an iterator name was specified, check that it matches.  */
+      if (iterator_name_len >= 0
+	  && (strncmp (p, iterator->name, iterator_name_len) != 0
+	      || iterator->name[iterator_name_len] != 0))
+	continue;
 
-static unsigned int
-mode_attr_index (struct map_value **mode_maps, const char *string)
-{
-  char *p;
-  struct map_value *mv;
-
-  /* Copy the attribute string into permanent storage, without the
-     angle brackets around it.  */
-  obstack_grow0 (&string_obstack, string + 1, strlen (string) - 2);
-  p = XOBFINISH (&string_obstack, char *);
-
-  mv = XNEW (struct map_value);
-  mv->number = *mode_maps == 0 ? 0 : (*mode_maps)->number + 1;
-  mv->string = p;
-  mv->next = *mode_maps;
-  *mode_maps = mv;
-
-  /* We return a code which we can map back into this string: the
-     number of machine modes + the number of mode iterators + the index
-     we just used.  */
-  return MAX_MACHINE_MODE + htab_elements (modes.iterators) + mv->number;
+      /* Find the attribute specification.  */
+      m = (struct mapping *) htab_find (iterator->group->attrs, &attr);
+      if (m)
+	{
+	  /* In contrast to code/mode/int iterators, attributes of subst
+	     iterators are linked to one specific subst-iterator.  So, if
+	     we are dealing with subst-iterator, we should check if it's
+	     the one which linked with the given attribute.  */
+	  if (iterator->group == &substs)
+	    {
+	      char *iter_name = find_subst_iter_by_attr (attr);
+	      if (strcmp (iter_name, iterator->name) != 0)
+		continue;
+	    }
+	  /* Find the attribute value associated with the current
+	     iterator value.  */
+	  for (v = m->values; v; v = v->next)
+	    if (v->number == iterator->current_value->number)
+	      return v;
+	}
+    }
+  return NULL;
 }
 
-/* Apply MODE_MAPS to the top level of X, expanding cases where an
-   attribute is used for a mode.  ITERATOR is the current iterator we are
-   expanding, and VALUE is the value to which we are expanding it.
-   This sets *UNKNOWN to true if we find a mode attribute which has not
-   yet been defined, and does not change it otherwise.  */
-
-static void
-apply_mode_maps (rtx x, struct map_value *mode_maps, struct mapping *iterator,
-		 int value, const char **unknown)
-{
-  unsigned int offset;
-  int indx;
-  struct map_value *pm;
-
-  offset = MAX_MACHINE_MODE + htab_elements (modes.iterators);
-  if (GET_MODE (x) < offset)
-    return;
+/* Apply the current iterator values to STRING.  Return the new string
+   if any changes were needed, otherwise return STRING itself.  */
 
-  indx = GET_MODE (x) - offset;
-  for (pm = mode_maps; pm; pm = pm->next)
-    {
-      if (pm->number == indx)
-	{
-	  struct map_value *v;
-
-	  v = map_attr_string (pm->string, iterator, value);
-	  if (v)
-	    PUT_MODE (x, (enum machine_mode) find_mode (v->string));
-	  else
-	    *unknown = pm->string;
-	  return;
-	}
-    }
-}
-
-/* Given that ITERATOR is being expanded as VALUE, apply the appropriate
-   string substitutions 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, struct mapping *iterator, int value)
+const char *
+md_reader::apply_iterator_to_string (const char *string)
 {
   char *base, *copy, *p, *start, *end;
   struct map_value *v;
@@ -296,76 +390,62 @@
       p = start + 1;
 
       *end = 0;
-      v = map_attr_string (p, iterator, value);
+      v = map_attr_string (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;
     }
   return string;
 }
 
-/* Return a copy of ORIGINAL in which all uses of ITERATOR have been
-   replaced by VALUE.  MODE_MAPS holds information about attribute
-   strings used for modes.  This sets *UNKNOWN_MODE_ATTR to the value of
-   an unknown mode attribute, and does not change it otherwise.  */
+/* Return a deep copy of X, substituting the current iterator
+   values into any strings.  */
 
-static rtx
-apply_iterator_to_rtx (rtx original, struct mapping *iterator, int value,
-		       struct map_value *mode_maps,
-		       const char **unknown_mode_attr)
+rtx
+md_reader::copy_rtx_for_iterators (rtx original)
 {
-  struct iterator_group *group;
-  const char *format_ptr;
+  const char *format_ptr, *p;
   int i, j;
   rtx x;
-  enum rtx_code bellwether_code;
 
   if (original == 0)
     return original;
 
   /* Create a shallow copy of ORIGINAL.  */
-  bellwether_code = BELLWETHER_CODE (GET_CODE (original));
-  x = rtx_alloc (bellwether_code);
-  memcpy (x, original, RTX_CODE_SIZE (bellwether_code));
-
-  /* Change the mode or code itself.  */
-  group = iterator->group;
-  if (group->uses_iterator_p (x, iterator->index + group->num_builtins))
-    group->apply_iterator (x, value);
-
-  if (mode_maps)
-    apply_mode_maps (x, mode_maps, iterator, value, unknown_mode_attr);
+  x = rtx_alloc (GET_CODE (original));
+  memcpy (x, original, RTX_CODE_SIZE (GET_CODE (original)));
 
   /* Change each string and recursively change each rtx.  */
-  format_ptr = GET_RTX_FORMAT (bellwether_code);
+  format_ptr = GET_RTX_FORMAT (GET_CODE (original));
   for (i = 0; format_ptr[i] != 0; i++)
     switch (format_ptr[i])
       {
       case 'T':
-	XTMPL (x, i) = apply_iterator_to_string (XTMPL (x, i), iterator, value);
+	while (XTMPL (x, i) != (p = apply_iterator_to_string (XTMPL (x, i))))
+	  XTMPL (x, i) = p;
 	break;
 
       case 'S':
       case 's':
-	XSTR (x, i) = apply_iterator_to_string (XSTR (x, i), iterator, value);
+	while (XSTR (x, i) != (p = apply_iterator_to_string (XSTR (x, i))))
+	  XSTR (x, i) = p;
 	break;
 
       case 'e':
-	XEXP (x, i) = apply_iterator_to_rtx (XEXP (x, i), iterator, value,
-					     mode_maps, unknown_mode_attr);
+	XEXP (x, i) = copy_rtx_for_iterators (XEXP (x, i));
 	break;
 
       case 'V':
@@ -374,9 +454,8 @@
 	  {
 	    XVEC (x, i) = rtvec_alloc (XVECLEN (original, i));
 	    for (j = 0; j < XVECLEN (x, i); j++)
-	      XVECEXP (x, i, j) = apply_iterator_to_rtx (XVECEXP (original, i, j),
-							 iterator, value, mode_maps,
-							 unknown_mode_attr);
+	      XVECEXP (x, i, j)
+		= copy_rtx_for_iterators (XVECEXP (original, i, j));
 	  }
 	break;
 
@@ -386,44 +465,7 @@
   return x;
 }
 
-/* Return true if X (or some subexpression of X) uses iterator ITERATOR.  */
-
-static bool
-uses_iterator_p (rtx x, struct mapping *iterator)
-{
-  struct iterator_group *group;
-  const char *format_ptr;
-  int i, j;
-
-  if (x == 0)
-    return false;
-
-  group = iterator->group;
-  if (group->uses_iterator_p (x, iterator->index + group->num_builtins))
-    return true;
-
-  format_ptr = GET_RTX_FORMAT (BELLWETHER_CODE (GET_CODE (x)));
-  for (i = 0; format_ptr[i] != 0; i++)
-    switch (format_ptr[i])
-      {
-      case 'e':
-	if (uses_iterator_p (XEXP (x, i), iterator))
-	  return true;
-	break;
-
-      case 'V':
-      case 'E':
-	if (XVEC (x, i))
-	  for (j = 0; j < XVECLEN (x, i); j++)
-	    if (uses_iterator_p (XVECEXP (x, i, j), iterator))
-	      return true;
-	break;
-
-      default:
-	break;
-      }
-  return false;
-}
+#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
@@ -434,7 +476,7 @@
 {
   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.  */
@@ -446,6 +488,7 @@
     {
     case DEFINE_INSN:
     case DEFINE_EXPAND:
+    case DEFINE_SUBST:
       XSTR (x, 2) = add_condition_to_string (XSTR (x, 2), extra);
       break;
 
@@ -466,52 +509,132 @@
     }
 }
 
-/* A htab_traverse callback.  Search the EXPR_LIST given by DATA
-   for rtxes that use the iterator in *SLOT.  Replace each such rtx
-   with a list of expansions.  */
+/* Apply the current iterator values to all attribute_uses.  */
+
+static void
+apply_attribute_uses (void)
+{
+  struct map_value *v;
+  attribute_use *ause;
+  unsigned int i;
+
+  FOR_EACH_VEC_ELT (attribute_uses, i, ause)
+    {
+      v = map_attr_string (ause->value);
+      if (!v)
+	fatal_with_file_and_line ("unknown iterator value `%s'", ause->value);
+      ause->group->apply_iterator (ause->x, ause->index,
+				   ause->group->find_builtin (v->string));
+    }
+}
+
+/* A htab_traverse callback for iterators.  Add all used iterators
+   to current_iterators.  */
 
 static int
-apply_iterator_traverse (void **slot, void *data)
+add_current_iterators (void **slot, void *data ATTRIBUTE_UNUSED)
 {
-  struct iterator_traverse_data *mtd = (struct iterator_traverse_data *) data;
   struct mapping *iterator;
-  struct map_value *v;
-  rtx elem, new_elem, original, x;
 
   iterator = (struct mapping *) *slot;
-  for (elem = mtd->queue; elem != 0; elem = XEXP (elem, 1))
-    if (uses_iterator_p (XEXP (elem, 0), iterator))
-      {
-	/* For each iterator we expand, we set UNKNOWN_MODE_ATTR to NULL.
-	   If apply_iterator_rtx finds an unknown attribute for a mode,
-	   it will set it to the attribute.  We want to know whether
-	   the attribute is unknown after we have expanded all
-	   possible iterators, so setting it to NULL here gives us the
-	   right result when the hash table traversal is complete.  */
-	mtd->unknown_mode_attr = NULL;
-
-	original = XEXP (elem, 0);
-	for (v = iterator->values; v != 0; v = v->next)
-	  {
-	    x = apply_iterator_to_rtx (original, iterator, v->number,
-				       mtd->mode_maps,
-				       &mtd->unknown_mode_attr);
-	    add_condition_to_rtx (x, v->string);
-	    if (v != iterator->values)
-	      {
-		/* Insert a new EXPR_LIST node after ELEM and put the
-		   new expansion there.  */
-		new_elem = rtx_alloc (EXPR_LIST);
-		XEXP (new_elem, 1) = XEXP (elem, 1);
-		XEXP (elem, 1) = new_elem;
-		elem = new_elem;
-	      }
-	    XEXP (elem, 0) = x;
-	  }
-    }
+  if (iterator->current_value)
+    current_iterators.safe_push (iterator);
   return 1;
 }
 
+/* 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, vec<rtx> *queue)
+{
+  unsigned int i;
+  const char *condition;
+  iterator_use *iuse;
+  struct mapping *iterator;
+  struct map_value *v;
+  rtx x;
+
+  if (iterator_uses.is_empty ())
+    {
+      /* Raise an error if any attributes were used.  */
+      apply_attribute_uses ();
+      queue->safe_push (original);
+      return;
+    }
+
+  /* Clear out the iterators from the previous run.  */
+  FOR_EACH_VEC_ELT (current_iterators, i, iterator)
+    iterator->current_value = NULL;
+  current_iterators.truncate (0);
+
+  /* Mark the iterators that we need this time.  */
+  FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
+    iuse->iterator->current_value = iuse->iterator->values;
+
+  /* Get the list of iterators that are in use, preserving the
+     definition order within each group.  */
+  htab_traverse (modes.iterators, add_current_iterators, NULL);
+  htab_traverse (codes.iterators, add_current_iterators, NULL);
+  htab_traverse (ints.iterators, add_current_iterators, NULL);
+  htab_traverse (substs.iterators, add_current_iterators, NULL);
+  gcc_assert (!current_iterators.is_empty ());
+
+  for (;;)
+    {
+      /* Apply the current iterator values.  Accumulate a condition to
+	 say when the resulting rtx can be used.  */
+      condition = "";
+      FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
+	{
+	  if (iuse->iterator->group == &substs)
+	    continue;
+	  v = iuse->iterator->current_value;
+	  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 = 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
+	 subst-iterator processing, we could add an attribute to the
+	 RTL-template, and we don't want to do it in the original one.  */
+      FOR_EACH_VEC_ELT (iterator_uses, i, iuse)
+	{
+	  v = iuse->iterator->current_value;
+	  if (iuse->iterator->group == &substs)
+	    {
+	      iuse->x = x;
+	      iuse->index = 0;
+	      current_iterator_name = iuse->iterator->name;
+	      iuse->iterator->group->apply_iterator (iuse->x, iuse->index,
+						     v->number);
+	    }
+	}
+      /* Add the new rtx to the end of the queue.  */
+      queue->safe_push (x);
+
+      /* Lexicographically increment the iterator value sequence.
+	 That is, cycle through iterator values, starting from the right,
+	 and stopping when one of them doesn't wrap around.  */
+      i = current_iterators.length ();
+      for (;;)
+	{
+	  if (i == 0)
+	    return;
+	  i--;
+	  iterator = current_iterators[i];
+	  iterator->current_value = iterator->current_value->next;
+	  if (iterator->current_value)
+	    break;
+	  iterator->current_value = iterator->values;
+	}
+    }
+}
+#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.  */
 
@@ -524,8 +647,8 @@
   m = XNEW (struct mapping);
   m->name = xstrdup (name);
   m->group = group;
-  m->index = htab_elements (table);
   m->values = 0;
+  m->current_value = NULL;
 
   slot = htab_find_slot (table, m, INSERT);
   if (*slot != 0)
@@ -566,19 +689,29 @@
   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.num_builtins = MAX_MACHINE_MODE;
   modes.find_builtin = find_mode;
-  modes.uses_iterator_p = uses_mode_iterator_p;
   modes.apply_iterator = apply_mode_iterator;
 
   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.num_builtins = NUM_RTX_CODE;
   codes.find_builtin = find_code;
-  codes.uses_iterator_p = uses_code_iterator_p;
   codes.apply_iterator = apply_code_iterator;
 
+  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.find_builtin = find_int;
+  ints.apply_iterator = apply_int_iterator;
+
+  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.find_builtin = find_int; /* We don't use it, anyway.  */
+#ifdef GENERATOR_FILE
+  substs.apply_iterator = apply_subst_iterator;
+#endif
+
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
   lower_ptr = &lower->values;
@@ -610,7 +743,7 @@
 
 /* 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
@@ -633,7 +766,7 @@
       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;
@@ -646,6 +779,8 @@
 }
 #endif
 
+
+#ifdef GENERATOR_FILE
 /* Process a define_conditions directive, starting with the optional
    space after the "define_conditions".  The directive looks like this:
 
@@ -659,14 +794,12 @@
    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 ()) != ']')
     {
@@ -681,18 +814,15 @@
       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)
@@ -709,25 +839,92 @@
     valid = 0;
   for (; *cp; cp++)
     if (! ISDIGIT (*cp))
-      valid = 0;
+      {
+        valid = 0;
+	break;
+      }
   if (!valid)
     fatal_with_file_and_line ("invalid decimal constant \"%s\"\n", string);
 }
 
-/* Search GROUP for a mode or code called NAME and return its numerical
-   identifier.  */
+static void
+validate_const_wide_int (const char *string)
+{
+  const char *cp;
+  int valid = 1;
+
+  cp = string;
+  while (*cp && ISSPACE (*cp))
+    cp++;
+  /* Skip the leading 0x.  */
+  if (cp[0] == '0' || cp[1] == 'x')
+    cp += 2;
+  else
+    valid = 0;
+  if (*cp == 0)
+    valid = 0;
+  for (; *cp; cp++)
+    if (! ISXDIGIT (*cp))
+      valid = 0;
+  if (!valid)
+    fatal_with_file_and_line ("invalid hex constant \"%s\"\n", string);
+}
+
+/* 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 int
-find_iterator (struct iterator_group *group, const char *name)
+static void
+record_iterator_use (struct mapping *iterator, rtx x, unsigned int index)
+{
+  struct iterator_use iuse = {iterator, x, index};
+  iterator_uses.safe_push (iuse);
+}
+
+/* Record that X uses attribute VALUE, which 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, rtx x,
+		      unsigned int index, const char *value)
+{
+  struct attribute_use ause = {group, value, x, index};
+  attribute_uses.safe_push (ause);
+}
+
+/* Interpret NAME as either a built-in value, iterator or attribute
+   for group GROUP.  X and INDEX are the values to pass to GROUP's
+   apply_iterator callback.  */
+
+void
+md_reader::record_potential_iterator_use (struct iterator_group *group,
+					  rtx x, unsigned int index,
+					  const char *name)
 {
   struct mapping *m;
+  size_t len;
 
-  m = (struct mapping *) htab_find (group->iterators, &name);
-  if (m != 0)
-    return m->index + group->num_builtins;
-  return group->find_builtin (name);
+  len = strlen (name);
+  if (name[0] == '<' && name[len - 1] == '>')
+    {
+      /* Copy the attribute string into permanent storage, without the
+	 angle brackets around it.  */
+      obstack_grow0 (&m_string_obstack, name + 1, len - 2);
+      record_attribute_use (group, x, index,
+			    XOBFINISH (&m_string_obstack, char *));
+    }
+  else
+    {
+      m = (struct mapping *) htab_find (group->iterators, &name);
+      if (m != 0)
+	record_iterator_use (m, x, index);
+      else
+	group->apply_iterator (x, index, group->find_builtin (name));
+    }
 }
 
+#ifdef GENERATOR_FILE
+
 /* Finish reading a declaration of the form:
 
        (define... <name> [<value1> ... <valuen>])
@@ -738,8 +935,8 @@
    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;
@@ -751,9 +948,7 @@
   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;
@@ -773,9 +968,7 @@
 	  /* 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);
@@ -786,8 +979,89 @@
   return m;
 }
 
+/* For iterator with name ATTR_NAME generate define_attr with values
+   'yes' and 'no'.  This attribute is used to mark templates to which
+   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, vec<rtx> *queue)
+{
+  rtx const_str, return_rtx;
+
+  return_rtx = rtx_alloc (DEFINE_ATTR);
+  PUT_CODE (return_rtx, DEFINE_ATTR);
+
+  const_str = rtx_alloc (CONST_STRING);
+  PUT_CODE (const_str, CONST_STRING);
+  XSTR (const_str, 0) = xstrdup ("no");
+
+  XSTR (return_rtx, 0) = xstrdup (attr_name);
+  XSTR (return_rtx, 1) = xstrdup ("no,yes");
+  XEXP (return_rtx, 2) = const_str;
+
+  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, vec<rtx> *queue)
+{
+  rtx return_rtx;
+  int i;
+
+  return_rtx = rtx_alloc (DEFINE_SUBST_ATTR);
+  PUT_CODE (return_rtx, DEFINE_SUBST_ATTR);
+
+  for (i = 0; i < 4; i++)
+    XSTR (return_rtx, i) = xstrdup (attr_operands[i]);
+
+  queue->safe_push (return_rtx);
+}
+
+/* Read define_subst_attribute construction.  It has next form:
+	(define_subst_attribute <attribute_name> <iterator_name> <value1> <value2>)
+   Attribute is substituted with value1 when no subst is applied and with
+   value2 in the opposite case.
+   Attributes are added to SUBST_ATTRS_TABLE.
+   In case the iterator is encountered for the first time, it's added to
+   SUBST_ITERS_TABLE.  Also, implicit define_attr is generated.  */
+
+static void
+read_subst_mapping (htab_t subst_iters_table, htab_t subst_attrs_table,
+		    vec<rtx> *queue)
+{
+  struct mapping *m;
+  struct map_value **end_ptr;
+  const char *attr_operands[4];
+  int i;
+
+  for (i = 0; i < 4; i++)
+    attr_operands[i] = rtx_reader_ptr->read_string (false);
+
+  add_define_subst_attr (attr_operands, queue);
+
+  bind_subst_iter_and_attr (attr_operands[1], attr_operands[0]);
+
+  m = (struct mapping *) htab_find (substs.iterators, &attr_operands[1]);
+  if (!m)
+    {
+      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_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]);
+}
+
 /* Check newly-created code iterator ITERATOR to see whether every code has the
-   same format.  Initialize the iterator's entry in bellwether_codes.  */
+   same format.  */
 
 static void
 check_code_iterator (struct mapping *iterator)
@@ -800,10 +1074,6 @@
     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);
-
-  bellwether_codes = XRESIZEVEC (enum rtx_code, bellwether_codes,
-				 iterator->index + 1);
-  bellwether_codes[iterator->index] = bellwether;
 }
 
 /* Read an rtx-related declaration from the MD file, given that it
@@ -812,19 +1082,8 @@
    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;
-  struct map_value *mode_maps;
-  struct iterator_traverse_data mtd;
-
-  /* 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)
@@ -852,39 +1111,143 @@
       check_code_iterator (read_mapping (&codes, codes.iterators));
       return false;
     }
+  if (strcmp (rtx_name, "define_int_attr") == 0)
+    {
+      read_mapping (&ints, ints.attrs);
+      return false;
+    }
+  if (strcmp (rtx_name, "define_int_iterator") == 0)
+    {
+      read_mapping (&ints, ints.iterators);
+      return false;
+    }
+  if (strcmp (rtx_name, "define_subst_attr") == 0)
+    {
+      read_subst_mapping (substs.iterators, substs.attrs, rtxen);
 
-  mode_maps = 0;
-  XEXP (queue_head, 0) = read_rtx_code (rtx_name, &mode_maps);
-  XEXP (queue_head, 1) = 0;
+      /* READ_SUBST_MAPPING could generate a new DEFINE_ATTR.  Return
+	 TRUE to process it.  */
+      return true;
+    }
+
+  apply_iterators (rtx_reader_ptr->read_rtx_code (rtx_name), rtxen);
+  iterator_uses.truncate (0);
+  attribute_uses.truncate (0);
+
+  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.  */
 
-  mtd.queue = queue_head;
-  mtd.mode_maps = mode_maps;
-  mtd.unknown_mode_attr = mode_maps ? mode_maps->string : NULL;
-  htab_traverse (modes.iterators, apply_iterator_traverse, &mtd);
-  htab_traverse (codes.iterators, apply_iterator_traverse, &mtd);
-  if (mtd.unknown_mode_attr)
-    fatal_with_file_and_line ("undefined attribute '%s' used for mode",
-			      mtd.unknown_mode_attr);
+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;
+	}
 
-  *x = queue_head;
-  return true;
+      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 (0 == strcmp (string, GET_REG_NOTE_NAME (i)))
+      return i;
+  fatal_with_file_and_line ("unrecognized REG_NOTE name: `%s'", string);
 }
 
 /* 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.  MODE_MAPS is as for iterator_traverse_data.  */
+   return it.  */
 
-static rtx
-read_rtx_code (const char *code_name, struct map_value **mode_maps)
+rtx
+rtx_reader::read_rtx_code (const char *code_name)
 {
-  int i;
-  RTX_CODE real_code, bellwether_code;
+  RTX_CODE code;
+  struct mapping *iterator = NULL;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
   int c;
-  int tmp_int;
-  HOST_WIDE_INT tmp_wide;
+  long reuse_id = -1;
 
   /* Linked list structure for making RTXs: */
   struct rtx_list
@@ -893,150 +1256,335 @@
       rtx value;		/* Value of this node.  */
     };
 
-  real_code = (enum rtx_code) find_iterator (&codes, code_name);
-  bellwether_code = BELLWETHER_CODE (real_code);
+  /* 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 this code is an iterator, build the rtx using the iterator's
+     first value.  */
+#ifdef GENERATOR_FILE
+  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);
+#else
+    code = (enum rtx_code) codes.find_builtin (code_name);
+#endif
 
   /* If we end up with an insn expression then we free this space below.  */
-  return_rtx = rtx_alloc (bellwether_code);
-  format_ptr = GET_RTX_FORMAT (bellwether_code);
-  PUT_CODE (return_rtx, real_code);
+  return_rtx = rtx_alloc (code);
+  format_ptr = GET_RTX_FORMAT (code);
+  memset (return_rtx, 0, RTX_CODE_SIZE (code));
+  PUT_CODE (return_rtx, code);
+
+  if (reuse_id != -1)
+    {
+      /* 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;
+    }
+
+  if (iterator)
+    record_iterator_use (iterator, return_rtx, 0);
+
+  /* Check for flags. */
+  read_flags (return_rtx);
+
+  /* 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 == ':')
+	{
+	  read_name (&name);
+	  PUT_MODE_RAW (return_rtx,
+			(machine_mode)parse_reg_note_name (name.string));
+	}
+      else
+	unread_char (ch);
+    }
 
   /* If what follows is `: mode ', read it and
      store the mode in the rtx.  */
 
-  i = read_skip_spaces ();
-  if (i == ':')
+  c = read_skip_spaces ();
+  if (c == ':')
     {
-      unsigned int mode;
-
       read_name (&name);
-      if (name.string[0] != '<' || name.string[strlen (name.string) - 1] != '>')
-	mode = find_iterator (&modes, name.string);
-      else
-	mode = mode_attr_index (mode_maps, name.string);
-      PUT_MODE (return_rtx, (enum machine_mode) mode);
-      if (GET_MODE (return_rtx) != mode)
-	fatal_with_file_and_line ("mode too large");
+      record_potential_iterator_use (&modes, return_rtx, 0, name.string);
     }
   else
-    unread_char (i);
+    unread_char (c);
+
+  if (INSN_CHAIN_CODE_P (code))
+    {
+      read_name (&name);
+      INSN_UID (return_rtx) = atoi (name.string);
+    }
 
-  for (i = 0; format_ptr[i] != 0; i++)
-    switch (format_ptr[i])
+  /* 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);
+
+  /* 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))
+    {
+      read_name (&name);
+      validate_const_wide_int (name.string);
       {
-	/* 0 means a field for internal use only.
-	   Don't expect it to be present in the input.  */
-      case '0':
-	break;
+	const char *s = name.string;
+	int len;
+	int index = 0;
+	int gs = HOST_BITS_PER_WIDE_INT/4;
+	int pos;
+	char * buf = XALLOCAVEC (char, gs + 1);
+	unsigned HOST_WIDE_INT wi;
+	int wlen;
+
+	/* Skip the leading spaces.  */
+	while (*s && ISSPACE (*s))
+	  s++;
+
+	/* Skip the leading 0x.  */
+	gcc_assert (s[0] == '0');
+	gcc_assert (s[1] == 'x');
+	s += 2;
+
+	len = strlen (s);
+	pos = len - gs;
+	wlen = (len + gs - 1) / gs;	/* Number of words needed */
+
+	return_rtx = const_wide_int_alloc (wlen);
+
+	while (pos > 0)
+	  {
+#if HOST_BITS_PER_WIDE_INT == 64
+	    sscanf (s + pos, "%16" HOST_WIDE_INT_PRINT "x", &wi);
+#else
+	    sscanf (s + pos, "%8" HOST_WIDE_INT_PRINT "x", &wi);
+#endif
+	    CWI_ELT (return_rtx, index++) = wi;
+	    pos -= gs;
+	  }
+	strncpy (buf, s, gs - pos);
+	buf [gs - pos] = 0;
+	sscanf (buf, "%" HOST_WIDE_INT_PRINT "x", &wi);
+	CWI_ELT (return_rtx, index++) = wi;
+	/* TODO: After reading, do we want to canonicalize with:
+	   value = lookup_const_wide_int (value); ? */
+      }
+    }
+
+  c = read_skip_spaces ();
+  /* Syntactic sugar for AND and IOR, allowing Lisp-like
+     arbitrary number of arguments for them.  */
+  if (c == '('
+      && (GET_CODE (return_rtx) == AND
+	  || GET_CODE (return_rtx) == IOR))
+    return read_rtx_variadic (return_rtx);
+
+  unread_char (c);
+  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;
 
-      case 'e':
-      case 'u':
-	XEXP (return_rtx, i) = read_nested_rtx (mode_maps);
-	break;
+  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 'V':
-	/* 'V' is an optional vector: if a closeparen follows,
-	   just store NULL for this element.  */
+    case 'E':
+      {
+	/* Obstack to store scratch vector in.  */
+	struct obstack vector_stack;
+	int list_counter = 0;
+	rtvec return_vec = NULL_RTVEC;
+
+	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);
+	    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[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 == ')')
 	  {
-	    XVEC (return_rtx, i) = 0;
+	    /* '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;
 	  }
-	/* Now process the vector.  */
 
-      case 'E':
-	{
-	  /* Obstack to store scratch vector in.  */
-	  struct obstack vector_stack;
-	  int list_counter = 0;
-	  rtvec return_vec = NULL_RTVEC;
+	/* 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[idx] == 'T');
 
-	  c = read_skip_spaces ();
-	  if (c != '[')
-	    fatal_expected_char ('[', c);
+	stringbuf = read_string (star_if_braced);
+	if (!stringbuf)
+	  break;
 
-	  /* 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 (mode_maps));
-	    }
-	  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 */
-	}
-	break;
-
-      case 'S':
-      case 'T':
-      case 's':
-	{
-	  char *stringbuf;
-	  int star_if_braced;
+#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))
+	  {
+	    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 *);
+	  }
 
-	  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 : "");
+	/* 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;
-	    }
-
-	  /* 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);
+	    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 */
 
-	  /* 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 *);
-	    }
+	const char *string_ptr = finalize_string (stringbuf);
 
-	  if (star_if_braced)
-	    XTMPL (return_rtx, i) = stringbuf;
-	  else
-	    XSTR (return_rtx, i) = stringbuf;
-	}
-	break;
+	if (star_if_braced)
+	  XTMPL (return_rtx, idx) = string_ptr;
+	else
+	  XSTR (return_rtx, idx) = string_ptr;
+      }
+      break;
 
-      case 'w':
+    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
@@ -1047,63 +1595,62 @@
 #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)
+#if HAVE_DECL_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;
+	XWINT (return_rtx, idx) = tmp_wide;
+      }
+      break;
 
-      case 'i':
-      case 'n':
-	read_name (&name);
-	validate_const_int (name.string);
-	tmp_int = atoi (name.string);
-	XINT (return_rtx, i) = tmp_int;
-	break;
+    case 'i':
+    case 'n':
+      /* Can be an iterator or an integer constant.  */
+      read_name (&name);
+      record_potential_iterator_use (&ints, return_rtx, idx, name.string);
+      break;
 
-      default:
-	gcc_unreachable ();
-      }
+    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;
 
-  c = read_skip_spaces ();
-  /* Syntactic sugar for AND and IOR, allowing Lisp-like
-     arbitrary number of arguments for them.  */
-  if (c == '('
-      && (GET_CODE (return_rtx) == AND
-	  || GET_CODE (return_rtx) == IOR))
-    return read_rtx_variadic (mode_maps, return_rtx);
+    default:
+      gcc_unreachable ();
+    }
 
-  unread_char (c);
   return return_rtx;
 }
 
-/* Read a nested rtx construct from the MD file and return it.
-   MODE_MAPS is as for iterator_traverse_data.  */
+/* Read a nested rtx construct from the MD file and return it.  */
 
-static rtx
-read_nested_rtx (struct map_value **mode_maps)
+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)
     return_rtx = NULL;
   else
-    return_rtx = read_rtx_code (name.string, mode_maps);
+    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;
 }
@@ -1114,8 +1661,8 @@
    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 (struct map_value **mode_maps, rtx form)
+rtx
+rtx_reader::read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
@@ -1128,7 +1675,7 @@
       PUT_MODE (q, GET_MODE (p));
 
       XEXP (q, 0) = XEXP (p, 1);
-      XEXP (q, 1) = read_nested_rtx (mode_maps);
+      XEXP (q, 1) = read_nested_rtx ();
 
       XEXP (p, 1) = q;
       p = q;
@@ -1138,3 +1685,23 @@
   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;
+}