gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Jun 2012 19:38:11 +0000 (19:38 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Jun 2012 19:38:11 +0000 (19:38 +0000)
* read-rtl.c (mapping): Remove index field.  Add current_value field.
Define heap vectors.
(iterator_group): Fix long line.  Remove num_builtins field and
uses_iterator fields.  Make apply_iterator take a void * parameter.
(iterator_use, atttribute_use): New structures.
(iterator_traverse_data, BELLWETHER_CODE, bellwether_codes): Delete.
(current_iterators, iterator_uses, attribute_uses): New variables.
(uses_mode_iterator_p, uses_code_iterator_p): Delete.
(apply_mode_iterator, apply_code_iterator): Take a void * parameter.
(map_attr_string, apply_iterator_to_string): Remove iterator
and value parameters.  Look through all current iterator values
for a matching attribute.
(mode_attr_index, apply_mode_maps): Delete.
(apply_iterator_to_rtx): Replace with...
(copy_rtx_for_iterators): ...this new function.
(uses_iterator_p, apply_iterator_traverse): Delete.
(apply_attribute_uses, add_current_iterators, apply_iterators): New
functions.
(add_mapping): Remove index field.  Set current_value field.
(initialize_iterators): Don't set num_builtins and uses_iterator_p
fields.
(find_iterator): Delete.
(record_iterator_use, record_attribute_use): New functions.
(record_potential_iterator_use): New function.
(check_code_iterator): Remove handling of bellwether codes.
(read_rtx): Remove mode maps.  Truncate iterator and attribute uses.
(read_rtx_code, read_nested_rtx, read_rtx_variadic): Remove mode_maps
parameter.  Use the first code iterator value instead of the
bellwether_codes array.  Use record_potential_iterator_use
for modes.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@188525 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/read-rtl.c

index 41a3e07..684361f 100644 (file)
@@ -1,3 +1,36 @@
+2012-06-13  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * read-rtl.c (mapping): Remove index field.  Add current_value field.
+       Define heap vectors.
+       (iterator_group): Fix long line.  Remove num_builtins field and
+       uses_iterator fields.  Make apply_iterator take a void * parameter.
+       (iterator_use, atttribute_use): New structures.
+       (iterator_traverse_data, BELLWETHER_CODE, bellwether_codes): Delete.
+       (current_iterators, iterator_uses, attribute_uses): New variables.
+       (uses_mode_iterator_p, uses_code_iterator_p): Delete.
+       (apply_mode_iterator, apply_code_iterator): Take a void * parameter.
+       (map_attr_string, apply_iterator_to_string): Remove iterator
+       and value parameters.  Look through all current iterator values
+       for a matching attribute.
+       (mode_attr_index, apply_mode_maps): Delete.
+       (apply_iterator_to_rtx): Replace with...
+       (copy_rtx_for_iterators): ...this new function.
+       (uses_iterator_p, apply_iterator_traverse): Delete.
+       (apply_attribute_uses, add_current_iterators, apply_iterators): New
+       functions.
+       (add_mapping): Remove index field.  Set current_value field.
+       (initialize_iterators): Don't set num_builtins and uses_iterator_p
+       fields.
+       (find_iterator): Delete.
+       (record_iterator_use, record_attribute_use): New functions.
+       (record_potential_iterator_use): New function.
+       (check_code_iterator): Remove handling of bellwether codes.
+       (read_rtx): Remove mode maps.  Truncate iterator and attribute uses.
+       (read_rtx_code, read_nested_rtx, read_rtx_variadic): Remove mode_maps
+       parameter.  Use the first code iterator value instead of the
+       bellwether_codes array.  Use record_potential_iterator_use
+       for modes.
+
 2012-06-13  Oleg Endo  <olegendo@gcc.gnu.org>
 
        PR target/53568
index 1402c54..c588722 100644 (file)
@@ -41,7 +41,7 @@ struct map_value {
 };
 
 /* 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 +50,80 @@ struct mapping {
   /* 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.  */
+/* Vector definitions for the above.  */
+typedef struct mapping *mapping_ptr;
+DEF_VEC_P (mapping_ptr);
+DEF_VEC_ALLOC_P (mapping_ptr, heap);
+
+/* 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 pointer use the given iterator value.  */
+  void (*apply_iterator) (void *, int);
+};
 
