Patchwork RFA: Alternative iterator implementation

login
register
mail settings
Submitter Tejas Belagod
Date June 11, 2012, 5:07 p.m.
Message ID <4FD625D1.5090000@arm.com>
Download mbox | patch
Permalink /patch/164228/
State New
Headers show

Comments

Tejas Belagod - June 11, 2012, 5:07 p.m.
Richard Sandiford wrote:
> As discussed in the context of the AARCH64 submission, this patch
> rewrites the iterator handling in read-rtl.c so that we record
> iterator positions using an on-the-side VEC rather than placeholder
> modes and codes.  We then substitute in-place for each sequence of
> iterator values and take a deep copy of the result.  We do any string
> substitutions during the copy.
> 
> The patch also generalises the current use of attributes for rtx modes
> ("(zero_extend:<WIDER_MODE> ...)", etc.) so that the same kind of thing
> can be done with future iterator types, including the int iterators.
> Not sure whether that'll be useful or not, but it made the patch
> easier to write.
> 
> Tested by making sure that the insn-*.c output didn't change for
> x86_64-linux-gnu, except that we now do a better job of retaining
> #line information (not seen as a good thing by everbody, I realise).
> Also made sure that things like insn-output.c are still generated
> in the blink of an eye.
> 
> Bootstrapped & regression-tested on x86_64-linux-gnu and i686-pc-linux-gnu.
> OK to install?
> 
> Richard
> 
> 
> gcc/
>         * 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.
> 
> Index: gcc/read-rtl.c
> ===================================================================
> --- gcc/read-rtl.c      2012-06-03 08:58:32.251211521 +0100
> +++ gcc/read-rtl.c      2012-06-03 09:20:47.633208254 +0100
> @@ -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);
> +};
> +
> +/* Records one use of an iterator.  */
> +struct iterator_use {
> +  /* The iterator itself.  */
> +  struct mapping *iterator;
> 
> -  /* Make the given rtx use the given mode or code.  */
> -  void (*apply_iterator) (rtx, int);
> +  /* 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 *st
>        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 *st
>    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, str
>           {
>             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, str
>    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,50 +344,115 @@ add_condition_to_rtx (rtx x, const char
>      }
>  }
> 
> -/* 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;
> +  if (iterator->current_value)
> +    VEC_safe_push (mapping_ptr, heap, current_iterators, iterator);
> +  return 1;
> +}
> 
> -       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;
> -         }
> +/* 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);
>      }
> -  return 1;
>  }
> 
>  /* Add a new "mapping" structure to hashtable TABLE.  NAME is the name
> @@ -524,8 +467,8 @@ add_mapping (struct iterator_group *grou
>    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 *gro
>  }
> 
>  /* 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 *ite
>      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 @@ check_code_iterator (struct mapping *ite
>  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, st
>        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, st
>    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, st
> 
>        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, st
>                 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, st
>    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
>    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
>     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 **mo
>        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;
> 

Hi Richard,

Thanks for this patch. I've attached the int iterators patch based on this. It 
has been bootstrapped on x86_64-linux-gnu and regression tested on 
arm-none-eabi. Also the generated .c and .h files have no diffs on 
arm-none-eabi. OK?

Thanks,
Tejas Belagod
ARM.

PS: The doc claims an example from the ARM port but that change will be in a 
subsequent patch.

Changelog:

2012-06-11  Tejas Belagod  <tejas.belagod@arm.com>

gcc/
	* doc/md.texi: Document int iterators.
	* read-rtl.c (ints): New.
	(find_int): New.
	(apply_int_iterator): New.
	(apply_iterators): Traverse int iterator table and add all the used
	iterators to list.
	(initialize_iterators): Initialize data structures and callbacks for int
	iterators.
	(read_rtx): Parse and read mappings for int iterators.
	(read_rtx_code): Record int iterator usage.
Richard Sandiford - June 11, 2012, 7:03 p.m.
Thanks for the update.

Tejas Belagod <tbelagod@arm.com> writes:
> +/* 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)
> +{
> +  char *endptr;
> +  int ret;
> +
> +  if (ISDIGIT (*name))
> +    {
> +      ret = strtol (name, &endptr, 0);
> +      gcc_assert (*endptr == '\0');

As I mentioned before, I think this should be an error rather than
an assert.  An assert would only be appropriate if this is something
that should already have been checked, but AFAICT nothing does.

In fact I think this ought to be:

  validate_const_int (name);
  return atoi (name);

And unless I'm missing something, this:

> +	/* Can be an iterator or an integer constant.  */
>  	read_name (&name);
> -	validate_const_int (name.string);
> -	tmp_int = atoi (name.string);
> -	XINT (return_rtx, i) = tmp_int;
> +	if (!ISDIGIT (name.string[0]))
> +	  {
> +	    struct mapping *iterator;
> +	    /* An iterator.  */
> +  	    iterator = (struct mapping *) htab_find (ints.iterators,
> +						     &name.string);
> +	    if (iterator)
> +	      record_iterator_use (iterator, &XINT (return_rtx, i));
> +	    else
> +	      fatal_with_file_and_line ("unknown iterator `%s'",name.string);
> +	  }
> +	else
> +	  {
> +	    validate_const_int (name.string);
> +	    tmp_int = atoi (name.string);
> +	    XINT (return_rtx, i) = tmp_int;
> +	  }

should simply be:

	/* Can be an iterator or an integer constant.  */
	read_name (&name);
	record_potential_iterator_use (&ints, &XINT (return_rtx, i),
				       name.string);
	break;

Richard

Patch

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 71b89c1..da88347 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -8903,6 +8903,7 @@  facilities to make this process easier.
 @menu
 * Mode Iterators::         Generating variations of patterns for different modes.
 * Code Iterators::         Doing the same for codes.
+* Int Iterators::          Doing the same for integers.
 @end menu
 
 @node Mode Iterators
@@ -9174,4 +9175,83 @@  This is equivalent to:
 @dots{}
 @end smallexample
 
+@node Int Iterators
+@subsection Int Iterators
+@cindex int iterators in @file{.md} files
+@findex define_int_iterator
+@findex define_int_attr
+
+Int iterators operate in a similar way to code iterators.  @xref{Code Iterators}.
+
+The construct:
+
+@smallexample
+(define_int_iterator @var{name} [(@var{int1} "@var{cond1}") @dots{} (@var{intn} "@var{condn}")])
+@end smallexample
+
+defines a pseudo integer constant @var{name} that can be instantiated as
+@var{inti} if condition @var{condi} is true.  Each @var{int}
+must have the same rtx format.  @xref{RTL Classes}. Int iterators can appear
+in only those rtx fields that have 'i' as the specifier. This means that
+each @var{int} has to be a constant defined using define_constant or
+define_c_enum.
+
+As with mode and code iterators, each pattern that uses @var{name} will be
+expanded @var{n} times, once with all uses of @var{name} replaced by
+@var{int1}, once with all uses replaced by @var{int2}, and so on.
+@xref{Defining Mode Iterators}.
+
+It is possible to define attributes for ints as well as for codes and modes.
+There are two standard integer attributes: @code{int}, the name of the
+code in lower case, and @code{INT}, the name of the code in upper case.
+Other attributes are defined using:
+
+@smallexample
+(define_int_attr @var{name} [(@var{int1} "@var{value1}") @dots{} (@var{intn} "@var{valuen}")])
+@end smallexample
+
+Here's an example of int iterators in action, taken from the ARM port:
+
+@smallexample
+(define_int_iterator QABSNEG [UNSPEC_VQABS UNSPEC_VQNEG])
+
+(define_int_attr absneg [(UNSPEC_VQABS "abs") (UNSPEC_VQNEG "neg")])
+
+(define_insn "neon_vq<absneg><mode>"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+	(unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
+		       (match_operand:SI 2 "immediate_operand" "i")]
+		      QABSNEG))]
+  "TARGET_NEON"
+  "vq<absneg>.<V_s_elem>\t%<V_reg>0, %<V_reg>1"
+  [(set_attr "neon_type" "neon_vqneg_vqabs")]
+)
+
+@end smallexample
+
+This is equivalent to:
+
+@smallexample
+(define_insn "neon_vqabs<mode>"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+	(unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
+		       (match_operand:SI 2 "immediate_operand" "i")]
+		      UNSPEC_VQABS))]
+  "TARGET_NEON"
+  "vqabs.<V_s_elem>\t%<V_reg>0, %<V_reg>1"
+  [(set_attr "neon_type" "neon_vqneg_vqabs")]
+)
+
+(define_insn "neon_vqneg<mode>"
+  [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+	(unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w")
+		       (match_operand:SI 2 "immediate_operand" "i")]
+		      UNSPEC_VQNEG))]
+  "TARGET_NEON"
+  "vqneg.<V_s_elem>\t%<V_reg>0, %<V_reg>1"
+  [(set_attr "neon_type" "neon_vqneg_vqabs")]
+)
+
+@end smallexample
+
 @end ifset
diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c
index c588722..6eff3c9 100644
--- a/gcc/read-rtl.c
+++ b/gcc/read-rtl.c
@@ -114,7 +114,7 @@  static rtx read_nested_rtx (void);
 static rtx read_rtx_variadic (rtx);
 
 /* The mode and code iterator structures.  */
-static struct iterator_group modes, codes;
+static struct iterator_group modes, codes, ints;
 
 /* All iterators used in the current rtx.  */
 static VEC (mapping_ptr, heap) *current_iterators;
@@ -165,6 +165,34 @@  apply_code_iterator (void *loc, int code)
   PUT_CODE ((rtx) loc, (enum rtx_code) code);
 }
 
+/* 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)
+{
+  char *endptr;
+  int ret;
+
+  if (ISDIGIT (*name))
+    {
+      ret = strtol (name, &endptr, 0);
+      gcc_assert (*endptr == '\0');
+      return ret;
+    }
+  else
+    fatal_with_file_and_line ("unknown int `%s'", name);
+}
+
+static void
+apply_int_iterator (void *loc, int value)
+{
+  *(int *)loc = value;
+}
+
 /* Map attribute string P to its current value.  Return null if the attribute
    isn't known.  */
 
@@ -412,6 +440,7 @@  apply_iterators (rtx original, rtx *queue)
      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);
   gcc_assert (!VEC_empty (mapping_ptr, current_iterators));
 
   for (;;)