-  /* Make the given rtx use the given mode or code.  */
-  void (*apply_iterator) (rtx, int);
+/* 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.  */
+  void *ptr;
 };
 
-/* 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;
+/* Vector definitions for the above.  */
+typedef struct iterator_use iterator_use;
+DEF_VEC_O (iterator_use);
+DEF_VEC_ALLOC_O (iterator_use, heap);
+
+/* 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.  */
+  void *ptr;
 };
 
-/* 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])
-
-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);
+/* Vector definitions for the above.  */
+typedef struct attribute_use attribute_use;
+DEF_VEC_O (attribute_use);
+DEF_VEC_ALLOC_O (attribute_use, heap);
+
 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 rtx read_rtx_code (const char *);
+static rtx read_nested_rtx (void);
+static rtx read_rtx_variadic (rtx);
 
 /* The mode and code iterator structures.  */
 static struct iterator_group modes, codes;
 
-/* Index I is the value of BELLWETHER_CODE (I + NUM_RTX_CODE).  */
-static enum rtx_code *bellwether_codes;
+/* All iterators used in the current rtx.  */
+static VEC (mapping_ptr, heap) *current_iterators;
+
+/* The list of all iterator uses in the current rtx.  */
+static VEC (iterator_use, heap) *iterator_uses;
+
+/* The list of all attribute uses in the current rtx.  */
+static VEC (attribute_use, heap) *attribute_uses;
 
 /* Implementations of the iterator_group callbacks for modes.  */
 
@@ -141,16 +139,10 @@ find_mode (const char *name)
   fatal_with_file_and_line ("unknown mode `%s'", name);
 }
 
-static bool
-uses_mode_iterator_p (rtx x, int mode)
-{
-  return (int) GET_MODE (x) == mode;
-}
-
 static void
-apply_mode_iterator (rtx x, int mode)
+apply_mode_iterator (void *loc, int mode)
 {
-  PUT_MODE (x, (enum machine_mode) mode);
+  PUT_MODE ((rtx) loc, (enum machine_mode) mode);
 }
 
 /* Implementations of the iterator_group callbacks for codes.  */
@@ -167,122 +159,64 @@ find_code (const char *name)
   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 (void *loc, int code)
 {
-  PUT_CODE (x, (enum rtx_code) code);
+  PUT_CODE ((rtx) loc, (enum rtx_code) code);
 }
 
-/* Map a code or mode attribute string P to the underlying string for
-   ITERATOR and VALUE.  */
+/* 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.  */
-
-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;
-}
-
-/* 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;
-
-  indx = GET_MODE (x) - offset;
-  for (pm = mode_maps; pm; pm = pm->next)
+  FOR_EACH_VEC_ELT (mapping_ptr, current_iterators, i, iterator)
     {
-      if (pm->number == indx)
-       {
-         struct map_value *v;
+      /* 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;
 
-         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;
-       }
+      /* Find the attribute specification.  */
+      m = (struct mapping *) htab_find (iterator->group->attrs, &attr);
+      if (m)
+       /* 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;
 }
 
-/* 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.  */
+/* 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, struct mapping *iterator, int value)
+apply_iterator_to_string (const char *string)
 {
   char *base, *copy, *p, *start, *end;
   struct map_value *v;
@@ -296,7 +230,7 @@ apply_iterator_to_string (const char *string, struct mapping *iterator, int valu
       p = start + 1;
 
       *end = 0;
-      v = map_attr_string (p, iterator, value);
+      v = map_attr_string (p);
       *end = '>';
       if (v == 0)
        continue;
@@ -317,55 +251,39 @@ apply_iterator_to_string (const char *string, struct mapping *iterator, int valu
   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)
+copy_rtx_for_iterators (rtx original)
 {
-  struct iterator_group *group;
   const char *format_ptr;
   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);
+       XTMPL (x, i) = apply_iterator_to_string (XTMPL (x, i));
        break;
 
       case 'S':
       case 's':
-       XSTR (x, i) = apply_iterator_to_string (XSTR (x, i), iterator, value);
+       XSTR (x, i) = apply_iterator_to_string (XSTR (x, i));
        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 +292,8 @@ apply_iterator_to_rtx (rtx original, struct mapping *iterator, int value,
          {
            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,45 +303,6 @@ apply_iterator_to_rtx (rtx original, struct mapping *iterator, int value,
   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;
-}
-
 /* 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".  */
@@ -466,52 +344,117 @@ add_condition_to_rtx (rtx x, const char *extra)
     }
 }
 
-/* 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_use, 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->ptr,
+                                  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)
+    VEC_safe_push (mapping_ptr, heap, current_iterators, 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, rtx *queue)
+{
+  unsigned int i;
+  const char *condition;
+  iterator_use *iuse;
+  struct mapping *iterator;
+  struct map_value *v;
+  rtx x;
+
+  if (VEC_empty (iterator_use, iterator_uses))
+    {
+      /* Raise an error if any attributes were used.  */
+      apply_attribute_uses ();
+      XEXP (*queue, 0) = original;
+      XEXP (*queue, 1) = NULL_RTX;
+      return;
+    }
+
+  /* Clear out the iterators from the previous run.  */
+  FOR_EACH_VEC_ELT (mapping_ptr, current_iterators, i, iterator)
+    iterator->current_value = NULL;
+  VEC_truncate (mapping_ptr, current_iterators, 0);
+
+  /* Mark the iterators that we need this time.  */
+  FOR_EACH_VEC_ELT (iterator_use, 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);
+  gcc_assert (!VEC_empty (mapping_ptr, current_iterators));
+
+  for (;;)
+    {
+      /* Apply the current iterator values.  Accumulate a condition to
+        say when the resulting rtx can be used.  */
+      condition = NULL;
+      FOR_EACH_VEC_ELT (iterator_use, iterator_uses, i, iuse)
+       {
+         v = iuse->iterator->current_value;
+         iuse->iterator->group->apply_iterator (iuse->ptr, v->number);
+         condition = join_c_conditions (condition, v->string);
+       }
+      apply_attribute_uses ();
+      x = copy_rtx_for_iterators (original);
+      add_condition_to_rtx (x, condition);
+
+      /* Add the new rtx to the end of the queue.  */
+      XEXP (*queue, 0) = x;
+      XEXP (*queue, 1) = NULL_RTX;
+
+      /* 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 = VEC_length (mapping_ptr, current_iterators);
+      for (;;)
+       {
+         if (i == 0)
+           return;
+         i--;
+         iterator = VEC_index (mapping_ptr, current_iterators, i);
+         iterator->current_value = iterator->current_value->next;
+         if (iterator->current_value)
+           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);
+    }
+}
+
 /* 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 +467,8 @@ add_mapping (struct iterator_group *group, htab_t table, const char *name)
   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,17 +509,13 @@ 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.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;
 
   lower = add_mapping (&modes, modes.attrs, "mode");
@@ -714,18 +653,60 @@ validate_const_int (const char *string)
     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.  */
+/* Record that PTR uses iterator ITERATOR.  */
 
-static int
-find_iterator (struct iterator_group *group, const char *name)
+static void
+record_iterator_use (struct mapping *iterator, void *ptr)
+{
+  struct iterator_use *iuse;
+
+  iuse = VEC_safe_push (iterator_use, heap, iterator_uses, NULL);
+  iuse->iterator = iterator;
+  iuse->ptr = ptr;
+}
+
+/* Record that PTR uses attribute VALUE, which must match a built-in
+   value from group GROUP.  */
+
+static void
+record_attribute_use (struct iterator_group *group, void *ptr,
+                     const char *value)
+{
+  struct attribute_use *ause;
+
+  ause = VEC_safe_push (attribute_use, heap, attribute_uses, NULL);
+  ause->group = group;
+  ause->value = value;
+  ause->ptr = ptr;
+}
+
+/* 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)
 {
   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 (&string_obstack, name + 1, len - 2);
+      record_attribute_use (group, ptr, XOBFINISH (&string_obstack, char *));
+    }
+  else
+    {
+      m = (struct mapping *) htab_find (group->iterators, &name);
+      if (m != 0)
+       record_iterator_use (m, ptr);
+      else
+       group->apply_iterator (ptr, group->find_builtin (name));
+    }
 }
 
 /* Finish reading a declaration of the form:
@@ -787,7 +768,7 @@ read_mapping (struct iterator_group *group, htab_t table)
 }
 
 /* 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 +781,6 @@ check_code_iterator (struct mapping *iterator)
     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
@@ -815,8 +792,6 @@ bool
 read_rtx (const char *rtx_name, rtx *x)
 {
   static rtx queue_head;
-  struct map_value *mode_maps;
-  struct iterator_traverse_data mtd;
 
   /* Do one-time initialization.  */
   if (queue_head == 0)
@@ -853,18 +828,9 @@ read_rtx (const char *rtx_name, rtx *x)
       return false;
     }
 
-  mode_maps = 0;
-  XEXP (queue_head, 0) = read_rtx_code (rtx_name, &mode_maps);
-  XEXP (queue_head, 1) = 0;
-
-  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);
+  apply_iterators (read_rtx_code (rtx_name), &queue_head);
+  VEC_truncate (iterator_use, iterator_uses, 0);
+  VEC_truncate (attribute_use, attribute_uses, 0);
 
   *x = queue_head;
   return true;
@@ -872,13 +838,14 @@ read_rtx (const char *rtx_name, rtx *x)
 
 /* 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)
+read_rtx_code (const char *code_name)
 {
   int i;
-  RTX_CODE real_code, bellwether_code;
+  RTX_CODE code;
+  struct mapping *iterator;
   const char *format_ptr;
   struct md_name name;
   rtx return_rtx;
@@ -893,13 +860,21 @@ read_rtx_code (const char *code_name, struct map_value **mode_maps)
       rtx value;               /* Value of this node.  */
     };
 
-  real_code = (enum rtx_code) find_iterator (&codes, code_name);
-  bellwether_code = BELLWETHER_CODE (real_code);
+  /* 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);
 
   /* 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);
+  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.  */
@@ -907,16 +882,8 @@ read_rtx_code (const char *code_name, struct map_value **mode_maps)
   i = read_skip_spaces ();
   if (i == ':')
     {
-      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, name.string);
     }
   else
     unread_char (i);
@@ -931,7 +898,7 @@ read_rtx_code (const char *code_name, struct map_value **mode_maps)
 
       case 'e':
       case 'u':
-       XEXP (return_rtx, i) = read_nested_rtx (mode_maps);
+       XEXP (return_rtx, i) = read_nested_rtx ();
        break;
 
       case 'V':
@@ -965,7 +932,7 @@ read_rtx_code (const char *code_name, struct map_value **mode_maps)
                fatal_expected_char (']', c);
              unread_char (c);
              list_counter++;
-             obstack_ptr_grow (&vector_stack, read_nested_rtx (mode_maps));
+             obstack_ptr_grow (&vector_stack, read_nested_rtx ());
            }
          if (list_counter > 0)
            {
@@ -1075,17 +1042,16 @@ read_rtx_code (const char *code_name, struct map_value **mode_maps)
   if (c == '('
       && (GET_CODE (return_rtx) == AND
          || GET_CODE (return_rtx) == IOR))
-    return read_rtx_variadic (mode_maps, return_rtx);
+    return read_rtx_variadic (return_rtx);
 
   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)
+read_nested_rtx (void)
 {
   struct md_name name;
   int c;
@@ -1099,7 +1065,7 @@ read_nested_rtx (struct map_value **mode_maps)
   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 != ')')
@@ -1115,7 +1081,7 @@ read_nested_rtx (struct map_value **mode_maps)
    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)
+read_rtx_variadic (rtx form)
 {
   char c = '(';
   rtx p = form, q;
@@ -1128,7 +1094,7 @@ read_rtx_variadic (struct map_value **mode_maps, rtx form)
       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;