@@ -518,6 +547,12 @@  initialize_iterators (void)
   codes.find_builtin = find_code;
   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;
+
   lower = add_mapping (&modes, modes.attrs, "mode");
   upper = add_mapping (&modes, modes.attrs, "MODE");
   lower_ptr = &lower->values;
@@ -827,6 +862,16 @@  read_rtx (const char *rtx_name, rtx *x)
       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;
+    }
 
   apply_iterators (read_rtx_code (rtx_name), &queue_head);
   VEC_truncate (iterator_use, iterator_uses, 0);
@@ -1026,10 +1071,25 @@  read_rtx_code (const char *code_name)
 
       case 'i':
       case 'n':
+	/* Can be an iterator or an integer constant.  */
 	read_name (&name);
-	validate_const_int (name.string);
-	tmp_int = atoi (name.string);
-	XINT (return_rtx, i) = tmp_int;
+	if (!ISDIGIT (name.string[0]))
+	  {
+	    struct mapping *iterator;
+	    /* An iterator.  */
+  	    iterator = (struct mapping *) htab_find (ints.iterators,
+						     &name.string);
+	    if (iterator)
+	      record_iterator_use (iterator, &XINT (return_rtx, i));
+	    else
+	      fatal_with_file_and_line ("unknown iterator `%s'",name.string);
+	  }
+	else
+	  {
+	    validate_const_int (name.string);
+	    tmp_int = atoi (name.string);
+	    XINT (return_rtx, i) = tmp_int;
+	  }
 	break;
 
       default: